diff options
Diffstat (limited to 'src/proguard/obfuscate/ClassObfuscator.java')
-rw-r--r-- | src/proguard/obfuscate/ClassObfuscator.java | 541 |
1 files changed, 0 insertions, 541 deletions
diff --git a/src/proguard/obfuscate/ClassObfuscator.java b/src/proguard/obfuscate/ClassObfuscator.java deleted file mode 100644 index 516c889..0000000 --- a/src/proguard/obfuscate/ClassObfuscator.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * ProGuard -- shrinking, optimization, obfuscation, and preverification - * of Java bytecode. - * - * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package proguard.obfuscate; - -import proguard.classfile.*; -import proguard.classfile.attribute.*; -import proguard.classfile.attribute.visitor.*; -import proguard.classfile.constant.ClassConstant; -import proguard.classfile.constant.visitor.ConstantVisitor; -import proguard.classfile.util.*; -import proguard.classfile.visitor.ClassVisitor; -import proguard.util.*; - -import java.util.*; - -/** - * This <code>ClassVisitor</code> comes up with obfuscated names for the - * classes it visits, and for their class members. The actual renaming is - * done afterward. - * - * @see ClassRenamer - * - * @author Eric Lafortune - */ -public class ClassObfuscator -extends SimplifiedVisitor -implements ClassVisitor, - AttributeVisitor, - InnerClassesInfoVisitor, - ConstantVisitor -{ - private final DictionaryNameFactory classNameFactory; - private final DictionaryNameFactory packageNameFactory; - private final boolean useMixedCaseClassNames; - private final StringMatcher keepPackageNamesMatcher; - private final String flattenPackageHierarchy; - private final String repackageClasses; - private final boolean allowAccessModification; - - private final Set classNamesToAvoid = new HashSet(); - - // Map: [package prefix - new package prefix] - private final Map packagePrefixMap = new HashMap(); - - // Map: [package prefix - package name factory] - private final Map packagePrefixPackageNameFactoryMap = new HashMap(); - - // Map: [package prefix - numeric class name factory] - private final Map packagePrefixClassNameFactoryMap = new HashMap(); - - // Map: [package prefix - numeric class name factory] - private final Map packagePrefixNumericClassNameFactoryMap = new HashMap(); - - // Field acting as temporary variables and as return values for names - // of outer classes and types of inner classes. - private String newClassName; - private boolean numericClassName; - - - /** - * Creates a new ClassObfuscator. - * @param programClassPool the class pool in which class names - * have to be unique. - * @param classNameFactory the optional class obfuscation dictionary. - * @param packageNameFactory the optional package obfuscation - * dictionary. - * @param useMixedCaseClassNames specifies whether obfuscated packages and - * classes can get mixed-case names. - * @param keepPackageNames the optional filter for which matching - * package names are kept. - * @param flattenPackageHierarchy the base package if the obfuscated package - * hierarchy is to be flattened. - * @param repackageClasses the base package if the obfuscated classes - * are to be repackaged. - * @param allowAccessModification specifies whether obfuscated classes can - * be freely moved between packages. - */ - public ClassObfuscator(ClassPool programClassPool, - DictionaryNameFactory classNameFactory, - DictionaryNameFactory packageNameFactory, - boolean useMixedCaseClassNames, - List keepPackageNames, - String flattenPackageHierarchy, - String repackageClasses, - boolean allowAccessModification) - { - this.classNameFactory = classNameFactory; - this.packageNameFactory = packageNameFactory; - - // First append the package separator if necessary. - if (flattenPackageHierarchy != null && - flattenPackageHierarchy.length() > 0) - { - flattenPackageHierarchy += ClassConstants.PACKAGE_SEPARATOR; - } - - // First append the package separator if necessary. - if (repackageClasses != null && - repackageClasses.length() > 0) - { - repackageClasses += ClassConstants.PACKAGE_SEPARATOR; - } - - this.useMixedCaseClassNames = useMixedCaseClassNames; - this.keepPackageNamesMatcher = keepPackageNames == null ? null : - new ListParser(new FileNameParser()).parse(keepPackageNames); - this.flattenPackageHierarchy = flattenPackageHierarchy; - this.repackageClasses = repackageClasses; - this.allowAccessModification = allowAccessModification; - - // Map the root package onto the root package. - packagePrefixMap.put("", ""); - - // Collect all names that have been taken already. - programClassPool.classesAccept(new MyKeepCollector()); - } - - - // Implementations for ClassVisitor. - - public void visitProgramClass(ProgramClass programClass) - { - // Does this class still need a new name? - newClassName = newClassName(programClass); - if (newClassName == null) - { - // Make sure the outer class has a name, if it exists. The name will - // be stored as the new class name, as a side effect, so we'll be - // able to use it as a prefix. - programClass.attributesAccept(this); - - // Figure out a package prefix. The package prefix may actually be - // the an outer class prefix, if any, or it may be the fixed base - // package, if classes are to be repackaged. - String newPackagePrefix = newClassName != null ? - newClassName + ClassConstants.INNER_CLASS_SEPARATOR : - newPackagePrefix(ClassUtil.internalPackagePrefix(programClass.getName())); - - // Come up with a new class name, numeric or ordinary. - newClassName = newClassName != null && numericClassName ? - generateUniqueNumericClassName(newPackagePrefix) : - generateUniqueClassName(newPackagePrefix); - - setNewClassName(programClass, newClassName); - } - } - - - public void visitLibraryClass(LibraryClass libraryClass) - { - // This can happen for dubious input, if the outer class of a program - // class is a library class, and its name is requested. - newClassName = libraryClass.getName(); - } - - - // Implementations for AttributeVisitor. - - public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} - - - public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) - { - // Make sure the outer classes have a name, if they exist. - innerClassesAttribute.innerClassEntriesAccept(clazz, this); - } - - - public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) - { - // Make sure the enclosing class has a name. - enclosingMethodAttribute.referencedClassAccept(this); - - String innerClassName = clazz.getName(); - String outerClassName = clazz.getClassName(enclosingMethodAttribute.u2classIndex); - - numericClassName = isNumericClassName(innerClassName, - outerClassName); - } - - - // Implementations for InnerClassesInfoVisitor. - - public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) - { - // Make sure the outer class has a name, if it exists. - int innerClassIndex = innerClassesInfo.u2innerClassIndex; - int outerClassIndex = innerClassesInfo.u2outerClassIndex; - if (innerClassIndex != 0 && - outerClassIndex != 0) - { - String innerClassName = clazz.getClassName(innerClassIndex); - if (innerClassName.equals(clazz.getName())) - { - clazz.constantPoolEntryAccept(outerClassIndex, this); - - String outerClassName = clazz.getClassName(outerClassIndex); - - numericClassName = isNumericClassName(innerClassName, - outerClassName); - } - } - } - - - /** - * Returns whether the given inner class name is a numeric name. - */ - private boolean isNumericClassName(String innerClassName, - String outerClassName) - { - int innerClassNameStart = outerClassName.length() + 1; - int innerClassNameLength = innerClassName.length(); - - if (innerClassNameStart >= innerClassNameLength) - { - return false; - } - - for (int index = innerClassNameStart; index < innerClassNameLength; index++) - { - if (!Character.isDigit(innerClassName.charAt(index))) - { - return false; - } - } - - return true; - } - - - // Implementations for ConstantVisitor. - - public void visitClassConstant(Clazz clazz, ClassConstant classConstant) - { - // Make sure the outer class has a name. - classConstant.referencedClassAccept(this); - } - - - /** - * This ClassVisitor collects package names and class names that have to - * be kept. - */ - private class MyKeepCollector implements ClassVisitor - { - public void visitProgramClass(ProgramClass programClass) - { - // Does the class already have a new name? - String newClassName = newClassName(programClass); - if (newClassName != null) - { - // Remember not to use this name. - classNamesToAvoid.add(mixedCaseClassName(newClassName)); - - // Are we not aggressively repackaging all obfuscated classes? - if (repackageClasses == null || - !allowAccessModification) - { - String className = programClass.getName(); - - // Keep the package name for all other classes in the same - // package. Do this recursively if we're not doing any - // repackaging. - mapPackageName(className, - newClassName, - repackageClasses == null && - flattenPackageHierarchy == null); - } - } - } - - - public void visitLibraryClass(LibraryClass libraryClass) - { - } - - - /** - * Makes sure the package name of the given class will always be mapped - * consistently with its new name. - */ - private void mapPackageName(String className, - String newClassName, - boolean recursively) - { - String packagePrefix = ClassUtil.internalPackagePrefix(className); - String newPackagePrefix = ClassUtil.internalPackagePrefix(newClassName); - - // Put the mapping of this package prefix, and possibly of its - // entire hierarchy, into the package prefix map. - do - { - packagePrefixMap.put(packagePrefix, newPackagePrefix); - - if (!recursively) - { - break; - } - - packagePrefix = ClassUtil.internalPackagePrefix(packagePrefix); - newPackagePrefix = ClassUtil.internalPackagePrefix(newPackagePrefix); - } - while (packagePrefix.length() > 0 && - newPackagePrefix.length() > 0); - } - } - - - // Small utility methods. - - /** - * Finds or creates the new package prefix for the given package. - */ - private String newPackagePrefix(String packagePrefix) - { - // Doesn't the package prefix have a new package prefix yet? - String newPackagePrefix = (String)packagePrefixMap.get(packagePrefix); - if (newPackagePrefix == null) - { - // Are we keeping the package name? - if (keepPackageNamesMatcher != null && - keepPackageNamesMatcher.matches(packagePrefix.length() > 0 ? - packagePrefix.substring(0, packagePrefix.length()-1) : - packagePrefix)) - { - return packagePrefix; - } - - // Are we forcing a new package prefix? - if (repackageClasses != null) - { - return repackageClasses; - } - - // Are we forcing a new superpackage prefix? - // Otherwise figure out the new superpackage prefix, recursively. - String newSuperPackagePrefix = flattenPackageHierarchy != null ? - flattenPackageHierarchy : - newPackagePrefix(ClassUtil.internalPackagePrefix(packagePrefix)); - - // Come up with a new package prefix. - newPackagePrefix = generateUniquePackagePrefix(newSuperPackagePrefix); - - // Remember to use this mapping in the future. - packagePrefixMap.put(packagePrefix, newPackagePrefix); - } - - return newPackagePrefix; - } - - - /** - * Creates a new package prefix in the given new superpackage. - */ - private String generateUniquePackagePrefix(String newSuperPackagePrefix) - { - // Find the right name factory for this package. - NameFactory packageNameFactory = - (NameFactory)packagePrefixPackageNameFactoryMap.get(newSuperPackagePrefix); - if (packageNameFactory == null) - { - // We haven't seen packages in this superpackage before. Create - // a new name factory for them. - packageNameFactory = new SimpleNameFactory(useMixedCaseClassNames); - if (this.packageNameFactory != null) - { - packageNameFactory = - new DictionaryNameFactory(this.packageNameFactory, - packageNameFactory); - } - - packagePrefixPackageNameFactoryMap.put(newSuperPackagePrefix, - packageNameFactory); - } - - return generateUniquePackagePrefix(newSuperPackagePrefix, packageNameFactory); - } - - - /** - * Creates a new package prefix in the given new superpackage, with the - * given package name factory. - */ - private String generateUniquePackagePrefix(String newSuperPackagePrefix, - NameFactory packageNameFactory) - { - // Come up with package names until we get an original one. - String newPackagePrefix; - do - { - // Let the factory produce a package name. - newPackagePrefix = newSuperPackagePrefix + - packageNameFactory.nextName() + - ClassConstants.PACKAGE_SEPARATOR; - } - while (packagePrefixMap.containsValue(newPackagePrefix)); - - return newPackagePrefix; - } - - - /** - * Creates a new class name in the given new package. - */ - private String generateUniqueClassName(String newPackagePrefix) - { - // Find the right name factory for this package. - NameFactory classNameFactory = - (NameFactory)packagePrefixClassNameFactoryMap.get(newPackagePrefix); - if (classNameFactory == null) - { - // We haven't seen classes in this package before. - // Create a new name factory for them. - classNameFactory = new SimpleNameFactory(useMixedCaseClassNames); - if (this.classNameFactory != null) - { - classNameFactory = - new DictionaryNameFactory(this.classNameFactory, - classNameFactory); - } - - packagePrefixClassNameFactoryMap.put(newPackagePrefix, - classNameFactory); - } - - return generateUniqueClassName(newPackagePrefix, classNameFactory); - } - - - /** - * Creates a new class name in the given new package. - */ - private String generateUniqueNumericClassName(String newPackagePrefix) - { - // Find the right name factory for this package. - NameFactory classNameFactory = - (NameFactory)packagePrefixNumericClassNameFactoryMap.get(newPackagePrefix); - if (classNameFactory == null) - { - // We haven't seen classes in this package before. - // Create a new name factory for them. - classNameFactory = new NumericNameFactory(); - - packagePrefixNumericClassNameFactoryMap.put(newPackagePrefix, - classNameFactory); - } - - return generateUniqueClassName(newPackagePrefix, classNameFactory); - } - - - /** - * Creates a new class name in the given new package, with the given - * class name factory. - */ - private String generateUniqueClassName(String newPackagePrefix, - NameFactory classNameFactory) - { - // Come up with class names until we get an original one. - String newClassName; - String newMixedCaseClassName; - do - { - // Let the factory produce a class name. - newClassName = newPackagePrefix + - classNameFactory.nextName(); - - newMixedCaseClassName = mixedCaseClassName(newClassName); - } - while (classNamesToAvoid.contains(newMixedCaseClassName)); - - // Explicitly make sure the name isn't used again if we have a - // user-specified dictionary and we're not allowed to have mixed case - // class names -- just to protect against problematic dictionaries. - if (this.classNameFactory != null && - !useMixedCaseClassNames) - { - classNamesToAvoid.add(newMixedCaseClassName); - } - - return newClassName; - } - - - /** - * Returns the given class name, unchanged if mixed-case class names are - * allowed, or the lower-case version otherwise. - */ - private String mixedCaseClassName(String className) - { - return useMixedCaseClassNames ? - className : - className.toLowerCase(); - } - - - /** - * Assigns a new name to the given class. - * @param clazz the given class. - * @param name the new name. - */ - static void setNewClassName(Clazz clazz, String name) - { - clazz.setVisitorInfo(name); - } - - - /** - * Retrieves the new name of the given class. - * @param clazz the given class. - * @return the class's new name, or <code>null</code> if it doesn't - * have one yet. - */ - static String newClassName(Clazz clazz) - { - Object visitorInfo = clazz.getVisitorInfo(); - - return visitorInfo instanceof String ? - (String)visitorInfo : - null; - } -} |