~ubuntu-branches/ubuntu/maverick/proguard/maverick

« back to all changes in this revision

Viewing changes to src/proguard/obfuscate/ClassObfuscator.java

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg, Onkar Shinde, Sam Clegg
  • Date: 2009-10-09 16:17:49 UTC
  • mfrom: (1.2.3 upstream) (3.1.6 karmic)
  • Revision ID: james.westby@ubuntu.com-20091009161749-qjk059y5r792co7c
Tags: 4.4-1
[ Onkar Shinde ]
* Merge from Ubuntu. (Closes: #534029, #548810)

[ Sam Clegg ]
* Thanks Onkar for the above fixes!
* New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3
3
 *             of Java bytecode.
4
4
 *
5
 
 * Copyright (c) 2002-2008 Eric Lafortune (eric@graphics.cornell.edu)
 
5
 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6
6
 *
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
27
27
import proguard.classfile.constant.visitor.ConstantVisitor;
28
28
import proguard.classfile.util.*;
29
29
import proguard.classfile.visitor.ClassVisitor;
 
30
import proguard.util.*;
30
31
 
31
32
import java.util.*;
32
33
 
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;
55
57
 
56
 
    private final Set classNamesToAvoid                  = new HashSet();
 
58
    private final Set classNamesToAvoid                       = new HashSet();
57
59
 
58
60
    // Map: [package prefix - new package prefix]
59
 
    private final Map packagePrefixMap                   = new HashMap();
 
61
    private final Map packagePrefixMap                        = new HashMap();
60
62
 
61
63
    // Map: [package prefix - package name factory]
62
 
    private final Map packagePrefixPackageNameFactoryMap = new HashMap();
63
 
 
64
 
    // Map: [package prefix - class name factory]
65
 
    private final Map packagePrefixClassNameFactoryMap   = new HashMap();
66
 
 
67
 
    // A field acting as a temporary variable and as a return value for names
68
 
    // of outer classes.
69
 
    private String newClassName;
 
64
    private final Map packagePrefixPackageNameFactoryMap      = new HashMap();
 
65
 
 
66
    // Map: [package prefix - numeric class name factory]
 
67
    private final Map packagePrefixClassNameFactoryMap        = new HashMap();
 
68
 
 
69
    // Map: [package prefix - numeric class name factory]
 
70
    private final Map packagePrefixNumericClassNameFactoryMap = new HashMap();
 
71
 
 
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;
70
76
 
71
77
 
72
78
    /**
78
84
     *                                dictionary.
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)
111
120
        }
112
121
 
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);
138
149
 
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()));
145
156
 
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);
148
161
 
149
162
            setNewClassName(programClass, newClassName);
150
163
        }
167
180
    {
168
181
        // Make sure the enclosing class has a name.
169
182
        enclosingMethodAttribute.referencedClassAccept(this);
 
183
 
 
184
        String innerClassName = clazz.getName();
 
185
        String outerClassName = clazz.getClassName(enclosingMethodAttribute.u2classIndex);
 
186
 
 
187
        numericClassName = isNumericClassName(innerClassName,
 
188
                                              outerClassName);
170
189
    }
171
190
 
172
191
 
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()))
183
 
        {
184
 
            clazz.constantPoolEntryAccept(outerClassIndex, this);
185
 
        }
 
200
            outerClassIndex != 0)
 
201
        {
 
202
            String innerClassName = clazz.getClassName(innerClassIndex);
 
203
            if (innerClassName.equals(clazz.getName()))
 
204
            {
 
205
                clazz.constantPoolEntryAccept(outerClassIndex, this);
 
206
 
 
207
                String outerClassName = clazz.getClassName(outerClassIndex);
 
208
 
 
209
                numericClassName = isNumericClassName(innerClassName,
 
210
                                                      outerClassName);
 
211
            }
 
212
        }
 
213
    }
 
214
 
 
215
 
 
216
    /**
 
217
     * Returns whether the given inner class name is a numeric name.
 
218
     */
 
219
    private boolean isNumericClassName(String innerClassName,
 
220
                                       String outerClassName)
 
221
    {
 
222
        int innerClassNameStart  = outerClassName.length() + 1;
 
223
        int innerClassNameLength = innerClassName.length();
 
224
 
 
225
        if (innerClassNameStart >= innerClassNameLength)
 
226
        {
 
227
            return false;
 
228
        }
 
229
 
 
230
        for (int index = innerClassNameStart; index < innerClassNameLength; index++)
 
231
        {
 
232
            if (!Character.isDigit(innerClassName.charAt(index)))
 
233
            {
 
234
                return false;
 
235
            }
 
236
        }
 
237
 
 
238
        return true;
186
239
    }
187
240
 
188
241
 
217
270
                    String className = programClass.getName();
218
271
 
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
221
274
                    // repackaging.
222
275
                    mapPackageName(className,
223
276
                                   newClassName,
275
328
        String newPackagePrefix = (String)packagePrefixMap.get(packagePrefix);
276
329
        if (newPackagePrefix == null)
277
330
        {
 
331
            // Are we keeping the package name?
 
332
            if (keepPackageNamesMatcher != null &&
 
333
                keepPackageNamesMatcher.matches(packagePrefix.length() > 0 ?
 
334
                    packagePrefix.substring(0, packagePrefix.length()-1) :
 
335
                    packagePrefix))
 
336
            {
 
337
                return packagePrefix;
 
338
            }
 
339
 
278
340
            // Are we forcing a new package prefix?
279
341
            if (repackageClasses != null)
280
342
            {
282
344
            }
283
345
 
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);
323
385
        }
324
386
 
 
387
        return generateUniquePackagePrefix(newSuperPackagePrefix, packageNameFactory);
 
388
    }
 
