2
2
* ProGuard -- shrinking, optimization, obfuscation, and preverification
5
* Copyright (c) 2002-2008 Eric Lafortune (eric@graphics.cornell.edu)
5
* Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
7
7
* This program is free software; you can redistribute it and/or modify it
8
8
* under the terms of the GNU General Public License as published by the Free
49
50
private final DictionaryNameFactory classNameFactory;
50
51
private final DictionaryNameFactory packageNameFactory;
51
52
private final boolean useMixedCaseClassNames;
53
private final StringMatcher keepPackageNamesMatcher;
52
54
private final String flattenPackageHierarchy;
53
55
private final String repackageClasses;
54
56
private final boolean allowAccessModification;
56
private final Set classNamesToAvoid = new HashSet();
58
private final Set classNamesToAvoid = new HashSet();
58
60
// Map: [package prefix - new package prefix]
59
private final Map packagePrefixMap = new HashMap();
61
private final Map packagePrefixMap = new HashMap();
61
63
// Map: [package prefix - package name factory]
62
private final Map packagePrefixPackageNameFactoryMap = new HashMap();
64
// Map: [package prefix - class name factory]
65
private final Map packagePrefixClassNameFactoryMap = new HashMap();
67
// A field acting as a temporary variable and as a return value for names
69
private String newClassName;
64
private final Map packagePrefixPackageNameFactoryMap = new HashMap();
66
// Map: [package prefix - numeric class name factory]
67
private final Map packagePrefixClassNameFactoryMap = new HashMap();
69
// Map: [package prefix - numeric class name factory]
70
private final Map packagePrefixNumericClassNameFactoryMap = new HashMap();
72
// Field acting as temporary variables and as return values for names
73
// of outer classes and types of inner classes.
74
private String newClassName;
75
private boolean numericClassName;
79
85
* @param useMixedCaseClassNames specifies whether obfuscated packages and
80
86
* classes can get mixed-case names.
87
* @param keepPackageNames the optional filter for which matching
88
* package names are kept.
81
89
* @param flattenPackageHierarchy the base package if the obfuscated package
82
90
* hierarchy is to be flattened.
83
91
* @param repackageClasses the base package if the obfuscated classes
89
97
DictionaryNameFactory classNameFactory,
90
98
DictionaryNameFactory packageNameFactory,
91
99
boolean useMixedCaseClassNames,
100
List keepPackageNames,
92
101
String flattenPackageHierarchy,
93
102
String repackageClasses,
94
103
boolean allowAccessModification)
113
122
this.useMixedCaseClassNames = useMixedCaseClassNames;
123
this.keepPackageNamesMatcher = keepPackageNames == null ? null :
124
new ListParser(new FileNameParser()).parse(keepPackageNames);
114
125
this.flattenPackageHierarchy = flattenPackageHierarchy;
115
126
this.repackageClasses = repackageClasses;
116
127
this.allowAccessModification = allowAccessModification;
137
148
programClass.attributesAccept(this);
139
150
// Figure out a package prefix. The package prefix may actually be
140
// the outer class prefix, if any, or it may be the fixed base
151
// the an outer class prefix, if any, or it may be the fixed base
141
152
// package, if classes are to be repackaged.
142
153
String newPackagePrefix = newClassName != null ?
143
154
newClassName + ClassConstants.INTERNAL_INNER_CLASS_SEPARATOR :
144
155
newPackagePrefix(ClassUtil.internalPackagePrefix(programClass.getName()));
146
// Come up with a new class name.
147
newClassName = generateUniqueClassName(newPackagePrefix);
157
// Come up with a new class name, numeric or ordinary.
158
newClassName = newClassName != null && numericClassName ?
159
generateUniqueNumericClassName(newPackagePrefix) :
160
generateUniqueClassName(newPackagePrefix);
149
162
setNewClassName(programClass, newClassName);
168
181
// Make sure the enclosing class has a name.
169
182
enclosingMethodAttribute.referencedClassAccept(this);
184
String innerClassName = clazz.getName();
185
String outerClassName = clazz.getClassName(enclosingMethodAttribute.u2classIndex);
187
numericClassName = isNumericClassName(innerClassName,
178
197
int innerClassIndex = innerClassesInfo.u2innerClassIndex;
179
198
int outerClassIndex = innerClassesInfo.u2outerClassIndex;
180
199
if (innerClassIndex != 0 &&
181
outerClassIndex != 0 &&
182
clazz.getClassName(innerClassIndex).equals(clazz.getName()))
184
clazz.constantPoolEntryAccept(outerClassIndex, this);
200
outerClassIndex != 0)
202
String innerClassName = clazz.getClassName(innerClassIndex);
203
if (innerClassName.equals(clazz.getName()))
205
clazz.constantPoolEntryAccept(outerClassIndex, this);
207
String outerClassName = clazz.getClassName(outerClassIndex);
209
numericClassName = isNumericClassName(innerClassName,
217
* Returns whether the given inner class name is a numeric name.
219
private boolean isNumericClassName(String innerClassName,
220
String outerClassName)
222
int innerClassNameStart = outerClassName.length() + 1;
223
int innerClassNameLength = innerClassName.length();
225
if (innerClassNameStart >= innerClassNameLength)
230
for (int index = innerClassNameStart; index < innerClassNameLength; index++)
232
if (!Character.isDigit(innerClassName.charAt(index)))
217
270
String className = programClass.getName();
219
272
// Keep the package name for all other classes in the same
220
// package. Do this resursively if we're not doing any
273
// package. Do this recursively if we're not doing any
222
275
mapPackageName(className,
275
328
String newPackagePrefix = (String)packagePrefixMap.get(packagePrefix);
276
329
if (newPackagePrefix == null)
331
// Are we keeping the package name?
332
if (keepPackageNamesMatcher != null &&
333
keepPackageNamesMatcher.matches(packagePrefix.length() > 0 ?
334
packagePrefix.substring(0, packagePrefix.length()-1) :
337
return packagePrefix;
278
340
// Are we forcing a new package prefix?
279
341
if (repackageClasses != null)
284
346
// Are we forcing a new superpackage prefix?
285
// Othewrise figure out the new superpackage prefix, recursively.
347
// Otherwise figure out the new superpackage prefix, recursively.
286
348
String newSuperPackagePrefix = flattenPackageHierarchy != null ?
287
349
flattenPackageHierarchy :
288
350
newPackagePrefix(ClassUtil.internalPackagePrefix(packagePrefix));
322
384
packageNameFactory);
387
return generateUniquePackagePrefix(newSuperPackagePrefix, packageNameFactory);
392
* Creates a new package prefix in the given new superpackage, with the
393
* given package name factory.
395
private String generateUniquePackagePrefix(String newSuperPackagePrefix,
396
NameFactory packageNameFactory)
325
398
// Come up with package names until we get an original one.
326
399
String newPackagePrefix;
347
420
(NameFactory)packagePrefixClassNameFactoryMap.get(newPackagePrefix);
348
421
if (classNameFactory == null)
350
// We haven't seen classes in this package before. Create a new name
423
// We haven't seen classes in this package before.
424
// Create a new name factory for them.
352
425
classNameFactory = new SimpleNameFactory(useMixedCaseClassNames);
353
426
if (this.classNameFactory != null)
361
434
classNameFactory);
437
return generateUniqueClassName(newPackagePrefix, classNameFactory);
442
* Creates a new class name in the given new package.
444
private String generateUniqueNumericClassName(String newPackagePrefix)
446
// Find the right name factory for this package.
447
NameFactory classNameFactory =
448
(NameFactory)packagePrefixNumericClassNameFactoryMap.get(newPackagePrefix);
449
if (classNameFactory == null)
451
// We haven't seen classes in this package before.
452
// Create a new name factory for them.
453
classNameFactory = new NumericNameFactory();
455
packagePrefixNumericClassNameFactoryMap.put(newPackagePrefix,
459
return generateUniqueClassName(newPackagePrefix, classNameFactory);
464
* Creates a new class name in the given new package, with the given
465
* class name factory.
467
private String generateUniqueClassName(String newPackagePrefix,
468
NameFactory classNameFactory)
364
470
// Come up with class names until we get an original one.
365
471
String newClassName;