1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package proguard.obfuscate;
22 
23 import java.util.*;
24 
25 
26 /**
27  * This <code>NameFactory</code> generates unique short names, using mixed-case
28  * characters or lower-case characters only.
29  *
30  * @author Eric Lafortune
31  */
32 public class SimpleNameFactory implements NameFactory
33 {
34     private static final int CHARACTER_COUNT = 26;
35 
36     private static final List cachedMixedCaseNames = new ArrayList();
37     private static final List cachedLowerCaseNames = new ArrayList();
38 
39     private final boolean generateMixedCaseNames;
40     private int     index = 0;
41 
42 
43     /**
44      * Creates a new <code>SimpleNameFactory</code> that generates mixed-case names.
45      */
SimpleNameFactory()46     public SimpleNameFactory()
47     {
48         this(true);
49     }
50 
51 
52     /**
53      * Creates a new <code>SimpleNameFactory</code>.
54      * @param generateMixedCaseNames a flag to indicate whether the generated
55      *                               names will be mixed-case, or lower-case only.
56      */
SimpleNameFactory(boolean generateMixedCaseNames)57     public SimpleNameFactory(boolean generateMixedCaseNames)
58     {
59         this.generateMixedCaseNames = generateMixedCaseNames;
60     }
61 
62 
63     // Implementations for NameFactory.
64 
reset()65     public void reset()
66     {
67         index = 0;
68     }
69 
70 
nextName()71     public String nextName()
72     {
73         return name(index++);
74     }
75 
76 
77     /**
78      * Returns the name at the given index.
79      */
name(int index)80     private String name(int index)
81     {
82         // Which cache do we need?
83         List cachedNames = generateMixedCaseNames ?
84             cachedMixedCaseNames :
85             cachedLowerCaseNames;
86 
87         // Do we have the name in the cache?
88         if (index < cachedNames.size())
89         {
90             return (String)cachedNames.get(index);
91         }
92 
93         // Create a new name and cache it.
94         String name = newName(index);
95         cachedNames.add(index, name);
96 
97         return name;
98     }
99 
100 
101     /**
102      * Creates and returns the name at the given index.
103      */
newName(int index)104     private String newName(int index)
105     {
106         // If we're allowed to generate mixed-case names, we can use twice as
107         // many characters.
108         int totalCharacterCount = generateMixedCaseNames ?
109             2 * CHARACTER_COUNT :
110             CHARACTER_COUNT;
111 
112         int baseIndex = index / totalCharacterCount;
113         int offset    = index % totalCharacterCount;
114 
115         char newChar = charAt(offset);
116 
117         String newName = baseIndex == 0 ?
118             new String(new char[] { newChar }) :
119             (name(baseIndex-1) + newChar);
120 
121         return newName;
122     }
123 
124 
125     /**
126      * Returns the character with the given index, between 0 and the number of
127      * acceptable characters.
128      */
charAt(int index)129     private char charAt(int index)
130     {
131         return (char)((index < CHARACTER_COUNT ? 'a' - 0               :
132                                                  'A' - CHARACTER_COUNT) + index);
133     }
134 
135 
main(String[] args)136     public static void main(String[] args)
137     {
138         System.out.println("Some mixed-case names:");
139         printNameSamples(new SimpleNameFactory(true), 60);
140         System.out.println("Some lower-case names:");
141         printNameSamples(new SimpleNameFactory(false), 60);
142         System.out.println("Some more mixed-case names:");
143         printNameSamples(new SimpleNameFactory(true), 80);
144         System.out.println("Some more lower-case names:");
145         printNameSamples(new SimpleNameFactory(false), 80);
146     }
147 
148 
printNameSamples(SimpleNameFactory factory, int count)149     private static void printNameSamples(SimpleNameFactory factory, int count)
150     {
151         for (int counter = 0; counter < count; counter++)
152         {
153             System.out.println("  ["+factory.nextName()+"]");
154         }
155     }
156 }
157