001: /**
002: * JavaGuard -- an obfuscation package for Java classfiles.
003: *
004: * Copyright (c) 1999 Mark Welsh (markw@retrologic.com)
005: * Copyright (c) 2002 Thorsten Heit (theit@gmx.de)
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * The author may be contacted at theit@gmx.de.
022: *
023: *
024: * $Id: KeywordNameMaker.java,v 1.2 2002/05/11 18:55:54 glurk Exp $
025: */package net.sf.javaguard;
026:
027: import java.io.*;
028: import java.util.Hashtable;
029: import java.util.Vector;
030:
031: /** Name generator that uses (almost) the full Java identifier namespace,
032: * and chooses to put some of the keyword names (legal in JVM, illegal in
033: * Java language) out front in sequence.
034: *
035: * @author <a href="mailto:markw@retrologic.com">Mark Welsh</a>
036: * @author <a href="mailto:theit@gmx.de">Thorsten Heit</a>
037: */
038: public class KeywordNameMaker extends NameMaker {
039: // Constants -------------------------------------------------------------
040: private static final String DUMMY_ARG_LIST = "dummy";
041:
042: // Fields ----------------------------------------------------------------
043: private int skipped = 0; // Names skipped in the sequence
044: private Vector namesToDate = new Vector();
045: private Hashtable argCount = new Hashtable();
046: private String[] noObfNames = null; // List of names not to be obfuscated
047: private String[] keywordsToUse;
048: private String[] keywordsToExclude;
049: private String[] firstLetter;
050: private String[] nextLetter;
051: private String[] noKeywords = {};
052: private String[] someKeywords = { "a", "if", "do", "for", "int",
053: "new", "try", "byte", "case", "char", "else", "goto",
054: "long", "null", "void" };
055: private String[] allKeywords = { "if", "do", "for", "int", "new",
056: "try", "byte", "case", "char", "else", "goto", "long",
057: "null", "this", "void", "true", "false", "break", "catch",
058: "class", "const", "float", "final", "short", "super",
059: "throw", "while", "double", "import", "native", "public",
060: "return", "static", "switch", "throws", "boolean",
061: "default", "extends", "finally", "package", "private",
062: "abstract", "continue", "volatile", "interface",
063: "protected", "transient", "implements", "instanceof",
064: "synchronized" };
065: private String[] firstLetterLower = { "a", "b", "c", "d", "e", "f",
066: "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
067: "s", "t", "u", "v", "w", "x", "y", "z" };
068: private String[] nextLetterLower = { "a", "b", "c", "d", "e", "f",
069: "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
070: "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3",
071: "4", "5", "6", "7", "8", "9" };
072: private String[] firstLetterAll = { "a", "b", "c", "d", "e", "f",
073: "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
074: "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D",
075: "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
076: "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
077: private String[] nextLetterAll = { "a", "b", "c", "d", "e", "f",
078: "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
079: "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D",
080: "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
081: "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1",
082: "2", "3", "4", "5", "6", "7", "8", "9" };
083:
084: /** Ctor. */
085: public KeywordNameMaker() {
086: this (null);
087: }
088:
089: /** Ctor - block names not to be obfuscated from the mapping target space. */
090: public KeywordNameMaker(String[] noObfNames) {
091: this (noObfNames, true);
092: }
093:
094: /** Ctor - block names not to be obfuscated from the mapping target space. */
095: public KeywordNameMaker(String[] noObfNames, boolean useKeywords) {
096: this (noObfNames, true, false);
097: }
098:
099: /** Ctor - block names not to be obfuscated from the mapping target space. */
100: public KeywordNameMaker(String[] noObfNames, boolean useKeywords,
101: boolean lowerCaseOnly) {
102: this .noObfNames = noObfNames == null ? new String[0]
103: : noObfNames;
104: if (useKeywords) {
105: keywordsToUse = someKeywords;
106: keywordsToExclude = someKeywords;
107: } else {
108: keywordsToUse = noKeywords;
109: keywordsToExclude = allKeywords;
110: }
111: if (lowerCaseOnly) {
112: firstLetter = firstLetterLower;
113: nextLetter = nextLetterLower;
114: } else {
115: firstLetter = firstLetterAll;
116: nextLetter = nextLetterAll;
117: }
118: }
119:
120: /** Return the next unique name for this namespace. */
121: protected String getNextName(String descriptor) {
122: // Check for arg-list in hashtable
123: String argList = DUMMY_ARG_LIST;
124: if (null != descriptor) {
125: argList = getArgList(descriptor);
126: }
127: Integer intCount = (Integer) argCount.get(argList);
128: int theCount = 0;
129: if (null == intCount) {
130: argCount.put(argList, new Integer(theCount));
131: } else {
132: theCount = intCount.intValue() + 1;
133: argCount.remove(argList);
134: argCount.put(argList, new Integer(theCount));
135: }
136: return getName(theCount);
137: }
138:
139: // Extract the arg-list from a descriptor
140: private String getArgList(String descriptor) {
141: int pos = descriptor.indexOf(')');
142: return descriptor.substring(1, pos);
143: }
144:
145: // Generate i'th allowed, unique name
146: private String getName(int index) {
147: // If we have previously computed this name, just return it
148: String name = null;
149: if (index < namesToDate.size()) {
150: name = (String) namesToDate.elementAt(index);
151: } else {
152: // Generate a new valid name for the sequence
153: for (;;) {
154: name = getNewName(index + skipped);
155: if (!Tools.isInArray(name, noObfNames)
156: && (index + skipped < keywordsToUse.length || !Tools
157: .isInArray(name, keywordsToExclude))) {
158: break;
159: }
160: skipped++;
161: }
162: namesToDate.addElement(name);
163: }
164: return name;
165: }
166:
167: // Generate j'th name in sequence (can repeat keywords)
168: private String getNewName(int index) {
169: String name = null;
170:
171: // Check if we are in the 'keyword' part of the namespace
172: if (index < keywordsToUse.length) {
173: name = keywordsToUse[index];
174: } else {
175: // Check if we are in the single letter part of the namespace
176: index -= keywordsToUse.length;
177: if (index < firstLetter.length) {
178: name = firstLetter[index];
179: } else {
180: // We are in the >=2 letter part of namespace
181: index -= firstLetter.length;
182: int nextLetters = 1;
183: int subspaceSize = nextLetter.length;
184: while (index >= firstLetter.length * subspaceSize) {
185: index -= firstLetter.length * subspaceSize;
186: nextLetters++;
187: subspaceSize *= nextLetter.length;
188: }
189:
190: // Pull out the name
191: StringBuffer sb = new StringBuffer(firstLetter[index
192: / subspaceSize]);
193: while (subspaceSize != 1) {
194: index %= subspaceSize;
195: subspaceSize /= nextLetter.length;
196: sb.append(nextLetter[index / subspaceSize]);
197: }
198:
199: // Check for collision with keywords
200: name = sb.toString();
201: }
202: }
203: return name;
204: }
205: }
|