NormalizedFileNames.java

    1/*******************************************************************************
    2 * Copyright (c) 2009, 2010 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;
   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 * 
   35 * @author Marc R. Hoffmann
   36 * @version 0.4.1.20101007204400
   37 */
   38class NormalizedFileNames {
   39
   40    private static final BitSet LEGAL_CHARS = new BitSet();
   41
   42    static {
   43        final String legal = "abcdefghijklmnopqrstuvwxyz"
   44                + "ABCDEFGHIJKLMNOPQRSTUVWYXZ0123456789$-._";
   45        for (final char c : legal.toCharArray()) {
   46            LEGAL_CHARS.set(c);
   47        }
   48    }
   49
   50    private final Map<String, String> mapping = new HashMap<String, String>();
   51
   52    private final Set<String> usedNames = new HashSet<String>();
   53
   54    public String getFileName(final String id) {
   55        String name = mapping.get(id);
   56        if (name != null) {
   57            return name;
   58        }
   59        name = replaceIllegalChars(id);
   60        name = ensureUniqueness(name);
   61        mapping.put(id, name);
   62        return name;
   63    }
   64
   65    private String replaceIllegalChars(final String s) {
   66        final StringBuilder sb = new StringBuilder(s.length());
   67        for (int i = 0; i < s.length(); i++) {
   68            final char c = s.charAt(i);
   69            sb.append(LEGAL_CHARS.get(c) ? c : '_');
   70        }
   71        return sb.toString();
   72    }
   73
   74    private String ensureUniqueness(final String s) {
   75        String unique = s;
   76        String lower = unique.toLowerCase();
   77        int idx = 1;
   78        while (usedNames.contains(lower)) {
   79            unique = s + '~' + idx++;
   80            lower = unique.toLowerCase();
   81        }
   82        usedNames.add(lower);
   83        return unique;
   84    }
   85
   86}