389
 
 
390
 
 
391
    /**
 
392
     * Creates a new package prefix in the given new superpackage, with the
 
393
     * given package name factory.
 
394
     */
 
395
    private String generateUniquePackagePrefix(String      newSuperPackagePrefix,
 
396
                                               NameFactory packageNameFactory)
 
397
    {
325
398
        // Come up with package names until we get an original one.
326
399
        String newPackagePrefix;
327
400
        do
347
420
            (NameFactory)packagePrefixClassNameFactoryMap.get(newPackagePrefix);
348
421
        if (classNameFactory == null)
349
422
        {
350
 
            // We haven't seen classes in this package before. Create a new name
351
 
            // factory for them.
 
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)
354
427
            {
361
434
                                                 classNameFactory);
362
435
        }
363
436
 
 
437
        return generateUniqueClassName(newPackagePrefix, classNameFactory);
 
438
    }
 
439
 
 
440
 
 
441
    /**
 
442
     * Creates a new class name in the given new package.
 
443
     */
 
444
    private String generateUniqueNumericClassName(String newPackagePrefix)
 
445
    {
 
446
        // Find the right name factory for this package.
 
447
        NameFactory classNameFactory =
 
448
            (NameFactory)packagePrefixNumericClassNameFactoryMap.get(newPackagePrefix);
 
449
        if (classNameFactory == null)
 
450
        {
 
451
            // We haven't seen classes in this package before.
 
452
            // Create a new name factory for them.
 
453
            classNameFactory = new NumericNameFactory();
 
454
 
 
455
            packagePrefixNumericClassNameFactoryMap.put(newPackagePrefix,
 
456
                                                        classNameFactory);
 
457
        }
 
458
 
 
459
        return generateUniqueClassName(newPackagePrefix, classNameFactory);
 
460
    }
 
461
 
 
462
 
 
463
    /**
 
464
     * Creates a new class name in the given new package, with the given
 
465
     * class name factory.
 
466
     */
 
467
    private String generateUniqueClassName(String      newPackagePrefix,
 
468
                                           NameFactory classNameFactory)
 
469
    {
364
470
        // Come up with class names until we get an original one.
365
471
        String newClassName;
366
472
        do
374
480
        return newClassName;
375
481
    }
376
482
 
 
483
 
377
484
    /**
378
485
     * Returns the given class name, unchanged if mixed-case class names are
379
486
     * allowed, or the lower-case version otherwise.