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