NormalizedFileNames.java revision 82c11be3dd19fc071f87fedc5782c11ca51a0732
1/******************************************************************************* 2 * Copyright (c) 2009, 2011 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Marc R. Hoffmann - initial API and implementation 10 * 11 *******************************************************************************/ 12package org.jacoco.report.internal; 13 14import java.util.BitSet; 15import java.util.HashMap; 16import java.util.HashSet; 17import java.util.Map; 18import java.util.Set; 19 20/** 21 * Internal utility to create normalized file names from string ids. The file 22 * names generated by an instance of this class have the following properties: 23 * 24 * <ul> 25 * <li>The same input id is mapped to the same file name.</li> 26 * <li>Different ids are mapped to different file names.</li> 27 * <li>For safe characters the file name corresponds to the input id, other 28 * characters are replaced by <code>_</code> (underscore).</li> 29 * <li>File names are case aware, i.e. the same file name but with different 30 * upper/lower case characters is not possible.</li> 31 * <li>If unique filenames can't directly created from the ids, additional 32 * suffixes are appended.</li> 33 * </ul> 34 */ 35class NormalizedFileNames { 36 37 private static final BitSet LEGAL_CHARS = new BitSet(); 38 39 static { 40 final String legal = "abcdefghijklmnopqrstuvwxyz" 41 + "ABCDEFGHIJKLMNOPQRSTUVWYXZ0123456789$-._"; 42 for (final char c : legal.toCharArray()) { 43 LEGAL_CHARS.set(c); 44 } 45 } 46 47 private final Map<String, String> mapping = new HashMap<String, String>(); 48 49 private final Set<String> usedNames = new HashSet<String>(); 50 51 public String getFileName(final String id) { 52 String name = mapping.get(id); 53 if (name != null) { 54 return name; 55 } 56 name = replaceIllegalChars(id); 57 name = ensureUniqueness(name); 58 mapping.put(id, name); 59 return name; 60 } 61 62 private String replaceIllegalChars(final String s) { 63 final StringBuilder sb = new StringBuilder(s.length()); 64 for (int i = 0; i < s.length(); i++) { 65 final char c = s.charAt(i); 66 sb.append(LEGAL_CHARS.get(c) ? c : '_'); 67 } 68 return sb.toString(); 69 } 70 71 private String ensureUniqueness(final String s) { 72 String unique = s; 73 String lower = unique.toLowerCase(); 74 int idx = 1; 75 while (usedNames.contains(lower)) { 76 unique = s + '~' + idx++; 77 lower = unique.toLowerCase(); 78 } 79 usedNames.add(lower); 80 return unique; 81 } 82 83} 84