proguard4.8/0000775000175000017500000000000011760503015011561 5ustar ericericproguard4.8/src/0000775000175000017500000000000011760503005012347 5ustar ericericproguard4.8/src/proguard/0000775000175000017500000000000011760503005014172 5ustar ericericproguard4.8/src/proguard/package.html0000644000175000017500000000024211736333522016457 0ustar ericeric This package contains the main ProGuard application. ProGuard can read jar files, shrink and obfuscate them, and write out the resulting jar file. proguard4.8/src/proguard/shrink/0000775000175000017500000000000011760503005015470 5ustar ericericproguard4.8/src/proguard/shrink/package.html0000644000175000017500000000012211736333522017752 0ustar ericeric This package contains classes to perform shrinking of class files. proguard4.8/src/proguard/shrink/ShortestUsageMarker.java0000644000175000017500000002176311736333522022314 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.visitor.*; /** * This ClassVisitor and MemberVisitor recursively marks all classes * and class elements that are being used. For each element, it finds the * shortest chain of dependencies. * * @see ClassShrinker * * @author Eric Lafortune */ public class ShortestUsageMarker extends UsageMarker { private static final ShortestUsageMark INITIAL_MARK = new ShortestUsageMark("is kept by a directive in the configuration.\n\n"); // A field acting as a parameter to the visitor methods. private ShortestUsageMark currentUsageMark = INITIAL_MARK; // A utility object to check for recursive causes. private final MyRecursiveCauseChecker recursiveCauseChecker = new MyRecursiveCauseChecker(); // Overriding implementations for UsageMarker. protected void markProgramClassBody(ProgramClass programClass) { ShortestUsageMark previousUsageMark = currentUsageMark; currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programClass), "is extended by ", 10000, programClass); super.markProgramClassBody(programClass); currentUsageMark = previousUsageMark; } protected void markProgramFieldBody(ProgramClass programClass, ProgramField programField) { ShortestUsageMark previousUsageMark = currentUsageMark; currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programField), "is referenced by ", 1, programClass, programField); super.markProgramFieldBody(programClass, programField); currentUsageMark = previousUsageMark; } protected void markProgramMethodBody(ProgramClass programClass, ProgramMethod programMethod) { ShortestUsageMark previousUsageMark = currentUsageMark; currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programMethod), "is invoked by ", 1, programClass, programMethod); super.markProgramMethodBody(programClass, programMethod); currentUsageMark = previousUsageMark; } protected void markMethodHierarchy(Clazz clazz, Method method) { ShortestUsageMark previousUsageMark = currentUsageMark; currentUsageMark = new ShortestUsageMark(getShortestUsageMark(method), "implements ", 100, clazz, method); super.markMethodHierarchy(clazz, method); currentUsageMark = previousUsageMark; } // Small utility methods. protected void markAsUsed(VisitorAccepter visitorAccepter) { Object visitorInfo = visitorAccepter.getVisitorInfo(); ShortestUsageMark shortestUsageMark = visitorInfo != null && visitorInfo instanceof ShortestUsageMark && !((ShortestUsageMark)visitorInfo).isCertain() && !currentUsageMark.isShorter((ShortestUsageMark)visitorInfo) ? new ShortestUsageMark((ShortestUsageMark)visitorInfo, true): currentUsageMark; visitorAccepter.setVisitorInfo(shortestUsageMark); } protected boolean shouldBeMarkedAsUsed(VisitorAccepter visitorAccepter) { Object visitorInfo = visitorAccepter.getVisitorInfo(); return //!(visitorAccepter instanceof Clazz && // isCausedBy(currentUsageMark, (Clazz)visitorAccepter)) && (visitorInfo == null || !(visitorInfo instanceof ShortestUsageMark) || !((ShortestUsageMark)visitorInfo).isCertain() || currentUsageMark.isShorter((ShortestUsageMark)visitorInfo)); } protected boolean isUsed(VisitorAccepter visitorAccepter) { Object visitorInfo = visitorAccepter.getVisitorInfo(); return visitorInfo != null && visitorInfo instanceof ShortestUsageMark && ((ShortestUsageMark)visitorInfo).isCertain(); } protected void markAsPossiblyUsed(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(new ShortestUsageMark(currentUsageMark, false)); } protected boolean shouldBeMarkedAsPossiblyUsed(VisitorAccepter visitorAccepter) { Object visitorInfo = visitorAccepter.getVisitorInfo(); return visitorInfo == null || !(visitorInfo instanceof ShortestUsageMark) || (!((ShortestUsageMark)visitorInfo).isCertain() && currentUsageMark.isShorter((ShortestUsageMark)visitorInfo)); } protected boolean isPossiblyUsed(VisitorAccepter visitorAccepter) { Object visitorInfo = visitorAccepter.getVisitorInfo(); return visitorInfo != null && visitorInfo instanceof ShortestUsageMark && !((ShortestUsageMark)visitorInfo).isCertain(); } protected ShortestUsageMark getShortestUsageMark(VisitorAccepter visitorAccepter) { Object visitorInfo = visitorAccepter.getVisitorInfo(); return (ShortestUsageMark)visitorInfo; } // Small utility methods. private boolean isCausedBy(ShortestUsageMark shortestUsageMark, Clazz clazz) { return recursiveCauseChecker.check(shortestUsageMark, clazz); } private class MyRecursiveCauseChecker implements ClassVisitor, MemberVisitor { private Clazz checkClass; private boolean isRecursing; public boolean check(ShortestUsageMark shortestUsageMark, Clazz clazz) { checkClass = clazz; isRecursing = false; shortestUsageMark.acceptClassVisitor(this); shortestUsageMark.acceptMemberVisitor(this); return isRecursing; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { checkCause(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { checkCause(libraryClass); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { checkCause(programField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { checkCause(programMethod); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { checkCause(libraryField); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { checkCause(libraryMethod); } // Small utility methods. private void checkCause(VisitorAccepter visitorAccepter) { if (ShortestUsageMarker.this.isUsed(visitorAccepter)) { ShortestUsageMark shortestUsageMark = ShortestUsageMarker.this.getShortestUsageMark(visitorAccepter); // Check the class of this mark, if any isRecursing = shortestUsageMark.isCausedBy(checkClass); // Check the causing class or method, if still necessary. if (!isRecursing) { shortestUsageMark.acceptClassVisitor(this); shortestUsageMark.acceptMemberVisitor(this); } } } } } proguard4.8/src/proguard/shrink/ShortestUsagePrinter.java0000644000175000017500000001635611736333522022520 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.util.ClassUtil; import proguard.classfile.visitor.*; import java.io.PrintStream; /** * This ClassVisitor and MemberVisitor prints out the reasons why * classes and class members have been marked as being used. * * @see UsageMarker * * @author Eric Lafortune */ public class ShortestUsagePrinter implements ClassVisitor, MemberVisitor { private final ShortestUsageMarker shortestUsageMarker; private final boolean verbose; private final PrintStream ps; /** * Creates a new UsagePrinter that prints verbosely to System.out. * @param shortestUsageMarker the usage marker that was used to mark the * classes and class members. */ public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker) { this(shortestUsageMarker, true); } /** * Creates a new UsagePrinter that prints to the given stream. * @param shortestUsageMarker the usage marker that was used to mark the * classes and class members. * @param verbose specifies whether the output should be verbose. */ public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker, boolean verbose) { this(shortestUsageMarker, verbose, System.out); } /** * Creates a new UsagePrinter that prints to the given stream. * @param shortestUsageMarker the usage marker that was used to mark the * classes and class members. * @param verbose specifies whether the output should be verbose. * @param printStream the stream to which to print. */ public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker, boolean verbose, PrintStream printStream) { this.shortestUsageMarker = shortestUsageMarker; this.verbose = verbose; this.ps = printStream; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Print the name of this class. ps.println(ClassUtil.externalClassName(programClass.getName())); // Print the reason for keeping this class. printReason(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { // Print the name of this class. ps.println(ClassUtil.externalClassName(libraryClass.getName())); // Print the reason for keeping this class. ps.println(" is a library class.\n"); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Print the name of this field. String name = programField.getName(programClass); String type = programField.getDescriptor(programClass); ps.println(ClassUtil.externalClassName(programClass.getName()) + (verbose ? ": " + ClassUtil.externalFullFieldDescription(0, name, type): "." + name) + lineNumberRange(programClass, programField)); // Print the reason for keeping this method. printReason(programField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Print the name of this method. String name = programMethod.getName(programClass); String type = programMethod.getDescriptor(programClass); ps.println(ClassUtil.externalClassName(programClass.getName()) + (verbose ? ": " + ClassUtil.externalFullMethodDescription(programClass.getName(), 0, name, type): "." + name) + lineNumberRange(programClass, programMethod)); // Print the reason for keeping this method. printReason(programMethod); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { // Print the name of this field. String name = libraryField.getName(libraryClass); String type = libraryField.getDescriptor(libraryClass); ps.println(ClassUtil.externalClassName(libraryClass.getName()) + (verbose ? ": " + ClassUtil.externalFullFieldDescription(0, name, type): "." + name)); // Print the reason for keeping this field. ps.println(" is a library field.\n"); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { // Print the name of this method. String name = libraryMethod.getName(libraryClass); String type = libraryMethod.getDescriptor(libraryClass); ps.println(ClassUtil.externalClassName(libraryClass.getName()) + (verbose ? ": " + ClassUtil.externalFullMethodDescription(libraryClass.getName(), 0, name, type): "." + name)); // Print the reason for keeping this method. ps.println(" is a library method.\n"); } // Small utility methods. private void printReason(VisitorAccepter visitorAccepter) { if (shortestUsageMarker.isUsed(visitorAccepter)) { ShortestUsageMark shortestUsageMark = shortestUsageMarker.getShortestUsageMark(visitorAccepter); // Print the reason for keeping this class. ps.print(" " + shortestUsageMark.getReason()); // Print the class or method that is responsible, with its reasons. shortestUsageMark.acceptClassVisitor(this); shortestUsageMark.acceptMemberVisitor(this); } else { ps.println(" is not being kept.\n"); } } /** * Returns the line number range of the given class member, followed by a * colon, or just an empty String if no range is available. */ private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember) { String range = programMember.getLineNumberRange(programClass); return range != null ? (" (" + range + ")") : ""; } } proguard4.8/src/proguard/shrink/UsedMemberFilter.java0000644000175000017500000000550011736333522021537 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.visitor.MemberVisitor; /** * This MemberVisitor delegates all its method calls to another MemberVisitor, * but only for Member objects that are marked as used. * * @see UsageMarker * * @author Eric Lafortune */ public class UsedMemberFilter implements MemberVisitor { private final UsageMarker usageMarker; private final MemberVisitor memberVisitor; /** * Creates a new UsedMemberFilter. * @param usageMarker the usage marker that is used to mark the classes * and class members. * @param memberVisitor the member visitor to which the visiting will be * delegated. */ public UsedMemberFilter(UsageMarker usageMarker, MemberVisitor memberVisitor) { this.usageMarker = usageMarker; this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (usageMarker.isUsed(programField)) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (usageMarker.isUsed(programMethod)) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (usageMarker.isUsed(libraryField)) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (usageMarker.isUsed(libraryMethod)) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } } proguard4.8/src/proguard/shrink/UsedClassFilter.java0000644000175000017500000000434511736333522021403 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor delegates all its method calls to another ClassVisitor, * but only for Clazz objects that are marked as used. * * @see UsageMarker * * @author Eric Lafortune */ public class UsedClassFilter implements ClassVisitor { private final UsageMarker usageMarker; private final ClassVisitor classVisitor; /** * Creates a new UsedClassFilter. * @param usageMarker the usage marker that is used to mark the classes * and class members. * @param classVisitor the class visitor to which the visiting will be * delegated. */ public UsedClassFilter(UsageMarker usageMarker, ClassVisitor classVisitor) { this.usageMarker = usageMarker; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (usageMarker.isUsed(programClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (usageMarker.isUsed(libraryClass)) { classVisitor.visitLibraryClass(libraryClass); } } } proguard4.8/src/proguard/shrink/UsageMarker.java0000644000175000017500000010560611736333522020557 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** * This ClassVisitor and MemberVisitor recursively marks all classes and class * elements that are being used. * * @see ClassShrinker * * @author Eric Lafortune */ class UsageMarker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor, InnerClassesInfoVisitor, ExceptionInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, // AnnotationVisitor, // ElementValueVisitor, InstructionVisitor { // A visitor info flag to indicate the ProgramMember object is being used, // if its Clazz can be determined as being used as well. private static final Object POSSIBLY_USED = new Object(); // A visitor info flag to indicate the visitor accepter is being used. private static final Object USED = new Object(); private final MyInterfaceUsageMarker interfaceUsageMarker = new MyInterfaceUsageMarker(); private final MyPossiblyUsedMemberUsageMarker possiblyUsedMemberUsageMarker = new MyPossiblyUsedMemberUsageMarker(); private final MemberVisitor nonEmptyMethodUsageMarker = new AllAttributeVisitor( new MyNonEmptyMethodUsageMarker()); private final ConstantVisitor parameterlessConstructorMarker = new ConstantTagFilter(new int[] { ClassConstants.CONSTANT_String, ClassConstants.CONSTANT_Class }, new ReferencedClassVisitor( new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT, ClassConstants.INTERNAL_METHOD_TYPE_INIT, this))); // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (shouldBeMarkedAsUsed(programClass)) { // Mark this class. markAsUsed(programClass); markProgramClassBody(programClass); } } protected void markProgramClassBody(ProgramClass programClass) { // Mark this class's name. markConstant(programClass, programClass.u2thisClass); // Mark the superclass. if (programClass.u2superClass != 0) { markConstant(programClass, programClass.u2superClass); } // Give the interfaces preliminary marks. programClass.hierarchyAccept(false, false, true, false, interfaceUsageMarker); // Explicitly mark the method, if it's not empty. programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, ClassConstants.INTERNAL_METHOD_TYPE_CLINIT, nonEmptyMethodUsageMarker); // Process all class members that have already been marked as possibly used. programClass.fieldsAccept(possiblyUsedMemberUsageMarker); programClass.methodsAccept(possiblyUsedMemberUsageMarker); // Mark the attributes. programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { if (shouldBeMarkedAsUsed(libraryClass)) { markAsUsed(libraryClass); // We're not going to analyze all library code. We're assuming that // if this class is being used, all of its methods will be used as // well. We'll mark them as such (here and in all subclasses). // Mark the superclass. Clazz superClass = libraryClass.superClass; if (superClass != null) { superClass.accept(this); } // Mark the interfaces. Clazz[] interfaceClasses = libraryClass.interfaceClasses; if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { if (interfaceClasses[index] != null) { interfaceClasses[index].accept(this); } } } // Mark all methods. libraryClass.methodsAccept(this); } } /** * This ClassVisitor marks ProgramClass objects as possibly used, * and it visits LibraryClass objects with its outer UsageMarker. */ private class MyInterfaceUsageMarker implements ClassVisitor { public void visitProgramClass(ProgramClass programClass) { if (shouldBeMarkedAsPossiblyUsed(programClass)) { // We can't process the interface yet, because it might not // be required. Give it a preliminary mark. markAsPossiblyUsed(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { // Make sure all library interface methods are marked. UsageMarker.this.visitLibraryClass(libraryClass); } } /** * This MemberVisitor marks ProgramField and ProgramMethod objects that * have already been marked as possibly used. */ private class MyPossiblyUsedMemberUsageMarker extends SimplifiedVisitor implements MemberVisitor { // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Has the method already been referenced? if (isPossiblyUsed(programField)) { markAsUsed(programField); // Mark the name and descriptor. markConstant(programClass, programField.u2nameIndex); markConstant(programClass, programField.u2descriptorIndex); // Mark the attributes. programField.attributesAccept(programClass, UsageMarker.this); // Mark the classes referenced in the descriptor string. programField.referencedClassesAccept(UsageMarker.this); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Has the method already been referenced? if (isPossiblyUsed(programMethod)) { markAsUsed(programMethod); // Mark the method body. markProgramMethodBody(programClass, programMethod); // Note that, if the method has been marked as possibly used, // the method hierarchy has already been marked (cfr. below). } } } /** * This AttributeVisitor marks ProgramMethod objects of non-empty methods. */ private class MyNonEmptyMethodUsageMarker extends SimplifiedVisitor implements AttributeVisitor { // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (codeAttribute.u4codeLength > 1) { method.accept(clazz, UsageMarker.this); } } } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (shouldBeMarkedAsUsed(programField)) { // Is the field's class used? if (isUsed(programClass)) { markAsUsed(programField); // Mark the field body. markProgramFieldBody(programClass, programField); } // Hasn't the field been marked as possibly being used yet? else if (shouldBeMarkedAsPossiblyUsed(programField)) { // We can't process the field yet, because the class isn't // marked as being used (yet). Give it a preliminary mark. markAsPossiblyUsed(programField); } } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (shouldBeMarkedAsUsed(programMethod)) { // Is the method's class used? if (isUsed(programClass)) { markAsUsed(programMethod); // Mark the method body. markProgramMethodBody(programClass, programMethod); // Mark the method hierarchy. markMethodHierarchy(programClass, programMethod); } // Hasn't the method been marked as possibly being used yet? else if (shouldBeMarkedAsPossiblyUsed(programMethod)) { // We can't process the method yet, because the class isn't // marked as being used (yet). Give it a preliminary mark. markAsPossiblyUsed(programMethod); // Mark the method hierarchy. markMethodHierarchy(programClass, programMethod); } } } public void visitLibraryField(LibraryClass programClass, LibraryField programField) {} public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (shouldBeMarkedAsUsed(libraryMethod)) { markAsUsed(libraryMethod); // Mark the method hierarchy. markMethodHierarchy(libraryClass, libraryMethod); } } protected void markProgramFieldBody(ProgramClass programClass, ProgramField programField) { // Mark the name and descriptor. markConstant(programClass, programField.u2nameIndex); markConstant(programClass, programField.u2descriptorIndex); // Mark the attributes. programField.attributesAccept(programClass, this); // Mark the classes referenced in the descriptor string. programField.referencedClassesAccept(this); } protected void markProgramMethodBody(ProgramClass programClass, ProgramMethod programMethod) { // Mark the name and descriptor. markConstant(programClass, programMethod.u2nameIndex); markConstant(programClass, programMethod.u2descriptorIndex); // Mark the attributes. programMethod.attributesAccept(programClass, this); // Mark the classes referenced in the descriptor string. programMethod.referencedClassesAccept(this); } /** * Marks the hierarchy of implementing or overriding methods corresponding * to the given method, if any. */ protected void markMethodHierarchy(Clazz clazz, Method method) { if ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC)) == 0 && !ClassUtil.isInitializer(method.getName(clazz))) { clazz.accept(new ConcreteClassDownTraveler( new ClassHierarchyTraveler(true, true, false, true, new NamedMethodVisitor(method.getName(clazz), method.getDescriptor(clazz), new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT, this))))); } } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { if (shouldBeMarkedAsUsed(integerConstant)) { markAsUsed(integerConstant); } } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { if (shouldBeMarkedAsUsed(longConstant)) { markAsUsed(longConstant); } } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { if (shouldBeMarkedAsUsed(floatConstant)) { markAsUsed(floatConstant); } } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { if (shouldBeMarkedAsUsed(doubleConstant)) { markAsUsed(doubleConstant); } } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { if (shouldBeMarkedAsUsed(stringConstant)) { markAsUsed(stringConstant); markConstant(clazz, stringConstant.u2stringIndex); // Mark the referenced class and class member, if any. stringConstant.referencedClassAccept(this); stringConstant.referencedMemberAccept(this); } } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { if (shouldBeMarkedAsUsed(utf8Constant)) { markAsUsed(utf8Constant); } } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { if (shouldBeMarkedAsUsed(invokeDynamicConstant)) { markAsUsed(invokeDynamicConstant); markConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); // Mark the bootstrap methods attribute. clazz.attributesAccept(new MyBootStrapMethodUsageMarker(invokeDynamicConstant.u2bootstrapMethodAttributeIndex)); } } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { if (shouldBeMarkedAsUsed(methodHandleConstant)) { markAsUsed(methodHandleConstant); markConstant(clazz, methodHandleConstant.u2referenceIndex); } } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { if (shouldBeMarkedAsUsed(refConstant)) { markAsUsed(refConstant); markConstant(clazz, refConstant.u2classIndex); markConstant(clazz, refConstant.u2nameAndTypeIndex); // When compiled with "-target 1.2" or higher, the class or // interface actually containing the referenced class member may // be higher up the hierarchy. Make sure it's marked, in case it // isn't used elsewhere. refConstant.referencedClassAccept(this); // Mark the referenced class member itself. refConstant.referencedMemberAccept(this); } } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { if (shouldBeMarkedAsUsed(classConstant)) { markAsUsed(classConstant); markConstant(clazz, classConstant.u2nameIndex); // Mark the referenced class itself. classConstant.referencedClassAccept(this); } } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { if (shouldBeMarkedAsUsed(methodTypeConstant)) { markAsUsed(methodTypeConstant); markConstant(clazz, methodTypeConstant.u2descriptorIndex); } } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { if (shouldBeMarkedAsUsed(nameAndTypeConstant)) { markAsUsed(nameAndTypeConstant); markConstant(clazz, nameAndTypeConstant.u2nameIndex); markConstant(clazz, nameAndTypeConstant.u2descriptorIndex); } } /** * This AttributeVisitor marks the bootstrap methods attributes, their * method entries, their method handles, and their arguments. */ private class MyBootStrapMethodUsageMarker extends SimplifiedVisitor implements AttributeVisitor, BootstrapMethodInfoVisitor { private int bootstrapMethodIndex; private MyBootStrapMethodUsageMarker(int bootstrapMethodIndex) { this.bootstrapMethodIndex = bootstrapMethodIndex; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { if (shouldBeMarkedAsUsed(bootstrapMethodsAttribute)) { markAsUsed(bootstrapMethodsAttribute); markConstant(clazz, bootstrapMethodsAttribute.u2attributeNameIndex); bootstrapMethodsAttribute.bootstrapMethodEntryAccept(clazz, bootstrapMethodIndex, this); } } // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { markAsUsed(bootstrapMethodInfo); markConstant(clazz, bootstrapMethodInfo.u2methodHandleIndex); // Mark the constant pool entries referenced by the arguments. bootstrapMethodInfo.methodArgumentsAccept(clazz, UsageMarker.this); } } // Implementations for AttributeVisitor. // Note that attributes are typically only referenced once, so we don't // test if they have been marked already. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { // This is the best we can do for unknown attributes. markAsUsed(unknownAttribute); markConstant(clazz, unknownAttribute.u2attributeNameIndex); } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { // Don't mark the attribute and its name here. We may mark it in // MyBootStrapMethodsAttributeUsageMarker. } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { markAsUsed(sourceFileAttribute); markConstant(clazz, sourceFileAttribute.u2attributeNameIndex); markConstant(clazz, sourceFileAttribute.u2sourceFileIndex); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { markAsUsed(sourceDirAttribute); markConstant(clazz, sourceDirAttribute.u2attributeNameIndex); markConstant(clazz, sourceDirAttribute.u2sourceDirIndex); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Don't mark the attribute and its name yet. We may mark it later, in // InnerUsageMarker. //markAsUsed(innerClassesAttribute); //markConstant(clazz, innerClassesAttribute.u2attrNameIndex); // Do mark the outer class entries. innerClassesAttribute.innerClassEntriesAccept(clazz, this); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { markAsUsed(enclosingMethodAttribute); markConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex); markConstant(clazz, enclosingMethodAttribute.u2classIndex); if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) { markConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex); } } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { markAsUsed(deprecatedAttribute); markConstant(clazz, deprecatedAttribute.u2attributeNameIndex); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { markAsUsed(syntheticAttribute); markConstant(clazz, syntheticAttribute.u2attributeNameIndex); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { markAsUsed(signatureAttribute); markConstant(clazz, signatureAttribute.u2attributeNameIndex); markConstant(clazz, signatureAttribute.u2signatureIndex); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { markAsUsed(constantValueAttribute); markConstant(clazz, constantValueAttribute.u2attributeNameIndex); markConstant(clazz, constantValueAttribute.u2constantValueIndex); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { markAsUsed(exceptionsAttribute); markConstant(clazz, exceptionsAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the exceptions. exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { markAsUsed(codeAttribute); markConstant(clazz, codeAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the instructions, // by the exceptions, and by the attributes. codeAttribute.instructionsAccept(clazz, method, this); codeAttribute.exceptionsAccept(clazz, method, this); codeAttribute.attributesAccept(clazz, method, this); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { markAsUsed(stackMapAttribute); markConstant(clazz, stackMapAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the stack map frames. stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { markAsUsed(stackMapTableAttribute); markConstant(clazz, stackMapTableAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the stack map frames. stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { markAsUsed(lineNumberTableAttribute); markConstant(clazz, lineNumberTableAttribute.u2attributeNameIndex); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { markAsUsed(localVariableTableAttribute); markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { markAsUsed(localVariableTypeTableAttribute); markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the local variable types. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Don't mark the attribute and its contents yet. We may mark them later, // in AnnotationUsageMarker. // markAsUsed(annotationsAttribute); // // markConstant(clazz, annotationsAttribute.u2attributeNameIndex); // // // Mark the constant pool entries referenced by the annotations. // annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Don't mark the attribute and its contents yet. We may mark them later, // in AnnotationUsageMarker. // markAsUsed(parameterAnnotationsAttribute); // // markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); // // // Mark the constant pool entries referenced by the annotations. // parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Don't mark the attribute and its contents yet. We may mark them later, // in AnnotationUsageMarker. // markAsUsed(annotationDefaultAttribute); // // markConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex); // // // Mark the constant pool entries referenced by the element value. // annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { markAsUsed(exceptionInfo); if (exceptionInfo.u2catchType != 0) { markConstant(clazz, exceptionInfo.u2catchType); } } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { // At this point, we only mark outer classes of this class. // Inner class can be marked later, by InnerUsageMarker. if (innerClassesInfo.u2innerClassIndex != 0 && clazz.getName().equals(clazz.getClassName(innerClassesInfo.u2innerClassIndex))) { markAsUsed(innerClassesInfo); innerClassesInfo.innerClassConstantAccept(clazz, this); innerClassesInfo.outerClassConstantAccept(clazz, this); innerClassesInfo.innerNameConstantAccept(clazz, this); } } // Implementations for StackMapFrameVisitor. public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {} public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { // Mark the constant pool entries referenced by the verification types. sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { // Mark the constant pool entries referenced by the verification types. moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { // Mark the constant pool entries referenced by the verification types. fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) { markConstant(clazz, objectType.u2classIndex); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { markConstant(clazz, localVariableInfo.u2nameIndex); markConstant(clazz, localVariableInfo.u2descriptorIndex); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { markConstant(clazz, localVariableTypeInfo.u2nameIndex); markConstant(clazz, localVariableTypeInfo.u2signatureIndex); } // // Implementations for AnnotationVisitor. // // public void visitAnnotation(Clazz clazz, Annotation annotation) // { // markConstant(clazz, annotation.u2typeIndex); // // // Mark the constant pool entries referenced by the element values. // annotation.elementValuesAccept(clazz, this); // } // // // // Implementations for ElementValueVisitor. // // public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) // { // if (constantElementValue.u2elementNameIndex != 0) // { // markConstant(clazz, constantElementValue.u2elementNameIndex); // } // // markConstant(clazz, constantElementValue.u2constantValueIndex); // } // // // public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) // { // if (enumConstantElementValue.u2elementNameIndex != 0) // { // markConstant(clazz, enumConstantElementValue.u2elementNameIndex); // } // // markConstant(clazz, enumConstantElementValue.u2typeNameIndex); // markConstant(clazz, enumConstantElementValue.u2constantNameIndex); // } // // // public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) // { // if (classElementValue.u2elementNameIndex != 0) // { // markConstant(clazz, classElementValue.u2elementNameIndex); // } // // // Mark the referenced class constant pool entry. // markConstant(clazz, classElementValue.u2classInfoIndex); // } // // // public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) // { // if (annotationElementValue.u2elementNameIndex != 0) // { // markConstant(clazz, annotationElementValue.u2elementNameIndex); // } // // // Mark the constant pool entries referenced by the annotation. // annotationElementValue.annotationAccept(clazz, this); // } // // // public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) // { // if (arrayElementValue.u2elementNameIndex != 0) // { // markConstant(clazz, arrayElementValue.u2elementNameIndex); // } // // // Mark the constant pool entries referenced by the element values. // arrayElementValue.elementValuesAccept(clazz, annotation, this); // } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { markConstant(clazz, constantInstruction.constantIndex); // Also mark the parameterless constructor of the class, in case the // string constant or class constant is being used in a Class.forName // or a .class construct. clazz.constantPoolEntryAccept(constantInstruction.constantIndex, parameterlessConstructorMarker); } // Small utility methods. /** * Marks the given visitor accepter as being used. */ protected void markAsUsed(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(USED); } /** * Returns whether the given visitor accepter should still be marked as * being used. */ protected boolean shouldBeMarkedAsUsed(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() != USED; } /** * Returns whether the given visitor accepter has been marked as being used. */ protected boolean isUsed(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() == USED; } /** * Marks the given visitor accepter as possibly being used. */ protected void markAsPossiblyUsed(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(POSSIBLY_USED); } /** * Returns whether the given visitor accepter should still be marked as * possibly being used. */ protected boolean shouldBeMarkedAsPossiblyUsed(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() != USED && visitorAccepter.getVisitorInfo() != POSSIBLY_USED; } /** * Returns whether the given visitor accepter has been marked as possibly * being used. */ protected boolean isPossiblyUsed(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() == POSSIBLY_USED; } /** * Clears any usage marks from the given visitor accepter. */ protected void markAsUnused(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(null); } /** * Marks the given constant pool entry of the given class. This includes * visiting any referenced objects. */ private void markConstant(Clazz clazz, int index) { clazz.constantPoolEntryAccept(index, this); } } proguard4.8/src/proguard/shrink/ShortestUsageMark.java0000644000175000017500000001236011736333522021756 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.visitor.*; /** * This class can be used as a mark when keeping classes, class members, and * other elements. It can be certain or preliminary. It also contains additional * information about the reasons why an element is being kept. * * @see ClassShrinker * * @author Eric Lafortune */ final class ShortestUsageMark { private final boolean certain; private final String reason; private final int depth; private Clazz clazz; private Member member; /** * Creates a new certain ShortestUsageMark. * @param reason the reason for this mark. */ public ShortestUsageMark(String reason) { this.certain = true; this.reason = reason; this.depth = 0; } /** * Creates a new certain ShortestUsageMark. * @param previousUsageMark the previous mark to which this one is linked. * @param reason the reason for this mark. * @param clazz the class causing this mark. */ public ShortestUsageMark(ShortestUsageMark previousUsageMark, String reason, int cost, Clazz clazz) { this(previousUsageMark, reason, cost, clazz, null); } /** * Creates a new certain ShortestUsageMark. * @param previousUsageMark the previous mark to which this one is linked. * @param reason the reason for this mark. * @param clazz the class causing this mark. * @param member the member in the above class causing this mark. * @param cost the added cost of following this path. */ public ShortestUsageMark(ShortestUsageMark previousUsageMark, String reason, int cost, Clazz clazz, Member member) { this.certain = true; this.reason = reason; this.depth = previousUsageMark.depth + cost; this.clazz = clazz; this.member = member; } /** * Creates a new ShortestUsageMark, based on another mark. * @param otherUsageMark the other mark, whose properties will be copied. * @param certain specifies whether this is a certain mark. */ public ShortestUsageMark(ShortestUsageMark otherUsageMark, boolean certain) { this.certain = certain; this.reason = otherUsageMark.reason; this.depth = otherUsageMark.depth; this.clazz = otherUsageMark.clazz; this.member = otherUsageMark.member; } /** * Returns whether this is a certain mark. */ public boolean isCertain() { return certain; } /** * Returns the reason for this mark. */ public String getReason() { return reason; } /** * Returns whether this mark has a shorter chain of reasons than the * given mark. */ public boolean isShorter(ShortestUsageMark otherUsageMark) { return this.depth < otherUsageMark.depth; } /** * Returns whether this is mark is caused by the given class. */ public boolean isCausedBy(Clazz clazz) { return clazz.equals(this.clazz); } /** * Applies the given class visitor to this mark's class, if any, * and if this mark doesn't have a member. */ public void acceptClassVisitor(ClassVisitor classVisitor) { if (clazz != null && member == null) { clazz.accept(classVisitor); } } /** * Applies the given class visitor to this mark's member, if any. */ public void acceptMemberVisitor(MemberVisitor memberVisitor) { if (clazz != null && member != null) { member.accept(clazz, memberVisitor); } } // Implementations for Object. public String toString() { return "certain=" + certain + ", depth="+depth+": " + reason + (clazz != null ? clazz.getName() : "(none)") + ": " + (member != null ? member.getName(clazz) : "(none)"); } } proguard4.8/src/proguard/shrink/ClassShrinker.java0000644000175000017500000003666411736333522021133 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.editor.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.util.Arrays; /** * This ClassVisitor removes constant pool entries, class members, and other * class elements that are not marked as being used. * * @see UsageMarker * * @author Eric Lafortune */ public class ClassShrinker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, AttributeVisitor, AnnotationVisitor, ElementValueVisitor { private final UsageMarker usageMarker; private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); /** * Creates a new ClassShrinker. * @param usageMarker the usage marker that is used to mark the classes * and class members. */ public ClassShrinker(UsageMarker usageMarker) { this.usageMarker = usageMarker; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Shrink the arrays for constant pool, interfaces, fields, methods, // and class attributes. programClass.u2interfacesCount = shrinkConstantIndexArray(programClass.constantPool, programClass.u2interfaces, programClass.u2interfacesCount); // Shrinking the constant pool also sets up an index map. int newConstantPoolCount = shrinkConstantPool(programClass.constantPool, programClass.u2constantPoolCount); programClass.u2fieldsCount = shrinkArray(programClass.fields, programClass.u2fieldsCount); programClass.u2methodsCount = shrinkArray(programClass.methods, programClass.u2methodsCount); programClass.u2attributesCount = shrinkArray(programClass.attributes, programClass.u2attributesCount); // Compact the remaining fields, methods, and attributes, // and remap their references to the constant pool. programClass.fieldsAccept(this); programClass.methodsAccept(this); programClass.attributesAccept(this); // Remap the references to the constant pool if it has shrunk. if (newConstantPoolCount < programClass.u2constantPoolCount) { programClass.u2constantPoolCount = newConstantPoolCount; // Remap all constant pool references. constantPoolRemapper.setConstantIndexMap(constantIndexMap); constantPoolRemapper.visitProgramClass(programClass); } // Remove the unused interfaces from the class signature. programClass.attributesAccept(new SignatureShrinker()); // Compact the extra field pointing to the subclasses of this class. programClass.subClasses = shrinkToNewArray(programClass.subClasses); } public void visitLibraryClass(LibraryClass libraryClass) { // Library classes are left unchanged. // Compact the extra field pointing to the subclasses of this class. libraryClass.subClasses = shrinkToNewArray(libraryClass.subClasses); } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { // Shrink the attributes array. programMember.u2attributesCount = shrinkArray(programMember.attributes, programMember.u2attributesCount); // Shrink any attributes. programMember.attributesAccept(programClass, this); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { // Shrink the array of BootstrapMethodInfo objects. bootstrapMethodsAttribute.u2bootstrapMethodsCount = shrinkArray(bootstrapMethodsAttribute.bootstrapMethods, bootstrapMethodsAttribute.u2bootstrapMethodsCount); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Shrink the array of InnerClassesInfo objects. innerClassesAttribute.u2classesCount = shrinkArray(innerClassesAttribute.classes, innerClassesAttribute.u2classesCount); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { // Sometimes, a class is still referenced (apparently as a dummy class), // but its enclosing method is not. Then remove the reference to // the enclosing method. // E.g. the anonymous inner class javax.swing.JList$1 is defined inside // a constructor of javax.swing.JList, but it is also referenced as a // dummy argument in a constructor of javax.swing.JList$ListSelectionHandler. if (enclosingMethodAttribute.referencedMethod != null && !usageMarker.isUsed(enclosingMethodAttribute.referencedMethod)) { enclosingMethodAttribute.u2nameAndTypeIndex = 0; enclosingMethodAttribute.referencedMethod = null; } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Shrink the attributes array. codeAttribute.u2attributesCount = shrinkArray(codeAttribute.attributes, codeAttribute.u2attributesCount); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Shrink the annotations array. annotationsAttribute.u2annotationsCount = shrinkArray(annotationsAttribute.annotations, annotationsAttribute.u2annotationsCount); // Shrink the annotations themselves. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Loop over all parameters. for (int parameterIndex = 0; parameterIndex < parameterAnnotationsAttribute.u2parametersCount; parameterIndex++) { // Shrink the parameter annotations array. parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex] = shrinkArray(parameterAnnotationsAttribute.parameterAnnotations[parameterIndex], parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex]); } // Shrink the annotations themselves. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { // Shrink the element values array. annotation.u2elementValuesCount = shrinkArray(annotation.elementValues, annotation.u2elementValuesCount); // Shrink the element values themselves. annotation.elementValuesAccept(clazz, this); } /** * This AttributeVisitor updates the Utf8 constants of class signatures, * removing any unused interfaces. */ private class SignatureShrinker extends SimplifiedVisitor implements AttributeVisitor { public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { Clazz[] referencedClasses = signatureAttribute.referencedClasses; if (referencedClasses != null) { // Go over the generic definitions, superclass and implemented interfaces. String signature = clazz.getString(signatureAttribute.u2signatureIndex); InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(signature); StringBuffer newSignatureBuffer = new StringBuffer(); int referencedClassIndex = 0; int newReferencedClassIndex = 0; while (internalTypeEnumeration.hasMoreTypes()) { // Consider the classes referenced by this signature. String type = internalTypeEnumeration.nextType(); int classCount = new DescriptorClassEnumeration(type).classCount(); Clazz referencedClass = referencedClasses[referencedClassIndex]; if (referencedClass == null || usageMarker.isUsed(referencedClass)) { // Append the superclass or interface. newSignatureBuffer.append(type); // Copy the referenced classes. for (int counter = 0; counter < classCount; counter++) { referencedClasses[newReferencedClassIndex++] = referencedClasses[referencedClassIndex++]; } } else { // Skip the referenced classes. referencedClassIndex += classCount; } } if (newReferencedClassIndex < referencedClassIndex) { // Update the signature. ((Utf8Constant)((ProgramClass)clazz).constantPool[signatureAttribute.u2signatureIndex]).setString(newSignatureBuffer.toString()); // Clear the unused entries. while (newReferencedClassIndex < referencedClassIndex) { referencedClasses[newReferencedClassIndex++] = null; } } } } } // Implementations for ElementValueVisitor. public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) {} public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { // Shrink the contained annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { // Shrink the element values array. arrayElementValue.u2elementValuesCount = shrinkArray(arrayElementValue.elementValues, arrayElementValue.u2elementValuesCount); // Shrink the element values themselves. arrayElementValue.elementValuesAccept(clazz, annotation, this); } // Small utility methods. /** * Removes all entries that are not marked as being used from the given * constant pool. * @return the new number of entries. */ private int shrinkConstantPool(Constant[] constantPool, int length) { if (constantIndexMap.length < length) { constantIndexMap = new int[length]; } int counter = 1; boolean isUsed = false; // Shift the used constant pool entries together. for (int index = 1; index < length; index++) { constantIndexMap[index] = counter; Constant constant = constantPool[index]; // Don't update the flag if this is the second half of a long entry. if (constant != null) { isUsed = usageMarker.isUsed(constant); } if (isUsed) { constantPool[counter++] = constant; } } // Clear the remaining constant pool elements. Arrays.fill(constantPool, counter, length, null); return counter; } /** * Removes all indices that point to unused constant pool entries * from the given array. * @return the new number of indices. */ private int shrinkConstantIndexArray(Constant[] constantPool, int[] array, int length) { int counter = 0; // Shift the used objects together. for (int index = 0; index < length; index++) { if (usageMarker.isUsed(constantPool[array[index]])) { array[counter++] = array[index]; } } // Clear the remaining array elements. Arrays.fill(array, counter, length, 0); return counter; } /** * Removes all Clazz objects that are not marked as being used * from the given array and returns the remaining objects in a an array * of the right size. * @return the new array. */ private Clazz[] shrinkToNewArray(Clazz[] array) { if (array == null) { return null; } // Shrink the given array in-place. int length = shrinkArray(array, array.length); if (length == 0) { return null; } // Return immediately if the array is of right size already. if (length == array.length) { return array; } // Copy the remaining elements into a new array of the right size. Clazz[] newArray = new Clazz[length]; System.arraycopy(array, 0, newArray, 0, length); return newArray; } /** * Removes all VisitorAccepter objects that are not marked as being used * from the given array. * @return the new number of VisitorAccepter objects. */ private int shrinkArray(VisitorAccepter[] array, int length) { int counter = 0; // Shift the used objects together. for (int index = 0; index < length; index++) { if (usageMarker.isUsed(array[index])) { array[counter++] = array[index]; } } // Clear any remaining array elements. if (counter < length) { Arrays.fill(array, counter, length, null); } return counter; } } proguard4.8/src/proguard/shrink/InterfaceUsageMarker.java0000644000175000017500000001105211736333522022367 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor recursively marks all interface * classes that are being used in the visited class. * * @see UsageMarker * * @author Eric Lafortune */ public class InterfaceUsageMarker extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor { private final UsageMarker usageMarker; // Fields acting as a return parameters for several methods. private boolean used; private boolean anyUsed; /** * Creates a new InterfaceUsageMarker. * @param usageMarker the usage marker that is used to mark the classes * and class members. */ public InterfaceUsageMarker(UsageMarker usageMarker) { this.usageMarker = usageMarker; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { boolean classUsed = usageMarker.isUsed(programClass); boolean classPossiblyUsed = usageMarker.isPossiblyUsed(programClass); if (classUsed || classPossiblyUsed) { // Check if any interfaces are being used. boolean oldAnyUsed = anyUsed; anyUsed = false; programClass.interfaceConstantsAccept(this); classUsed |= anyUsed; anyUsed = oldAnyUsed; // Is this an interface with a preliminary mark? if (classPossiblyUsed) { // Should it be included now? if (classUsed) { // At least one if this interface's interfaces is being used. // Mark this interface as well. usageMarker.markAsUsed(programClass); // Mark this interface's name. programClass.thisClassConstantAccept(this); // Mark the superclass (java/lang/Object). programClass.superClassConstantAccept(this); } else { // Unmark this interface, so we don't bother looking at it again. usageMarker.markAsUnused(programClass); } } } // The return value. used = classUsed; } public void visitLibraryClass(LibraryClass libraryClass) { // The return values. used = true; anyUsed = true; } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { boolean classUsed = usageMarker.isUsed(classConstant); if (!classUsed) { // The ClassConstant isn't marked as being used yet. But maybe it // should be included as an interface, so check the actual class. classConstant.referencedClassAccept(this); classUsed = used; if (classUsed) { // The class is being used. Mark the ClassConstant as being used // as well. usageMarker.markAsUsed(classConstant); clazz.constantPoolEntryAccept(classConstant.u2nameIndex, this); } } // The return values. used = classUsed; anyUsed |= classUsed; } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { if (!usageMarker.isUsed(utf8Constant)) { usageMarker.markAsUsed(utf8Constant); } } } proguard4.8/src/proguard/shrink/InnerUsageMarker.java0000644000175000017500000001234311736333522021546 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This AttributeVisitor recursively marks all necessary inner class information * in the attributes that it visits. * * @see UsageMarker * * @author Eric Lafortune */ public class InnerUsageMarker extends SimplifiedVisitor implements AttributeVisitor, InnerClassesInfoVisitor, ConstantVisitor, ClassVisitor { private final UsageMarker usageMarker; // Fields acting as a return parameters for several methods. private boolean attributeUsed; private boolean classUsed; /** * Creates a new InnerUsageMarker. * @param usageMarker the usage marker that is used to mark the classes * and class members. */ public InnerUsageMarker(UsageMarker usageMarker) { this.usageMarker = usageMarker; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Mark the necessary inner classes information. attributeUsed = false; innerClassesAttribute.innerClassEntriesAccept(clazz, this); if (attributeUsed) { // We got a positive used flag, so some inner class is being used. // Mark this attribute as being used as well. usageMarker.markAsUsed(innerClassesAttribute); markConstant(clazz, innerClassesAttribute.u2attributeNameIndex); } } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { boolean innerClassesInfoUsed = usageMarker.isUsed(innerClassesInfo); if (!innerClassesInfoUsed) { // Check if the inner class (if any) is marked as being used. classUsed = true; innerClassesInfo.innerClassConstantAccept(clazz, this); innerClassesInfoUsed = classUsed; // Check if the outer class (if any) is marked as being used. classUsed = true; innerClassesInfo.outerClassConstantAccept(clazz, this); innerClassesInfoUsed &= classUsed; // If both the inner class and the outer class are marked as being // used, then mark this InnerClassesInfo as well. if (innerClassesInfoUsed) { usageMarker.markAsUsed(innerClassesInfo); innerClassesInfo.innerNameConstantAccept(clazz, this); } } // The return value. attributeUsed |= innerClassesInfoUsed; } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classUsed = usageMarker.isUsed(classConstant); // Is the class constant marked as being used? if (!classUsed) { // Check the referenced class. classUsed = true; classConstant.referencedClassAccept(this); // Is the referenced class marked as being used? if (classUsed) { // Mark the class constant and its Utf8 constant. usageMarker.markAsUsed(classConstant); markConstant(clazz, classConstant.u2nameIndex); } } } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { usageMarker.markAsUsed(utf8Constant); } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { classUsed = usageMarker.isUsed(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { classUsed = true; } // Small utility methods. /** * Marks the given constant pool entry of the given class. This includes * visiting any other referenced constant pool entries. */ private void markConstant(Clazz clazz, int index) { clazz.constantPoolEntryAccept(index, this); } } proguard4.8/src/proguard/shrink/AnnotationUsageMarker.java0000644000175000017500000002414611736333522022611 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.attribute.Attribute; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This AttributeVisitor recursively marks all necessary annotation information * in the attributes that it visits. * * @see UsageMarker * * @author Eric Lafortune */ public class AnnotationUsageMarker extends SimplifiedVisitor implements AttributeVisitor, AnnotationVisitor, ElementValueVisitor, ConstantVisitor, ClassVisitor, MemberVisitor { private final UsageMarker usageMarker; // Fields acting as a return parameters for several methods. private boolean attributeUsed; private boolean annotationUsed; private boolean classUsed; private boolean methodUsed; /** * Creates a new AnnotationUsageMarker. * @param usageMarker the usage marker that is used to mark the classes * and class members. */ public AnnotationUsageMarker(UsageMarker usageMarker) { this.usageMarker = usageMarker; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Mark the necessary annotation information. attributeUsed = false; annotationsAttribute.annotationsAccept(clazz, this); if (attributeUsed) { // We got a positive used flag, so some annotation is being used. // Mark this attribute as being used as well. usageMarker.markAsUsed(annotationsAttribute); markConstant(clazz, annotationsAttribute.u2attributeNameIndex); } } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Mark the necessary annotation information. attributeUsed = false; parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); if (attributeUsed) { // We got a positive used flag, so some annotation is being used. // Mark this attribute as being used as well. usageMarker.markAsUsed(parameterAnnotationsAttribute); markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); } } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Mark the necessary annotation information in any annotation elements. annotationDefaultAttribute.defaultValueAccept(clazz, this); // Always mark annotation defaults. usageMarker.markAsUsed(annotationDefaultAttribute); markConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { if (isReferencedClassUsed(annotation)) { // Mark the annotation as being used. usageMarker.markAsUsed(annotation); markConstant(clazz, annotation.u2typeIndex); // Mark the necessary element values. annotation.elementValuesAccept(clazz, this); // The return values. annotationUsed = true; attributeUsed = true; } } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { if (isReferencedMethodUsed(constantElementValue)) { // Mark the element value as being used. usageMarker.markAsUsed(constantElementValue); markConstant(clazz, constantElementValue.u2elementNameIndex); markConstant(clazz, constantElementValue.u2constantValueIndex); } } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { if (isReferencedMethodUsed(enumConstantElementValue)) { // Check the referenced classes. classUsed = true; enumConstantElementValue.referencedClassesAccept(this); if (classUsed) { // Mark the element value as being used. usageMarker.markAsUsed(enumConstantElementValue); markConstant(clazz, enumConstantElementValue.u2elementNameIndex); markConstant(clazz, enumConstantElementValue.u2typeNameIndex); markConstant(clazz, enumConstantElementValue.u2constantNameIndex); } } } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { if (isReferencedMethodUsed(classElementValue)) { // Check the referenced classes. classUsed = true; classElementValue.referencedClassesAccept(this); if (classUsed) { // Mark the element value as being used. usageMarker.markAsUsed(classElementValue); markConstant(clazz, classElementValue.u2elementNameIndex); markConstant(clazz, classElementValue.u2classInfoIndex); } } } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { if (isReferencedMethodUsed(annotationElementValue)) { boolean oldAnnotationUsed = annotationUsed; // Check and mark the contained annotation. annotationUsed = false; annotationElementValue.annotationAccept(clazz, this); if (annotationUsed) { // Mark the element value as being used. usageMarker.markAsUsed(annotationElementValue); markConstant(clazz, annotationElementValue.u2elementNameIndex); } annotationUsed = oldAnnotationUsed; } } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { if (isReferencedMethodUsed(arrayElementValue)) { // Check and mark the contained element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); // Mark the element value as being used. usageMarker.markAsUsed(arrayElementValue); markConstant(clazz, arrayElementValue.u2elementNameIndex); } } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) { usageMarker.markAsUsed(constant); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classUsed = usageMarker.isUsed(classConstant); // Is the class constant marked as being used? if (!classUsed) { // Check the referenced class. classUsed = true; classConstant.referencedClassAccept(this); // Is the referenced class marked as being used? if (classUsed) { // Mark the class constant and its Utf8 constant. usageMarker.markAsUsed(classConstant); markConstant(clazz, classConstant.u2nameIndex); } } } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { classUsed = usageMarker.isUsed(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { classUsed = true; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { methodUsed = usageMarker.isUsed(programMethod); } public void visitLibraryMethod(LibraryClass LibraryClass, LibraryMethod libraryMethod) { classUsed = true; } // Small utility methods. /** * Returns whether the annotation class has been marked as being used. */ private boolean isReferencedClassUsed(Annotation annotation) { // Check if the referenced class is being used. classUsed = true; annotation.referencedClassAccept(this); return classUsed; } /** * Returns whether the annotation method has been marked as being used. */ private boolean isReferencedMethodUsed(ElementValue elementValue) { // Check if the referenced method is being used. methodUsed = true; elementValue.referencedMethodAccept(this); return methodUsed; } /** * Marks the specified constant pool entry. */ private void markConstant(Clazz clazz, int index) { if (index > 0) { clazz.constantPoolEntryAccept(index, this); } } } proguard4.8/src/proguard/shrink/UsagePrinter.java0000644000175000017500000001313311736333522020752 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.io.PrintStream; /** * This ClassVisitor prints out the classes and class members that have been * marked as being used (or not used). * * @see UsageMarker * * @author Eric Lafortune */ public class UsagePrinter extends SimplifiedVisitor implements ClassVisitor, MemberVisitor { private final UsageMarker usageMarker; private final boolean printUnusedItems; private final PrintStream ps; // A field to remember the class name, if a header is needed for class members. private String className; /** * Creates a new UsagePrinter that prints to System.out. * @param usageMarker the usage marker that was used to mark the * classes and class members. * @param printUnusedItems a flag that indicates whether only unused items * should be printed, or alternatively, only used * items. */ public UsagePrinter(UsageMarker usageMarker, boolean printUnusedItems) { this(usageMarker, printUnusedItems, System.out); } /** * Creates a new UsagePrinter that prints to the given stream. * @param usageMarker the usage marker that was used to mark the * classes and class members. * @param printUnusedItems a flag that indicates whether only unused items * should be printed, or alternatively, only used * items. * @param printStream the stream to which to print. */ public UsagePrinter(UsageMarker usageMarker, boolean printUnusedItems, PrintStream printStream) { this.usageMarker = usageMarker; this.printUnusedItems = printUnusedItems; this.ps = printStream; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (usageMarker.isUsed(programClass)) { if (printUnusedItems) { className = programClass.getName(); programClass.fieldsAccept(this); programClass.methodsAccept(this); className = null; } else { ps.println(ClassUtil.externalClassName(programClass.getName())); } } else { if (printUnusedItems) { ps.println(ClassUtil.externalClassName(programClass.getName())); } } } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (usageMarker.isUsed(programField) ^ printUnusedItems) { printClassNameHeader(); ps.println(" " + lineNumberRange(programClass, programField) + ClassUtil.externalFullFieldDescription( programField.getAccessFlags(), programField.getName(programClass), programField.getDescriptor(programClass))); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (usageMarker.isUsed(programMethod) ^ printUnusedItems) { printClassNameHeader(); ps.println(" " + lineNumberRange(programClass, programMethod) + ClassUtil.externalFullMethodDescription( programClass.getName(), programMethod.getAccessFlags(), programMethod.getName(programClass), programMethod.getDescriptor(programClass))); } } // Small utility methods. /** * Prints the class name field. The field is then cleared, so it is not * printed again. */ private void printClassNameHeader() { if (className != null) { ps.println(ClassUtil.externalClassName(className) + ":"); className = null; } } /** * Returns the line number range of the given class member, followed by a * colon, or just an empty String if no range is available. */ private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember) { String range = programMember.getLineNumberRange(programClass); return range != null ? (range + ":") : ""; } } proguard4.8/src/proguard/shrink/Shrinker.java0000644000175000017500000001512111736333522020126 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.shrink; import proguard.*; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.visitor.*; import java.io.*; /** * This class shrinks class pools according to a given configuration. * * @author Eric Lafortune */ public class Shrinker { private final Configuration configuration; /** * Creates a new Shrinker. */ public Shrinker(Configuration configuration) { this.configuration = configuration; } /** * Performs shrinking of the given program class pool. */ public ClassPool execute(ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { // Check if we have at least some keep commands. if (configuration.keep == null) { throw new IOException("You have to specify '-keep' options for the shrinking step."); } // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); libraryClassPool.classesAccept(new ClassCleaner()); // Create a visitor for marking the seeds. UsageMarker usageMarker = configuration.whyAreYouKeeping == null ? new UsageMarker() : new ShortestUsageMarker(); // Automatically mark the parameterless constructors of seed classes, // mainly for convenience and for backward compatibility. ClassVisitor classUsageMarker = new MultiClassVisitor(new ClassVisitor[] { usageMarker, new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT, ClassConstants.INTERNAL_METHOD_TYPE_INIT, usageMarker) }); ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, classUsageMarker, usageMarker, true, false, false); // Mark the seeds. programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); // Mark interfaces that have to be kept. programClassPool.classesAccept(new InterfaceUsageMarker(usageMarker)); // Mark the inner class and annotation information that has to be kept. programClassPool.classesAccept( new UsedClassFilter(usageMarker, new AllAttributeVisitor(true, new MultiAttributeVisitor(new AttributeVisitor[] { new InnerUsageMarker(usageMarker), new AnnotationUsageMarker(usageMarker), })))); // Should we explain ourselves? if (configuration.whyAreYouKeeping != null) { System.out.println(); // Create a visitor for explaining classes and class members. ShortestUsagePrinter shortestUsagePrinter = new ShortestUsagePrinter((ShortestUsageMarker)usageMarker, configuration.verbose); ClassPoolVisitor whyClassPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.whyAreYouKeeping, shortestUsagePrinter, shortestUsagePrinter); // Mark the seeds. programClassPool.accept(whyClassPoolvisitor); libraryClassPool.accept(whyClassPoolvisitor); } if (configuration.printUsage != null) { PrintStream ps = isFile(configuration.printUsage) ? new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printUsage))) : System.out; // Print out items that will be removed. programClassPool.classesAcceptAlphabetically( new UsagePrinter(usageMarker, true, ps)); if (ps != System.out) { ps.close(); } } // Discard unused program classes. int originalProgramClassPoolSize = programClassPool.size(); ClassPool newProgramClassPool = new ClassPool(); programClassPool.classesAccept( new UsedClassFilter(usageMarker, new MultiClassVisitor( new ClassVisitor[] { new ClassShrinker(usageMarker), new ClassPoolFiller(newProgramClassPool) }))); programClassPool.clear(); // Check if we have at least some output classes. int newProgramClassPoolSize = newProgramClassPool.size(); if (newProgramClassPoolSize == 0) { throw new IOException("The output jar is empty. Did you specify the proper '-keep' options?"); } if (configuration.verbose) { System.out.println("Removing unused program classes and class elements..."); System.out.println(" Original number of program classes: " + originalProgramClassPoolSize); System.out.println(" Final number of program classes: " + newProgramClassPoolSize); } return newProgramClassPool; } /** * Returns whether the given file is actually a file, or just a placeholder * for the standard output. */ private boolean isFile(File file) { return file.getPath().length() > 0; } } proguard4.8/src/proguard/evaluation/0000775000175000017500000000000011760503005016341 5ustar ericericproguard4.8/src/proguard/evaluation/value/0000775000175000017500000000000011760503005017455 5ustar ericericproguard4.8/src/proguard/evaluation/value/package.html0000644000175000017500000000012711736333522021744 0ustar ericeric This package contains classes that represent partial evaluation values. proguard4.8/src/proguard/evaluation/value/IntegerValue.java0000644000175000017500000006664111736333522022735 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.ClassConstants; /** * This class represents a partially evaluated integer value. * * @author Eric Lafortune */ public abstract class IntegerValue extends Category1Value { /** * Returns the specific integer value, if applicable. */ public int value() { return 0; } // Basic unary methods. /** * Returns the negated value of this IntegerValue. */ public abstract IntegerValue negate(); /** * Converts this IntegerValue to a byte IntegerValue. */ public abstract IntegerValue convertToByte(); /** * Converts this IntegerValue to a character IntegerValue. */ public abstract IntegerValue convertToCharacter(); /** * Converts this IntegerValue to a short IntegerValue. */ public abstract IntegerValue convertToShort(); /** * Converts this IntegerValue to a LongValue. */ public abstract LongValue convertToLong(); /** * Converts this IntegerValue to a FloatValue. */ public abstract FloatValue convertToFloat(); /** * Converts this IntegerValue to a DoubleValue. */ public abstract DoubleValue convertToDouble(); // Basic binary methods. /** * Returns the generalization of this IntegerValue and the given other * IntegerValue. */ public abstract IntegerValue generalize(IntegerValue other); /** * Returns the sum of this IntegerValue and the given IntegerValue. */ public abstract IntegerValue add(IntegerValue other); /** * Returns the difference of this IntegerValue and the given IntegerValue. */ public abstract IntegerValue subtract(IntegerValue other); /** * Returns the difference of the given IntegerValue and this IntegerValue. */ public abstract IntegerValue subtractFrom(IntegerValue other); /** * Returns the product of this IntegerValue and the given IntegerValue. */ public abstract IntegerValue multiply(IntegerValue other) throws ArithmeticException; /** * Returns the quotient of this IntegerValue and the given IntegerValue. */ public abstract IntegerValue divide(IntegerValue other) throws ArithmeticException; /** * Returns the quotient of the given IntegerValue and this IntegerValue. */ public abstract IntegerValue divideOf(IntegerValue other) throws ArithmeticException; /** * Returns the remainder of this IntegerValue divided by the given * IntegerValue. */ public abstract IntegerValue remainder(IntegerValue other) throws ArithmeticException; /** * Returns the remainder of the given IntegerValue divided by this * IntegerValue. */ public abstract IntegerValue remainderOf(IntegerValue other) throws ArithmeticException; /** * Returns this IntegerValue, shifted left by the given IntegerValue. */ public abstract IntegerValue shiftLeft(IntegerValue other); /** * Returns this IntegerValue, shifted right by the given IntegerValue. */ public abstract IntegerValue shiftRight(IntegerValue other); /** * Returns this unsigned IntegerValue, shifted left by the given * IntegerValue. */ public abstract IntegerValue unsignedShiftRight(IntegerValue other); /** * Returns the given IntegerValue, shifted left by this IntegerValue. */ public abstract IntegerValue shiftLeftOf(IntegerValue other); /** * Returns the given IntegerValue, shifted right by this IntegerValue. */ public abstract IntegerValue shiftRightOf(IntegerValue other); /** * Returns the given unsigned IntegerValue, shifted left by this * IntegerValue. */ public abstract IntegerValue unsignedShiftRightOf(IntegerValue other); /** * Returns the given LongValue, shifted left by this IntegerValue. */ public abstract LongValue shiftLeftOf(LongValue other); /** * Returns the given LongValue, shifted right by this IntegerValue. */ public abstract LongValue shiftRightOf(LongValue other); /** * Returns the given unsigned LongValue, shifted right by this IntegerValue. */ public abstract LongValue unsignedShiftRightOf(LongValue other); /** * Returns the logical and of this IntegerValue and the given * IntegerValue. */ public abstract IntegerValue and(IntegerValue other); /** * Returns the logical or of this IntegerValue and the given * IntegerValue. */ public abstract IntegerValue or(IntegerValue other); /** * Returns the logical xor of this IntegerValue and the given * IntegerValue. */ public abstract IntegerValue xor(IntegerValue other); /** * Returns whether this IntegerValue and the given IntegerValue are equal: * NEVER, MAYBE, or ALWAYS. */ public abstract int equal(IntegerValue other); /** * Returns whether this IntegerValue is less than the given IntegerValue: * NEVER, MAYBE, or ALWAYS. */ public abstract int lessThan(IntegerValue other); /** * Returns whether this IntegerValue is less than or equal to the given * IntegerValue: NEVER, MAYBE, or * ALWAYS. */ public abstract int lessThanOrEqual(IntegerValue other); // Derived binary methods. /** * Returns whether this IntegerValue and the given IntegerValue are different: * NEVER, MAYBE, or ALWAYS. */ public final int notEqual(IntegerValue other) { return -equal(other); } /** * Returns whether this IntegerValue is greater than the given IntegerValue: * NEVER, MAYBE, or ALWAYS. */ public final int greaterThan(IntegerValue other) { return -lessThanOrEqual(other); } /** * Returns whether this IntegerValue is greater than or equal to the given IntegerValue: * NEVER, MAYBE, or ALWAYS. */ public final int greaterThanOrEqual(IntegerValue other) { return -lessThan(other); } // Similar binary methods, but this time with unknown arguments. /** * Returns the generalization of this IntegerValue and the given other * UnknownIntegerValue. */ public IntegerValue generalize(UnknownIntegerValue other) { return generalize((IntegerValue)other); } /** * Returns the sum of this IntegerValue and the given UnknownIntegerValue. */ public IntegerValue add(UnknownIntegerValue other) { return add((IntegerValue)other); } /** * Returns the difference of this IntegerValue and the given UnknownIntegerValue. */ public IntegerValue subtract(UnknownIntegerValue other) { return subtract((IntegerValue)other); } /** * Returns the difference of the given UnknownIntegerValue and this IntegerValue. */ public IntegerValue subtractFrom(UnknownIntegerValue other) { return subtractFrom((IntegerValue)other); } /** * Returns the product of this IntegerValue and the given UnknownIntegerValue. */ public IntegerValue multiply(UnknownIntegerValue other) { return multiply((IntegerValue)other); } /** * Returns the quotient of this IntegerValue and the given * UnknownIntegerValue. */ public IntegerValue divide(UnknownIntegerValue other) { return divide((IntegerValue)other); } /** * Returns the quotient of the given UnknownIntegerValue and this * IntegerValue. */ public IntegerValue divideOf(UnknownIntegerValue other) { return divideOf((IntegerValue)other); } /** * Returns the remainder of this IntegerValue divided by the given * UnknownIntegerValue. */ public IntegerValue remainder(UnknownIntegerValue other) { return remainder((IntegerValue)other); } /** * Returns the remainder of the given UnknownIntegerValue divided by this * IntegerValue. */ public IntegerValue remainderOf(UnknownIntegerValue other) { return remainderOf((IntegerValue)other); } /** * Returns this IntegerValue, shifted left by the given UnknownIntegerValue. */ public IntegerValue shiftLeft(UnknownIntegerValue other) { return shiftLeft((IntegerValue)other); } /** * Returns this IntegerValue, shifted right by the given UnknownIntegerValue. */ public IntegerValue shiftRight(UnknownIntegerValue other) { return shiftRight((IntegerValue)other); } /** * Returns this unsigned IntegerValue, shifted right by the given * UnknownIntegerValue. */ public IntegerValue unsignedShiftRight(UnknownIntegerValue other) { return unsignedShiftRight((IntegerValue)other); } /** * Returns the given UnknownIntegerValue, shifted left by this IntegerValue. */ public IntegerValue shiftLeftOf(UnknownIntegerValue other) { return shiftLeftOf((IntegerValue)other); } /** * Returns the given UnknownIntegerValue, shifted right by this IntegerValue. */ public IntegerValue shiftRightOf(UnknownIntegerValue other) { return shiftRightOf((IntegerValue)other); } /** * Returns the given unsigned UnknownIntegerValue, shifted right by this * IntegerValue. */ public IntegerValue unsignedShiftRightOf(UnknownIntegerValue other) { return unsignedShiftRightOf((IntegerValue)other); } /** * Returns the given UnknownLongValue, shifted left by this IntegerValue. */ public LongValue shiftLeftOf(UnknownLongValue other) { return shiftLeftOf((LongValue)other); } /** * Returns the given UnknownLongValue, shifted right by this IntegerValue. */ public LongValue shiftRightOf(UnknownLongValue other) { return shiftRightOf((LongValue)other); } /** * Returns the given unsigned UnknownLongValue, shifted right by this * IntegerValue. */ public LongValue unsignedShiftRightOf(UnknownLongValue other) { return unsignedShiftRightOf((LongValue)other); } /** * Returns the logical and of this IntegerValue and the given * UnknownIntegerValue. */ public IntegerValue and(UnknownIntegerValue other) { return and((IntegerValue)other); } /** * Returns the logical or of this IntegerValue and the given * UnknownIntegerValue. */ public IntegerValue or(UnknownIntegerValue other) { return or((IntegerValue)other); } /** * Returns the logical xor of this IntegerValue and the given * UnknownIntegerValue. */ public IntegerValue xor(UnknownIntegerValue other) { return xor((IntegerValue)other); } /** * Returns whether this IntegerValue and the given UnknownIntegerValue are * equal: NEVER, MAYBE, or ALWAYS. */ public int equal(UnknownIntegerValue other) { return equal((IntegerValue)other); } /** * Returns whether this IntegerValue is less than the given * UnknownIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public int lessThan(UnknownIntegerValue other) { return lessThan((IntegerValue)other); } /** * Returns whether this IntegerValue is less than or equal to the given * UnknownIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public int lessThanOrEqual(UnknownIntegerValue other) { return lessThanOrEqual((IntegerValue)other); } // Derived binary methods. /** * Returns whether this IntegerValue and the given UnknownIntegerValue are * different: NEVER, MAYBE, or ALWAYS. */ public final int notEqual(UnknownIntegerValue other) { return -equal(other); } /** * Returns whether this IntegerValue is greater than the given * UnknownIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public final int greaterThan(UnknownIntegerValue other) { return -lessThanOrEqual(other); } /** * Returns whether this IntegerValue is greater than or equal to the given * UnknownIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public final int greaterThanOrEqual(UnknownIntegerValue other) { return -lessThan(other); } // Similar binary methods, but this time with specific arguments. /** * Returns the generalization of this IntegerValue and the given other * SpecificIntegerValue. */ public IntegerValue generalize(SpecificIntegerValue other) { return generalize((IntegerValue)other); } /** * Returns the sum of this IntegerValue and the given SpecificIntegerValue. */ public IntegerValue add(SpecificIntegerValue other) { return add((IntegerValue)other); } /** * Returns the difference of this IntegerValue and the given SpecificIntegerValue. */ public IntegerValue subtract(SpecificIntegerValue other) { return subtract((IntegerValue)other); } /** * Returns the difference of the given SpecificIntegerValue and this IntegerValue. */ public IntegerValue subtractFrom(SpecificIntegerValue other) { return subtractFrom((IntegerValue)other); } /** * Returns the product of this IntegerValue and the given SpecificIntegerValue. */ public IntegerValue multiply(SpecificIntegerValue other) { return multiply((IntegerValue)other); } /** * Returns the quotient of this IntegerValue and the given * SpecificIntegerValue. */ public IntegerValue divide(SpecificIntegerValue other) { return divide((IntegerValue)other); } /** * Returns the quotient of the given SpecificIntegerValue and this * IntegerValue. */ public IntegerValue divideOf(SpecificIntegerValue other) { return divideOf((IntegerValue)other); } /** * Returns the remainder of this IntegerValue divided by the given * SpecificIntegerValue. */ public IntegerValue remainder(SpecificIntegerValue other) { return remainder((IntegerValue)other); } /** * Returns the remainder of the given SpecificIntegerValue divided by this * IntegerValue. */ public IntegerValue remainderOf(SpecificIntegerValue other) { return remainderOf((IntegerValue)other); } /** * Returns this IntegerValue, shifted left by the given SpecificIntegerValue. */ public IntegerValue shiftLeft(SpecificIntegerValue other) { return shiftLeft((IntegerValue)other); } /** * Returns this IntegerValue, shifted right by the given SpecificIntegerValue. */ public IntegerValue shiftRight(SpecificIntegerValue other) { return shiftRight((IntegerValue)other); } /** * Returns this unsigned IntegerValue, shifted right by the given * SpecificIntegerValue. */ public IntegerValue unsignedShiftRight(SpecificIntegerValue other) { return unsignedShiftRight((IntegerValue)other); } /** * Returns the given SpecificIntegerValue, shifted left by this IntegerValue. */ public IntegerValue shiftLeftOf(SpecificIntegerValue other) { return shiftLeftOf((IntegerValue)other); } /** * Returns the given SpecificIntegerValue, shifted right by this IntegerValue. */ public IntegerValue shiftRightOf(SpecificIntegerValue other) { return shiftRightOf((IntegerValue)other); } /** * Returns the given unsigned SpecificIntegerValue, shifted right by this * IntegerValue. */ public IntegerValue unsignedShiftRightOf(SpecificIntegerValue other) { return unsignedShiftRightOf((IntegerValue)other); } /** * Returns the given SpecificLongValue, shifted left by this IntegerValue. */ public LongValue shiftLeftOf(SpecificLongValue other) { return shiftLeftOf((LongValue)other); } /** * Returns the given SpecificLongValue, shifted right by this IntegerValue. */ public LongValue shiftRightOf(SpecificLongValue other) { return shiftRightOf((LongValue)other); } /** * Returns the given unsigned SpecificLongValue, shifted right by this * IntegerValue. */ public LongValue unsignedShiftRightOf(SpecificLongValue other) { return unsignedShiftRightOf((LongValue)other); } /** * Returns the logical and of this IntegerValue and the given * SpecificIntegerValue. */ public IntegerValue and(SpecificIntegerValue other) { return and((IntegerValue)other); } /** * Returns the logical or of this IntegerValue and the given * SpecificIntegerValue. */ public IntegerValue or(SpecificIntegerValue other) { return or((IntegerValue)other); } /** * Returns the logical xor of this IntegerValue and the given * SpecificIntegerValue. */ public IntegerValue xor(SpecificIntegerValue other) { return xor((IntegerValue)other); } /** * Returns whether this IntegerValue and the given SpecificIntegerValue are * equal: NEVER, MAYBE, or ALWAYS. */ public int equal(SpecificIntegerValue other) { return equal((IntegerValue)other); } /** * Returns whether this IntegerValue is less than the given * SpecificIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public int lessThan(SpecificIntegerValue other) { return lessThan((IntegerValue)other); } /** * Returns whether this IntegerValue is less than or equal to the given * SpecificIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public int lessThanOrEqual(SpecificIntegerValue other) { return lessThanOrEqual((IntegerValue)other); } // Derived binary methods. /** * Returns whether this IntegerValue and the given SpecificIntegerValue are * different: NEVER, MAYBE, or ALWAYS. */ public final int notEqual(SpecificIntegerValue other) { return -equal(other); } /** * Returns whether this IntegerValue is greater than the given * SpecificIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public final int greaterThan(SpecificIntegerValue other) { return -lessThanOrEqual(other); } /** * Returns whether this IntegerValue is greater than or equal to the given * SpecificIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public final int greaterThanOrEqual(SpecificIntegerValue other) { return -lessThan(other); } // Similar binary methods, but this time with particular arguments. /** * Returns the generalization of this IntegerValue and the given other * ParticularIntegerValue. */ public IntegerValue generalize(ParticularIntegerValue other) { return generalize((SpecificIntegerValue)other); } /** * Returns the sum of this IntegerValue and the given ParticularIntegerValue. */ public IntegerValue add(ParticularIntegerValue other) { return add((SpecificIntegerValue)other); } /** * Returns the difference of this IntegerValue and the given ParticularIntegerValue. */ public IntegerValue subtract(ParticularIntegerValue other) { return subtract((SpecificIntegerValue)other); } /** * Returns the difference of the given ParticularIntegerValue and this IntegerValue. */ public IntegerValue subtractFrom(ParticularIntegerValue other) { return subtractFrom((SpecificIntegerValue)other); } /** * Returns the product of this IntegerValue and the given ParticularIntegerValue. */ public IntegerValue multiply(ParticularIntegerValue other) { return multiply((SpecificIntegerValue)other); } /** * Returns the quotient of this IntegerValue and the given * ParticularIntegerValue. */ public IntegerValue divide(ParticularIntegerValue other) { return divide((SpecificIntegerValue)other); } /** * Returns the quotient of the given ParticularIntegerValue and this * IntegerValue. */ public IntegerValue divideOf(ParticularIntegerValue other) { return divideOf((SpecificIntegerValue)other); } /** * Returns the remainder of this IntegerValue divided by the given * ParticularIntegerValue. */ public IntegerValue remainder(ParticularIntegerValue other) { return remainder((SpecificIntegerValue)other); } /** * Returns the remainder of the given ParticularIntegerValue divided by this * IntegerValue. */ public IntegerValue remainderOf(ParticularIntegerValue other) { return remainderOf((SpecificIntegerValue)other); } /** * Returns this IntegerValue, shifted left by the given ParticularIntegerValue. */ public IntegerValue shiftLeft(ParticularIntegerValue other) { return shiftLeft((SpecificIntegerValue)other); } /** * Returns this IntegerValue, shifted right by the given ParticularIntegerValue. */ public IntegerValue shiftRight(ParticularIntegerValue other) { return shiftRight((SpecificIntegerValue)other); } /** * Returns this unsigned IntegerValue, shifted right by the given * ParticularIntegerValue. */ public IntegerValue unsignedShiftRight(ParticularIntegerValue other) { return unsignedShiftRight((SpecificIntegerValue)other); } /** * Returns the given ParticularIntegerValue, shifted left by this IntegerValue. */ public IntegerValue shiftLeftOf(ParticularIntegerValue other) { return shiftLeftOf((SpecificIntegerValue)other); } /** * Returns the given ParticularIntegerValue, shifted right by this IntegerValue. */ public IntegerValue shiftRightOf(ParticularIntegerValue other) { return shiftRightOf((SpecificIntegerValue)other); } /** * Returns the given unsigned ParticularIntegerValue, shifted right by this * IntegerValue. */ public IntegerValue unsignedShiftRightOf(ParticularIntegerValue other) { return unsignedShiftRightOf((SpecificIntegerValue)other); } /** * Returns the given ParticularLongValue, shifted left by this IntegerValue. */ public LongValue shiftLeftOf(ParticularLongValue other) { return shiftLeftOf((SpecificLongValue)other); } /** * Returns the given ParticularLongValue, shifted right by this IntegerValue. */ public LongValue shiftRightOf(ParticularLongValue other) { return shiftRightOf((SpecificLongValue)other); } /** * Returns the given unsigned ParticularLongValue, shifted right by this * IntegerValue. */ public LongValue unsignedShiftRightOf(ParticularLongValue other) { return unsignedShiftRightOf((SpecificLongValue)other); } /** * Returns the logical and of this IntegerValue and the given * ParticularIntegerValue. */ public IntegerValue and(ParticularIntegerValue other) { return and((SpecificIntegerValue)other); } /** * Returns the logical or of this IntegerValue and the given * ParticularIntegerValue. */ public IntegerValue or(ParticularIntegerValue other) { return or((SpecificIntegerValue)other); } /** * Returns the logical xor of this IntegerValue and the given * ParticularIntegerValue. */ public IntegerValue xor(ParticularIntegerValue other) { return xor((SpecificIntegerValue)other); } /** * Returns whether this IntegerValue and the given ParticularIntegerValue are * equal: NEVER, MAYBE, or ALWAYS. */ public int equal(ParticularIntegerValue other) { return equal((SpecificIntegerValue)other); } /** * Returns whether this IntegerValue is less than the given * ParticularIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public int lessThan(ParticularIntegerValue other) { return lessThan((SpecificIntegerValue)other); } /** * Returns whether this IntegerValue is less than or equal to the given * ParticularIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public int lessThanOrEqual(ParticularIntegerValue other) { return lessThanOrEqual((SpecificIntegerValue)other); } // Derived binary methods. /** * Returns whether this IntegerValue and the given ParticularIntegerValue are * different: NEVER, MAYBE, or ALWAYS. */ public final int notEqual(ParticularIntegerValue other) { return -equal(other); } /** * Returns whether this IntegerValue is greater than the given * ParticularIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public final int greaterThan(ParticularIntegerValue other) { return -lessThanOrEqual(other); } /** * Returns whether this IntegerValue is greater than or equal to the given * ParticularIntegerValue: NEVER, MAYBE, or * ALWAYS. */ public final int greaterThanOrEqual(ParticularIntegerValue other) { return -lessThan(other); } // Implementations for Value. public final IntegerValue integerValue() { return this; } public final Value generalize(Value other) { return this.generalize(other.integerValue()); } public final int computationalType() { return TYPE_INTEGER; } public final String internalType() { return String.valueOf(ClassConstants.INTERNAL_TYPE_INT); } } proguard4.8/src/proguard/evaluation/value/SpecificFloatValue.java0000644000175000017500000001113011736333522024032 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This FloatValue represents a specific float value. * * @author Eric Lafortune */ abstract class SpecificFloatValue extends FloatValue { // Implementations of unary methods of FloatValue. public FloatValue negate() { return new NegatedFloatValue(this); } public IntegerValue convertToInteger() { return new ConvertedIntegerValue(this); } public LongValue convertToLong() { return new ConvertedLongValue(this); } public DoubleValue convertToDouble() { return new ConvertedDoubleValue(this); } // Implementations of binary methods of FloatValue. public FloatValue generalize(FloatValue other) { return other.generalize(this); } public FloatValue add(FloatValue other) { return other.add(this); } public FloatValue subtract(FloatValue other) { return other.subtractFrom(this); } public FloatValue subtractFrom(FloatValue other) { return other.subtract(this); } public FloatValue multiply(FloatValue other) { return other.multiply(this); } public FloatValue divide(FloatValue other) { return other.divideOf(this); } public FloatValue divideOf(FloatValue other) { return other.divide(this); } public FloatValue remainder(FloatValue other) { return other.remainderOf(this); } public FloatValue remainderOf(FloatValue other) { return other.remainder(this); } public IntegerValue compare(FloatValue other) { return other.compareReverse(this); } // Implementations of binary FloatValue methods with SpecificFloatValue // arguments. public FloatValue generalize(SpecificFloatValue other) { return this.equals(other) ? this : ValueFactory.FLOAT_VALUE; } public FloatValue add(SpecificFloatValue other) { return new CompositeFloatValue(this, CompositeFloatValue.ADD, other); } public FloatValue subtract(SpecificFloatValue other) { return new CompositeFloatValue(this, CompositeFloatValue.SUBTRACT, other); } public FloatValue subtractFrom(SpecificFloatValue other) { return new CompositeFloatValue(other, CompositeFloatValue.SUBTRACT, this); } public FloatValue multiply(SpecificFloatValue other) { return new CompositeFloatValue(this, CompositeFloatValue.MULTIPLY, other); } public FloatValue divide(SpecificFloatValue other) { return new CompositeFloatValue(this, CompositeFloatValue.DIVIDE, other); } public FloatValue divideOf(SpecificFloatValue other) { return new CompositeFloatValue(other, CompositeFloatValue.DIVIDE, this); } public FloatValue remainder(SpecificFloatValue other) { return new CompositeFloatValue(this, CompositeFloatValue.REMAINDER, other); } public FloatValue remainderOf(SpecificFloatValue other) { return new CompositeFloatValue(other, CompositeFloatValue.REMAINDER, this); } public IntegerValue compare(SpecificFloatValue other) { return ValueFactory.INTEGER_VALUE; // Not handling NaN properly. //return this.equals(other) ? // SpecificValueFactory.INTEGER_VALUE_0 : // new ComparisonValue(this, other); } // Implementations for Value. public boolean isSpecific() { return true; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } } proguard4.8/src/proguard/evaluation/value/IdentifiedFloatValue.java0000644000175000017500000000361111736333522024356 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This FloatValue represents a float value that is identified by a unique ID. * * @author Eric Lafortune */ final class IdentifiedFloatValue extends SpecificFloatValue { private final ValueFactory valuefactory; private final int id; /** * Creates a new float value with the given ID. */ public IdentifiedFloatValue(ValueFactory valuefactory, int id) { this.valuefactory = valuefactory; this.id = id; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.valuefactory.equals(((IdentifiedFloatValue)object).valuefactory) && this.id == ((IdentifiedFloatValue)object).id; } public int hashCode() { return super.hashCode() ^ valuefactory.hashCode() ^ id; } public String toString() { return "f"+id; } }proguard4.8/src/proguard/evaluation/value/IdentifiedReferenceValue.java0000644000175000017500000000545711736333522025221 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.Clazz; /** * This LongValue represents a reference value that is identified by a unique ID. * * @author Eric Lafortune */ final class IdentifiedReferenceValue extends ReferenceValue { private final ValueFactory valuefactory; private final int id; /** * Creates a new long value with the given ID. */ public IdentifiedReferenceValue(String type, Clazz referencedClass, boolean mayBeNull, ValueFactory valuefactory, int id) { super(type, referencedClass, mayBeNull); this.valuefactory = valuefactory; this.id = id; } // Implementations for ReferenceValue. public int equal(ReferenceValue other) { return this.equals(other) ? ALWAYS : MAYBE; } // Implementations of binary methods of ReferenceValue. public ReferenceValue generalize(ReferenceValue other) { // Remove the ID if both values don't share the same ID. return this.equals(other) ? this : new ReferenceValue(type, referencedClass, mayBeNull).generalize(other); } // Implementations for Value. public boolean isSpecific() { return true; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.valuefactory.equals(((IdentifiedReferenceValue)object).valuefactory) && this.id == ((IdentifiedReferenceValue)object).id; } public int hashCode() { return super.hashCode() ^ valuefactory.hashCode() ^ id; } public String toString() { return super.toString()+'#'+id; } }proguard4.8/src/proguard/evaluation/value/InstructionOffsetValue.java0000644000175000017500000001633711736333522025025 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.ClassConstants; /** * This class represents a partially evaluated instruction offset. It can * contain 0 or more specific instruction offsets. * * @author Eric Lafortune */ public class InstructionOffsetValue extends Category1Value { public static final InstructionOffsetValue EMPTY_VALUE = new InstructionOffsetValue(); private int[] values; private InstructionOffsetValue() { } public InstructionOffsetValue(int value) { this.values = new int[] { value }; } public InstructionOffsetValue(int[] values) { this.values = values; } public int instructionOffsetCount() { return values == null ? 0 : values.length; } public int instructionOffset(int index) { return values[index]; } /** * Returns whether the given value is present in this list of instruction * offsets. */ public boolean contains(int value) { if (values != null) { for (int index = 0; index < values.length; index++) { if (values[index] == value) { return true; } } } return false; } /** * Returns the minimum value from this list of instruction offsets. * Returns Integer.MAX_VALUE if the list is empty. */ public int minimumValue() { int minimumValue = Integer.MAX_VALUE; if (values != null) { for (int index = 0; index < values.length; index++) { int value = values[index]; if (minimumValue > value) { minimumValue = value; } } } return minimumValue; } /** * Returns the maximum value from this list of instruction offsets. * Returns Integer.MIN_VALUE if the list is empty. */ public int maximumValue() { int maximumValue = Integer.MIN_VALUE; if (values != null) { for (int index = 0; index < values.length; index++) { int value = values[index]; if (maximumValue < value) { maximumValue = value; } } } return maximumValue; } /** * Returns the generalization of this InstructionOffsetValue and the given * other InstructionOffsetValue. The values of the other InstructionOffsetValue * are guaranteed to remain at the end of the list, in the same order. */ public final Value generalize(InstructionOffsetValue other) { // If the values array of either is null, return the other one. if (this.values == null) { return other; } if (other.values == null) { return this; } // Compute the length of the union of the arrays. int newLength = this.values.length; for (int index = 0; index < other.values.length; index++) { if (!this.contains(other.values[index])) { newLength++; } } // If the length of the union array is equal to the length of the values // array of either, return it. if (newLength == other.values.length) { return other; } // The ordering of the this array may not be right, so we can't just // use it. //if (newLength == this.values.length) //{ // return this; //} // Create the union array. int[] newValues = new int[newLength]; int newIndex = 0; // Copy the values that are different from the other array. for (int index = 0; index < this.values.length; index++) { if (!other.contains(this.values[index])) { newValues[newIndex++] = this.values[index]; } } // Copy the values from the other array. for (int index = 0; index < other.values.length; index++) { newValues[newIndex++] = other.values[index]; } return new InstructionOffsetValue(newValues); } // Implementations for Value. public final InstructionOffsetValue instructionOffsetValue() { return this; } public boolean isSpecific() { return true; } public boolean isParticular() { return true; } public final Value generalize(Value other) { return this.generalize(other.instructionOffsetValue()); } public final int computationalType() { return TYPE_INSTRUCTION_OFFSET; } public final String internalType() { return String.valueOf(ClassConstants.INTERNAL_TYPE_INT); } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } InstructionOffsetValue other = (InstructionOffsetValue)object; if (this.values == other.values) { return true; } if (this.values == null || other.values == null || this.values.length != other.values.length) { return false; } for (int index = 0; index < other.values.length; index++) { if (!this.contains(other.values[index])) { return false; } } return true; } public int hashCode() { int hashCode = this.getClass().hashCode(); if (values != null) { for (int index = 0; index < values.length; index++) { hashCode ^= values[index]; } } return hashCode; } public String toString() { StringBuffer buffer = new StringBuffer(); if (values != null) { for (int index = 0; index < values.length; index++) { if (index > 0) { buffer.append(','); } buffer.append(values[index]); } } return buffer.append(':').toString(); } } proguard4.8/src/proguard/evaluation/value/IdentifiedValueFactory.java0000644000175000017500000000422611736333522024723 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.*; import proguard.classfile.util.ClassUtil; /** * This class provides methods to create and reuse IntegerValue objects. * * @author Eric Lafortune */ public class IdentifiedValueFactory extends SpecificValueFactory { private int integerID; private int longID; private int floatID; private int doubleID; private int referenceID; // Implementations for ValueFactory. public IntegerValue createIntegerValue() { return new IdentifiedIntegerValue(this, integerID++); } public LongValue createLongValue() { return new IdentifiedLongValue(this, longID++); } public FloatValue createFloatValue() { return new IdentifiedFloatValue(this, floatID++); } public DoubleValue createDoubleValue() { return new IdentifiedDoubleValue(this, doubleID++); } public ReferenceValue createReferenceValue(String type, Clazz referencedClass, boolean mayBeNull) { return type == null ? REFERENCE_VALUE_NULL : new IdentifiedReferenceValue(type, referencedClass, mayBeNull, this, referenceID++); } }proguard4.8/src/proguard/evaluation/value/ConvertedIntegerValue.java0000644000175000017500000000333311736333522024574 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents a integer value that is converted from another * scalar value. * * @author Eric Lafortune */ final class ConvertedIntegerValue extends SpecificIntegerValue { private final Value value; /** * Creates a new converted integer value of the given value. */ public ConvertedIntegerValue(Value value) { this.value = value; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.value.equals(((ConvertedIntegerValue)object).value); } public int hashCode() { return super.hashCode() ^ value.hashCode(); } public String toString() { return "(int)("+value+")"; } }proguard4.8/src/proguard/evaluation/value/UnknownLongValue.java0000644000175000017500000000634411736333522023611 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This class represents a partially evaluated long value. * * @author Eric Lafortune */ public class UnknownLongValue extends LongValue { // Basic unary methods. public LongValue negate() { return this; } public IntegerValue convertToInteger() { return ValueFactory.INTEGER_VALUE; } public FloatValue convertToFloat() { return ValueFactory.FLOAT_VALUE; } public DoubleValue convertToDouble() { return ValueFactory.DOUBLE_VALUE; } // Basic binary methods. public LongValue generalize(LongValue other) { return this; } public LongValue add(LongValue other) { return this; } public LongValue subtract(LongValue other) { return this; } public LongValue subtractFrom(LongValue other) { return this; } public LongValue multiply(LongValue other) throws ArithmeticException { return this; } public LongValue divide(LongValue other) throws ArithmeticException { return this; } public LongValue divideOf(LongValue other) throws ArithmeticException { return this; } public LongValue remainder(LongValue other) throws ArithmeticException { return this; } public LongValue remainderOf(LongValue other) throws ArithmeticException { return this; } public LongValue shiftLeft(IntegerValue other) { return this; } public LongValue shiftRight(IntegerValue other) { return this; } public LongValue unsignedShiftRight(IntegerValue other) { return this; } public LongValue and(LongValue other) { return this; } public LongValue or(LongValue other) { return this; } public LongValue xor(LongValue other) { return this; } public IntegerValue compare(LongValue other) { return ValueFactory.INTEGER_VALUE; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } public String toString() { return "l"; } }proguard4.8/src/proguard/evaluation/value/FloatValue.java0000644000175000017500000002262311736333522022375 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.ClassConstants; /** * This class represents a partially evaluated float value. * * @author Eric Lafortune */ public abstract class FloatValue extends Category1Value { /** * Returns the specific float value, if applicable. */ public float value() { return 0f; } // Basic unary methods. /** * Returns the negated value of this FloatValue. */ public abstract FloatValue negate(); /** * Converts this FloatValue to an IntegerValue. */ public abstract IntegerValue convertToInteger(); /** * Converts this FloatValue to a LongValue. */ public abstract LongValue convertToLong(); /** * Converts this FloatValue to a DoubleValue. */ public abstract DoubleValue convertToDouble(); // Basic binary methods. /** * Returns the generalization of this FloatValue and the given other * FloatValue. */ public abstract FloatValue generalize(FloatValue other); /** * Returns the sum of this FloatValue and the given FloatValue. */ public abstract FloatValue add(FloatValue other); /** * Returns the difference of this FloatValue and the given FloatValue. */ public abstract FloatValue subtract(FloatValue other); /** * Returns the difference of the given FloatValue and this FloatValue. */ public abstract FloatValue subtractFrom(FloatValue other); /** * Returns the product of this FloatValue and the given FloatValue. */ public abstract FloatValue multiply(FloatValue other); /** * Returns the quotient of this FloatValue and the given FloatValue. */ public abstract FloatValue divide(FloatValue other); /** * Returns the quotient of the given FloatValue and this FloatValue. */ public abstract FloatValue divideOf(FloatValue other); /** * Returns the remainder of this FloatValue divided by the given FloatValue. */ public abstract FloatValue remainder(FloatValue other); /** * Returns the remainder of the given FloatValue divided by this FloatValue. */ public abstract FloatValue remainderOf(FloatValue other); /** * Returns an IntegerValue with value -1, 0, or 1, if this FloatValue is * less than, equal to, or greater than the given FloatValue, respectively. */ public abstract IntegerValue compare(FloatValue other); // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this FloatValue is * less than, equal to, or greater than the given FloatValue, respectively. */ public final IntegerValue compareReverse(FloatValue other) { return compare(other).negate(); } // Similar binary methods, but this time with more specific arguments. /** * Returns the generalization of this FloatValue and the given other * SpecificFloatValue. */ public FloatValue generalize(SpecificFloatValue other) { return generalize((FloatValue)other); } /** * Returns the sum of this FloatValue and the given SpecificFloatValue. */ public FloatValue add(SpecificFloatValue other) { return add((FloatValue)other); } /** * Returns the difference of this FloatValue and the given SpecificFloatValue. */ public FloatValue subtract(SpecificFloatValue other) { return subtract((FloatValue)other); } /** * Returns the difference of the given SpecificFloatValue and this FloatValue. */ public FloatValue subtractFrom(SpecificFloatValue other) { return subtractFrom((FloatValue)other); } /** * Returns the product of this FloatValue and the given SpecificFloatValue. */ public FloatValue multiply(SpecificFloatValue other) { return multiply((FloatValue)other); } /** * Returns the quotient of this FloatValue and the given SpecificFloatValue. */ public FloatValue divide(SpecificFloatValue other) { return divide((FloatValue)other); } /** * Returns the quotient of the given SpecificFloatValue and this * FloatValue. */ public FloatValue divideOf(SpecificFloatValue other) { return divideOf((FloatValue)other); } /** * Returns the remainder of this FloatValue divided by the given * SpecificFloatValue. */ public FloatValue remainder(SpecificFloatValue other) { return remainder((FloatValue)other); } /** * Returns the remainder of the given SpecificFloatValue and this * FloatValue. */ public FloatValue remainderOf(SpecificFloatValue other) { return remainderOf((FloatValue)other); } /** * Returns an IntegerValue with value -1, 0, or 1, if this FloatValue is * less than, equal to, or greater than the given SpecificFloatValue, * respectively. */ public IntegerValue compare(SpecificFloatValue other) { return compare((FloatValue)other); } // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this FloatValue is * less than, equal to, or greater than the given SpecificFloatValue, * respectively. */ public final IntegerValue compareReverse(SpecificFloatValue other) { return compare(other).negate(); } // Similar binary methods, but this time with particular arguments. /** * Returns the generalization of this FloatValue and the given other * ParticularFloatValue. */ public FloatValue generalize(ParticularFloatValue other) { return generalize((SpecificFloatValue)other); } /** * Returns the sum of this FloatValue and the given ParticularFloatValue. */ public FloatValue add(ParticularFloatValue other) { return add((SpecificFloatValue)other); } /** * Returns the difference of this FloatValue and the given ParticularFloatValue. */ public FloatValue subtract(ParticularFloatValue other) { return subtract((SpecificFloatValue)other); } /** * Returns the difference of the given ParticularFloatValue and this FloatValue. */ public FloatValue subtractFrom(ParticularFloatValue other) { return subtractFrom((SpecificFloatValue)other); } /** * Returns the product of this FloatValue and the given ParticularFloatValue. */ public FloatValue multiply(ParticularFloatValue other) { return multiply((SpecificFloatValue)other); } /** * Returns the quotient of this FloatValue and the given ParticularFloatValue. */ public FloatValue divide(ParticularFloatValue other) { return divide((SpecificFloatValue)other); } /** * Returns the quotient of the given ParticularFloatValue and this * FloatValue. */ public FloatValue divideOf(ParticularFloatValue other) { return divideOf((SpecificFloatValue)other); } /** * Returns the remainder of this FloatValue divided by the given * ParticularFloatValue. */ public FloatValue remainder(ParticularFloatValue other) { return remainder((SpecificFloatValue)other); } /** * Returns the remainder of the given ParticularFloatValue and this * FloatValue. */ public FloatValue remainderOf(ParticularFloatValue other) { return remainderOf((SpecificFloatValue)other); } /** * Returns an IntegerValue with value -1, 0, or 1, if this FloatValue is * less than, equal to, or greater than the given ParticularFloatValue, * respectively. */ public IntegerValue compare(ParticularFloatValue other) { return compare((SpecificFloatValue)other); } // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this FloatValue is * less than, equal to, or greater than the given ParticularFloatValue, * respectively. */ public final IntegerValue compareReverse(ParticularFloatValue other) { return compare(other).negate(); } // Implementations for Value. public final FloatValue floatValue() { return this; } public final Value generalize(Value other) { return this.generalize(other.floatValue()); } public final int computationalType() { return TYPE_FLOAT; } public final String internalType() { return String.valueOf(ClassConstants.INTERNAL_TYPE_FLOAT); } } proguard4.8/src/proguard/evaluation/value/ComparisonValue.java0000644000175000017500000000365411736333522023445 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents the result of a comparisons of two scalar * values. * * @author Eric Lafortune */ final class ComparisonValue extends SpecificIntegerValue { private final Value value1; private final Value value2; /** * Creates a new comparison integer value of the two given scalar values. */ public ComparisonValue(Value value1, Value value2) { this.value1 = value1; this.value2 = value2; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.value1.equals(((ComparisonValue)object).value1) && this.value2.equals(((ComparisonValue)object).value2); } public int hashCode() { return super.hashCode() ^ value1.hashCode() ^ value2.hashCode(); } public String toString() { return "("+value1+"~"+ value2 +")"; } }proguard4.8/src/proguard/evaluation/value/UnknownIntegerValue.java0000644000175000017500000001037411736333523024306 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This class represents a partially evaluated integer value. * * @author Eric Lafortune */ public class UnknownIntegerValue extends IntegerValue { // Basic unary methods. public IntegerValue negate() { return this; } public IntegerValue convertToByte() { return this; } public IntegerValue convertToCharacter() { return this; } public IntegerValue convertToShort() { return this; } public LongValue convertToLong() { return ValueFactory.LONG_VALUE; } public FloatValue convertToFloat() { return ValueFactory.FLOAT_VALUE; } public DoubleValue convertToDouble() { return ValueFactory.DOUBLE_VALUE; } // Basic binary methods. public IntegerValue generalize(IntegerValue other) { return this; } public IntegerValue add(IntegerValue other) { return this; } public IntegerValue subtract(IntegerValue other) { return this; } public IntegerValue subtractFrom(IntegerValue other) { return this; } public IntegerValue multiply(IntegerValue other) throws ArithmeticException { return this; } public IntegerValue divide(IntegerValue other) throws ArithmeticException { return this; } public IntegerValue divideOf(IntegerValue other) throws ArithmeticException { return this; } public IntegerValue remainder(IntegerValue other) throws ArithmeticException { return this; } public IntegerValue remainderOf(IntegerValue other) throws ArithmeticException { return this; } public IntegerValue shiftLeft(IntegerValue other) { return this; } public IntegerValue shiftLeftOf(IntegerValue other) { return this; } public IntegerValue shiftRight(IntegerValue other) { return this; } public IntegerValue shiftRightOf(IntegerValue other) { return this; } public IntegerValue unsignedShiftRight(IntegerValue other) { return this; } public IntegerValue unsignedShiftRightOf(IntegerValue other) { return this; } public LongValue shiftLeftOf(LongValue other) { return ValueFactory.LONG_VALUE; } public LongValue shiftRightOf(LongValue other) { return ValueFactory.LONG_VALUE; } public LongValue unsignedShiftRightOf(LongValue other) { return ValueFactory.LONG_VALUE; } public IntegerValue and(IntegerValue other) { return this; } public IntegerValue or(IntegerValue other) { return this; } public IntegerValue xor(IntegerValue other) { return this; } public int equal(IntegerValue other) { return MAYBE; } public int lessThan(IntegerValue other) { return MAYBE; } public int lessThanOrEqual(IntegerValue other) { return MAYBE; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } public String toString() { return "i"; } }proguard4.8/src/proguard/evaluation/value/CompositeFloatValue.java0000644000175000017500000000501311736333523024253 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This FloatValue represents the result of a binary operation on two float * values. * * @author Eric Lafortune */ final class CompositeFloatValue extends SpecificFloatValue { public static final byte ADD = '+'; public static final byte SUBTRACT = '-'; public static final byte MULTIPLY = '*'; public static final byte DIVIDE = '/'; public static final byte REMAINDER = '%'; private final FloatValue floatValue1; private final byte operation; private final FloatValue floatValue2; /** * Creates a new composite float value of the two given float values * and the given operation. */ public CompositeFloatValue(FloatValue floatValue1, byte operation, FloatValue floatValue2) { this.floatValue1 = floatValue1; this.operation = operation; this.floatValue2 = floatValue2; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.floatValue1.equals(((CompositeFloatValue)object).floatValue1) && this.operation == ((CompositeFloatValue)object).operation && this.floatValue2.equals(((CompositeFloatValue)object).floatValue2); } public int hashCode() { return super.hashCode() ^ floatValue1.hashCode() ^ floatValue2.hashCode(); } public String toString() { return "("+floatValue1+((char)operation)+floatValue2+")"; } }proguard4.8/src/proguard/evaluation/value/Category1Value.java0000644000175000017500000000241411736333523023163 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This abstract class represents a partially evaluated Category 1 value. * * @author Eric Lafortune */ public abstract class Category1Value extends Value { // Implementations for Value. public final Category1Value category1Value() { return this; } public final boolean isCategory2() { return false; } } proguard4.8/src/proguard/evaluation/value/NegatedLongValue.java0000644000175000017500000000350011736333523023511 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This LongValue represents a long value that is negated. * * @author Eric Lafortune */ final class NegatedLongValue extends SpecificLongValue { private final LongValue longValue; /** * Creates a new negated long value of the given long value. */ public NegatedLongValue(LongValue longValue) { this.longValue = longValue; } // Implementations of unary methods of LongValue. public LongValue negate() { return longValue; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.longValue.equals(((NegatedLongValue)object).longValue); } public int hashCode() { return super.hashCode() ^ longValue.hashCode(); } public String toString() { return "-"+longValue; } }proguard4.8/src/proguard/evaluation/value/IdentifiedDoubleValue.java0000644000175000017500000000362111736333523024525 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This DoubleValue represents a double value that is identified by a unique ID. * * @author Eric Lafortune */ final class IdentifiedDoubleValue extends SpecificDoubleValue { private final ValueFactory valuefactory; private final int id; /** * Creates a new double value with the given ID. */ public IdentifiedDoubleValue(ValueFactory valuefactory, int id) { this.valuefactory = valuefactory; this.id = id; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.valuefactory.equals(((IdentifiedDoubleValue)object).valuefactory) && this.id == ((IdentifiedDoubleValue)object).id; } public int hashCode() { return super.hashCode() ^ valuefactory.hashCode() ^ id; } public String toString() { return "d"+id; } }proguard4.8/src/proguard/evaluation/value/ParticularLongValue.java0000644000175000017500000001430311736333523024253 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This LongValue represents a particular long value. * * @author Eric Lafortune */ final class ParticularLongValue extends SpecificLongValue { private final long value; /** * Creates a new particular long value. */ public ParticularLongValue(long value) { this.value = value; } // Implementations for LongValue. public long value() { return value; } // Implementations of unary methods of LongValue. public LongValue negate() { return new ParticularLongValue(-value); } public IntegerValue convertToInteger() { return new ParticularIntegerValue((int)value); } public FloatValue convertToFloat() { return new ParticularFloatValue((float)value); } public DoubleValue convertToDouble() { return new ParticularDoubleValue((double)value); } // Implementations of binary methods of LongValue. public LongValue generalize(LongValue other) { return other.generalize(this); } public LongValue add(LongValue other) { return other.add(this); } public LongValue subtract(LongValue other) { return other.subtractFrom(this); } public LongValue subtractFrom(LongValue other) { return other.subtract(this); } public LongValue multiply(LongValue other) { return other.multiply(this); } public LongValue divide(LongValue other) throws ArithmeticException { return other.divideOf(this); } public LongValue divideOf(LongValue other) throws ArithmeticException { return other.divide(this); } public LongValue remainder(LongValue other) throws ArithmeticException { return other.remainderOf(this); } public LongValue remainderOf(LongValue other) throws ArithmeticException { return other.remainder(this); } public LongValue shiftLeft(IntegerValue other) { return other.shiftLeftOf(this); } public LongValue shiftRight(IntegerValue other) { return other.shiftRightOf(this); } public LongValue unsignedShiftRight(IntegerValue other) { return other.unsignedShiftRightOf(this); } public LongValue and(LongValue other) { return other.and(this); } public LongValue or(LongValue other) { return other.or(this); } public LongValue xor(LongValue other) { return other.xor(this); } public IntegerValue compare(LongValue other) { return other.compareReverse(this); } // Implementations of binary LongValue methods with ParticularLongValue // arguments. public LongValue generalize(ParticularLongValue other) { return generalize((SpecificLongValue)other); } public LongValue add(ParticularLongValue other) { return new ParticularLongValue(this.value + other.value); } public LongValue subtract(ParticularLongValue other) { return new ParticularLongValue(this.value - other.value); } public LongValue subtractFrom(ParticularLongValue other) { return new ParticularLongValue(other.value - this.value); } public LongValue multiply(ParticularLongValue other) { return new ParticularLongValue(this.value * other.value); } public LongValue divide(ParticularLongValue other) throws ArithmeticException { return new ParticularLongValue(this.value / other.value); } public LongValue divideOf(ParticularLongValue other) throws ArithmeticException { return new ParticularLongValue(other.value / this.value); } public LongValue remainder(ParticularLongValue other) throws ArithmeticException { return new ParticularLongValue(this.value % other.value); } public LongValue remainderOf(ParticularLongValue other) throws ArithmeticException { return new ParticularLongValue(other.value % this.value); } public LongValue shiftLeft(ParticularIntegerValue other) { return new ParticularLongValue(this.value << other.value()); } public LongValue shiftRight(ParticularIntegerValue other) { return new ParticularLongValue(this.value >> other.value()); } public LongValue unsignedShiftRight(ParticularIntegerValue other) { return new ParticularLongValue(this.value >>> other.value()); } public LongValue and(ParticularLongValue other) { return new ParticularLongValue(this.value & other.value); } public LongValue or(ParticularLongValue other) { return new ParticularLongValue(this.value | other.value); } public LongValue xor(ParticularLongValue other) { return new ParticularLongValue(this.value ^ other.value); } // Implementations for Value. public boolean isParticular() { return true; } // Implementations for Object. public boolean equals(Object object) { return super.equals(object) && this.value == ((ParticularLongValue)object).value; } public int hashCode() { return this.getClass().hashCode() ^ (int)value; } public String toString() { return value+"L"; } }proguard4.8/src/proguard/evaluation/value/ConvertedFloatValue.java0000644000175000017500000000331711736333523024247 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This FloatValue represents a float value that is converted from another * scalar value. * * @author Eric Lafortune */ final class ConvertedFloatValue extends SpecificFloatValue { private final Value value; /** * Creates a new converted float value of the given value. */ public ConvertedFloatValue(Value value) { this.value = value; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.value.equals(((ConvertedFloatValue)object).value); } public int hashCode() { return super.hashCode() ^ value.hashCode(); } public String toString() { return "(float)("+value+")"; } }proguard4.8/src/proguard/evaluation/value/SpecificValueFactory.java0000644000175000017500000000762011736333523024406 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This class provides methods to create and reuse IntegerValue objects. * * @author Eric Lafortune */ public class SpecificValueFactory extends ValueFactory { // Shared copies of Value objects, to avoid creating a lot of objects. static final IntegerValue INTEGER_VALUE_M1 = new ParticularIntegerValue(-1); static final IntegerValue INTEGER_VALUE_0 = new ParticularIntegerValue(0); static final IntegerValue INTEGER_VALUE_1 = new ParticularIntegerValue(1); static final IntegerValue INTEGER_VALUE_2 = new ParticularIntegerValue(2); static final IntegerValue INTEGER_VALUE_3 = new ParticularIntegerValue(3); static final IntegerValue INTEGER_VALUE_4 = new ParticularIntegerValue(4); static final IntegerValue INTEGER_VALUE_5 = new ParticularIntegerValue(5); static final LongValue LONG_VALUE_0 = new ParticularLongValue(0); static final LongValue LONG_VALUE_1 = new ParticularLongValue(1); static final FloatValue FLOAT_VALUE_0 = new ParticularFloatValue(0.0f); static final FloatValue FLOAT_VALUE_1 = new ParticularFloatValue(1.0f); static final FloatValue FLOAT_VALUE_2 = new ParticularFloatValue(2.0f); static final DoubleValue DOUBLE_VALUE_0 = new ParticularDoubleValue(0.0); static final DoubleValue DOUBLE_VALUE_1 = new ParticularDoubleValue(1.0); private static int POS_ZERO_FLOAT_BITS = Float.floatToIntBits(0.0f); private static long POS_ZERO_DOUBLE_BITS = Double.doubleToLongBits(0.0); // Implementations for ValueFactory. public IntegerValue createIntegerValue(int value) { switch (value) { case -1: return INTEGER_VALUE_M1; case 0: return INTEGER_VALUE_0; case 1: return INTEGER_VALUE_1; case 2: return INTEGER_VALUE_2; case 3: return INTEGER_VALUE_3; case 4: return INTEGER_VALUE_4; case 5: return INTEGER_VALUE_5; default: return new ParticularIntegerValue(value); } } public LongValue createLongValue(long value) { return value == 0 ? LONG_VALUE_0 : value == 1 ? LONG_VALUE_1 : new ParticularLongValue(value); } public FloatValue createFloatValue(float value) { // Make sure to distinguish between +0.0 and -0.0. return value == 0.0f && Float.floatToIntBits(value) == POS_ZERO_FLOAT_BITS ? FLOAT_VALUE_0 : value == 1.0f ? FLOAT_VALUE_1 : value == 2.0f ? FLOAT_VALUE_2 : new ParticularFloatValue(value); } public DoubleValue createDoubleValue(double value) { // Make sure to distinguish between +0.0 and -0.0. return value == 0.0 && Double.doubleToLongBits(value) == POS_ZERO_DOUBLE_BITS ? DOUBLE_VALUE_0 : value == 1.0 ? DOUBLE_VALUE_1 : new ParticularDoubleValue(value); } } proguard4.8/src/proguard/evaluation/value/NegatedFloatValue.java0000644000175000017500000000352511736333523023666 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This FloatValue represents a float value that is negated. * * @author Eric Lafortune */ final class NegatedFloatValue extends SpecificFloatValue { private final FloatValue floatValue; /** * Creates a new negated float value of the given float value. */ public NegatedFloatValue(FloatValue floatValue) { this.floatValue = floatValue; } // Implementations of unary methods of FloatValue. public FloatValue negate() { return floatValue; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.floatValue.equals(((NegatedFloatValue)object).floatValue); } public int hashCode() { return super.hashCode() ^ floatValue.hashCode(); } public String toString() { return "-"+floatValue; } }proguard4.8/src/proguard/evaluation/value/NegatedIntegerValue.java0000644000175000017500000000357711736333523024225 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents a integer value that is negated. * * @author Eric Lafortune */ final class NegatedIntegerValue extends SpecificIntegerValue { private final IntegerValue integerValue; /** * Creates a new negated integer value of the given integer value. */ public NegatedIntegerValue(IntegerValue integerValue) { this.integerValue = integerValue; } // Implementations of unary methods of IntegerValue. public IntegerValue negate() { return integerValue; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.integerValue.equals(((NegatedIntegerValue)object).integerValue); } public int hashCode() { return super.hashCode() ^ integerValue.hashCode(); } public String toString() { return "-"+integerValue; } }proguard4.8/src/proguard/evaluation/value/ParticularDoubleValue.java0000644000175000017500000001251411736333523024570 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This DoubleValue represents a particular double value. * * @author Eric Lafortune */ final class ParticularDoubleValue extends SpecificDoubleValue { private final double value; /** * Creates a new particular double value. */ public ParticularDoubleValue(double value) { this.value = value; } // Implementations for DoubleValue. public double value() { return value; } // Implementations of unary methods of DoubleValue. public DoubleValue negate() { return new ParticularDoubleValue(-value); } public IntegerValue convertToInteger() { return new ParticularIntegerValue((int)value); } public LongValue convertToLong() { return new ParticularLongValue((long)value); } public FloatValue convertToFloat() { return new ParticularFloatValue((float)value); } // Implementations of binary methods of DoubleValue. public DoubleValue generalize(DoubleValue other) { return other.generalize(this); } public DoubleValue add(DoubleValue other) { // Careful: -0.0 + 0.0 == 0.0 //return value == 0.0 ? other : other.add(this); return other.add(this); } public DoubleValue subtract(DoubleValue other) { // Careful: -0.0 + 0.0 == 0.0 //return value == 0.0 ? other.negate() : other.subtractFrom(this); return other.subtractFrom(this); } public DoubleValue subtractFrom(DoubleValue other) { // Careful: -0.0 + 0.0 == 0.0 //return value == 0.0 ? other : other.subtract(this); return other.subtract(this); } public DoubleValue multiply(DoubleValue other) { return other.multiply(this); } public DoubleValue divide(DoubleValue other) { return other.divideOf(this); } public DoubleValue divideOf(DoubleValue other) { return other.divide(this); } public DoubleValue remainder(DoubleValue other) { return other.remainderOf(this); } public DoubleValue remainderOf(DoubleValue other) { return other.remainder(this); } public IntegerValue compare(DoubleValue other) { return other.compareReverse(this); } // Implementations of binary DoubleValue methods with ParticularDoubleValue // arguments. public DoubleValue generalize(ParticularDoubleValue other) { return this.value == other.value ? this : ValueFactory.DOUBLE_VALUE; } public DoubleValue add(ParticularDoubleValue other) { return new ParticularDoubleValue(this.value + other.value); } public DoubleValue subtract(ParticularDoubleValue other) { return new ParticularDoubleValue(this.value - other.value); } public DoubleValue subtractFrom(ParticularDoubleValue other) { return new ParticularDoubleValue(other.value - this.value); } public DoubleValue multiply(ParticularDoubleValue other) { return new ParticularDoubleValue(this.value * other.value); } public DoubleValue divide(ParticularDoubleValue other) { return new ParticularDoubleValue(this.value / other.value); } public DoubleValue divideOf(ParticularDoubleValue other) { return new ParticularDoubleValue(other.value / this.value); } public DoubleValue remainder(ParticularDoubleValue other) { return new ParticularDoubleValue(this.value % other.value); } public DoubleValue remainderOf(ParticularDoubleValue other) { return new ParticularDoubleValue(other.value % this.value); } public IntegerValue compare(ParticularDoubleValue other) { return this.value < other.value ? SpecificValueFactory.INTEGER_VALUE_M1 : this.value == other.value ? SpecificValueFactory.INTEGER_VALUE_0 : SpecificValueFactory.INTEGER_VALUE_1; } // Implementations for Value. public boolean isParticular() { return true; } // Implementations for Object. public boolean equals(Object object) { return super.equals(object) && this.value == ((ParticularDoubleValue)object).value; } public int hashCode() { return super.hashCode() ^ (int)Double.doubleToLongBits(value); } public String toString() { return value+"d"; } }proguard4.8/src/proguard/evaluation/value/SpecificDoubleValue.java0000644000175000017500000001122611736333523024206 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This DoubleValue represents a specific double value. * * @author Eric Lafortune */ abstract class SpecificDoubleValue extends DoubleValue { // Implementations of unary methods of DoubleValue. public DoubleValue negate() { return new NegatedDoubleValue(this); } public IntegerValue convertToInteger() { return new ConvertedIntegerValue(this); } public LongValue convertToLong() { return new ConvertedLongValue(this); } public FloatValue convertToFloat() { return new ConvertedFloatValue(this); } // Implementations of binary methods of DoubleValue. public DoubleValue generalize(DoubleValue other) { return other.generalize(this); } public DoubleValue add(DoubleValue other) { return other.add(this); } public DoubleValue subtract(DoubleValue other) { return other.subtractFrom(this); } public DoubleValue subtractFrom(DoubleValue other) { return other.subtract(this); } public DoubleValue multiply(DoubleValue other) { return other.multiply(this); } public DoubleValue divide(DoubleValue other) { return other.divideOf(this); } public DoubleValue divideOf(DoubleValue other) { return other.divide(this); } public DoubleValue remainder(DoubleValue other) { return other.remainderOf(this); } public DoubleValue remainderOf(DoubleValue other) { return other.remainder(this); } public IntegerValue compare(DoubleValue other) { return other.compareReverse(this); } // Implementations of binary DoubleValue methods with SpecificDoubleValue // arguments. public DoubleValue generalize(SpecificDoubleValue other) { return this.equals(other) ? this : ValueFactory.DOUBLE_VALUE; } public DoubleValue add(SpecificDoubleValue other) { return new CompositeDoubleValue(this, CompositeDoubleValue.ADD, other); } public DoubleValue subtract(SpecificDoubleValue other) { return new CompositeDoubleValue(this, CompositeDoubleValue.SUBTRACT, other); } public DoubleValue subtractFrom(SpecificDoubleValue other) { return new CompositeDoubleValue(other, CompositeDoubleValue.SUBTRACT, this); } public DoubleValue multiply(SpecificDoubleValue other) { return new CompositeDoubleValue(this, CompositeDoubleValue.MULTIPLY, other); } public DoubleValue divide(SpecificDoubleValue other) { return new CompositeDoubleValue(this, CompositeDoubleValue.DIVIDE, other); } public DoubleValue divideOf(SpecificDoubleValue other) { return new CompositeDoubleValue(other, CompositeDoubleValue.DIVIDE, this); } public DoubleValue remainder(SpecificDoubleValue other) { return new CompositeDoubleValue(this, CompositeDoubleValue.REMAINDER, other); } public DoubleValue remainderOf(SpecificDoubleValue other) { return new CompositeDoubleValue(other, CompositeDoubleValue.REMAINDER, this); } public IntegerValue compare(SpecificDoubleValue other) { return ValueFactory.INTEGER_VALUE; // Not handling NaN properly. //return this.equals(other) ? // SpecificValueFactory.INTEGER_VALUE_0 : // new ComparisonValue(this, other); } // Implementations for Value. public boolean isSpecific() { return true; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } } proguard4.8/src/proguard/evaluation/value/LongValue.java0000644000175000017500000003242611736333523022232 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.ClassConstants; /** * This class represents a partially evaluated long value. * * @author Eric Lafortune */ public abstract class LongValue extends Category2Value { /** * Returns the specific long value, if applicable. */ public long value() { return 0; } // Basic unary methods. /** * Returns the negated value of this LongValue. */ public abstract LongValue negate(); /** * Converts this LongValue to an IntegerValue. */ public abstract IntegerValue convertToInteger(); /** * Converts this LongValue to a FloatValue. */ public abstract FloatValue convertToFloat(); /** * Converts this LongValue to a DoubleValue. */ public abstract DoubleValue convertToDouble(); // Basic binary methods. /** * Returns the generalization of this LongValue and the given other * LongValue. */ public LongValue generalize(LongValue other) { return other.generalize(this); } /** * Returns the sum of this LongValue and the given LongValue. */ public LongValue add(LongValue other) { return other.add(this); } /** * Returns the difference of this LongValue and the given LongValue. */ public LongValue subtract(LongValue other) { return other.subtractFrom(this); } /** * Returns the difference of the given LongValue and this LongValue. */ public LongValue subtractFrom(LongValue other) { return other.subtract(this); } /** * Returns the product of this LongValue and the given LongValue. */ public LongValue multiply(LongValue other) throws ArithmeticException { return other.multiply(this); } /** * Returns the quotient of this LongValue and the given LongValue. */ public LongValue divide(LongValue other) throws ArithmeticException { return other.divideOf(this); } /** * Returns the quotient of the given LongValue and this LongValue. */ public LongValue divideOf(LongValue other) throws ArithmeticException { return other.divide(this); } /** * Returns the remainder of this LongValue divided by the given * LongValue. */ public LongValue remainder(LongValue other) throws ArithmeticException { return other.remainderOf(this); } /** * Returns the remainder of the given LongValue divided by this * LongValue. */ public LongValue remainderOf(LongValue other) throws ArithmeticException { return other.remainder(this); } /** * Returns this LongValue, shifted left by the given IntegerValue. */ public LongValue shiftLeft(IntegerValue other) { return other.shiftLeftOf(this); } /** * Returns this LongValue, shifted right by the given IntegerValue. */ public LongValue shiftRight(IntegerValue other) { return other.shiftRightOf(this); } /** * Returns this unsigned LongValue, shifted left by the given * IntegerValue. */ public LongValue unsignedShiftRight(IntegerValue other) { return other.unsignedShiftRightOf(this); } /** * Returns the logical and of this LongValue and the given * LongValue. */ public LongValue and(LongValue other) { return other.and(this); } /** * Returns the logical or of this LongValue and the given * LongValue. */ public LongValue or(LongValue other) { return other.or(this); } /** * Returns the logical xor of this LongValue and the given * LongValue. */ public LongValue xor(LongValue other) { return other.xor(this); } /** * Returns an IntegerValue with value -1, 0, or 1, if this LongValue is * less than, equal to, or greater than the given LongValue, respectively. */ public IntegerValue compare(LongValue other) { return other.compareReverse(this); } // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this LongValue is * less than, equal to, or greater than the given LongValue, respectively. */ public final IntegerValue compareReverse(LongValue other) { return compare(other).negate(); } // Similar binary methods, but this time with more specific arguments. /** * Returns the generalization of this LongValue and the given other * SpecificLongValue. */ public LongValue generalize(SpecificLongValue other) { return this; } /** * Returns the sum of this LongValue and the given SpecificLongValue. */ public LongValue add(SpecificLongValue other) { return this; } /** * Returns the difference of this LongValue and the given SpecificLongValue. */ public LongValue subtract(SpecificLongValue other) { return this; } /** * Returns the difference of the given SpecificLongValue and this LongValue. */ public LongValue subtractFrom(SpecificLongValue other) { return this; } /** * Returns the product of this LongValue and the given SpecificLongValue. */ public LongValue multiply(SpecificLongValue other) { return this; } /** * Returns the quotient of this LongValue and the given * SpecificLongValue. */ public LongValue divide(SpecificLongValue other) { return this; } /** * Returns the quotient of the given SpecificLongValue and this * LongValue. */ public LongValue divideOf(SpecificLongValue other) { return this; } /** * Returns the remainder of this LongValue divided by the given * SpecificLongValue. */ public LongValue remainder(SpecificLongValue other) { return this; } /** * Returns the remainder of the given SpecificLongValue divided by this * LongValue. */ public LongValue remainderOf(SpecificLongValue other) { return this; } /** * Returns this LongValue, shifted left by the given SpecificLongValue. */ public LongValue shiftLeft(SpecificLongValue other) { return this; } /** * Returns this LongValue, shifted right by the given SpecificLongValue. */ public LongValue shiftRight(SpecificLongValue other) { return this; } /** * Returns this unsigned LongValue, shifted right by the given * SpecificLongValue. */ public LongValue unsignedShiftRight(SpecificLongValue other) { return this; } /** * Returns the logical and of this LongValue and the given * SpecificLongValue. */ public LongValue and(SpecificLongValue other) { return this; } /** * Returns the logical or of this LongValue and the given * SpecificLongValue. */ public LongValue or(SpecificLongValue other) { return this; } /** * Returns the logical xor of this LongValue and the given * SpecificLongValue. */ public LongValue xor(SpecificLongValue other) { return this; } /** * Returns an IntegerValue with value -1, 0, or 1, if this LongValue is * less than, equal to, or greater than the given SpecificLongValue, * respectively. */ public IntegerValue compare(SpecificLongValue other) { return new ComparisonValue(this, other); } // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this LongValue is * less than, equal to, or greater than the given SpecificLongValue, * respectively. */ public final IntegerValue compareReverse(SpecificLongValue other) { return compare(other).negate(); } // Similar binary methods, but this time with particular arguments. /** * Returns the generalization of this LongValue and the given other * ParticularLongValue. */ public LongValue generalize(ParticularLongValue other) { return generalize((SpecificLongValue)other); } /** * Returns the sum of this LongValue and the given ParticularLongValue. */ public LongValue add(ParticularLongValue other) { return add((SpecificLongValue)other); } /** * Returns the difference of this LongValue and the given ParticularLongValue. */ public LongValue subtract(ParticularLongValue other) { return subtract((SpecificLongValue)other); } /** * Returns the difference of the given ParticularLongValue and this LongValue. */ public LongValue subtractFrom(ParticularLongValue other) { return subtractFrom((SpecificLongValue)other); } /** * Returns the product of this LongValue and the given ParticularLongValue. */ public LongValue multiply(ParticularLongValue other) { return multiply((SpecificLongValue)other); } /** * Returns the quotient of this LongValue and the given * ParticularLongValue. */ public LongValue divide(ParticularLongValue other) { return divide((SpecificLongValue)other); } /** * Returns the quotient of the given ParticularLongValue and this * LongValue. */ public LongValue divideOf(ParticularLongValue other) { return divideOf((SpecificLongValue)other); } /** * Returns the remainder of this LongValue divided by the given * ParticularLongValue. */ public LongValue remainder(ParticularLongValue other) { return remainder((SpecificLongValue)other); } /** * Returns the remainder of the given ParticularLongValue divided by this * LongValue. */ public LongValue remainderOf(ParticularLongValue other) { return remainderOf((SpecificLongValue)other); } /** * Returns this LongValue, shifted left by the given ParticularIntegerValue. */ public LongValue shiftLeft(ParticularIntegerValue other) { return shiftLeft((SpecificIntegerValue)other); } /** * Returns this LongValue, shifted right by the given ParticularIntegerValue. */ public LongValue shiftRight(ParticularIntegerValue other) { return shiftRight((SpecificIntegerValue)other); } /** * Returns this unsigned LongValue, shifted right by the given * ParticularIntegerValue. */ public LongValue unsignedShiftRight(ParticularIntegerValue other) { return unsignedShiftRight((SpecificIntegerValue)other); } /** * Returns the logical and of this LongValue and the given * ParticularLongValue. */ public LongValue and(ParticularLongValue other) { return and((SpecificLongValue)other); } /** * Returns the logical or of this LongValue and the given * ParticularLongValue. */ public LongValue or(ParticularLongValue other) { return or((SpecificLongValue)other); } /** * Returns the logical xor of this LongValue and the given * ParticularLongValue. */ public LongValue xor(ParticularLongValue other) { return xor((SpecificLongValue)other); } /** * Returns an IntegerValue with value -1, 0, or 1, if this LongValue is * less than, equal to, or greater than the given ParticularLongValue, * respectively. */ public IntegerValue compare(ParticularLongValue other) { return compare((SpecificLongValue)other); } // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this LongValue is * less than, equal to, or greater than the given ParticularLongValue, * respectively. */ public final IntegerValue compareReverse(ParticularLongValue other) { return compare(other).negate(); } // Implementations for Value. public final LongValue longValue() { return this; } public final Value generalize(Value other) { return this.generalize(other.longValue()); } public final int computationalType() { return TYPE_LONG; } public final String internalType() { return String.valueOf(ClassConstants.INTERNAL_TYPE_INT); } } proguard4.8/src/proguard/evaluation/value/CompositeIntegerValue.java0000644000175000017500000000574211736333523024614 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents the result of a binary operation on two integer * values. * * @author Eric Lafortune */ final class CompositeIntegerValue extends SpecificIntegerValue { public static final byte ADD = '+'; public static final byte SUBTRACT = '-'; public static final byte MULTIPLY = '*'; public static final byte DIVIDE = '/'; public static final byte REMAINDER = '%'; public static final byte SHIFT_LEFT = '<'; public static final byte SHIFT_RIGHT = '>'; public static final byte UNSIGNED_SHIFT_RIGHT = '}'; public static final byte AND = '&'; public static final byte OR = '|'; public static final byte XOR = '^'; private final IntegerValue integerValue1; private final byte operation; private final IntegerValue integerValue2; /** * Creates a new composite integer value of the two given integer values * and the given operation. */ public CompositeIntegerValue(IntegerValue integerValue1, byte operation, IntegerValue integerValue2) { this.integerValue1 = integerValue1; this.operation = operation; this.integerValue2 = integerValue2; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.integerValue1.equals(((CompositeIntegerValue)object).integerValue1) && this.operation == ((CompositeIntegerValue)object).operation && this.integerValue2.equals(((CompositeIntegerValue)object).integerValue2); } public int hashCode() { return super.hashCode() ^ integerValue1.hashCode() ^ integerValue2.hashCode(); } public String toString() { return "("+integerValue1+((char)operation)+integerValue2+")"; } }proguard4.8/src/proguard/evaluation/value/ValueFactory.java0000644000175000017500000001620511736333523022737 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.*; import proguard.classfile.util.ClassUtil; /** * This class provides methods to create and reuse Value objects. * * @author Eric Lafortune */ public class ValueFactory { // Shared copies of Value objects, to avoid creating a lot of objects. static final IntegerValue INTEGER_VALUE = new UnknownIntegerValue(); static final LongValue LONG_VALUE = new UnknownLongValue(); static final FloatValue FLOAT_VALUE = new UnknownFloatValue(); static final DoubleValue DOUBLE_VALUE = new UnknownDoubleValue(); static final ReferenceValue REFERENCE_VALUE_NULL = new ReferenceValue(null, null, true); static final ReferenceValue REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL = new ReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT, null, true); static final ReferenceValue REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL = new ReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT, null, false); /** * Creates a new Value of the given type. * The type must be a fully specified internal type for primitives, classes, * or arrays. */ public Value createValue(String type, Clazz referencedClass, boolean mayBeNull) { switch (type.charAt(0)) { case ClassConstants.INTERNAL_TYPE_VOID: return null; case ClassConstants.INTERNAL_TYPE_BOOLEAN: case ClassConstants.INTERNAL_TYPE_BYTE: case ClassConstants.INTERNAL_TYPE_CHAR: case ClassConstants.INTERNAL_TYPE_SHORT: case ClassConstants.INTERNAL_TYPE_INT: return createIntegerValue(); case ClassConstants.INTERNAL_TYPE_LONG: return createLongValue(); case ClassConstants.INTERNAL_TYPE_FLOAT: return createFloatValue(); case ClassConstants.INTERNAL_TYPE_DOUBLE: return createDoubleValue(); default: return createReferenceValue(ClassUtil.isInternalArrayType(type) ? type : ClassUtil.internalClassNameFromClassType(type), referencedClass, mayBeNull); } } /** * Creates a new IntegerValue with an undefined value. */ public IntegerValue createIntegerValue() { return INTEGER_VALUE; } /** * Creates a new IntegerValue with a given particular value. */ public IntegerValue createIntegerValue(int value) { return createIntegerValue(); } /** * Creates a new LongValue with an undefined value. */ public LongValue createLongValue() { return LONG_VALUE; } /** * Creates a new LongValue with a given particular value. */ public LongValue createLongValue(long value) { return createLongValue(); } /** * Creates a new FloatValue with an undefined value. */ public FloatValue createFloatValue() { return FLOAT_VALUE; } /** * Creates a new FloatValue with a given particular value. */ public FloatValue createFloatValue(float value) { return createFloatValue(); } /** * Creates a new DoubleValue with an undefined value. */ public DoubleValue createDoubleValue() { return DOUBLE_VALUE; } /** * Creates a new DoubleValue with a given particular value. */ public DoubleValue createDoubleValue(double value) { return createDoubleValue(); } /** * Creates a new ReferenceValue that represents null. */ public ReferenceValue createReferenceValueNull() { return REFERENCE_VALUE_NULL; } /** * Creates a new ReferenceValue of the given type. The type must be an * internal class name or an array type. If the type is null, * the ReferenceValue represents null. */ public ReferenceValue createReferenceValue(String type, Clazz referencedClass, boolean mayBeNull) { return type == null ? REFERENCE_VALUE_NULL : !type.equals(ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT) ? new ReferenceValue(type, referencedClass, mayBeNull) : mayBeNull ? REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL : REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL; } /** * Creates a new ReferenceValue for arrays of the given type and length. * The type must be a fully specified internal type for primitives, classes, * or arrays. */ public ReferenceValue createArrayReferenceValue(String type, Clazz referencedClass, IntegerValue arrayLength) { return createArrayReferenceValue(type, referencedClass, arrayLength, createValue(type, referencedClass, false)); } /** * Creates a new ReferenceValue for arrays of the given type and length, * containing the given element. The type must be a fully specified internal * type for primitives, classes, or arrays. */ public ReferenceValue createArrayReferenceValue(String type, Clazz referencedClass, IntegerValue arrayLength, Value elementValue) { return createReferenceValue(ClassConstants.INTERNAL_TYPE_ARRAY + type, referencedClass, false); } } proguard4.8/src/proguard/evaluation/value/DoubleValue.java0000644000175000017500000002306111736333523022540 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.ClassConstants; /** * This class represents a partially evaluated double value. * * @author Eric Lafortune */ public abstract class DoubleValue extends Category2Value { /** * Returns the specific double value, if applicable. */ public double value() { return 0.0; } // Basic unary methods. /** * Returns the negated value of this DoubleValue. */ public abstract DoubleValue negate(); /** * Converts this DoubleValue to an IntegerValue. */ public abstract IntegerValue convertToInteger(); /** * Converts this DoubleValue to a LongValue. */ public abstract LongValue convertToLong(); /** * Converts this DoubleValue to a FloatValue. */ public abstract FloatValue convertToFloat(); // Basic binary methods. /** * Returns the generalization of this DoubleValue and the given other * DoubleValue. */ public abstract DoubleValue generalize(DoubleValue other); /** * Returns the sum of this DoubleValue and the given DoubleValue. */ public abstract DoubleValue add(DoubleValue other); /** * Returns the difference of this DoubleValue and the given DoubleValue. */ public abstract DoubleValue subtract(DoubleValue other); /** * Returns the difference of the given DoubleValue and this DoubleValue. */ public abstract DoubleValue subtractFrom(DoubleValue other); /** * Returns the product of this DoubleValue and the given DoubleValue. */ public abstract DoubleValue multiply(DoubleValue other); /** * Returns the quotient of this DoubleValue and the given DoubleValue. */ public abstract DoubleValue divide(DoubleValue other); /** * Returns the quotient of the given DoubleValue and this DoubleValue. */ public abstract DoubleValue divideOf(DoubleValue other); /** * Returns the remainder of this DoubleValue divided by the given DoubleValue. */ public abstract DoubleValue remainder(DoubleValue other); /** * Returns the remainder of the given DoubleValue divided by this DoubleValue. */ public abstract DoubleValue remainderOf(DoubleValue other); /** * Returns an IntegerValue with value -1, 0, or 1, if this DoubleValue is * less than, equal to, or greater than the given DoubleValue, respectively. */ public abstract IntegerValue compare(DoubleValue other); // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this DoubleValue is * less than, equal to, or greater than the given DoubleValue, respectively. */ public final IntegerValue compareReverse(DoubleValue other) { return compare(other).negate(); } // Similar binary methods, but this time with more specific arguments. /** * Returns the generalization of this DoubleValue and the given other * SpecificDoubleValue. */ public DoubleValue generalize(SpecificDoubleValue other) { return generalize((DoubleValue)other); } /** * Returns the sum of this DoubleValue and the given SpecificDoubleValue. */ public DoubleValue add(SpecificDoubleValue other) { return add((DoubleValue)other); } /** * Returns the difference of this DoubleValue and the given SpecificDoubleValue. */ public DoubleValue subtract(SpecificDoubleValue other) { return subtract((DoubleValue)other); } /** * Returns the difference of the given SpecificDoubleValue and this DoubleValue. */ public DoubleValue subtractFrom(SpecificDoubleValue other) { return subtractFrom((DoubleValue)other); } /** * Returns the product of this DoubleValue and the given SpecificDoubleValue. */ public DoubleValue multiply(SpecificDoubleValue other) { return multiply((DoubleValue)other); } /** * Returns the quotient of this DoubleValue and the given SpecificDoubleValue. */ public DoubleValue divide(SpecificDoubleValue other) { return divide((DoubleValue)other); } /** * Returns the quotient of the given SpecificDoubleValue and this * DoubleValue. */ public DoubleValue divideOf(SpecificDoubleValue other) { return divideOf((DoubleValue)other); } /** * Returns the remainder of this DoubleValue divided by the given * SpecificDoubleValue. */ public DoubleValue remainder(SpecificDoubleValue other) { return remainder((DoubleValue)other); } /** * Returns the remainder of the given SpecificDoubleValue and this * DoubleValue. */ public DoubleValue remainderOf(SpecificDoubleValue other) { return remainderOf((DoubleValue)other); } /** * Returns an IntegerValue with value -1, 0, or 1, if this DoubleValue is * less than, equal to, or greater than the given SpecificDoubleValue, * respectively. */ public IntegerValue compare(SpecificDoubleValue other) { return compare((DoubleValue)other); } // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this DoubleValue is * less than, equal to, or greater than the given SpecificDoubleValue, * respectively. */ public final IntegerValue compareReverse(SpecificDoubleValue other) { return compare(other).negate(); } // Similar binary methods, but this time with particular arguments. /** * Returns the generalization of this DoubleValue and the given other * ParticularDoubleValue. */ public DoubleValue generalize(ParticularDoubleValue other) { return generalize((SpecificDoubleValue)other); } /** * Returns the sum of this DoubleValue and the given ParticularDoubleValue. */ public DoubleValue add(ParticularDoubleValue other) { return add((SpecificDoubleValue)other); } /** * Returns the difference of this DoubleValue and the given ParticularDoubleValue. */ public DoubleValue subtract(ParticularDoubleValue other) { return subtract((SpecificDoubleValue)other); } /** * Returns the difference of the given ParticularDoubleValue and this DoubleValue. */ public DoubleValue subtractFrom(ParticularDoubleValue other) { return subtractFrom((SpecificDoubleValue)other); } /** * Returns the product of this DoubleValue and the given ParticularDoubleValue. */ public DoubleValue multiply(ParticularDoubleValue other) { return multiply((SpecificDoubleValue)other); } /** * Returns the quotient of this DoubleValue and the given ParticularDoubleValue. */ public DoubleValue divide(ParticularDoubleValue other) { return divide((SpecificDoubleValue)other); } /** * Returns the quotient of the given ParticularDoubleValue and this * DoubleValue. */ public DoubleValue divideOf(ParticularDoubleValue other) { return divideOf((SpecificDoubleValue)other); } /** * Returns the remainder of this DoubleValue divided by the given * ParticularDoubleValue. */ public DoubleValue remainder(ParticularDoubleValue other) { return remainder((SpecificDoubleValue)other); } /** * Returns the remainder of the given ParticularDoubleValue and this * DoubleValue. */ public DoubleValue remainderOf(ParticularDoubleValue other) { return remainderOf((SpecificDoubleValue)other); } /** * Returns an IntegerValue with value -1, 0, or 1, if this DoubleValue is * less than, equal to, or greater than the given ParticularDoubleValue, * respectively. */ public IntegerValue compare(ParticularDoubleValue other) { return compare((SpecificDoubleValue)other); } // Derived binary methods. /** * Returns an IntegerValue with value 1, 0, or -1, if this DoubleValue is * less than, equal to, or greater than the given ParticularDoubleValue, * respectively. */ public final IntegerValue compareReverse(ParticularDoubleValue other) { return compare(other).negate(); } // Implementations for Value. public final DoubleValue doubleValue() { return this; } public final Value generalize(Value other) { return this.generalize(other.doubleValue()); } public final int computationalType() { return TYPE_DOUBLE; } public final String internalType() { return String.valueOf(ClassConstants.INTERNAL_TYPE_DOUBLE); } } proguard4.8/src/proguard/evaluation/value/ConvertedCharacterValue.java0000644000175000017500000000337011736333523025075 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents a character value that is converted from an * integer value. * * @author Eric Lafortune */ final class ConvertedCharacterValue extends SpecificIntegerValue { private final IntegerValue value; /** * Creates a new converted character value of the given integer value. */ public ConvertedCharacterValue(IntegerValue value) { this.value = value; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.value.equals(((ConvertedCharacterValue)object).value); } public int hashCode() { return super.hashCode() ^ value.hashCode(); } public String toString() { return "(char)("+value+")"; } }proguard4.8/src/proguard/evaluation/value/SpecificLongValue.java0000644000175000017500000001461411736333523023677 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This LongValue represents a specific long value. * * @author Eric Lafortune */ abstract class SpecificLongValue extends LongValue { // Implementations of unary methods of LongValue. public LongValue negate() { return new NegatedLongValue(this); } public IntegerValue convertToInteger() { return new ConvertedIntegerValue(this); } public FloatValue convertToFloat() { return new ConvertedFloatValue(this); } public DoubleValue convertToDouble() { return new ConvertedDoubleValue(this); } // Implementations of binary methods of LongValue. public LongValue generalize(LongValue other) { return other.generalize(this); } public LongValue add(LongValue other) { return other.add(this); } public LongValue subtract(LongValue other) { return other.subtractFrom(this); } public LongValue subtractFrom(LongValue other) { return other.subtract(this); } public LongValue multiply(LongValue other) { return other.multiply(this); } public LongValue divide(LongValue other) throws ArithmeticException { return other.divideOf(this); } public LongValue divideOf(LongValue other) throws ArithmeticException { return other.divide(this); } public LongValue remainder(LongValue other) throws ArithmeticException { return other.remainderOf(this); } public LongValue remainderOf(LongValue other) throws ArithmeticException { return other.remainder(this); } public LongValue shiftLeft(IntegerValue other) { return other.shiftLeftOf(this); } public LongValue shiftRight(IntegerValue other) { return other.shiftRightOf(this); } public LongValue unsignedShiftRight(IntegerValue other) { return other.unsignedShiftRightOf(this); } public LongValue and(LongValue other) { return other.and(this); } public LongValue or(LongValue other) { return other.or(this); } public LongValue xor(LongValue other) { return other.xor(this); } public IntegerValue compare(LongValue other) { return other.compareReverse(this); } // Implementations of binary LongValue methods with SpecificLongValue // arguments. public LongValue generalize(SpecificLongValue other) { return this.equals(other) ? this : ValueFactory.LONG_VALUE; } public LongValue add(SpecificLongValue other) { return new CompositeLongValue(this, CompositeLongValue.ADD, other); } public LongValue subtract(SpecificLongValue other) { return this.equals(other) ? SpecificValueFactory.LONG_VALUE_0 : new CompositeLongValue(this, CompositeLongValue.SUBTRACT, other); } public LongValue subtractFrom(SpecificLongValue other) { return this.equals(other) ? SpecificValueFactory.LONG_VALUE_0 : new CompositeLongValue(other, CompositeLongValue.SUBTRACT, this); } public LongValue multiply(SpecificLongValue other) { return new CompositeLongValue(this, CompositeLongValue.MULTIPLY, other); } public LongValue divide(SpecificLongValue other) throws ArithmeticException { return new CompositeLongValue(this, CompositeLongValue.DIVIDE, other); } public LongValue divideOf(SpecificLongValue other) throws ArithmeticException { return new CompositeLongValue(other, CompositeLongValue.DIVIDE, this); } public LongValue remainder(SpecificLongValue other) throws ArithmeticException { return new CompositeLongValue(this, CompositeLongValue.REMAINDER, other); } public LongValue remainderOf(SpecificLongValue other) throws ArithmeticException { return new CompositeLongValue(other, CompositeLongValue.REMAINDER, this); } public LongValue shiftLeft(SpecificLongValue other) { return new CompositeLongValue(this, CompositeLongValue.SHIFT_LEFT, other); } public LongValue shiftRight(SpecificLongValue other) { return new CompositeLongValue(this, CompositeLongValue.SHIFT_RIGHT, other); } public LongValue unsignedShiftRight(SpecificLongValue other) { return new CompositeLongValue(this, CompositeLongValue.UNSIGNED_SHIFT_RIGHT, other); } public LongValue and(SpecificLongValue other) { return this.equals(other) ? this : new CompositeLongValue(other, CompositeLongValue.AND, this); } public LongValue or(SpecificLongValue other) { return this.equals(other) ? this : new CompositeLongValue(other, CompositeLongValue.OR, this); } public LongValue xor(SpecificLongValue other) { return this.equals(other) ? SpecificValueFactory.LONG_VALUE_0 : new CompositeLongValue(other, CompositeLongValue.XOR, this); } public IntegerValue compare(SpecificLongValue other) { return new ComparisonValue(this, other); } // Implementations for Value. public boolean isSpecific() { return true; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } } proguard4.8/src/proguard/evaluation/value/SpecificIntegerValue.java0000644000175000017500000002201211736333523024364 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents a specific integer value. * * @author Eric Lafortune */ abstract class SpecificIntegerValue extends IntegerValue { // Implementations of unary methods of IntegerValue. public IntegerValue negate() { return new NegatedIntegerValue(this); } public IntegerValue convertToByte() { return new ConvertedByteValue(this); } public IntegerValue convertToCharacter() { return new ConvertedCharacterValue(this); } public IntegerValue convertToShort() { return new ConvertedShortValue(this); } public LongValue convertToLong() { return new ConvertedLongValue(this); } public FloatValue convertToFloat() { return new ConvertedFloatValue(this); } public DoubleValue convertToDouble() { return new ConvertedDoubleValue(this); } // Implementations of binary methods of IntegerValue. public IntegerValue generalize(IntegerValue other) { return other.generalize(this); } public IntegerValue add(IntegerValue other) { return other.add(this); } public IntegerValue subtract(IntegerValue other) { return other.subtractFrom(this); } public IntegerValue subtractFrom(IntegerValue other) { return other.subtract(this); } public IntegerValue multiply(IntegerValue other) { return other.multiply(this); } public IntegerValue divide(IntegerValue other) throws ArithmeticException { return other.divideOf(this); } public IntegerValue divideOf(IntegerValue other) throws ArithmeticException { return other.divide(this); } public IntegerValue remainder(IntegerValue other) throws ArithmeticException { return other.remainderOf(this); } public IntegerValue remainderOf(IntegerValue other) throws ArithmeticException { return other.remainder(this); } public IntegerValue shiftLeft(IntegerValue other) { return other.shiftLeftOf(this); } public IntegerValue shiftLeftOf(IntegerValue other) { return other.shiftLeft(this); } public IntegerValue shiftRight(IntegerValue other) { return other.shiftRightOf(this); } public IntegerValue shiftRightOf(IntegerValue other) { return other.shiftRight(this); } public IntegerValue unsignedShiftRight(IntegerValue other) { return other.unsignedShiftRightOf(this); } public IntegerValue unsignedShiftRightOf(IntegerValue other) { return other.unsignedShiftRight(this); } public LongValue shiftLeftOf(LongValue other) { return other.shiftLeft(this); } public LongValue shiftRightOf(LongValue other) { return other.shiftRight(this); } public LongValue unsignedShiftRightOf(LongValue other) { return other.unsignedShiftRight(this); } public IntegerValue and(IntegerValue other) { return other.and(this); } public IntegerValue or(IntegerValue other) { return other.or(this); } public IntegerValue xor(IntegerValue other) { return other.xor(this); } public int equal(IntegerValue other) { return other.equal(this); } public int lessThan(IntegerValue other) { return other.greaterThan(this); } public int lessThanOrEqual(IntegerValue other) { return other.greaterThanOrEqual(this); } // Implementations of binary IntegerValue methods with SpecificIntegerValue // arguments. public IntegerValue generalize(SpecificIntegerValue other) { return this.equals(other) ? this : ValueFactory.INTEGER_VALUE; } public IntegerValue add(SpecificIntegerValue other) { return new CompositeIntegerValue(this, CompositeIntegerValue.ADD, other); } public IntegerValue subtract(SpecificIntegerValue other) { return this.equals(other) ? SpecificValueFactory.INTEGER_VALUE_0 : new CompositeIntegerValue(this, CompositeIntegerValue.SUBTRACT, other); } public IntegerValue subtractFrom(SpecificIntegerValue other) { return this.equals(other) ? SpecificValueFactory.INTEGER_VALUE_0 : new CompositeIntegerValue(other, CompositeIntegerValue.SUBTRACT, this); } public IntegerValue multiply(SpecificIntegerValue other) { return new CompositeIntegerValue(this, CompositeIntegerValue.MULTIPLY, other); } public IntegerValue divide(SpecificIntegerValue other) throws ArithmeticException { return new CompositeIntegerValue(this, CompositeIntegerValue.DIVIDE, other); } public IntegerValue divideOf(SpecificIntegerValue other) throws ArithmeticException { return new CompositeIntegerValue(other, CompositeIntegerValue.DIVIDE, this); } public IntegerValue remainder(SpecificIntegerValue other) throws ArithmeticException { return new CompositeIntegerValue(this, CompositeIntegerValue.REMAINDER, other); } public IntegerValue remainderOf(SpecificIntegerValue other) throws ArithmeticException { return new CompositeIntegerValue(other, CompositeIntegerValue.REMAINDER, this); } public IntegerValue shiftLeft(SpecificIntegerValue other) { return new CompositeIntegerValue(this, CompositeIntegerValue.SHIFT_LEFT, other); } public IntegerValue shiftRight(SpecificIntegerValue other) { return new CompositeIntegerValue(this, CompositeIntegerValue.SHIFT_RIGHT, other); } public IntegerValue unsignedShiftRight(SpecificIntegerValue other) { return new CompositeIntegerValue(this, CompositeIntegerValue.UNSIGNED_SHIFT_RIGHT, other); } public IntegerValue shiftLeftOf(SpecificIntegerValue other) { return new CompositeIntegerValue(other, CompositeIntegerValue.SHIFT_LEFT, this); } public IntegerValue shiftRightOf(SpecificIntegerValue other) { return new CompositeIntegerValue(other, CompositeIntegerValue.SHIFT_RIGHT, this); } public IntegerValue unsignedShiftRightOf(SpecificIntegerValue other) { return new CompositeIntegerValue(other, CompositeIntegerValue.UNSIGNED_SHIFT_RIGHT, this); } public LongValue shiftLeftOf(SpecificLongValue other) { return new CompositeLongValue(other, CompositeLongValue.SHIFT_LEFT, this); } public LongValue shiftRightOf(SpecificLongValue other) { return new CompositeLongValue(other, CompositeLongValue.SHIFT_RIGHT, this); } public LongValue unsignedShiftRightOf(SpecificLongValue other) { return new CompositeLongValue(other, CompositeLongValue.UNSIGNED_SHIFT_RIGHT, this); } public IntegerValue and(SpecificIntegerValue other) { return this.equals(other) ? this : new CompositeIntegerValue(other, CompositeIntegerValue.AND, this); } public IntegerValue or(SpecificIntegerValue other) { return this.equals(other) ? this : new CompositeIntegerValue(other, CompositeIntegerValue.OR, this); } public IntegerValue xor(SpecificIntegerValue other) { return this.equals(other) ? SpecificValueFactory.INTEGER_VALUE_0 : new CompositeIntegerValue(other, CompositeIntegerValue.XOR, this); } public int equal(SpecificIntegerValue other) { return this.equals(other) ? ALWAYS : MAYBE; } public int lessThan(SpecificIntegerValue other) { return this.equals(other) ? NEVER : MAYBE; } public int lessThanOrEqual(SpecificIntegerValue other) { return this.equals(other) ? ALWAYS : MAYBE; } // Implementations for Value. public boolean isSpecific() { return true; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } } proguard4.8/src/proguard/evaluation/value/ConvertedLongValue.java0000644000175000017500000000330711736333523024100 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This LongValue represents a long value that is converted from another * scalar value. * * @author Eric Lafortune */ final class ConvertedLongValue extends SpecificLongValue { private final Value value; /** * Creates a new converted long value of the given value. */ public ConvertedLongValue(Value value) { this.value = value; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.value.equals(((ConvertedLongValue)object).value); } public int hashCode() { return super.hashCode() ^ value.hashCode(); } public String toString() { return "(long)("+value+")"; } }proguard4.8/src/proguard/evaluation/value/IdentifiedLongValue.java0000644000175000017500000000360111736333523024210 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This LongValue represents a long value that is identified by a unique ID. * * @author Eric Lafortune */ final class IdentifiedLongValue extends SpecificLongValue { private final ValueFactory valuefactory; private final int id; /** * Creates a new long value with the given ID. */ public IdentifiedLongValue(ValueFactory valuefactory, int id) { this.valuefactory = valuefactory; this.id = id; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.valuefactory.equals(((IdentifiedLongValue)object).valuefactory) && this.id == ((IdentifiedLongValue)object).id; } public int hashCode() { return super.hashCode() ^ valuefactory.hashCode() ^ id; } public String toString() { return "l"+id; } }proguard4.8/src/proguard/evaluation/value/UnknownDoubleValue.java0000644000175000017500000000520511736333523024120 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This class represents a partially evaluated double value. * * @author Eric Lafortune */ public class UnknownDoubleValue extends DoubleValue { // Basic unary methods. public DoubleValue negate() { return this; } public IntegerValue convertToInteger() { return ValueFactory.INTEGER_VALUE; } public LongValue convertToLong() { return ValueFactory.LONG_VALUE; } public FloatValue convertToFloat() { return ValueFactory.FLOAT_VALUE; } // Basic binary methods. public DoubleValue generalize(DoubleValue other) { return this; } public DoubleValue add(DoubleValue other) { return this; } public DoubleValue subtract(DoubleValue other) { return this; } public DoubleValue subtractFrom(DoubleValue other) { return this; } public DoubleValue multiply(DoubleValue other) { return this; } public DoubleValue divide(DoubleValue other) { return this; } public DoubleValue divideOf(DoubleValue other) { return this; } public DoubleValue remainder(DoubleValue other) { return this; } public DoubleValue remainderOf(DoubleValue other) { return this; } public IntegerValue compare(DoubleValue other) { return ValueFactory.INTEGER_VALUE; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } public String toString() { return "d"; } }proguard4.8/src/proguard/evaluation/value/ParticularFloatValue.java0000644000175000017500000001240711736333523024424 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This FloatValue represents a particular float value. * * @author Eric Lafortune */ final class ParticularFloatValue extends SpecificFloatValue { private final float value; /** * Creates a new particular float value. */ public ParticularFloatValue(float value) { this.value = value; } // Implementations for FloatValue. public float value() { return value; } // Implementations of unary methods of FloatValue. public FloatValue negate() { return new ParticularFloatValue(-value); } public IntegerValue convertToInteger() { return new ParticularIntegerValue((int)value); } public LongValue convertToLong() { return new ParticularLongValue((long)value); } public DoubleValue convertToDouble() { return new ParticularDoubleValue((float)value); } // Implementations of binary methods of FloatValue. public FloatValue generalize(FloatValue other) { return other.generalize(this); } public FloatValue add(FloatValue other) { // Careful: -0.0 + 0.0 == 0.0 //return value == 0.0 ? other : other.add(this); return other.add(this); } public FloatValue subtract(FloatValue other) { // Careful: -0.0 + 0.0 == 0.0 //return value == 0.0 ? other.negate() : other.subtractFrom(this); return other.subtractFrom(this); } public FloatValue subtractFrom(FloatValue other) { // Careful: -0.0 + 0.0 == 0.0 //return value == 0.0 ? other : other.subtract(this); return other.subtract(this); } public FloatValue multiply(FloatValue other) { return other.multiply(this); } public FloatValue divide(FloatValue other) { return other.divideOf(this); } public FloatValue divideOf(FloatValue other) { return other.divide(this); } public FloatValue remainder(FloatValue other) { return other.remainderOf(this); } public FloatValue remainderOf(FloatValue other) { return other.remainder(this); } public IntegerValue compare(FloatValue other) { return other.compareReverse(this); } // Implementations of binary FloatValue methods with ParticularFloatValue // arguments. public FloatValue generalize(ParticularFloatValue other) { return this.value == other.value ? this : ValueFactory.FLOAT_VALUE; } public FloatValue add(ParticularFloatValue other) { return new ParticularFloatValue(this.value + other.value); } public FloatValue subtract(ParticularFloatValue other) { return new ParticularFloatValue(this.value - other.value); } public FloatValue subtractFrom(ParticularFloatValue other) { return new ParticularFloatValue(other.value - this.value); } public FloatValue multiply(ParticularFloatValue other) { return new ParticularFloatValue(this.value * other.value); } public FloatValue divide(ParticularFloatValue other) { return new ParticularFloatValue(this.value / other.value); } public FloatValue divideOf(ParticularFloatValue other) { return new ParticularFloatValue(other.value / this.value); } public FloatValue remainder(ParticularFloatValue other) { return new ParticularFloatValue(this.value % other.value); } public FloatValue remainderOf(ParticularFloatValue other) { return new ParticularFloatValue(other.value % this.value); } public IntegerValue compare(ParticularFloatValue other) { return this.value < other.value ? SpecificValueFactory.INTEGER_VALUE_M1 : this.value == other.value ? SpecificValueFactory.INTEGER_VALUE_0 : SpecificValueFactory.INTEGER_VALUE_1; } // Implementations for Value. public boolean isParticular() { return true; } // Implementations for Object. public boolean equals(Object object) { return super.equals(object) && this.value == ((ParticularFloatValue)object).value; } public int hashCode() { return super.hashCode() ^ Float.floatToIntBits(value); } public String toString() { return value+"f"; } }proguard4.8/src/proguard/evaluation/value/ConvertedDoubleValue.java0000644000175000017500000000332711736333523024415 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This DoubleValue represents a double value that is converted from another * scalar value. * * @author Eric Lafortune */ final class ConvertedDoubleValue extends SpecificDoubleValue { private final Value value; /** * Creates a new converted double value of the given value. */ public ConvertedDoubleValue(Value value) { this.value = value; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.value.equals(((ConvertedDoubleValue)object).value); } public int hashCode() { return super.hashCode() ^ value.hashCode(); } public String toString() { return "(double)("+value+")"; } }proguard4.8/src/proguard/evaluation/value/ReferenceValue.java0000644000175000017500000004467511736333523023242 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; import proguard.classfile.*; import proguard.classfile.util.ClassUtil; import proguard.classfile.visitor.ClassCollector; import java.util.*; /** * This class represents a partially evaluated reference value. It has a type * and a flag that indicates whether the value could be null. If * the type is null, the value is null. * * @author Eric Lafortune */ public class ReferenceValue extends Category1Value { private static final boolean DEBUG = false; protected final String type; protected final Clazz referencedClass; protected final boolean mayBeNull; /** * Creates a new ReferenceValue. */ public ReferenceValue(String type, Clazz referencedClass, boolean mayBeNull) { this.type = type; this.referencedClass = referencedClass; this.mayBeNull = mayBeNull; } /** * Returns the type. */ public String getType() { return type; } /** * Returns the class that is referenced by the type. */ public Clazz getReferencedClass() { return referencedClass; } // Basic unary methods. /** * Returns whether the type is null. */ public int isNull() { return type == null ? ALWAYS : mayBeNull ? MAYBE : NEVER; } /** * Returns whether the type is an instance of the given type. */ public int instanceOf(String otherType, Clazz otherReferencedClass) { String thisType = this.type; // If this type is null, it is never an instance of any class. if (thisType == null) { return NEVER; } // Start taking into account the type dimensions. int thisDimensionCount = ClassUtil.internalArrayTypeDimensionCount(thisType); int otherDimensionCount = ClassUtil.internalArrayTypeDimensionCount(otherType); int commonDimensionCount = Math.min(thisDimensionCount, otherDimensionCount); // Strip any common array prefixes. thisType = thisType.substring(commonDimensionCount); otherType = otherType.substring(commonDimensionCount); // If either stripped type is a primitive type, we can tell right away. if (commonDimensionCount > 0 && (ClassUtil.isInternalPrimitiveType(thisType.charAt(0)) || ClassUtil.isInternalPrimitiveType(otherType.charAt(0)))) { return !thisType.equals(otherType) ? NEVER : mayBeNull ? MAYBE : ALWAYS; } // Strip the class type prefix and suffix of this type, if any. if (thisDimensionCount == commonDimensionCount) { thisType = ClassUtil.internalClassNameFromClassType(thisType); } // Strip the class type prefix and suffix of the other type, if any. if (otherDimensionCount == commonDimensionCount) { otherType = ClassUtil.internalClassNameFromClassType(otherType); } // If this type is an array type, and the other type is not // java.lang.Object, java.lang.Cloneable, or java.io.Serializable, // this type can never be an instance. if (thisDimensionCount > otherDimensionCount && !ClassUtil.isInternalArrayInterfaceName(otherType)) { return NEVER; } // If the other type is an array type, and this type is not // java.lang.Object, java.lang.Cloneable, or java.io.Serializable, // this type can never be an instance. if (thisDimensionCount < otherDimensionCount && !ClassUtil.isInternalArrayInterfaceName(thisType)) { return NEVER; } // If this type may be null, it might not be an instance of any class. if (mayBeNull) { return MAYBE; } // If this type is equal to the other type, or if the other type is // java.lang.Object, this type is always an instance. if (thisType.equals(otherType) || ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT.equals(otherType)) { return ALWAYS; } // If this type is an array type, it's ok. if (thisDimensionCount > otherDimensionCount) { return ALWAYS; } // If the other type is an array type, it might be ok. if (thisDimensionCount < otherDimensionCount) { return MAYBE; } // If the value extends the type, we're sure. return referencedClass != null && otherReferencedClass != null && referencedClass.extendsOrImplements(otherReferencedClass) ? ALWAYS : MAYBE; } /** * Returns the length of the array, assuming this type is an array. */ public IntegerValue arrayLength(ValueFactory valueFactory) { return valueFactory.createIntegerValue(); } /** * Returns the value of the array at the given index, assuming this type * is an array. */ public Value arrayLoad(IntegerValue integerValue, ValueFactory valueFactory) { return type == null ? ValueFactory.REFERENCE_VALUE_NULL : !ClassUtil.isInternalArrayType(type) ? ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL : valueFactory.createValue(type.substring(1), referencedClass, true); } // Basic binary methods. /** * Returns the generalization of this ReferenceValue and the given other * ReferenceValue. */ public ReferenceValue generalize(ReferenceValue other) { // If both types are identical, the generalization is the same too. if (this.equals(other)) { return this; } String thisType = this.type; String otherType = other.type; // If both types are nul, the generalization is null too. if (thisType == null && otherType == null) { return ValueFactory.REFERENCE_VALUE_NULL; } // If this type is null, the generalization is the other type, maybe null. if (thisType == null) { return other.generalizeMayBeNull(true); } // If the other type is null, the generalization is this type, maybe null. if (otherType == null) { return this.generalizeMayBeNull(true); } boolean mayBeNull = this.mayBeNull || other.mayBeNull; // If the two types are equal, the generalization remains the same, maybe null. if (thisType.equals(otherType)) { return this.generalizeMayBeNull(mayBeNull); } // Start taking into account the type dimensions. int thisDimensionCount = ClassUtil.internalArrayTypeDimensionCount(thisType); int otherDimensionCount = ClassUtil.internalArrayTypeDimensionCount(otherType); int commonDimensionCount = Math.min(thisDimensionCount, otherDimensionCount); if (thisDimensionCount == otherDimensionCount) { // See if we can take into account the referenced classes. Clazz thisReferencedClass = this.referencedClass; Clazz otherReferencedClass = other.referencedClass; if (thisReferencedClass != null && otherReferencedClass != null) { if (thisReferencedClass.extendsOrImplements(otherReferencedClass)) { return other.generalizeMayBeNull(mayBeNull); } if (otherReferencedClass.extendsOrImplements(thisReferencedClass)) { return this.generalizeMayBeNull(mayBeNull); } // Collect the superclasses and interfaces of this class. Set thisSuperClasses = new HashSet(); thisReferencedClass.hierarchyAccept(false, true, true, false, new ClassCollector(thisSuperClasses)); int thisSuperClassesCount = thisSuperClasses.size(); if (thisSuperClassesCount == 0 && thisReferencedClass.getSuperName() != null) { throw new IllegalArgumentException("Can't find any super classes of ["+thisType+"] (not even immediate super class ["+thisReferencedClass.getSuperName()+"])"); } // Collect the superclasses and interfaces of the other class. Set otherSuperClasses = new HashSet(); otherReferencedClass.hierarchyAccept(false, true, true, false, new ClassCollector(otherSuperClasses)); int otherSuperClassesCount = otherSuperClasses.size(); if (otherSuperClassesCount == 0 && otherReferencedClass.getSuperName() != null) { throw new IllegalArgumentException("Can't find any super classes of ["+otherType+"] (not even immediate super class ["+otherReferencedClass.getSuperName()+"])"); } if (DEBUG) { System.out.println("ReferenceValue.generalize this ["+thisReferencedClass.getName()+"] with other ["+otherReferencedClass.getName()+"]"); System.out.println(" This super classes: "+thisSuperClasses); System.out.println(" Other super classes: "+otherSuperClasses); } // Find the common superclasses. thisSuperClasses.retainAll(otherSuperClasses); if (DEBUG) { System.out.println(" Common super classes: "+thisSuperClasses); } // Find a class that is a subclass of all common superclasses, // or that at least has the maximum number of common superclasses. Clazz commonClass = null; int maximumSuperClassCount = -1; // Go over all common superclasses to find it. In case of // multiple subclasses, keep the lowest one alphabetically, // in order to ensure that the choice is deterministic. Iterator commonSuperClasses = thisSuperClasses.iterator(); while (commonSuperClasses.hasNext()) { Clazz commonSuperClass = (Clazz)commonSuperClasses.next(); int superClassCount = superClassCount(commonSuperClass, thisSuperClasses); if (maximumSuperClassCount < superClassCount || (maximumSuperClassCount == superClassCount && commonClass != null && commonClass.getName().compareTo(commonSuperClass.getName()) > 0)) { commonClass = commonSuperClass; maximumSuperClassCount = superClassCount; } } if (commonClass == null) { throw new IllegalArgumentException("Can't find common super class of ["+ thisType +"] (with "+thisSuperClassesCount +" known super classes) and ["+ otherType+"] (with "+otherSuperClassesCount+" known super classes)"); } if (DEBUG) { System.out.println(" Best common class: ["+commonClass.getName()+"]"); } // TODO: Handle more difficult cases, with multiple global subclasses. return new ReferenceValue(commonDimensionCount == 0 ? commonClass.getName() : ClassUtil.internalArrayTypeFromClassName(commonClass.getName(), commonDimensionCount), commonClass, mayBeNull); } } else if (thisDimensionCount > otherDimensionCount) { // See if the other type is an interface type of arrays. if (ClassUtil.isInternalArrayInterfaceName(ClassUtil.internalClassNameFromClassType(otherType))) { return other.generalizeMayBeNull(mayBeNull); } } else if (thisDimensionCount < otherDimensionCount) { // See if this type is an interface type of arrays. if (ClassUtil.isInternalArrayInterfaceName(ClassUtil.internalClassNameFromClassType(thisType))) { return this.generalizeMayBeNull(mayBeNull); } } // Reduce the common dimension count if either type is an array of // primitives type of this dimension. if (commonDimensionCount > 0 && (ClassUtil.isInternalPrimitiveType(otherType.charAt(commonDimensionCount))) || ClassUtil.isInternalPrimitiveType(thisType.charAt(commonDimensionCount))) { commonDimensionCount--; } // Fall back on a basic Object or array of Objects type. return commonDimensionCount == 0 ? mayBeNull ? ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL : ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL : new ReferenceValue(ClassUtil.internalArrayTypeFromClassName(ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT, commonDimensionCount), null, mayBeNull); } /** * Returns if the number of superclasses of the given class in the given * set of classes. */ private int superClassCount(Clazz subClass, Set classes) { int count = 0; Iterator iterator = classes.iterator(); while (iterator.hasNext()) { Clazz clazz = (Clazz)iterator.next(); if (subClass.extendsOrImplements(clazz)) { count++; } } return count; } /** * Returns whether this ReferenceValue is equal to the given other * ReferenceValue. * @return NEVER, MAYBE, or ALWAYS. */ public int equal(ReferenceValue other) { return this.type == null && other.type == null ? ALWAYS : MAYBE; } // Derived unary methods. /** * Returns whether this ReferenceValue is not null. * @return NEVER, MAYBE, or ALWAYS. */ public final int isNotNull() { return -isNull(); } /** * Returns the generalization of this ReferenceValue and the given other * ReferenceValue. */ private ReferenceValue generalizeMayBeNull(boolean mayBeNull) { return this.mayBeNull || !mayBeNull ? this : new ReferenceValue(this.type, this.referencedClass, true); } // Derived binary methods. /** * Returns whether this ReferenceValue and the given ReferenceValue are different. * @return NEVER, MAYBE, or ALWAYS. */ public final int notEqual(ReferenceValue other) { return -equal(other); } // Implementations for Value. public final ReferenceValue referenceValue() { return this; } public final Value generalize(Value other) { return this.generalize(other.referenceValue()); } public boolean isParticular() { return type == null; } public final int computationalType() { return TYPE_REFERENCE; } public final String internalType() { return type == null ? ClassConstants.INTERNAL_TYPE_JAVA_LANG_OBJECT : ClassUtil.isInternalArrayType(type) ? type : ClassConstants.INTERNAL_TYPE_CLASS_START + type + ClassConstants.INTERNAL_TYPE_CLASS_END; } // Implementations for Object. public boolean equals(Object object) { if (this == object) { return true; } if (object == null || this.getClass() != object.getClass()) { return false; } ReferenceValue other = (ReferenceValue)object; return this.type == null ? other.type == null : (this.mayBeNull == other.mayBeNull && this.type.equals(other.type)); } public int hashCode() { return this.getClass().hashCode() ^ (type == null ? 0 : type.hashCode() ^ (mayBeNull ? 0 : 1)); } public String toString() { return type == null ? "null" : type + (referencedClass == null ? "?" : "") + (mayBeNull ? "" : "!"); } } proguard4.8/src/proguard/evaluation/value/ParticularIntegerValue.java0000644000175000017500000002214111736333523024750 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents a particular integer value. * * @author Eric Lafortune */ final class ParticularIntegerValue extends SpecificIntegerValue { private final int value; /** * Creates a new particular integer value. */ public ParticularIntegerValue(int value) { this.value = value; } // Implementations for IntegerValue. public int value() { return value; } // Implementations of unary methods of IntegerValue. public IntegerValue negate() { return new ParticularIntegerValue(-value); } public IntegerValue convertToByte() { int byteValue = (byte)value; return byteValue == value ? this : new ParticularIntegerValue(byteValue); } public IntegerValue convertToCharacter() { int charValue = (char)value; return charValue == value ? this : new ParticularIntegerValue(charValue); } public IntegerValue convertToShort() { int shortValue = (short)value; return shortValue == value ? this : new ParticularIntegerValue(shortValue); } public LongValue convertToLong() { return new ParticularLongValue((long)value); } public FloatValue convertToFloat() { return new ParticularFloatValue((float)value); } public DoubleValue convertToDouble() { return new ParticularDoubleValue((double)value); } // Implementations of binary methods of IntegerValue. public IntegerValue generalize(IntegerValue other) { return other.generalize(this); } public IntegerValue add(IntegerValue other) { return other.add(this); } public IntegerValue subtract(IntegerValue other) { return other.subtractFrom(this); } public IntegerValue subtractFrom(IntegerValue other) { return other.subtract(this); } public IntegerValue multiply(IntegerValue other) { return other.multiply(this); } public IntegerValue divide(IntegerValue other) throws ArithmeticException { return other.divideOf(this); } public IntegerValue divideOf(IntegerValue other) throws ArithmeticException { return other.divide(this); } public IntegerValue remainder(IntegerValue other) throws ArithmeticException { return other.remainderOf(this); } public IntegerValue remainderOf(IntegerValue other) throws ArithmeticException { return other.remainder(this); } public IntegerValue shiftLeft(IntegerValue other) { return other.shiftLeftOf(this); } public IntegerValue shiftLeftOf(IntegerValue other) { return other.shiftLeft(this); } public IntegerValue shiftRight(IntegerValue other) { return other.shiftRightOf(this); } public IntegerValue shiftRightOf(IntegerValue other) { return other.shiftRight(this); } public IntegerValue unsignedShiftRight(IntegerValue other) { return other.unsignedShiftRightOf(this); } public IntegerValue unsignedShiftRightOf(IntegerValue other) { return other.unsignedShiftRight(this); } public LongValue shiftLeftOf(LongValue other) { return other.shiftLeft(this); } public LongValue shiftRightOf(LongValue other) { return other.shiftRight(this); } public LongValue unsignedShiftRightOf(LongValue other) { return other.unsignedShiftRight(this); } public IntegerValue and(IntegerValue other) { return other.and(this); } public IntegerValue or(IntegerValue other) { return other.or(this); } public IntegerValue xor(IntegerValue other) { return other.xor(this); } public int equal(IntegerValue other) { return other.equal(this); } public int lessThan(IntegerValue other) { return other.greaterThan(this); } public int lessThanOrEqual(IntegerValue other) { return other.greaterThanOrEqual(this); } // Implementations of binary IntegerValue methods with ParticularIntegerValue // arguments. public IntegerValue generalize(ParticularIntegerValue other) { return generalize((SpecificIntegerValue)other); } public IntegerValue add(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value + other.value); } public IntegerValue subtract(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value - other.value); } public IntegerValue subtractFrom(ParticularIntegerValue other) { return new ParticularIntegerValue(other.value - this.value); } public IntegerValue multiply(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value * other.value); } public IntegerValue divide(ParticularIntegerValue other) throws ArithmeticException { return new ParticularIntegerValue(this.value / other.value); } public IntegerValue divideOf(ParticularIntegerValue other) throws ArithmeticException { return new ParticularIntegerValue(other.value / this.value); } public IntegerValue remainder(ParticularIntegerValue other) throws ArithmeticException { return new ParticularIntegerValue(this.value % other.value); } public IntegerValue remainderOf(ParticularIntegerValue other) throws ArithmeticException { return new ParticularIntegerValue(other.value % this.value); } public IntegerValue shiftLeft(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value << other.value); } public IntegerValue shiftRight(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value >> other.value); } public IntegerValue unsignedShiftRight(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value >>> other.value); } public IntegerValue shiftLeftOf(ParticularIntegerValue other) { return new ParticularIntegerValue(other.value << this.value); } public IntegerValue shiftRightOf(ParticularIntegerValue other) { return new ParticularIntegerValue(other.value >> this.value); } public IntegerValue unsignedShiftRightOf(ParticularIntegerValue other) { return new ParticularIntegerValue(other.value >>> this.value); } public LongValue shiftLeftOf(ParticularLongValue other) { return new ParticularLongValue(other.value() << this.value); } public LongValue shiftRightOf(ParticularLongValue other) { return new ParticularLongValue(other.value() >> this.value); } public LongValue unsignedShiftRightOf(ParticularLongValue other) { return new ParticularLongValue(other.value() >>> this.value); } public IntegerValue and(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value & other.value); } public IntegerValue or(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value | other.value); } public IntegerValue xor(ParticularIntegerValue other) { return new ParticularIntegerValue(this.value ^ other.value); } public int equal(ParticularIntegerValue other) { return this.value == other.value ? ALWAYS : NEVER; } public int lessThan(ParticularIntegerValue other) { return this.value < other.value ? ALWAYS : NEVER; } public int lessThanOrEqual(ParticularIntegerValue other) { return this.value <= other.value ? ALWAYS : NEVER; } // Implementations for Value. public boolean isParticular() { return true; } // Implementations for Object. public boolean equals(Object object) { return super.equals(object) && this.value == ((ParticularIntegerValue)object).value; } public int hashCode() { return this.getClass().hashCode() ^ value; } public String toString() { return Integer.toString(value); } }proguard4.8/src/proguard/evaluation/value/TopValue.java0000644000175000017500000000365011736333523022072 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This class represents a partially evaluated top value. A top value is the * dummy value that takes up the extra space when storing a long value or a * double value. * * @author Eric Lafortune */ public class TopValue extends Category1Value { // Implementations for Value. public boolean isSpecific() { return true; } public boolean isParticular() { return true; } public final Value generalize(Value other) { return this.getClass() == other.getClass() ? this : null; } public final int computationalType() { return TYPE_TOP; } public final String internalType() { return null; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } public String toString() { return "T"; } } proguard4.8/src/proguard/evaluation/value/IdentifiedIntegerValue.java0000644000175000017500000000363111736333523024711 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents a integer value that is identified by a unique ID. * * @author Eric Lafortune */ final class IdentifiedIntegerValue extends SpecificIntegerValue { private final ValueFactory valuefactory; private final int id; /** * Creates a new integer value with the given ID. */ public IdentifiedIntegerValue(ValueFactory valuefactory, int id) { this.valuefactory = valuefactory; this.id = id; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.valuefactory.equals(((IdentifiedIntegerValue)object).valuefactory) && this.id == ((IdentifiedIntegerValue)object).id; } public int hashCode() { return super.hashCode() ^ valuefactory.hashCode() ^ id; } public String toString() { return "i"+id; } }proguard4.8/src/proguard/evaluation/value/UnknownFloatValue.java0000644000175000017500000000516111736333523023754 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This class represents a partially evaluated float value. * * @author Eric Lafortune */ public class UnknownFloatValue extends FloatValue { // Basic unary methods. public FloatValue negate() { return this; } public IntegerValue convertToInteger() { return ValueFactory.INTEGER_VALUE; } public LongValue convertToLong() { return ValueFactory.LONG_VALUE; } public DoubleValue convertToDouble() { return ValueFactory.DOUBLE_VALUE; } // Basic binary methods. public FloatValue generalize(FloatValue other) { return this; } public FloatValue add(FloatValue other) { return this; } public FloatValue subtract(FloatValue other) { return this; } public FloatValue subtractFrom(FloatValue other) { return this; } public FloatValue multiply(FloatValue other) { return this; } public FloatValue divide(FloatValue other) { return this; } public FloatValue divideOf(FloatValue other) { return this; } public FloatValue remainder(FloatValue other) { return this; } public FloatValue remainderOf(FloatValue other) { return this; } public IntegerValue compare(FloatValue other) { return ValueFactory.INTEGER_VALUE; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } public String toString() { return "d"; } }proguard4.8/src/proguard/evaluation/value/NegatedDoubleValue.java0000644000175000017500000000355211736333523024033 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This DoubleValue represents a double value that is negated. * * @author Eric Lafortune */ final class NegatedDoubleValue extends SpecificDoubleValue { private final DoubleValue doubleValue; /** * Creates a new negated double value of the given double value. */ public NegatedDoubleValue(DoubleValue doubleValue) { this.doubleValue = doubleValue; } // Implementations of unary methods of DoubleValue. public DoubleValue negate() { return doubleValue; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.doubleValue.equals(((NegatedDoubleValue)object).doubleValue); } public int hashCode() { return super.hashCode() ^ doubleValue.hashCode(); } public String toString() { return "-"+doubleValue; } }proguard4.8/src/proguard/evaluation/value/CompositeLongValue.java0000644000175000017500000000556311736333523024117 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This LongValue represents the result of a binary operation on two long * values. * * @author Eric Lafortune */ final class CompositeLongValue extends SpecificLongValue { public static final byte ADD = '+'; public static final byte SUBTRACT = '-'; public static final byte MULTIPLY = '*'; public static final byte DIVIDE = '/'; public static final byte REMAINDER = '%'; public static final byte SHIFT_LEFT = '<'; public static final byte SHIFT_RIGHT = '>'; public static final byte UNSIGNED_SHIFT_RIGHT = '}'; public static final byte AND = '&'; public static final byte OR = '|'; public static final byte XOR = '^'; private final LongValue longValue1; private final byte operation; private final Value longValue2; /** * Creates a new composite long value of the two given long values * and the given operation. */ public CompositeLongValue(LongValue longValue1, byte operation, Value longValue2) { this.longValue1 = longValue1; this.operation = operation; this.longValue2 = longValue2; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.longValue1.equals(((CompositeLongValue)object).longValue1) && this.operation == ((CompositeLongValue)object).operation && this.longValue2.equals(((CompositeLongValue)object).longValue2); } public int hashCode() { return super.hashCode() ^ longValue1.hashCode() ^ longValue2.hashCode(); } public String toString() { return "("+longValue1+((char)operation)+longValue2+")"; } }proguard4.8/src/proguard/evaluation/value/ConvertedShortValue.java0000644000175000017500000000334511736333523024302 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents a short value that is converted from an * integer value. * * @author Eric Lafortune */ final class ConvertedShortValue extends SpecificIntegerValue { private final IntegerValue value; /** * Creates a new converted short value of the given integer value. */ public ConvertedShortValue(IntegerValue value) { this.value = value; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.value.equals(((ConvertedShortValue)object).value); } public int hashCode() { return super.hashCode() ^ value.hashCode(); } public String toString() { return "(short)("+value+")"; } }proguard4.8/src/proguard/evaluation/value/Value.java0000644000175000017500000001240111736333523021401 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This abstract class represents a partially evaluated value. * * @author Eric Lafortune */ public abstract class Value { public static final int NEVER = -1; public static final int MAYBE = 0; public static final int ALWAYS = 1; public static final int TYPE_INTEGER = 1; public static final int TYPE_LONG = 2; public static final int TYPE_FLOAT = 3; public static final int TYPE_DOUBLE = 4; public static final int TYPE_REFERENCE = 5; public static final int TYPE_INSTRUCTION_OFFSET = 6; public static final int TYPE_TOP = 7; /** * Returns this Value as a Category1Value. */ public Category1Value category1Value() { throw new IllegalArgumentException("Value is not a Category 1 value [" + this.getClass().getName() + "]"); } /** * Returns this Value as a Category2Value. */ public Category2Value category2Value() { throw new IllegalArgumentException("Value is not a Category 2 value [" + this.getClass().getName() + "]"); } /** * Returns this Value as an IntegerValue. */ public IntegerValue integerValue() { throw new IllegalArgumentException("Value is not an integer value [" + this.getClass().getName() + "]"); } /** * Returns this Value as a LongValue. */ public LongValue longValue() { throw new IllegalArgumentException("Value is not a long value [" + this.getClass().getName() + "]"); } /** * Returns this Value as a FloatValue. */ public FloatValue floatValue() { throw new IllegalArgumentException("Value is not a float value [" + this.getClass().getName() + "]"); } /** * Returns this Value as a DoubleValue. */ public DoubleValue doubleValue() { throw new IllegalArgumentException("Value is not a double value [" + this.getClass().getName() + "]"); } /** * Returns this Value as a ReferenceValue. */ public ReferenceValue referenceValue() { throw new IllegalArgumentException("Value is not a reference value [" + this.getClass().getName() + "]"); } /** * Returns this Value as an InstructionOffsetValue. */ public InstructionOffsetValue instructionOffsetValue() { throw new IllegalArgumentException("Value is not an instruction offset value [" + this.getClass().getName() + "]"); } /** * Returns whether this Value represents a single specific (but possibly * unknown) value. */ public boolean isSpecific() { return false; } /** * Returns whether this Value represents a single particular (known) * value. */ public boolean isParticular() { return false; } /** * Returns the generalization of this Value and the given other Value. */ public abstract Value generalize(Value other); /** * Returns whether the computational type of this Value is a category 2 type. * This means that it takes up the space of two category 1 types on the * stack, for instance. */ public abstract boolean isCategory2(); /** * Returns the computational type of this Value. * @return TYPE_INTEGER, * TYPE_LONG, * TYPE_FLOAT, * TYPE_DOUBLE, * TYPE_REFERENCE, or * TYPE_INSTRUCTION_OFFSET. */ public abstract int computationalType(); /** * Returns the internal type of this Value. * @return ClassConstants.INTERNAL_TYPE_BOOLEAN, * ClassConstants.INTERNAL_TYPE_BYTE, * ClassConstants.INTERNAL_TYPE_CHAR, * ClassConstants.INTERNAL_TYPE_SHORT, * ClassConstants.INTERNAL_TYPE_INT, * ClassConstants.INTERNAL_TYPE_LONG, * ClassConstants.INTERNAL_TYPE_FLOAT, * ClassConstants.INTERNAL_TYPE_DOUBLE, * ClassConstants.INTERNAL_TYPE_CLASS_START ... ClassConstants.INTERNAL_TYPE_CLASS_END, or * an array type containing any of these types (always as String). */ public abstract String internalType(); } proguard4.8/src/proguard/evaluation/value/Category2Value.java0000644000175000017500000000241311736333523023163 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This abstract class represents a partially evaluated Category 2 value. * * @author Eric Lafortune */ public abstract class Category2Value extends Value { // Implementations for Value. public final Category2Value category2Value() { return this; } public final boolean isCategory2() { return true; } } proguard4.8/src/proguard/evaluation/value/ConvertedByteValue.java0000644000175000017500000000333711736333523024107 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This IntegerValue represents a byte value that is converted from an * integer value. * * @author Eric Lafortune */ final class ConvertedByteValue extends SpecificIntegerValue { private final IntegerValue value; /** * Creates a new converted byte value of the given integer value. */ public ConvertedByteValue(IntegerValue value) { this.value = value; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.value.equals(((ConvertedByteValue)object).value); } public int hashCode() { return super.hashCode() ^ value.hashCode(); } public String toString() { return "(byte)("+value+")"; } }proguard4.8/src/proguard/evaluation/value/CompositeDoubleValue.java0000644000175000017500000000506011736333523024422 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation.value; /** * This DoubleValue represents the result of a binary operation on two double * values. * * @author Eric Lafortune */ final class CompositeDoubleValue extends SpecificDoubleValue { public static final byte ADD = '+'; public static final byte SUBTRACT = '-'; public static final byte MULTIPLY = '*'; public static final byte DIVIDE = '/'; public static final byte REMAINDER = '%'; private final DoubleValue doubleValue1; private final byte operation; private final DoubleValue doubleValue2; /** * Creates a new composite double value of the two given double values * and the given operation. */ public CompositeDoubleValue(DoubleValue doubleValue1, byte operation, DoubleValue doubleValue2) { this.doubleValue1 = doubleValue1; this.operation = operation; this.doubleValue2 = doubleValue2; } // Implementations for Object. public boolean equals(Object object) { return this == object || super.equals(object) && this.doubleValue1.equals(((CompositeDoubleValue)object).doubleValue1) && this.operation == ((CompositeDoubleValue)object).operation && this.doubleValue2.equals(((CompositeDoubleValue)object).doubleValue2); } public int hashCode() { return super.hashCode() ^ doubleValue1.hashCode() ^ doubleValue2.hashCode(); } public String toString() { return "("+doubleValue1+((char)operation)+doubleValue2+")"; } }proguard4.8/src/proguard/evaluation/ClassConstantValueFactory.java0000644000175000017500000000360611736333523024324 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.evaluation.value.*; /** * This class creates java.lang.Class ReferenceValue instances that correspond * to specified constant pool entries. * * @author Eric Lafortune */ public class ClassConstantValueFactory extends ConstantValueFactory { public ClassConstantValueFactory(ValueFactory valueFactory) { super(valueFactory); } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Create a Class reference instead of a reference to the class. value = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS, classConstant.javaLangClassClass, false); } }proguard4.8/src/proguard/evaluation/Processor.java0000644000175000017500000010523511736333523021200 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.evaluation.value.*; /** * This InstructionVisitor executes the instructions that it visits on a given * local variable frame and stack. * * @author Eric Lafortune */ public class Processor implements InstructionVisitor { private final Variables variables; private final Stack stack; private final ValueFactory valueFactory; private final BranchUnit branchUnit; private final InvocationUnit invocationUnit; private final ConstantValueFactory constantValueFactory; private final ClassConstantValueFactory classConstantValueFactory; /** * Creates a new processor that operates on the given environment. * @param variables the local variable frame. * @param stack the local stack. * @param branchUnit the class that can affect the program counter. * @param invocationUnit the class that can access other program members. */ public Processor(Variables variables, Stack stack, ValueFactory valueFactory, BranchUnit branchUnit, InvocationUnit invocationUnit) { this.variables = variables; this.stack = stack; this.valueFactory = valueFactory; this.branchUnit = branchUnit; this.invocationUnit = invocationUnit; constantValueFactory = new ConstantValueFactory(valueFactory); classConstantValueFactory = new ClassConstantValueFactory(valueFactory); } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { switch (simpleInstruction.opcode) { case InstructionConstants.OP_NOP: break; case InstructionConstants.OP_ACONST_NULL: stack.push(valueFactory.createReferenceValueNull()); break; case InstructionConstants.OP_ICONST_M1: case InstructionConstants.OP_ICONST_0: case InstructionConstants.OP_ICONST_1: case InstructionConstants.OP_ICONST_2: case InstructionConstants.OP_ICONST_3: case InstructionConstants.OP_ICONST_4: case InstructionConstants.OP_ICONST_5: case InstructionConstants.OP_BIPUSH: case InstructionConstants.OP_SIPUSH: stack.push(valueFactory.createIntegerValue(simpleInstruction.constant)); break; case InstructionConstants.OP_LCONST_0: case InstructionConstants.OP_LCONST_1: stack.push(valueFactory.createLongValue(simpleInstruction.constant)); break; case InstructionConstants.OP_FCONST_0: case InstructionConstants.OP_FCONST_1: case InstructionConstants.OP_FCONST_2: stack.push(valueFactory.createFloatValue((float)simpleInstruction.constant)); break; case InstructionConstants.OP_DCONST_0: case InstructionConstants.OP_DCONST_1: stack.push(valueFactory.createDoubleValue((double)simpleInstruction.constant)); break; case InstructionConstants.OP_IALOAD: case InstructionConstants.OP_BALOAD: case InstructionConstants.OP_CALOAD: case InstructionConstants.OP_SALOAD: stack.ipop(); stack.apop(); stack.push(valueFactory.createIntegerValue()); break; case InstructionConstants.OP_LALOAD: stack.ipop(); stack.apop(); stack.push(valueFactory.createLongValue()); break; case InstructionConstants.OP_FALOAD: stack.ipop(); stack.apop(); stack.push(valueFactory.createFloatValue()); break; case InstructionConstants.OP_DALOAD: stack.ipop(); stack.apop(); stack.push(valueFactory.createDoubleValue()); break; case InstructionConstants.OP_AALOAD: { IntegerValue arrayIndex = stack.ipop(); ReferenceValue arrayReference = stack.apop(); stack.push(arrayReference.arrayLoad(arrayIndex, valueFactory)); break; } case InstructionConstants.OP_IASTORE: case InstructionConstants.OP_BASTORE: case InstructionConstants.OP_CASTORE: case InstructionConstants.OP_SASTORE: stack.ipop(); stack.ipop(); stack.apop(); break; case InstructionConstants.OP_LASTORE: stack.lpop(); stack.ipop(); stack.apop(); break; case InstructionConstants.OP_FASTORE: stack.fpop(); stack.ipop(); stack.apop(); break; case InstructionConstants.OP_DASTORE: stack.dpop(); stack.ipop(); stack.apop(); break; case InstructionConstants.OP_AASTORE: stack.apop(); stack.ipop(); stack.apop(); break; case InstructionConstants.OP_POP: stack.pop1(); break; case InstructionConstants.OP_POP2: stack.pop2(); break; case InstructionConstants.OP_DUP: stack.dup(); break; case InstructionConstants.OP_DUP_X1: stack.dup_x1(); break; case InstructionConstants.OP_DUP_X2: stack.dup_x2(); break; case InstructionConstants.OP_DUP2: stack.dup2(); break; case InstructionConstants.OP_DUP2_X1: stack.dup2_x1(); break; case InstructionConstants.OP_DUP2_X2: stack.dup2_x2(); break; case InstructionConstants.OP_SWAP: stack.swap(); break; case InstructionConstants.OP_IADD: stack.push(stack.ipop().add(stack.ipop())); break; case InstructionConstants.OP_LADD: stack.push(stack.lpop().add(stack.lpop())); break; case InstructionConstants.OP_FADD: stack.push(stack.fpop().add(stack.fpop())); break; case InstructionConstants.OP_DADD: stack.push(stack.dpop().add(stack.dpop())); break; case InstructionConstants.OP_ISUB: stack.push(stack.ipop().subtractFrom(stack.ipop())); break; case InstructionConstants.OP_LSUB: stack.push(stack.lpop().subtractFrom(stack.lpop())); break; case InstructionConstants.OP_FSUB: stack.push(stack.fpop().subtractFrom(stack.fpop())); break; case InstructionConstants.OP_DSUB: stack.push(stack.dpop().subtractFrom(stack.dpop())); break; case InstructionConstants.OP_IMUL: stack.push(stack.ipop().multiply(stack.ipop())); break; case InstructionConstants.OP_LMUL: stack.push(stack.lpop().multiply(stack.lpop())); break; case InstructionConstants.OP_FMUL: stack.push(stack.fpop().multiply(stack.fpop())); break; case InstructionConstants.OP_DMUL: stack.push(stack.dpop().multiply(stack.dpop())); break; case InstructionConstants.OP_IDIV: try { stack.push(stack.ipop().divideOf(stack.ipop())); } catch (ArithmeticException ex) { stack.push(valueFactory.createIntegerValue()); // TODO: Forward ArithmeticExceptions. //stack.clear(); //stack.push(valueFactory.createReference(false)); //branchUnit.throwException(); } break; case InstructionConstants.OP_LDIV: try { stack.push(stack.lpop().divideOf(stack.lpop())); } catch (ArithmeticException ex) { stack.push(valueFactory.createLongValue()); // TODO: Forward ArithmeticExceptions. //stack.clear(); //stack.push(valueFactory.createReference(false)); //branchUnit.throwException(); } break; case InstructionConstants.OP_FDIV: stack.push(stack.fpop().divideOf(stack.fpop())); break; case InstructionConstants.OP_DDIV: stack.push(stack.dpop().divideOf(stack.dpop())); break; case InstructionConstants.OP_IREM: try { stack.push(stack.ipop().remainderOf(stack.ipop())); } catch (ArithmeticException ex) { stack.push(valueFactory.createIntegerValue()); // TODO: Forward ArithmeticExceptions. //stack.clear(); //stack.push(valueFactory.createReference(false)); //branchUnit.throwException(); } break; case InstructionConstants.OP_LREM: try { stack.push(stack.lpop().remainderOf(stack.lpop())); } catch (ArithmeticException ex) { stack.push(valueFactory.createLongValue()); // TODO: Forward ArithmeticExceptions. //stack.clear(); //stack.push(valueFactory.createReference(false)); //branchUnit.throwException(); } break; case InstructionConstants.OP_FREM: stack.push(stack.fpop().remainderOf(stack.fpop())); break; case InstructionConstants.OP_DREM: stack.push(stack.dpop().remainderOf(stack.dpop())); break; case InstructionConstants.OP_INEG: stack.push(stack.ipop().negate()); break; case InstructionConstants.OP_LNEG: stack.push(stack.lpop().negate()); break; case InstructionConstants.OP_FNEG: stack.push(stack.fpop().negate()); break; case InstructionConstants.OP_DNEG: stack.push(stack.dpop().negate()); break; case InstructionConstants.OP_ISHL: stack.push(stack.ipop().shiftLeftOf(stack.ipop())); break; case InstructionConstants.OP_LSHL: stack.push(stack.ipop().shiftLeftOf(stack.lpop())); break; case InstructionConstants.OP_ISHR: stack.push(stack.ipop().shiftRightOf(stack.ipop())); break; case InstructionConstants.OP_LSHR: stack.push(stack.ipop().shiftRightOf(stack.lpop())); break; case InstructionConstants.OP_IUSHR: stack.push(stack.ipop().unsignedShiftRightOf(stack.ipop())); break; case InstructionConstants.OP_LUSHR: stack.push(stack.ipop().unsignedShiftRightOf(stack.lpop())); break; case InstructionConstants.OP_IAND: stack.push(stack.ipop().and(stack.ipop())); break; case InstructionConstants.OP_LAND: stack.push(stack.lpop().and(stack.lpop())); break; case InstructionConstants.OP_IOR: stack.push(stack.ipop().or(stack.ipop())); break; case InstructionConstants.OP_LOR: stack.push(stack.lpop().or(stack.lpop())); break; case InstructionConstants.OP_IXOR: stack.push(stack.ipop().xor(stack.ipop())); break; case InstructionConstants.OP_LXOR: stack.push(stack.lpop().xor(stack.lpop())); break; case InstructionConstants.OP_I2L: stack.push(stack.ipop().convertToLong()); break; case InstructionConstants.OP_I2F: stack.push(stack.ipop().convertToFloat()); break; case InstructionConstants.OP_I2D: stack.push(stack.ipop().convertToDouble()); break; case InstructionConstants.OP_L2I: stack.push(stack.lpop().convertToInteger()); break; case InstructionConstants.OP_L2F: stack.push(stack.lpop().convertToFloat()); break; case InstructionConstants.OP_L2D: stack.push(stack.lpop().convertToDouble()); break; case InstructionConstants.OP_F2I: stack.push(stack.fpop().convertToInteger()); break; case InstructionConstants.OP_F2L: stack.push(stack.fpop().convertToLong()); break; case InstructionConstants.OP_F2D: stack.push(stack.fpop().convertToDouble()); break; case InstructionConstants.OP_D2I: stack.push(stack.dpop().convertToInteger()); break; case InstructionConstants.OP_D2L: stack.push(stack.dpop().convertToLong()); break; case InstructionConstants.OP_D2F: stack.push(stack.dpop().convertToFloat()); break; case InstructionConstants.OP_I2B: stack.push(stack.ipop().convertToByte()); break; case InstructionConstants.OP_I2C: stack.push(stack.ipop().convertToCharacter()); break; case InstructionConstants.OP_I2S: stack.push(stack.ipop().convertToShort()); break; case InstructionConstants.OP_LCMP: // stack.push(stack.lpop().compareReverse(stack.lpop())); LongValue longValue1 = stack.lpop(); LongValue longValue2 = stack.lpop(); stack.push(longValue2.compare(longValue1)); break; case InstructionConstants.OP_FCMPL: FloatValue floatValue1 = stack.fpop(); FloatValue floatValue2 = stack.fpop(); stack.push(floatValue2.compare(floatValue1)); break; case InstructionConstants.OP_FCMPG: stack.push(stack.fpop().compareReverse(stack.fpop())); break; case InstructionConstants.OP_DCMPL: DoubleValue doubleValue1 = stack.dpop(); DoubleValue doubleValue2 = stack.dpop(); stack.push(doubleValue2.compare(doubleValue1)); break; case InstructionConstants.OP_DCMPG: stack.push(stack.dpop().compareReverse(stack.dpop())); break; case InstructionConstants.OP_IRETURN: invocationUnit.exitMethod(clazz, method, stack.ipop()); branchUnit.returnFromMethod(); break; case InstructionConstants.OP_LRETURN: invocationUnit.exitMethod(clazz, method, stack.lpop()); branchUnit.returnFromMethod(); break; case InstructionConstants.OP_FRETURN: invocationUnit.exitMethod(clazz, method, stack.fpop()); branchUnit.returnFromMethod(); break; case InstructionConstants.OP_DRETURN: invocationUnit.exitMethod(clazz, method, stack.dpop()); branchUnit.returnFromMethod(); break; case InstructionConstants.OP_ARETURN: invocationUnit.exitMethod(clazz, method, stack.apop()); branchUnit.returnFromMethod(); break; case InstructionConstants.OP_RETURN: branchUnit.returnFromMethod(); break; case InstructionConstants.OP_NEWARRAY: IntegerValue arrayLength = stack.ipop(); stack.push(valueFactory.createArrayReferenceValue(String.valueOf(InstructionUtil.internalTypeFromArrayType((byte)simpleInstruction.constant)), null, arrayLength)); break; case InstructionConstants.OP_ARRAYLENGTH: stack.apop(); stack.push(valueFactory.createIntegerValue()); break; case InstructionConstants.OP_ATHROW: ReferenceValue exceptionReferenceValue = stack.apop(); stack.clear(); stack.push(exceptionReferenceValue); branchUnit.throwException(); break; case InstructionConstants.OP_MONITORENTER: case InstructionConstants.OP_MONITOREXIT: stack.apop(); break; default: throw new IllegalArgumentException("Unknown simple instruction ["+simpleInstruction.opcode+"]"); } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { int constantIndex = constantInstruction.constantIndex; switch (constantInstruction.opcode) { case InstructionConstants.OP_LDC: case InstructionConstants.OP_LDC_W: case InstructionConstants.OP_LDC2_W: stack.push(classConstantValueFactory.constantValue(clazz, constantIndex)); break; case InstructionConstants.OP_GETSTATIC: case InstructionConstants.OP_PUTSTATIC: case InstructionConstants.OP_GETFIELD: case InstructionConstants.OP_PUTFIELD: case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: case InstructionConstants.OP_INVOKEDYNAMIC: invocationUnit.invokeMember(clazz, method, codeAttribute, offset, constantInstruction, stack); break; case InstructionConstants.OP_NEW: stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue()); break; case InstructionConstants.OP_ANEWARRAY: { ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue(); stack.push(valueFactory.createArrayReferenceValue(referenceValue.internalType(), referenceValue.getReferencedClass(), stack.ipop())); break; } case InstructionConstants.OP_CHECKCAST: // TODO: Check cast. ReferenceValue castValue = stack.apop(); ReferenceValue castResultValue = castValue.isNull() == Value.ALWAYS ? castValue : castValue.isNull() == Value.NEVER ? constantValueFactory.constantValue(clazz, constantIndex).referenceValue() : constantValueFactory.constantValue(clazz, constantIndex).referenceValue().generalize(valueFactory.createReferenceValueNull()); stack.push(castResultValue); break; case InstructionConstants.OP_INSTANCEOF: { ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue(); int instanceOf = stack.apop().instanceOf(referenceValue.getType(), referenceValue.getReferencedClass()); stack.push(instanceOf == Value.NEVER ? valueFactory.createIntegerValue(0) : instanceOf == Value.ALWAYS ? valueFactory.createIntegerValue(1) : valueFactory.createIntegerValue()); break; } case InstructionConstants.OP_MULTIANEWARRAY: { int dimensionCount = constantInstruction.constant; for (int dimension = 0; dimension < dimensionCount; dimension++) { // TODO: Use array lengths. IntegerValue arrayLength = stack.ipop(); } stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue()); break; } default: throw new IllegalArgumentException("Unknown constant pool instruction ["+constantInstruction.opcode+"]"); } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { int variableIndex = variableInstruction.variableIndex; switch (variableInstruction.opcode) { case InstructionConstants.OP_ILOAD: case InstructionConstants.OP_ILOAD_0: case InstructionConstants.OP_ILOAD_1: case InstructionConstants.OP_ILOAD_2: case InstructionConstants.OP_ILOAD_3: stack.push(variables.iload(variableIndex)); break; case InstructionConstants.OP_LLOAD: case InstructionConstants.OP_LLOAD_0: case InstructionConstants.OP_LLOAD_1: case InstructionConstants.OP_LLOAD_2: case InstructionConstants.OP_LLOAD_3: stack.push(variables.lload(variableIndex)); break; case InstructionConstants.OP_FLOAD: case InstructionConstants.OP_FLOAD_0: case InstructionConstants.OP_FLOAD_1: case InstructionConstants.OP_FLOAD_2: case InstructionConstants.OP_FLOAD_3: stack.push(variables.fload(variableIndex)); break; case InstructionConstants.OP_DLOAD: case InstructionConstants.OP_DLOAD_0: case InstructionConstants.OP_DLOAD_1: case InstructionConstants.OP_DLOAD_2: case InstructionConstants.OP_DLOAD_3: stack.push(variables.dload(variableIndex)); break; case InstructionConstants.OP_ALOAD: case InstructionConstants.OP_ALOAD_0: case InstructionConstants.OP_ALOAD_1: case InstructionConstants.OP_ALOAD_2: case InstructionConstants.OP_ALOAD_3: stack.push(variables.aload(variableIndex)); break; case InstructionConstants.OP_ISTORE: case InstructionConstants.OP_ISTORE_0: case InstructionConstants.OP_ISTORE_1: case InstructionConstants.OP_ISTORE_2: case InstructionConstants.OP_ISTORE_3: variables.store(variableIndex, stack.ipop()); break; case InstructionConstants.OP_LSTORE: case InstructionConstants.OP_LSTORE_0: case InstructionConstants.OP_LSTORE_1: case InstructionConstants.OP_LSTORE_2: case InstructionConstants.OP_LSTORE_3: variables.store(variableIndex, stack.lpop()); break; case InstructionConstants.OP_FSTORE: case InstructionConstants.OP_FSTORE_0: case InstructionConstants.OP_FSTORE_1: case InstructionConstants.OP_FSTORE_2: case InstructionConstants.OP_FSTORE_3: variables.store(variableIndex, stack.fpop()); break; case InstructionConstants.OP_DSTORE: case InstructionConstants.OP_DSTORE_0: case InstructionConstants.OP_DSTORE_1: case InstructionConstants.OP_DSTORE_2: case InstructionConstants.OP_DSTORE_3: variables.store(variableIndex, stack.dpop()); break; case InstructionConstants.OP_ASTORE: case InstructionConstants.OP_ASTORE_0: case InstructionConstants.OP_ASTORE_1: case InstructionConstants.OP_ASTORE_2: case InstructionConstants.OP_ASTORE_3: // The operand on the stack can be a reference or a return // address, so we'll relax the pop operation. //variables.store(variableIndex, stack.apop()); variables.store(variableIndex, stack.pop()); break; case InstructionConstants.OP_IINC: variables.store(variableIndex, variables.iload(variableIndex).add( valueFactory.createIntegerValue(variableInstruction.constant))); break; case InstructionConstants.OP_RET: // The return address should be in the last offset of the // given instruction offset variable (even though there may // be other offsets). InstructionOffsetValue instructionOffsetValue = variables.oload(variableIndex); branchUnit.branch(clazz, codeAttribute, offset, instructionOffsetValue.instructionOffset(instructionOffsetValue.instructionOffsetCount()-1)); break; default: throw new IllegalArgumentException("Unknown variable instruction ["+variableInstruction.opcode+"]"); } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { int branchTarget = offset + branchInstruction.branchOffset; switch (branchInstruction.opcode) { case InstructionConstants.OP_IFEQ: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().equal(valueFactory.createIntegerValue(0))); break; case InstructionConstants.OP_IFNE: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().notEqual(valueFactory.createIntegerValue(0))); break; case InstructionConstants.OP_IFLT: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().lessThan(valueFactory.createIntegerValue(0))); break; case InstructionConstants.OP_IFGE: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().greaterThanOrEqual(valueFactory.createIntegerValue(0))); break; case InstructionConstants.OP_IFGT: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().greaterThan(valueFactory.createIntegerValue(0))); break; case InstructionConstants.OP_IFLE: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().lessThanOrEqual(valueFactory.createIntegerValue(0))); break; case InstructionConstants.OP_IFICMPEQ: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().equal(stack.ipop())); break; case InstructionConstants.OP_IFICMPNE: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().notEqual(stack.ipop())); break; case InstructionConstants.OP_IFICMPLT: // Note that the stack entries are popped in reverse order. branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().greaterThan(stack.ipop())); break; case InstructionConstants.OP_IFICMPGE: // Note that the stack entries are popped in reverse order. branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().lessThanOrEqual(stack.ipop())); break; case InstructionConstants.OP_IFICMPGT: // Note that the stack entries are popped in reverse order. branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().lessThan(stack.ipop())); break; case InstructionConstants.OP_IFICMPLE: // Note that the stack entries are popped in reverse order. branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.ipop().greaterThanOrEqual(stack.ipop())); break; case InstructionConstants.OP_IFACMPEQ: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.apop().equal(stack.apop())); break; case InstructionConstants.OP_IFACMPNE: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.apop().notEqual(stack.apop())); break; case InstructionConstants.OP_GOTO: case InstructionConstants.OP_GOTO_W: branchUnit.branch(clazz, codeAttribute, offset, branchTarget); break; case InstructionConstants.OP_JSR: case InstructionConstants.OP_JSR_W: stack.push(new InstructionOffsetValue(offset + branchInstruction.length(offset))); branchUnit.branch(clazz, codeAttribute, offset, branchTarget); break; case InstructionConstants.OP_IFNULL: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.apop().isNull()); break; case InstructionConstants.OP_IFNONNULL: branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, stack.apop().isNotNull()); break; default: throw new IllegalArgumentException("Unknown branch instruction ["+branchInstruction.opcode+"]"); } } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { IntegerValue indexValue = stack.ipop(); // If there is no definite branch in any of the cases below, // branch to the default offset. branchUnit.branch(clazz, codeAttribute, offset, offset + tableSwitchInstruction.defaultOffset); for (int index = 0; index < tableSwitchInstruction.jumpOffsets.length; index++) { int conditional = indexValue.equal(valueFactory.createIntegerValue( tableSwitchInstruction.lowCase + index)); branchUnit.branchConditionally(clazz, codeAttribute, offset, offset + tableSwitchInstruction.jumpOffsets[index], conditional); // If this branch is always taken, we can skip the rest. if (conditional == Value.ALWAYS) { break; } } } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { IntegerValue indexValue = stack.ipop(); // If there is no definite branch in any of the cases below, // branch to the default offset. branchUnit.branch(clazz, codeAttribute, offset, offset + lookUpSwitchInstruction.defaultOffset); for (int index = 0; index < lookUpSwitchInstruction.jumpOffsets.length; index++) { int conditional = indexValue.equal(valueFactory.createIntegerValue( lookUpSwitchInstruction.cases[index])); branchUnit.branchConditionally(clazz, codeAttribute, offset, offset + lookUpSwitchInstruction.jumpOffsets[index], conditional); // If this branch is always taken, we can skip the rest. if (conditional == Value.ALWAYS) { break; } } } } proguard4.8/src/proguard/evaluation/BranchUnit.java0000644000175000017500000000376111736333523021257 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.classfile.Clazz; import proguard.classfile.attribute.CodeAttribute; /** * This InstructionVisitor evaluates the instructions that it visits. * * @author Eric Lafortune */ public interface BranchUnit { /** * Sets the new instruction offset. */ public void branch(Clazz clazz, CodeAttribute codeAttribute, int offset, int branchTarget); /** * Sets the new instruction offset, depending on the certainty of the * conditional branch. */ public void branchConditionally(Clazz clazz, CodeAttribute codeAttribute, int offset, int branchTarget, int conditional); /** * Returns from the method with the given value. */ public void returnFromMethod(); /** * Handles the throwing of an exception. */ public void throwException(); } proguard4.8/src/proguard/evaluation/Variables.java0000644000175000017500000002173411736333523021132 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.evaluation.value.*; import java.util.Arrays; /** * This class represents a local variable frame that contains Value * objects. Values are generalizations of all values that have been stored in * the respective variables. * * @author Eric Lafortune */ public class Variables { private static final TopValue TOP_VALUE = new TopValue(); protected Value[] values; protected int size; /** * Creates a new Variables object with a given maximum number of variables. */ public Variables(int size) { this.values = new Value[size]; this.size = size; } /** * Creates a Variables object that is a copy of the given Variables object. */ public Variables(Variables variables) { // Create the values array. this(variables.size); // Copy the values. initialize(variables); } /** * Resets this Variables object, so that it can be reused. */ public void reset(int size) { // Is the values array large enough? if (size > values.length) { // Create a new one. values = new Value[size]; } else { // Clear the variables. Arrays.fill(values, null); } this.size = size; } /** * Initializes the values of this Variables object with the values of the * given Variables object. The other object may have fewer values, in which * case the remaining values are left unchanged. */ public void initialize(Variables other) { if (this.size < other.size) { throw new IllegalArgumentException("Variable frame is too small ["+this.size+"] compared to other frame ["+other.size+"]"); } // Copy the values. System.arraycopy(other.values, 0, this.values, 0, other.size); } /** * Generalizes the values of this Variables object with the values of the * given Variables object. * @param clearConflictingOtherVariables specifies whether the other * variables should be cleared too, * in case of conflicts. * @return whether the generalization has made any difference. */ public boolean generalize(Variables other, boolean clearConflictingOtherVariables) { if (this.size != other.size) { throw new IllegalArgumentException("Variable frames have different sizes ["+this.size+"] and ["+other.size+"]"); } boolean changed = false; for (int index = 0; index < size; index++) { Value thisValue = this.values[index]; Value otherValue = other.values[index]; // Occasionally, two values of different types might be present // in the same variable in a variable frame (corresponding to // two local variables that share the same index), at some point // outside of their scopes. Don't generalize the variable then, // but let it clear instead. if (thisValue != null && otherValue != null && thisValue.computationalType() == otherValue.computationalType()) { Value newValue = thisValue.generalize(otherValue); changed = changed || !thisValue.equals(newValue); this.values[index] = newValue; } else { changed = changed || thisValue != null; this.values[index] = null; if (clearConflictingOtherVariables) { other.values[index] = null; } } } return changed; } /** * Returns the number of variables. */ public int size() { return size; } /** * Gets the Value of the variable with the given index, without disturbing it. */ public Value getValue(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("Variable index ["+index+"] out of bounds ["+size+"]"); } return values[index]; } /** * Stores the given Value at the given variable index. */ public void store(int index, Value value) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("Variable index ["+index+"] out of bounds ["+size+"]"); } // Store the value. values[index] = value; // Account for the extra space required by Category 2 values. if (value.isCategory2()) { values[index + 1] = TOP_VALUE; } } /** * Loads the Value from the variable with the given index. */ public Value load(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("Variable index ["+index+"] out of bounds ["+size+"]"); } return values[index]; } // Load methods that provide convenient casts to the expected value types. /** * Loads the IntegerValue from the variable with the given index. */ public IntegerValue iload(int index) { return load(index).integerValue(); } /** * Loads the LongValue from the variable with the given index. */ public LongValue lload(int index) { return load(index).longValue(); } /** * Loads the FloatValue from the variable with the given index. */ public FloatValue fload(int index) { return load(index).floatValue(); } /** * Loads the DoubleValue from the variable with the given index. */ public DoubleValue dload(int index) { return load(index).doubleValue(); } /** * Loads the ReferenceValue from the variable with the given index. */ public ReferenceValue aload(int index) { return load(index).referenceValue(); } /** * Loads the InstructionOffsetValue from the variable with the given index. */ public InstructionOffsetValue oload(int index) { return load(index).instructionOffsetValue(); } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } Variables other = (Variables)object; if (this.size != other.size) { return false; } for (int index = 0; index < size; index++) { Value thisValue = this.values[index]; Value otherValue = other.values[index]; // Occasionally, two values of different types might be // present in the same variable in a variable frame // (corresponding to two local variables that share the // same index), at some point outside of their scopes. // We'll ignore these. if (thisValue != null && otherValue != null && thisValue.computationalType() == otherValue.computationalType() && !thisValue.equals(otherValue)) { return false; } } return true; } public int hashCode() { int hashCode = size; for (int index = 0; index < size; index++) { Value value = values[index]; if (value != null) { hashCode ^= value.hashCode(); } } return hashCode; } public String toString() { StringBuffer buffer = new StringBuffer(); for (int index = 0; index < size; index++) { Value value = values[index]; buffer = buffer.append('[') .append(value == null ? "empty" : value.toString()) .append(']'); } return buffer.toString(); } } proguard4.8/src/proguard/evaluation/InvocationUnit.java0000644000175000017500000000430211736333523022163 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.ConstantInstruction; import proguard.evaluation.value.Value; /** * This interface sets up the variables for entering a method, * and it updates the stack for the invocation of a class member. * * @author Eric Lafortune */ public interface InvocationUnit { /** * Sets up the given variables for entering the given method. */ public void enterMethod(Clazz clazz, Method method, Variables variables); /** * Exits the given method with the given return value. */ public void exitMethod(Clazz clazz, Method method, Value returnValue); /** * Updates the given stack corresponding to the execution of the given * field or method reference instruction. */ public void invokeMember(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction, Stack stack); } proguard4.8/src/proguard/evaluation/BasicBranchUnit.java0000644000175000017500000000674511736333523022226 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.classfile.Clazz; import proguard.classfile.attribute.CodeAttribute; import proguard.evaluation.value.InstructionOffsetValue; /** * This BranchUnit remembers the branch unit commands that are invoked on it. * I doesn't consider conditions when branching. * * @author Eric Lafortune */ public class BasicBranchUnit implements BranchUnit { private boolean wasCalled; private InstructionOffsetValue traceBranchTargets; /** * Resets the flag that tells whether any of the branch unit commands was * called. */ public void resetCalled() { wasCalled = false; } /** * Sets the flag that tells whether any of the branch unit commands was * called. */ protected void setCalled() { wasCalled = true; } /** * Returns whether any of the branch unit commands was called. */ public boolean wasCalled() { return wasCalled; } /** * Sets the initial branch targets, which will be updated as the branch * methods of the branch unit are called. */ public void setTraceBranchTargets(InstructionOffsetValue branchTargets) { this.traceBranchTargets = branchTargets; } public InstructionOffsetValue getTraceBranchTargets() { return traceBranchTargets; } // Implementations for BranchUnit. public void branch(Clazz clazz, CodeAttribute codeAttribute, int offset, int branchTarget) { // Override the branch targets. traceBranchTargets = new InstructionOffsetValue(branchTarget); wasCalled = true; } public void branchConditionally(Clazz clazz, CodeAttribute codeAttribute, int offset, int branchTarget, int conditional) { // Accumulate the branch targets. traceBranchTargets = traceBranchTargets.generalize(new InstructionOffsetValue(branchTarget)).instructionOffsetValue(); wasCalled = true; } public void returnFromMethod() { // Stop processing this block. traceBranchTargets = InstructionOffsetValue.EMPTY_VALUE; wasCalled = true; } public void throwException() { // Stop processing this block. traceBranchTargets = InstructionOffsetValue.EMPTY_VALUE; wasCalled = true; } } proguard4.8/src/proguard/evaluation/TracedVariables.java0000644000175000017500000001314511736333523022252 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.evaluation.value.Value; /** * This Variables class saves additional information with variables, to keep * track of their origins. *

* The Variables class stores a given producer Value along with each Value it * stores. It then generalizes a given collected Value with the producer Value * of each Value it loads. The producer Value and the initial collected Value * can be set; the generalized collected Value can be retrieved. * * @author Eric Lafortune */ public class TracedVariables extends Variables { public static final int NONE = -1; private Value producerValue; private Variables producerVariables; /** * Creates a new TracedVariables with a given size. */ public TracedVariables(int size) { super(size); producerVariables = new Variables(size); } /** * Creates a new TracedVariables that is a copy of the given TracedVariables. */ public TracedVariables(TracedVariables tracedVariables) { super(tracedVariables); producerVariables = new Variables(tracedVariables.producerVariables); } /** * Sets the Value that will be stored along with all store instructions. */ public void setProducerValue(Value producerValue) { this.producerValue = producerValue; } /** * Gets the producer Value for the specified variable, without disturbing it. * @param index the variable index. * @return the producer value of the given variable. */ public Value getProducerValue(int index) { return producerVariables.getValue(index); } /** * Sets the given producer Value for the specified variable, without * disturbing it. * @param index the variable index. * @param value the producer value to set. */ public void setProducerValue(int index, Value value) { producerVariables.store(index, value); } // Implementations for Variables. public void reset(int size) { super.reset(size); producerVariables.reset(size); } public void initialize(TracedVariables other) { super.initialize(other); producerVariables.initialize(other.producerVariables); } public boolean generalize(TracedVariables other, boolean clearConflictingOtherVariables) { boolean variablesChanged = super.generalize(other, clearConflictingOtherVariables); boolean producersChanged = producerVariables.generalize(other.producerVariables, clearConflictingOtherVariables); /* consumerVariables.generalize(other.consumerVariables)*/ // Clear any traces if a variable has become null. if (variablesChanged) { for (int index = 0; index < size; index++) { if (values[index] == null) { producerVariables.values[index] = null; if (clearConflictingOtherVariables) { other.producerVariables.values[index] = null; } } } } return variablesChanged || producersChanged; } public void store(int index, Value value) { // Store the value itself in the variable. super.store(index, value); // Store the producer value in its producer variable. producerVariables.store(index, producerValue); // Account for the extra space required by Category 2 values. if (value.isCategory2()) { producerVariables.store(index+1, producerValue); } } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } TracedVariables other = (TracedVariables)object; return super.equals(object) && this.producerVariables.equals(other.producerVariables); } public int hashCode() { return super.hashCode() ^ producerVariables.hashCode(); } public String toString() { StringBuffer buffer = new StringBuffer(); for (int index = 0; index < this.size(); index++) { Value value = this.values[index]; Value producerValue = producerVariables.getValue(index); buffer = buffer.append('[') .append(producerValue == null ? "empty:" : producerValue.toString()) .append(value == null ? "empty" : value.toString()) .append(']'); } return buffer.toString(); } } proguard4.8/src/proguard/evaluation/ConstantValueFactory.java0000644000175000017500000000776311736333523023346 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.evaluation.value.*; /** * This class creates Value instance that correspond to specified constant pool * entries. * * @author Eric Lafortune */ public class ConstantValueFactory extends SimplifiedVisitor implements ConstantVisitor { protected final ValueFactory valueFactory; // Field acting as a parameter for the ConstantVisitor methods. protected Value value; public ConstantValueFactory(ValueFactory valueFactory) { this.valueFactory = valueFactory; } /** * Returns the Value of the constant pool element at the given index. */ public Value constantValue(Clazz clazz, int constantIndex) { // Visit the constant pool entry to get its return value. clazz.constantPoolEntryAccept(constantIndex, this); return value; } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { value = valueFactory.createIntegerValue(integerConstant.getValue()); } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { value = valueFactory.createLongValue(longConstant.getValue()); } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { value = valueFactory.createFloatValue(floatConstant.getValue()); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { value = valueFactory.createDoubleValue(doubleConstant.getValue()); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { value = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING, stringConstant.javaLangStringClass, false); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { value = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_HANDLE, methodHandleConstant.javaLangInvokeMethodHandleClass, false); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { value = valueFactory.createReferenceValue(classConstant.getName(clazz), classConstant.referencedClass, false); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { value = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_TYPE, methodTypeConstant.javaLangInvokeMethodTypeClass, false); } }proguard4.8/src/proguard/evaluation/Stack.java0000644000175000017500000003265411736333523020272 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.evaluation.value.*; import java.util.Arrays; /** * This class represents an operand stack that contains Value * objects. * * @author Eric Lafortune */ public class Stack { private static final TopValue TOP_VALUE = new TopValue(); protected Value[] values; protected int currentSize; protected int actualMaxSize; /** * Creates a new Stack with a given maximum size, accounting for the double * space required by Category 2 values. */ public Stack(int maxSize) { values = new Value[maxSize]; } /** * Creates a Stack that is a copy of the given Stack. */ public Stack(Stack stack) { // Create the values array. this(stack.values.length); // Copy the stack contents. copy(stack); } /** * Returns the actual maximum stack size that was required for all stack * operations, accounting for the double space required by Category 2 values. */ public int getActualMaxSize() { return actualMaxSize; } /** * Resets this Stack, so that it can be reused. */ public void reset(int maxSize) { // Is the values array large enough? if (maxSize > values.length) { // Create a new one. values = new Value[maxSize]; } // Clear the sizes. clear(); actualMaxSize = 0; } /** * Copies the values of the given Stack into this Stack. */ public void copy(Stack other) { // Is the values array large enough? if (other.values.length > values.length) { // Create a new one. values = new Value[other.values.length]; } // Copy the stack contents. System.arraycopy(other.values, 0, this.values, 0, other.currentSize); // Copy the sizes. currentSize = other.currentSize; actualMaxSize = other.actualMaxSize; } /** * Generalizes the values of this Stack with the values of the given Stack. * The stacks must have the same current sizes. * @return whether the generalization has made any difference. */ public boolean generalize(Stack other) { if (this.currentSize != other.currentSize) { throw new IllegalArgumentException("Stacks have different current sizes ["+this.currentSize+"] and ["+other.currentSize+"]"); } boolean changed = false; // Generalize the stack values. for (int index = 0; index < currentSize; index++) { Value thisValue = this.values[index]; if (thisValue != null) { Value newValue = null; Value otherValue = other.values[index]; if (otherValue != null) { newValue = thisValue.generalize(otherValue); } changed = changed || !thisValue.equals(newValue); values[index] = newValue; } } // Check if the other stack extends beyond this one. if (this.actualMaxSize < other.actualMaxSize) { this.actualMaxSize = other.actualMaxSize; } return changed; } /** * Clears the stack. */ public void clear() { // Clear the stack contents. Arrays.fill(values, 0, currentSize, null); currentSize = 0; } /** * Returns the number of elements currently on the stack, accounting for the * double space required by Category 2 values. */ public int size() { return currentSize; } /** * Gets the specified Value from the stack, without disturbing it. * @param index the index of the stack element, counting from the bottom * of the stack. * @return the value at the specified position. */ public Value getBottom(int index) { return values[index]; } /** * Sets the specified Value on the stack, without disturbing it. * @param index the index of the stack element, counting from the bottom * of the stack. * @param value the value to set. */ public void setBottom(int index, Value value) { values[index] = value; } /** * Gets the specified Value from the stack, without disturbing it. * @param index the index of the stack element, counting from the top * of the stack. * @return the value at the specified position. */ public Value getTop(int index) { return values[currentSize - index - 1]; } /** * Sets the specified Value on the stack, without disturbing it. * @param index the index of the stack element, counting from the top * of the stack. * @param value the value to set. */ public void setTop(int index, Value value) { values[currentSize - index - 1] = value; } /** * Removes the specified Value from the stack. * @param index the index of the stack element, counting from the top * of the stack. */ public void removeTop(int index) { System.arraycopy(values, currentSize - index, values, currentSize - index - 1, index); currentSize--; } /** * Pushes the given Value onto the stack. */ public void push(Value value) { // Account for the extra space required by Category 2 values. if (value.isCategory2()) { values[currentSize++] = TOP_VALUE; } // Push the value. values[currentSize++] = value; // Update the maximum actual size; if (actualMaxSize < currentSize) { actualMaxSize = currentSize; } } /** * Pops the top Value from the stack. */ public Value pop() { Value value = values[--currentSize]; values[currentSize] = null; // Account for the extra space required by Category 2 values. if (value.isCategory2()) { values[--currentSize] = null; } return value; } // Pop methods that provide convenient casts to the expected value types. /** * Pops the top IntegerValue from the stack. */ public IntegerValue ipop() { return pop().integerValue(); } /** * Pops the top LongValue from the stack. */ public LongValue lpop() { return pop().longValue(); } /** * Pops the top FloatValue from the stack. */ public FloatValue fpop() { return pop().floatValue(); } /** * Pops the top DoubleValue from the stack. */ public DoubleValue dpop() { return pop().doubleValue(); } /** * Pops the top ReferenceValue from the stack. */ public ReferenceValue apop() { return pop().referenceValue(); } /** * Pops the top InstructionOffsetValue from the stack. */ public InstructionOffsetValue opop() { return pop().instructionOffsetValue(); } /** * Pops the top category 1 value from the stack. */ public void pop1() { values[--currentSize] = null; } /** * Pops the top category 2 value from the stack (or alternatively, two * Category 1 stack elements). */ public void pop2() { values[--currentSize] = null; values[--currentSize] = null; } /** * Duplicates the top Category 1 value. */ public void dup() { values[currentSize] = values[currentSize - 1].category1Value(); currentSize++; // Update the maximum actual size; if (actualMaxSize < currentSize) { actualMaxSize = currentSize; } } /** * Duplicates the top Category 1 value, one Category 1 element down the * stack. */ public void dup_x1() { values[currentSize] = values[currentSize - 1].category1Value(); values[currentSize - 1] = values[currentSize - 2].category1Value(); values[currentSize - 2] = values[currentSize ]; currentSize++; // Update the maximum actual size; if (actualMaxSize < currentSize) { actualMaxSize = currentSize; } } /** * Duplicates the top Category 1 value, two Category 1 elements (or one * Category 2 element) down the stack. */ public void dup_x2() { values[currentSize] = values[currentSize - 1].category1Value(); values[currentSize - 1] = values[currentSize - 2]; values[currentSize - 2] = values[currentSize - 3]; values[currentSize - 3] = values[currentSize ]; currentSize++; // Update the maximum actual size; if (actualMaxSize < currentSize) { actualMaxSize = currentSize; } } /** * Duplicates the top Category 2 value (or alternatively, the equivalent * Category 1 stack elements). */ public void dup2() { values[currentSize ] = values[currentSize - 2]; values[currentSize + 1] = values[currentSize - 1]; currentSize += 2; // Update the maximum actual size; if (actualMaxSize < currentSize) { actualMaxSize = currentSize; } } /** * Duplicates the top Category 2 value, one Category 1 element down the * stack (or alternatively, the equivalent Category 1 stack values). */ public void dup2_x1() { values[currentSize + 1] = values[currentSize - 1]; values[currentSize ] = values[currentSize - 2]; values[currentSize - 1] = values[currentSize - 3]; values[currentSize - 2] = values[currentSize + 1]; values[currentSize - 3] = values[currentSize ]; currentSize += 2; // Update the maximum actual size; if (actualMaxSize < currentSize) { actualMaxSize = currentSize; } } /** * Duplicates the top Category 2 value, one Category 2 stack element down * the stack (or alternatively, the equivalent Category 1 stack values). */ public void dup2_x2() { values[currentSize + 1] = values[currentSize - 1]; values[currentSize ] = values[currentSize - 2]; values[currentSize - 1] = values[currentSize - 3]; values[currentSize - 2] = values[currentSize - 4]; values[currentSize - 3] = values[currentSize + 1]; values[currentSize - 4] = values[currentSize ]; currentSize += 2; // Update the maximum actual size; if (actualMaxSize < currentSize) { actualMaxSize = currentSize; } } /** * Swaps the top two Category 1 values. */ public void swap() { Value value1 = values[currentSize - 1].category1Value(); Value value2 = values[currentSize - 2].category1Value(); values[currentSize - 1] = value2; values[currentSize - 2] = value1; } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } Stack other = (Stack)object; if (this.currentSize != other.currentSize) { return false; } for (int index = 0; index < currentSize; index++) { Value thisValue = this.values[index]; Value otherValue = other.values[index]; if (thisValue == null ? otherValue != null : !thisValue.equals(otherValue)) { return false; } } return true; } public int hashCode() { int hashCode = currentSize; for (int index = 0; index < currentSize; index++) { Value value = values[index]; if (value != null) { hashCode ^= value.hashCode(); } } return hashCode; } public String toString() { StringBuffer buffer = new StringBuffer(); for (int index = 0; index < currentSize; index++) { Value value = values[index]; buffer = buffer.append('[') .append(value == null ? "empty" : value.toString()) .append(']'); } return buffer.toString(); } } proguard4.8/src/proguard/evaluation/BasicInvocationUnit.java0000644000175000017500000003326711736333523023141 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.evaluation.value.*; /** * This InvocationUnit sets up the variables for entering a method, * and it updates the stack for the invocation of a class member, * using simple values. * * @author Eric Lafortune */ public class BasicInvocationUnit extends SimplifiedVisitor implements InvocationUnit, ConstantVisitor, MemberVisitor { protected final ValueFactory valueFactory; // Fields acting as parameters between the visitor methods. private boolean isStatic; private boolean isLoad; private Stack stack; private Clazz returnTypeClass; /** * Creates a new BasicInvocationUnit with the given value factory. */ public BasicInvocationUnit(ValueFactory valueFactory) { this.valueFactory = valueFactory; } // Implementations for InvocationUnit. public void enterMethod(Clazz clazz, Method method, Variables variables) { String descriptor = method.getDescriptor(clazz); // Initialize the parameters. boolean isStatic = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0; // Count the number of parameters, taking into account their categories. int parameterSize = ClassUtil.internalMethodParameterSize(descriptor, isStatic); // Reuse the existing parameters object, ensuring the right size. variables.reset(parameterSize); // Go over the parameters again. InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); int parameterIndex = 0; int variableIndex = 0; // Put the 'this' reference in variable 0. if (!isStatic) { // Get the reference value. Value value = getMethodParameterValue(clazz, method, parameterIndex++, ClassUtil.internalTypeFromClassName(clazz.getName()), clazz); // Store the value in variable 0. variables.store(variableIndex++, value); } Clazz[] referencedClasses = ((ProgramMethod)method).referencedClasses; int referencedClassIndex = 0; // Set up the variables corresponding to the parameter types and values. while (internalTypeEnumeration.hasMoreTypes()) { String type = internalTypeEnumeration.nextType(); Clazz referencedClass = referencedClasses != null && ClassUtil.isInternalClassType(type) ? referencedClasses[referencedClassIndex++] : null; // Get the parameter value. Value value = getMethodParameterValue(clazz, method, parameterIndex++, type, referencedClass); // Store the value in the corresponding variable. variables.store(variableIndex++, value); // Increment the variable index again for Category 2 values. if (value.isCategory2()) { variableIndex++; } } } public void exitMethod(Clazz clazz, Method method, Value returnValue) { setMethodReturnValue(clazz, method, returnValue); } public void invokeMember(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction, Stack stack) { int constantIndex = constantInstruction.constantIndex; switch (constantInstruction.opcode) { case InstructionConstants.OP_GETSTATIC: isStatic = true; isLoad = true; break; case InstructionConstants.OP_PUTSTATIC: isStatic = true; isLoad = false; break; case InstructionConstants.OP_GETFIELD: isStatic = false; isLoad = true; break; case InstructionConstants.OP_PUTFIELD: isStatic = false; isLoad = false; break; case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEDYNAMIC: isStatic = true; break; case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKEINTERFACE: isStatic = false; break; } // Pop the parameters and push the return value. this.stack = stack; clazz.constantPoolEntryAccept(constantIndex, this); this.stack = null; } // Implementations for ConstantVisitor. public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { // Pop the field value, if applicable. if (!isLoad) { setFieldValue(clazz, fieldrefConstant, stack.pop()); } // Pop the reference value, if applicable. if (!isStatic) { setFieldClassValue(clazz, fieldrefConstant, stack.apop()); } // Push the field value, if applicable. if (isLoad) { String type = fieldrefConstant.getType(clazz); stack.push(getFieldValue(clazz, fieldrefConstant, type)); } } public void visitAnyMethodrefConstant(Clazz clazz, RefConstant methodrefConstant) { String type = methodrefConstant.getType(clazz); // Count the number of parameters. int parameterCount = ClassUtil.internalMethodParameterCount(type); if (!isStatic) { parameterCount++; } // Pop the parameters and the class reference, in reverse order. for (int parameterIndex = parameterCount-1; parameterIndex >= 0; parameterIndex--) { setMethodParameterValue(clazz, methodrefConstant, parameterIndex, stack.pop()); } // Push the return value, if applicable. String returnType = ClassUtil.internalMethodReturnType(type); if (returnType.charAt(0) != ClassConstants.INTERNAL_TYPE_VOID) { stack.push(getMethodReturnValue(clazz, methodrefConstant, returnType)); } } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { String type = invokeDynamicConstant.getType(clazz); // Count the number of parameters. int parameterCount = ClassUtil.internalMethodParameterCount(type); if (!isStatic) { parameterCount++; } // Pop the parameters and the class reference, in reverse order. for (int parameterIndex = parameterCount-1; parameterIndex >= 0; parameterIndex--) { stack.pop(); } // Push the return value, if applicable. String returnType = ClassUtil.internalMethodReturnType(type); if (returnType.charAt(0) != ClassConstants.INTERNAL_TYPE_VOID) { stack.push(getMethodReturnValue(clazz, invokeDynamicConstant, returnType)); } } /** * Sets the class through which the specified field is accessed. */ protected void setFieldClassValue(Clazz clazz, RefConstant refConstant, ReferenceValue value) { // We don't care about the new value. } /** * Returns the class though which the specified field is accessed. */ protected Value getFieldClassValue(Clazz clazz, RefConstant refConstant, String type) { // Try to figure out the class of the return type. returnTypeClass = null; refConstant.referencedMemberAccept(this); return valueFactory.createValue(type, returnTypeClass, true); } /** * Sets the value of the specified field. */ protected void setFieldValue(Clazz clazz, RefConstant refConstant, Value value) { // We don't care about the new field value. } /** * Returns the value of the specified field. */ protected Value getFieldValue(Clazz clazz, RefConstant refConstant, String type) { // Try to figure out the class of the return type. returnTypeClass = null; refConstant.referencedMemberAccept(this); return valueFactory.createValue(type, returnTypeClass, true); } /** * Sets the value of the specified method parameter. */ protected void setMethodParameterValue(Clazz clazz, RefConstant refConstant, int parameterIndex, Value value) { // We don't care about the parameter value. } /** * Returns the value of the specified method parameter. */ protected Value getMethodParameterValue(Clazz clazz, Method method, int parameterIndex, String type, Clazz referencedClass) { return valueFactory.createValue(type, referencedClass, true); } /** * Sets the return value of the specified method. */ protected void setMethodReturnValue(Clazz clazz, Method method, Value value) { // We don't care about the return value. } /** * Returns the return value of the specified method. */ protected Value getMethodReturnValue(Clazz clazz, RefConstant refConstant, String type) { // Try to figure out the class of the return type. returnTypeClass = null; refConstant.referencedMemberAccept(this); return valueFactory.createValue(type, returnTypeClass, true); } /** * Returns the return value of the specified method. */ protected Value getMethodReturnValue(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant, String type) { // Try to figure out the class of the return type. Clazz[] referencedClasses = invokeDynamicConstant.referencedClasses; Clazz returnTypeClass = referencedClasses == null ? null : referencedClasses[referencedClasses.length - 1]; return valueFactory.createValue(type, returnTypeClass, true); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { returnTypeClass = programField.referencedClass; } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { Clazz[] referencedClasses = programMethod.referencedClasses; if (referencedClasses != null) { returnTypeClass = referencedClasses[referencedClasses.length - 1]; } } public void visitLibraryField(LibraryClass programClass, LibraryField programField) { returnTypeClass = programField.referencedClass; } public void visitLibraryMethod(LibraryClass programClass, LibraryMethod programMethod) { Clazz[] referencedClasses = programMethod.referencedClasses; if (referencedClasses != null) { returnTypeClass = referencedClasses[referencedClasses.length - 1]; } } // public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) // { // } } proguard4.8/src/proguard/evaluation/TracedStack.java0000644000175000017500000001712711736333523021413 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.evaluation; import proguard.evaluation.value.Value; /** * This Stack saves additional information with stack elements, to keep track * of their origins and destinations. *

* The stack stores a given producer Value along with each Value it stores. * It then generalizes a given collected Value with the producer Value * of each Value it loads. The producer Value and the initial collected Value * can be set; the generalized collected Value can be retrieved. * * @author Eric Lafortune */ public class TracedStack extends Stack { private Value producerValue; private Stack producerStack; /** * Creates a new TracedStack with a given maximum size. */ public TracedStack(int maxSize) { super(maxSize); producerStack = new Stack(maxSize); } /** * Creates a new TracedStack that is a copy of the given TracedStack. */ public TracedStack(TracedStack tracedStack) { super(tracedStack); producerStack = new Stack(tracedStack.producerStack); } /** * Sets the Value that will be stored along with all push and pop * instructions. */ public void setProducerValue(Value producerValue) { this.producerValue = producerValue; } /** * Gets the specified producer Value from the stack, without disturbing it. * @param index the index of the stack element, counting from the bottom * of the stack. * @return the producer value at the specified position. */ public Value getBottomProducerValue(int index) { return producerStack.getBottom(index); } /** * Sets the specified producer Value on the stack, without disturbing it. * @param index the index of the stack element, counting from the bottom * of the stack. * @param value the producer value to set. */ public void setBottomProducerValue(int index, Value value) { producerStack.setBottom(index, value); } /** * Gets the specified producer Value from the stack, without disturbing it. * @param index the index of the stack element, counting from the top * of the stack. * @return the producer value at the specified position. */ public Value getTopProducerValue(int index) { return producerStack.getTop(index); } /** * Sets the specified producer Value on the stack, without disturbing it. * @param index the index of the stack element, counting from the top * of the stack. * @param value the producer value to set. */ public void setTopProducerValue(int index, Value value) { producerStack.setTop(index, value); } // Implementations for Stack. public void reset(int size) { super.reset(size); producerStack.reset(size); } public void copy(TracedStack other) { super.copy(other); producerStack.copy(other.producerStack); } public boolean generalize(TracedStack other) { return super.generalize(other) | producerStack.generalize(other.producerStack); } public void clear() { super.clear(); producerStack.clear(); } public void removeTop(int index) { super.removeTop(index); producerStack.removeTop(index); } public void push(Value value) { super.push(value); producerPush(); // Account for the extra space required by Category 2 values. if (value.isCategory2()) { producerPush(); } } public Value pop() { Value value = super.pop(); producerPop(); // Account for the extra space required by Category 2 values. if (value.isCategory2()) { producerPop(); } return value; } public void pop1() { super.pop1(); producerPop(); } public void pop2() { super.pop2(); producerPop(); producerPop(); } public void dup() { super.dup(); producerPop(); producerPush(); producerPush(); } public void dup_x1() { super.dup_x1(); producerPop(); producerPop(); producerPush(); producerPush(); producerPush(); } public void dup_x2() { super.dup_x2(); producerPop(); producerPop(); producerPop(); producerPush(); producerPush(); producerPush(); producerPush(); } public void dup2() { super.dup2(); producerPop(); producerPop(); producerPush(); producerPush(); producerPush(); producerPush(); } public void dup2_x1() { super.dup2_x1(); producerPop(); producerPop(); producerPop(); producerPush(); producerPush(); producerPush(); producerPush(); producerPush(); } public void dup2_x2() { super.dup2_x2(); producerPop(); producerPop(); producerPop(); producerPop(); producerPush(); producerPush(); producerPush(); producerPush(); producerPush(); producerPush(); } public void swap() { super.swap(); producerPop(); producerPop(); producerPush(); producerPush(); } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } TracedStack other = (TracedStack)object; return super.equals(object) && this.producerStack.equals(other.producerStack); } public int hashCode() { return super.hashCode() ^ producerStack.hashCode(); } public String toString() { StringBuffer buffer = new StringBuffer(); for (int index = 0; index < this.size(); index++) { Value value = this.values[index]; Value producerValue = producerStack.getBottom(index); buffer = buffer.append('[') .append(producerValue == null ? "empty:" : producerValue.toString()) .append(value == null ? "empty" : value.toString()) .append(']'); } return buffer.toString(); } // Small utility methods. private void producerPush() { producerStack.push(producerValue); } private void producerPop() { producerStack.pop(); } } proguard4.8/src/proguard/ArgumentWordReader.java0000644000175000017500000000537511736333523020617 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.io.*; /** * A WordReader that returns words from an argument list. * Single arguments are split into individual words if necessary. * * @author Eric Lafortune */ public class ArgumentWordReader extends WordReader { private final String[] arguments; private int index = 0; // /** // * Creates a new ArgumentWordReader for the given arguments. // */ // public ArgumentWordReader(String[] arguments) // { // this(arguments, null); // } // // /** * Creates a new ArgumentWordReader for the given arguments, with the * given base directory. */ public ArgumentWordReader(String[] arguments, File baseDir) { super(baseDir); this.arguments = arguments; } // Implementations for WordReader. protected String nextLine() throws IOException { return index < arguments.length ? arguments[index++] : null; } protected String lineLocationDescription() { return "argument number " + index; } /** * Test application that prints out the individual words of * the argument list. */ public static void main(String[] args) { try { WordReader reader = new ArgumentWordReader(args, null); try { while (true) { String word = reader.nextWord(false); if (word == null) System.exit(-1); System.err.println("["+word+"]"); } } catch (Exception ex) { ex.printStackTrace(); } finally { reader.close(); } } catch (IOException ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/classfile/0000775000175000017500000000000011760503005016137 5ustar ericericproguard4.8/src/proguard/classfile/LibraryMethod.java0000644000175000017500000000462211736333523021562 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.visitor.*; /** * Representation of a method from a class-file. * * @author Eric Lafortune */ public class LibraryMethod extends LibraryMember implements Method { /** * An extra field pointing to the Clazz objects referenced in the * descriptor string. This field is filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz[] referencedClasses; /** * Creates an uninitialized LibraryMethod. */ public LibraryMethod() { } /** * Creates an initialized LibraryMethod. */ public LibraryMethod(int u2accessFlags, String name, String descriptor) { super(u2accessFlags, name, descriptor); } // Implementations for LibraryMember. public void accept(LibraryClass libraryClass, MemberVisitor memberVisitor) { memberVisitor.visitLibraryMethod(libraryClass, this); } // Implementations for Member. public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { for (int index = 0; index < referencedClasses.length; index++) { if (referencedClasses[index] != null) { referencedClasses[index].accept(classVisitor); } } } } } proguard4.8/src/proguard/classfile/package.html0000644000175000017500000000123011736333523020423 0ustar ericeric This package contains classes to represent the various elements of class files.

A class file is represented by the {@link proguard.classfile.ClassFile ClassFile} interface. This interface currently has two alternative representations:

proguard4.8/src/proguard/classfile/instruction/0000775000175000017500000000000011760503005020520 5ustar ericericproguard4.8/src/proguard/classfile/instruction/package.html0000644000175000017500000000057311736333523023015 0ustar ericeric This package contains classes to represent Java bytecode instructions.

Not every instruction currently has its own class. Only groups of instructions that refer to the constant pool get their own representations.

While the package is sufficient for the current needs of the ProGuard application, it may very well be reorganised and extended in the future. proguard4.8/src/proguard/classfile/instruction/InstructionFactory.java0000644000175000017500000003037011736333523025246 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; /** * This class provides methods to create and reuse Instruction objects. * * @author Eric Lafortune */ public class InstructionFactory { /** * Creates a new Instruction from the data in the byte array, starting * at the given index. */ public static Instruction create(byte[] code, int offset) { Instruction instruction; int index = offset; byte opcode = code[index++]; boolean wide = false; if (opcode == InstructionConstants.OP_WIDE) { opcode = code[index++]; wide = true; } switch (opcode) { // Simple instructions. case InstructionConstants.OP_NOP: case InstructionConstants.OP_ACONST_NULL: case InstructionConstants.OP_ICONST_M1: case InstructionConstants.OP_ICONST_0: case InstructionConstants.OP_ICONST_1: case InstructionConstants.OP_ICONST_2: case InstructionConstants.OP_ICONST_3: case InstructionConstants.OP_ICONST_4: case InstructionConstants.OP_ICONST_5: case InstructionConstants.OP_LCONST_0: case InstructionConstants.OP_LCONST_1: case InstructionConstants.OP_FCONST_0: case InstructionConstants.OP_FCONST_1: case InstructionConstants.OP_FCONST_2: case InstructionConstants.OP_DCONST_0: case InstructionConstants.OP_DCONST_1: case InstructionConstants.OP_BIPUSH: case InstructionConstants.OP_SIPUSH: case InstructionConstants.OP_IALOAD: case InstructionConstants.OP_LALOAD: case InstructionConstants.OP_FALOAD: case InstructionConstants.OP_DALOAD: case InstructionConstants.OP_AALOAD: case InstructionConstants.OP_BALOAD: case InstructionConstants.OP_CALOAD: case InstructionConstants.OP_SALOAD: case InstructionConstants.OP_IASTORE: case InstructionConstants.OP_LASTORE: case InstructionConstants.OP_FASTORE: case InstructionConstants.OP_DASTORE: case InstructionConstants.OP_AASTORE: case InstructionConstants.OP_BASTORE: case InstructionConstants.OP_CASTORE: case InstructionConstants.OP_SASTORE: case InstructionConstants.OP_POP: case InstructionConstants.OP_POP2: case InstructionConstants.OP_DUP: case InstructionConstants.OP_DUP_X1: case InstructionConstants.OP_DUP_X2: case InstructionConstants.OP_DUP2: case InstructionConstants.OP_DUP2_X1: case InstructionConstants.OP_DUP2_X2: case InstructionConstants.OP_SWAP: case InstructionConstants.OP_IADD: case InstructionConstants.OP_LADD: case InstructionConstants.OP_FADD: case InstructionConstants.OP_DADD: case InstructionConstants.OP_ISUB: case InstructionConstants.OP_LSUB: case InstructionConstants.OP_FSUB: case InstructionConstants.OP_DSUB: case InstructionConstants.OP_IMUL: case InstructionConstants.OP_LMUL: case InstructionConstants.OP_FMUL: case InstructionConstants.OP_DMUL: case InstructionConstants.OP_IDIV: case InstructionConstants.OP_LDIV: case InstructionConstants.OP_FDIV: case InstructionConstants.OP_DDIV: case InstructionConstants.OP_IREM: case InstructionConstants.OP_LREM: case InstructionConstants.OP_FREM: case InstructionConstants.OP_DREM: case InstructionConstants.OP_INEG: case InstructionConstants.OP_LNEG: case InstructionConstants.OP_FNEG: case InstructionConstants.OP_DNEG: case InstructionConstants.OP_ISHL: case InstructionConstants.OP_LSHL: case InstructionConstants.OP_ISHR: case InstructionConstants.OP_LSHR: case InstructionConstants.OP_IUSHR: case InstructionConstants.OP_LUSHR: case InstructionConstants.OP_IAND: case InstructionConstants.OP_LAND: case InstructionConstants.OP_IOR: case InstructionConstants.OP_LOR: case InstructionConstants.OP_IXOR: case InstructionConstants.OP_LXOR: case InstructionConstants.OP_I2L: case InstructionConstants.OP_I2F: case InstructionConstants.OP_I2D: case InstructionConstants.OP_L2I: case InstructionConstants.OP_L2F: case InstructionConstants.OP_L2D: case InstructionConstants.OP_F2I: case InstructionConstants.OP_F2L: case InstructionConstants.OP_F2D: case InstructionConstants.OP_D2I: case InstructionConstants.OP_D2L: case InstructionConstants.OP_D2F: case InstructionConstants.OP_I2B: case InstructionConstants.OP_I2C: case InstructionConstants.OP_I2S: case InstructionConstants.OP_LCMP: case InstructionConstants.OP_FCMPL: case InstructionConstants.OP_FCMPG: case InstructionConstants.OP_DCMPL: case InstructionConstants.OP_DCMPG: case InstructionConstants.OP_IRETURN: case InstructionConstants.OP_LRETURN: case InstructionConstants.OP_FRETURN: case InstructionConstants.OP_DRETURN: case InstructionConstants.OP_ARETURN: case InstructionConstants.OP_RETURN: case InstructionConstants.OP_NEWARRAY: case InstructionConstants.OP_ARRAYLENGTH: case InstructionConstants.OP_ATHROW: case InstructionConstants.OP_MONITORENTER: case InstructionConstants.OP_MONITOREXIT: instruction = new SimpleInstruction(); break; // Instructions with a contant pool index. case InstructionConstants.OP_LDC: case InstructionConstants.OP_LDC_W: case InstructionConstants.OP_LDC2_W: case InstructionConstants.OP_GETSTATIC: case InstructionConstants.OP_PUTSTATIC: case InstructionConstants.OP_GETFIELD: case InstructionConstants.OP_PUTFIELD: case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: case InstructionConstants.OP_INVOKEDYNAMIC: case InstructionConstants.OP_NEW: case InstructionConstants.OP_ANEWARRAY: case InstructionConstants.OP_CHECKCAST: case InstructionConstants.OP_INSTANCEOF: case InstructionConstants.OP_MULTIANEWARRAY: instruction = new ConstantInstruction(); break; // Instructions with a local variable index. case InstructionConstants.OP_ILOAD: case InstructionConstants.OP_LLOAD: case InstructionConstants.OP_FLOAD: case InstructionConstants.OP_DLOAD: case InstructionConstants.OP_ALOAD: case InstructionConstants.OP_ILOAD_0: case InstructionConstants.OP_ILOAD_1: case InstructionConstants.OP_ILOAD_2: case InstructionConstants.OP_ILOAD_3: case InstructionConstants.OP_LLOAD_0: case InstructionConstants.OP_LLOAD_1: case InstructionConstants.OP_LLOAD_2: case InstructionConstants.OP_LLOAD_3: case InstructionConstants.OP_FLOAD_0: case InstructionConstants.OP_FLOAD_1: case InstructionConstants.OP_FLOAD_2: case InstructionConstants.OP_FLOAD_3: case InstructionConstants.OP_DLOAD_0: case InstructionConstants.OP_DLOAD_1: case InstructionConstants.OP_DLOAD_2: case InstructionConstants.OP_DLOAD_3: case InstructionConstants.OP_ALOAD_0: case InstructionConstants.OP_ALOAD_1: case InstructionConstants.OP_ALOAD_2: case InstructionConstants.OP_ALOAD_3: case InstructionConstants.OP_ISTORE: case InstructionConstants.OP_LSTORE: case InstructionConstants.OP_FSTORE: case InstructionConstants.OP_DSTORE: case InstructionConstants.OP_ASTORE: case InstructionConstants.OP_ISTORE_0: case InstructionConstants.OP_ISTORE_1: case InstructionConstants.OP_ISTORE_2: case InstructionConstants.OP_ISTORE_3: case InstructionConstants.OP_LSTORE_0: case InstructionConstants.OP_LSTORE_1: case InstructionConstants.OP_LSTORE_2: case InstructionConstants.OP_LSTORE_3: case InstructionConstants.OP_FSTORE_0: case InstructionConstants.OP_FSTORE_1: case InstructionConstants.OP_FSTORE_2: case InstructionConstants.OP_FSTORE_3: case InstructionConstants.OP_DSTORE_0: case InstructionConstants.OP_DSTORE_1: case InstructionConstants.OP_DSTORE_2: case InstructionConstants.OP_DSTORE_3: case InstructionConstants.OP_ASTORE_0: case InstructionConstants.OP_ASTORE_1: case InstructionConstants.OP_ASTORE_2: case InstructionConstants.OP_ASTORE_3: case InstructionConstants.OP_IINC: case InstructionConstants.OP_RET: instruction = new VariableInstruction(wide); break; // Instructions with a branch offset operand. case InstructionConstants.OP_IFEQ: case InstructionConstants.OP_IFNE: case InstructionConstants.OP_IFLT: case InstructionConstants.OP_IFGE: case InstructionConstants.OP_IFGT: case InstructionConstants.OP_IFLE: case InstructionConstants.OP_IFICMPEQ: case InstructionConstants.OP_IFICMPNE: case InstructionConstants.OP_IFICMPLT: case InstructionConstants.OP_IFICMPGE: case InstructionConstants.OP_IFICMPGT: case InstructionConstants.OP_IFICMPLE: case InstructionConstants.OP_IFACMPEQ: case InstructionConstants.OP_IFACMPNE: case InstructionConstants.OP_GOTO: case InstructionConstants.OP_JSR: case InstructionConstants.OP_IFNULL: case InstructionConstants.OP_IFNONNULL: case InstructionConstants.OP_GOTO_W: case InstructionConstants.OP_JSR_W: instruction = new BranchInstruction(); break; // The tableswitch instruction. case InstructionConstants.OP_TABLESWITCH: instruction = new TableSwitchInstruction(); break; // The lookupswitch instruction. case InstructionConstants.OP_LOOKUPSWITCH: instruction = new LookUpSwitchInstruction(); break; default: throw new IllegalArgumentException("Unknown instruction opcode ["+opcode+"] at offset "+offset); } instruction.opcode = opcode; instruction.readInfo(code, index); return instruction; } } proguard4.8/src/proguard/classfile/instruction/Instruction.java0000644000175000017500000005373311736333523023726 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.visitor.InstructionVisitor; /** * Base class for representing instructions. * * @author Eric Lafortune */ public abstract class Instruction { // An array for marking Category 2 instructions. private static final boolean[] IS_CATEGORY2 = new boolean[] { false, // nop false, // aconst_null false, // iconst_m1 false, // iconst_0 false, // iconst_1 false, // iconst_2 false, // iconst_3 false, // iconst_4 false, // iconst_5 true, // lconst_0 true, // lconst_1 false, // fconst_0 false, // fconst_1 false, // fconst_2 true, // dconst_0 true, // dconst_1 false, // bipush false, // sipush false, // ldc false, // ldc_w true, // ldc2_w false, // iload true, // lload false, // fload true, // dload false, // aload false, // iload_0 false, // iload_1 false, // iload_2 false, // iload_3 true, // lload_0 true, // lload_1 true, // lload_2 true, // lload_3 false, // fload_0 false, // fload_1 false, // fload_2 false, // fload_3 true, // dload_0 true, // dload_1 true, // dload_2 true, // dload_3 false, // aload_0 false, // aload_1 false, // aload_2 false, // aload_3 false, // iaload true, // laload false, // faload true, // daload false, // aaload false, // baload false, // caload false, // saload false, // istore true, // lstore false, // fstore true, // dstore false, // astore false, // istore_0 false, // istore_1 false, // istore_2 false, // istore_3 true, // lstore_0 true, // lstore_1 true, // lstore_2 true, // lstore_3 false, // fstore_0 false, // fstore_1 false, // fstore_2 false, // fstore_3 true, // dstore_0 true, // dstore_1 true, // dstore_2 true, // dstore_3 false, // astore_0 false, // astore_1 false, // astore_2 false, // astore_3 false, // iastore true, // lastore false, // fastore true, // dastore false, // aastore false, // bastore false, // castore false, // sastore false, // pop true, // pop2 false, // dup false, // dup_x1 false, // dup_x2 true, // dup2 true, // dup2_x1 true, // dup2_x2 false, // swap false, // iadd true, // ladd false, // fadd true, // dadd false, // isub true, // lsub false, // fsub true, // dsub false, // imul true, // lmul false, // fmul true, // dmul false, // idiv true, // ldiv false, // fdiv true, // ddiv false, // irem true, // lrem false, // frem true, // drem false, // ineg true, // lneg false, // fneg true, // dneg false, // ishl true, // lshl false, // ishr true, // lshr false, // iushr true, // lushr false, // iand true, // land false, // ior true, // lor false, // ixor true, // lxor false, // iinc false, // i2l false, // i2f false, // i2d true, // l2i true, // l2f true, // l2d false, // f2i false, // f2l false, // f2d true, // d2i true, // d2l true, // d2f false, // i2b false, // i2c false, // i2s true, // lcmp false, // fcmpl false, // fcmpg true, // dcmpl true, // dcmpg false, // ifeq false, // ifne false, // iflt false, // ifge false, // ifgt false, // ifle false, // ificmpeq false, // ificmpne false, // ificmplt false, // ificmpge false, // ificmpgt false, // ificmple false, // ifacmpeq false, // ifacmpne false, // goto false, // jsr false, // ret false, // tableswitch false, // lookupswitch false, // ireturn true, // lreturn false, // freturn true, // dreturn false, // areturn false, // return false, // getstatic false, // putstatic false, // getfield false, // putfield false, // invokevirtual false, // invokespecial false, // invokestatic false, // invokeinterface false, // invokedynamic false, // new false, // newarray false, // anewarray false, // arraylength false, // athrow false, // checkcast false, // instanceof false, // monitorenter false, // monitorexit false, // wide false, // multianewarray false, // ifnull false, // ifnonnull false, // goto_w false, // jsr_w }; // An array containing the fixed number of entries popped from the stack, // for all instructions. private static final int[] STACK_POP_COUNTS = new int[] { 0, // nop 0, // aconst_null 0, // iconst_m1 0, // iconst_0 0, // iconst_1 0, // iconst_2 0, // iconst_3 0, // iconst_4 0, // iconst_5 0, // lconst_0 0, // lconst_1 0, // fconst_0 0, // fconst_1 0, // fconst_2 0, // dconst_0 0, // dconst_1 0, // bipush 0, // sipush 0, // ldc 0, // ldc_w 0, // ldc2_w 0, // iload 0, // lload 0, // fload 0, // dload 0, // aload 0, // iload_0 0, // iload_1 0, // iload_2 0, // iload_3 0, // lload_0 0, // lload_1 0, // lload_2 0, // lload_3 0, // fload_0 0, // fload_1 0, // fload_2 0, // fload_3 0, // dload_0 0, // dload_1 0, // dload_2 0, // dload_3 0, // aload_0 0, // aload_1 0, // aload_2 0, // aload_3 2, // iaload 2, // laload 2, // faload 2, // daload 2, // aaload 2, // baload 2, // caload 2, // saload 1, // istore 2, // lstore 1, // fstore 2, // dstore 1, // astore 1, // istore_0 1, // istore_1 1, // istore_2 1, // istore_3 2, // lstore_0 2, // lstore_1 2, // lstore_2 2, // lstore_3 1, // fstore_0 1, // fstore_1 1, // fstore_2 1, // fstore_3 2, // dstore_0 2, // dstore_1 2, // dstore_2 2, // dstore_3 1, // astore_0 1, // astore_1 1, // astore_2 1, // astore_3 3, // iastore 4, // lastore 3, // fastore 4, // dastore 3, // aastore 3, // bastore 3, // castore 3, // sastore 1, // pop 2, // pop2 1, // dup 2, // dup_x1 3, // dup_x2 2, // dup2 3, // dup2_x1 4, // dup2_x2 2, // swap 2, // iadd 4, // ladd 2, // fadd 4, // dadd 2, // isub 4, // lsub 2, // fsub 4, // dsub 2, // imul 4, // lmul 2, // fmul 4, // dmul 2, // idiv 4, // ldiv 2, // fdiv 4, // ddiv 2, // irem 4, // lrem 2, // frem 4, // drem 1, // ineg 2, // lneg 1, // fneg 2, // dneg 2, // ishl 3, // lshl 2, // ishr 3, // lshr 2, // iushr 3, // lushr 2, // iand 4, // land 2, // ior 4, // lor 2, // ixor 4, // lxor 0, // iinc 1, // i2l 1, // i2f 1, // i2d 2, // l2i 2, // l2f 2, // l2d 1, // f2i 1, // f2l 1, // f2d 2, // d2i 2, // d2l 2, // d2f 1, // i2b 1, // i2c 1, // i2s 4, // lcmp 2, // fcmpl 2, // fcmpg 4, // dcmpl 4, // dcmpg 1, // ifeq 1, // ifne 1, // iflt 1, // ifge 1, // ifgt 1, // ifle 2, // ificmpeq 2, // ificmpne 2, // ificmplt 2, // ificmpge 2, // ificmpgt 2, // ificmple 2, // ifacmpeq 2, // ifacmpne 0, // goto 0, // jsr 0, // ret 1, // tableswitch 1, // lookupswitch 1, // ireturn 2, // lreturn 1, // freturn 2, // dreturn 1, // areturn 0, // return 0, // getstatic 0, // putstatic 1, // getfield 1, // putfield 1, // invokevirtual 1, // invokespecial 0, // invokestatic 1, // invokeinterface 0, // invokedynamic 0, // new 1, // newarray 1, // anewarray 1, // arraylength 1, // athrow 1, // checkcast 1, // instanceof 1, // monitorenter 1, // monitorexit 0, // wide 0, // multianewarray 1, // ifnull 1, // ifnonnull 0, // goto_w 0, // jsr_w }; // An array containing the fixed number of entries pushed onto the stack, // for all instructions. private static final int[] STACK_PUSH_COUNTS = new int[] { 0, // nop 1, // aconst_null 1, // iconst_m1 1, // iconst_0 1, // iconst_1 1, // iconst_2 1, // iconst_3 1, // iconst_4 1, // iconst_5 2, // lconst_0 2, // lconst_1 1, // fconst_0 1, // fconst_1 1, // fconst_2 2, // dconst_0 2, // dconst_1 1, // bipush 1, // sipush 1, // ldc 1, // ldc_w 2, // ldc2_w 1, // iload 2, // lload 1, // fload 2, // dload 1, // aload 1, // iload_0 1, // iload_1 1, // iload_2 1, // iload_3 2, // lload_0 2, // lload_1 2, // lload_2 2, // lload_3 1, // fload_0 1, // fload_1 1, // fload_2 1, // fload_3 2, // dload_0 2, // dload_1 2, // dload_2 2, // dload_3 1, // aload_0 1, // aload_1 1, // aload_2 1, // aload_3 1, // iaload 2, // laload 1, // faload 2, // daload 1, // aaload 1, // baload 1, // caload 1, // saload 0, // istore 0, // lstore 0, // fstore 0, // dstore 0, // astore 0, // istore_0 0, // istore_1 0, // istore_2 0, // istore_3 0, // lstore_0 0, // lstore_1 0, // lstore_2 0, // lstore_3 0, // fstore_0 0, // fstore_1 0, // fstore_2 0, // fstore_3 0, // dstore_0 0, // dstore_1 0, // dstore_2 0, // dstore_3 0, // astore_0 0, // astore_1 0, // astore_2 0, // astore_3 0, // iastore 0, // lastore 0, // fastore 0, // dastore 0, // aastore 0, // bastore 0, // castore 0, // sastore 0, // pop 0, // pop2 2, // dup 3, // dup_x1 4, // dup_x2 4, // dup2 5, // dup2_x1 6, // dup2_x2 2, // swap 1, // iadd 2, // ladd 1, // fadd 2, // dadd 1, // isub 2, // lsub 1, // fsub 2, // dsub 1, // imul 2, // lmul 1, // fmul 2, // dmul 1, // idiv 2, // ldiv 1, // fdiv 2, // ddiv 1, // irem 2, // lrem 1, // frem 2, // drem 1, // ineg 2, // lneg 1, // fneg 2, // dneg 1, // ishl 2, // lshl 1, // ishr 2, // lshr 1, // iushr 2, // lushr 1, // iand 2, // land 1, // ior 2, // lor 1, // ixor 2, // lxor 0, // iinc 2, // i2l 1, // i2f 2, // i2d 1, // l2i 1, // l2f 2, // l2d 1, // f2i 2, // f2l 2, // f2d 1, // d2i 2, // d2l 1, // d2f 1, // i2b 1, // i2c 1, // i2s 1, // lcmp 1, // fcmpl 1, // fcmpg 1, // dcmpl 1, // dcmpg 0, // ifeq 0, // ifne 0, // iflt 0, // ifge 0, // ifgt 0, // ifle 0, // ificmpeq 0, // ificmpne 0, // ificmplt 0, // ificmpge 0, // ificmpgt 0, // ificmple 0, // ifacmpeq 0, // ifacmpne 0, // goto 1, // jsr 0, // ret 0, // tableswitch 0, // lookupswitch 0, // ireturn 0, // lreturn 0, // freturn 0, // dreturn 0, // areturn 0, // return 0, // getstatic 0, // putstatic 0, // getfield 0, // putfield 0, // invokevirtual 0, // invokespecial 0, // invokestatic 0, // invokeinterface 0, // invokedynamic 1, // new 1, // newarray 1, // anewarray 1, // arraylength 0, // athrow 1, // checkcast 1, // instanceof 0, // monitorenter 0, // monitorexit 0, // wide 1, // multianewarray 0, // ifnull 0, // ifnonnull 0, // goto_w 1, // jsr_w }; public byte opcode; /** * Returns the canonical opcode of this instruction, i.e. typically the * opcode whose extension has been removed. */ public byte canonicalOpcode() { return opcode; } /** * Shrinks this instruction to its shortest possible form. * @return this instruction. */ public abstract Instruction shrink(); /** * Writes the Instruction at the given offset in the given code attribute. */ public final void write(CodeAttribute codeAttribute, int offset) { write(codeAttribute.code, offset); } /** * Writes the Instruction at the given offset in the given code array. */ public void write(byte[] code, int offset) { // Write the wide opcode, if necessary. if (isWide()) { code[offset++] = InstructionConstants.OP_WIDE; } // Write the opcode. code[offset++] = opcode; // Write any additional arguments. writeInfo(code, offset); } /** * Returns whether the instruction is wide, i.e. preceded by a wide opcode. * With the current specifications, only variable instructions can be wide. */ protected boolean isWide() { return false; } /** * Reads the data following the instruction opcode. */ protected abstract void readInfo(byte[] code, int offset); /** * Writes data following the instruction opcode. */ protected abstract void writeInfo(byte[] code, int offset); /** * Returns the length in bytes of the instruction. */ public abstract int length(int offset); /** * Accepts the given visitor. */ public abstract void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor); /** * Returns a description of the instruction, at the given offset. */ public String toString(int offset) { return "["+offset+"] "+ this.toString(); } /** * Returns the name of the instruction. */ public String getName() { return InstructionConstants.NAMES[opcode & 0xff]; } /** * Returns whether the instruction is a Category 2 instruction. This means * that it operates on long or double arguments. */ public boolean isCategory2() { return IS_CATEGORY2[opcode & 0xff]; } /** * Returns the number of entries popped from the stack during the execution * of the instruction. */ public int stackPopCount(Clazz clazz) { return STACK_POP_COUNTS[opcode & 0xff]; } /** * Returns the number of entries pushed onto the stack during the execution * of the instruction. */ public int stackPushCount(Clazz clazz) { return STACK_PUSH_COUNTS[opcode & 0xff]; } // Small utility methods. protected static int readByte(byte[] code, int offset) { return code[offset] & 0xff; } protected static int readShort(byte[] code, int offset) { return ((code[offset++] & 0xff) << 8) | ( code[offset ] & 0xff ); } protected static int readInt(byte[] code, int offset) { return ( code[offset++] << 24) | ((code[offset++] & 0xff) << 16) | ((code[offset++] & 0xff) << 8) | ( code[offset ] & 0xff ); } protected static int readValue(byte[] code, int offset, int valueSize) { switch (valueSize) { case 0: return 0; case 1: return readByte( code, offset); case 2: return readShort(code, offset); case 4: return readInt( code, offset); default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]"); } } protected static int readSignedByte(byte[] code, int offset) { return code[offset]; } protected static int readSignedShort(byte[] code, int offset) { return (code[offset++] << 8) | (code[offset ] & 0xff); } protected static int readSignedValue(byte[] code, int offset, int valueSize) { switch (valueSize) { case 0: return 0; case 1: return readSignedByte( code, offset); case 2: return readSignedShort(code, offset); case 4: return readInt( code, offset); default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]"); } } protected static void writeByte(byte[] code, int offset, int value) { if (value > 0xff) { throw new IllegalArgumentException("Unsigned byte value larger than 0xff ["+value+"]"); } code[offset] = (byte)value; } protected static void writeShort(byte[] code, int offset, int value) { if (value > 0xffff) { throw new IllegalArgumentException("Unsigned short value larger than 0xffff ["+value+"]"); } code[offset++] = (byte)(value >> 8); code[offset ] = (byte)(value ); } protected static void writeInt(byte[] code, int offset, int value) { code[offset++] = (byte)(value >> 24); code[offset++] = (byte)(value >> 16); code[offset++] = (byte)(value >> 8); code[offset ] = (byte)(value ); } protected static void writeValue(byte[] code, int offset, int value, int valueSize) { switch (valueSize) { case 0: break; case 1: writeByte( code, offset, value); break; case 2: writeShort(code, offset, value); break; case 4: writeInt( code, offset, value); break; default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]"); } } protected static void writeSignedByte(byte[] code, int offset, int value) { if (value << 24 >> 24 != value) { throw new IllegalArgumentException("Signed byte value out of range ["+value+"]"); } code[offset] = (byte)value; } protected static void writeSignedShort(byte[] code, int offset, int value) { if (value << 16 >> 16 != value) { throw new IllegalArgumentException("Signed short value out of range ["+value+"]"); } code[offset++] = (byte)(value >> 8); code[offset ] = (byte)(value ); } protected static void writeSignedValue(byte[] code, int offset, int value, int valueSize) { switch (valueSize) { case 0: break; case 1: writeSignedByte( code, offset, value); break; case 2: writeSignedShort(code, offset, value); break; case 4: writeInt( code, offset, value); break; default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]"); } } } proguard4.8/src/proguard/classfile/instruction/TableSwitchInstruction.java0000644000175000017500000001052111736333523026044 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.visitor.InstructionVisitor; /** * This Instruction represents a simple instruction without variable arguments * or constant pool references. * * @author Eric Lafortune */ public class TableSwitchInstruction extends SwitchInstruction { public int lowCase; public int highCase; /** * Creates an uninitialized TableSwitchInstruction. */ public TableSwitchInstruction() {} /** * Creates a new TableSwitchInstruction with the given arguments. */ public TableSwitchInstruction(byte opcode, int defaultOffset, int lowCase, int highCase, int[] jumpOffsets) { this.opcode = opcode; this.defaultOffset = defaultOffset; this.lowCase = lowCase; this.highCase = highCase; this.jumpOffsets = jumpOffsets; } /** * Copies the given instruction into this instruction. * @param tableSwitchInstruction the instruction to be copied. * @return this instruction. */ public TableSwitchInstruction copy(TableSwitchInstruction tableSwitchInstruction) { this.opcode = tableSwitchInstruction.opcode; this.defaultOffset = tableSwitchInstruction.defaultOffset; this.lowCase = tableSwitchInstruction.lowCase; this.highCase = tableSwitchInstruction.highCase; this.jumpOffsets = tableSwitchInstruction.jumpOffsets; return this; } // Implementations for Instruction. public Instruction shrink() { // There aren't any ways to shrink this instruction. return this; } protected void readInfo(byte[] code, int offset) { // Skip up to three padding bytes. offset += -offset & 3; // Read the three 32-bit arguments. defaultOffset = readInt(code, offset); offset += 4; lowCase = readInt(code, offset); offset += 4; highCase = readInt(code, offset); offset += 4; // Read the jump offsets. jumpOffsets = new int[highCase - lowCase + 1]; for (int index = 0; index < jumpOffsets.length; index++) { jumpOffsets[index] = readInt(code, offset); offset += 4; } } protected void writeInfo(byte[] code, int offset) { // Write up to three padding bytes. while ((offset & 3) != 0) { writeByte(code, offset++, 0); } // Write the three 32-bit arguments. writeInt(code, offset, defaultOffset); offset += 4; writeInt(code, offset, lowCase); offset += 4; writeInt(code, offset, highCase); offset += 4; // Write the jump offsets. int length = highCase - lowCase + 1; for (int index = 0; index < length; index++) { writeInt(code, offset, jumpOffsets[index]); offset += 4; } } public int length(int offset) { return 1 + (-(offset+1) & 3) + 12 + (highCase - lowCase + 1) * 4; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) { instructionVisitor.visitTableSwitchInstruction(clazz, method, codeAttribute, offset, this); } } proguard4.8/src/proguard/classfile/instruction/SwitchInstruction.java0000644000175000017500000000465211736333523025104 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; /** * This Instruction represents a simple instruction without variable arguments * or constant pool references. * * @author Eric Lafortune */ public abstract class SwitchInstruction extends Instruction { public int defaultOffset; public int[] jumpOffsets; /** * Creates an uninitialized SwitchInstruction. */ public SwitchInstruction() {} /** * Creates a new SwitchInstruction with the given arguments. */ public SwitchInstruction(byte opcode, int defaultOffset, int[] jumpOffsets) { this.opcode = opcode; this.defaultOffset = defaultOffset; this.jumpOffsets = jumpOffsets; } /** * Copies the given instruction into this instruction. * @param switchInstruction the instruction to be copied. * @return this instruction. */ public SwitchInstruction copy(SwitchInstruction switchInstruction) { this.opcode = switchInstruction.opcode; this.defaultOffset = switchInstruction.defaultOffset; this.jumpOffsets = switchInstruction.jumpOffsets; return this; } // Implementations for Instruction. public String toString(int offset) { return "["+offset+"] "+toString()+" (target="+(offset+defaultOffset)+")"; } // Implementations for Object. public String toString() { return getName()+" ("+jumpOffsets.length+" offsets, default="+defaultOffset+")"; } } proguard4.8/src/proguard/classfile/instruction/LookUpSwitchInstruction.java0000644000175000017500000001031011736333523026222 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.visitor.InstructionVisitor; /** * This Instruction represents a simple instruction without variable arguments * or constant pool references. * * @author Eric Lafortune */ public class LookUpSwitchInstruction extends SwitchInstruction { public int[] cases; /** * Creates an uninitialized LookUpSwitchInstruction. */ public LookUpSwitchInstruction() {} /** * Creates a new LookUpSwitchInstruction with the given arguments. */ public LookUpSwitchInstruction(byte opcode, int defaultOffset, int[] cases, int[] jumpOffsets) { this.opcode = opcode; this.defaultOffset = defaultOffset; this.cases = cases; this.jumpOffsets = jumpOffsets; } /** * Copies the given instruction into this instruction. * @param lookUpSwitchInstruction the instruction to be copied. * @return this instruction. */ public LookUpSwitchInstruction copy(LookUpSwitchInstruction lookUpSwitchInstruction) { this.opcode = lookUpSwitchInstruction.opcode; this.defaultOffset = lookUpSwitchInstruction.defaultOffset; this.cases = lookUpSwitchInstruction.cases; this.jumpOffsets = lookUpSwitchInstruction.jumpOffsets; return this; } // Implementations for Instruction. public Instruction shrink() { // There aren't any ways to shrink this instruction. return this; } protected void readInfo(byte[] code, int offset) { // Skip up to three padding bytes. offset += -offset & 3; // Read the two 32-bit arguments. defaultOffset = readInt(code, offset); offset += 4; int jumpOffsetCount = readInt(code, offset); offset += 4; // Read the matches-offset pairs. cases = new int[jumpOffsetCount]; jumpOffsets = new int[jumpOffsetCount]; for (int index = 0; index < jumpOffsetCount; index++) { cases[index] = readInt(code, offset); offset += 4; jumpOffsets[index] = readInt(code, offset); offset += 4; } } protected void writeInfo(byte[] code, int offset) { // Write up to three padding bytes. while ((offset & 3) != 0) { writeByte(code, offset++, 0); } // Write the two 32-bit arguments. writeInt(code, offset, defaultOffset); offset += 4; writeInt(code, offset, cases.length); offset += 4; // Write the matches-offset pairs. for (int index = 0; index < cases.length; index++) { writeInt(code, offset, cases[index]); offset += 4; writeInt(code, offset, jumpOffsets[index]); offset += 4; } } public int length(int offset) { return 1 + (-(offset+1) & 3) + 8 + cases.length * 8; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) { instructionVisitor.visitLookUpSwitchInstruction(clazz, method, codeAttribute, offset, this); } } proguard4.8/src/proguard/classfile/instruction/visitor/0000775000175000017500000000000011760503005022217 5ustar ericericproguard4.8/src/proguard/classfile/instruction/visitor/package.html0000644000175000017500000000010011736333523024476 0ustar ericeric This package contains visitors for instructions. proguard4.8/src/proguard/classfile/instruction/visitor/InstructionCounter.java0000644000175000017500000000355711736333523026764 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction.visitor; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.Instruction; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor counts the number of instructions that has been visited. * * @author Eric Lafortune */ public class InstructionCounter extends SimplifiedVisitor implements InstructionVisitor { private int count; /** * Returns the number of instructions that has been visited so far. */ public int getCount() { return count; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { count++; } } proguard4.8/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java0000644000175000017500000001147711736333523030017 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction.visitor; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.*; /** * This InstructionVisitor delegates all visits to each InstructionVisitor * in a given list. * * @author Eric Lafortune */ public class MultiInstructionVisitor implements InstructionVisitor { private static final int ARRAY_SIZE_INCREMENT = 5; private InstructionVisitor[] instructionVisitors; private int instructionVisitorCount; public MultiInstructionVisitor() { } public MultiInstructionVisitor(InstructionVisitor[] instructionVisitors) { this.instructionVisitors = instructionVisitors; this.instructionVisitorCount = instructionVisitors.length; } public void addInstructionVisitor(InstructionVisitor instructionVisitor) { ensureArraySize(); instructionVisitors[instructionVisitorCount++] = instructionVisitor; } private void ensureArraySize() { if (instructionVisitors == null) { instructionVisitors = new InstructionVisitor[ARRAY_SIZE_INCREMENT]; } else if (instructionVisitors.length == instructionVisitorCount) { InstructionVisitor[] newInstructionVisitors = new InstructionVisitor[instructionVisitorCount + ARRAY_SIZE_INCREMENT]; System.arraycopy(instructionVisitors, 0, newInstructionVisitors, 0, instructionVisitorCount); instructionVisitors = newInstructionVisitors; } } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { for (int index = 0; index < instructionVisitorCount; index++) { instructionVisitors[index].visitSimpleInstruction(clazz, method, codeAttribute, offset, simpleInstruction); } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { for (int index = 0; index < instructionVisitorCount; index++) { instructionVisitors[index].visitVariableInstruction(clazz, method, codeAttribute, offset, variableInstruction); } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { for (int index = 0; index < instructionVisitorCount; index++) { instructionVisitors[index].visitConstantInstruction(clazz, method, codeAttribute, offset, constantInstruction); } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { for (int index = 0; index < instructionVisitorCount; index++) { instructionVisitors[index].visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction); } } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { for (int index = 0; index < instructionVisitorCount; index++) { instructionVisitors[index].visitTableSwitchInstruction(clazz, method, codeAttribute, offset, tableSwitchInstruction); } } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { for (int index = 0; index < instructionVisitorCount; index++) { instructionVisitors[index].visitLookUpSwitchInstruction(clazz, method, codeAttribute, offset, lookUpSwitchInstruction); } } } proguard4.8/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java0000644000175000017500000000354711736333523027434 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor lets a given InstructionVisitor visit all Instruction * objects of the CodeAttribute objects it visits. * * @author Eric Lafortune */ public class AllInstructionVisitor extends SimplifiedVisitor implements AttributeVisitor { private final InstructionVisitor instructionVisitor; public AllInstructionVisitor(InstructionVisitor instructionVisitor) { this.instructionVisitor = instructionVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { codeAttribute.instructionsAccept(clazz, method, instructionVisitor); } } proguard4.8/src/proguard/classfile/instruction/visitor/InstructionVisitor.java0000644000175000017500000000423511736333523026776 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction.visitor; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.*; /** * This interface specifies the methods for a visitor of * Instruction objects. * * @author Eric Lafortune */ public interface InstructionVisitor { public void visitSimpleInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction); public void visitVariableInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction); public void visitConstantInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction); public void visitBranchInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction); public void visitTableSwitchInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction); public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction); } proguard4.8/src/proguard/classfile/instruction/BranchInstruction.java0000644000175000017500000001204711736333523025035 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.visitor.InstructionVisitor; /** * This interface describes an instruction that branches to a given offset in * the code. * * @author Eric Lafortune */ public class BranchInstruction extends Instruction { public int branchOffset; /** * Creates an uninitialized BranchInstruction. */ public BranchInstruction() {} public BranchInstruction(byte opcode, int branchOffset) { this.opcode = opcode; this.branchOffset = branchOffset; } /** * Copies the given instruction into this instruction. * @param branchInstruction the instruction to be copied. * @return this instruction. */ public BranchInstruction copy(BranchInstruction branchInstruction) { this.opcode = branchInstruction.opcode; this.branchOffset = branchInstruction.branchOffset; return this; } // Implementations for Instruction. public byte canonicalOpcode() { // Remove the _w extension, if any. switch (opcode) { case InstructionConstants.OP_GOTO_W: return InstructionConstants.OP_GOTO; case InstructionConstants.OP_JSR_W: return InstructionConstants.OP_JSR; default: return opcode; } } public Instruction shrink() { // Do we need an ordinary branch or a wide branch? if (requiredBranchOffsetSize() == 2) { // Can we replace the wide branch by an ordinary branch? if (opcode == InstructionConstants.OP_GOTO_W) { opcode = InstructionConstants.OP_GOTO; } else if (opcode == InstructionConstants.OP_JSR_W) { opcode = InstructionConstants.OP_JSR; } } else { // Should we replace the ordinary branch by a wide branch? if (opcode == InstructionConstants.OP_GOTO) { opcode = InstructionConstants.OP_GOTO_W; } else if (opcode == InstructionConstants.OP_JSR) { opcode = InstructionConstants.OP_JSR_W; } else { throw new IllegalArgumentException("Branch instruction can't be widened ("+this.toString()+")"); } } return this; } protected void readInfo(byte[] code, int offset) { branchOffset = readSignedValue(code, offset, branchOffsetSize()); } protected void writeInfo(byte[] code, int offset) { if (requiredBranchOffsetSize() > branchOffsetSize()) { throw new IllegalArgumentException("Instruction has invalid branch offset size ("+this.toString(offset)+")"); } writeSignedValue(code, offset, branchOffset, branchOffsetSize()); } public int length(int offset) { return 1 + branchOffsetSize(); } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) { instructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, this); } public String toString(int offset) { return "["+offset+"] "+toString()+" (target="+(offset+branchOffset)+")"; } // Implementations for Object. public String toString() { return getName()+" "+(branchOffset >= 0 ? "+" : "")+branchOffset; } // Small utility methods. /** * Returns the branch offset size for this instruction. */ private int branchOffsetSize() { return opcode == InstructionConstants.OP_GOTO_W || opcode == InstructionConstants.OP_JSR_W ? 4 : 2; } /** * Computes the required branch offset size for this instruction's branch * offset. */ private int requiredBranchOffsetSize() { return branchOffset << 16 >> 16 == branchOffset ? 2 : 4; } } proguard4.8/src/proguard/classfile/instruction/InstructionConstants.java0000644000175000017500000003754311736333523025624 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; /** * Representation of an instruction. * * @author Eric Lafortune */ public interface InstructionConstants { public static final byte OP_NOP = 0; public static final byte OP_ACONST_NULL = 1; public static final byte OP_ICONST_M1 = 2; public static final byte OP_ICONST_0 = 3; public static final byte OP_ICONST_1 = 4; public static final byte OP_ICONST_2 = 5; public static final byte OP_ICONST_3 = 6; public static final byte OP_ICONST_4 = 7; public static final byte OP_ICONST_5 = 8; public static final byte OP_LCONST_0 = 9; public static final byte OP_LCONST_1 = 10; public static final byte OP_FCONST_0 = 11; public static final byte OP_FCONST_1 = 12; public static final byte OP_FCONST_2 = 13; public static final byte OP_DCONST_0 = 14; public static final byte OP_DCONST_1 = 15; public static final byte OP_BIPUSH = 16; public static final byte OP_SIPUSH = 17; public static final byte OP_LDC = 18; public static final byte OP_LDC_W = 19; public static final byte OP_LDC2_W = 20; public static final byte OP_ILOAD = 21; public static final byte OP_LLOAD = 22; public static final byte OP_FLOAD = 23; public static final byte OP_DLOAD = 24; public static final byte OP_ALOAD = 25; public static final byte OP_ILOAD_0 = 26; public static final byte OP_ILOAD_1 = 27; public static final byte OP_ILOAD_2 = 28; public static final byte OP_ILOAD_3 = 29; public static final byte OP_LLOAD_0 = 30; public static final byte OP_LLOAD_1 = 31; public static final byte OP_LLOAD_2 = 32; public static final byte OP_LLOAD_3 = 33; public static final byte OP_FLOAD_0 = 34; public static final byte OP_FLOAD_1 = 35; public static final byte OP_FLOAD_2 = 36; public static final byte OP_FLOAD_3 = 37; public static final byte OP_DLOAD_0 = 38; public static final byte OP_DLOAD_1 = 39; public static final byte OP_DLOAD_2 = 40; public static final byte OP_DLOAD_3 = 41; public static final byte OP_ALOAD_0 = 42; public static final byte OP_ALOAD_1 = 43; public static final byte OP_ALOAD_2 = 44; public static final byte OP_ALOAD_3 = 45; public static final byte OP_IALOAD = 46; public static final byte OP_LALOAD = 47; public static final byte OP_FALOAD = 48; public static final byte OP_DALOAD = 49; public static final byte OP_AALOAD = 50; public static final byte OP_BALOAD = 51; public static final byte OP_CALOAD = 52; public static final byte OP_SALOAD = 53; public static final byte OP_ISTORE = 54; public static final byte OP_LSTORE = 55; public static final byte OP_FSTORE = 56; public static final byte OP_DSTORE = 57; public static final byte OP_ASTORE = 58; public static final byte OP_ISTORE_0 = 59; public static final byte OP_ISTORE_1 = 60; public static final byte OP_ISTORE_2 = 61; public static final byte OP_ISTORE_3 = 62; public static final byte OP_LSTORE_0 = 63; public static final byte OP_LSTORE_1 = 64; public static final byte OP_LSTORE_2 = 65; public static final byte OP_LSTORE_3 = 66; public static final byte OP_FSTORE_0 = 67; public static final byte OP_FSTORE_1 = 68; public static final byte OP_FSTORE_2 = 69; public static final byte OP_FSTORE_3 = 70; public static final byte OP_DSTORE_0 = 71; public static final byte OP_DSTORE_1 = 72; public static final byte OP_DSTORE_2 = 73; public static final byte OP_DSTORE_3 = 74; public static final byte OP_ASTORE_0 = 75; public static final byte OP_ASTORE_1 = 76; public static final byte OP_ASTORE_2 = 77; public static final byte OP_ASTORE_3 = 78; public static final byte OP_IASTORE = 79; public static final byte OP_LASTORE = 80; public static final byte OP_FASTORE = 81; public static final byte OP_DASTORE = 82; public static final byte OP_AASTORE = 83; public static final byte OP_BASTORE = 84; public static final byte OP_CASTORE = 85; public static final byte OP_SASTORE = 86; public static final byte OP_POP = 87; public static final byte OP_POP2 = 88; public static final byte OP_DUP = 89; public static final byte OP_DUP_X1 = 90; public static final byte OP_DUP_X2 = 91; public static final byte OP_DUP2 = 92; public static final byte OP_DUP2_X1 = 93; public static final byte OP_DUP2_X2 = 94; public static final byte OP_SWAP = 95; public static final byte OP_IADD = 96; public static final byte OP_LADD = 97; public static final byte OP_FADD = 98; public static final byte OP_DADD = 99; public static final byte OP_ISUB = 100; public static final byte OP_LSUB = 101; public static final byte OP_FSUB = 102; public static final byte OP_DSUB = 103; public static final byte OP_IMUL = 104; public static final byte OP_LMUL = 105; public static final byte OP_FMUL = 106; public static final byte OP_DMUL = 107; public static final byte OP_IDIV = 108; public static final byte OP_LDIV = 109; public static final byte OP_FDIV = 110; public static final byte OP_DDIV = 111; public static final byte OP_IREM = 112; public static final byte OP_LREM = 113; public static final byte OP_FREM = 114; public static final byte OP_DREM = 115; public static final byte OP_INEG = 116; public static final byte OP_LNEG = 117; public static final byte OP_FNEG = 118; public static final byte OP_DNEG = 119; public static final byte OP_ISHL = 120; public static final byte OP_LSHL = 121; public static final byte OP_ISHR = 122; public static final byte OP_LSHR = 123; public static final byte OP_IUSHR = 124; public static final byte OP_LUSHR = 125; public static final byte OP_IAND = 126; public static final byte OP_LAND = 127; public static final byte OP_IOR = -128; public static final byte OP_LOR = -127; public static final byte OP_IXOR = -126; public static final byte OP_LXOR = -125; public static final byte OP_IINC = -124; public static final byte OP_I2L = -123; public static final byte OP_I2F = -122; public static final byte OP_I2D = -121; public static final byte OP_L2I = -120; public static final byte OP_L2F = -119; public static final byte OP_L2D = -118; public static final byte OP_F2I = -117; public static final byte OP_F2L = -116; public static final byte OP_F2D = -115; public static final byte OP_D2I = -114; public static final byte OP_D2L = -113; public static final byte OP_D2F = -112; public static final byte OP_I2B = -111; public static final byte OP_I2C = -110; public static final byte OP_I2S = -109; public static final byte OP_LCMP = -108; public static final byte OP_FCMPL = -107; public static final byte OP_FCMPG = -106; public static final byte OP_DCMPL = -105; public static final byte OP_DCMPG = -104; public static final byte OP_IFEQ = -103; public static final byte OP_IFNE = -102; public static final byte OP_IFLT = -101; public static final byte OP_IFGE = -100; public static final byte OP_IFGT = -99; public static final byte OP_IFLE = -98; public static final byte OP_IFICMPEQ = -97; public static final byte OP_IFICMPNE = -96; public static final byte OP_IFICMPLT = -95; public static final byte OP_IFICMPGE = -94; public static final byte OP_IFICMPGT = -93; public static final byte OP_IFICMPLE = -92; public static final byte OP_IFACMPEQ = -91; public static final byte OP_IFACMPNE = -90; public static final byte OP_GOTO = -89; public static final byte OP_JSR = -88; public static final byte OP_RET = -87; public static final byte OP_TABLESWITCH = -86; public static final byte OP_LOOKUPSWITCH = -85; public static final byte OP_IRETURN = -84; public static final byte OP_LRETURN = -83; public static final byte OP_FRETURN = -82; public static final byte OP_DRETURN = -81; public static final byte OP_ARETURN = -80; public static final byte OP_RETURN = -79; public static final byte OP_GETSTATIC = -78; public static final byte OP_PUTSTATIC = -77; public static final byte OP_GETFIELD = -76; public static final byte OP_PUTFIELD = -75; public static final byte OP_INVOKEVIRTUAL = -74; public static final byte OP_INVOKESPECIAL = -73; public static final byte OP_INVOKESTATIC = -72; public static final byte OP_INVOKEINTERFACE = -71; public static final byte OP_INVOKEDYNAMIC = -70; public static final byte OP_NEW = -69; public static final byte OP_NEWARRAY = -68; public static final byte OP_ANEWARRAY = -67; public static final byte OP_ARRAYLENGTH = -66; public static final byte OP_ATHROW = -65; public static final byte OP_CHECKCAST = -64; public static final byte OP_INSTANCEOF = -63; public static final byte OP_MONITORENTER = -62; public static final byte OP_MONITOREXIT = -61; public static final byte OP_WIDE = -60; public static final byte OP_MULTIANEWARRAY = -59; public static final byte OP_IFNULL = -58; public static final byte OP_IFNONNULL = -57; public static final byte OP_GOTO_W = -56; public static final byte OP_JSR_W = -55; public static final String[] NAMES = { "nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", "iconst_2", "iconst_3", "iconst_4", "iconst_5", "lconst_0", "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", "lload", "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", "fload_1", "fload_2", "fload_3", "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", "laload", "faload", "daload", "aaload", "baload", "caload", "saload", "istore", "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1", "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1", "astore_2", "astore_3", "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2", "dup", "dup_x1", "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", "ldiv", "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", "iand", "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s", "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "ificmpeq", "ificmpne", "ificmplt", "ificmpge", "ificmpgt", "ificmple", "ifacmpeq", "ifacmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", "dreturn", "areturn", "return", "getstatic", "putstatic", "getfield", "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface", "invokedynamic", "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", "monitorexit", "wide", "multianewarray", "ifnull", "ifnonnull", "goto_w", "jsr_w", }; public static final byte ARRAY_T_BOOLEAN = 4; public static final byte ARRAY_T_CHAR = 5; public static final byte ARRAY_T_FLOAT = 6; public static final byte ARRAY_T_DOUBLE = 7; public static final byte ARRAY_T_BYTE = 8; public static final byte ARRAY_T_SHORT = 9; public static final byte ARRAY_T_INT = 10; public static final byte ARRAY_T_LONG = 11; } proguard4.8/src/proguard/classfile/instruction/InstructionUtil.java0000644000175000017500000000640511736333523024556 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; import proguard.classfile.ClassConstants; /** * Utility methods for converting between representations of names and * descriptions. * * @author Eric Lafortune */ public class InstructionUtil { /** * Returns the internal type corresponding to the given 'newarray' type. * @param arrayType InstructionConstants.ARRAY_T_BOOLEAN, * InstructionConstants.ARRAY_T_BYTE, * InstructionConstants.ARRAY_T_CHAR, * InstructionConstants.ARRAY_T_SHORT, * InstructionConstants.ARRAY_T_INT, * InstructionConstants.ARRAY_T_LONG, * InstructionConstants.ARRAY_T_FLOAT, or * InstructionConstants.ARRAY_T_DOUBLE. * @return ClassConstants.INTERNAL_TYPE_BOOLEAN, * ClassConstants.INTERNAL_TYPE_BYTE, * ClassConstants.INTERNAL_TYPE_CHAR, * ClassConstants.INTERNAL_TYPE_SHORT, * ClassConstants.INTERNAL_TYPE_INT, * ClassConstants.INTERNAL_TYPE_LONG, * ClassConstants.INTERNAL_TYPE_FLOAT, or * ClassConstants.INTERNAL_TYPE_DOUBLE. */ public static char internalTypeFromArrayType(byte arrayType) { switch (arrayType) { case InstructionConstants.ARRAY_T_BOOLEAN: return ClassConstants.INTERNAL_TYPE_BOOLEAN; case InstructionConstants.ARRAY_T_CHAR: return ClassConstants.INTERNAL_TYPE_CHAR; case InstructionConstants.ARRAY_T_FLOAT: return ClassConstants.INTERNAL_TYPE_FLOAT; case InstructionConstants.ARRAY_T_DOUBLE: return ClassConstants.INTERNAL_TYPE_DOUBLE; case InstructionConstants.ARRAY_T_BYTE: return ClassConstants.INTERNAL_TYPE_BYTE; case InstructionConstants.ARRAY_T_SHORT: return ClassConstants.INTERNAL_TYPE_SHORT; case InstructionConstants.ARRAY_T_INT: return ClassConstants.INTERNAL_TYPE_INT; case InstructionConstants.ARRAY_T_LONG: return ClassConstants.INTERNAL_TYPE_LONG; default: throw new IllegalArgumentException("Unknown array type ["+arrayType+"]"); } } } proguard4.8/src/proguard/classfile/instruction/VariableInstruction.java0000644000175000017500000003237611736333523025374 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.visitor.InstructionVisitor; /** * This Instruction represents an instruction that refers to a variable on the * local variable stack. * * @author Eric Lafortune */ public class VariableInstruction extends Instruction { public boolean wide; public int variableIndex; public int constant; /** * Creates an uninitialized VariableInstruction. */ public VariableInstruction() {} public VariableInstruction(boolean wide) { this.wide = wide; } public VariableInstruction(byte opcode) { this(opcode, embeddedVariable(opcode), 0); } public VariableInstruction(byte opcode, int variableIndex) { this(opcode, variableIndex, 0); } public VariableInstruction(byte opcode, int variableIndex, int constant) { this.opcode = opcode; this.variableIndex = variableIndex; this.constant = constant; this.wide = requiredVariableIndexSize() > 1 || requiredConstantSize() > 1; } /** * Copies the given instruction into this instruction. * @param variableInstruction the instruction to be copied. * @return this instruction. */ public VariableInstruction copy(VariableInstruction variableInstruction) { this.opcode = variableInstruction.opcode; this.variableIndex = variableInstruction.variableIndex; this.constant = variableInstruction.constant; this.wide = variableInstruction.wide; return this; } /** * Return the embedded variable of the given opcode, or 0 if the opcode * doesn't have one. */ private static int embeddedVariable(byte opcode) { switch (opcode) { case InstructionConstants.OP_ILOAD_1: case InstructionConstants.OP_LLOAD_1: case InstructionConstants.OP_FLOAD_1: case InstructionConstants.OP_DLOAD_1: case InstructionConstants.OP_ALOAD_1: case InstructionConstants.OP_ISTORE_1: case InstructionConstants.OP_LSTORE_1: case InstructionConstants.OP_FSTORE_1: case InstructionConstants.OP_DSTORE_1: case InstructionConstants.OP_ASTORE_1: return 1; case InstructionConstants.OP_ILOAD_2: case InstructionConstants.OP_LLOAD_2: case InstructionConstants.OP_FLOAD_2: case InstructionConstants.OP_DLOAD_2: case InstructionConstants.OP_ALOAD_2: case InstructionConstants.OP_ISTORE_2: case InstructionConstants.OP_LSTORE_2: case InstructionConstants.OP_FSTORE_2: case InstructionConstants.OP_DSTORE_2: case InstructionConstants.OP_ASTORE_2: return 2; case InstructionConstants.OP_ILOAD_3: case InstructionConstants.OP_LLOAD_3: case InstructionConstants.OP_FLOAD_3: case InstructionConstants.OP_DLOAD_3: case InstructionConstants.OP_ALOAD_3: case InstructionConstants.OP_ISTORE_3: case InstructionConstants.OP_LSTORE_3: case InstructionConstants.OP_FSTORE_3: case InstructionConstants.OP_DSTORE_3: case InstructionConstants.OP_ASTORE_3: return 3; default: return 0; } } /** * Returns whether this instruction stores the value of a variable. * The value is false for the ret instruction, but true for the iinc * instruction. */ public boolean isStore() { // A store instruction can be recognized as follows. Note that this // excludes the ret instruction, which has a negative opcode. return opcode >= InstructionConstants.OP_ISTORE || opcode == InstructionConstants.OP_IINC; } /** * Returns whether this instruction loads the value of a variable. * The value is true for the ret instruction and for the iinc * instruction. */ public boolean isLoad() { // A load instruction can be recognized as follows. Note that this // includes the ret instruction, which has a negative opcode. return opcode < InstructionConstants.OP_ISTORE; } // Implementations for Instruction. public byte canonicalOpcode() { // Remove the _0, _1, _2, _3 extension, if any. switch (opcode) { case InstructionConstants.OP_ILOAD_0: case InstructionConstants.OP_ILOAD_1: case InstructionConstants.OP_ILOAD_2: case InstructionConstants.OP_ILOAD_3: return InstructionConstants.OP_ILOAD; case InstructionConstants.OP_LLOAD_0: case InstructionConstants.OP_LLOAD_1: case InstructionConstants.OP_LLOAD_2: case InstructionConstants.OP_LLOAD_3: return InstructionConstants.OP_LLOAD; case InstructionConstants.OP_FLOAD_0: case InstructionConstants.OP_FLOAD_1: case InstructionConstants.OP_FLOAD_2: case InstructionConstants.OP_FLOAD_3: return InstructionConstants.OP_FLOAD; case InstructionConstants.OP_DLOAD_0: case InstructionConstants.OP_DLOAD_1: case InstructionConstants.OP_DLOAD_2: case InstructionConstants.OP_DLOAD_3: return InstructionConstants.OP_DLOAD; case InstructionConstants.OP_ALOAD_0: case InstructionConstants.OP_ALOAD_1: case InstructionConstants.OP_ALOAD_2: case InstructionConstants.OP_ALOAD_3: return InstructionConstants.OP_ALOAD; case InstructionConstants.OP_ISTORE_0: case InstructionConstants.OP_ISTORE_1: case InstructionConstants.OP_ISTORE_2: case InstructionConstants.OP_ISTORE_3: return InstructionConstants.OP_ISTORE; case InstructionConstants.OP_LSTORE_0: case InstructionConstants.OP_LSTORE_1: case InstructionConstants.OP_LSTORE_2: case InstructionConstants.OP_LSTORE_3: return InstructionConstants.OP_LSTORE; case InstructionConstants.OP_FSTORE_0: case InstructionConstants.OP_FSTORE_1: case InstructionConstants.OP_FSTORE_2: case InstructionConstants.OP_FSTORE_3: return InstructionConstants.OP_FSTORE; case InstructionConstants.OP_DSTORE_0: case InstructionConstants.OP_DSTORE_1: case InstructionConstants.OP_DSTORE_2: case InstructionConstants.OP_DSTORE_3: return InstructionConstants.OP_DSTORE; case InstructionConstants.OP_ASTORE_0: case InstructionConstants.OP_ASTORE_1: case InstructionConstants.OP_ASTORE_2: case InstructionConstants.OP_ASTORE_3: return InstructionConstants.OP_ASTORE; default: return opcode; } } public Instruction shrink() { opcode = canonicalOpcode(); // Is this instruction pointing to a variable with index from 0 to 3? if (variableIndex <= 3) { switch (opcode) { case InstructionConstants.OP_ILOAD: opcode = (byte)(InstructionConstants.OP_ILOAD_0 + variableIndex); break; case InstructionConstants.OP_LLOAD: opcode = (byte)(InstructionConstants.OP_LLOAD_0 + variableIndex); break; case InstructionConstants.OP_FLOAD: opcode = (byte)(InstructionConstants.OP_FLOAD_0 + variableIndex); break; case InstructionConstants.OP_DLOAD: opcode = (byte)(InstructionConstants.OP_DLOAD_0 + variableIndex); break; case InstructionConstants.OP_ALOAD: opcode = (byte)(InstructionConstants.OP_ALOAD_0 + variableIndex); break; case InstructionConstants.OP_ISTORE: opcode = (byte)(InstructionConstants.OP_ISTORE_0 + variableIndex); break; case InstructionConstants.OP_LSTORE: opcode = (byte)(InstructionConstants.OP_LSTORE_0 + variableIndex); break; case InstructionConstants.OP_FSTORE: opcode = (byte)(InstructionConstants.OP_FSTORE_0 + variableIndex); break; case InstructionConstants.OP_DSTORE: opcode = (byte)(InstructionConstants.OP_DSTORE_0 + variableIndex); break; case InstructionConstants.OP_ASTORE: opcode = (byte)(InstructionConstants.OP_ASTORE_0 + variableIndex); break; } } // Only make the instruction wide if necessary. wide = requiredVariableIndexSize() > 1 || requiredConstantSize() > 1; return this; } protected boolean isWide() { return wide; } protected void readInfo(byte[] code, int offset) { int variableIndexSize = variableIndexSize(); int constantSize = constantSize(); // Also initialize embedded variable indexes. if (variableIndexSize == 0) { // An embedded variable index can be decoded as follows. variableIndex = opcode < InstructionConstants.OP_ISTORE_0 ? (opcode - InstructionConstants.OP_ILOAD_0 ) & 3 : (opcode - InstructionConstants.OP_ISTORE_0) & 3; } else { variableIndex = readValue(code, offset, variableIndexSize); offset += variableIndexSize; } constant = readSignedValue(code, offset, constantSize); } protected void writeInfo(byte[] code, int offset) { int variableIndexSize = variableIndexSize(); int constantSize = constantSize(); if (requiredVariableIndexSize() > variableIndexSize) { throw new IllegalArgumentException("Instruction has invalid variable index size ("+this.toString(offset)+")"); } if (requiredConstantSize() > constantSize) { throw new IllegalArgumentException("Instruction has invalid constant size ("+this.toString(offset)+")"); } writeValue(code, offset, variableIndex, variableIndexSize); offset += variableIndexSize; writeSignedValue(code, offset, constant, constantSize); } public int length(int offset) { return (wide ? 2 : 1) + variableIndexSize() + constantSize(); } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) { instructionVisitor.visitVariableInstruction(clazz, method, codeAttribute, offset, this); } // Implementations for Object. public String toString() { return getName() + (wide ? "_w" : "") + " v"+variableIndex + (constantSize() > 0 ? ", "+constant : ""); } // Small utility methods. /** * Returns the variable index size for this instruction. */ private int variableIndexSize() { return (opcode >= InstructionConstants.OP_ILOAD_0 && opcode <= InstructionConstants.OP_ALOAD_3) || (opcode >= InstructionConstants.OP_ISTORE_0 && opcode <= InstructionConstants.OP_ASTORE_3) ? 0 : wide ? 2 : 1; } /** * Computes the required variable index size for this instruction's variable * index. */ private int requiredVariableIndexSize() { return (variableIndex & 0x3) == variableIndex ? 0 : (variableIndex & 0xff) == variableIndex ? 1 : (variableIndex & 0xffff) == variableIndex ? 2 : 4; } /** * Returns the constant size for this instruction. */ private int constantSize() { return opcode != InstructionConstants.OP_IINC ? 0 : wide ? 2 : 1; } /** * Computes the required constant size for this instruction's constant. */ private int requiredConstantSize() { return opcode != InstructionConstants.OP_IINC ? 0 : constant << 24 >> 24 == constant ? 1 : constant << 16 >> 16 == constant ? 2 : 4; } } proguard4.8/src/proguard/classfile/instruction/SimpleInstruction.java0000644000175000017500000001750011736333523025070 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.visitor.InstructionVisitor; /** * This Instruction represents a simple instruction without variable arguments * or constant pool references. * * @author Eric Lafortune */ public class SimpleInstruction extends Instruction { public int constant; /** * Creates an uninitialized SimpleInstruction. */ public SimpleInstruction() {} /** * Creates a new SimpleInstruction with the given opcode. */ public SimpleInstruction(byte opcode) { this(opcode, embeddedConstant(opcode)); } /** * Creates a new SimpleInstruction with the given opcode and constant. */ public SimpleInstruction(byte opcode, int constant) { this.opcode = opcode; this.constant = constant; } /** * Copies the given instruction into this instruction. * @param simpleInstruction the instruction to be copied. * @return this instruction. */ public SimpleInstruction copy(SimpleInstruction simpleInstruction) { this.opcode = simpleInstruction.opcode; this.constant = simpleInstruction.constant; return this; } /** * Return the embedded constant of the given opcode, or 0 if the opcode * doesn't have one. */ private static int embeddedConstant(byte opcode) { switch (opcode) { case InstructionConstants.OP_ICONST_M1: return -1; case InstructionConstants.OP_ICONST_1: case InstructionConstants.OP_LCONST_1: case InstructionConstants.OP_FCONST_1: case InstructionConstants.OP_DCONST_1: return 1; case InstructionConstants.OP_ICONST_2: case InstructionConstants.OP_FCONST_2: return 2; case InstructionConstants.OP_ICONST_3: return 3; case InstructionConstants.OP_ICONST_4: return 4; case InstructionConstants.OP_ICONST_5: return 5; default: return 0; } } // Implementations for Instruction. public byte canonicalOpcode() { // Replace any _1, _2, _3,... extension by _0. switch (opcode) { case InstructionConstants.OP_ICONST_M1: case InstructionConstants.OP_ICONST_0: case InstructionConstants.OP_ICONST_1: case InstructionConstants.OP_ICONST_2: case InstructionConstants.OP_ICONST_3: case InstructionConstants.OP_ICONST_4: case InstructionConstants.OP_ICONST_5: case InstructionConstants.OP_BIPUSH: case InstructionConstants.OP_SIPUSH: return InstructionConstants.OP_ICONST_0; case InstructionConstants.OP_LCONST_0: case InstructionConstants.OP_LCONST_1: return InstructionConstants.OP_LCONST_0; case InstructionConstants.OP_FCONST_0: case InstructionConstants.OP_FCONST_1: case InstructionConstants.OP_FCONST_2: return InstructionConstants.OP_FCONST_0; case InstructionConstants.OP_DCONST_0: case InstructionConstants.OP_DCONST_1: return InstructionConstants.OP_DCONST_0; default: return opcode; } } public Instruction shrink() { // Reconstruct the opcode of the shortest instruction, if there are // any alternatives. switch (opcode) { case InstructionConstants.OP_ICONST_M1: case InstructionConstants.OP_ICONST_0: case InstructionConstants.OP_ICONST_1: case InstructionConstants.OP_ICONST_2: case InstructionConstants.OP_ICONST_3: case InstructionConstants.OP_ICONST_4: case InstructionConstants.OP_ICONST_5: case InstructionConstants.OP_BIPUSH: case InstructionConstants.OP_SIPUSH: switch (requiredConstantSize()) { case 0: opcode = (byte)(InstructionConstants.OP_ICONST_0 + constant); break; case 1: opcode = InstructionConstants.OP_BIPUSH; break; case 2: opcode = InstructionConstants.OP_SIPUSH; break; } break; case InstructionConstants.OP_LCONST_0: case InstructionConstants.OP_LCONST_1: opcode = (byte)(InstructionConstants.OP_LCONST_0 + constant); break; case InstructionConstants.OP_FCONST_0: case InstructionConstants.OP_FCONST_1: case InstructionConstants.OP_FCONST_2: opcode = (byte)(InstructionConstants.OP_FCONST_0 + constant); break; case InstructionConstants.OP_DCONST_0: case InstructionConstants.OP_DCONST_1: opcode = (byte)(InstructionConstants.OP_DCONST_0 + constant); break; } return this; } protected void readInfo(byte[] code, int offset) { int constantSize = constantSize(); // Also initialize embedded constants that are different from 0. constant = constantSize == 0 ? embeddedConstant(opcode) : readSignedValue(code, offset, constantSize); } protected void writeInfo(byte[] code, int offset) { int constantSize = constantSize(); if (requiredConstantSize() > constantSize) { throw new IllegalArgumentException("Instruction has invalid constant size ("+this.toString(offset)+")"); } writeSignedValue(code, offset, constant, constantSize); } public int length(int offset) { return 1 + constantSize(); } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) { instructionVisitor.visitSimpleInstruction(clazz, method, codeAttribute, offset, this); } // Implementations for Object. public String toString() { return getName() + (constantSize() > 0 ? " "+constant : ""); } // Small utility methods. /** * Returns the constant size for this instruction. */ private int constantSize() { return opcode == InstructionConstants.OP_BIPUSH || opcode == InstructionConstants.OP_NEWARRAY ? 1 : opcode == InstructionConstants.OP_SIPUSH ? 2 : 0; } /** * Computes the required constant size for this instruction. */ private int requiredConstantSize() { return constant >= -1 && constant <= 5 ? 0 : constant << 24 >> 24 == constant ? 1 : constant << 16 >> 16 == constant ? 2 : 4; } } proguard4.8/src/proguard/classfile/instruction/ConstantInstruction.java0000644000175000017500000002374111752431530025427 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.instruction; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.ClassUtil; /** * This Instruction represents an instruction that refers to an entry in the * constant pool. * * @author Eric Lafortune */ public class ConstantInstruction extends Instruction implements ConstantVisitor { public int constantIndex; public int constant; // Fields acting as return parameters for the ConstantVisitor methods. private int parameterStackDelta; private int typeStackDelta; /** * Creates an uninitialized ConstantInstruction. */ public ConstantInstruction() {} /** * Creates a new ConstantInstruction with the given opcode and constant pool * index. */ public ConstantInstruction(byte opcode, int constantIndex) { this(opcode, constantIndex, 0); } /** * Creates a new ConstantInstruction with the given opcode, constant pool * index, and constant. */ public ConstantInstruction(byte opcode, int constantIndex, int constant) { this.opcode = opcode; this.constantIndex = constantIndex; this.constant = constant; } /** * Copies the given instruction into this instruction. * @param constantInstruction the instruction to be copied. * @return this instruction. */ public ConstantInstruction copy(ConstantInstruction constantInstruction) { this.opcode = constantInstruction.opcode; this.constantIndex = constantInstruction.constantIndex; this.constant = constantInstruction.constant; return this; } // Implementations for Instruction. public byte canonicalOpcode() { // Remove the _w extension, if any. return opcode == InstructionConstants.OP_LDC_W ? InstructionConstants.OP_LDC : opcode; } public Instruction shrink() { // Do we need a short index or a long index? if (requiredConstantIndexSize() == 1) { // Can we replace the long instruction by a short instruction? if (opcode == InstructionConstants.OP_LDC_W) { opcode = InstructionConstants.OP_LDC; } } else { // Should we replace the short instruction by a long instruction? if (opcode == InstructionConstants.OP_LDC) { opcode = InstructionConstants.OP_LDC_W; } } return this; } protected void readInfo(byte[] code, int offset) { int constantIndexSize = constantIndexSize(); int constantSize = constantSize(); constantIndex = readValue(code, offset, constantIndexSize); offset += constantIndexSize; constant = readValue(code, offset, constantSize); } protected void writeInfo(byte[] code, int offset) { int constantIndexSize = constantIndexSize(); int constantSize = constantSize(); if (requiredConstantIndexSize() > constantIndexSize) { throw new IllegalArgumentException("Instruction has invalid constant index size ("+this.toString(offset)+")"); } writeValue(code, offset, constantIndex, constantIndexSize); offset += constantIndexSize; writeValue(code, offset, constant, constantSize); } public int length(int offset) { return 1 + constantIndexSize() + constantSize(); } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) { instructionVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, this); } public int stackPopCount(Clazz clazz) { int stackPopCount = super.stackPopCount(clazz); // Some special cases. switch (opcode) { case InstructionConstants.OP_MULTIANEWARRAY: // For each dimension, an integer size is popped from the stack. stackPopCount += constant; break; case InstructionConstants.OP_PUTSTATIC: case InstructionConstants.OP_PUTFIELD: // The field value is be popped from the stack. clazz.constantPoolEntryAccept(constantIndex, this); stackPopCount += typeStackDelta; break; case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: case InstructionConstants.OP_INVOKEDYNAMIC: // Some parameters may be popped from the stack. clazz.constantPoolEntryAccept(constantIndex, this); stackPopCount += parameterStackDelta; break; } return stackPopCount; } public int stackPushCount(Clazz clazz) { int stackPushCount = super.stackPushCount(clazz); // Some special cases. switch (opcode) { case InstructionConstants.OP_GETSTATIC: case InstructionConstants.OP_GETFIELD: case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: case InstructionConstants.OP_INVOKEDYNAMIC: // The field value or a return value may be pushed onto the stack. clazz.constantPoolEntryAccept(constantIndex, this); stackPushCount += typeStackDelta; break; } return stackPushCount; } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) {} public void visitLongConstant(Clazz clazz, LongConstant longConstant) {} public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) {} public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) {} public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) {} public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) {} public void visitClassConstant(Clazz clazz, ClassConstant classConstant) {} public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) {} public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { String type = fieldrefConstant.getType(clazz); typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type)); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this); } public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) { clazz.constantPoolEntryAccept(interfaceMethodrefConstant.u2nameAndTypeIndex, this); } public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { clazz.constantPoolEntryAccept(methodrefConstant.u2nameAndTypeIndex, this); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { String type = nameAndTypeConstant.getType(clazz); parameterStackDelta = ClassUtil.internalMethodParameterSize(type); typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type)); } // Implementations for Object. public String toString() { return getName()+" #"+constantIndex+(constantSize() == 0 ? "" : ", "+constant); } // Small utility methods. /** * Returns the constant pool index size for this instruction. */ private int constantIndexSize() { return opcode == InstructionConstants.OP_LDC ? 1 : 2; } /** * Returns the constant size for this instruction. */ private int constantSize() { return opcode == InstructionConstants.OP_MULTIANEWARRAY ? 1 : opcode == InstructionConstants.OP_INVOKEDYNAMIC || opcode == InstructionConstants.OP_INVOKEINTERFACE ? 2 : 0; } /** * Computes the required constant pool index size for this instruction's * constant pool index. */ private int requiredConstantIndexSize() { return (constantIndex & 0xff) == constantIndex ? 1 : (constantIndex & 0xffff) == constantIndex ? 2 : 4; } } proguard4.8/src/proguard/classfile/ProgramField.java0000644000175000017500000000550311736333523021367 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.attribute.Attribute; import proguard.classfile.visitor.*; /** * Representation of a field from a program class. * * @author Eric Lafortune */ public class ProgramField extends ProgramMember implements Field { /** * An extra field pointing to the Clazz object referenced in the * descriptor string. This field is filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz referencedClass; /** * Creates an uninitialized ProgramField. */ public ProgramField() { } /** * Creates an initialized ProgramField. */ public ProgramField(int u2accessFlags, int u2nameIndex, int u2descriptorIndex, int u2attributesCount, Attribute[] attributes, Clazz referencedClass) { super(u2accessFlags, u2nameIndex, u2descriptorIndex, u2attributesCount, attributes); this.referencedClass = referencedClass; } // Implementations for ProgramMember. public void accept(ProgramClass programClass, MemberVisitor memberVisitor) { memberVisitor.visitProgramField(programClass, this); } public void attributesAccept(ProgramClass programClass, AttributeVisitor attributeVisitor) { for (int index = 0; index < u2attributesCount; index++) { attributes[index].accept(programClass, this, attributeVisitor); } } // Implementations for Member. public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClass != null) { referencedClass.accept(classVisitor); } } } proguard4.8/src/proguard/classfile/attribute/0000775000175000017500000000000011760503005020142 5ustar ericericproguard4.8/src/proguard/classfile/attribute/package.html0000644000175000017500000000013511736333523022431 0ustar ericeric This package contains classes to represent the attributes inside class files. proguard4.8/src/proguard/classfile/attribute/ConstantValueAttribute.java0000644000175000017500000000350011736333523025464 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a constant value attribute. * * @author Eric Lafortune */ public class ConstantValueAttribute extends Attribute { public int u2constantValueIndex; /** * Creates an uninitialized ConstantValueAttribute. */ public ConstantValueAttribute() { } /** * Creates an initialized ConstantValueAttribute. */ public ConstantValueAttribute(int u2attributeNameIndex, int u2constantValueIndex) { super(u2attributeNameIndex); this.u2constantValueIndex = u2constantValueIndex; } // Implementations for Attribute. public void accept(Clazz clazz, Field field, AttributeVisitor attributeVisitor) { attributeVisitor.visitConstantValueAttribute(clazz, field, this); } } proguard4.8/src/proguard/classfile/attribute/SyntheticAttribute.java0000644000175000017500000000367611736333523024666 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a synthetic attribute. * * @author Eric Lafortune */ public class SyntheticAttribute extends Attribute { /** * Creates an uninitialized SyntheticAttribute. */ public SyntheticAttribute() { } /** * Creates an initialized SyntheticAttribute. */ public SyntheticAttribute(int u2attributeNameIndex) { super(u2attributeNameIndex); } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitSyntheticAttribute(clazz, this); } public void accept(Clazz clazz, Field field, AttributeVisitor attributeVisitor) { attributeVisitor.visitSyntheticAttribute(clazz, field, this); } public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitSyntheticAttribute(clazz, method, this); } } proguard4.8/src/proguard/classfile/attribute/BootstrapMethodsAttribute.java0000755000175000017500000000636311736333523026214 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Attribute represents a bootstrap methods attribute. * * @author Eric Lafortune */ public class BootstrapMethodsAttribute extends Attribute { public int u2bootstrapMethodsCount; public BootstrapMethodInfo[] bootstrapMethods; /** * Creates an uninitialized BootstrapMethodsAttribute. */ public BootstrapMethodsAttribute() { } /** * Creates an initialized BootstrapMethodsAttribute. */ public BootstrapMethodsAttribute(int u2attributeNameIndex, int u2bootstrapMethodsCount, BootstrapMethodInfo[] bootstrapMethods) { super(u2attributeNameIndex); this.u2bootstrapMethodsCount = u2bootstrapMethodsCount; this.bootstrapMethods = bootstrapMethods; } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitBootstrapMethodsAttribute(clazz, this); } /** * Applies the given constant pool visitor to all bootstrap method info * entries. */ public void bootstrapMethodEntriesAccept(Clazz clazz, BootstrapMethodInfoVisitor bootstrapMethodInfoVisitor) { for (int index = 0; index < u2bootstrapMethodsCount; index++) { // We don't need double dispatching here, since there is only one // type of BootstrapMethodInfo. bootstrapMethodInfoVisitor.visitBootstrapMethodInfo(clazz, bootstrapMethods[index]); } } /** * Applies the given constant pool visitor to the specified bootstrap method * info entry. */ public void bootstrapMethodEntryAccept(Clazz clazz, int bootstrapMethodIndex, BootstrapMethodInfoVisitor bootstrapMethodInfoVisitor) { // We don't need double dispatching here, since there is only one // type of BootstrapMethodInfo. bootstrapMethodInfoVisitor.visitBootstrapMethodInfo(clazz, bootstrapMethods[bootstrapMethodIndex]); } } proguard4.8/src/proguard/classfile/attribute/DeprecatedAttribute.java0000644000175000017500000000370711736333523024747 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a deprecated attribute. * * @author Eric Lafortune */ public class DeprecatedAttribute extends Attribute { /** * Creates an uninitialized DeprecatedAttribute. */ public DeprecatedAttribute() { } /** * Creates an initialized DeprecatedAttribute. */ public DeprecatedAttribute(int u2attributeNameIndex) { super(u2attributeNameIndex); } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitDeprecatedAttribute(clazz, this); } public void accept(Clazz clazz, Field field, AttributeVisitor attributeVisitor) { attributeVisitor.visitDeprecatedAttribute(clazz, field, this); } public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitDeprecatedAttribute(clazz, method, this); } } proguard4.8/src/proguard/classfile/attribute/UnknownAttribute.java0000644000175000017500000000466511736333523024352 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents an unknown attribute. * * @author Eric Lafortune */ public class UnknownAttribute extends Attribute { public final int u4attributeLength; public byte[] info; /** * Creates an uninitialized UnknownAttribute with the given length. */ public UnknownAttribute(int attributeLength) { u4attributeLength = attributeLength; } /** * Creates an initialized UnknownAttribute. */ public UnknownAttribute(int u2attributeNameIndex, int u4attributeLength, byte[] info) { super(u2attributeNameIndex); this.u4attributeLength = u4attributeLength; this.info = info; } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitUnknownAttribute(clazz, this); } public void accept(Clazz clazz, Field field, AttributeVisitor attributeVisitor) { attributeVisitor.visitUnknownAttribute(clazz, this); } public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitUnknownAttribute(clazz, this); } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor) { attributeVisitor.visitUnknownAttribute(clazz, this); } } proguard4.8/src/proguard/classfile/attribute/InnerClassesAttribute.java0000644000175000017500000000462211736333523025275 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.Clazz; import proguard.classfile.attribute.visitor.*; /** * This Attribute represents an inner classes attribute. * * @author Eric Lafortune */ public class InnerClassesAttribute extends Attribute { public int u2classesCount; public InnerClassesInfo[] classes; /** * Creates an uninitialized InnerClassesAttribute. */ public InnerClassesAttribute() { } /** * Creates an initialized InnerClassesAttribute. */ public InnerClassesAttribute(int u2attributeNameIndex, int u2classesCount, InnerClassesInfo[] classes) { super(u2attributeNameIndex); this.u2classesCount = u2classesCount; this.classes = classes; } // // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitInnerClassesAttribute(clazz, this); } /** * Applies the given visitor to all inner classes. */ public void innerClassEntriesAccept(Clazz clazz, InnerClassesInfoVisitor innerClassesInfoVisitor) { for (int index = 0; index < u2classesCount; index++) { // We don't need double dispatching here, since there is only one // type of InnerClassesInfo. innerClassesInfoVisitor.visitInnerClassesInfo(clazz, classes[index]); } } } proguard4.8/src/proguard/classfile/attribute/Attribute.java0000644000175000017500000001013511736333523022757 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This abstract class represents an attribute that is attached to a class, * a class member, or a code attribute. Specific types of attributes are * subclassed from it. * * @author Eric Lafortune * @noinspection AbstractClassWithoutAbstractMethods */ public abstract class Attribute implements VisitorAccepter { public int u2attributeNameIndex; //public int u4attributeLength; //public byte info[]; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Create an uninitialized Attribute. */ protected Attribute() { } /** * Create an initialized Attribute. */ protected Attribute(int u2attributeNameIndex) { this.u2attributeNameIndex = u2attributeNameIndex; } /** * Returns the String name of the attribute. */ public String getAttributeName(Clazz clazz) { return clazz.getString(u2attributeNameIndex); } // Methods to be implemented by extensions, if applicable. /** * Accepts the given visitor. */ public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } /** * Accepts the given visitor in the context of the given field. */ public void accept(Clazz clazz, Field field, AttributeVisitor attributeVisitor) { // Delegate the default invocation if the field is null anyway. if (field == null) { accept(clazz, attributeVisitor); } else { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } } /** * Accepts the given visitor in the context of the given method. */ public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { // Delegate the default invocation if the method is null anyway. if (method == null) { accept(clazz, (Field)null, attributeVisitor); } else { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } } /** * Accepts the given visitor in the context of the given code attribute. */ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor) { // Delegate the default invocation if the code attribute is null anyway. if (codeAttribute == null) { accept(clazz, method, attributeVisitor); } else { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } proguard4.8/src/proguard/classfile/attribute/LocalVariableTableAttribute.java0000644000175000017500000000530011736333523026346 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; /** * This Attribute represents a local variable table attribute. * * @author Eric Lafortune */ public class LocalVariableTableAttribute extends Attribute { public int u2localVariableTableLength; public LocalVariableInfo[] localVariableTable; /** * Creates an uninitialized LocalVariableTableAttribute. */ public LocalVariableTableAttribute() { } /** * Creates an initialized LocalVariableTableAttribute. */ public LocalVariableTableAttribute(int u2attributeNameIndex, int u2localVariableTableLength, LocalVariableInfo[] localVariableTable) { super(u2attributeNameIndex); this.u2localVariableTableLength = u2localVariableTableLength; this.localVariableTable = localVariableTable; } // Implementations for Attribute. public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor) { attributeVisitor.visitLocalVariableTableAttribute(clazz, method, codeAttribute, this); } /** * Applies the given visitor to all local variables. */ public void localVariablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfoVisitor localVariableInfoVisitor) { for (int index = 0; index < u2localVariableTableLength; index++) { // We don't need double dispatching here, since there is only one // type of LocalVariableInfo. localVariableInfoVisitor.visitLocalVariableInfo(clazz, method, codeAttribute, localVariableTable[index]); } } } proguard4.8/src/proguard/classfile/attribute/BootstrapMethodInfo.java0000755000175000017500000000505111736333523024752 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * Representation of a bootstrap method. * * @author Eric Lafortune */ public class BootstrapMethodInfo implements VisitorAccepter { public int u2methodHandleIndex; public int u2methodArgumentCount; public int[] u2methodArguments; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Creates an uninitialized BootstrapMethodInfo. */ public BootstrapMethodInfo() { } /** * Creates an initialized BootstrapMethodInfo. */ public BootstrapMethodInfo(int u2methodHandleIndex, int u2methodArgumentCount, int[] u2methodArguments) { this.u2methodHandleIndex = u2methodHandleIndex; this.u2methodArgumentCount = u2methodArgumentCount; this.u2methodArguments = u2methodArguments; } /** * Applies the given constant pool visitor to the argument constants of the * bootstrap method. */ public void methodArgumentsAccept(Clazz clazz, ConstantVisitor constantVisitor) { for (int index = 0; index < u2methodArgumentCount; index++) { clazz.constantPoolEntryAccept(u2methodArguments[index], constantVisitor); } } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } proguard4.8/src/proguard/classfile/attribute/LocalVariableInfo.java0000664000175000017500000000654211736333523024341 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.Clazz; import proguard.classfile.visitor.ClassVisitor; /** * Representation of an Local Variable table entry. * * @author Eric Lafortune */ public class LocalVariableInfo implements Comparable { public int u2startPC; public int u2length; public int u2nameIndex; public int u2descriptorIndex; public int u2index; /** * An extra field pointing to the referenced Clazz object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}. */ public Clazz referencedClass; /** * Creates an uninitialized LocalVariableInfo. */ public LocalVariableInfo() { } /** * Creates an initialized LocalVariableInfo. */ public LocalVariableInfo(int u2startPC, int u2length, int u2nameIndex, int u2descriptorIndex, int u2index) { this.u2startPC = u2startPC; this.u2length = u2length; this.u2nameIndex = u2nameIndex; this.u2descriptorIndex = u2descriptorIndex; this.u2index = u2index; } /** * Lets the referenced class accept the given visitor. */ public void referencedClassAccept(ClassVisitor classVisitor) { if (referencedClass != null) { referencedClass.accept(classVisitor); } } // Implementations for Comparable. public int compareTo(Object object) { LocalVariableInfo other = (LocalVariableInfo)object; return this.u2startPC < other.u2startPC ? -1 : this.u2startPC > other.u2startPC ? 1 : this.u2index < other.u2index ? -1 : this.u2index > other.u2index ? 1 : this.u2length < other.u2length ? -1 : this.u2length > other.u2length ? 1 : this.u2descriptorIndex < other.u2descriptorIndex ? -1 : this.u2descriptorIndex > other.u2descriptorIndex ? 1 : this.u2nameIndex < other.u2nameIndex ? -1 : this.u2nameIndex > other.u2nameIndex ? 1 : 0; } } proguard4.8/src/proguard/classfile/attribute/InnerClassesInfo.java0000644000175000017500000000607111736333523024225 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * Representation of an Inner Classes table entry. * * @author Eric Lafortune */ public class InnerClassesInfo implements VisitorAccepter { public int u2innerClassIndex; public int u2outerClassIndex; public int u2innerNameIndex; public int u2innerClassAccessFlags; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Returns the inner class index. */ protected int getInnerClassIndex() { return u2innerClassIndex; } /** * Returns the name index. */ protected int getInnerNameIndex() { return u2innerNameIndex; } /** * Sets the name index. */ protected void setInnerNameIndex(int index) { u2innerNameIndex = index; } /** * Applies the given constant pool visitor to the class constant of the * inner class, if any. */ public void innerClassConstantAccept(Clazz clazz, ConstantVisitor constantVisitor) { if (u2innerClassIndex != 0) { clazz.constantPoolEntryAccept(u2innerClassIndex, constantVisitor); } } /** * Applies the given constant pool visitor to the class constant of the * outer class, if any. */ public void outerClassConstantAccept(Clazz clazz, ConstantVisitor constantVisitor) { if (u2outerClassIndex != 0) { clazz.constantPoolEntryAccept(u2outerClassIndex, constantVisitor); } } /** * Applies the given constant pool visitor to the Utf8 constant of the * inner name, if any. */ public void innerNameConstantAccept(Clazz clazz, ConstantVisitor constantVisitor) { if (u2innerNameIndex != 0) { clazz.constantPoolEntryAccept(u2innerNameIndex, constantVisitor); } } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } proguard4.8/src/proguard/classfile/attribute/visitor/0000775000175000017500000000000011760503005021641 5ustar ericericproguard4.8/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java0000644000175000017500000000267511736333523026761 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; /** * This interface specifies the methods for a visitor of * LineNumberInfo objects. Note that there is only a single * implementation of LineNumberInfo, such that this interface * is not strictly necessary as a visitor. * * @author Eric Lafortune */ public interface LineNumberInfoVisitor { public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo); } proguard4.8/src/proguard/classfile/attribute/visitor/package.html0000644000175000017500000000012311736333523024125 0ustar ericeric This package contains visitors for attributes and their components. proguard4.8/src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java0000644000175000017500000000356411736333523027741 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor lets a given InnerClassesInfoVisitor visit all * InnerClassessInfo objects of the InnerClassesAttribute objects it visits. * * @author Eric Lafortune */ public class AllInnerClassesInfoVisitor extends SimplifiedVisitor implements AttributeVisitor { private final InnerClassesInfoVisitor innerClassesInfoVisitor; public AllInnerClassesInfoVisitor(InnerClassesInfoVisitor innerClassesInfoVisitor) { this.innerClassesInfoVisitor = innerClassesInfoVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { innerClassesAttribute.innerClassEntriesAccept(clazz, innerClassesInfoVisitor); } }proguard4.8/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java0000644000175000017500000000271711736333523027416 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; /** * This interface specifies the methods for a visitor of * LocalVariableInfo objects. Note that there is only a single * implementation of LocalVariableInfo, such that this interface * is not strictly necessary as a visitor. * * @author Eric Lafortune */ public interface LocalVariableInfoVisitor { public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo); } proguard4.8/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java0000644000175000017500000003164411736333523027061 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; /** * This AttributeVisitor delegates all visits to each AttributeVisitor * in a given list. * * @author Eric Lafortune */ public class MultiAttributeVisitor implements AttributeVisitor { private AttributeVisitor[] attributeVisitors; public MultiAttributeVisitor() { } public MultiAttributeVisitor(AttributeVisitor[] attributeVisitors) { this.attributeVisitors = attributeVisitors; } public void addAttributeVisitor(AttributeVisitor attributeVisitor) { incrementArraySize(); attributeVisitors[attributeVisitors.length - 1] = attributeVisitor; } private void incrementArraySize() { if (attributeVisitors == null) { attributeVisitors = new AttributeVisitor[1]; } else { AttributeVisitor[] newAttributeVisitors = new AttributeVisitor[attributeVisitors.length + 1]; System.arraycopy(attributeVisitors, 0, newAttributeVisitors, 0, attributeVisitors.length); attributeVisitors = newAttributeVisitors; } } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitUnknownAttribute(clazz, unknownAttribute); } } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitBootstrapMethodsAttribute(clazz, bootstrapMethodsAttribute); } } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitSourceFileAttribute(clazz, sourceFileAttribute); } } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitSourceDirAttribute(clazz, sourceDirAttribute); } } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitInnerClassesAttribute(clazz, innerClassesAttribute); } } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitEnclosingMethodAttribute(clazz, enclosingMethodAttribute); } } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitDeprecatedAttribute(clazz, deprecatedAttribute); } } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitSyntheticAttribute(clazz, syntheticAttribute); } } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute syntheticAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitSignatureAttribute(clazz, syntheticAttribute); } } public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitDeprecatedAttribute(clazz, field, deprecatedAttribute); } } public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitSyntheticAttribute(clazz, field, syntheticAttribute); } } public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute syntheticAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitSignatureAttribute(clazz, field, syntheticAttribute); } } public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitDeprecatedAttribute(clazz, method, deprecatedAttribute); } } public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitSyntheticAttribute(clazz, method, syntheticAttribute); } } public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute syntheticAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitSignatureAttribute(clazz, method, syntheticAttribute); } } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitConstantValueAttribute(clazz, field, constantValueAttribute); } } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitExceptionsAttribute(clazz, method, exceptionsAttribute); } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitCodeAttribute(clazz, method, codeAttribute); } } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitStackMapAttribute(clazz, method, codeAttribute, stackMapAttribute); } } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitStackMapTableAttribute(clazz, method, codeAttribute, stackMapTableAttribute); } } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitLineNumberTableAttribute(clazz, method, codeAttribute, lineNumberTableAttribute); } } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitLocalVariableTableAttribute(clazz, method, codeAttribute, localVariableTableAttribute); } } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitLocalVariableTypeTableAttribute(clazz, method, codeAttribute, localVariableTypeTableAttribute); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitRuntimeVisibleAnnotationsAttribute(clazz, runtimeVisibleAnnotationsAttribute); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitRuntimeInvisibleAnnotationsAttribute(clazz, runtimeInvisibleAnnotationsAttribute); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitRuntimeVisibleAnnotationsAttribute(clazz, field, runtimeVisibleAnnotationsAttribute); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitRuntimeInvisibleAnnotationsAttribute(clazz, field, runtimeInvisibleAnnotationsAttribute); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitRuntimeVisibleAnnotationsAttribute(clazz, method, runtimeVisibleAnnotationsAttribute); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitRuntimeInvisibleAnnotationsAttribute(clazz, method, runtimeInvisibleAnnotationsAttribute); } } public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitRuntimeVisibleParameterAnnotationsAttribute(clazz, method, runtimeVisibleParameterAnnotationsAttribute); } } public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitRuntimeInvisibleParameterAnnotationsAttribute(clazz, method, runtimeInvisibleParameterAnnotationsAttribute); } } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { for (int index = 0; index < attributeVisitors.length; index++) { attributeVisitors[index].visitAnnotationDefaultAttribute(clazz, method, annotationDefaultAttribute); } } } proguard4.8/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java0000755000175000017500000000272411736333523030035 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import java.beans.MethodDescriptor; /** * This interface specifies the methods for a visitor of * BootstrapMethodInfo objects. Note that there is only a single * implementation of BootstrapMethodInfo, such that this interface * is not strictly necessary as a visitor. * * @author Eric Lafortune */ public interface BootstrapMethodInfoVisitor { public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo); } proguard4.8/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java0000644000175000017500000000274711736333523030263 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; /** * This interface specifies the methods for a visitor of * LocalVariableTypeInfo objects. Note that there is only a single * implementation of LocalVariableTypeInfo, such that this interface * is not strictly necessary as a visitor. * * @author Eric Lafortune */ public interface LocalVariableTypeInfoVisitor { public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo); } proguard4.8/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java0000644000175000017500000002735611736333523027342 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.obfuscate.AttributeShrinker; /** * This AttributeVisitor delegates its visits to one of two other * AttributeVisitor instances, depending on whether the visited attribute * is strictly required or not. * * @see AttributeShrinker * * @author Eric Lafortune */ public class RequiredAttributeFilter implements AttributeVisitor { private final AttributeVisitor requiredAttributeVisitor; private final AttributeVisitor optionalAttributeVisitor; /** * Creates a new RequiredAttributeFilter for visiting required attributes. * @param requiredAttributeVisitor the visitor that will visit required * attributes. */ public RequiredAttributeFilter(AttributeVisitor requiredAttributeVisitor) { this(requiredAttributeVisitor, null); } /** * Creates a new RequiredAttributeFilter for visiting required and * optional attributes. * @param requiredAttributeVisitor the visitor that will visit required * attributes. * @param optionalAttributeVisitor the visitor that will visit optional * attributes. */ public RequiredAttributeFilter(AttributeVisitor requiredAttributeVisitor, AttributeVisitor optionalAttributeVisitor) { this.requiredAttributeVisitor = requiredAttributeVisitor; this.optionalAttributeVisitor = optionalAttributeVisitor; } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { if (optionalAttributeVisitor != null) { unknownAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { if (requiredAttributeVisitor != null) { bootstrapMethodsAttribute.accept(clazz, requiredAttributeVisitor); } } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { if (optionalAttributeVisitor != null) { sourceFileAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { if (optionalAttributeVisitor != null) { sourceDirAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { if (optionalAttributeVisitor != null) { innerClassesAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { if (optionalAttributeVisitor != null) { enclosingMethodAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { if (optionalAttributeVisitor != null) { deprecatedAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute) { if (optionalAttributeVisitor != null) { deprecatedAttribute.accept(clazz, field, optionalAttributeVisitor); } } public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute) { if (optionalAttributeVisitor != null) { deprecatedAttribute.accept(clazz, method, optionalAttributeVisitor); } } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { if (optionalAttributeVisitor != null) { syntheticAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute) { if (optionalAttributeVisitor != null) { syntheticAttribute.accept(clazz, field, optionalAttributeVisitor); } } public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute) { if (optionalAttributeVisitor != null) { syntheticAttribute.accept(clazz, method, optionalAttributeVisitor); } } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { if (optionalAttributeVisitor != null) { signatureAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute signatureAttribute) { if (optionalAttributeVisitor != null) { signatureAttribute.accept(clazz, field, optionalAttributeVisitor); } } public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute) { if (optionalAttributeVisitor != null) { signatureAttribute.accept(clazz, method, optionalAttributeVisitor); } } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { if (requiredAttributeVisitor != null) { constantValueAttribute.accept(clazz, field, requiredAttributeVisitor); } } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { if (optionalAttributeVisitor != null) { exceptionsAttribute.accept(clazz, method, optionalAttributeVisitor); } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (requiredAttributeVisitor != null) { codeAttribute.accept(clazz, method, requiredAttributeVisitor); } } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { if (optionalAttributeVisitor != null) { stackMapAttribute.accept(clazz, method, codeAttribute, optionalAttributeVisitor); } } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { if (requiredAttributeVisitor != null) { stackMapTableAttribute.accept(clazz, method, codeAttribute, requiredAttributeVisitor); } } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { if (optionalAttributeVisitor != null) { lineNumberTableAttribute.accept(clazz, method, codeAttribute, optionalAttributeVisitor); } } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { if (optionalAttributeVisitor != null) { localVariableTableAttribute.accept(clazz, method, codeAttribute, optionalAttributeVisitor); } } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { if (optionalAttributeVisitor != null) { localVariableTypeTableAttribute.accept(clazz, method, codeAttribute, optionalAttributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (optionalAttributeVisitor != null) { runtimeVisibleAnnotationsAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (optionalAttributeVisitor != null) { runtimeVisibleAnnotationsAttribute.accept(clazz, field, optionalAttributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (optionalAttributeVisitor != null) { runtimeVisibleAnnotationsAttribute.accept(clazz, method, optionalAttributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (optionalAttributeVisitor != null) { runtimeInvisibleAnnotationsAttribute.accept(clazz, optionalAttributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (optionalAttributeVisitor != null) { runtimeInvisibleAnnotationsAttribute.accept(clazz, field, optionalAttributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (optionalAttributeVisitor != null) { runtimeInvisibleAnnotationsAttribute.accept(clazz, method, optionalAttributeVisitor); } } public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute) { if (optionalAttributeVisitor != null) { runtimeVisibleParameterAnnotationsAttribute.accept(clazz, method, optionalAttributeVisitor); } } public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute) { if (optionalAttributeVisitor != null) { runtimeInvisibleParameterAnnotationsAttribute.accept(clazz, method, optionalAttributeVisitor); } } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { if (optionalAttributeVisitor != null) { annotationDefaultAttribute.accept(clazz, method, optionalAttributeVisitor); } } } proguard4.8/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java0000664000175000017500000003124211740563614026432 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.util.*; import java.util.List; /** * This AttributeVisitor delegates its visits another AttributeVisitor, but * only when the visited attribute has a name that that matches a given regular * expression. * * @author Eric Lafortune */ public class AttributeNameFilter implements AttributeVisitor { private final StringMatcher regularExpressionMatcher; private final AttributeVisitor attributeVisitor; /** * Creates a new AttributeNameFilter. * @param regularExpression the regular expression against which attribute * names will be matched. * @param attributeVisitor the AttributeVisitor to which * visits will be delegated. */ public AttributeNameFilter(String regularExpression, AttributeVisitor attributeVisitor) { this(new ListParser(new NameParser()).parse(regularExpression), attributeVisitor); } /** * Creates a new AttributeNameFilter. * @param regularExpression the regular expression against which attribute * names will be matched. * @param attributeVisitor the AttributeVisitor to which * visits will be delegated. */ public AttributeNameFilter(List regularExpression, AttributeVisitor attributeVisitor) { this(new ListParser(new NameParser()).parse(regularExpression), attributeVisitor); } /** * Creates a new AttributeNameFilter. * @param regularExpressionMatcher the string matcher against which * attribute names will be matched. * @param attributeVisitor the AttributeVisitor to * which visits will be delegated. */ public AttributeNameFilter(StringMatcher regularExpressionMatcher, AttributeVisitor attributeVisitor) { this.regularExpressionMatcher = regularExpressionMatcher; this.attributeVisitor = attributeVisitor; } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { if (accepted(clazz, unknownAttribute)) { unknownAttribute.accept(clazz, attributeVisitor); } } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { if (accepted(clazz, bootstrapMethodsAttribute)) { bootstrapMethodsAttribute.accept(clazz, attributeVisitor); } } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { if (accepted(clazz, sourceFileAttribute)) { sourceFileAttribute.accept(clazz, attributeVisitor); } } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { if (accepted(clazz, sourceDirAttribute)) { sourceDirAttribute.accept(clazz, attributeVisitor); } } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { if (accepted(clazz, innerClassesAttribute)) { innerClassesAttribute.accept(clazz, attributeVisitor); } } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { if (accepted(clazz, enclosingMethodAttribute)) { enclosingMethodAttribute.accept(clazz, attributeVisitor); } } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { if (accepted(clazz, deprecatedAttribute)) { deprecatedAttribute.accept(clazz, attributeVisitor); } } public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute) { if (accepted(clazz, deprecatedAttribute)) { deprecatedAttribute.accept(clazz, field, attributeVisitor); } } public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute) { if (accepted(clazz, deprecatedAttribute)) { deprecatedAttribute.accept(clazz, method, attributeVisitor); } } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { if (accepted(clazz, syntheticAttribute)) { syntheticAttribute.accept(clazz, attributeVisitor); } } public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute) { if (accepted(clazz, syntheticAttribute)) { syntheticAttribute.accept(clazz, field, attributeVisitor); } } public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute) { if (accepted(clazz, syntheticAttribute)) { syntheticAttribute.accept(clazz, method, attributeVisitor); } } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { if (accepted(clazz, signatureAttribute)) { signatureAttribute.accept(clazz, attributeVisitor); } } public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute signatureAttribute) { if (accepted(clazz, signatureAttribute)) { signatureAttribute.accept(clazz, field, attributeVisitor); } } public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute) { if (accepted(clazz, signatureAttribute)) { signatureAttribute.accept(clazz, method, attributeVisitor); } } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { if (accepted(clazz, constantValueAttribute)) { constantValueAttribute.accept(clazz, field, attributeVisitor); } } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { if (accepted(clazz, exceptionsAttribute)) { exceptionsAttribute.accept(clazz, method, attributeVisitor); } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (accepted(clazz, codeAttribute)) { codeAttribute.accept(clazz, method, attributeVisitor); } } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { if (accepted(clazz, stackMapAttribute)) { stackMapAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { if (accepted(clazz, stackMapTableAttribute)) { stackMapTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { if (accepted(clazz, lineNumberTableAttribute)) { lineNumberTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { if (accepted(clazz, localVariableTableAttribute)) { localVariableTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { if (accepted(clazz, localVariableTypeTableAttribute)) { localVariableTypeTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (accepted(clazz, runtimeVisibleAnnotationsAttribute)) { runtimeVisibleAnnotationsAttribute.accept(clazz, attributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (accepted(clazz, runtimeVisibleAnnotationsAttribute)) { runtimeVisibleAnnotationsAttribute.accept(clazz, field, attributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (accepted(clazz, runtimeVisibleAnnotationsAttribute)) { runtimeVisibleAnnotationsAttribute.accept(clazz, method, attributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (accepted(clazz, runtimeInvisibleAnnotationsAttribute)) { runtimeInvisibleAnnotationsAttribute.accept(clazz, attributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (accepted(clazz, runtimeInvisibleAnnotationsAttribute)) { runtimeInvisibleAnnotationsAttribute.accept(clazz, field, attributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (accepted(clazz, runtimeInvisibleAnnotationsAttribute)) { runtimeInvisibleAnnotationsAttribute.accept(clazz, method, attributeVisitor); } } public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute) { if (accepted(clazz, runtimeVisibleParameterAnnotationsAttribute)) { runtimeVisibleParameterAnnotationsAttribute.accept(clazz, method, attributeVisitor); } } public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute) { if (accepted(clazz, runtimeInvisibleParameterAnnotationsAttribute)) { runtimeInvisibleParameterAnnotationsAttribute.accept(clazz, method, attributeVisitor); } } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { if (accepted(clazz, annotationDefaultAttribute)) { annotationDefaultAttribute.accept(clazz, method, attributeVisitor); } } // Small utility methods. private boolean accepted(Clazz clazz, Attribute attribute) { return regularExpressionMatcher.matches(attribute.getAttributeName(clazz)); } } proguard4.8/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java0000644000175000017500000000266011736333523027304 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.Clazz; import proguard.classfile.attribute.InnerClassesInfo; /** * This interface specifies the methods for a visitor of * InnerClassesInfo objects. Note that there is only a single * implementation of InnerClassesInfo, such that this interface * is not strictly necessary as a visitor. * * @author Eric Lafortune */ public interface InnerClassesInfoVisitor { public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo); } proguard4.8/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java0000664000175000017500000000734111736333523026476 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor, MemberVisitor, and AttributeVisitor lets a given * AttributeVisitor visit all Attribute objects of the program classes, * program class members, or code attributes, respectively, that it visits. * * @author Eric Lafortune */ public class AllAttributeVisitor extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, AttributeVisitor { private final boolean deep; private final AttributeVisitor attributeVisitor; /** * Creates a new shallow AllAttributeVisitor. * @param attributeVisitor the AttributeVisitor to which visits will be * delegated. */ public AllAttributeVisitor(AttributeVisitor attributeVisitor) { this(false, attributeVisitor); } /** * Creates a new optionally deep AllAttributeVisitor. * @param deep specifies whether the attributes contained * further down the class structure should be * visited too. * @param attributeVisitor the AttributeVisitor to which visits will be * delegated. */ public AllAttributeVisitor(boolean deep, AttributeVisitor attributeVisitor) { this.deep = deep; this.attributeVisitor = attributeVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.attributesAccept(attributeVisitor); // Visit the attributes further down the class structure, if required. if (deep) { programClass.fieldsAccept(this); programClass.methodsAccept(this); programClass.attributesAccept(this); } } public void visitLibraryClass(LibraryClass libraryClass) {} // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { programMember.attributesAccept(programClass, attributeVisitor); // Visit the attributes further down the member structure, if required. if (deep) { programMember.attributesAccept(programClass, this); } } public void visitLibraryMember(LibraryClass programClass, LibraryMember programMember) {} // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { codeAttribute.attributesAccept(clazz, method, attributeVisitor); } } proguard4.8/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java0000644000175000017500000002375711736333523027334 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.util.StringMatcher; /** * This AttributeVisitor delegates its visits another AttributeVisitor, but * only when the visited attribute is not empty. For instance, a local variable * table without variables is empty. * * @author Eric Lafortune */ public class NonEmptyAttributeFilter implements AttributeVisitor { private final AttributeVisitor attributeVisitor; /** * Creates a new NonEmptyAttributeFilter. * @param attributeVisitor the AttributeVisitor to which * visits will be delegated. */ public NonEmptyAttributeFilter(AttributeVisitor attributeVisitor) { this.attributeVisitor = attributeVisitor; } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { unknownAttribute.accept(clazz, attributeVisitor); } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { if (bootstrapMethodsAttribute.u2bootstrapMethodsCount > 0) { bootstrapMethodsAttribute.accept(clazz, attributeVisitor); } } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { sourceFileAttribute.accept(clazz, attributeVisitor); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { sourceDirAttribute.accept(clazz, attributeVisitor); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { if (innerClassesAttribute.u2classesCount > 0) { innerClassesAttribute.accept(clazz, attributeVisitor); } } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { enclosingMethodAttribute.accept(clazz, attributeVisitor); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { deprecatedAttribute.accept(clazz, attributeVisitor); } public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute) { deprecatedAttribute.accept(clazz, field, attributeVisitor); } public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute) { deprecatedAttribute.accept(clazz, method, attributeVisitor); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { syntheticAttribute.accept(clazz, attributeVisitor); } public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute) { syntheticAttribute.accept(clazz, field, attributeVisitor); } public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute) { syntheticAttribute.accept(clazz, method, attributeVisitor); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { signatureAttribute.accept(clazz, attributeVisitor); } public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute signatureAttribute) { signatureAttribute.accept(clazz, field, attributeVisitor); } public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute) { signatureAttribute.accept(clazz, method, attributeVisitor); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { constantValueAttribute.accept(clazz, field, attributeVisitor); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { if (exceptionsAttribute.u2exceptionIndexTableLength > 0) { exceptionsAttribute.accept(clazz, method, attributeVisitor); } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { codeAttribute.accept(clazz, method, attributeVisitor); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { if (stackMapAttribute.u2stackMapFramesCount > 0) { stackMapAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { if (stackMapTableAttribute.u2stackMapFramesCount > 0) { stackMapTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { if (lineNumberTableAttribute.u2lineNumberTableLength > 0) { lineNumberTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { if (localVariableTableAttribute.u2localVariableTableLength > 0) { localVariableTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { if (localVariableTypeTableAttribute.u2localVariableTypeTableLength > 0) { localVariableTypeTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (runtimeVisibleAnnotationsAttribute.u2annotationsCount > 0) { runtimeVisibleAnnotationsAttribute.accept(clazz, attributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (runtimeVisibleAnnotationsAttribute.u2annotationsCount > 0) { runtimeVisibleAnnotationsAttribute.accept(clazz, field, attributeVisitor); } } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { if (runtimeVisibleAnnotationsAttribute.u2annotationsCount > 0) { runtimeVisibleAnnotationsAttribute.accept(clazz, method, attributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (runtimeInvisibleAnnotationsAttribute.u2annotationsCount > 0) { runtimeInvisibleAnnotationsAttribute.accept(clazz, attributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (runtimeInvisibleAnnotationsAttribute.u2annotationsCount > 0) { runtimeInvisibleAnnotationsAttribute.accept(clazz, field, attributeVisitor); } } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { if (runtimeInvisibleAnnotationsAttribute.u2annotationsCount > 0) { runtimeInvisibleAnnotationsAttribute.accept(clazz, method, attributeVisitor); } } public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute) { if (runtimeVisibleParameterAnnotationsAttribute.u2parametersCount > 0) { runtimeVisibleParameterAnnotationsAttribute.accept(clazz, method, attributeVisitor); } } public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute) { if (runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount > 0) { runtimeInvisibleParameterAnnotationsAttribute.accept(clazz, method, attributeVisitor); } } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { annotationDefaultAttribute.accept(clazz, method, attributeVisitor); } } proguard4.8/src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java0000644000175000017500000000365311736333523030465 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor lets a given BootstrapMethodInfoVisitor visit all * bootstrap method objects of the BootstrapMethodsAttribute objects it visits. * * @author Eric Lafortune */ public class AllBootstrapMethodInfoVisitor extends SimplifiedVisitor implements AttributeVisitor { private final BootstrapMethodInfoVisitor bootstrapMethodInfoVisitor; public AllBootstrapMethodInfoVisitor(BootstrapMethodInfoVisitor bootstrapMethodInfoVisitor) { this.bootstrapMethodInfoVisitor = bootstrapMethodInfoVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, bootstrapMethodInfoVisitor); } } proguard4.8/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java0000644000175000017500000000266611736333523026657 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; /** * This interface specifies the methods for a visitor of * ExceptionInfo objects. Note that there is only a single * implementation of ExceptionInfo, such that this interface * is not strictly necessary as a visitor. * * @author Eric Lafortune */ public interface ExceptionInfoVisitor { public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo); } proguard4.8/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java0000644000175000017500000000347011736333523027302 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor lets a given ExceptionInfoVisitor visit all exceptions * objects of the CodeAttribute objects it visits. * * @author Eric Lafortune */ public class AllExceptionInfoVisitor extends SimplifiedVisitor implements AttributeVisitor { private final ExceptionInfoVisitor exceptionInfoVisitor; public AllExceptionInfoVisitor(ExceptionInfoVisitor exceptionInfoVisitor) { this.exceptionInfoVisitor = exceptionInfoVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { codeAttribute.exceptionsAccept(clazz, method, exceptionInfoVisitor); } } proguard4.8/src/proguard/classfile/attribute/visitor/AttributeVisitor.java0000644000175000017500000001414711736333523026045 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; /** * This interface specifies the methods for a visitor of Attribute * objects. * * @author Eric Lafortune */ public interface AttributeVisitor { // Attributes that are attached to classes. public void visitUnknownAttribute( Clazz clazz, UnknownAttribute unknownAttribute); public void visitBootstrapMethodsAttribute( Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute); public void visitSourceFileAttribute( Clazz clazz, SourceFileAttribute sourceFileAttribute); public void visitSourceDirAttribute( Clazz clazz, SourceDirAttribute sourceDirAttribute); public void visitInnerClassesAttribute( Clazz clazz, InnerClassesAttribute innerClassesAttribute); public void visitEnclosingMethodAttribute( Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute); // Attributes that are attached to classes, fields, and methods. public void visitDeprecatedAttribute( Clazz clazz, DeprecatedAttribute deprecatedAttribute); public void visitDeprecatedAttribute( Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute); public void visitDeprecatedAttribute( Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute); public void visitSyntheticAttribute( Clazz clazz, SyntheticAttribute syntheticAttribute); public void visitSyntheticAttribute( Clazz clazz, Field field, SyntheticAttribute syntheticAttribute); public void visitSyntheticAttribute( Clazz clazz, Method method, SyntheticAttribute syntheticAttribute); public void visitSignatureAttribute( Clazz clazz, SignatureAttribute signatureAttribute); public void visitSignatureAttribute( Clazz clazz, Field field, SignatureAttribute signatureAttribute); public void visitSignatureAttribute( Clazz clazz, Method method, SignatureAttribute signatureAttribute); // Attributes that are attached to fields. public void visitConstantValueAttribute( Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute); // Attributes that are attached to methods. public void visitExceptionsAttribute( Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute); public void visitCodeAttribute( Clazz clazz, Method method, CodeAttribute codeAttribute); // Attributes that are attached to code attributes. public void visitStackMapAttribute( Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute); public void visitStackMapTableAttribute( Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute); public void visitLineNumberTableAttribute( Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute); public void visitLocalVariableTableAttribute( Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute); public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute); // Annotation attributes. public void visitRuntimeVisibleAnnotationsAttribute( Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute); public void visitRuntimeVisibleAnnotationsAttribute( Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute); public void visitRuntimeVisibleAnnotationsAttribute( Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute); public void visitRuntimeInvisibleAnnotationsAttribute( Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute); public void visitRuntimeInvisibleAnnotationsAttribute( Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute); public void visitRuntimeInvisibleAnnotationsAttribute( Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute); public void visitRuntimeVisibleParameterAnnotationsAttribute( Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute); public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute); public void visitAnnotationDefaultAttribute( Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute); } proguard4.8/src/proguard/classfile/attribute/visitor/StackSizeComputer.java0000644000175000017500000003220211736333523026131 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.visitor; import proguard.classfile.*; import proguard.classfile.visitor.ClassPrinter; import proguard.classfile.attribute.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import java.util.Arrays; /** * This AttributeVisitor computes the stack sizes at all instruction offsets * of the code attributes that it visits. * * @author Eric Lafortune */ public class StackSizeComputer extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private boolean[] evaluated = new boolean[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] stackSizes = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean exitInstructionBlock; private int stackSize; private int maxStackSize; /** * Returns whether the instruction at the given offset is reachable in the * most recently visited code attribute. */ public boolean isReachable(int instructionOffset) { return evaluated[instructionOffset]; } /** * Returns the stack size at the given instruction offset of the most * recently visited code attribute. */ public int getStackSize(int instructionOffset) { if (!evaluated[instructionOffset]) { throw new IllegalArgumentException("Unknown stack size at unreachable instruction offset ["+instructionOffset+"]"); } return stackSizes[instructionOffset]; } /** * Returns the maximum stack size of the most recently visited code attribute. */ public int getMaxStackSize() { return maxStackSize; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // TODO: Remove this when the code has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while computing stack sizes:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); if (DEBUG) { method.accept(clazz, new ClassPrinter()); } throw ex; } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (DEBUG) { System.out.println("StackSizeComputer: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); } // Try to reuse the previous array. int codeLength = codeAttribute.u4codeLength; if (evaluated.length < codeLength) { evaluated = new boolean[codeLength]; stackSizes = new int[codeLength]; } else { Arrays.fill(evaluated, 0, codeLength, false); } // The initial stack is always empty. stackSize = 0; maxStackSize = 0; // Evaluate the instruction block starting at the entry point of the method. evaluateInstructionBlock(clazz, method, codeAttribute, 0); // Evaluate the exception handlers. codeAttribute.exceptionsAccept(clazz, method, this); } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { byte opcode = simpleInstruction.opcode; // Some simple instructions exit from the current instruction block. exitInstructionBlock = opcode == InstructionConstants.OP_IRETURN || opcode == InstructionConstants.OP_LRETURN || opcode == InstructionConstants.OP_FRETURN || opcode == InstructionConstants.OP_DRETURN || opcode == InstructionConstants.OP_ARETURN || opcode == InstructionConstants.OP_RETURN || opcode == InstructionConstants.OP_ATHROW; } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Constant pool instructions never end the current instruction block. exitInstructionBlock = false; } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { byte opcode = variableInstruction.opcode; // The ret instruction end the current instruction block. exitInstructionBlock = opcode == InstructionConstants.OP_RET; } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { byte opcode = branchInstruction.opcode; // Evaluate the target instruction blocks. evaluateInstructionBlock(clazz, method, codeAttribute, offset + branchInstruction.branchOffset); // Evaluate the instructions after a subroutine branch. if (opcode == InstructionConstants.OP_JSR || opcode == InstructionConstants.OP_JSR_W) { // We assume subroutine calls (jsr and jsr_w instructions) don't // change the stack, other than popping the return value. stackSize -= 1; evaluateInstructionBlock(clazz, method, codeAttribute, offset + branchInstruction.length(offset)); } // Some branch instructions always end the current instruction block. exitInstructionBlock = opcode == InstructionConstants.OP_GOTO || opcode == InstructionConstants.OP_GOTO_W || opcode == InstructionConstants.OP_JSR || opcode == InstructionConstants.OP_JSR_W; } public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) { // Evaluate the target instruction blocks. // Loop over all jump offsets. int[] jumpOffsets = switchInstruction.jumpOffsets; for (int index = 0; index < jumpOffsets.length; index++) { // Evaluate the jump instruction block. evaluateInstructionBlock(clazz, method, codeAttribute, offset + jumpOffsets[index]); } // Also evaluate the default instruction block. evaluateInstructionBlock(clazz, method, codeAttribute, offset + switchInstruction.defaultOffset); // The switch instruction always ends the current instruction block. exitInstructionBlock = true; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { if (DEBUG) { System.out.println("Exception:"); } // The stack size when entering the exception handler is always 1. stackSize = 1; // Evaluate the instruction block starting at the entry point of the // exception handler. evaluateInstructionBlock(clazz, method, codeAttribute, exceptionInfo.u2handlerPC); } // Small utility methods. /** * Evaluates a block of instructions that hasn't been handled before, * starting at the given offset and ending at a branch instruction, a return * instruction, or a throw instruction. Branch instructions are handled * recursively. */ private void evaluateInstructionBlock(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset) { if (DEBUG) { if (evaluated[instructionOffset]) { System.out.println("-- (instruction block at "+instructionOffset+" already evaluated)"); } else { System.out.println("-- instruction block:"); } } // Remember the initial stack size. int initialStackSize = stackSize; // Remember the maximum stack size. if (maxStackSize < stackSize) { maxStackSize = stackSize; } // Evaluate any instructions that haven't been evaluated before. while (!evaluated[instructionOffset]) { // Mark the instruction as evaluated. evaluated[instructionOffset] = true; Instruction instruction = InstructionFactory.create(codeAttribute.code, instructionOffset); if (DEBUG) { int stackPushCount = instruction.stackPushCount(clazz); int stackPopCount = instruction.stackPopCount(clazz); System.out.println("["+instructionOffset+"]: "+ stackSize+" - "+ stackPopCount+" + "+ stackPushCount+" = "+ (stackSize+stackPushCount-stackPopCount)+": "+ instruction.toString(instructionOffset)); } // Compute the instruction's effect on the stack size. stackSize -= instruction.stackPopCount(clazz); if (stackSize < 0) { throw new IllegalArgumentException("Stack size becomes negative after instruction "+ instruction.toString(instructionOffset)+" in ["+ clazz.getName()+"."+ method.getName(clazz)+ method.getDescriptor(clazz)+"]"); } stackSizes[instructionOffset] = stackSize += instruction.stackPushCount(clazz); // Remember the maximum stack size. if (maxStackSize < stackSize) { maxStackSize = stackSize; } // Remember the next instruction offset. int nextInstructionOffset = instructionOffset + instruction.length(instructionOffset); // Visit the instruction, in order to handle branches. instruction.accept(clazz, method, codeAttribute, instructionOffset, this); // Stop evaluating after a branch. if (exitInstructionBlock) { break; } // Continue with the next instruction. instructionOffset = nextInstructionOffset; if (DEBUG) { if (evaluated[instructionOffset]) { System.out.println("-- (instruction at "+instructionOffset+" already evaluated)"); } } } // Restore the stack size for possible subsequent instruction blocks. this.stackSize = initialStackSize; } } proguard4.8/src/proguard/classfile/attribute/LineNumberTableAttribute.java0000644000175000017500000000616211736333523025715 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; /** * This Attribute represents a line number table attribute. * * @author Eric Lafortune */ public class LineNumberTableAttribute extends Attribute { public int u2lineNumberTableLength; public LineNumberInfo[] lineNumberTable; /** * Creates an uninitialized LineNumberTableAttribute. */ public LineNumberTableAttribute() { } /** * Creates an initialized LineNumberTableAttribute. */ public LineNumberTableAttribute(int u2attributeNameIndex, int u2lineNumberTableLength, LineNumberInfo[] lineNumberTable) { super(u2attributeNameIndex); this.u2lineNumberTableLength = u2lineNumberTableLength; this.lineNumberTable = lineNumberTable; } /** * Returns the line number corresponding to the given byte code program * counter. */ public int getLineNumber(int pc) { for (int index = u2lineNumberTableLength-1 ; index >= 0 ; index--) { LineNumberInfo info = lineNumberTable[index]; if (pc >= info.u2startPC) { return info.u2lineNumber; } } return u2lineNumberTableLength > 0 ? lineNumberTable[0].u2lineNumber : 0; } // Implementations for Attribute. public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor) { attributeVisitor.visitLineNumberTableAttribute(clazz, method, codeAttribute, this); } /** * Applies the given visitor to all line numbers. */ public void lineNumbersAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfoVisitor lineNumberInfoVisitor) { for (int index = 0; index < u2lineNumberTableLength; index++) { // We don't need double dispatching here, since there is only one // type of LineNumberInfo. lineNumberInfoVisitor.visitLineNumberInfo(clazz, method, codeAttribute, lineNumberTable[index]); } } } proguard4.8/src/proguard/classfile/attribute/ExceptionInfo.java0000644000175000017500000000515011736333523023567 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.VisitorAccepter; /** * Representation of an Exception table entry. * * @author Eric Lafortune */ public class ExceptionInfo implements VisitorAccepter { public int u2startPC; public int u2endPC; public int u2handlerPC; public int u2catchType; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Creates an uninitialized ExceptionInfo. */ public ExceptionInfo() { this(0, 0, 0, 0); } /** * Creates an ExceptionInfo with the given properties. */ public ExceptionInfo(int u2startPC, int u2endPC, int u2handlerPC, int u2catchType) { this.u2startPC = u2startPC; this.u2endPC = u2endPC; this.u2handlerPC = u2handlerPC; this.u2catchType = u2catchType; } /** * Returns whether the exception's try block contains the instruction at the * given offset. */ public boolean isApplicable(int instructionOffset) { return instructionOffset >= u2startPC && instructionOffset < u2endPC; } /** * Returns whether the exception's try block overlaps with the specified * block of instructions. */ public boolean isApplicable(int startOffset, int endOffset) { return u2startPC < endOffset && u2endPC > startOffset; } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } proguard4.8/src/proguard/classfile/attribute/SourceDirAttribute.java0000644000175000017500000000340211736333523024576 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.Clazz; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a source directory attribute. * * @author Eric Lafortune */ public class SourceDirAttribute extends Attribute { public int u2sourceDirIndex; /** * Creates an uninitialized SourceDirAttribute. */ public SourceDirAttribute() { } /** * Creates an initialized SourceDirAttribute. */ public SourceDirAttribute(int u2attributeNameIndex, int u2sourceDirIndex) { super(u2attributeNameIndex); this.u2sourceDirIndex = u2sourceDirIndex; } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitSourceDirAttribute(clazz, this); } } proguard4.8/src/proguard/classfile/attribute/ExceptionsAttribute.java0000644000175000017500000000474011736333523025026 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Attribute represents an exceptions attribute. * * @author Eric Lafortune */ public class ExceptionsAttribute extends Attribute { public int u2exceptionIndexTableLength; public int[] u2exceptionIndexTable; /** * Creates an uninitialized ExceptionsAttribute. */ public ExceptionsAttribute() { } /** * Creates an initialized ExceptionsAttribute. */ public ExceptionsAttribute(int u2attributeNameIndex, int u2exceptionIndexTableLength, int[] u2exceptionIndexTable) { super(u2attributeNameIndex); this.u2exceptionIndexTableLength = u2exceptionIndexTableLength; this.u2exceptionIndexTable = u2exceptionIndexTable; } // Implementations for Attribute. public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitExceptionsAttribute(clazz, method, this); } /** * Applies the given constant pool visitor to all exception class pool info * entries. */ public void exceptionEntriesAccept(Clazz clazz, ConstantVisitor constantVisitor) { for (int index = 0; index < u2exceptionIndexTableLength; index++) { clazz.constantPoolEntryAccept(u2exceptionIndexTable[index], constantVisitor); } } } proguard4.8/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java0000644000175000017500000000547211736333523027222 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; /** * This Attribute represents a local variable table type attribute. * * @author Eric Lafortune */ public class LocalVariableTypeTableAttribute extends Attribute { public int u2localVariableTypeTableLength; public LocalVariableTypeInfo[] localVariableTypeTable; /** * Creates an uninitialized LocalVariableTypeTableAttribute. */ public LocalVariableTypeTableAttribute() { } /** * Creates an initialized LocalVariableTypeTableAttribute. */ public LocalVariableTypeTableAttribute(int u2attributeNameIndex, int u2localVariableTypeTableLength, LocalVariableTypeInfo[] localVariableTypeTable) { super(u2attributeNameIndex); this.u2localVariableTypeTableLength = u2localVariableTypeTableLength; this.localVariableTypeTable = localVariableTypeTable; } // Implementations for Attribute. public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor) { attributeVisitor.visitLocalVariableTypeTableAttribute(clazz, method, codeAttribute, this); } /** * Applies the given visitor to all local variable types. */ public void localVariablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfoVisitor localVariableTypeInfoVisitor) { for (int index = 0; index < u2localVariableTypeTableLength; index++) { // We don't need double dispatching here, since there is only one // type of LocalVariableTypeInfo. localVariableTypeInfoVisitor.visitLocalVariableTypeInfo(clazz, method, codeAttribute, localVariableTypeTable[index]); } } } proguard4.8/src/proguard/classfile/attribute/LocalVariableTypeInfo.java0000644000175000017500000000727711736333523025207 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.Clazz; import proguard.classfile.visitor.ClassVisitor; /** * Representation of an Local Variable table entry. * * @author Eric Lafortune */ public class LocalVariableTypeInfo implements Comparable { public int u2startPC; public int u2length; public int u2nameIndex; public int u2signatureIndex; public int u2index; /** * An extra field pointing to the Clazz objects referenced in the * type string. This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz[] referencedClasses; /** * Creates an uninitialized LocalVariableTypeInfo. */ public LocalVariableTypeInfo() { } /** * Creates an initialized LocalVariableTypeInfo. */ public LocalVariableTypeInfo(int u2startPC, int u2length, int u2nameIndex, int u2signatureIndex, int u2index) { this.u2startPC = u2startPC; this.u2length = u2length; this.u2nameIndex = u2nameIndex; this.u2signatureIndex = u2signatureIndex; this.u2index = u2index; } /** * Applies the given visitor to all referenced classes. */ public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { for (int index = 0; index < referencedClasses.length; index++) { Clazz referencedClass = referencedClasses[index]; if (referencedClass != null) { referencedClass.accept(classVisitor); } } } } // Implementations for Comparable. public int compareTo(Object object) { LocalVariableTypeInfo other = (LocalVariableTypeInfo)object; return this.u2startPC < other.u2startPC ? -1 : this.u2startPC > other.u2startPC ? 1 : this.u2length < other.u2length ? -1 : this.u2length > other.u2length ? 1 : this.u2index < other.u2index ? -1 : this.u2index > other.u2index ? 1 : this.u2signatureIndex < other.u2signatureIndex ? -1 : this.u2signatureIndex > other.u2signatureIndex ? 1 : this.u2nameIndex < other.u2nameIndex ? -1 : this.u2nameIndex > other.u2nameIndex ? 1 : 0; } } proguard4.8/src/proguard/classfile/attribute/EnclosingMethodAttribute.java0000644000175000017500000000703611736333523025770 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.visitor.*; /** * This Attribute represents an enclosing method attribute. * * @author Eric Lafortune */ public class EnclosingMethodAttribute extends Attribute { public int u2classIndex; public int u2nameAndTypeIndex; /** * An extra field pointing to the referenced Clazz object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}. */ public Clazz referencedClass; /** * An extra field optionally pointing to the referenced Method object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}. */ public Method referencedMethod; /** * Creates an uninitialized EnclosingMethodAttribute. */ public EnclosingMethodAttribute() { } /** * Creates an initialized EnclosingMethodAttribute. */ public EnclosingMethodAttribute(int u2attributeNameIndex, int u2classIndex, int u2nameAndTypeIndex) { super(u2attributeNameIndex); this.u2classIndex = u2classIndex; this.u2nameAndTypeIndex = u2nameAndTypeIndex; } /** * Returns the class name. */ public String getClassName(Clazz clazz) { return clazz.getClassName(u2classIndex); } /** * Returns the method/field name. */ public String getName(Clazz clazz) { return clazz.getName(u2nameAndTypeIndex); } /** * Returns the type. */ public String getType(Clazz clazz) { return clazz.getType(u2nameAndTypeIndex); } /** * Lets the referenced class accept the given visitor. */ public void referencedClassAccept(ClassVisitor classVisitor) { if (referencedClass != null) { referencedClass.accept(classVisitor); } } /** * Lets the referenced class member accept the given visitor. */ public void referencedMethodAccept(MemberVisitor memberVisitor) { if (referencedMethod != null) { referencedMethod.accept(referencedClass, memberVisitor); } } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitEnclosingMethodAttribute(clazz, this); } } proguard4.8/src/proguard/classfile/attribute/SourceFileAttribute.java0000644000175000017500000000341011736333523024736 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.Clazz; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a source file attribute. * * @author Eric Lafortune */ public class SourceFileAttribute extends Attribute { public int u2sourceFileIndex; /** * Creates an uninitialized SourceFileAttribute. */ public SourceFileAttribute() { } /** * Creates an initialized SourceFileAttribute. */ public SourceFileAttribute(int u2attributeNameIndex, int u2sourceFileIndex) { super(u2attributeNameIndex); this.u2sourceFileIndex = u2sourceFileIndex; } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitSourceFileAttribute(clazz, this); } } proguard4.8/src/proguard/classfile/attribute/annotation/0000775000175000017500000000000011760503005022314 5ustar ericericproguard4.8/src/proguard/classfile/attribute/annotation/package.html0000644000175000017500000000015011736333523024600 0ustar ericeric This package contains classes to represent the annotation attributes inside class files. proguard4.8/src/proguard/classfile/attribute/annotation/ElementValue.java0000644000175000017500000000664111736333523025563 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; import proguard.classfile.visitor.MemberVisitor; /** * This abstract class represents an element value that is attached to an * annotation or an annotation default. Specific types of element values are * subclassed from it. * * @author Eric Lafortune */ public abstract class ElementValue implements VisitorAccepter { /** * An extra field for the optional element name. It is used in element value * pairs of annotations. Otherwise, it is 0. */ public int u2elementNameIndex; /** * An extra field pointing to the referenced Clazz * object, if applicable. This field is typically filled out by the * {@link proguard.classfile.util.ClassReferenceInitializer}. */ public Clazz referencedClass; /** * An extra field pointing to the referenced Method * object, if applicable. This field is typically filled out by the * {@link proguard.classfile.util.ClassReferenceInitializer}. */ public Method referencedMethod; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Creates an uninitialized ElementValue. */ protected ElementValue() { } /** * Creates an initialized ElementValue. */ protected ElementValue(int u2elementNameIndex) { this.u2elementNameIndex = u2elementNameIndex; } /** * Returns the element name. */ public String getMethodName(Clazz clazz) { return clazz.getString(u2elementNameIndex); } // Abstract methods to be implemented by extensions. /** * Returns the tag of this element value. */ public abstract int getTag(); /** * Accepts the given visitor. */ public abstract void accept(Clazz clazz, Annotation annotation, ElementValueVisitor elementValueVisitor); /** * Applies the given visitor to the referenced method. */ public void referencedMethodAccept(MemberVisitor memberVisitor) { if (referencedMethod != null) { referencedMethod.accept(referencedClass, memberVisitor); } } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } proguard4.8/src/proguard/classfile/attribute/annotation/ArrayElementValue.java0000644000175000017500000000472111736333523026557 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; /** * This ElementValue represents an array element value. * * @author Eric Lafortune */ public class ArrayElementValue extends ElementValue { public int u2elementValuesCount; public ElementValue[] elementValues; /** * Creates an uninitialized ArrayElementValue. */ public ArrayElementValue() { } /** * Creates an initialized ArrayElementValue. */ public ArrayElementValue(int u2elementNameIndex, int u2elementValuesCount, ElementValue[] elementValues) { super(u2elementNameIndex); this.u2elementValuesCount = u2elementValuesCount; this.elementValues = elementValues; } // Implementations for ElementValue. public int getTag() { return ClassConstants.ELEMENT_VALUE_ARRAY; } public void accept(Clazz clazz, Annotation annotation, ElementValueVisitor elementValueVisitor) { elementValueVisitor.visitArrayElementValue(clazz, annotation, this); } /** * Applies the given visitor to all nested element values. */ public void elementValuesAccept(Clazz clazz, Annotation annotation, ElementValueVisitor elementValueVisitor) { for (int index = 0; index < u2elementValuesCount; index++) { elementValues[index].accept(clazz, annotation, elementValueVisitor); } } } proguard4.8/src/proguard/classfile/attribute/annotation/ConstantElementValue.java0000644000175000017500000000407611736333523027275 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.Clazz; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; /** * This ElementValue represents a constant element value. * * @author Eric Lafortune */ public class ConstantElementValue extends ElementValue { public final int u1tag; public int u2constantValueIndex; /** * Creates an uninitialized ConstantElementValue. */ public ConstantElementValue(int u1tag) { this.u1tag = u1tag; } /** * Creates an initialized ConstantElementValue. */ public ConstantElementValue(int u1tag, int u2elementNameIndex, int u2constantValueIndex) { super(u2elementNameIndex); this.u1tag = u1tag; this.u2constantValueIndex = u2constantValueIndex; } // Implementations for ElementValue. public int getTag() { return u1tag; } public void accept(Clazz clazz, Annotation annotation, ElementValueVisitor elementValueVisitor) { elementValueVisitor.visitConstantElementValue(clazz, annotation, this); } } proguard4.8/src/proguard/classfile/attribute/annotation/ClassElementValue.java0000644000175000017500000000543711736333523026553 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ElementValue represents a class element value. * * @author Eric Lafortune */ public class ClassElementValue extends ElementValue { public int u2classInfoIndex; /** * An extra field pointing to the Clazz objects referenced in the * type name string. This field is filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz[] referencedClasses; /** * Creates an uninitialized ClassElementValue. */ public ClassElementValue() { } /** * Creates an initialized ClassElementValue. */ public ClassElementValue(int u2elementNameIndex, int u2classInfoIndex) { super(u2elementNameIndex); this.u2classInfoIndex = u2classInfoIndex; } /** * Applies the given visitor to all referenced classes. */ public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { for (int index = 0; index < referencedClasses.length; index++) { Clazz referencedClass = referencedClasses[index]; if (referencedClass != null) { referencedClass.accept(classVisitor); } } } } // Implementations for ElementValue. public int getTag() { return ClassConstants.ELEMENT_VALUE_CLASS; } public void accept(Clazz clazz, Annotation annotation, ElementValueVisitor elementValueVisitor) { elementValueVisitor.visitClassElementValue(clazz, annotation, this); } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootproguard4.8/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.javaproguard4.8/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribut0000644000175000017500000000437411736333523033344 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a runtime invisible parameter annotations attribute. * * @author Eric Lafortune */ public class RuntimeInvisibleParameterAnnotationsAttribute extends ParameterAnnotationsAttribute { /** * Creates an uninitialized RuntimeInvisibleParameterAnnotationsAttribute. */ public RuntimeInvisibleParameterAnnotationsAttribute() { } /** * Creates an initialized RuntimeInvisibleParameterAnnotationsAttribute. */ public RuntimeInvisibleParameterAnnotationsAttribute(int u2attributeNameIndex, int u2parametersCount, int[] u2parameterAnnotationsCount, Annotation[][] parameterAnnotations) { super(u2attributeNameIndex, u2parametersCount, u2parameterAnnotationsCount, parameterAnnotations); } // Implementations for Attribute. public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitRuntimeInvisibleParameterAnnotationsAttribute(clazz, method, this); } } proguard4.8/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java0000644000175000017500000000445111736333523032235 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a runtime visible annotations attribute. * * @author Eric Lafortune */ public class RuntimeVisibleAnnotationsAttribute extends AnnotationsAttribute { /** * Creates an uninitialized RuntimeVisibleAnnotationsAttribute. */ public RuntimeVisibleAnnotationsAttribute() { } /** * Creates an initialized RuntimeVisibleAnnotationsAttribute. */ public RuntimeVisibleAnnotationsAttribute(int u2attributeNameIndex, int u2annotationsCount, Annotation[] annotations) { super(u2attributeNameIndex, u2annotationsCount, annotations); } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, this); } public void accept(Clazz clazz, Field field, AttributeVisitor attributeVisitor) { attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, field, this); } public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, method, this); } } proguard4.8/src/proguard/classfile/attribute/annotation/visitor/0000775000175000017500000000000011760503005024013 5ustar ericericproguard4.8/src/proguard/classfile/attribute/annotation/visitor/package.html0000644000175000017500000000013611736333523026303 0ustar ericeric This package contains visitors for annotation attributes and their components. proguard4.8/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java0000644000175000017500000000336211736333523030363 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation.visitor; import proguard.classfile.*; import proguard.classfile.attribute.annotation.Annotation; /** * This interface specifies the methods for a visitor of * Annotation objects. Note that there is only a single * implementation of Annotation, such that this interface * is not strictly necessary as a visitor. * * @author Eric Lafortune */ public interface AnnotationVisitor { public void visitAnnotation(Clazz clazz, Annotation annotation); public void visitAnnotation(Clazz clazz, Field field, Annotation annotation); public void visitAnnotation(Clazz clazz, Method method, Annotation annotation); public void visitAnnotation(Clazz clazz, Method method, int parameterIndex, Annotation annotation); } proguard4.8/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java0000644000175000017500000000652511736333523030643 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation.visitor; import proguard.classfile.Clazz; import proguard.classfile.attribute.annotation.*; /** * This interface specifies the methods for a visitor of ElementValue * objects. * * @author Eric Lafortune */ public interface ElementValueVisitor { public void visitConstantElementValue( Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue); public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue); public void visitClassElementValue( Clazz clazz, Annotation annotation, ClassElementValue classElementValue); public void visitAnnotationElementValue( Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue); public void visitArrayElementValue( Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue); // public void visitConstantElementValue( Clazz clazz, Field field, Annotation annotation, ConstantElementValue constantElementValue); // public void visitEnumConstantElementValue(Clazz clazz, Field field, Annotation annotation, EnumConstantElementValue enumConstantElementValue); // public void visitClassElementValue( Clazz clazz, Field field, Annotation annotation, ClassElementValue classElementValue); // public void visitAnnotationElementValue( Clazz clazz, Field field, Annotation annotation, AnnotationElementValue annotationElementValue); // public void visitArrayElementValue( Clazz clazz, Field field, Annotation annotation, ArrayElementValue arrayElementValue); // // public void visitConstantElementValue( Clazz clazz, Method method, Annotation annotation, ConstantElementValue constantElementValue); // public void visitEnumConstantElementValue(Clazz clazz, Method method, Annotation annotation, EnumConstantElementValue enumConstantElementValue); // public void visitClassElementValue( Clazz clazz, Method method, Annotation annotation, ClassElementValue classElementValue); // public void visitAnnotationElementValue( Clazz clazz, Method method, Annotation annotation, AnnotationElementValue annotationElementValue); // public void visitArrayElementValue( Clazz clazz, Method method, Annotation annotation, ArrayElementValue arrayElementValue); } proguard4.8/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java0000644000175000017500000000733611736333523031021 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation.visitor; import proguard.classfile.*; import proguard.classfile.attribute.Attribute; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor lets a given AnnotationVisitor visit all Annotation * objects of the attributes it visits. * * @author Eric Lafortune */ public class AllAnnotationVisitor extends SimplifiedVisitor implements AttributeVisitor { private final AnnotationVisitor annotationVisitor; public AllAnnotationVisitor(AnnotationVisitor annotationVisitor) { this.annotationVisitor = annotationVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { // Visit the annotations. runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, annotationVisitor); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { // Visit the annotations. runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, field, annotationVisitor); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { // Visit the annotations. runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, method, annotationVisitor); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { // Visit the annotations. runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, annotationVisitor); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { // Visit the annotations. runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, field, annotationVisitor); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { // Visit the annotations. runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, method, annotationVisitor); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Visit the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, annotationVisitor); } } proguard4.8/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java0000644000175000017500000000646411736333523031021 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation.visitor; import proguard.classfile.*; import proguard.classfile.attribute.annotation.Annotation; import proguard.classfile.util.SimplifiedVisitor; import proguard.util.*; /** * This AnnotationVisitor delegates its visits to another given * AnnotationVisitor, but only when the visited annotation has * a type that matches a given regular expression. * * @author Eric Lafortune */ public class AnnotationTypeFilter extends SimplifiedVisitor implements AnnotationVisitor { private final StringMatcher regularExpressionMatcher; private final AnnotationVisitor annotationVisitor; /** * Creates a new ClassNameFilter. * @param regularExpression the regular expression against which annotation * type names will be matched. * @param annotationVisitor the annotationVisitor to which * visits will be delegated. */ public AnnotationTypeFilter(String regularExpression, AnnotationVisitor annotationVisitor) { this.regularExpressionMatcher = new ListParser(new ClassNameParser()).parse(regularExpression); this.annotationVisitor = annotationVisitor; } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { if (accepted(annotation.getType(clazz))) { annotationVisitor.visitAnnotation(clazz, annotation); } } public void visitAnnotation(Clazz clazz, Field field, Annotation annotation) { if (accepted(annotation.getType(clazz))) { annotationVisitor.visitAnnotation(clazz, field, annotation); } } public void visitAnnotation(Clazz clazz, Method method, Annotation annotation) { if (accepted(annotation.getType(clazz))) { annotationVisitor.visitAnnotation(clazz, method, annotation); } } public void visitAnnotation(Clazz clazz, Method method, int parameterIndex, Annotation annotation) { if (accepted(annotation.getType(clazz))) { annotationVisitor.visitAnnotation(clazz, method, parameterIndex, annotation); } } // Small utility methods. private boolean accepted(String name) { return regularExpressionMatcher.matches(name); } } proguard4.8/src/proguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.java0000644000175000017500000000374011736333523032016 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation.visitor; import proguard.classfile.*; import proguard.classfile.attribute.annotation.Annotation; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; /** * This AnnotationVisitor delegates all visits to a given MemberVisitor. * The latter visits the class member of each visited class member annotation * or method parameter annotation, although never twice in a row. * * @author Eric Lafortune */ public class AnnotationToMemberVisitor extends SimplifiedVisitor implements AnnotationVisitor { private final MemberVisitor memberVisitor; private Member lastVisitedMember; public AnnotationToMemberVisitor(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Member member, Annotation annotation) { if (!member.equals(lastVisitedMember)) { member.accept(clazz, memberVisitor); lastVisitedMember = member; } } } proguard4.8/src/proguard/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.java0000644000175000017500000000360311736333523031152 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation.visitor; import proguard.classfile.Clazz; import proguard.classfile.attribute.annotation.Annotation; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This AnnotationVisitor delegates all visits to a given ClassVisitor. * The latter visits the class of each visited annotation, although * never twice in a row. * * @author Eric Lafortune */ public class AnnotatedClassVisitor extends SimplifiedVisitor implements AnnotationVisitor { private final ClassVisitor classVisitor; private Clazz lastVisitedClass; public AnnotatedClassVisitor(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { if (!clazz.equals(lastVisitedClass)) { clazz.accept(classVisitor); lastVisitedClass = clazz; } } } proguard4.8/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java0000644000175000017500000000447311736333523032570 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a runtime invisible annotations attribute. * * @author Eric Lafortune */ public class RuntimeInvisibleAnnotationsAttribute extends AnnotationsAttribute { /** * Creates an uninitialized RuntimeInvisibleAnnotationsAttribute. */ public RuntimeInvisibleAnnotationsAttribute() { } /** * Creates an initialized RuntimeInvisibleAnnotationsAttribute. */ public RuntimeInvisibleAnnotationsAttribute(int u2attributeNameIndex, int u2annotationsCount, Annotation[] annotations) { super(u2attributeNameIndex, u2annotationsCount, annotations); } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, this); } public void accept(Clazz clazz, Field field, AttributeVisitor attributeVisitor) { attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, field, this); } public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, method, this); } } proguard4.8/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java0000644000175000017500000000627311736333523027357 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.Attribute; import proguard.classfile.attribute.annotation.visitor.AnnotationVisitor; /** * This Attribute represents an annotations attribute. * * @author Eric Lafortune */ public abstract class AnnotationsAttribute extends Attribute { public int u2annotationsCount; public Annotation[] annotations; /** * Creates an uninitialized AnnotationsAttribute. */ protected AnnotationsAttribute() { } /** * Creates an initialized AnnotationsAttribute. */ protected AnnotationsAttribute(int u2attributeNameIndex, int u2annotationsCount, Annotation[] annotations) { super(u2attributeNameIndex); this.u2annotationsCount = u2annotationsCount; this.annotations = annotations; } /** * Applies the given visitor to all class annotations. */ public void annotationsAccept(Clazz clazz, AnnotationVisitor annotationVisitor) { for (int index = 0; index < u2annotationsCount; index++) { // We don't need double dispatching here, since there is only one // type of Annotation. annotationVisitor.visitAnnotation(clazz, annotations[index]); } } /** * Applies the given visitor to all field annotations. */ public void annotationsAccept(Clazz clazz, Field field, AnnotationVisitor annotationVisitor) { for (int index = 0; index < u2annotationsCount; index++) { // We don't need double dispatching here, since there is only one // type of Annotation. annotationVisitor.visitAnnotation(clazz, field, annotations[index]); } } /** * Applies the given visitor to all method annotations. */ public void annotationsAccept(Clazz clazz, Method method, AnnotationVisitor annotationVisitor) { for (int index = 0; index < u2annotationsCount; index++) { // We don't need double dispatching here, since there is only one // type of Annotation. annotationVisitor.visitAnnotation(clazz, method, annotations[index]); } } } proguard4.8/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java0000644000175000017500000000602211736333523030113 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ElementValue represents an enumeration constant element value. * * @author Eric Lafortune */ public class EnumConstantElementValue extends ElementValue { public int u2typeNameIndex; public int u2constantNameIndex; /** * An extra field pointing to the Clazz objects referenced in the * type name string. This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz[] referencedClasses; /** * Creates an uninitialized EnumConstantElementValue. */ public EnumConstantElementValue() { } /** * Creates an initialized EnumConstantElementValue. */ public EnumConstantElementValue(int u2elementNameIndex, int u2typeNameIndex, int u2constantNameIndex) { super(u2elementNameIndex); this.u2typeNameIndex = u2typeNameIndex; this.u2constantNameIndex = u2constantNameIndex; } /** * Applies the given visitor to all referenced classes. */ public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { for (int index = 0; index < referencedClasses.length; index++) { Clazz referencedClass = referencedClasses[index]; if (referencedClass != null) { referencedClass.accept(classVisitor); } } } } // Implementations for ElementValue. public int getTag() { return ClassConstants.ELEMENT_VALUE_ENUM_CONSTANT; } public void accept(Clazz clazz, Annotation annotation, ElementValueVisitor elementValueVisitor) { elementValueVisitor.visitEnumConstantElementValue(clazz, annotation, this); } } proguard4.8/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java0000644000175000017500000000603211736333523031211 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.Attribute; import proguard.classfile.attribute.annotation.visitor.AnnotationVisitor; /** * This Attribute represents a runtime parameter annotations attribute. * * @author Eric Lafortune */ public abstract class ParameterAnnotationsAttribute extends Attribute { public int u2parametersCount; public int[] u2parameterAnnotationsCount; public Annotation[][] parameterAnnotations; /** * Creates an uninitialized ParameterAnnotationsAttribute. */ protected ParameterAnnotationsAttribute() { } /** * Creates an initialized ParameterAnnotationsAttribute. */ protected ParameterAnnotationsAttribute(int u2attributeNameIndex, int u2parametersCount, int[] u2parameterAnnotationsCount, Annotation[][] parameterAnnotations) { super(u2attributeNameIndex); this.u2parametersCount = u2parametersCount; this.u2parameterAnnotationsCount = u2parameterAnnotationsCount; this.parameterAnnotations = parameterAnnotations; } /** * Applies the given visitor to all annotations. */ public void annotationsAccept(Clazz clazz, Method method, AnnotationVisitor annotationVisitor) { // Loop over all parameters. for (int parameterIndex = 0; parameterIndex < u2parametersCount; parameterIndex++) { int annotationsCount = u2parameterAnnotationsCount[parameterIndex]; Annotation[] annotations = parameterAnnotations[parameterIndex]; // Loop over all parameter annotations. for (int index = 0; index < annotationsCount; index++) { // We don't need double dispatching here, since there is only one // type of Annotation. annotationVisitor.visitAnnotation(clazz, method, parameterIndex, annotations[index]); } } } } proguard4.8/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java0000644000175000017500000000432611736333523030476 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.Attribute; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents an annotation default attribute. * * @author Eric Lafortune */ public class AnnotationDefaultAttribute extends Attribute { public ElementValue defaultValue; /** * Creates an uninitialized AnnotationDefaultAttribute. */ public AnnotationDefaultAttribute() { } /** * Creates an initialized AnnotationDefaultAttribute. */ public AnnotationDefaultAttribute(int u2attributeNameIndex, ElementValue defaultValue) { super(u2attributeNameIndex); this.defaultValue = defaultValue; } /** * Applies the given visitor to the default element value. */ public void defaultValueAccept(Clazz clazz, ElementValueVisitor elementValueVisitor) { defaultValue.accept(clazz, null, elementValueVisitor); } // Implementations for Attribute. public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitAnnotationDefaultAttribute(clazz, method, this); } } proguard4.8/src/proguard/classfile/attribute/annotation/Annotation.java0000644000175000017500000000761611736333523025312 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; import proguard.classfile.visitor.ClassVisitor; /** * Representation of an annotation. * * @author Eric Lafortune */ public class Annotation implements VisitorAccepter { public int u2typeIndex; public int u2elementValuesCount; public ElementValue[] elementValues; /** * An extra field pointing to the Clazz objects referenced in the * type string. This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz[] referencedClasses; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Creates an uninitialized Annotation. */ public Annotation() { } /** * Creates an initialized Annotation. */ public Annotation(int u2typeIndex, int u2elementValuesCount, ElementValue[] elementValues) { this.u2typeIndex = u2typeIndex; this.u2elementValuesCount = u2elementValuesCount; this.elementValues = elementValues; } /** * Returns the type. */ public String getType(Clazz clazz) { return clazz.getString(u2typeIndex); } /** * Applies the given visitor to the first referenced class. This is the * main annotation class. */ public void referencedClassAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { Clazz referencedClass = referencedClasses[0]; if (referencedClass != null) { referencedClass.accept(classVisitor); } } } /** * Applies the given visitor to all referenced classes. */ public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { for (int index = 0; index < referencedClasses.length; index++) { Clazz referencedClass = referencedClasses[index]; if (referencedClass != null) { referencedClass.accept(classVisitor); } } } } /** * Applies the given visitor to all element value pairs. */ public void elementValuesAccept(Clazz clazz, ElementValueVisitor elementValueVisitor) { for (int index = 0; index < u2elementValuesCount; index++) { elementValues[index].accept(clazz, this, elementValueVisitor); } } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootproguard4.8/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.javaproguard4.8/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.0000644000175000017500000000435011736333523033232 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a runtime visible parameter annotations attribute. * * @author Eric Lafortune */ public class RuntimeVisibleParameterAnnotationsAttribute extends ParameterAnnotationsAttribute { /** * Creates an uninitialized RuntimeVisibleParameterAnnotationsAttribute. */ public RuntimeVisibleParameterAnnotationsAttribute() { } /** * Creates an initialized RuntimeVisibleParameterAnnotationsAttribute. */ public RuntimeVisibleParameterAnnotationsAttribute(int u2attributeNameIndex, int u2parametersCount, int[] u2parameterAnnotationsCount, Annotation[][] parameterAnnotations) { super(u2attributeNameIndex, u2parametersCount, u2parameterAnnotationsCount, parameterAnnotations); } // Implementations for Attribute. public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitRuntimeVisibleParameterAnnotationsAttribute(clazz, method, this); } } proguard4.8/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java0000644000175000017500000000424711736333523027616 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.annotation; import proguard.classfile.*; import proguard.classfile.attribute.annotation.visitor.*; /** * This ElementValue represents an annotation element value. * * @author Eric Lafortune */ public class AnnotationElementValue extends ElementValue { public Annotation annotationValue; /** * Creates an uninitialized AnnotationElementValue. */ public AnnotationElementValue() { } /** * Creates an initialized AnnotationElementValue. */ public AnnotationElementValue(int u2elementNameIndex, Annotation annotationValue) { super(u2elementNameIndex); this.annotationValue = annotationValue; } /** * Applies the given visitor to the annotation. */ public void annotationAccept(Clazz clazz, AnnotationVisitor annotationVisitor) { annotationVisitor.visitAnnotation(clazz, annotationValue); } // Implementations for ElementValue. public int getTag() { return ClassConstants.ELEMENT_VALUE_ANNOTATION; } public void accept(Clazz clazz, Annotation annotation, ElementValueVisitor elementValueVisitor) { elementValueVisitor.visitAnnotationElementValue(clazz, annotation, this); } } proguard4.8/src/proguard/classfile/attribute/SignatureAttribute.java0000644000175000017500000000571411736333523024650 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This Attribute represents a signature attribute. * * @author Eric Lafortune */ public class SignatureAttribute extends Attribute { public int u2signatureIndex; /** * An extra field pointing to the Clazz objects referenced in the * signature string. This field is filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz[] referencedClasses; /** * Creates an uninitialized SignatureAttribute. */ public SignatureAttribute() { } /** * Creates an initialized SignatureAttribute. */ public SignatureAttribute(int u2attributeNameIndex, int u2signatureIndex) { super(u2attributeNameIndex); this.u2signatureIndex = u2signatureIndex; } /** * Lets the Clazz objects referenced in the signature string accept the * given visitor. */ public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { for (int index = 0; index < referencedClasses.length; index++) { if (referencedClasses[index] != null) { referencedClasses[index].accept(classVisitor); } } } } // Implementations for Attribute. public void accept(Clazz clazz, AttributeVisitor attributeVisitor) { attributeVisitor.visitSignatureAttribute(clazz, this); } public void accept(Clazz clazz, Field field, AttributeVisitor attributeVisitor) { attributeVisitor.visitSignatureAttribute(clazz, field, this); } public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitSignatureAttribute(clazz, method, this); } } proguard4.8/src/proguard/classfile/attribute/LineNumberInfo.java0000644000175000017500000000263111736333523023672 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; /** * Representation of an Line Number table entry. * * @author Eric Lafortune */ public class LineNumberInfo { public int u2startPC; public int u2lineNumber; /** * Creates an uninitialized LineNumberInfo. */ public LineNumberInfo() { } /** * Creates an initialized LineNumberInfo. */ public LineNumberInfo(int u2startPC, int u2lineNumber) { this.u2startPC = u2startPC; this.u2lineNumber = u2lineNumber; } } proguard4.8/src/proguard/classfile/attribute/CodeAttribute.java0000644000175000017500000001526211736333523023560 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; /** * This Attribute represents a code attribute. * * @author Eric Lafortune */ public class CodeAttribute extends Attribute { public int u2maxStack; public int u2maxLocals; public int u4codeLength; public byte[] code; public int u2exceptionTableLength; public ExceptionInfo[] exceptionTable; public int u2attributesCount; public Attribute[] attributes; /** * Creates an uninitialized CodeAttribute. */ public CodeAttribute() { } /** * Creates an initialized CodeAttribute. */ public CodeAttribute(int u2attributeNameIndex, int u2maxStack, int u2maxLocals, int u4codeLength, byte[] code, int u2exceptionTableLength, ExceptionInfo[] exceptionTable, int u2attributesCount, Attribute[] attributes) { super(u2attributeNameIndex); this.u2maxStack = u2maxStack; this.u2maxLocals = u2maxLocals; this.u4codeLength = u4codeLength; this.code = code; this.u2exceptionTableLength = u2exceptionTableLength; this.exceptionTable = exceptionTable; this.u2attributesCount = u2attributesCount; this.attributes = attributes; } /** * Returns the (first) attribute with the given name. */ public Attribute getAttribute(Clazz clazz, String name) { for (int index = 0; index < u2attributesCount; index++) { Attribute attribute = attributes[index]; if (attribute.getAttributeName(clazz).equals(name)) { return attribute; } } return null; } // Implementations for Attribute. public void accept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { attributeVisitor.visitCodeAttribute(clazz, method, this); } /** * Applies the given instruction visitor to all instructions. */ public void instructionsAccept(Clazz clazz, Method method, InstructionVisitor instructionVisitor) { instructionsAccept(clazz, method, 0, u4codeLength, instructionVisitor); } /** * Applies the given instruction visitor to the instruction at the specified * offset. */ public void instructionAccept(Clazz clazz, Method method, int offset, InstructionVisitor instructionVisitor) { Instruction instruction = InstructionFactory.create(code, offset); instruction.accept(clazz, method, this, offset, instructionVisitor); } /** * Applies the given instruction visitor to all instructions in the * specified range of offsets. */ public void instructionsAccept(Clazz clazz, Method method, int startOffset, int endOffset, InstructionVisitor instructionVisitor) { int offset = startOffset; while (offset < endOffset) { // Note that the instruction is only volatile. Instruction instruction = InstructionFactory.create(code, offset); int instructionLength = instruction.length(offset); instruction.accept(clazz, method, this, offset, instructionVisitor); offset += instructionLength; } } /** * Applies the given exception visitor to all exceptions. */ public void exceptionsAccept(Clazz clazz, Method method, ExceptionInfoVisitor exceptionInfoVisitor) { for (int index = 0; index < u2exceptionTableLength; index++) { // We don't need double dispatching here, since there is only one // type of ExceptionInfo. exceptionInfoVisitor.visitExceptionInfo(clazz, method, this, exceptionTable[index]); } } /** * Applies the given exception visitor to all exceptions that are applicable * to the instruction at the specified offset. */ public void exceptionsAccept(Clazz clazz, Method method, int offset, ExceptionInfoVisitor exceptionInfoVisitor) { for (int index = 0; index < u2exceptionTableLength; index++) { ExceptionInfo exceptionInfo = exceptionTable[index]; if (exceptionInfo.isApplicable(offset)) { exceptionInfoVisitor.visitExceptionInfo(clazz, method, this, exceptionInfo); } } } /** * Applies the given exception visitor to all exceptions that are applicable * to any of the instructions in the specified range of offsets. */ public void exceptionsAccept(Clazz clazz, Method method, int startOffset, int endOffset, ExceptionInfoVisitor exceptionInfoVisitor) { for (int index = 0; index < u2exceptionTableLength; index++) { ExceptionInfo exceptionInfo = exceptionTable[index]; if (exceptionInfo.isApplicable(startOffset, endOffset)) { exceptionInfoVisitor.visitExceptionInfo(clazz, method, this, exceptionInfo); } } } /** * Applies the given attribute visitor to all attributes. */ public void attributesAccept(Clazz clazz, Method method, AttributeVisitor attributeVisitor) { for (int index = 0; index < u2attributesCount; index++) { attributes[index].accept(clazz, method, this, attributeVisitor); } } } proguard4.8/src/proguard/classfile/attribute/preverification/0000775000175000017500000000000011760503005023333 5ustar ericericproguard4.8/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java0000644000175000017500000000620711736333523031026 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; /** * This class provides methods to create and reuse IntegerType objects. * * @author Eric Lafortune */ public class VerificationTypeFactory { // Shared copies of Type objects, to avoid creating a lot of objects. static final IntegerType INTEGER_TYPE = new IntegerType(); static final LongType LONG_TYPE = new LongType(); static final FloatType FLOAT_TYPE = new FloatType(); static final DoubleType DOUBLE_TYPE = new DoubleType(); static final TopType TOP_TYPE = new TopType(); static final NullType NULL_TYPE = new NullType(); static final UninitializedThisType UNINITIALIZED_THIS_TYPE = new UninitializedThisType(); /** * Creates a new IntegerType. */ public static IntegerType createIntegerType() { return INTEGER_TYPE; } /** * Creates a new LongType. */ public static LongType createLongType() { return LONG_TYPE; } /** * Creates a new FloatType. */ public static FloatType createFloatType() { return FLOAT_TYPE; } /** * Creates a new DoubleType. */ public static DoubleType createDoubleType() { return DOUBLE_TYPE; } /** * Creates a new TopType. */ public static TopType createTopType() { return TOP_TYPE; } /** * Creates a new NullType. */ public static NullType createNullType() { return NULL_TYPE; } /** * Creates a new UninitializedThisType. */ public static UninitializedThisType createUninitializedThisType() { return UNINITIALIZED_THIS_TYPE; } /** * Creates a new UninitializedType for an instance that was created at * the given offset. */ public static UninitializedType createUninitializedType(int newInstructionOffset) { return new UninitializedType(newInstructionOffset); } /** * Creates a new ObjectType of the given type. */ public static ObjectType createObjectType(int classIndex) { return new ObjectType(classIndex); } } proguard4.8/src/proguard/classfile/attribute/preverification/TopType.java0000644000175000017500000000446011736333523025615 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents a Top type. * * @author Eric Lafortune */ public class TopType extends VerificationType { // Implementations for VerificationType. public int getTag() { return TOP_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitTopType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackTopType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesTopType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public String toString() { return "T"; } } proguard4.8/src/proguard/classfile/attribute/preverification/SameZeroFrame.java0000644000175000017500000000420011736333523026701 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.StackMapFrameVisitor; /** * This StackMapFrame represents a "same frame" or a "same frame extended". * * @author Eric Lafortune * @noinspection PointlessArithmeticExpression */ public class SameZeroFrame extends StackMapFrame { /** * Creates an uninitialized SameZeroFrame. */ public SameZeroFrame() { } /** * Creates a SameZeroFrame with the given tag. */ public SameZeroFrame(int tag) { u2offsetDelta = tag - SAME_ZERO_FRAME; } // Implementations for StackMapFrame. public int getTag() { return u2offsetDelta < 64 ? SAME_ZERO_FRAME + u2offsetDelta : SAME_ZERO_FRAME_EXTENDED; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrameVisitor stackMapFrameVisitor) { stackMapFrameVisitor.visitSameZeroFrame(clazz, method, codeAttribute, offset, this); } // Implementations for Object. public String toString() { return super.toString()+"Var: ..., Stack: (empty)"; } } proguard4.8/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java0000644000175000017500000001072111736333523026723 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.*; /** * This StackMapFrame represents an "append frame". * * @author Eric Lafortune */ public class MoreZeroFrame extends StackMapFrame { public int additionalVariablesCount; public VerificationType[] additionalVariables; /** * Creates an uninitialized MoreZeroFrame. */ public MoreZeroFrame() { } /** * Creates a MoreZeroFrame with the given tag. */ public MoreZeroFrame(int tag) { additionalVariablesCount = tag + 1 - MORE_ZERO_FRAME; } /** * Creates a MoreZeroFrame with the given additional variables. */ public MoreZeroFrame(VerificationType[] additionalVariables) { this(additionalVariables.length, additionalVariables); } /** * Creates a MoreZeroFrame with the given additional variables. */ public MoreZeroFrame(int additionalVariablesCount, VerificationType[] additionalVariables) { this.additionalVariablesCount = additionalVariablesCount; this.additionalVariables = additionalVariables; } /** * Applies the given verification type visitor to all variables. */ public void additionalVariablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationTypeVisitor verificationTypeVisitor) { for (int index = 0; index < additionalVariablesCount; index++) { additionalVariables[index].accept(clazz, method, codeAttribute, offset, verificationTypeVisitor); } } // Implementations for StackMapFrame. public int getTag() { return MORE_ZERO_FRAME + additionalVariablesCount - 1; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrameVisitor stackMapFrameVisitor) { stackMapFrameVisitor.visitMoreZeroFrame(clazz, method, codeAttribute, offset, this); } // Implementations for Object. public boolean equals(Object object) { if (!super.equals(object)) { return false; } MoreZeroFrame other = (MoreZeroFrame)object; if (this.u2offsetDelta != other.u2offsetDelta || this.additionalVariablesCount != other.additionalVariablesCount) { return false; } for (int index = 0; index < additionalVariablesCount; index++) { VerificationType thisType = this.additionalVariables[index]; VerificationType otherType = other.additionalVariables[index]; if (!thisType.equals(otherType)) { return false; } } return true; } public int hashCode() { int hashCode = super.hashCode(); for (int index = 0; index < additionalVariablesCount; index++) { hashCode ^= additionalVariables[index].hashCode(); } return hashCode; } public String toString() { StringBuffer buffer = new StringBuffer(super.toString()).append("Var: ..."); for (int index = 0; index < additionalVariablesCount; index++) { buffer = buffer.append('[') .append(additionalVariables[index].toString()) .append(']'); } buffer.append(", Stack: (empty)"); return buffer.toString(); } } proguard4.8/src/proguard/classfile/attribute/preverification/IntegerType.java0000644000175000017500000000451011736333523026444 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents a Integer type. * * @author Eric Lafortune */ public class IntegerType extends VerificationType { // Implementations for VerificationType. public int getTag() { return INTEGER_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitIntegerType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackIntegerType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesIntegerType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public String toString() { return "i"; } } proguard4.8/src/proguard/classfile/attribute/preverification/SameOneFrame.java0000644000175000017500000000607311736333523026515 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.*; /** * This StackMapFrame represents a "same locals 1 stack item frame" or a * "same locals 1 stack item frame extended". * * @author Eric Lafortune */ public class SameOneFrame extends StackMapFrame { public VerificationType stackItem; /** * Creates an uninitialized SameOneFrame. */ public SameOneFrame() { } /** * Creates a SameOneFrame with the given tag. */ public SameOneFrame(int tag) { u2offsetDelta = tag - SAME_ONE_FRAME; } /** * Creates a SameOneFrame with the given stack verification type. */ public SameOneFrame(VerificationType stackItem) { this.stackItem = stackItem; } /** * Applies the given verification type visitor to the stack item. */ public void stackItemAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationTypeVisitor verificationTypeVisitor) { stackItem.accept(clazz, method, codeAttribute, offset, verificationTypeVisitor); } // Implementations for StackMapFrame. public int getTag() { return u2offsetDelta < 64 ? SAME_ONE_FRAME + u2offsetDelta : SAME_ONE_FRAME_EXTENDED; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrameVisitor stackMapFrameVisitor) { stackMapFrameVisitor.visitSameOneFrame(clazz, method, codeAttribute, offset, this); } // Implementations for Object. public boolean equals(Object object) { if (!super.equals(object)) { return false; } SameOneFrame other = (SameOneFrame)object; return this.u2offsetDelta == other.u2offsetDelta && this.stackItem.equals(other.stackItem); } public int hashCode() { return super.hashCode() ^ stackItem.hashCode(); } public String toString() { return super.toString()+"Var: ..., Stack: ["+stackItem.toString()+"]"; } } proguard4.8/src/proguard/classfile/attribute/preverification/ObjectType.java0000644000175000017500000000574311736333523026266 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents an Object type. * * @author Eric Lafortune */ public class ObjectType extends VerificationType { public int u2classIndex; /** * Creates an uninitialized ObjectType. */ public ObjectType() { } /** * Creates an ObjectType that points to the given class constant. */ public ObjectType(int u2classIndex) { this.u2classIndex = u2classIndex; } // Implementations for VerificationType. public int getTag() { return OBJECT_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitObjectType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackObjectType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesObjectType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public boolean equals(Object object) { if (!super.equals(object)) { return false; } ObjectType other = (ObjectType)object; return this.u2classIndex == other.u2classIndex; } public int hashCode() { return super.hashCode() ^ u2classIndex; } public String toString() { return "a:" + u2classIndex; } } proguard4.8/src/proguard/classfile/attribute/preverification/StackMapAttribute.java0000644000175000017500000000560011736333523027575 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.preverification.visitor.StackMapFrameVisitor; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents an exceptions attribute. * * @author Eric Lafortune */ public class StackMapAttribute extends Attribute { public int u2stackMapFramesCount; public FullFrame[] stackMapFrames; /** * Creates an uninitialized ExceptionsAttribute. */ public StackMapAttribute() { } /** * Creates a StackMapTableAttribute with the given stack map frames. */ public StackMapAttribute(FullFrame[] stackMapFrames) { this(stackMapFrames.length, stackMapFrames); } /** * Creates a StackMapTableAttribute with the given stack map frames. */ public StackMapAttribute(int stackMapFramesCount, FullFrame[] stackMapFrames) { this.u2stackMapFramesCount = stackMapFramesCount; this.stackMapFrames = stackMapFrames; } // Implementations for Attribute. public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor) { attributeVisitor.visitStackMapAttribute(clazz, method, codeAttribute, this); } /** * Applies the given stack map frame visitor to all stack map frames. */ public void stackMapFramesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapFrameVisitor stackMapFrameVisitor) { for (int index = 0; index < u2stackMapFramesCount; index++) { FullFrame stackMapFrame = stackMapFrames[index]; // We don't need double dispatching here, since there is only one // type of StackMapFrame. stackMapFrameVisitor.visitFullFrame(clazz, method, codeAttribute, stackMapFrame.getOffsetDelta(), stackMapFrame); } } } proguard4.8/src/proguard/classfile/attribute/preverification/LongType.java0000644000175000017500000000446611736333523025760 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents a Long type. * * @author Eric Lafortune */ public class LongType extends VerificationType { // Implementations for VerificationType. public int getTag() { return LONG_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitLongType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackLongType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesLongType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public String toString() { return "l"; } } proguard4.8/src/proguard/classfile/attribute/preverification/NullType.java0000644000175000017500000000446611736333523025773 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents a Null type. * * @author Eric Lafortune */ public class NullType extends VerificationType { // Implementations for VerificationType. public int getTag() { return NULL_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitNullType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackNullType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesNullType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public String toString() { return "n"; } } proguard4.8/src/proguard/classfile/attribute/preverification/visitor/0000775000175000017500000000000011760503005025032 5ustar ericericproguard4.8/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java0000644000175000017500000000362211736333523031745 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification.visitor; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.*; /** * This interface specifies the methods for a visitor of * StackMapFrame objects. * * @author Eric Lafortune */ public interface StackMapFrameVisitor { public void visitSameZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameZeroFrame sameZeroFrame); public void visitSameOneFrame( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame); public void visitLessZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LessZeroFrame lessZeroFrame); public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame); public void visitFullFrame( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame); } proguard4.8/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java0000644000175000017500000001305611736333523032555 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification.visitor; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.*; /** * This interface specifies the methods for a visitor of * VerificationType objects. There a methods for stack entries * and methods for variable entries. * * @author Eric Lafortune */ public interface VerificationTypeVisitor { public void visitIntegerType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, IntegerType integerType); public void visitFloatType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FloatType floatType); public void visitLongType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LongType longType); public void visitDoubleType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, DoubleType doubleType); public void visitTopType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TopType topType); public void visitObjectType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType); public void visitNullType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, NullType nullType); public void visitUninitializedType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType); public void visitUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedThisType uninitializedThisType); public void visitStackIntegerType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, IntegerType integerType); public void visitStackFloatType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, FloatType floatType); public void visitStackLongType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, LongType longType); public void visitStackDoubleType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, DoubleType doubleType); public void visitStackTopType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, TopType topType); public void visitStackObjectType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, ObjectType objectType); public void visitStackNullType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, NullType nullType); public void visitStackUninitializedType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, UninitializedType uninitializedType); public void visitStackUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, UninitializedThisType uninitializedThisType); public void visitVariablesIntegerType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, IntegerType integerType); public void visitVariablesFloatType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, FloatType floatType); public void visitVariablesLongType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, LongType longType); public void visitVariablesDoubleType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, DoubleType doubleType); public void visitVariablesTopType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, TopType topType); public void visitVariablesObjectType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, ObjectType objectType); public void visitVariablesNullType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, NullType nullType); public void visitVariablesUninitializedType( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, UninitializedType uninitializedType); public void visitVariablesUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, UninitializedThisType uninitializedThisType); } proguard4.8/src/proguard/classfile/attribute/preverification/LessZeroFrame.java0000644000175000017500000000532411736333523026732 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.StackMapFrameVisitor; /** * This StackMapFrame represents an "chop frame". * * @author Eric Lafortune */ public class LessZeroFrame extends StackMapFrame { public int choppedVariablesCount; /** * Creates an uninitialized LessZeroFrame. */ public LessZeroFrame() { } /** * Creates a LessZeroFrame with the given tag. */ public LessZeroFrame(int tag) { choppedVariablesCount = LESS_ZERO_FRAME + 3 - tag; } /** * Creates a LessZeroFrame with the given number of chopped variables. */ public LessZeroFrame(byte choppedVariablesCount) { this.choppedVariablesCount = (int)choppedVariablesCount; } // Implementations for StackMapFrame. public int getTag() { return LESS_ZERO_FRAME + 3 - choppedVariablesCount; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrameVisitor stackMapFrameVisitor) { stackMapFrameVisitor.visitLessZeroFrame(clazz, method, codeAttribute, offset, this); } // Implementations for Object. public boolean equals(Object object) { if (!super.equals(object)) { return false; } LessZeroFrame other = (LessZeroFrame)object; return this.u2offsetDelta == other.u2offsetDelta && this.choppedVariablesCount != other.choppedVariablesCount; } public int hashCode() { return super.hashCode() ^ choppedVariablesCount; } public String toString() { return super.toString()+"Var: (chopped "+choppedVariablesCount+"), Stack: (empty)"; } } proguard4.8/src/proguard/classfile/attribute/preverification/FloatType.java0000644000175000017500000000447411736333523026125 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents a Float type. * * @author Eric Lafortune */ public class FloatType extends VerificationType { // Implementations for VerificationType. public int getTag() { return FLOAT_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitFloatType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackFloatType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesFloatType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public String toString() { return "f"; } } proguard4.8/src/proguard/classfile/attribute/preverification/DoubleType.java0000644000175000017500000000450211736333523026262 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents a Double type. * * @author Eric Lafortune */ public class DoubleType extends VerificationType { // Implementations for VerificationType. public int getTag() { return DOUBLE_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitDoubleType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackDoubleType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesDoubleType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public String toString() { return "d"; } } proguard4.8/src/proguard/classfile/attribute/preverification/UninitializedThisType.java0000644000175000017500000000461211736333523030512 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents a UninitializedThis type. * * @author Eric Lafortune */ public class UninitializedThisType extends VerificationType { // Implementations for VerificationType. public int getTag() { return UNINITIALIZED_THIS_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitUninitializedThisType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackUninitializedThisType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesUninitializedThisType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public String toString() { return "u:this"; } } proguard4.8/src/proguard/classfile/attribute/preverification/StackMapFrame.java0000644000175000017500000000620111736333523026662 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.StackMapFrameVisitor; /** * This abstract class represents a stack map frame. Specific types * of entries are subclassed from it. * * @author Eric Lafortune */ public abstract class StackMapFrame implements VisitorAccepter { public static final int SAME_ZERO_FRAME = 0; public static final int SAME_ONE_FRAME = 64; public static final int SAME_ONE_FRAME_EXTENDED = 247; public static final int LESS_ZERO_FRAME = 248; public static final int SAME_ZERO_FRAME_EXTENDED = 251; public static final int MORE_ZERO_FRAME = 252; public static final int FULL_FRAME = 255; public int u2offsetDelta; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Returns the bytecode offset delta relative to the previous stack map * frame. */ public int getOffsetDelta() { return u2offsetDelta; } // Abstract methods to be implemented by extensions. /** * Returns the stack map frame tag that specifies the entry type. */ public abstract int getTag(); /** * Accepts the given visitor. */ public abstract void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrameVisitor stackMapFrameVisitor); // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } StackMapFrame other = (StackMapFrame)object; return this.u2offsetDelta == other.u2offsetDelta; } public int hashCode() { return getClass().hashCode() ^ u2offsetDelta; } public String toString() { return "[" + u2offsetDelta + "] "; } } proguard4.8/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java0000644000175000017500000000600211736333523030542 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.preverification.visitor.StackMapFrameVisitor; import proguard.classfile.attribute.visitor.AttributeVisitor; /** * This Attribute represents a stack map table attribute. * * @author Eric Lafortune */ public class StackMapTableAttribute extends Attribute { public int u2stackMapFramesCount; public StackMapFrame[] stackMapFrames; /** * Creates an uninitialized StackMapTableAttribute. */ public StackMapTableAttribute() { } /** * Creates a StackMapTableAttribute with the given stack map frames. */ public StackMapTableAttribute(StackMapFrame[] stackMapFrames) { this(stackMapFrames.length, stackMapFrames); } /** * Creates a StackMapTableAttribute with the given stack map frames. */ public StackMapTableAttribute(int stackMapFramesCount, StackMapFrame[] stackMapFrames) { this.u2stackMapFramesCount = stackMapFramesCount; this.stackMapFrames = stackMapFrames; } // Implementations for Attribute. public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor) { attributeVisitor.visitStackMapTableAttribute(clazz, method, codeAttribute, this); } /** * Applies the given stack map frame visitor to all stack map frames. */ public void stackMapFramesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapFrameVisitor stackMapFrameVisitor) { int offset = 0; for (int index = 0; index < u2stackMapFramesCount; index++) { StackMapFrame stackMapFrame = stackMapFrames[index]; // Note that the byte code offset is computed differently for the // first stack map frame. offset += stackMapFrame.getOffsetDelta() + (index == 0 ? 0 : 1); stackMapFrame.accept(clazz, method, codeAttribute, offset, stackMapFrameVisitor); } } } proguard4.8/src/proguard/classfile/attribute/preverification/VerificationType.java0000644000175000017500000000657211736333523027503 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This abstract class represents a verification type of a local variable or * a stack element. Specific verification types are subclassed from it. * * @author Eric Lafortune */ public abstract class VerificationType implements VisitorAccepter { public static final int TOP_TYPE = 0; public static final int INTEGER_TYPE = 1; public static final int FLOAT_TYPE = 2; public static final int DOUBLE_TYPE = 3; public static final int LONG_TYPE = 4; public static final int NULL_TYPE = 5; public static final int UNINITIALIZED_THIS_TYPE = 6; public static final int OBJECT_TYPE = 7; public static final int UNINITIALIZED_TYPE = 8; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Returns the tag of the verification type. */ public abstract int getTag(); /** * Accepts the given visitor in the context of a method's code, either on * a stack or as a variable. */ public abstract void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor); /** * Accepts the given visitor in the context of a stack in a method's code . */ public abstract void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor); /** * Accepts the given visitor in the context of a variable in a method's code. */ public abstract void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor); // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } // Implementations for Object. public boolean equals(Object object) { return object != null && this.getClass() == object.getClass(); } public int hashCode() { return this.getClass().hashCode(); } } proguard4.8/src/proguard/classfile/attribute/preverification/UninitializedType.java0000644000175000017500000000620511736333523027662 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.VerificationTypeVisitor; /** * This VerificationType represents a Uninitialized type. * * @author Eric Lafortune */ public class UninitializedType extends VerificationType { public int u2newInstructionOffset; /** * Creates an uninitialized UninitializedType. */ public UninitializedType() { } /** * Creates an UninitializedType pointing to the given 'new' instruction. */ public UninitializedType(int u2newInstructionOffset) { this.u2newInstructionOffset = u2newInstructionOffset; } // Implementations for VerificationType. public int getTag() { return UNINITIALIZED_TYPE; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitUninitializedType(clazz, method, codeAttribute, instructionOffset, this); } public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int stackIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitStackUninitializedType(clazz, method, codeAttribute, instructionOffset, stackIndex, this); } public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int instructionOffset, int variableIndex, VerificationTypeVisitor verificationTypeVisitor) { verificationTypeVisitor.visitVariablesUninitializedType(clazz, method, codeAttribute, instructionOffset, variableIndex, this); } // Implementations for Object. public boolean equals(Object object) { if (!super.equals(object)) { return false; } UninitializedType other = (UninitializedType)object; return this.u2newInstructionOffset == other.u2newInstructionOffset; } public int hashCode() { return super.hashCode() ^ u2newInstructionOffset; } public String toString() { return "u:" + u2newInstructionOffset; } } proguard4.8/src/proguard/classfile/attribute/preverification/FullFrame.java0000644000175000017500000001314711736333523026070 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.attribute.preverification; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.preverification.visitor.*; /** * This StackMapFrame represents a "full frame". * * @author Eric Lafortune */ public class FullFrame extends StackMapFrame { public int variablesCount; public VerificationType[] variables; public int stackCount; public VerificationType[] stack; /** * Creates an uninitialized FullFrame. */ public FullFrame() { } /** * Creates a FullFrame with the given variables and stack. */ public FullFrame(int offsetDelta, VerificationType[] variables, VerificationType[] stack) { this(offsetDelta, variables.length, variables, stack.length, stack); } /** * Creates a FullFrame with the given variables and stack. */ public FullFrame(int offsetDelta, int variablesCount, VerificationType[] variables, int stackCount, VerificationType[] stack) { this.u2offsetDelta = offsetDelta; this.variablesCount = variablesCount; this.variables = variables; this.stackCount = stackCount; this.stack = stack; } /** * Applies the given verification type visitor to all variables. */ public void variablesAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationTypeVisitor verificationTypeVisitor) { for (int index = 0; index < variablesCount; index++) { variables[index].variablesAccept(clazz, method, codeAttribute, offset, index, verificationTypeVisitor); } } /** * Applies the given verification type visitor to all stack. */ public void stackAccept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationTypeVisitor verificationTypeVisitor) { for (int index = 0; index < stackCount; index++) { stack[index].stackAccept(clazz, method, codeAttribute, offset, index, verificationTypeVisitor); } } // Implementations for StackMapFrame. public int getTag() { return FULL_FRAME; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrameVisitor stackMapFrameVisitor) { stackMapFrameVisitor.visitFullFrame(clazz, method, codeAttribute, offset, this); } // Implementations for Object. public boolean equals(Object object) { if (!super.equals(object)) { return false; } FullFrame other = (FullFrame)object; if (this.u2offsetDelta != other.u2offsetDelta || this.variablesCount != other.variablesCount || this.stackCount != other.stackCount) { return false; } for (int index = 0; index < variablesCount; index++) { VerificationType thisType = this.variables[index]; VerificationType otherType = other.variables[index]; if (!thisType.equals(otherType)) { return false; } } for (int index = 0; index < stackCount; index++) { VerificationType thisType = this.stack[index]; VerificationType otherType = other.stack[index]; if (!thisType.equals(otherType)) { return false; } } return true; } public int hashCode() { int hashCode = super.hashCode(); for (int index = 0; index < variablesCount; index++) { hashCode ^= variables[index].hashCode(); } for (int index = 0; index < stackCount; index++) { hashCode ^= stack[index].hashCode(); } return hashCode; } public String toString() { StringBuffer buffer = new StringBuffer(super.toString()).append("Var: "); for (int index = 0; index < variablesCount; index++) { buffer = buffer.append('[') .append(variables[index].toString()) .append(']'); } buffer.append(", Stack: "); for (int index = 0; index < stackCount; index++) { buffer = buffer.append('[') .append(stack[index].toString()) .append(']'); } return buffer.toString(); } } proguard4.8/src/proguard/classfile/ClassPool.java0000664000175000017500000001002011740556650020706 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.util.ClassUtil; import proguard.classfile.visitor.*; import java.util.*; /** * This is a set of representations of classes. They can be enumerated or * retrieved by name. They can also be accessed by means of class visitors. * * @author Eric Lafortune */ public class ClassPool { // We're using a sorted tree map instead of a hash map to store the classes, // in order to make the processing more deterministic. private final Map classes = new TreeMap(); /** * Clears the class pool. */ public void clear() { classes.clear(); } /** * Adds the given Clazz to the class pool. */ public void addClass(Clazz clazz) { classes.put(clazz.getName(), clazz); } /** * Removes the given Clazz from the class pool. */ public void removeClass(Clazz clazz) { removeClass(clazz.getName()); } /** * Removes the specified Clazz from the class pool. */ public void removeClass(String className) { classes.remove(className); } /** * Returns a Clazz from the class pool based on its name. Returns * null if the class with the given name is not in the class * pool. */ public Clazz getClass(String className) { return (Clazz)classes.get(className); } /** * Returns an Iterator of all class names in the class pool. */ public Iterator classNames() { return classes.keySet().iterator(); } /** * Returns the number of classes in the class pool. */ public int size() { return classes.size(); } /** * Applies the given ClassPoolVisitor to the class pool. */ public void accept(ClassPoolVisitor classPoolVisitor) { classPoolVisitor.visitClassPool(this); } /** * Applies the given ClassVisitor to all classes in the class pool, * in random order. */ public void classesAccept(ClassVisitor classVisitor) { Iterator iterator = classes.values().iterator(); while (iterator.hasNext()) { Clazz clazz = (Clazz)iterator.next(); clazz.accept(classVisitor); } } /** * Applies the given ClassVisitor to all classes in the class pool, * in sorted order. */ public void classesAcceptAlphabetically(ClassVisitor classVisitor) { // We're already using a tree map. //TreeMap sortedClasses = new TreeMap(classes); //Iterator iterator = sortedClasses.values().iterator(); Iterator iterator = classes.values().iterator(); while (iterator.hasNext()) { Clazz clazz = (Clazz)iterator.next(); clazz.accept(classVisitor); } } /** * Applies the given ClassVisitor to the class with the given name, * if it is present in the class pool. */ public void classAccept(String className, ClassVisitor classVisitor) { Clazz clazz = getClass(className); if (clazz != null) { clazz.accept(classVisitor); } } } proguard4.8/src/proguard/classfile/Clazz.java0000644000175000017500000002047411736333523020103 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.visitor.*; /** * This interface provides access to the representation of a Java class. * * @author Eric Lafortune */ public interface Clazz extends VisitorAccepter { /** * Returns the access flags of this class. * @see ClassConstants */ public int getAccessFlags(); /** * Returns the full internal name of this class. */ public String getName(); /** * Returns the full internal name of the super class of this class, or * null if this class represents java.lang.Object. */ public String getSuperName(); /** * Returns the number of interfaces that this class implements. */ public int getInterfaceCount(); /** * Returns the full internal name of the interface at the given index of * this class. */ public String getInterfaceName(int index); /** * Returns the tag value of the Constant at the specified index. */ public int getTag(int constantIndex); /** * Returns the String value of the Utf8Constant at the specified index. */ public String getString(int constantIndex); /** * Returns the String value of the StringConstant at the specified index. */ public String getStringString(int constantIndex); /** * Returns the class name of ClassConstant at the specified index. */ public String getClassName(int constantIndex); /** * Returns the name of the NameAndTypeConstant at the specified index. */ public String getName(int constantIndex); /** * Returns the type of the NameAndTypeConstant at the specified index. */ public String getType(int constantIndex); /** * Returns the name of the RefConstant at the specified index. */ public String getRefName(int constantIndex); /** * Returns the type of the RefConstant at the specified index. */ public String getRefType(int constantIndex); // Methods pertaining to related classes. /** * Notifies this Clazz that it is being subclassed by another class. */ public void addSubClass(Clazz clazz); /** * Returns the super class of this class. */ public Clazz getSuperClass(); /** * Returns the interface at the given index. */ public Clazz getInterface(int index); /** * Returns whether this class extends the given class. * A class is always considered to extend itself. * Interfaces are considered to only extend the root Object class. */ public boolean extends_(Clazz clazz); /** * Returns whether this class extends the specified class. * A class is always considered to extend itself. * Interfaces are considered to only extend the root Object class. */ public boolean extends_(String className); /** * Returns whether this class implements the given class. * A class is always considered to implement itself. * Interfaces are considered to implement all their superinterfaces. */ public boolean extendsOrImplements(Clazz clazz); /** * Returns whether this class implements the specified class. * A class is always considered to implement itself. * Interfaces are considered to implement all their superinterfaces. */ public boolean extendsOrImplements(String className); // Methods for getting specific class members. /** * Returns the field with the given name and descriptor. */ Field findField(String name, String descriptor); /** * Returns the method with the given name and descriptor. */ Method findMethod(String name, String descriptor); // Methods for accepting various types of visitors. /** * Accepts the given class visitor. */ public void accept(ClassVisitor classVisitor); /** * Accepts the given class visitor in the class hierarchy. * @param visitThisClass specifies whether to visit this class. * @param visitSuperClass specifies whether to visit the super classes. * @param visitInterfaces specifies whether to visit the interfaces. * @param visitSubclasses specifies whether to visit the subclasses. * @param classVisitor the ClassVisitor that will * visit the class hierarchy. */ public void hierarchyAccept(boolean visitThisClass, boolean visitSuperClass, boolean visitInterfaces, boolean visitSubclasses, ClassVisitor classVisitor); /** * Lets the given class visitor visit all known subclasses. * @param classVisitor the ClassVisitor that will visit the * subclasses. */ public void subclassesAccept(ClassVisitor classVisitor); /** * Lets the given constant pool entry visitor visit all constant pool entries * of this class. */ public void constantPoolEntriesAccept(ConstantVisitor constantVisitor); /** * Lets the given constant pool entry visitor visit the constant pool entry * at the specified index. */ public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor); /** * Lets the given constant pool entry visitor visit the class constant pool * entry of this class. */ public void thisClassConstantAccept(ConstantVisitor constantVisitor); /** * Lets the given constant pool entry visitor visit the class constant pool * entry of the super class of this class, if there is one. */ public void superClassConstantAccept(ConstantVisitor constantVisitor); /** * Lets the given constant pool entry visitor visit the class constant pool * entries for all interfaces of this class. */ public void interfaceConstantsAccept(ConstantVisitor constantVisitor); /** * Lets the given member info visitor visit all fields of this class. */ public void fieldsAccept(MemberVisitor memberVisitor); /** * Lets the given member info visitor visit the specified field. */ public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor); /** * Lets the given member info visitor visit all methods of this class. */ public void methodsAccept(MemberVisitor memberVisitor); /** * Lets the given member info visitor visit the specified method. */ public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor); /** * Returns whether the given method may possibly have implementing or * overriding methods down the class hierarchy. This can only be true * if the class is not final, and the method is not private, static, or * final, or a constructor. * @param method the method that may have implementations. * @return whether it may have implementations. */ public boolean mayHaveImplementations(Method method); /** * Lets the given attribute info visitor visit all attributes of this class. */ public void attributesAccept(AttributeVisitor attributeVisitor); /** * Lets the given attribute info visitor visit the specified attribute. */ public void attributeAccept(String name, AttributeVisitor attributeVisitor); } proguard4.8/src/proguard/classfile/LibraryClass.java0000644000175000017500000003570311736333523021413 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** * This Clazz is a compact representation of the essential data in a Java class. * * @author Eric Lafortune */ public class LibraryClass implements Clazz { public int u2accessFlags; public String thisClassName; public String superClassName; public String[] interfaceNames; public LibraryField[] fields; public LibraryMethod[] methods; /** * An extra field pointing to the superclass of this class. * This field is filled out by the {@link ClassSuperHierarchyInitializer}. */ public Clazz superClass; /** * An extra field pointing to the interfaces of this class. * This field is filled out by the {@link ClassSuperHierarchyInitializer}. */ public Clazz[] interfaceClasses; /** * An extra field pointing to the subclasses of this class. * This field is filled out by the {@link ClassSubHierarchyInitializer}. */ public Clazz[] subClasses; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Creates an empty LibraryClass. */ public LibraryClass() {} /** * Returns whether this library class is visible to the outside world. */ boolean isVisible() { return (u2accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0; } // Implementations for Clazz. public int getAccessFlags() { return u2accessFlags; } public String getName() { return thisClassName; } public String getSuperName() { // This may be java/lang/Object, in which case there is no super. return superClassName; } public int getInterfaceCount() { return interfaceClasses.length; } public String getInterfaceName(int index) { return interfaceNames[index]; } public int getTag(int constantIndex) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); } public String getString(int constantIndex) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); } public String getStringString(int constantIndex) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); } public String getClassName(int constantIndex) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); } public String getName(int constantIndex) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); } public String getType(int constantIndex) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); } public String getRefName(int constantIndex) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); } public String getRefType(int constantIndex) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool"); } public void addSubClass(Clazz clazz) { if (subClasses == null) { subClasses = new Clazz[1]; } else { // Copy the old elements into new larger array. Clazz[] temp = new Clazz[subClasses.length+1]; System.arraycopy(subClasses, 0, temp, 0, subClasses.length); subClasses = temp; } subClasses[subClasses.length-1] = clazz; } public Clazz getSuperClass() { return superClass; } public Clazz getInterface(int index) { return interfaceClasses[index]; } public boolean extends_(Clazz clazz) { if (this.equals(clazz)) { return true; } return superClass != null && superClass.extends_(clazz); } public boolean extends_(String className) { if (getName().equals(className)) { return true; } return superClass != null && superClass.extends_(className); } public boolean extendsOrImplements(Clazz clazz) { if (this.equals(clazz)) { return true; } if (superClass != null && superClass.extendsOrImplements(clazz)) { return true; } if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { Clazz interfaceClass = interfaceClasses[index]; if (interfaceClass != null && interfaceClass.extendsOrImplements(clazz)) { return true; } } } return false; } public boolean extendsOrImplements(String className) { if (getName().equals(className)) { return true; } if (superClass != null && superClass.extendsOrImplements(className)) { return true; } if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { Clazz interfaceClass = interfaceClasses[index]; if (interfaceClass != null && interfaceClass.extendsOrImplements(className)) { return true; } } } return false; } public Field findField(String name, String descriptor) { for (int index = 0; index < fields.length; index++) { Field field = fields[index]; if (field != null && (name == null || field.getName(this).equals(name)) && (descriptor == null || field.getDescriptor(this).equals(descriptor))) { return field; } } return null; } public Method findMethod(String name, String descriptor) { for (int index = 0; index < methods.length; index++) { Method method = methods[index]; if (method != null && (name == null || method.getName(this).equals(name)) && (descriptor == null || method.getDescriptor(this).equals(descriptor))) { return method; } } return null; } public void accept(ClassVisitor classVisitor) { classVisitor.visitLibraryClass(this); } public void hierarchyAccept(boolean visitThisClass, boolean visitSuperClass, boolean visitInterfaces, boolean visitSubclasses, ClassVisitor classVisitor) { // First visit the current classfile. if (visitThisClass) { accept(classVisitor); } // Then visit its superclass, recursively. if (visitSuperClass) { if (superClass != null) { superClass.hierarchyAccept(true, true, visitInterfaces, false, classVisitor); } } // Then visit its interfaces, recursively. if (visitInterfaces) { // Visit the interfaces of the superclasses, if we haven't done so yet. if (!visitSuperClass) { if (superClass != null) { superClass.hierarchyAccept(false, false, true, false, classVisitor); } } // Visit the interfaces. if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { Clazz interfaceClass = interfaceClasses[index]; if (interfaceClass != null) { interfaceClass.hierarchyAccept(true, false, true, false, classVisitor); } } } } // Then visit its subclasses, recursively. if (visitSubclasses) { if (subClasses != null) { for (int index = 0; index < subClasses.length; index++) { subClasses[index].hierarchyAccept(true, false, false, true, classVisitor); } } } } /** * Lets the given class visitor visit the superclass, if it is known. * @param classVisitor the ClassVisitor that will visit the * superclass. */ public void superClassAccept(ClassVisitor classVisitor) { if (superClass != null) { superClass.accept(classVisitor); } } /** * Lets the given class visitor visit all known direct interfaces. * @param classVisitor the ClassVisitor that will visit the * interfaces. */ public void interfacesAccept(ClassVisitor classVisitor) { if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { Clazz interfaceClass = interfaceClasses[index]; if (interfaceClass != null) { interfaceClass.accept(classVisitor); } } } } public void subclassesAccept(ClassVisitor classVisitor) { if (subClasses != null) { for (int index = 0; index < subClasses.length; index++) { subClasses[index].accept(classVisitor); } } } public void constantPoolEntriesAccept(ConstantVisitor constantVisitor) { // This class doesn't keep references to its constant pool entries. } public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor) { // This class doesn't keep references to its constant pool entries. } public void thisClassConstantAccept(ConstantVisitor constantVisitor) { // This class doesn't keep references to its constant pool entries. } public void superClassConstantAccept(ConstantVisitor constantVisitor) { // This class doesn't keep references to its constant pool entries. } public void interfaceConstantsAccept(ConstantVisitor constantVisitor) { // This class doesn't keep references to its constant pool entries. } public void fieldsAccept(MemberVisitor memberVisitor) { for (int index = 0; index < fields.length; index++) { Field field = fields[index]; if (field != null) { field.accept(this, memberVisitor); } } } public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor) { Field field = findField(name, descriptor); if (field != null) { field.accept(this, memberVisitor); } } public void methodsAccept(MemberVisitor memberVisitor) { for (int index = 0; index < methods.length; index++) { Method method = methods[index]; if (method != null) { method.accept(this, memberVisitor); } } } public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor) { Method method = findMethod(name, descriptor); if (method != null) { method.accept(this, memberVisitor); } } public boolean mayHaveImplementations(Method method) { return (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 && (method == null || ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_FINAL)) == 0 && !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))); } public void attributesAccept(AttributeVisitor attributeVisitor) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes"); } public void attributeAccept(String name, AttributeVisitor attributeVisitor) { throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes"); } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } // Implementations for Object. public String toString() { return "LibraryClass("+getName()+")"; } } proguard4.8/src/proguard/classfile/io/0000775000175000017500000000000011760503005016546 5ustar ericericproguard4.8/src/proguard/classfile/io/ProgramClassReader.java0000664000175000017500000011614611736333523023153 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.io; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.io.DataInput; /** * This ClassVisitor fills out the ProgramClass objects that it visits with data * from the given DataInput object. * * @author Eric Lafortune */ public class ProgramClassReader extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor, BootstrapMethodInfoVisitor, InnerClassesInfoVisitor, ExceptionInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LineNumberInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { private final RuntimeDataInput dataInput; /** * Creates a new ProgramClassReader for reading from the given DataInput. */ public ProgramClassReader(DataInput dataInput) { this.dataInput = new RuntimeDataInput(dataInput); } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Read and check the magic number. programClass.u4magic = dataInput.readInt(); ClassUtil.checkMagicNumber(programClass.u4magic); // Read and check the version numbers. int u2minorVersion = dataInput.readUnsignedShort(); int u2majorVersion = dataInput.readUnsignedShort(); programClass.u4version = ClassUtil.internalClassVersion(u2majorVersion, u2minorVersion); ClassUtil.checkVersionNumbers(programClass.u4version); // Read the constant pool. Note that the first entry is not used. programClass.u2constantPoolCount = dataInput.readUnsignedShort(); programClass.constantPool = new Constant[programClass.u2constantPoolCount]; for (int index = 1; index < programClass.u2constantPoolCount; index++) { Constant constant = createConstant(); constant.accept(programClass, this); programClass.constantPool[index] = constant; // Long constants and double constants take up two entries in the // constant pool. int tag = constant.getTag(); if (tag == ClassConstants.CONSTANT_Long || tag == ClassConstants.CONSTANT_Double) { programClass.constantPool[++index] = null; } } // Read the general class information. programClass.u2accessFlags = dataInput.readUnsignedShort(); programClass.u2thisClass = dataInput.readUnsignedShort(); programClass.u2superClass = dataInput.readUnsignedShort(); // Read the interfaces. programClass.u2interfacesCount = dataInput.readUnsignedShort(); programClass.u2interfaces = new int[programClass.u2interfacesCount]; for (int index = 0; index < programClass.u2interfacesCount; index++) { programClass.u2interfaces[index] = dataInput.readUnsignedShort(); } // Read the fields. programClass.u2fieldsCount = dataInput.readUnsignedShort(); programClass.fields = new ProgramField[programClass.u2fieldsCount]; for (int index = 0; index < programClass.u2fieldsCount; index++) { ProgramField programField = new ProgramField(); this.visitProgramField(programClass, programField); programClass.fields[index] = programField; } // Read the methods. programClass.u2methodsCount = dataInput.readUnsignedShort(); programClass.methods = new ProgramMethod[programClass.u2methodsCount]; for (int index = 0; index < programClass.u2methodsCount; index++) { ProgramMethod programMethod = new ProgramMethod(); this.visitProgramMethod(programClass, programMethod); programClass.methods[index] = programMethod; } // Read the class attributes. programClass.u2attributesCount = dataInput.readUnsignedShort(); programClass.attributes = new Attribute[programClass.u2attributesCount]; for (int index = 0; index < programClass.u2attributesCount; index++) { Attribute attribute = createAttribute(programClass); attribute.accept(programClass, this); programClass.attributes[index] = attribute; } } public void visitLibraryClass(LibraryClass libraryClass) { } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Read the general field information. programField.u2accessFlags = dataInput.readUnsignedShort(); programField.u2nameIndex = dataInput.readUnsignedShort(); programField.u2descriptorIndex = dataInput.readUnsignedShort(); // Read the field attributes. programField.u2attributesCount = dataInput.readUnsignedShort(); programField.attributes = new Attribute[programField.u2attributesCount]; for (int index = 0; index < programField.u2attributesCount; index++) { Attribute attribute = createAttribute(programClass); attribute.accept(programClass, programField, this); programField.attributes[index] = attribute; } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Read the general method information. programMethod.u2accessFlags = dataInput.readUnsignedShort(); programMethod.u2nameIndex = dataInput.readUnsignedShort(); programMethod.u2descriptorIndex = dataInput.readUnsignedShort(); // Read the method attributes. programMethod.u2attributesCount = dataInput.readUnsignedShort(); programMethod.attributes = new Attribute[programMethod.u2attributesCount]; for (int index = 0; index < programMethod.u2attributesCount; index++) { Attribute attribute = createAttribute(programClass); attribute.accept(programClass, programMethod, this); programMethod.attributes[index] = attribute; } } public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) { } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { integerConstant.u4value = dataInput.readInt(); } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { longConstant.u8value = dataInput.readLong(); } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { floatConstant.f4value = dataInput.readFloat(); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { doubleConstant.f8value = dataInput.readDouble(); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { stringConstant.u2stringIndex = dataInput.readUnsignedShort(); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { int u2length = dataInput.readUnsignedShort(); // Read the UTF-8 bytes. byte[] bytes = new byte[u2length]; dataInput.readFully(bytes); utf8Constant.setBytes(bytes); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { invokeDynamicConstant.u2bootstrapMethodAttributeIndex = dataInput.readUnsignedShort(); invokeDynamicConstant.u2nameAndTypeIndex = dataInput.readUnsignedShort(); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { methodHandleConstant.u1referenceKind = dataInput.readUnsignedByte(); methodHandleConstant.u2referenceIndex = dataInput.readUnsignedShort(); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { refConstant.u2classIndex = dataInput.readUnsignedShort(); refConstant.u2nameAndTypeIndex = dataInput.readUnsignedShort(); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.u2nameIndex = dataInput.readUnsignedShort(); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { methodTypeConstant.u2descriptorIndex = dataInput.readUnsignedShort(); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { nameAndTypeConstant.u2nameIndex = dataInput.readUnsignedShort(); nameAndTypeConstant.u2descriptorIndex = dataInput.readUnsignedShort(); } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { // Read the unknown information. byte[] info = new byte[unknownAttribute.u4attributeLength]; dataInput.readFully(info); unknownAttribute.info = info; } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { // Read the bootstrap methods. bootstrapMethodsAttribute.u2bootstrapMethodsCount = dataInput.readUnsignedShort(); bootstrapMethodsAttribute.bootstrapMethods = new BootstrapMethodInfo[bootstrapMethodsAttribute.u2bootstrapMethodsCount]; for (int index = 0; index < bootstrapMethodsAttribute.u2bootstrapMethodsCount; index++) { BootstrapMethodInfo bootstrapMethodInfo = new BootstrapMethodInfo(); visitBootstrapMethodInfo(clazz, bootstrapMethodInfo); bootstrapMethodsAttribute.bootstrapMethods[index] = bootstrapMethodInfo; } } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { sourceFileAttribute.u2sourceFileIndex = dataInput.readUnsignedShort(); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { sourceDirAttribute.u2sourceDirIndex = dataInput.readUnsignedShort(); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Read the inner classes. innerClassesAttribute.u2classesCount = dataInput.readUnsignedShort(); innerClassesAttribute.classes = new InnerClassesInfo[innerClassesAttribute.u2classesCount]; for (int index = 0; index < innerClassesAttribute.u2classesCount; index++) { InnerClassesInfo innerClassesInfo = new InnerClassesInfo(); visitInnerClassesInfo(clazz, innerClassesInfo); innerClassesAttribute.classes[index] = innerClassesInfo; } } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { enclosingMethodAttribute.u2classIndex = dataInput.readUnsignedShort(); enclosingMethodAttribute.u2nameAndTypeIndex = dataInput.readUnsignedShort(); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { // This attribute does not contain any additional information. } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { // This attribute does not contain any additional information. } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { signatureAttribute.u2signatureIndex = dataInput.readUnsignedShort(); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { constantValueAttribute.u2constantValueIndex = dataInput.readUnsignedShort(); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { // Read the exceptions. exceptionsAttribute.u2exceptionIndexTableLength = dataInput.readUnsignedShort(); exceptionsAttribute.u2exceptionIndexTable = new int[exceptionsAttribute.u2exceptionIndexTableLength]; for (int index = 0; index < exceptionsAttribute.u2exceptionIndexTableLength; index++) { exceptionsAttribute.u2exceptionIndexTable[index] = dataInput.readUnsignedShort(); } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Read the stack size and local variable frame size. codeAttribute.u2maxStack = dataInput.readUnsignedShort(); codeAttribute.u2maxLocals = dataInput.readUnsignedShort(); // Read the byte code. codeAttribute.u4codeLength = dataInput.readInt(); byte[] code = new byte[codeAttribute.u4codeLength]; dataInput.readFully(code); codeAttribute.code = code; // Read the exceptions. codeAttribute.u2exceptionTableLength = dataInput.readUnsignedShort(); codeAttribute.exceptionTable = new ExceptionInfo[codeAttribute.u2exceptionTableLength]; for (int index = 0; index < codeAttribute.u2exceptionTableLength; index++) { ExceptionInfo exceptionInfo = new ExceptionInfo(); visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo); codeAttribute.exceptionTable[index] = exceptionInfo; } // Read the code attributes. codeAttribute.u2attributesCount = dataInput.readUnsignedShort(); codeAttribute.attributes = new Attribute[codeAttribute.u2attributesCount]; for (int index = 0; index < codeAttribute.u2attributesCount; index++) { Attribute attribute = createAttribute(clazz); attribute.accept(clazz, method, codeAttribute, this); codeAttribute.attributes[index] = attribute; } } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { // Read the stack map frames (only full frames, without tag). stackMapAttribute.u2stackMapFramesCount = dataInput.readUnsignedShort(); stackMapAttribute.stackMapFrames = new FullFrame[stackMapAttribute.u2stackMapFramesCount]; for (int index = 0; index < stackMapAttribute.u2stackMapFramesCount; index++) { FullFrame stackMapFrame = new FullFrame(); visitFullFrame(clazz, method, codeAttribute, index, stackMapFrame); stackMapAttribute.stackMapFrames[index] = stackMapFrame; } } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { // Read the stack map frames. stackMapTableAttribute.u2stackMapFramesCount = dataInput.readUnsignedShort(); stackMapTableAttribute.stackMapFrames = new StackMapFrame[stackMapTableAttribute.u2stackMapFramesCount]; for (int index = 0; index < stackMapTableAttribute.u2stackMapFramesCount; index++) { StackMapFrame stackMapFrame = createStackMapFrame(); stackMapFrame.accept(clazz, method, codeAttribute, 0, this); stackMapTableAttribute.stackMapFrames[index] = stackMapFrame; } } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { // Read the line numbers. lineNumberTableAttribute.u2lineNumberTableLength = dataInput.readUnsignedShort(); lineNumberTableAttribute.lineNumberTable = new LineNumberInfo[lineNumberTableAttribute.u2lineNumberTableLength]; for (int index = 0; index < lineNumberTableAttribute.u2lineNumberTableLength; index++) { LineNumberInfo lineNumberInfo = new LineNumberInfo(); visitLineNumberInfo(clazz, method, codeAttribute, lineNumberInfo); lineNumberTableAttribute.lineNumberTable[index] = lineNumberInfo; } } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Read the local variables. localVariableTableAttribute.u2localVariableTableLength = dataInput.readUnsignedShort(); localVariableTableAttribute.localVariableTable = new LocalVariableInfo[localVariableTableAttribute.u2localVariableTableLength]; for (int index = 0; index < localVariableTableAttribute.u2localVariableTableLength; index++) { LocalVariableInfo localVariableInfo = new LocalVariableInfo(); visitLocalVariableInfo(clazz, method, codeAttribute, localVariableInfo); localVariableTableAttribute.localVariableTable[index] = localVariableInfo; } } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Read the local variable types. localVariableTypeTableAttribute.u2localVariableTypeTableLength = dataInput.readUnsignedShort(); localVariableTypeTableAttribute.localVariableTypeTable = new LocalVariableTypeInfo[localVariableTypeTableAttribute.u2localVariableTypeTableLength]; for (int index = 0; index < localVariableTypeTableAttribute.u2localVariableTypeTableLength; index++) { LocalVariableTypeInfo localVariableTypeInfo = new LocalVariableTypeInfo(); visitLocalVariableTypeInfo(clazz, method, codeAttribute, localVariableTypeInfo); localVariableTypeTableAttribute.localVariableTypeTable[index] = localVariableTypeInfo; } } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Read the annotations. annotationsAttribute.u2annotationsCount = dataInput.readUnsignedShort(); annotationsAttribute.annotations = new Annotation[annotationsAttribute.u2annotationsCount]; for (int index = 0; index < annotationsAttribute.u2annotationsCount; index++) { Annotation annotation = new Annotation(); visitAnnotation(clazz, annotation); annotationsAttribute.annotations[index] = annotation; } } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Read the parameter annotations. parameterAnnotationsAttribute.u2parametersCount = dataInput.readUnsignedByte(); // The java compilers of JDK 1.5, JDK 1.6, and Eclipse all count the // number of parameters of constructors of non-static inner classes // incorrectly. Fix it right here. int parameterStart = 0; if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { int realParametersCount = ClassUtil.internalMethodParameterCount(method.getDescriptor(clazz)); parameterStart = realParametersCount - parameterAnnotationsAttribute.u2parametersCount; parameterAnnotationsAttribute.u2parametersCount = realParametersCount; } parameterAnnotationsAttribute.u2parameterAnnotationsCount = new int[parameterAnnotationsAttribute.u2parametersCount]; parameterAnnotationsAttribute.parameterAnnotations = new Annotation[parameterAnnotationsAttribute.u2parametersCount][]; for (int parameterIndex = parameterStart; parameterIndex < parameterAnnotationsAttribute.u2parametersCount; parameterIndex++) { // Read the parameter annotations of the given parameter. int u2annotationsCount = dataInput.readUnsignedShort(); Annotation[] annotations = new Annotation[u2annotationsCount]; for (int index = 0; index < u2annotationsCount; index++) { Annotation annotation = new Annotation(); visitAnnotation(clazz, annotation); annotations[index] = annotation; } parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex] = u2annotationsCount; parameterAnnotationsAttribute.parameterAnnotations[parameterIndex] = annotations; } } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Read the default element value. ElementValue elementValue = createElementValue(); elementValue.accept(clazz, null, this); annotationDefaultAttribute.defaultValue = elementValue; } // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { bootstrapMethodInfo.u2methodHandleIndex = dataInput.readUnsignedShort(); // Read the bootstrap method arguments. bootstrapMethodInfo.u2methodArgumentCount = dataInput.readUnsignedShort(); bootstrapMethodInfo.u2methodArguments = new int[bootstrapMethodInfo.u2methodArgumentCount]; for (int index = 0; index < bootstrapMethodInfo.u2methodArgumentCount; index++) { bootstrapMethodInfo.u2methodArguments[index] = dataInput.readUnsignedShort(); } } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { innerClassesInfo.u2innerClassIndex = dataInput.readUnsignedShort(); innerClassesInfo.u2outerClassIndex = dataInput.readUnsignedShort(); innerClassesInfo.u2innerNameIndex = dataInput.readUnsignedShort(); innerClassesInfo.u2innerClassAccessFlags = dataInput.readUnsignedShort(); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { exceptionInfo.u2startPC = dataInput.readUnsignedShort(); exceptionInfo.u2endPC = dataInput.readUnsignedShort(); exceptionInfo.u2handlerPC = dataInput.readUnsignedShort(); exceptionInfo.u2catchType = dataInput.readUnsignedShort(); } // Implementations for StackMapFrameVisitor. public void visitSameZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameZeroFrame sameZeroFrame) { if (sameZeroFrame.getTag() == StackMapFrame.SAME_ZERO_FRAME_EXTENDED) { sameZeroFrame.u2offsetDelta = dataInput.readUnsignedShort(); } } public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { if (sameOneFrame.getTag() == StackMapFrame.SAME_ONE_FRAME_EXTENDED) { sameOneFrame.u2offsetDelta = dataInput.readUnsignedShort(); } // Read the verification type of the stack entry. VerificationType verificationType = createVerificationType(); verificationType.accept(clazz, method, codeAttribute, offset, this); sameOneFrame.stackItem = verificationType; } public void visitLessZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LessZeroFrame lessZeroFrame) { lessZeroFrame.u2offsetDelta = dataInput.readUnsignedShort(); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { moreZeroFrame.u2offsetDelta = dataInput.readUnsignedShort(); // Read the verification types of the additional local variables. moreZeroFrame.additionalVariables = new VerificationType[moreZeroFrame.additionalVariablesCount]; for (int index = 0; index < moreZeroFrame.additionalVariablesCount; index++) { VerificationType verificationType = createVerificationType(); verificationType.accept(clazz, method, codeAttribute, offset, this); moreZeroFrame.additionalVariables[index] = verificationType; } } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { fullFrame.u2offsetDelta = dataInput.readUnsignedShort(); // Read the verification types of the local variables. fullFrame.variablesCount = dataInput.readUnsignedShort(); fullFrame.variables = new VerificationType[fullFrame.variablesCount]; for (int index = 0; index < fullFrame.variablesCount; index++) { VerificationType verificationType = createVerificationType(); verificationType.variablesAccept(clazz, method, codeAttribute, offset, index, this); fullFrame.variables[index] = verificationType; } // Read the verification types of the stack entries. fullFrame.stackCount = dataInput.readUnsignedShort(); fullFrame.stack = new VerificationType[fullFrame.stackCount]; for (int index = 0; index < fullFrame.stackCount; index++) { VerificationType verificationType = createVerificationType(); verificationType.stackAccept(clazz, method, codeAttribute, offset, index, this); fullFrame.stack[index] = verificationType; } } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) { // Most verification types don't contain any additional information. } public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) { objectType.u2classIndex = dataInput.readUnsignedShort(); } public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType) { uninitializedType.u2newInstructionOffset = dataInput.readUnsignedShort(); } // Implementations for LineNumberInfoVisitor. public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) { lineNumberInfo.u2startPC = dataInput.readUnsignedShort(); lineNumberInfo.u2lineNumber = dataInput.readUnsignedShort(); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { localVariableInfo.u2startPC = dataInput.readUnsignedShort(); localVariableInfo.u2length = dataInput.readUnsignedShort(); localVariableInfo.u2nameIndex = dataInput.readUnsignedShort(); localVariableInfo.u2descriptorIndex = dataInput.readUnsignedShort(); localVariableInfo.u2index = dataInput.readUnsignedShort(); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { localVariableTypeInfo.u2startPC = dataInput.readUnsignedShort(); localVariableTypeInfo.u2length = dataInput.readUnsignedShort(); localVariableTypeInfo.u2nameIndex = dataInput.readUnsignedShort(); localVariableTypeInfo.u2signatureIndex = dataInput.readUnsignedShort(); localVariableTypeInfo.u2index = dataInput.readUnsignedShort(); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { // Read the annotation type. annotation.u2typeIndex = dataInput.readUnsignedShort(); // Read the element value pairs. annotation.u2elementValuesCount = dataInput.readUnsignedShort(); annotation.elementValues = new ElementValue[annotation.u2elementValuesCount]; for (int index = 0; index < annotation.u2elementValuesCount; index++) { int u2elementNameIndex = dataInput.readUnsignedShort(); ElementValue elementValue = createElementValue(); elementValue.u2elementNameIndex = u2elementNameIndex; elementValue.accept(clazz, annotation, this); annotation.elementValues[index] = elementValue; } } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { constantElementValue.u2constantValueIndex = dataInput.readUnsignedShort(); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { enumConstantElementValue.u2typeNameIndex = dataInput.readUnsignedShort(); enumConstantElementValue.u2constantNameIndex = dataInput.readUnsignedShort(); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { classElementValue.u2classInfoIndex = dataInput.readUnsignedShort(); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { // Read the annotation. Annotation annotationValue = new Annotation(); visitAnnotation(clazz, annotationValue); annotationElementValue.annotationValue = annotationValue; } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { // Read the element values. arrayElementValue.u2elementValuesCount = dataInput.readUnsignedShort(); arrayElementValue.elementValues = new ElementValue[arrayElementValue.u2elementValuesCount]; for (int index = 0; index < arrayElementValue.u2elementValuesCount; index++) { ElementValue elementValue = createElementValue(); elementValue.accept(clazz, annotation, this); arrayElementValue.elementValues[index] = elementValue; } } // Small utility methods. private Constant createConstant() { int u1tag = dataInput.readUnsignedByte(); switch (u1tag) { case ClassConstants.CONSTANT_Integer: return new IntegerConstant(); case ClassConstants.CONSTANT_Float: return new FloatConstant(); case ClassConstants.CONSTANT_Long: return new LongConstant(); case ClassConstants.CONSTANT_Double: return new DoubleConstant(); case ClassConstants.CONSTANT_String: return new StringConstant(); case ClassConstants.CONSTANT_Utf8: return new Utf8Constant(); case ClassConstants.CONSTANT_InvokeDynamic: return new InvokeDynamicConstant(); case ClassConstants.CONSTANT_MethodHandle: return new MethodHandleConstant(); case ClassConstants.CONSTANT_Fieldref: return new FieldrefConstant(); case ClassConstants.CONSTANT_Methodref: return new MethodrefConstant(); case ClassConstants.CONSTANT_InterfaceMethodref: return new InterfaceMethodrefConstant(); case ClassConstants.CONSTANT_Class: return new ClassConstant(); case ClassConstants.CONSTANT_MethodType : return new MethodTypeConstant(); case ClassConstants.CONSTANT_NameAndType: return new NameAndTypeConstant(); default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool"); } } private Attribute createAttribute(Clazz clazz) { int u2attributeNameIndex = dataInput.readUnsignedShort(); int u4attributeLength = dataInput.readInt(); String attributeName = clazz.getString(u2attributeNameIndex); Attribute attribute = attributeName.equals(ClassConstants.ATTR_BootstrapMethods) ? (Attribute)new BootstrapMethodsAttribute(): attributeName.equals(ClassConstants.ATTR_SourceFile) ? (Attribute)new SourceFileAttribute(): attributeName.equals(ClassConstants.ATTR_SourceDir) ? (Attribute)new SourceDirAttribute(): attributeName.equals(ClassConstants.ATTR_InnerClasses) ? (Attribute)new InnerClassesAttribute(): attributeName.equals(ClassConstants.ATTR_EnclosingMethod) ? (Attribute)new EnclosingMethodAttribute(): attributeName.equals(ClassConstants.ATTR_Deprecated) ? (Attribute)new DeprecatedAttribute(): attributeName.equals(ClassConstants.ATTR_Synthetic) ? (Attribute)new SyntheticAttribute(): attributeName.equals(ClassConstants.ATTR_Signature) ? (Attribute)new SignatureAttribute(): attributeName.equals(ClassConstants.ATTR_ConstantValue) ? (Attribute)new ConstantValueAttribute(): attributeName.equals(ClassConstants.ATTR_Exceptions) ? (Attribute)new ExceptionsAttribute(): attributeName.equals(ClassConstants.ATTR_Code) ? (Attribute)new CodeAttribute(): attributeName.equals(ClassConstants.ATTR_StackMap) ? (Attribute)new StackMapAttribute(): attributeName.equals(ClassConstants.ATTR_StackMapTable) ? (Attribute)new StackMapTableAttribute(): attributeName.equals(ClassConstants.ATTR_LineNumberTable) ? (Attribute)new LineNumberTableAttribute(): attributeName.equals(ClassConstants.ATTR_LocalVariableTable) ? (Attribute)new LocalVariableTableAttribute(): attributeName.equals(ClassConstants.ATTR_LocalVariableTypeTable) ? (Attribute)new LocalVariableTypeTableAttribute(): attributeName.equals(ClassConstants.ATTR_RuntimeVisibleAnnotations) ? (Attribute)new RuntimeVisibleAnnotationsAttribute(): attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleAnnotations) ? (Attribute)new RuntimeInvisibleAnnotationsAttribute(): attributeName.equals(ClassConstants.ATTR_RuntimeVisibleParameterAnnotations) ? (Attribute)new RuntimeVisibleParameterAnnotationsAttribute(): attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleParameterAnnotations) ? (Attribute)new RuntimeInvisibleParameterAnnotationsAttribute(): attributeName.equals(ClassConstants.ATTR_AnnotationDefault) ? (Attribute)new AnnotationDefaultAttribute(): (Attribute)new UnknownAttribute(u4attributeLength); attribute.u2attributeNameIndex = u2attributeNameIndex; return attribute; } private StackMapFrame createStackMapFrame() { int u1tag = dataInput.readUnsignedByte(); return u1tag < StackMapFrame.SAME_ONE_FRAME ? (StackMapFrame)new SameZeroFrame(u1tag) : u1tag < StackMapFrame.SAME_ONE_FRAME_EXTENDED ? (StackMapFrame)new SameOneFrame(u1tag) : u1tag < StackMapFrame.LESS_ZERO_FRAME ? (StackMapFrame)new SameOneFrame(u1tag) : u1tag < StackMapFrame.SAME_ZERO_FRAME_EXTENDED ? (StackMapFrame)new LessZeroFrame(u1tag) : u1tag < StackMapFrame.MORE_ZERO_FRAME ? (StackMapFrame)new SameZeroFrame(u1tag) : u1tag < StackMapFrame.FULL_FRAME ? (StackMapFrame)new MoreZeroFrame(u1tag) : (StackMapFrame)new FullFrame(); } private VerificationType createVerificationType() { int u1tag = dataInput.readUnsignedByte(); switch (u1tag) { case VerificationType.INTEGER_TYPE: return new IntegerType(); case VerificationType.FLOAT_TYPE: return new FloatType(); case VerificationType.LONG_TYPE: return new LongType(); case VerificationType.DOUBLE_TYPE: return new DoubleType(); case VerificationType.TOP_TYPE: return new TopType(); case VerificationType.OBJECT_TYPE: return new ObjectType(); case VerificationType.NULL_TYPE: return new NullType(); case VerificationType.UNINITIALIZED_TYPE: return new UninitializedType(); case VerificationType.UNINITIALIZED_THIS_TYPE: return new UninitializedThisType(); default: throw new RuntimeException("Unknown verification type ["+u1tag+"] in stack map frame"); } } private ElementValue createElementValue() { int u1tag = dataInput.readUnsignedByte(); switch (u1tag) { case ClassConstants.INTERNAL_TYPE_BOOLEAN: case ClassConstants.INTERNAL_TYPE_BYTE: case ClassConstants.INTERNAL_TYPE_CHAR: case ClassConstants.INTERNAL_TYPE_SHORT: case ClassConstants.INTERNAL_TYPE_INT: case ClassConstants.INTERNAL_TYPE_FLOAT: case ClassConstants.INTERNAL_TYPE_LONG: case ClassConstants.INTERNAL_TYPE_DOUBLE: case ClassConstants.ELEMENT_VALUE_STRING_CONSTANT: return new ConstantElementValue(u1tag); case ClassConstants.ELEMENT_VALUE_ENUM_CONSTANT: return new EnumConstantElementValue(); case ClassConstants.ELEMENT_VALUE_CLASS: return new ClassElementValue(); case ClassConstants.ELEMENT_VALUE_ANNOTATION: return new AnnotationElementValue(); case ClassConstants.ELEMENT_VALUE_ARRAY: return new ArrayElementValue(); default: throw new IllegalArgumentException("Unknown element value tag ["+u1tag+"]"); } } } proguard4.8/src/proguard/classfile/io/package.html0000644000175000017500000000012211736333523021031 0ustar ericeric This package contains classes for reading and writing class files. proguard4.8/src/proguard/classfile/io/LibraryClassReader.java0000644000175000017500000003062411736333523023142 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.io; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.io.DataInput; /** * This ClassVisitor fills out the LibraryClass objects that it visits with data * from the given DataInput object. * * @author Eric Lafortune */ public class LibraryClassReader extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor { private static final LibraryField[] EMPTY_LIBRARY_FIELDS = new LibraryField[0]; private static final LibraryMethod[] EMPTY_LIBRARY_METHODS = new LibraryMethod[0]; private final RuntimeDataInput dataInput; private final boolean skipNonPublicClasses; private final boolean skipNonPublicClassMembers; // A global array that acts as a parameter for the visitor methods. private Constant[] constantPool; /** * Creates a new ProgramClassReader for reading from the given DataInput. */ public LibraryClassReader(DataInput dataInput, boolean skipNonPublicClasses, boolean skipNonPublicClassMembers) { this.dataInput = new RuntimeDataInput(dataInput); this.skipNonPublicClasses = skipNonPublicClasses; this.skipNonPublicClassMembers = skipNonPublicClassMembers; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass libraryClass) { } public void visitLibraryClass(LibraryClass libraryClass) { // Read and check the magic number. int u4magic = dataInput.readInt(); ClassUtil.checkMagicNumber(u4magic); // Read and check the version numbers. int u2minorVersion = dataInput.readUnsignedShort(); int u2majorVersion = dataInput.readUnsignedShort(); int u4version = ClassUtil.internalClassVersion(u2majorVersion, u2minorVersion); ClassUtil.checkVersionNumbers(u4version); // Read the constant pool. Note that the first entry is not used. int u2constantPoolCount = dataInput.readUnsignedShort(); // Create the constant pool array. constantPool = new Constant[u2constantPoolCount]; for (int index = 1; index < u2constantPoolCount; index++) { Constant constant = createConstant(); constant.accept(libraryClass, this); int tag = constant.getTag(); if (tag == ClassConstants.CONSTANT_Class || tag == ClassConstants.CONSTANT_Utf8) { constantPool[index] = constant; } // Long constants and double constants take up two entries in the // constant pool. if (tag == ClassConstants.CONSTANT_Long || tag == ClassConstants.CONSTANT_Double) { index++; } } // Read the general class information. libraryClass.u2accessFlags = dataInput.readUnsignedShort(); // We may stop parsing this library class if it's not public anyway. // E.g. only about 60% of all rt.jar classes need to be parsed. if (skipNonPublicClasses && AccessUtil.accessLevel(libraryClass.getAccessFlags()) < AccessUtil.PUBLIC) { return; } // Read the class and super class indices. int u2thisClass = dataInput.readUnsignedShort(); int u2superClass = dataInput.readUnsignedShort(); // Store their actual names. libraryClass.thisClassName = getClassName(u2thisClass); libraryClass.superClassName = (u2superClass == 0) ? null : getClassName(u2superClass); // Read the interfaces int u2interfacesCount = dataInput.readUnsignedShort(); libraryClass.interfaceNames = new String[u2interfacesCount]; for (int index = 0; index < u2interfacesCount; index++) { // Store the actual interface name. int u2interface = dataInput.readUnsignedShort(); libraryClass.interfaceNames[index] = getClassName(u2interface); } // Read the fields. int u2fieldsCount = dataInput.readUnsignedShort(); // Create the fields array. LibraryField[] reusableFields = new LibraryField[u2fieldsCount]; int visibleFieldsCount = 0; for (int index = 0; index < u2fieldsCount; index++) { LibraryField field = new LibraryField(); this.visitLibraryMember(libraryClass, field); // Only store fields that are visible. if (AccessUtil.accessLevel(field.getAccessFlags()) >= (skipNonPublicClassMembers ? AccessUtil.PROTECTED : AccessUtil.PACKAGE_VISIBLE)) { reusableFields[visibleFieldsCount++] = field; } } // Copy the visible fields (if any) into a fields array of the right size. if (visibleFieldsCount == 0) { libraryClass.fields = EMPTY_LIBRARY_FIELDS; } else { libraryClass.fields = new LibraryField[visibleFieldsCount]; System.arraycopy(reusableFields, 0, libraryClass.fields, 0, visibleFieldsCount); } // Read the methods. int u2methodsCount = dataInput.readUnsignedShort(); // Create the methods array. LibraryMethod[] reusableMethods = new LibraryMethod[u2methodsCount]; int visibleMethodsCount = 0; for (int index = 0; index < u2methodsCount; index++) { LibraryMethod method = new LibraryMethod(); this.visitLibraryMember(libraryClass, method); // Only store methods that are visible. if (AccessUtil.accessLevel(method.getAccessFlags()) >= (skipNonPublicClassMembers ? AccessUtil.PROTECTED : AccessUtil.PACKAGE_VISIBLE)) { reusableMethods[visibleMethodsCount++] = method; } } // Copy the visible methods (if any) into a methods array of the right size. if (visibleMethodsCount == 0) { libraryClass.methods = EMPTY_LIBRARY_METHODS; } else { libraryClass.methods = new LibraryMethod[visibleMethodsCount]; System.arraycopy(reusableMethods, 0, libraryClass.methods, 0, visibleMethodsCount); } // Skip the class attributes. skipAttributes(); } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass libraryClass, ProgramMember libraryMember) { } public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) { // Read the general field information. libraryMember.u2accessFlags = dataInput.readUnsignedShort(); libraryMember.name = getString(dataInput.readUnsignedShort()); libraryMember.descriptor = getString(dataInput.readUnsignedShort()); // Skip the field attributes. skipAttributes(); } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { dataInput.skipBytes(4); } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { dataInput.skipBytes(8); } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { dataInput.skipBytes(4); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { dataInput.skipBytes(8); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { dataInput.skipBytes(2); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { int u2length = dataInput.readUnsignedShort(); // Read the UTF-8 bytes. byte[] bytes = new byte[u2length]; dataInput.readFully(bytes); utf8Constant.setBytes(bytes); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { dataInput.skipBytes(4); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { dataInput.skipBytes(3); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { dataInput.skipBytes(4); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.u2nameIndex = dataInput.readUnsignedShort(); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { dataInput.skipBytes(2); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { dataInput.skipBytes(4); } // Small utility methods. /** * Returns the class name of the ClassConstant at the specified index in the * reusable constant pool. */ private String getClassName(int constantIndex) { ClassConstant classEntry = (ClassConstant)constantPool[constantIndex]; return getString(classEntry.u2nameIndex); } /** * Returns the string of the Utf8Constant at the specified index in the * reusable constant pool. */ private String getString(int constantIndex) { return ((Utf8Constant)constantPool[constantIndex]).getString(); } private Constant createConstant() { int u1tag = dataInput.readUnsignedByte(); switch (u1tag) { case ClassConstants.CONSTANT_Integer: return new IntegerConstant(); case ClassConstants.CONSTANT_Float: return new FloatConstant(); case ClassConstants.CONSTANT_Long: return new LongConstant(); case ClassConstants.CONSTANT_Double: return new DoubleConstant(); case ClassConstants.CONSTANT_String: return new StringConstant(); case ClassConstants.CONSTANT_Utf8: return new Utf8Constant(); case ClassConstants.CONSTANT_InvokeDynamic: return new InvokeDynamicConstant(); case ClassConstants.CONSTANT_MethodHandle: return new MethodHandleConstant(); case ClassConstants.CONSTANT_Fieldref: return new FieldrefConstant(); case ClassConstants.CONSTANT_Methodref: return new MethodrefConstant(); case ClassConstants.CONSTANT_InterfaceMethodref: return new InterfaceMethodrefConstant(); case ClassConstants.CONSTANT_Class: return new ClassConstant(); case ClassConstants.CONSTANT_MethodType : return new MethodTypeConstant(); case ClassConstants.CONSTANT_NameAndType: return new NameAndTypeConstant(); default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool"); } } private void skipAttributes() { int u2attributesCount = dataInput.readUnsignedShort(); for (int index = 0; index < u2attributesCount; index++) { skipAttribute(); } } private void skipAttribute() { dataInput.skipBytes(2); int u4attributeLength = dataInput.readInt(); dataInput.skipBytes(u4attributeLength); } } proguard4.8/src/proguard/classfile/io/ProgramClassWriter.java0000644000175000017500000006447711736333523023234 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.io; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.io.*; /** * This ClassVisitor writes out the ProgramClass objects that it visits to the * given DataOutput object. * * @author Eric Lafortune */ public class ProgramClassWriter extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor { private RuntimeDataOutput dataOutput; private final ConstantBodyWriter constantBodyWriter = new ConstantBodyWriter(); private final AttributeBodyWriter attributeBodyWriter = new AttributeBodyWriter(); private final StackMapFrameBodyWriter stackMapFrameBodyWriter = new StackMapFrameBodyWriter(); private final VerificationTypeBodyWriter verificationTypeBodyWriter = new VerificationTypeBodyWriter(); private final ElementValueBodyWriter elementValueBodyWriter = new ElementValueBodyWriter(); /** * Creates a new ProgramClassWriter for writing to the given DataOutput. */ public ProgramClassWriter(DataOutput dataOutput) { this.dataOutput = new RuntimeDataOutput(dataOutput); } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Write the magic number. dataOutput.writeInt(programClass.u4magic); // Write the version numbers. dataOutput.writeShort(ClassUtil.internalMinorClassVersion(programClass.u4version)); dataOutput.writeShort(ClassUtil.internalMajorClassVersion(programClass.u4version)); // Write the constant pool. dataOutput.writeShort(programClass.u2constantPoolCount); programClass.constantPoolEntriesAccept(this); // Write the general class information. dataOutput.writeShort(programClass.u2accessFlags); dataOutput.writeShort(programClass.u2thisClass); dataOutput.writeShort(programClass.u2superClass); // Write the interfaces. dataOutput.writeShort(programClass.u2interfacesCount); for (int index = 0; index < programClass.u2interfacesCount; index++) { dataOutput.writeShort(programClass.u2interfaces[index]); } // Write the fields. dataOutput.writeShort(programClass.u2fieldsCount); programClass.fieldsAccept(this); // Write the methods. dataOutput.writeShort(programClass.u2methodsCount); programClass.methodsAccept(this); // Write the class attributes. dataOutput.writeShort(programClass.u2attributesCount); programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Write the general field information. dataOutput.writeShort(programField.u2accessFlags); dataOutput.writeShort(programField.u2nameIndex); dataOutput.writeShort(programField.u2descriptorIndex); // Write the field attributes. dataOutput.writeShort(programField.u2attributesCount); programField.attributesAccept(programClass, this); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Write the general method information. dataOutput.writeShort(programMethod.u2accessFlags); dataOutput.writeShort(programMethod.u2nameIndex); dataOutput.writeShort(programMethod.u2descriptorIndex); // Write the method attributes. dataOutput.writeShort(programMethod.u2attributesCount); programMethod.attributesAccept(programClass, this); } public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) { } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) { // Write the tag. dataOutput.writeByte(constant.getTag()); // Write the actual body. constant.accept(clazz, constantBodyWriter); } private class ConstantBodyWriter extends SimplifiedVisitor implements ConstantVisitor { // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { dataOutput.writeInt(integerConstant.u4value); } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { dataOutput.writeLong(longConstant.u8value); } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { dataOutput.writeFloat(floatConstant.f4value); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { dataOutput.writeDouble(doubleConstant.f8value); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { dataOutput.writeShort(stringConstant.u2stringIndex); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { byte[] bytes = utf8Constant.getBytes(); dataOutput.writeShort(bytes.length); dataOutput.write(bytes); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { dataOutput.writeShort(invokeDynamicConstant.u2bootstrapMethodAttributeIndex); dataOutput.writeShort(invokeDynamicConstant.u2nameAndTypeIndex); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { dataOutput.writeByte(methodHandleConstant.u1referenceKind); dataOutput.writeShort(methodHandleConstant.u2referenceIndex); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { dataOutput.writeShort(refConstant.u2classIndex); dataOutput.writeShort(refConstant.u2nameAndTypeIndex); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { dataOutput.writeShort(classConstant.u2nameIndex); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { dataOutput.writeShort(methodTypeConstant.u2descriptorIndex); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { dataOutput.writeShort(nameAndTypeConstant.u2nameIndex); dataOutput.writeShort(nameAndTypeConstant.u2descriptorIndex); } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) { // Write the attribute name index. dataOutput.writeShort(attribute.u2attributeNameIndex); // We'll write the attribute body into an array first, so we can // automatically figure out its length. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Temporarily replace the current data output. RuntimeDataOutput oldDataOutput = dataOutput; dataOutput = new RuntimeDataOutput(new DataOutputStream(byteArrayOutputStream)); // Write the attribute body into the array. Note that the // accept method with two dummy null arguments never throws // an UnsupportedOperationException. attribute.accept(clazz, null, null, attributeBodyWriter); // Restore the original data output. dataOutput = oldDataOutput; // Write the attribute length and body. byte[] info = byteArrayOutputStream.toByteArray(); dataOutput.writeInt(info.length); dataOutput.write(info); } private class AttributeBodyWriter extends SimplifiedVisitor implements AttributeVisitor, BootstrapMethodInfoVisitor, InnerClassesInfoVisitor, ExceptionInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LineNumberInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { // Write the unknown information. dataOutput.write(unknownAttribute.info); } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { // Write the bootstrap methods. dataOutput.writeShort(bootstrapMethodsAttribute.u2bootstrapMethodsCount); bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { dataOutput.writeShort(sourceFileAttribute.u2sourceFileIndex); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { dataOutput.writeShort(sourceDirAttribute.u2sourceDirIndex); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Write the inner classes. dataOutput.writeShort(innerClassesAttribute.u2classesCount); innerClassesAttribute.innerClassEntriesAccept(clazz, this); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { dataOutput.writeShort(enclosingMethodAttribute.u2classIndex); dataOutput.writeShort(enclosingMethodAttribute.u2nameAndTypeIndex); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { // This attribute does not contain any additional information. } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { // This attribute does not contain any additional information. } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { dataOutput.writeShort(signatureAttribute.u2signatureIndex); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { dataOutput.writeShort(constantValueAttribute.u2constantValueIndex); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { // Write the exceptions. dataOutput.writeShort(exceptionsAttribute.u2exceptionIndexTableLength); for (int index = 0; index < exceptionsAttribute.u2exceptionIndexTableLength; index++) { dataOutput.writeShort(exceptionsAttribute.u2exceptionIndexTable[index]); } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Write the stack size and local variable frame size. dataOutput.writeShort(codeAttribute.u2maxStack); dataOutput.writeShort(codeAttribute.u2maxLocals); // Write the byte code. dataOutput.writeInt(codeAttribute.u4codeLength); dataOutput.write(codeAttribute.code, 0, codeAttribute.u4codeLength); // Write the exceptions. dataOutput.writeShort(codeAttribute.u2exceptionTableLength); codeAttribute.exceptionsAccept(clazz, method, this); // Write the code attributes. dataOutput.writeShort(codeAttribute.u2attributesCount); codeAttribute.attributesAccept(clazz, method, ProgramClassWriter.this); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { // Write the stack map frames (only full frames, without tag). dataOutput.writeShort(stackMapAttribute.u2stackMapFramesCount); stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, stackMapFrameBodyWriter); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { // Write the stack map frames. dataOutput.writeShort(stackMapTableAttribute.u2stackMapFramesCount); stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { // Write the line numbers. dataOutput.writeShort(lineNumberTableAttribute.u2lineNumberTableLength); lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Write the local variables. dataOutput.writeShort(localVariableTableAttribute.u2localVariableTableLength); localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Write the local variable types. dataOutput.writeShort(localVariableTypeTableAttribute.u2localVariableTypeTableLength); localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Write the annotations. dataOutput.writeShort(annotationsAttribute.u2annotationsCount); annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Write the parameter annotations. dataOutput.writeByte(parameterAnnotationsAttribute.u2parametersCount); for (int parameterIndex = 0; parameterIndex < parameterAnnotationsAttribute.u2parametersCount; parameterIndex++) { // Write the parameter annotations of the given parameter. int u2annotationsCount = parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex]; Annotation[] annotations = parameterAnnotationsAttribute.parameterAnnotations[parameterIndex]; dataOutput.writeShort(u2annotationsCount); for (int index = 0; index < u2annotationsCount; index++) { visitAnnotation(clazz, annotations[index]); } } } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Write the default element value. annotationDefaultAttribute.defaultValue.accept(clazz, null, this); } // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { dataOutput.writeShort(bootstrapMethodInfo.u2methodHandleIndex); // Write the bootstrap method arguments. dataOutput.writeShort(bootstrapMethodInfo.u2methodArgumentCount); for (int index = 0; index < bootstrapMethodInfo.u2methodArgumentCount; index++) { dataOutput.writeShort(bootstrapMethodInfo.u2methodArguments[index]); } } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { dataOutput.writeShort(innerClassesInfo.u2innerClassIndex); dataOutput.writeShort(innerClassesInfo.u2outerClassIndex); dataOutput.writeShort(innerClassesInfo.u2innerNameIndex); dataOutput.writeShort(innerClassesInfo.u2innerClassAccessFlags); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { dataOutput.writeShort(exceptionInfo.u2startPC); dataOutput.writeShort(exceptionInfo.u2endPC); dataOutput.writeShort(exceptionInfo.u2handlerPC); dataOutput.writeShort(exceptionInfo.u2catchType); } // Implementations for StackMapFrameVisitor. public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) { // Write the stack map frame tag. dataOutput.writeByte(stackMapFrame.getTag()); // Write the actual body. stackMapFrame.accept(clazz, method, codeAttribute, offset, stackMapFrameBodyWriter); } // Implementations for LineNumberInfoVisitor. public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) { dataOutput.writeShort(lineNumberInfo.u2startPC); dataOutput.writeShort(lineNumberInfo.u2lineNumber); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { dataOutput.writeShort(localVariableInfo.u2startPC); dataOutput.writeShort(localVariableInfo.u2length); dataOutput.writeShort(localVariableInfo.u2nameIndex); dataOutput.writeShort(localVariableInfo.u2descriptorIndex); dataOutput.writeShort(localVariableInfo.u2index); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { dataOutput.writeShort(localVariableTypeInfo.u2startPC); dataOutput.writeShort(localVariableTypeInfo.u2length); dataOutput.writeShort(localVariableTypeInfo.u2nameIndex); dataOutput.writeShort(localVariableTypeInfo.u2signatureIndex); dataOutput.writeShort(localVariableTypeInfo.u2index); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { // Write the annotation type. dataOutput.writeShort(annotation.u2typeIndex); // Write the element value pairs. dataOutput.writeShort(annotation.u2elementValuesCount); annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) { // Write the element name index, if applicable. int u2elementNameIndex = elementValue.u2elementNameIndex; if (u2elementNameIndex != 0) { dataOutput.writeShort(u2elementNameIndex); } // Write the tag. dataOutput.writeByte(elementValue.getTag()); // Write the actual body. elementValue.accept(clazz, annotation, elementValueBodyWriter); } } private class StackMapFrameBodyWriter extends SimplifiedVisitor implements StackMapFrameVisitor, VerificationTypeVisitor { public void visitSameZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameZeroFrame sameZeroFrame) { if (sameZeroFrame.getTag() == StackMapFrame.SAME_ZERO_FRAME_EXTENDED) { dataOutput.writeShort(sameZeroFrame.u2offsetDelta); } } public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { if (sameOneFrame.getTag() == StackMapFrame.SAME_ONE_FRAME_EXTENDED) { dataOutput.writeShort(sameOneFrame.u2offsetDelta); } // Write the verification type of the stack entry. sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); } public void visitLessZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LessZeroFrame lessZeroFrame) { dataOutput.writeShort(lessZeroFrame.u2offsetDelta); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { dataOutput.writeShort(moreZeroFrame.u2offsetDelta); // Write the verification types of the additional local variables. moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { dataOutput.writeShort(fullFrame.u2offsetDelta); // Write the verification types of the local variables. dataOutput.writeShort(fullFrame.variablesCount); fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); // Write the verification types of the stack entries. dataOutput.writeShort(fullFrame.stackCount); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) { // Write the verification type tag. dataOutput.writeByte(verificationType.getTag()); // Write the actual body. verificationType.accept(clazz, method, codeAttribute, offset, verificationTypeBodyWriter); } } private class VerificationTypeBodyWriter extends SimplifiedVisitor implements VerificationTypeVisitor { // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) { // Most verification types don't contain any additional information. } public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) { dataOutput.writeShort(objectType.u2classIndex); } public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType) { dataOutput.writeShort(uninitializedType.u2newInstructionOffset); } } private class ElementValueBodyWriter extends SimplifiedVisitor implements ElementValueVisitor { // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { dataOutput.writeShort(constantElementValue.u2constantValueIndex); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { dataOutput.writeShort(enumConstantElementValue.u2typeNameIndex); dataOutput.writeShort(enumConstantElementValue.u2constantNameIndex); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { dataOutput.writeShort(classElementValue.u2classInfoIndex); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { // Write the annotation. attributeBodyWriter.visitAnnotation(clazz, annotationElementValue.annotationValue); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { // Write the element values. dataOutput.writeShort(arrayElementValue.u2elementValuesCount); arrayElementValue.elementValuesAccept(clazz, annotation, attributeBodyWriter); } } } proguard4.8/src/proguard/classfile/io/RuntimeDataOutput.java0000644000175000017500000001065611736333523023066 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.io; import java.io.*; /** * This class delegates its method calls to the corresponding DataOutput methods, * converting its IOExceptions to RuntimeExceptions. * * @author Eric Lafortune */ final class RuntimeDataOutput { private final DataOutput dataOutput; public RuntimeDataOutput(DataOutput dataOutput) { this.dataOutput = dataOutput; } // Methods delegating to DataOutput. public void write(byte[] b) { try { dataOutput.write(b); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void write(byte[] b, int off, int len) { try { dataOutput.write(b, off, len); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void write(int b) { try { dataOutput.write(b); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeBoolean(boolean v) { try { dataOutput.writeBoolean(v); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeByte(int v) { try { dataOutput.writeByte(v); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeBytes(String s) { try { dataOutput.writeBytes(s); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeChar(int v) { try { dataOutput.writeChar(v); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeChars(String s) { try { dataOutput.writeChars(s); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeDouble(double v) { try { dataOutput.writeDouble(v); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeFloat(float v) { try { dataOutput.writeFloat(v); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeInt(int v) { try { dataOutput.writeInt(v); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeLong(long v) { try { dataOutput.writeLong(v); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeShort(int v) { try { dataOutput.writeShort(v); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void writeUTF(String str) { try { dataOutput.writeUTF(str); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } } proguard4.8/src/proguard/classfile/io/RuntimeDataInput.java0000644000175000017500000001121011736333523022650 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.io; import java.io.*; /** * This class delegates its method calls to the corresponding DataInput methods, * converting its IOExceptions to RuntimeExceptions. * * @author Eric Lafortune */ final class RuntimeDataInput { private final DataInput dataInput; public RuntimeDataInput(DataInput dataInput) { this.dataInput = dataInput; } // Methods delegating to DataInput. public boolean readBoolean() { try { return dataInput.readBoolean(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public byte readByte() { try { return dataInput.readByte(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public char readChar() { try { return dataInput.readChar(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public double readDouble() { try { return dataInput.readDouble(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public float readFloat() { try { return dataInput.readFloat(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void readFully(byte[] b) { try { dataInput.readFully(b); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public void readFully(byte[] b, int off, int len) { try { dataInput.readFully(b, off, len); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public int readInt() { try { return dataInput.readInt(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public String readLine() { try { return dataInput.readLine(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public long readLong() { try { return dataInput.readLong(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public short readShort() { try { return dataInput.readShort(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public int readUnsignedByte() { try { return dataInput.readUnsignedByte(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public int readUnsignedShort() { try { return dataInput.readUnsignedShort(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public String readUTF() { try { return dataInput.readUTF(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } public int skipBytes(int n) { try { return dataInput.skipBytes(n); } catch (IOException ex) { throw new RuntimeException(ex.getMessage()); } } } proguard4.8/src/proguard/classfile/ClassConstants.java0000664000175000017500000005704011736333523021763 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; /** * Constants used in representing a Java class (*.class). * * @author Eric Lafortune */ public interface ClassConstants { public static final String CLASS_FILE_EXTENSION = ".class"; public static final int MAGIC = 0xCAFEBABE; public static final int INTERNAL_CLASS_VERSION_1_0_MAJOR = 45; public static final int INTERNAL_CLASS_VERSION_1_0_MINOR = 3; public static final int INTERNAL_CLASS_VERSION_1_2_MAJOR = 46; public static final int INTERNAL_CLASS_VERSION_1_2_MINOR = 0; public static final int INTERNAL_CLASS_VERSION_1_3_MAJOR = 47; public static final int INTERNAL_CLASS_VERSION_1_3_MINOR = 0; public static final int INTERNAL_CLASS_VERSION_1_4_MAJOR = 48; public static final int INTERNAL_CLASS_VERSION_1_4_MINOR = 0; public static final int INTERNAL_CLASS_VERSION_1_5_MAJOR = 49; public static final int INTERNAL_CLASS_VERSION_1_5_MINOR = 0; public static final int INTERNAL_CLASS_VERSION_1_6_MAJOR = 50; public static final int INTERNAL_CLASS_VERSION_1_6_MINOR = 0; public static final int INTERNAL_CLASS_VERSION_1_7_MAJOR = 51; public static final int INTERNAL_CLASS_VERSION_1_7_MINOR = 0; public static final int INTERNAL_CLASS_VERSION_1_0 = (INTERNAL_CLASS_VERSION_1_0_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_0_MINOR; public static final int INTERNAL_CLASS_VERSION_1_2 = (INTERNAL_CLASS_VERSION_1_2_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_2_MINOR; public static final int INTERNAL_CLASS_VERSION_1_3 = (INTERNAL_CLASS_VERSION_1_3_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_3_MINOR; public static final int INTERNAL_CLASS_VERSION_1_4 = (INTERNAL_CLASS_VERSION_1_4_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_4_MINOR; public static final int INTERNAL_CLASS_VERSION_1_5 = (INTERNAL_CLASS_VERSION_1_5_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_5_MINOR; public static final int INTERNAL_CLASS_VERSION_1_6 = (INTERNAL_CLASS_VERSION_1_6_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_6_MINOR; public static final int INTERNAL_CLASS_VERSION_1_7 = (INTERNAL_CLASS_VERSION_1_7_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_7_MINOR; public static final String EXTERNAL_CLASS_VERSION_1_0 = "1.0"; public static final String EXTERNAL_CLASS_VERSION_1_1 = "1.1"; public static final String EXTERNAL_CLASS_VERSION_1_2 = "1.2"; public static final String EXTERNAL_CLASS_VERSION_1_3 = "1.3"; public static final String EXTERNAL_CLASS_VERSION_1_4 = "1.4"; public static final String EXTERNAL_CLASS_VERSION_1_5 = "1.5"; public static final String EXTERNAL_CLASS_VERSION_1_6 = "1.6"; public static final String EXTERNAL_CLASS_VERSION_1_7 = "1.7"; public static final String EXTERNAL_CLASS_VERSION_1_5_ALIAS = "5"; public static final String EXTERNAL_CLASS_VERSION_1_6_ALIAS = "6"; public static final String EXTERNAL_CLASS_VERSION_1_7_ALIAS = "7"; public static final int INTERNAL_ACC_PUBLIC = 0x0001; public static final int INTERNAL_ACC_PRIVATE = 0x0002; public static final int INTERNAL_ACC_PROTECTED = 0x0004; public static final int INTERNAL_ACC_STATIC = 0x0008; public static final int INTERNAL_ACC_FINAL = 0x0010; public static final int INTERNAL_ACC_SUPER = 0x0020; public static final int INTERNAL_ACC_SYNCHRONIZED = 0x0020; public static final int INTERNAL_ACC_VOLATILE = 0x0040; public static final int INTERNAL_ACC_TRANSIENT = 0x0080; public static final int INTERNAL_ACC_BRIDGE = 0x0040; public static final int INTERNAL_ACC_VARARGS = 0x0080; public static final int INTERNAL_ACC_NATIVE = 0x0100; public static final int INTERNAL_ACC_INTERFACE = 0x0200; public static final int INTERNAL_ACC_ABSTRACT = 0x0400; public static final int INTERNAL_ACC_STRICT = 0x0800; public static final int INTERNAL_ACC_SYNTHETIC = 0x1000; public static final int INTERNAL_ACC_ANNOTATTION = 0x2000; public static final int INTERNAL_ACC_ENUM = 0x4000; public static final int VALID_INTERNAL_ACC_CLASS = INTERNAL_ACC_PUBLIC | INTERNAL_ACC_FINAL | INTERNAL_ACC_SUPER | INTERNAL_ACC_INTERFACE | INTERNAL_ACC_ABSTRACT | INTERNAL_ACC_SYNTHETIC | INTERNAL_ACC_ANNOTATTION | INTERNAL_ACC_ENUM; public static final int VALID_INTERNAL_ACC_FIELD = INTERNAL_ACC_PUBLIC | INTERNAL_ACC_PRIVATE | INTERNAL_ACC_PROTECTED | INTERNAL_ACC_STATIC | INTERNAL_ACC_FINAL | INTERNAL_ACC_VOLATILE | INTERNAL_ACC_TRANSIENT | INTERNAL_ACC_SYNTHETIC | INTERNAL_ACC_ENUM; public static final int VALID_INTERNAL_ACC_METHOD = INTERNAL_ACC_PUBLIC | INTERNAL_ACC_PRIVATE | INTERNAL_ACC_PROTECTED | INTERNAL_ACC_STATIC | INTERNAL_ACC_FINAL | INTERNAL_ACC_SYNCHRONIZED | INTERNAL_ACC_BRIDGE | INTERNAL_ACC_VARARGS | INTERNAL_ACC_NATIVE | INTERNAL_ACC_ABSTRACT | INTERNAL_ACC_STRICT | INTERNAL_ACC_SYNTHETIC; public static final String EXTERNAL_ACC_PUBLIC = "public"; public static final String EXTERNAL_ACC_PRIVATE = "private"; public static final String EXTERNAL_ACC_PROTECTED = "protected"; public static final String EXTERNAL_ACC_STATIC = "static"; public static final String EXTERNAL_ACC_FINAL = "final"; public static final String EXTERNAL_ACC_SUPER = "super"; public static final String EXTERNAL_ACC_SYNCHRONIZED = "synchronized"; public static final String EXTERNAL_ACC_VOLATILE = "volatile"; public static final String EXTERNAL_ACC_TRANSIENT = "transient"; public static final String EXTERNAL_ACC_BRIDGE = "bridge"; public static final String EXTERNAL_ACC_VARARGS = "varargs"; public static final String EXTERNAL_ACC_NATIVE = "native"; public static final String EXTERNAL_ACC_INTERFACE = "interface"; public static final String EXTERNAL_ACC_ABSTRACT = "abstract"; public static final String EXTERNAL_ACC_STRICT = "strictfp"; public static final String EXTERNAL_ACC_SYNTHETIC = "synthetic"; public static final String EXTERNAL_ACC_ANNOTATION = "@"; public static final String EXTERNAL_ACC_ENUM = "enum"; public static final int CONSTANT_Utf8 = 1; public static final int CONSTANT_Integer = 3; public static final int CONSTANT_Float = 4; public static final int CONSTANT_Long = 5; public static final int CONSTANT_Double = 6; public static final int CONSTANT_Class = 7; public static final int CONSTANT_String = 8; public static final int CONSTANT_Fieldref = 9; public static final int CONSTANT_Methodref = 10; public static final int CONSTANT_InterfaceMethodref = 11; public static final int CONSTANT_NameAndType = 12; public static final int CONSTANT_MethodHandle = 15; public static final int CONSTANT_MethodType = 16; public static final int CONSTANT_InvokeDynamic = 18; public static final int REF_getField = 1; public static final int REF_getStatic = 2; public static final int REF_putField = 3; public static final int REF_putStatic = 4; public static final int REF_invokeVirtual = 5; public static final int REF_invokeStatic = 6; public static final int REF_invokeSpecial = 7; public static final int REF_newInvokeSpecial = 8; public static final int REF_invokeInterface = 9; public static final String ATTR_BootstrapMethods = "BootstrapMethods"; public static final String ATTR_SourceFile = "SourceFile"; public static final String ATTR_SourceDir = "SourceDir"; public static final String ATTR_InnerClasses = "InnerClasses"; public static final String ATTR_EnclosingMethod = "EnclosingMethod"; public static final String ATTR_Deprecated = "Deprecated"; public static final String ATTR_Synthetic = "Synthetic"; public static final String ATTR_Signature = "Signature"; public static final String ATTR_ConstantValue = "ConstantValue"; public static final String ATTR_Exceptions = "Exceptions"; public static final String ATTR_Code = "Code"; public static final String ATTR_StackMap = "StackMap"; public static final String ATTR_StackMapTable = "StackMapTable"; public static final String ATTR_LineNumberTable = "LineNumberTable"; public static final String ATTR_LocalVariableTable = "LocalVariableTable"; public static final String ATTR_LocalVariableTypeTable = "LocalVariableTypeTable"; public static final String ATTR_RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations"; public static final String ATTR_RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations"; public static final String ATTR_RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations"; public static final String ATTR_RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations"; public static final String ATTR_AnnotationDefault = "AnnotationDefault"; public static final int ELEMENT_VALUE_STRING_CONSTANT = 's'; public static final int ELEMENT_VALUE_ENUM_CONSTANT = 'e'; public static final int ELEMENT_VALUE_CLASS = 'c'; public static final int ELEMENT_VALUE_ANNOTATION = '@'; public static final int ELEMENT_VALUE_ARRAY = '['; public static final char EXTERNAL_PACKAGE_SEPARATOR = '.'; public static final char EXTERNAL_INNER_CLASS_SEPARATOR = '.'; public static final char INTERNAL_PACKAGE_SEPARATOR = '/'; public static final char INTERNAL_INNER_CLASS_SEPARATOR = '$'; public static final char SPECIAL_CLASS_CHARACTER = '-'; public static final char SPECIAL_MEMBER_SEPARATOR = '$'; public static final char EXTERNAL_METHOD_ARGUMENTS_OPEN = '('; public static final char EXTERNAL_METHOD_ARGUMENTS_CLOSE = ')'; public static final char EXTERNAL_METHOD_ARGUMENTS_SEPARATOR = ','; public static final char INTERNAL_METHOD_ARGUMENTS_OPEN = '('; public static final char INTERNAL_METHOD_ARGUMENTS_CLOSE = ')'; public static final String INTERNAL_PACKAGE_JAVA_LANG = "java/lang/"; public static final String INTERNAL_NAME_JAVA_LANG_OBJECT = "java/lang/Object"; public static final String INTERNAL_TYPE_JAVA_LANG_OBJECT = "Ljava/lang/Object;"; public static final String INTERNAL_NAME_JAVA_LANG_CLONEABLE = "java/lang/Cloneable"; public static final String INTERNAL_NAME_JAVA_LANG_THROWABLE = "java/lang/Throwable"; public static final String INTERNAL_NAME_JAVA_LANG_CLASS = "java/lang/Class"; public static final String INTERNAL_NAME_JAVA_LANG_STRING = "java/lang/String"; public static final String INTERNAL_NAME_JAVA_LANG_STRING_BUFFER = "java/lang/StringBuffer"; public static final String INTERNAL_NAME_JAVA_LANG_STRING_BUILDER = "java/lang/StringBuilder"; public static final String INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_HANDLE = "java/lang/invoke/MethodHandle"; public static final String INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_TYPE = "java/lang/invoke/MethodType"; public static final String INTERNAL_NAME_JAVA_IO_SERIALIZABLE = "java/io/Serializable"; public static final String INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER = "java/util/concurrent/atomic/AtomicIntegerFieldUpdater"; public static final String INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER = "java/util/concurrent/atomic/AtomicLongFieldUpdater"; public static final String INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER = "java/util/concurrent/atomic/AtomicReferenceFieldUpdater"; public static final String INTERNAL_METHOD_NAME_INIT = ""; public static final String INTERNAL_METHOD_TYPE_INIT = "()V"; public static final String INTERNAL_METHOD_NAME_CLINIT = ""; public static final String INTERNAL_METHOD_TYPE_CLINIT = "()V"; public static final String INTERNAL_METHOD_NAME_CLASS_FOR_NAME = "forName"; public static final String INTERNAL_METHOD_TYPE_CLASS_FOR_NAME = "(Ljava/lang/String;)Ljava/lang/Class;"; public static final String INTERNAL_METHOD_NAME_CLASS_GET_COMPONENT_TYPE = "getComponentType"; public static final String INTERNAL_METHOD_TYPE_CLASS_GET_COMPONENT_TYPE = "()Ljava/lang/Class;"; public static final String INTERNAL_METHOD_NAME_CLASS_GET_FIELD = "getField"; public static final String INTERNAL_METHOD_TYPE_CLASS_GET_FIELD = "(Ljava/lang/String;)Ljava/lang/reflect/Field;"; public static final String INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD = "getDeclaredField"; public static final String INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD = "(Ljava/lang/String;)Ljava/lang/reflect/Field;"; public static final String INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_CONSTRUCTOR = "getConstructor"; public static final String INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_CONSTRUCTOR = "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"; public static final String INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_DECLARED_CONSTRUCTOR = "getDeclaredConstructor"; public static final String INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_DECLARED_CONSTRUCTOR = "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"; public static final String INTERNAL_METHOD_NAME_CLASS_GET_METHOD = "getMethod"; public static final String INTERNAL_METHOD_TYPE_CLASS_GET_METHOD = "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"; public static final String INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD = "getDeclaredMethod"; public static final String INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD = "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"; public static final String INTERNAL_METHOD_NAME_NEW_UPDATER = "newUpdater"; public static final String INTERNAL_METHOD_TYPE_NEW_INTEGER_UPDATER = "(Ljava/lang/Class;Ljava/lang/String;)Ljava/util/concurrent/atomic/AtomicIntegerFieldUpdater;"; public static final String INTERNAL_METHOD_TYPE_NEW_LONG_UPDATER = "(Ljava/lang/Class;Ljava/lang/String;)Ljava/util/concurrent/atomic/AtomicLongFieldUpdater;"; public static final String INTERNAL_METHOD_TYPE_NEW_REFERENCE_UPDATER = "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;)Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;"; public static final String INTERNAL_METHOD_NAME_DOT_CLASS_JAVAC = "class$"; public static final String INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC = "(Ljava/lang/String;)Ljava/lang/Class;"; public static final String INTERNAL_METHOD_NAME_DOT_CLASS_JIKES = "class"; public static final String INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES = "(Ljava/lang/String;Z)Ljava/lang/Class;"; public static final String INTERNAL_METHOD_NAME_NEW_INSTANCE = "newInstance"; public static final String INTERNAL_METHOD_TYPE_NEW_INSTANCE = "()Ljava/lang/Object;"; public static final String INTERNAL_METHOD_NAME_EQUALS = "equals"; public static final String INTERNAL_METHOD_TYPE_EQUALS = "(Ljava/lang/Object;)Z"; public static final String INTERNAL_METHOD_NAME_LENGTH = "length"; public static final String INTERNAL_METHOD_NAME_VALUEOF = "valueOf"; public static final String INTERNAL_METHOD_TYPE_VALUEOF_BOOLEAN = "(Z)Ljava/lang/String;"; public static final String INTERNAL_METHOD_TYPE_VALUEOF_CHAR = "(C)Ljava/lang/String;"; public static final String INTERNAL_METHOD_TYPE_VALUEOF_INT = "(I)Ljava/lang/String;"; public static final String INTERNAL_METHOD_TYPE_VALUEOF_LONG = "(J)Ljava/lang/String;"; public static final String INTERNAL_METHOD_TYPE_VALUEOF_FLOAT = "(F)Ljava/lang/String;"; public static final String INTERNAL_METHOD_TYPE_VALUEOF_DOUBLE = "(D)Ljava/lang/String;"; public static final String INTERNAL_METHOD_TYPE_VALUEOF_OBJECT = "(Ljava/lang/Object;)Ljava/lang/String;"; public static final String INTERNAL_METHOD_TYPE_LENGTH = "()I"; public static final String INTERNAL_METHOD_NAME_APPEND = "append"; public static final String INTERNAL_METHOD_TYPE_STRING_VOID = "(Ljava/lang/String;)V"; public static final String INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUFFER = "(Z)Ljava/lang/StringBuffer;"; public static final String INTERNAL_METHOD_TYPE_CHAR_STRING_BUFFER = "(C)Ljava/lang/StringBuffer;"; public static final String INTERNAL_METHOD_TYPE_INT_STRING_BUFFER = "(I)Ljava/lang/StringBuffer;"; public static final String INTERNAL_METHOD_TYPE_LONG_STRING_BUFFER = "(J)Ljava/lang/StringBuffer;"; public static final String INTERNAL_METHOD_TYPE_FLOAT_STRING_BUFFER = "(F)Ljava/lang/StringBuffer;"; public static final String INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUFFER = "(D)Ljava/lang/StringBuffer;"; public static final String INTERNAL_METHOD_TYPE_STRING_STRING_BUFFER = "(Ljava/lang/String;)Ljava/lang/StringBuffer;"; public static final String INTERNAL_METHOD_TYPE_OBJECT_STRING_BUFFER = "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"; public static final String INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUILDER = "(Z)Ljava/lang/StringBuilder;"; public static final String INTERNAL_METHOD_TYPE_CHAR_STRING_BUILDER = "(C)Ljava/lang/StringBuilder;"; public static final String INTERNAL_METHOD_TYPE_INT_STRING_BUILDER = "(I)Ljava/lang/StringBuilder;"; public static final String INTERNAL_METHOD_TYPE_LONG_STRING_BUILDER = "(J)Ljava/lang/StringBuilder;"; public static final String INTERNAL_METHOD_TYPE_FLOAT_STRING_BUILDER = "(F)Ljava/lang/StringBuilder;"; public static final String INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUILDER = "(D)Ljava/lang/StringBuilder;"; public static final String INTERNAL_METHOD_TYPE_STRING_STRING_BUILDER = "(Ljava/lang/String;)Ljava/lang/StringBuilder;"; public static final String INTERNAL_METHOD_TYPE_OBJECT_STRING_BUILDER = "(Ljava/lang/Object;)Ljava/lang/StringBuilder;"; public static final String INTERNAL_METHOD_NAME_TOSTRING = "toString"; public static final String INTERNAL_METHOD_TYPE_TOSTRING = "()Ljava/lang/String;"; public static final char INTERNAL_TYPE_VOID = 'V'; public static final char INTERNAL_TYPE_BOOLEAN = 'Z'; public static final char INTERNAL_TYPE_BYTE = 'B'; public static final char INTERNAL_TYPE_CHAR = 'C'; public static final char INTERNAL_TYPE_SHORT = 'S'; public static final char INTERNAL_TYPE_INT = 'I'; public static final char INTERNAL_TYPE_LONG = 'J'; public static final char INTERNAL_TYPE_FLOAT = 'F'; public static final char INTERNAL_TYPE_DOUBLE = 'D'; public static final char INTERNAL_TYPE_CLASS_START = 'L'; public static final char INTERNAL_TYPE_CLASS_END = ';'; public static final char INTERNAL_TYPE_ARRAY = '['; public static final char INTERNAL_TYPE_GENERIC_VARIABLE_START = 'T'; public static final char INTERNAL_TYPE_GENERIC_START = '<'; public static final char INTERNAL_TYPE_GENERIC_BOUND = ':'; public static final char INTERNAL_TYPE_GENERIC_END = '>'; public static final String EXTERNAL_TYPE_JAVA_LANG_OBJECT = "java.lang.Object"; public static final String EXTERNAL_PACKAGE_JAVA_LANG = "java.lang."; public static final String EXTERNAL_TYPE_VOID = "void"; public static final String EXTERNAL_TYPE_BOOLEAN = "boolean"; public static final String EXTERNAL_TYPE_BYTE = "byte"; public static final String EXTERNAL_TYPE_CHAR = "char"; public static final String EXTERNAL_TYPE_SHORT = "short"; public static final String EXTERNAL_TYPE_INT = "int"; public static final String EXTERNAL_TYPE_FLOAT = "float"; public static final String EXTERNAL_TYPE_LONG = "long"; public static final String EXTERNAL_TYPE_DOUBLE = "double"; public static final String EXTERNAL_TYPE_ARRAY = "[]"; public static final int TYPICAL_CONSTANT_POOL_SIZE = 256; public static final int TYPICAL_FIELD_COUNT = 64; public static final int TYPICAL_METHOD_COUNT = 64; public static final int TYPICAL_CODE_LENGTH = 1024; public static final int TYPICAL_EXCEPTION_TABLE_LENGTH = 16; public static final int TYPICAL_VARIABLES_SIZE = 64; public static final int TYPICAL_STACK_SIZE = 16; } proguard4.8/src/proguard/classfile/editor/0000775000175000017500000000000011760503005017425 5ustar ericericproguard4.8/src/proguard/classfile/editor/package.html0000644000175000017500000000010111736333523021705 0ustar ericeric This package contains visitors to edit byte code. proguard4.8/src/proguard/classfile/editor/ConstantPoolEditor.java0000644000175000017500000007153011736333524024100 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.constant.*; /** * This class can add constant pool entries to a given class. * * @author Eric Lafortune */ public class ConstantPoolEditor { private static final boolean DEBUG = false; private ProgramClass targetClass; /** * Creates a new ConstantPoolEditor that will edit constants in the given * target class. */ public ConstantPoolEditor(ProgramClass targetClass) { this.targetClass = targetClass; } /** * Finds or creates a IntegerConstant constant pool entry with the given * value. * @return the constant pool index of the Utf8Constant. */ public int addIntegerConstant(int value) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_Integer) { IntegerConstant integerConstant = (IntegerConstant)constant; if (integerConstant.getValue() == value) { return index; } } } return addConstant(new IntegerConstant(value)); } /** * Finds or creates a LongConstant constant pool entry with the given value. * @return the constant pool index of the LongConstant. */ public int addLongConstant(long value) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_Long) { LongConstant longConstant = (LongConstant)constant; if (longConstant.getValue() == value) { return index; } } } return addConstant(new LongConstant(value)); } /** * Finds or creates a FloatConstant constant pool entry with the given * value. * @return the constant pool index of the FloatConstant. */ public int addFloatConstant(float value) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_Float) { FloatConstant floatConstant = (FloatConstant)constant; if (floatConstant.getValue() == value) { return index; } } } return addConstant(new FloatConstant(value)); } /** * Finds or creates a DoubleConstant constant pool entry with the given * value. * @return the constant pool index of the DoubleConstant. */ public int addDoubleConstant(double value) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_Double) { DoubleConstant doubleConstant = (DoubleConstant)constant; if (doubleConstant.getValue() == value) { return index; } } } return addConstant(new DoubleConstant(value)); } /** * Finds or creates a StringConstant constant pool entry with the given * value. * @return the constant pool index of the StringConstant. */ public int addStringConstant(String string, Clazz referencedClass, Member referencedMember) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_String) { StringConstant stringConstant = (StringConstant)constant; if (stringConstant.getString(targetClass).equals(string)) { return index; } } } return addConstant(new StringConstant(addUtf8Constant(string), referencedClass, referencedMember)); } /** * Finds or creates a InvokeDynamicConstant constant pool entry with the * given bootstrap method constant pool entry index, method name, and * descriptor. * @return the constant pool index of the InvokeDynamicConstant. */ public int addInvokeDynamicConstant(int bootstrapMethodIndex, String name, String descriptor, Clazz[] referencedClasses) { return addInvokeDynamicConstant(bootstrapMethodIndex, addNameAndTypeConstant(name, descriptor), referencedClasses); } /** * Finds or creates a InvokeDynamicConstant constant pool entry with the given * class constant pool entry index and name and type constant pool entry * index. * @return the constant pool index of the InvokeDynamicConstant. */ public int addInvokeDynamicConstant(int bootstrapMethodIndex, int nameAndTypeIndex, Clazz[] referencedClasses) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_InvokeDynamic) { InvokeDynamicConstant invokeDynamicConstant = (InvokeDynamicConstant)constant; if (invokeDynamicConstant.u2bootstrapMethodAttributeIndex == bootstrapMethodIndex && invokeDynamicConstant.u2nameAndTypeIndex == nameAndTypeIndex) { return index; } } } return addConstant(new InvokeDynamicConstant(bootstrapMethodIndex, nameAndTypeIndex, referencedClasses)); } /** * Finds or creates a MethodHandleConstant constant pool entry of the * specified kind and with the given field ref, interface method ref, * or method ref constant pool entry index. * @return the constant pool index of the MethodHandleConstant. */ public int addMethodHandleConstant(int referenceKind, int referenceIndex) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_MethodHandle) { MethodHandleConstant methodHandleConstant = (MethodHandleConstant)constant; if (methodHandleConstant.u1referenceKind == referenceKind && methodHandleConstant.u2referenceIndex == referenceIndex) { return index; } } } return addConstant(new MethodHandleConstant(referenceKind, referenceIndex)); } /** * Finds or creates a FieldrefConstant constant pool entry for the given * class and field. * @return the constant pool index of the FieldrefConstant. */ public int addFieldrefConstant(Clazz referencedClass, Member referencedMember) { return addFieldrefConstant(referencedClass.getName(), referencedMember.getName(referencedClass), referencedMember.getDescriptor(referencedClass), referencedClass, referencedMember); } /** * Finds or creates a FieldrefConstant constant pool entry with the given * class name, field name, and descriptor. * @return the constant pool index of the FieldrefConstant. */ public int addFieldrefConstant(String className, String name, String descriptor, Clazz referencedClass, Member referencedMember) { return addFieldrefConstant(className, addNameAndTypeConstant(name, descriptor), referencedClass, referencedMember); } /** * Finds or creates a FieldrefConstant constant pool entry with the given * class name, field name, and descriptor. * @return the constant pool index of the FieldrefConstant. */ public int addFieldrefConstant(String className, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { return addFieldrefConstant(addClassConstant(className, referencedClass), nameAndTypeIndex, referencedClass, referencedMember); } /** * Finds or creates a FieldrefConstant constant pool entry with the given * class constant pool entry index, field name, and descriptor. * @return the constant pool index of the FieldrefConstant. */ public int addFieldrefConstant(int classIndex, String name, String descriptor, Clazz referencedClass, Member referencedMember) { return addFieldrefConstant(classIndex, addNameAndTypeConstant(name, descriptor), referencedClass, referencedMember); } /** * Finds or creates a FieldrefConstant constant pool entry with the given * class constant pool entry index and name and type constant pool entry * index. * @return the constant pool index of the FieldrefConstant. */ public int addFieldrefConstant(int classIndex, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_Fieldref) { FieldrefConstant fieldrefConstant = (FieldrefConstant)constant; if (fieldrefConstant.u2classIndex == classIndex && fieldrefConstant.u2nameAndTypeIndex == nameAndTypeIndex) { return index; } } } return addConstant(new FieldrefConstant(classIndex, nameAndTypeIndex, referencedClass, referencedMember)); } /** * Finds or creates a InterfaceMethodrefConstant constant pool entry with the * given class name, method name, and descriptor. * @return the constant pool index of the InterfaceMethodrefConstant. */ public int addInterfaceMethodrefConstant(String className, String name, String descriptor, Clazz referencedClass, Member referencedMember) { return addInterfaceMethodrefConstant(className, addNameAndTypeConstant(name, descriptor), referencedClass, referencedMember); } /** * Finds or creates a InterfaceMethodrefConstant constant pool entry with the * given class name, method name, and descriptor. * @return the constant pool index of the InterfaceMethodrefConstant. */ public int addInterfaceMethodrefConstant(String className, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { return addInterfaceMethodrefConstant(addClassConstant(className, referencedClass), nameAndTypeIndex, referencedClass, referencedMember); } /** * Finds or creates a InterfaceMethodrefConstant constant pool entry for the * given class and method. * @return the constant pool index of the InterfaceMethodrefConstant. */ public int addInterfaceMethodrefConstant(Clazz referencedClass, Member referencedMember) { return addInterfaceMethodrefConstant(referencedClass.getName(), referencedMember.getName(referencedClass), referencedMember.getDescriptor(referencedClass), referencedClass, referencedMember); } /** * Finds or creates a InterfaceMethodrefConstant constant pool entry with the * given class constant pool entry index, method name, and descriptor. * @return the constant pool index of the InterfaceMethodrefConstant. */ public int addInterfaceMethodrefConstant(int classIndex, String name, String descriptor, Clazz referencedClass, Member referencedMember) { return addInterfaceMethodrefConstant(classIndex, addNameAndTypeConstant(name, descriptor), referencedClass, referencedMember); } /** * Finds or creates a InterfaceMethodrefConstant constant pool entry with the * given class constant pool entry index and name and type constant pool * entry index. * @return the constant pool index of the InterfaceMethodrefConstant. */ public int addInterfaceMethodrefConstant(int classIndex, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_InterfaceMethodref) { InterfaceMethodrefConstant methodrefConstant = (InterfaceMethodrefConstant)constant; if (methodrefConstant.u2classIndex == classIndex && methodrefConstant.u2nameAndTypeIndex == nameAndTypeIndex) { return index; } } } return addConstant(new InterfaceMethodrefConstant(classIndex, nameAndTypeIndex, referencedClass, referencedMember)); } /** * Finds or creates a MethodrefConstant constant pool entry for the given * class and method. * @return the constant pool index of the MethodrefConstant. */ public int addMethodrefConstant(Clazz referencedClass, Member referencedMember) { return addMethodrefConstant(referencedClass.getName(), referencedMember.getName(referencedClass), referencedMember.getDescriptor(referencedClass), referencedClass, referencedMember); } /** * Finds or creates a MethodrefConstant constant pool entry with the given * class name, method name, and descriptor. * @return the constant pool index of the MethodrefConstant. */ public int addMethodrefConstant(String className, String name, String descriptor, Clazz referencedClass, Member referencedMember) { return addMethodrefConstant(className, addNameAndTypeConstant(name, descriptor), referencedClass, referencedMember); } /** * Finds or creates a MethodrefConstant constant pool entry with the given * class name, method name, and descriptor. * @return the constant pool index of the MethodrefConstant. */ public int addMethodrefConstant(String className, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { return addMethodrefConstant(addClassConstant(className, referencedClass), nameAndTypeIndex, referencedClass, referencedMember); } /** * Finds or creates a MethodrefConstant constant pool entry with the given * class constant pool entry index, method name, and descriptor. * @return the constant pool index of the MethodrefConstant. */ public int addMethodrefConstant(int classIndex, String name, String descriptor, Clazz referencedClass, Member referencedMember) { return addMethodrefConstant(classIndex, addNameAndTypeConstant(name, descriptor), referencedClass, referencedMember); } /** * Finds or creates a MethodrefConstant constant pool entry with the given * class constant pool entry index and name and type constant pool entry * index. * @return the constant pool index of the MethodrefConstant. */ public int addMethodrefConstant(int classIndex, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_Methodref) { MethodrefConstant methodrefConstant = (MethodrefConstant)constant; if (methodrefConstant.u2classIndex == classIndex && methodrefConstant.u2nameAndTypeIndex == nameAndTypeIndex) { return index; } } } return addConstant(new MethodrefConstant(classIndex, nameAndTypeIndex, referencedClass, referencedMember)); } /** * Finds or creates a ClassConstant constant pool entry for the given class. * @return the constant pool index of the ClassConstant. */ public int addClassConstant(Clazz referencedClass) { return addClassConstant(referencedClass.getName(), referencedClass); } /** * Finds or creates a ClassConstant constant pool entry with the given name. * @return the constant pool index of the ClassConstant. */ public int addClassConstant(String name, Clazz referencedClass) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_Class) { ClassConstant classConstant = (ClassConstant)constant; if (classConstant.getName(targetClass).equals(name)) { return index; } } } int nameIndex = addUtf8Constant(name); return addConstant(new ClassConstant(nameIndex, referencedClass)); } /** * Finds or creates a MethodTypeConstant constant pool entry with the given * type. * @return the constant pool index of the MethodTypeConstant. */ public int addMethodTypeConstant(String type) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_MethodType) { MethodTypeConstant methodTypeConstant = (MethodTypeConstant)constant; if (methodTypeConstant.getType(targetClass).equals(type)) { return index; } } } return addConstant(new MethodTypeConstant(addUtf8Constant(type))); } /** * Finds or creates a NameAndTypeConstant constant pool entry with the given * name and type. * @return the constant pool index of the NameAndTypeConstant. */ public int addNameAndTypeConstant(String name, String type) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_NameAndType) { NameAndTypeConstant nameAndTypeConstant = (NameAndTypeConstant)constant; if (nameAndTypeConstant.getName(targetClass).equals(name) && nameAndTypeConstant.getType(targetClass).equals(type)) { return index; } } } return addConstant(new NameAndTypeConstant(addUtf8Constant(name), addUtf8Constant(type))); } /** * Finds or creates a Utf8Constant constant pool entry for the given string. * @return the constant pool index of the Utf8Constant. */ public int addUtf8Constant(String string) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Check if the entry already exists. for (int index = 1; index < constantPoolCount; index++) { Constant constant = constantPool[index]; if (constant != null && constant.getTag() == ClassConstants.CONSTANT_Utf8) { Utf8Constant utf8Constant = (Utf8Constant)constant; if (utf8Constant.getString().equals(string)) { return index; } } } return addConstant(new Utf8Constant(string)); } /** * Adds a given constant pool entry to the end of the constant pool/ * @return the constant pool index for the added entry. */ public int addConstant(Constant constant) { int constantPoolCount = targetClass.u2constantPoolCount; Constant[] constantPool = targetClass.constantPool; // Make sure there is enough space for another constant pool entry. if (constantPool.length < constantPoolCount+2) { targetClass.constantPool = new Constant[constantPoolCount+2]; System.arraycopy(constantPool, 0, targetClass.constantPool, 0, constantPoolCount); constantPool = targetClass.constantPool; } if (DEBUG) { System.out.println(targetClass.getName()+": adding ["+constant.getClass().getName()+"] at index "+targetClass.u2constantPoolCount); } // Create a new Utf8Constant for the given string. constantPool[targetClass.u2constantPoolCount++] = constant; // Long constants and double constants take up two entries in the // constant pool. int tag = constant.getTag(); if (tag == ClassConstants.CONSTANT_Long || tag == ClassConstants.CONSTANT_Double) { constantPool[targetClass.u2constantPoolCount++] = null; } return constantPoolCount; } } proguard4.8/src/proguard/classfile/editor/AttributeSorter.java0000644000175000017500000000575511736333524023456 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; import java.util.*; /** * This ClassVisitor sorts the attributes of the classes that it visits. * The sorting order is based on the types of the attributes. * * @author Eric Lafortune */ public class AttributeSorter extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, AttributeVisitor, Comparator { // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Sort the attributes. Arrays.sort(programClass.attributes, 0, programClass.u2attributesCount, this); // Sort the attributes of the class members. programClass.fieldsAccept(this); programClass.methodsAccept(this); } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { // Sort the attributes. Arrays.sort(programMember.attributes, 0, programMember.u2attributesCount, this); // Sort the attributes of the attributes. programMember.attributesAccept(programClass, this); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Sort the attributes. Arrays.sort(codeAttribute.attributes, 0, codeAttribute.u2attributesCount, this); } // Implementations for Comparator. public int compare(Object object1, Object object2) { Attribute attribute1 = (Attribute)object1; Attribute attribute2 = (Attribute)object2; return attribute1.u2attributeNameIndex < attribute2.u2attributeNameIndex ? -1 : attribute1.u2attributeNameIndex > attribute2.u2attributeNameIndex ? 1 : 0; } } proguard4.8/src/proguard/classfile/editor/LineNumberInfoAdder.java0000644000175000017500000000422011736333524024112 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.visitor.LineNumberInfoVisitor; import proguard.classfile.attribute.*; import proguard.classfile.*; /** * This LineNumberInfoVisitor adds all line numbers that it visits to the given * target line number attribute. */ public class LineNumberInfoAdder implements LineNumberInfoVisitor { private final LineNumberTableAttributeEditor lineNumberTableAttributeEditor; /** * Creates a new LineNumberInfoAdder that will copy line numbers into the * given target line number table. */ public LineNumberInfoAdder(LineNumberTableAttribute targetLineNumberTableAttribute) { this.lineNumberTableAttributeEditor = new LineNumberTableAttributeEditor(targetLineNumberTableAttribute); } // Implementations for LineNumberInfoVisitor. public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) { // Create a new line number. LineNumberInfo newLineNumberInfo = new LineNumberInfo(lineNumberInfo.u2startPC, lineNumberInfo.u2lineNumber); // Add it to the target. lineNumberTableAttributeEditor.addLineNumberInfo(newLineNumberInfo); } } proguard4.8/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java0000644000175000017500000000571111736333524025422 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.visitor.LocalVariableTypeInfoVisitor; import proguard.classfile.attribute.*; import proguard.classfile.*; /** * This LocalVariableTypeInfoVisitor adds all line numbers that it visits to the given * target line number attribute. */ public class LocalVariableTypeInfoAdder implements LocalVariableTypeInfoVisitor { private final ConstantAdder constantAdder; private final LocalVariableTypeTableAttributeEditor localVariableTypeTableAttributeEditor; /** * Creates a new LocalVariableTypeInfoAdder that will copy line numbers into the * given target line number table. */ public LocalVariableTypeInfoAdder(ProgramClass targetClass, LocalVariableTypeTableAttribute targetLocalVariableTypeTableAttribute) { this.constantAdder = new ConstantAdder(targetClass); this.localVariableTypeTableAttributeEditor = new LocalVariableTypeTableAttributeEditor(targetLocalVariableTypeTableAttribute); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { // Create a new line number. LocalVariableTypeInfo newLocalVariableTypeInfo = new LocalVariableTypeInfo(localVariableTypeInfo.u2startPC, localVariableTypeInfo.u2length, constantAdder.addConstant(clazz, localVariableTypeInfo.u2nameIndex), constantAdder.addConstant(clazz, localVariableTypeInfo.u2signatureIndex), localVariableTypeInfo.u2index); // TODO: Clone array. newLocalVariableTypeInfo.referencedClasses = localVariableTypeInfo.referencedClasses; // Add it to the target. localVariableTypeTableAttributeEditor.addLocalVariableTypeInfo(newLocalVariableTypeInfo); } }proguard4.8/src/proguard/classfile/editor/InstructionAdder.java0000644000175000017500000000536111736333524023566 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.instruction.*; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor adds all instructions that it visits to the given * target code attribute. * * @author Eric Lafortune */ public class InstructionAdder extends SimplifiedVisitor implements InstructionVisitor { private final ConstantAdder constantAdder; private final CodeAttributeComposer codeAttributeComposer; /** * Creates a new InstructionAdder that will copy classes into the given * target code attribute. */ public InstructionAdder(ProgramClass targetClass, CodeAttributeComposer targetComposer) { constantAdder = new ConstantAdder(targetClass); codeAttributeComposer = targetComposer; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { // Add the instruction. codeAttributeComposer.appendInstruction(offset, instruction); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Create a copy of the instruction. Instruction newConstantInstruction = new ConstantInstruction(constantInstruction.opcode, constantAdder.addConstant(clazz, constantInstruction.constantIndex), constantInstruction.constant).shrink(); // Add the instruction. codeAttributeComposer.appendInstruction(offset, newConstantInstruction); } }proguard4.8/src/proguard/classfile/editor/ExceptionsAttributeEditor.java0000644000175000017500000000502711736333524025460 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.ExceptionsAttribute; /** * This class can add exceptions to a given exceptions attribute. * Exceptions to be added must have been added to the constant pool and filled * out beforehand. * * @author Eric Lafortune */ public class ExceptionsAttributeEditor { private ExceptionsAttribute targetExceptionsAttribute; /** * Creates a new ExceptionsAttributeEditor that will edit exceptions in the * given exceptions attribute. */ public ExceptionsAttributeEditor(ExceptionsAttribute targetExceptionsAttribute) { this.targetExceptionsAttribute = targetExceptionsAttribute; } /** * Adds a given exception to the exceptions attribute. */ public void addException(int exceptionIndex) { int exceptionIndexTableLength = targetExceptionsAttribute.u2exceptionIndexTableLength; int[] exceptionIndexTable = targetExceptionsAttribute.u2exceptionIndexTable; // Make sure there is enough space for the new exception. if (exceptionIndexTable.length <= exceptionIndexTableLength) { targetExceptionsAttribute.u2exceptionIndexTable = new int[exceptionIndexTableLength+1]; System.arraycopy(exceptionIndexTable, 0, targetExceptionsAttribute.u2exceptionIndexTable, 0, exceptionIndexTableLength); exceptionIndexTable = targetExceptionsAttribute.u2exceptionIndexTable; } // Add the exception. exceptionIndexTable[targetExceptionsAttribute.u2exceptionIndexTableLength++] = exceptionIndex; } } proguard4.8/src/proguard/classfile/editor/AnnotationAdder.java0000644000175000017500000001372411736333524023361 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.AnnotationVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AnnotationVisitor adds all annotations that it visits to the given * target annotation element value, target annotation attribute, or target * parameter annotation attribute. * * @author Eric Lafortune */ public class AnnotationAdder extends SimplifiedVisitor implements AnnotationVisitor { private static final ElementValue[] EMPTY_ELEMENT_VALUES = new ElementValue[0]; private final ProgramClass targetClass; private final AnnotationElementValue targetAnnotationElementValue; private final AnnotationsAttributeEditor annotationsAttributeEditor; private final ParameterAnnotationsAttributeEditor parameterAnnotationsAttributeEditor; private final ConstantAdder constantAdder; /** * Creates a new AnnotationAdder that will copy annotations into the given * target annotation element value. */ public AnnotationAdder(ProgramClass targetClass, AnnotationElementValue targetAnnotationElementValue) { this.targetClass = targetClass; this.targetAnnotationElementValue = targetAnnotationElementValue; this.annotationsAttributeEditor = null; this.parameterAnnotationsAttributeEditor = null; constantAdder = new ConstantAdder(targetClass); } /** * Creates a new AnnotationAdder that will copy annotations into the given * target annotations attribute. */ public AnnotationAdder(ProgramClass targetClass, AnnotationsAttribute targetAnnotationsAttribute) { this.targetClass = targetClass; this.targetAnnotationElementValue = null; this.annotationsAttributeEditor = new AnnotationsAttributeEditor(targetAnnotationsAttribute); this.parameterAnnotationsAttributeEditor = null; constantAdder = new ConstantAdder(targetClass); } /** * Creates a new AnnotationAdder that will copy annotations into the given * target parameter annotations attribute. */ public AnnotationAdder(ProgramClass targetClass, ParameterAnnotationsAttribute targetParameterAnnotationsAttribute) { this.targetClass = targetClass; this.targetAnnotationElementValue = null; this.annotationsAttributeEditor = null; this.parameterAnnotationsAttributeEditor = new ParameterAnnotationsAttributeEditor(targetParameterAnnotationsAttribute); constantAdder = new ConstantAdder(targetClass); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { Annotation newAnnotation = new Annotation(constantAdder.addConstant(clazz, annotation.u2typeIndex), 0, annotation.u2elementValuesCount > 0 ? new ElementValue[annotation.u2elementValuesCount] : EMPTY_ELEMENT_VALUES); // TODO: Clone array. newAnnotation.referencedClasses = annotation.referencedClasses; // Add the element values. annotation.elementValuesAccept(clazz, new ElementValueAdder(targetClass, newAnnotation, false)); // What's the target? if (targetAnnotationElementValue != null) { // Simply set the completed annotation. targetAnnotationElementValue.annotationValue = newAnnotation; } else { // Add the completed annotation. annotationsAttributeEditor.addAnnotation(newAnnotation); } } public void visitAnnotation(Clazz clazz, Method method, int parameterIndex, Annotation annotation) { Annotation newAnnotation = new Annotation(constantAdder.addConstant(clazz, annotation.u2typeIndex), 0, annotation.u2elementValuesCount > 0 ? new ElementValue[annotation.u2elementValuesCount] : EMPTY_ELEMENT_VALUES); // TODO: Clone array. newAnnotation.referencedClasses = annotation.referencedClasses; // Add the element values. annotation.elementValuesAccept(clazz, new ElementValueAdder(targetClass, newAnnotation, false)); // Add the completed annotation. parameterAnnotationsAttributeEditor.addAnnotation(parameterIndex, newAnnotation); } }proguard4.8/src/proguard/classfile/editor/AnnotationsAttributeEditor.java0000644000175000017500000000462311736333524025635 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.annotation.*; /** * This class can add annotations to a given annotations attribute. * Annotations to be added must have been filled out beforehand. * * @author Eric Lafortune */ public class AnnotationsAttributeEditor { private AnnotationsAttribute targetAnnotationsAttribute; /** * Creates a new AnnotationsAttributeEditor that will edit annotations in * the given annotations attribute. */ public AnnotationsAttributeEditor(AnnotationsAttribute targetAnnotationsAttribute) { this.targetAnnotationsAttribute = targetAnnotationsAttribute; } /** * Adds a given annotation to the annotations attribute. */ public void addAnnotation(Annotation annotation) { int annotationsCount = targetAnnotationsAttribute.u2annotationsCount; Annotation[] annotations = targetAnnotationsAttribute.annotations; // Make sure there is enough space for the new annotation. if (annotations.length <= annotationsCount) { targetAnnotationsAttribute.annotations = new Annotation[annotationsCount+1]; System.arraycopy(annotations, 0, targetAnnotationsAttribute.annotations, 0, annotationsCount); annotations = targetAnnotationsAttribute.annotations; } // Add the annotation. annotations[targetAnnotationsAttribute.u2annotationsCount++] = annotation; } }proguard4.8/src/proguard/classfile/editor/ExceptionInfoAdder.java0000644000175000017500000000470711736333524024022 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.ExceptionInfoVisitor; /** * This ExceptionInfoVisitor adds all exception information that it visits to * the given target code attribute. * * @author Eric Lafortune */ public class ExceptionInfoAdder implements ExceptionInfoVisitor { private final ConstantAdder constantAdder; private final CodeAttributeComposer codeAttributeComposer; /** * Creates a new ExceptionAdder that will copy exceptions into the given * target code attribute. */ public ExceptionInfoAdder(ProgramClass targetClass, CodeAttributeComposer targetComposer) { constantAdder = new ConstantAdder(targetClass); codeAttributeComposer = targetComposer; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { // Create a copy of the exception info. ExceptionInfo newExceptionInfo = new ExceptionInfo(exceptionInfo.u2startPC, exceptionInfo.u2endPC, exceptionInfo.u2handlerPC, exceptionInfo.u2catchType == 0 ? 0 : constantAdder.addConstant(clazz, exceptionInfo.u2catchType)); // Add the completed exception info. codeAttributeComposer.appendException(newExceptionInfo); } }proguard4.8/src/proguard/classfile/editor/SubclassAdder.java0000644000175000017500000000324011736333524023016 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor adds the given class to the list of subclasses of the * classes that it visits. * * @author Eric Lafortune */ public class SubclassAdder implements ClassVisitor { private final Clazz subclass; /** * Creates a new SubclassAdder that will add the given subclass. */ public SubclassAdder(Clazz subclass) { this.subclass = subclass; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.addSubClass(subclass); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.addSubClass(subclass); } }proguard4.8/src/proguard/classfile/editor/MemberAdder.java0000644000175000017500000002737711736333524022467 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.Attribute; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; /** * This MemberVisitor copies all class members that it visits to the given * target class. Their visitor info is set to the class members from which they * were copied. * * @author Eric Lafortune */ public class MemberAdder extends SimplifiedVisitor implements MemberVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0]; private final ProgramClass targetClass; // private final boolean addFields; private final MemberVisitor extraMemberVisitor; private final ConstantAdder constantAdder; private final ClassEditor classEditor; private final ConstantPoolEditor constantPoolEditor; /** * Creates a new MemberAdder that will copy methods into the given target * class. * @param targetClass the class to which all visited class members will be * added. */ public MemberAdder(ProgramClass targetClass) { this(targetClass, null); } /** * Creates a new MemberAdder that will copy methods into the given target * class. * @param targetClass the class to which all visited class members * will be added. * @param extraMemberVisitor an optional member visitor that visits each * new member right after it has been added. This * allows changing the visitor info, for instance. */ // * @param addFields specifies whether fields should be added, or fused // * with the present fields. public MemberAdder(ProgramClass targetClass, // boolean addFields, MemberVisitor extraMemberVisitor) { this.targetClass = targetClass; // this.addFields = addFields; this.extraMemberVisitor = extraMemberVisitor; constantAdder = new ConstantAdder(targetClass); classEditor = new ClassEditor(targetClass); constantPoolEditor = new ConstantPoolEditor(targetClass); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { String name = programField.getName(programClass); String descriptor = programField.getDescriptor(programClass); int accessFlags = programField.getAccessFlags(); // Does the target class already have such a field? ProgramField targetField = (ProgramField)targetClass.findField(name, descriptor); if (targetField != null) { // Is the field private or static? int targetAccessFlags = targetField.getAccessFlags(); if ((targetAccessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC)) != 0) { if (DEBUG) { System.out.println("MemberAdder: renaming field ["+targetClass+"."+targetField.getName(targetClass)+" "+targetField.getDescriptor(targetClass)+"]"); } // Rename the private or static field. targetField.u2nameIndex = constantPoolEditor.addUtf8Constant(newUniqueMemberName(name, targetClass.getName())); } // else // { // // Keep the non-private and non-static field, but update its // // contents, in order to keep any references to it valid. // if (DEBUG) // { // System.out.println("MemberAdder: updating field ["+programClass+"."+programField.getName(programClass)+" "+programField.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]"); // } // // // Combine the access flags. // targetField.u2accessFlags = accessFlags | targetAccessFlags; // // // Add and replace any attributes. // programField.attributesAccept(programClass, // new AttributeAdder(targetClass, // targetField, // true)); // // // Don't add a new field. // return; // } } if (DEBUG) { System.out.println("MemberAdder: copying field ["+programClass+"."+programField.getName(programClass)+" "+programField.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]"); } // Create a copy of the field. ProgramField newProgramField = new ProgramField(accessFlags, constantAdder.addConstant(programClass, programField.u2nameIndex), constantAdder.addConstant(programClass, programField.u2descriptorIndex), 0, programField.u2attributesCount > 0 ? new Attribute[programField.u2attributesCount] : EMPTY_ATTRIBUTES, programField.referencedClass); // Link to its visitor info. newProgramField.setVisitorInfo(programField); // Copy its attributes. programField.attributesAccept(programClass, new AttributeAdder(targetClass, newProgramField, false)); // Add the completed field. classEditor.addField(newProgramField); // Visit the newly added field, if necessary. if (extraMemberVisitor != null) { extraMemberVisitor.visitProgramField(targetClass, newProgramField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { String name = programMethod.getName(programClass); String descriptor = programMethod.getDescriptor(programClass); int accessFlags = programMethod.getAccessFlags(); // Does the target class already have such a method? ProgramMethod targetMethod = (ProgramMethod)targetClass.findMethod(name, descriptor); if (targetMethod != null) { // is this source method abstract? if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) { // Keep the target method. if (DEBUG) { System.out.println("MemberAdder: skipping abstract method ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]"); } // Don't add a new method. return; } // Is the target method abstract? int targetAccessFlags = targetMethod.getAccessFlags(); if ((targetAccessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) { // Keep the abstract method, but update its contents, in order // to keep any references to it valid. if (DEBUG) { System.out.println("MemberAdder: updating method ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]"); } // Replace the access flags. targetMethod.u2accessFlags = accessFlags & ~ClassConstants.INTERNAL_ACC_FINAL; // Add and replace the attributes. programMethod.attributesAccept(programClass, new AttributeAdder(targetClass, targetMethod, true)); // Don't add a new method. return; } if (DEBUG) { System.out.println("MemberAdder: renaming method ["+targetClass.getName()+"."+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]"); } // Rename the private (non-abstract) or static method. targetMethod.u2nameIndex = constantPoolEditor.addUtf8Constant(newUniqueMemberName(name, descriptor)); } if (DEBUG) { System.out.println("MemberAdder: copying method ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]"); } // Create a copy of the method. ProgramMethod newProgramMethod = new ProgramMethod(accessFlags & ~ClassConstants.INTERNAL_ACC_FINAL, constantAdder.addConstant(programClass, programMethod.u2nameIndex), constantAdder.addConstant(programClass, programMethod.u2descriptorIndex), 0, programMethod.u2attributesCount > 0 ? new Attribute[programMethod.u2attributesCount] : EMPTY_ATTRIBUTES, programMethod.referencedClasses != null ? (Clazz[])programMethod.referencedClasses.clone() : null); // Link to its visitor info. newProgramMethod.setVisitorInfo(programMethod); // Copy its attributes. programMethod.attributesAccept(programClass, new AttributeAdder(targetClass, newProgramMethod, false)); // Add the completed method. classEditor.addMethod(newProgramMethod); // Visit the newly added method, if necessary. if (extraMemberVisitor != null) { extraMemberVisitor.visitProgramMethod(targetClass, newProgramMethod); } } // Small utility methods. /** * Returns a unique class member name, based on the given name and descriptor. */ private String newUniqueMemberName(String name, String descriptor) { return name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ? ClassConstants.INTERNAL_METHOD_NAME_INIT : name + ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode())); } } proguard4.8/src/proguard/classfile/editor/SubclassToAdder.java0000644000175000017500000000332611736333524023326 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor adds all classes that it visits to the list of subclasses * of the given target class. * * @author Eric Lafortune */ public class SubclassToAdder implements ClassVisitor { private final Clazz targetClass; /** * Creates a new SubclassAdder that will add subclasses to the given * target class. */ public SubclassToAdder(Clazz targetClass) { this.targetClass = targetClass; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { targetClass.addSubClass(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { targetClass.addSubClass(libraryClass); } }proguard4.8/src/proguard/classfile/editor/AttributesEditor.java0000644000175000017500000002140311736333524023575 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; /** * This class can add and delete attributes to and from classes, fields, * methods, and code attributes. Attributes to be added must be filled out * beforehand, including their references to the constant pool. Existing * attributes of the same type are always replaced. * * @author Eric Lafortune */ public class AttributesEditor { private final ProgramClass targetClass; private final ProgramMember targetMember; private final CodeAttribute targetAttribute; private final boolean replaceAttributes; /** * Creates a new AttributeAdder that will edit attributes in the given * target class. */ public AttributesEditor(ProgramClass targetClass, boolean replaceAttributes) { this(targetClass, null, null, replaceAttributes); } /** * Creates a new AttributeAdder that will edit attributes in the given * target class member. */ public AttributesEditor(ProgramClass targetClass, ProgramMember targetMember, boolean replaceAttributes) { this(targetClass, targetMember, null, replaceAttributes); } /** * Creates a new AttributeAdder that will edit attributes in the given * target code attribute. */ public AttributesEditor(ProgramClass targetClass, ProgramMember targetMember, CodeAttribute targetAttribute, boolean replaceAttributes) { this.targetClass = targetClass; this.targetMember = targetMember; this.targetAttribute = targetAttribute; this.replaceAttributes = replaceAttributes; } /** * Adds the given attribute to the target. */ public void addAttribute(Attribute attribute) { // What's the target? if (targetAttribute != null) { // Try to replace an existing attribute. if (!replaceAttributes || !replaceAttribute(targetAttribute.u2attributesCount, targetAttribute.attributes, attribute)) { // Otherwise append the attribute. targetAttribute.attributes = addAttribute(targetAttribute.u2attributesCount, targetAttribute.attributes, attribute); targetAttribute.u2attributesCount++; } } else if (targetMember != null) { // Try to replace an existing attribute. if (!replaceAttributes || !replaceAttribute(targetMember.u2attributesCount, targetMember.attributes, attribute)) { // Otherwise append the attribute. targetMember.attributes = addAttribute(targetMember.u2attributesCount, targetMember.attributes, attribute); targetMember.u2attributesCount++; } } else { // Try to replace an existing attribute. if (!replaceAttributes || !replaceAttribute(targetClass.u2attributesCount, targetClass.attributes, attribute)) { // Otherwise append the attribute. targetClass.attributes = addAttribute(targetClass.u2attributesCount, targetClass.attributes, attribute); targetClass.u2attributesCount++; } } } /** * Deletes the specified attribute from the target. */ public void deleteAttribute(String attributeName) { // What's the target? if (targetAttribute != null) { targetAttribute.u2attributesCount = deleteAttribute(targetAttribute.u2attributesCount, targetAttribute.attributes, attributeName); } else if (targetMember != null) { targetMember.u2attributesCount = deleteAttribute(targetMember.u2attributesCount, targetMember.attributes, attributeName); } else { targetClass.u2attributesCount = deleteAttribute(targetClass.u2attributesCount, targetClass.attributes, attributeName); } } // Small utility methods. /** * Tries put the given attribute in place of an existing attribute of the * same name, returning whether it was present. */ private boolean replaceAttribute(int attributesCount, Attribute[] attributes, Attribute attribute) { // Find the attribute with the same name. int index = findAttribute(attributesCount, attributes, attribute.getAttributeName(targetClass)); if (index < 0) { return false; } attributes[index] = attribute; return true; } /** * Appends the given attribute to the given array of attributes, creating a * new array if necessary. */ private Attribute[] addAttribute(int attributesCount, Attribute[] attributes, Attribute attribute) { // Is the array too small to contain the additional attribute? if (attributes.length <= attributesCount) { // Create a new array and copy the attributes into it. Attribute[] newAttributes = new Attribute[attributesCount + 1]; System.arraycopy(attributes, 0, newAttributes, 0, attributesCount); attributes = newAttributes; } // Append the attribute. attributes[attributesCount] = attribute; return attributes; } /** * Deletes the attributes with the given name from the given array of * attributes, returning the new number of attributes. */ private int deleteAttribute(int attributesCount, Attribute[] attributes, String attributeName) { // Find the attribute. int index = findAttribute(attributesCount, attributes, attributeName); if (index < 0) { return attributesCount; } // Shift the other attributes in the array. System.arraycopy(attributes, index + 1, attributes, index, attributesCount - index - 1); // Clear the last entry in the array. attributes[--attributesCount] = null; return attributesCount; } /** * Finds the index of the attribute with the given name in the given * array of attributes. */ private int findAttribute(int attributesCount, Attribute[] attributes, String attributeName) { for (int index = 0; index < attributesCount; index++) { if (attributes[index].getAttributeName(targetClass).equals(attributeName)) { return index; } } return -1; } } proguard4.8/src/proguard/classfile/editor/NamedAttributeDeleter.java0000644000175000017500000000317011736333524024516 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.visitor.*; import proguard.util.StringMatcher; /** * This ClassVisitor deletes attributes with a given name in the program * classes that it visits. * * @author Eric Lafortune */ public class NamedAttributeDeleter implements ClassVisitor { private final String attributeName; public NamedAttributeDeleter(String attributeName) { this.attributeName = attributeName; } // Implementations for ClassVisitor. public void visitLibraryClass(LibraryClass libraryClass) {} public void visitProgramClass(ProgramClass programClass) { new AttributesEditor(programClass, false).deleteAttribute(attributeName); } }proguard4.8/src/proguard/classfile/editor/LocalVariableInfoAdder.java0000644000175000017500000000542411736333524024561 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.visitor.LocalVariableInfoVisitor; import proguard.classfile.attribute.*; import proguard.classfile.*; /** * This LocalVariableInfoVisitor adds all line numbers that it visits to the given * target line number attribute. */ public class LocalVariableInfoAdder implements LocalVariableInfoVisitor { private final ConstantAdder constantAdder; private final LocalVariableTableAttributeEditor localVariableTableAttributeEditor; /** * Creates a new LocalVariableInfoAdder that will copy line numbers into the * given target line number table. */ public LocalVariableInfoAdder(ProgramClass targetClass, LocalVariableTableAttribute targetLocalVariableTableAttribute) { this.constantAdder = new ConstantAdder(targetClass); this.localVariableTableAttributeEditor = new LocalVariableTableAttributeEditor(targetLocalVariableTableAttribute); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Create a new line number. LocalVariableInfo newLocalVariableInfo = new LocalVariableInfo(localVariableInfo.u2startPC, localVariableInfo.u2length, constantAdder.addConstant(clazz, localVariableInfo.u2nameIndex), constantAdder.addConstant(clazz, localVariableInfo.u2descriptorIndex), localVariableInfo.u2index); newLocalVariableInfo.referencedClass = localVariableInfo.referencedClass; // Add it to the target. localVariableTableAttributeEditor.addLocalVariableInfo(newLocalVariableInfo); } }proguard4.8/src/proguard/classfile/editor/ClassReferenceFixer.java0000644000175000017500000004704711736333524024176 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** * This ClassVisitor fixes references of constant pool entries, fields, * methods, and attributes to classes whose names have changed. Descriptors * of member references are not updated yet. * * @see MemberReferenceFixer * @author Eric Lafortune */ public class ClassReferenceFixer extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, MemberVisitor, AttributeVisitor, InnerClassesInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { private final boolean ensureUniqueMemberNames; /** * Creates a new ClassReferenceFixer. * @param ensureUniqueMemberNames specifies whether class members whose * descriptor changes should get new, unique * names, in order to avoid naming conflicts * with similar methods. */ public ClassReferenceFixer(boolean ensureUniqueMemberNames) { this.ensureUniqueMemberNames = ensureUniqueMemberNames; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Fix the constant pool. programClass.constantPoolEntriesAccept(this); // Fix class members. programClass.fieldsAccept(this); programClass.methodsAccept(this); // Fix the attributes. programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { // Fix class members. libraryClass.fieldsAccept(this); libraryClass.methodsAccept(this); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Has the descriptor changed? String descriptor = programField.getDescriptor(programClass); String newDescriptor = newDescriptor(descriptor, programField.referencedClass); if (!descriptor.equals(newDescriptor)) { ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor(programClass); // Update the descriptor. programField.u2descriptorIndex = constantPoolEditor.addUtf8Constant(newDescriptor); // Update the name, if requested. if (ensureUniqueMemberNames) { String name = programField.getName(programClass); String newName = newUniqueMemberName(name, descriptor); programField.u2nameIndex = constantPoolEditor.addUtf8Constant(newName); } } // Fix the attributes. programField.attributesAccept(programClass, this); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Has the descriptor changed? String descriptor = programMethod.getDescriptor(programClass); String newDescriptor = newDescriptor(descriptor, programMethod.referencedClasses); if (!descriptor.equals(newDescriptor)) { ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor(programClass); // Update the descriptor. programMethod.u2descriptorIndex = constantPoolEditor.addUtf8Constant(newDescriptor); // Update the name, if requested. if (ensureUniqueMemberNames) { String name = programMethod.getName(programClass); String newName = newUniqueMemberName(name, descriptor); programMethod.u2nameIndex = constantPoolEditor.addUtf8Constant(newName); } } // Fix the attributes. programMethod.attributesAccept(programClass, this); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { // Has the descriptor changed? String descriptor = libraryField.getDescriptor(libraryClass); String newDescriptor = newDescriptor(descriptor, libraryField.referencedClass); // Update the descriptor. libraryField.descriptor = newDescriptor; } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { // Has the descriptor changed? String descriptor = libraryMethod.getDescriptor(libraryClass); String newDescriptor = newDescriptor(descriptor, libraryMethod.referencedClasses); // Update the descriptor. libraryMethod.descriptor = newDescriptor; } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Does the string refer to a class, due to a Class.forName construct? Clazz referencedClass = stringConstant.referencedClass; Member referencedMember = stringConstant.referencedMember; if (referencedClass != null && referencedMember == null) { // Reconstruct the new class name. String externalClassName = stringConstant.getString(clazz); String internalClassName = ClassUtil.internalClassName(externalClassName); String newInternalClassName = newClassName(internalClassName, referencedClass); // Update the String entry if required. if (!newInternalClassName.equals(internalClassName)) { String newExternalClassName = ClassUtil.externalClassName(newInternalClassName); // Refer to a new Utf8 entry. stringConstant.u2stringIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newExternalClassName); } } } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Do we know the referenced class? Clazz referencedClass = classConstant.referencedClass; if (referencedClass != null) { // Has the class name changed? String className = classConstant.getName(clazz); String newClassName = newClassName(className, referencedClass); if (!className.equals(newClassName)) { // Refer to a new Utf8 entry. classConstant.u2nameIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newClassName); } } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Fix the inner class names. innerClassesAttribute.innerClassEntriesAccept(clazz, this); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Fix the attributes. codeAttribute.attributesAccept(clazz, method, this); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Fix the types of the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Fix the signatures of the local variables. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { // Compute the new signature. String signature = clazz.getString(signatureAttribute.u2signatureIndex); String newSignature = newDescriptor(signature, signatureAttribute.referencedClasses); if (!signature.equals(newSignature)) { signatureAttribute.u2signatureIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature); } } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Fix the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Fix the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Fix the annotation. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { // Fix the inner class name. int innerClassIndex = innerClassesInfo.u2innerClassIndex; int innerNameIndex = innerClassesInfo.u2innerNameIndex; if (innerClassIndex != 0 && innerNameIndex != 0) { String newInnerName = clazz.getClassName(innerClassIndex); int index = newInnerName.lastIndexOf(ClassConstants.INTERNAL_INNER_CLASS_SEPARATOR); if (index >= 0) { innerClassesInfo.u2innerNameIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newInnerName.substring(index + 1)); } } } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Has the descriptor changed? String descriptor = clazz.getString(localVariableInfo.u2descriptorIndex); String newDescriptor = newDescriptor(descriptor, localVariableInfo.referencedClass); if (!descriptor.equals(newDescriptor)) { // Refer to a new Utf8 entry. localVariableInfo.u2descriptorIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newDescriptor); } } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { // Has the signature changed? String signature = clazz.getString(localVariableTypeInfo.u2signatureIndex); String newSignature = newDescriptor(signature, localVariableTypeInfo.referencedClasses); if (!signature.equals(newSignature)) { localVariableTypeInfo.u2signatureIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature); } } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { // Compute the new type name. String typeName = clazz.getString(annotation.u2typeIndex); String newTypeName = newDescriptor(typeName, annotation.referencedClasses); if (!typeName.equals(newTypeName)) { // Refer to a new Utf8 entry. annotation.u2typeIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newTypeName); } // Fix the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { // Compute the new type name. String typeName = clazz.getString(enumConstantElementValue.u2typeNameIndex); String newTypeName = newDescriptor(typeName, enumConstantElementValue.referencedClasses); if (!typeName.equals(newTypeName)) { // Refer to a new Utf8 entry. enumConstantElementValue.u2typeNameIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newTypeName); } } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { // Compute the new class name. String className = clazz.getString(classElementValue.u2classInfoIndex); String newClassName = newDescriptor(className, classElementValue.referencedClasses); if (!className.equals(newClassName)) { // Refer to a new Utf8 entry. classElementValue.u2classInfoIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newClassName); } } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { // Fix the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { // Fix the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } // Small utility methods. private static String newDescriptor(String descriptor, Clazz referencedClass) { // If there is no referenced class, the descriptor won't change. if (referencedClass == null) { return descriptor; } // Unravel and reconstruct the class element of the descriptor. DescriptorClassEnumeration descriptorClassEnumeration = new DescriptorClassEnumeration(descriptor); StringBuffer newDescriptorBuffer = new StringBuffer(descriptor.length()); newDescriptorBuffer.append(descriptorClassEnumeration.nextFluff()); // Only if the descriptor contains a class name (e.g. with an array of // primitive types), the descriptor can change. if (descriptorClassEnumeration.hasMoreClassNames()) { String className = descriptorClassEnumeration.nextClassName(); String fluff = descriptorClassEnumeration.nextFluff(); String newClassName = newClassName(className, referencedClass); newDescriptorBuffer.append(newClassName); newDescriptorBuffer.append(fluff); } return newDescriptorBuffer.toString(); } private static String newDescriptor(String descriptor, Clazz[] referencedClasses) { // If there are no referenced classes, the descriptor won't change. if (referencedClasses == null || referencedClasses.length == 0) { return descriptor; } // Unravel and reconstruct the class elements of the descriptor. DescriptorClassEnumeration descriptorClassEnumeration = new DescriptorClassEnumeration(descriptor); StringBuffer newDescriptorBuffer = new StringBuffer(descriptor.length()); newDescriptorBuffer.append(descriptorClassEnumeration.nextFluff()); int index = 0; while (descriptorClassEnumeration.hasMoreClassNames()) { String className = descriptorClassEnumeration.nextClassName(); boolean isInnerClassName = descriptorClassEnumeration.isInnerClassName(); String fluff = descriptorClassEnumeration.nextFluff(); String newClassName = newClassName(className, referencedClasses[index++]); // Strip the outer class name again, if it's an inner class. if (isInnerClassName) { newClassName = newClassName.substring(newClassName.lastIndexOf(ClassConstants.INTERNAL_INNER_CLASS_SEPARATOR)+1); } newDescriptorBuffer.append(newClassName); newDescriptorBuffer.append(fluff); } return newDescriptorBuffer.toString(); } /** * Returns a unique class member name, based on the given name and descriptor. */ private String newUniqueMemberName(String name, String descriptor) { return name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ? ClassConstants.INTERNAL_METHOD_NAME_INIT : name + ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode())); } /** * Returns the new class name based on the given class name and the new * name of the given referenced class. Class names of array types * are handled properly. */ private static String newClassName(String className, Clazz referencedClass) { // If there is no referenced class, the class name won't change. if (referencedClass == null) { return className; } // Reconstruct the class name. String newClassName = referencedClass.getName(); // Is it an array type? if (className.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY) { // Add the array prefixes and suffix "[L...;". newClassName = className.substring(0, className.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1) + newClassName + ClassConstants.INTERNAL_TYPE_CLASS_END; } return newClassName; } } proguard4.8/src/proguard/classfile/editor/VariableSizeUpdater.java0000644000175000017500000000710611736333524024211 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; /** * This AttributeVisitor computes and updates the maximum local variable frame * size of the code attributes that it visits. It also cleans up the local * variable tables. * * @author Eric Lafortune */ public class VariableSizeUpdater extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private VariableCleaner variableCleaner = new VariableCleaner(); // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // The minimum variable size is determined by the arguments. codeAttribute.u2maxLocals = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), method.getAccessFlags()); if (DEBUG) { System.out.println("VariableSizeUpdater: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); System.out.println(" Max locals: "+codeAttribute.u2maxLocals+" <- parameters"); } // Go over all instructions. codeAttribute.instructionsAccept(clazz, method, this); // Remove the unused variables of the attributes. variableCleaner.visitCodeAttribute(clazz, method, codeAttribute); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { int variableSize = variableInstruction.variableIndex + 1; if (variableInstruction.isCategory2()) { variableSize++; } if (codeAttribute.u2maxLocals < variableSize) { codeAttribute.u2maxLocals = variableSize; if (DEBUG) { System.out.println(" Max locals: "+codeAttribute.u2maxLocals+" <- "+variableInstruction.toString(offset)); } } } } proguard4.8/src/proguard/classfile/editor/NameAndTypeShrinker.java0000644000175000017500000001360011736333524024153 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.ConstantPoolRemapper; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; import java.util.Arrays; /** * This ClassVisitor removes NameAndType constant pool entries that are not * used. * * @author Eric Lafortune */ public class NameAndTypeShrinker extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, AttributeVisitor { // A visitor info flag to indicate the NameAndType constant pool entry is being used. private static final Object USED = new Object(); private int[] constantIndexMap; private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Mark the NameAndType entries referenced by all other constant pool // entries. programClass.constantPoolEntriesAccept(this); // Mark the NameAndType entries referenced by all EnclosingMethod // attributes. programClass.attributesAccept(this); // Shift the used constant pool entries together, filling out the // index map. int newConstantPoolCount = shrinkConstantPool(programClass.constantPool, programClass.u2constantPoolCount); // Remap the references to the constant pool if it has shrunk. if (newConstantPoolCount < programClass.u2constantPoolCount) { programClass.u2constantPoolCount = newConstantPoolCount; // Remap all constant pool references. constantPoolRemapper.setConstantIndexMap(constantIndexMap); constantPoolRemapper.visitProgramClass(programClass); } } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { markNameAndTypeConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { markNameAndTypeConstant(clazz, refConstant.u2nameAndTypeIndex); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) { markNameAndTypeConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex); } } // Small utility methods. /** * Marks the given UTF-8 constant pool entry of the given class. */ private void markNameAndTypeConstant(Clazz clazz, int index) { markAsUsed((NameAndTypeConstant)((ProgramClass)clazz).getConstant(index)); } /** * Marks the given VisitorAccepter as being used. * In this context, the VisitorAccepter will be a NameAndTypeConstant object. */ private void markAsUsed(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(USED); } /** * Returns whether the given VisitorAccepter has been marked as being used. * In this context, the VisitorAccepter will be a NameAndTypeConstant object. */ private boolean isUsed(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() == USED; } /** * Removes all NameAndType entries that are not marked as being used * from the given constant pool. * @return the new number of entries. */ private int shrinkConstantPool(Constant[] constantPool, int length) { // Create a new index map, if necessary. if (constantIndexMap == null || constantIndexMap.length < length) { constantIndexMap = new int[length]; } int counter = 1; boolean isUsed = false; // Shift the used constant pool entries together. for (int index = 1; index < length; index++) { constantIndexMap[index] = counter; Constant constant = constantPool[index]; // Don't update the flag if this is the second half of a long entry. if (constant != null) { isUsed = constant.getTag() != ClassConstants.CONSTANT_NameAndType || isUsed(constant); } if (isUsed) { constantPool[counter++] = constant; } } // Clear the remaining constant pool elements. Arrays.fill(constantPool, counter, length, null); return counter; } } proguard4.8/src/proguard/classfile/editor/ConstantAdder.java0000644000175000017500000002116011736333524023031 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.util.ListUtil; /** * This ConstantVisitor adds all constants that it visits to the constant pool * of a given target class. * * @author Eric Lafortune */ public class ConstantAdder implements ConstantVisitor { private final ConstantPoolEditor constantPoolEditor; private int constantIndex; /** * Creates a new ConstantAdder that will copy constants into the given * target class. */ public ConstantAdder(ProgramClass targetClass) { constantPoolEditor = new ConstantPoolEditor(targetClass); } /** * Adds a copy of the specified constant in the given class and returns * its index. If the specified index is 0, the returned value is 0 too. */ public int addConstant(Clazz clazz, int constantIndex) { clazz.constantPoolEntryAccept(constantIndex, this); return this.constantIndex; } /** * Adds a copy of the given constant in the given class and returns * its index. */ public int addConstant(Clazz clazz, Constant constant) { constant.accept(clazz, this); return this.constantIndex; } /** * Returns the index of the most recently created constant in the constant * pool of the target class. */ public int getConstantIndex() { return constantIndex; } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { constantIndex = constantPoolEditor.addIntegerConstant(integerConstant.getValue()); } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { constantIndex = constantPoolEditor.addLongConstant(longConstant.getValue()); } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { constantIndex = constantPoolEditor.addFloatConstant(floatConstant.getValue()); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { constantIndex = constantPoolEditor.addDoubleConstant(doubleConstant.getValue()); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { constantIndex = constantPoolEditor.addStringConstant(stringConstant.getString(clazz), stringConstant.referencedClass, stringConstant.referencedMember); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { constantIndex = constantPoolEditor.addUtf8Constant(utf8Constant.getString()); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { // First add the name and type constant. clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this); // Copy the referenced classes. Clazz[] referencedClasses = invokeDynamicConstant.referencedClasses; Clazz[] referencedClassesCopy = null; if (referencedClasses != null) { referencedClassesCopy = new Clazz[referencedClasses.length]; System.arraycopy(referencedClasses, 0, referencedClassesCopy, 0, referencedClasses.length); } // Then add the actual invoke dynamic constant. constantIndex = constantPoolEditor.addInvokeDynamicConstant(invokeDynamicConstant.getBootstrapMethodAttributeIndex(), constantIndex, referencedClassesCopy); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { // First add the field ref, interface method ref, or method ref // constant. clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); // Then add the actual method handle constant. constantIndex = constantPoolEditor.addMethodHandleConstant(methodHandleConstant.getReferenceKind(), constantIndex); } public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { // First add the referenced class constant, with its own referenced class. clazz.constantPoolEntryAccept(fieldrefConstant.u2classIndex, this); // Then add the actual field reference constant, with its referenced // class and class member. constantIndex = constantPoolEditor.addFieldrefConstant(constantIndex, fieldrefConstant.getName(clazz), fieldrefConstant.getType(clazz), fieldrefConstant.referencedClass, fieldrefConstant.referencedMember); } public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) { // First add the referenced class constant, with its own referenced class. clazz.constantPoolEntryAccept(interfaceMethodrefConstant.u2classIndex, this); // Then add the actual interface method reference constant, with its // referenced class and class member. constantIndex = constantPoolEditor.addInterfaceMethodrefConstant(constantIndex, interfaceMethodrefConstant.getName(clazz), interfaceMethodrefConstant.getType(clazz), interfaceMethodrefConstant.referencedClass, interfaceMethodrefConstant.referencedMember); } public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { // First add the referenced class constant, with its own referenced class. clazz.constantPoolEntryAccept(methodrefConstant.u2classIndex, this); // Then add the actual method reference constant, with its referenced // class and class member. constantIndex = constantPoolEditor.addMethodrefConstant(constantIndex, methodrefConstant.getName(clazz), methodrefConstant.getType(clazz), methodrefConstant.referencedClass, methodrefConstant.referencedMember); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Add the class constant, with its referenced class.. constantIndex = constantPoolEditor.addClassConstant(classConstant.getName(clazz), classConstant.referencedClass); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { constantIndex = constantPoolEditor.addMethodTypeConstant(methodTypeConstant.getType(clazz)); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { constantIndex = constantPoolEditor.addNameAndTypeConstant(nameAndTypeConstant.getName(clazz), nameAndTypeConstant.getType(clazz)); } } proguard4.8/src/proguard/classfile/editor/VariableEditor.java0000644000175000017500000000751411736333524023203 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; import java.util.Arrays; /** * This AttributeVisitor accumulates specified changes to local variables, and * then applies these accumulated changes to the code attributes that it visits. * * @author Eric Lafortune */ public class VariableEditor extends SimplifiedVisitor implements AttributeVisitor { private boolean modified; private boolean[] deleted = new boolean[ClassConstants.TYPICAL_VARIABLES_SIZE]; private int[] variableMap = new int[ClassConstants.TYPICAL_VARIABLES_SIZE]; private final VariableRemapper variableRemapper = new VariableRemapper(); /** * Resets the accumulated code changes. * @param maxLocals the length of the local variable frame that will be * edited next. */ public void reset(int maxLocals) { // Try to reuse the previous array. if (deleted.length < maxLocals) { // Create a new array. deleted = new boolean[maxLocals]; } else { // Reset the array. Arrays.fill(deleted, 0, maxLocals, false); } modified = false; } /** * Remembers to delete the given variable. * @param variableIndex the index of the variable to be deleted. */ public void deleteVariable(int variableIndex) { deleted[variableIndex] = true; modified = true; } /** * Returns whether the given variable at the given offset has deleted. */ public boolean isDeleted(int instructionOffset) { return deleted[instructionOffset]; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Avoid doing any work if nothing is changing anyway. if (!modified) { return; } int oldMaxLocals = codeAttribute.u2maxLocals; // Make sure there is a sufficiently large variable map. if (variableMap.length < oldMaxLocals) { variableMap = new int[oldMaxLocals]; } // Fill out the variable map. int newVariableIndex = 0; for (int oldVariableIndex = 0; oldVariableIndex < oldMaxLocals; oldVariableIndex++) { variableMap[oldVariableIndex] = deleted[oldVariableIndex] ? -1 : newVariableIndex++; } // Set the map. variableRemapper.setVariableMap(variableMap); // Remap the variables. variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); // Update the length of local variable frame. codeAttribute.u2maxLocals = newVariableIndex; } } proguard4.8/src/proguard/classfile/editor/AccessFixer.java0000664000175000017500000001424711740564012022502 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** * This ConstantVisitor fixes the access modifiers of all classes and class * members that are referenced by the constants that it visits. * * @author Eric Lafortune */ public class AccessFixer extends SimplifiedVisitor implements ConstantVisitor, ClassVisitor, MemberVisitor { private MyReferencedClassFinder referencedClassFinder = new MyReferencedClassFinder(); private Clazz referencingClass; private Clazz referencedClass; // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { referencingClass = clazz; referencedClass = stringConstant.referencedClass; // Make sure the access flags of the referenced class or class member, // if any, are acceptable. stringConstant.referencedClassAccept(this); stringConstant.referencedMemberAccept(this); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { // Check the bootstrap method. invokeDynamicConstant.bootstrapMethodHandleAccept(clazz, this); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { // Check the method reference. clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { referencingClass = clazz; // Remember the specified class, since it might be different from // the referenced class that actually contains the class member. clazz.constantPoolEntryAccept(refConstant.u2classIndex, referencedClassFinder); // Make sure the access flags of the referenced class member are // acceptable. refConstant.referencedMemberAccept(this); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { referencingClass = clazz; // Make sure the access flags of the referenced class are acceptable. classConstant.referencedClassAccept(this); } // Implementations for ClassVisitor. public void visitLibraryClass(LibraryClass libraryClass) {} public void visitProgramClass(ProgramClass programClass) { int currentAccessFlags = programClass.getAccessFlags(); int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); // Compute the required access level. Clazz referencingClass = this.referencingClass; int requiredAccessLevel = inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE : AccessUtil.PUBLIC; // Fix the class access flags if necessary. if (currentAccessLevel < requiredAccessLevel) { programClass.u2accessFlags = AccessUtil.replaceAccessFlags(currentAccessFlags, AccessUtil.accessFlags(requiredAccessLevel)); } } // Implementations for MemberVisitor. public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {} public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { int currentAccessFlags = programMember.getAccessFlags(); int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); // Compute the required access level. int requiredAccessLevel = programClass.equals(referencingClass) ? AccessUtil.PRIVATE : inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE : referencedClass.extends_(referencingClass) && referencingClass.extends_(programClass) ? AccessUtil.PROTECTED : AccessUtil.PUBLIC; // Fix the class member access flags if necessary. if (currentAccessLevel < requiredAccessLevel) { programMember.u2accessFlags = AccessUtil.replaceAccessFlags(currentAccessFlags, AccessUtil.accessFlags(requiredAccessLevel)); } } /** * This ConstantVisitor returns the referenced class of the class constant * that it visits. */ private class MyReferencedClassFinder extends SimplifiedVisitor implements ConstantVisitor { // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { referencedClass = classConstant.referencedClass; } } // Small utility methods. private boolean inSamePackage(ProgramClass class1, Clazz class2) { return ClassUtil.internalPackageName(class1.getName()).equals( ClassUtil.internalPackageName(class2.getName())); } } proguard4.8/src/proguard/classfile/editor/CodeAttributeEditorResetter.java0000644000175000017500000000371511736333524025731 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor resets it CodeAttributeEditor whenever it visits a * code attribute. * * @author Eric Lafortune */ public class CodeAttributeEditorResetter extends SimplifiedVisitor implements AttributeVisitor { private final CodeAttributeEditor codeAttributeEditor; /** * Creates a new CodeAttributeEditorResetter. * @param codeAttributeEditor the code attribute editor that will be reset. */ public CodeAttributeEditorResetter(CodeAttributeEditor codeAttributeEditor) { this.codeAttributeEditor = codeAttributeEditor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { codeAttributeEditor.reset(codeAttribute.u4codeLength); } } proguard4.8/src/proguard/classfile/editor/MethodInvocationFixer.java0000644000175000017500000002333011736333524024551 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; /** * This AttributeVisitor fixes all inappropriate special/virtual/static/interface * invocations of the code attributes that it visits. * * @author Eric Lafortune */ public class MethodInvocationFixer extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ConstantVisitor { private static final boolean DEBUG = false; private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); // Return values for the visitor methods. private Clazz referencedClass; private Clazz referencedMethodClass; private Member referencedMethod; // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Reset the code attribute editor. codeAttributeEditor.reset(codeAttribute.u4codeLength); // Remap the variables of the instructions. codeAttribute.instructionsAccept(clazz, method, this); // Apply the code atribute editor. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { int constantIndex = constantInstruction.constantIndex; // Get information on the called class and method, if present. referencedMethod = null; clazz.constantPoolEntryAccept(constantIndex, this); // Did we find the called class and method? if (referencedClass != null && referencedMethod != null) { // Do we need to update the opcode? byte opcode = constantInstruction.opcode; // Is the method static? if ((referencedMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0) { // But is it not a static invocation? if (opcode != InstructionConstants.OP_INVOKESTATIC) { // Replace the invocation by an invokestatic instruction. Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, constantIndex).shrink(); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); if (DEBUG) { debug(clazz, method, offset, constantInstruction, replacementInstruction); } } } // Is the method private, or an instance initializer? else if ((referencedMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_PRIVATE) != 0 || referencedMethod.getName(referencedMethodClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { // But is it not a special invocation? if (opcode != InstructionConstants.OP_INVOKESPECIAL) { // Replace the invocation by an invokespecial instruction. Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, constantIndex).shrink(); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); if (DEBUG) { debug(clazz, method, offset, constantInstruction, replacementInstruction); } } } // Is the method an interface method? else if ((referencedClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0) { int invokeinterfaceConstant = (ClassUtil.internalMethodParameterSize(referencedMethod.getDescriptor(referencedMethodClass), false)) << 8; // But is it not an interface invocation, or is the parameter // size incorrect? if (opcode != InstructionConstants.OP_INVOKEINTERFACE || constantInstruction.constant != invokeinterfaceConstant) { // Fix the parameter size of the interface invocation. Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_INVOKEINTERFACE, constantIndex, invokeinterfaceConstant).shrink(); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); if (DEBUG) { debug(clazz, method, offset, constantInstruction, replacementInstruction); } } } // The method is not static, private, an instance initializer, or // an interface method. else { // But is it not a virtual invocation (or a special invocation, // but not a super call)? if (opcode != InstructionConstants.OP_INVOKEVIRTUAL && (opcode != InstructionConstants.OP_INVOKESPECIAL || clazz.equals(referencedClass) || !clazz.extends_(referencedClass))) { // Replace the invocation by an invokevirtual instruction. Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, constantIndex).shrink(); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); if (DEBUG) { debug(clazz, method, offset, constantInstruction, replacementInstruction); } } } } } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) { // Remember the referenced class. Note that we're interested in the // class of the method reference, not in the class in which the // method was actually found, unless it is an array type. // if (ClassUtil.isInternalArrayType(refConstant.getClassName(clazz))) { // For an array type, the class will be java.lang.Object. referencedClass = refConstant.referencedClass; } else { clazz.constantPoolEntryAccept(refConstant.u2classIndex, this); } // Remember the referenced method. referencedMethodClass = refConstant.referencedClass; referencedMethod = refConstant.referencedMember; } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Remember the referenced class. referencedClass = classConstant.referencedClass; } // Small utility methods. private void debug(Clazz clazz, Method method, int offset, ConstantInstruction constantInstruction, Instruction replacementInstruction) { System.out.println("MethodInvocationFixer:"); System.out.println(" Class = "+clazz.getName()); System.out.println(" Method = "+method.getName(clazz)+method.getDescriptor(clazz)); System.out.println(" Instruction = "+constantInstruction.toString(offset)); System.out.println(" -> Class = "+referencedClass); System.out.println(" Method = "+referencedMethod); if ((referencedClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0) { System.out.println(" Parameter size = "+(ClassUtil.internalMethodParameterSize(referencedMethod.getDescriptor(referencedMethodClass), false))); } System.out.println(" Replacement instruction = "+replacementInstruction.toString(offset)); } } proguard4.8/src/proguard/classfile/editor/InstructionWriter.java0000644000175000017500000002357611736333524024033 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor writes out the instructions that it visits, * collecting instructions that have to be widened. As an AttributeVisitor, * it then applies the collected changes. The process will be repeated * recursively, if necessary. * * @author Eric Lafortune */ public class InstructionWriter extends SimplifiedVisitor implements InstructionVisitor, AttributeVisitor { private int codeLength; private CodeAttributeEditor codeAttributeEditor; /** * Resets the accumulated code changes. * @param codeLength the length of the code that will be edited next. */ public void reset(int codeLength) { this.codeLength = codeLength; // The code attribute editor has to be created lazily. if (codeAttributeEditor != null) { codeAttributeEditor.reset(codeLength); } } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Try to write out the instruction. // Simple instructions should always fit. simpleInstruction.write(codeAttribute, offset); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { try { // Try to write out the instruction. constantInstruction.write(codeAttribute, offset); } catch (IllegalArgumentException exception) { // Create a new constant instruction that will fit. Instruction replacementInstruction = new ConstantInstruction(constantInstruction.opcode, constantInstruction.constantIndex, constantInstruction.constant).shrink(); replaceInstruction(offset, replacementInstruction); // Write out a dummy constant instruction for now. constantInstruction.constantIndex = 0; constantInstruction.constant = 0; constantInstruction.write(codeAttribute, offset); } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { try { // Try to write out the instruction. variableInstruction.write(codeAttribute, offset); } catch (IllegalArgumentException exception) { // Create a new variable instruction that will fit. Instruction replacementInstruction = new VariableInstruction(variableInstruction.opcode, variableInstruction.variableIndex, variableInstruction.constant).shrink(); replaceInstruction(offset, replacementInstruction); // Write out a dummy variable instruction for now. variableInstruction.variableIndex = 0; variableInstruction.constant = 0; variableInstruction.write(codeAttribute, offset); } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { try { // Try to write out the instruction. branchInstruction.write(codeAttribute, offset); } catch (IllegalArgumentException exception) { // Create a new unconditional branch that will fit. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO_W, branchInstruction.branchOffset); // Create a new instruction that will fit. switch (branchInstruction.opcode) { default: { // Create a new branch instruction that will fit. replacementInstruction = new BranchInstruction(branchInstruction.opcode, branchInstruction.branchOffset).shrink(); break; } // Some special cases, for which a wide branch doesn't exist. case InstructionConstants.OP_IFEQ: case InstructionConstants.OP_IFNE: case InstructionConstants.OP_IFLT: case InstructionConstants.OP_IFGE: case InstructionConstants.OP_IFGT: case InstructionConstants.OP_IFLE: case InstructionConstants.OP_IFICMPEQ: case InstructionConstants.OP_IFICMPNE: case InstructionConstants.OP_IFICMPLT: case InstructionConstants.OP_IFICMPGE: case InstructionConstants.OP_IFICMPGT: case InstructionConstants.OP_IFICMPLE: case InstructionConstants.OP_IFACMPEQ: case InstructionConstants.OP_IFACMPNE: { // Insert the complementary conditional branch. Instruction complementaryConditionalBranch = new BranchInstruction((byte)(((branchInstruction.opcode+1) ^ 1) - 1), (1+2) + (1+4)); insertBeforeInstruction(offset, complementaryConditionalBranch); // Create a new unconditional branch that will fit. break; } case InstructionConstants.OP_IFNULL: case InstructionConstants.OP_IFNONNULL: { // Insert the complementary conditional branch. Instruction complementaryConditionalBranch = new BranchInstruction((byte)(branchInstruction.opcode ^ 1), (1+2) + (1+4)); insertBeforeInstruction(offset, complementaryConditionalBranch); // Create a new unconditional branch that will fit. break; } } replaceInstruction(offset, replacementInstruction); // Write out a dummy branch instruction for now. branchInstruction.branchOffset = 0; branchInstruction.write(codeAttribute, offset); } } public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) { // Try to write out the instruction. // Switch instructions should always fit. switchInstruction.write(codeAttribute, offset); } // Implementations for AttributeVisitor. public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Avoid doing any work if nothing is changing anyway. if (codeAttributeEditor != null) { // Apply the collected expansions. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); // Clear the modifications for the next run. codeAttributeEditor = null; } } // Small utility methods. /** * Remembers to place the given instruction right before the instruction * at the given offset. */ private void insertBeforeInstruction(int instructionOffset, Instruction instruction) { ensureCodeAttributeEditor(); // Replace the instruction. codeAttributeEditor.insertBeforeInstruction(instructionOffset, instruction); } /** * Remembers to replace the instruction at the given offset by the given * instruction. */ private void replaceInstruction(int instructionOffset, Instruction instruction) { ensureCodeAttributeEditor(); // Replace the instruction. codeAttributeEditor.replaceInstruction(instructionOffset, instruction); } /** * Remembers to place the given instruction right after the instruction * at the given offset. */ private void insertAfterInstruction(int instructionOffset, Instruction instruction) { ensureCodeAttributeEditor(); // Replace the instruction. codeAttributeEditor.insertAfterInstruction(instructionOffset, instruction); } /** * Makes sure there is a code attribute editor for the given code attribute. */ private void ensureCodeAttributeEditor() { if (codeAttributeEditor == null) { codeAttributeEditor = new CodeAttributeEditor(); codeAttributeEditor.reset(codeLength); } } } proguard4.8/src/proguard/classfile/editor/InterfacesEditor.java0000644000175000017500000000744411736333524023543 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import java.util.Arrays; /** * This class can add and delete interfaces to and from classes. References to * the constant pool must be filled out beforehand. * * @author Eric Lafortune */ public class InterfacesEditor { private final ProgramClass targetClass; /** * Creates a new InterfacesEditor that will edit interfaces in the given * target class. */ public InterfacesEditor(ProgramClass targetClass) { this.targetClass = targetClass; } /** * Adds the specified interface to the target class, if it isn't present yet. */ public void addInterface(int interfaceConstantIndex) { // Is the interface not yet present? if (findInterfaceIndex(interfaceConstantIndex) < 0) { int interfacesCount = targetClass.u2interfacesCount++; int[] interfaces = targetClass.u2interfaces; // Is the array too small to contain the additional interface? if (interfaces.length <= interfacesCount) { // Create a new array and copy the interfaces into it. int[] newinterfaces = new int[interfacesCount + 1]; System.arraycopy(interfaces, 0, newinterfaces, 0, interfacesCount); interfaces = newinterfaces; targetClass.u2interfaces = interfaces; } // Append the interface. interfaces[interfacesCount] = interfaceConstantIndex; } } /** * Deletes the given interface from the target class, if it is present. */ public void deleteInterface(int interfaceConstantIndex) { // Is the interface already present? int interfaceIndex = findInterfaceIndex(interfaceConstantIndex); if (interfaceIndex >= 0) { int interfacesCount = --targetClass.u2interfacesCount; int[] interfaces = targetClass.u2interfaces; // Shift the other interfaces in the array. for (int index = interfaceIndex; index < interfacesCount; index++) { interfaces[index] = interfaces[index + 1]; } // Clear the remaining entry in the array. interfaces[interfacesCount] = 0; } } // Small utility methods. /** * Finds the index of the specified interface in the list of interfaces of * the target class. */ private int findInterfaceIndex(int interfaceConstantIndex) { int interfacesCount = targetClass.u2interfacesCount; int[] interfaces = targetClass.u2interfaces; for (int index = 0; index < interfacesCount; index++) { if (interfaces[index] == interfaceConstantIndex) { return index; } } return -1; } }proguard4.8/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java0000644000175000017500000000551011736333524027472 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.annotation.*; /** * This class can add annotations to a given parameter annotations attribute. * Annotations to be added must have been filled out beforehand. * * @author Eric Lafortune */ public class ParameterAnnotationsAttributeEditor { private ParameterAnnotationsAttribute targetParameterAnnotationsAttribute; /** * Creates a new ParameterAnnotationsAttributeEditor that will edit * annotations in the given parameter annotations attribute. */ public ParameterAnnotationsAttributeEditor(ParameterAnnotationsAttribute targetParameterAnnotationsAttribute) { this.targetParameterAnnotationsAttribute = targetParameterAnnotationsAttribute; } /** * Adds a given annotation to the annotations attribute. */ public void addAnnotation(int parameterIndex, Annotation annotation) { int annotationsCount = targetParameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex]; Annotation[] annotations = targetParameterAnnotationsAttribute.parameterAnnotations[parameterIndex]; // Make sure there is enough space for the new annotation. if (annotations == null || annotations.length <= annotationsCount) { targetParameterAnnotationsAttribute.parameterAnnotations[parameterIndex] = new Annotation[annotationsCount+1]; if (annotations != null) { System.arraycopy(annotations, 0, targetParameterAnnotationsAttribute.parameterAnnotations[parameterIndex], 0, annotationsCount); } annotations = targetParameterAnnotationsAttribute.parameterAnnotations[parameterIndex]; } // Add the annotation. annotations[targetParameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex]++] = annotation; } }proguard4.8/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java0000644000175000017500000000510111736333524026340 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.*; /** * This class can add line numbers to a given line number table attribute. * Line numbers to be added must have been filled out beforehand. * * @author Eric Lafortune */ public class LineNumberTableAttributeEditor { private LineNumberTableAttribute targetLineNumberTableAttribute; /** * Creates a new LineNumberTableAttributeEditor that will edit line numbers * in the given line number table attribute. */ public LineNumberTableAttributeEditor(LineNumberTableAttribute targetLineNumberTableAttribute) { this.targetLineNumberTableAttribute = targetLineNumberTableAttribute; } /** * Adds a given line number to the line number table attribute. */ public void addLineNumberInfo(LineNumberInfo lineNumberInfo) { int lineNumberTableLength = targetLineNumberTableAttribute.u2lineNumberTableLength; LineNumberInfo[] lineNumberTable = targetLineNumberTableAttribute.lineNumberTable; // Make sure there is enough space for the new lineNumberInfo. if (lineNumberTable.length <= lineNumberTableLength) { targetLineNumberTableAttribute.lineNumberTable = new LineNumberInfo[lineNumberTableLength+1]; System.arraycopy(lineNumberTable, 0, targetLineNumberTableAttribute.lineNumberTable, 0, lineNumberTableLength); lineNumberTable = targetLineNumberTableAttribute.lineNumberTable; } // Add the lineNumberInfo. lineNumberTable[targetLineNumberTableAttribute.u2lineNumberTableLength++] = lineNumberInfo; } }proguard4.8/src/proguard/classfile/editor/InnerClassesAccessFixer.java0000644000175000017500000000525111736333524025014 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.visitor.InnerClassesInfoVisitor; import proguard.classfile.attribute.InnerClassesInfo; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** * This InnerClassesInfoVisitor fixes the inner class access flags of the * inner classes information that it visits. * * @author Eric Lafortune */ public class InnerClassesAccessFixer extends SimplifiedVisitor implements InnerClassesInfoVisitor, ConstantVisitor, ClassVisitor { private int innerClassAccessFlags; // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { // The current access flags are the default. innerClassAccessFlags = innerClassesInfo.u2innerClassAccessFlags; // See if we can find new access flags. innerClassesInfo.innerClassConstantAccept(clazz, this); // Update the access flags. innerClassesInfo.u2innerClassAccessFlags = innerClassAccessFlags; } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.referencedClassAccept(this); } // Implementations for ClassVisitor. public void visitLibraryClass(LibraryClass libraryClass) {} public void visitProgramClass(ProgramClass programClass) { innerClassAccessFlags = AccessUtil.replaceAccessFlags(innerClassAccessFlags, programClass.u2accessFlags); } }proguard4.8/src/proguard/classfile/editor/InterfaceSorter.java0000644000175000017500000001202711736333524023401 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.ClassVisitor; import java.util.*; /** * This ClassVisitor sorts the interfaces of the program classes that it visits. * * @author Eric Lafortune */ public class InterfaceSorter extends SimplifiedVisitor implements ClassVisitor, AttributeVisitor { // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { int[] interfaces = programClass.u2interfaces; int interfacesCount = programClass.u2interfacesCount; if (interfacesCount > 1) { // Sort the interfaces. Arrays.sort(interfaces, 0, interfacesCount); // Remove any duplicate entries. int newInterfacesCount = 0; int previousInterfaceIndex = 0; for (int index = 0; index < interfacesCount; index++) { int interfaceIndex = interfaces[index]; // Isn't this a duplicate of the previous interface? if (interfaceIndex != previousInterfaceIndex) { interfaces[newInterfacesCount++] = interfaceIndex; // Remember the interface. previousInterfaceIndex = interfaceIndex; } } programClass.u2interfacesCount = newInterfacesCount; // Update the signature, if any programClass.attributesAccept(this); } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { // Process the generic definitions, superclass, and implemented // interfaces. String signature = clazz.getString(signatureAttribute.u2signatureIndex); // Count the signature types. InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(signature); int count = 0; int interfacesCount = -1; while (internalTypeEnumeration.hasMoreTypes()) { String internalType = internalTypeEnumeration.nextType(); count++; if (ClassUtil.isInternalClassType(internalType)) { interfacesCount++; } } // Put the signature types in an array. internalTypeEnumeration = new InternalTypeEnumeration(signature); String[] internalTypes = new String[count]; for (int index = 0; index < count; index++) { String internalType = internalTypeEnumeration.nextType(); internalTypes[index] = internalType; } // Sort the interface types in the array. Arrays.sort(internalTypes, count - interfacesCount, count); // Recompose the signature types in a string. StringBuffer newSignatureBuffer = new StringBuffer(); for (int index = 0; index < count; index++) { // Is this not an interface type, or an interface type that isn't // a duplicate of the previous interface type? if (index < count - interfacesCount || !internalTypes[index].equals(internalTypes[index-1])) { newSignatureBuffer.append(internalTypes[index]); } } String newSignature = newSignatureBuffer.toString(); // Did the signature change? if (!newSignature.equals(signature)) { // Update the signature. ((Utf8Constant)((ProgramClass)clazz).constantPool[signatureAttribute.u2signatureIndex]).setString(newSignatureBuffer.toString()); // Clear the referenced classes. // TODO: Properly update the referenced classes. signatureAttribute.referencedClasses = null; } } } proguard4.8/src/proguard/classfile/editor/ClassEditor.java0000644000175000017500000001645111736333524022523 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; /** * This class can add interfaces and class members to a given class. * Elements to be added must be filled out beforehand, including their * references to the constant pool. * * @author Eric Lafortune */ public class ClassEditor { private static final boolean DEBUG = false; private ProgramClass targetClass; /** * Creates a new ClassEditor that will edit elements in the given * target class. */ public ClassEditor(ProgramClass targetClass) { this.targetClass = targetClass; } /** * Adds the given interface. */ public void addInterface(int interfaceConstantIndex) { int interfacesCount = targetClass.u2interfacesCount; int[] interfaces = targetClass.u2interfaces; // Make sure there is enough space for the new interface. if (interfaces.length <= interfacesCount) { targetClass.u2interfaces = new int[interfacesCount+1]; System.arraycopy(interfaces, 0, targetClass.u2interfaces, 0, interfacesCount); interfaces = targetClass.u2interfaces; } if (DEBUG) { System.out.println(targetClass.getName()+": adding interface ["+targetClass.getClassName(interfaceConstantIndex)+"]"); } // Add the interface. interfaces[targetClass.u2interfacesCount++] = interfaceConstantIndex; } /** * Removes the given interface. */ public void removeInterface(int interfaceConstantIndex) { int interfacesCount = targetClass.u2interfacesCount; int[] interfaces = targetClass.u2interfaces; int interfaceIndex = findInterfaceIndex(interfaceConstantIndex); // Shift the interface entries. System.arraycopy(interfaces, interfaceIndex+1, interfaces, interfaceIndex, interfacesCount - interfaceIndex - 1); // Clear the last entry. interfaces[--targetClass.u2interfacesCount] = 0; } /** * Finds the index of the given interface in the target class. */ private int findInterfaceIndex(int interfaceConstantIndex) { int interfacesCount = targetClass.u2interfacesCount; int[] interfaces = targetClass.u2interfaces; for (int index = 0; index < interfacesCount; index++) { if (interfaces[index] == interfaceConstantIndex) { return index; } } return interfacesCount; } /** * Adds the given field. */ public void addField(Field field) { int fieldsCount = targetClass.u2fieldsCount; Field[] fields = targetClass.fields; // Make sure there is enough space for the new field. if (fields.length <= fieldsCount) { targetClass.fields = new ProgramField[fieldsCount+1]; System.arraycopy(fields, 0, targetClass.fields, 0, fieldsCount); fields = targetClass.fields; } if (DEBUG) { System.out.println(targetClass.getName()+": adding field ["+field.getName(targetClass)+" "+field.getDescriptor(targetClass)+"]"); } // Add the field. fields[targetClass.u2fieldsCount++] = field; } /** * Removes the given field. Note that removing a field that is still being * referenced can cause unpredictable effects. */ public void removeField(Field field) { int fieldsCount = targetClass.u2fieldsCount; Field[] fields = targetClass.fields; int fieldIndex = findFieldIndex(field); // Shift the field entries. System.arraycopy(fields, fieldIndex+1, fields, fieldIndex, fieldsCount - fieldIndex - 1); // Clear the last entry. fields[--targetClass.u2fieldsCount] = null; } /** * Finds the index of the given field in the target class. */ private int findFieldIndex(Field field) { int fieldsCount = targetClass.u2fieldsCount; Field[] fields = targetClass.fields; for (int index = 0; index < fieldsCount; index++) { if (fields[index].equals(field)) { return index; } } return fieldsCount; } /** * Adds the given method. */ public void addMethod(Method method) { int methodsCount = targetClass.u2methodsCount; Method[] methods = targetClass.methods; // Make sure there is enough space for the new method. if (methods.length <= methodsCount) { targetClass.methods = new ProgramMethod[methodsCount+1]; System.arraycopy(methods, 0, targetClass.methods, 0, methodsCount); methods = targetClass.methods; } if (DEBUG) { System.out.println(targetClass.getName()+": adding method ["+method.getName(targetClass)+method.getDescriptor(targetClass)+"]"); } // Add the method. methods[targetClass.u2methodsCount++] = method; } /** * Removes the given method. Note that removing a method that is still being * referenced can cause unpredictable effects. */ public void removeMethod(Method method) { int methodsCount = targetClass.u2methodsCount; Method[] methods = targetClass.methods; int methodIndex = findMethodIndex(method); // Shift the method entries. System.arraycopy(methods, methodIndex+1, methods, methodIndex, methodsCount - methodIndex - 1); // Clear the last entry. methods[--targetClass.u2methodsCount] = null; } /** * Finds the index of the given method in the target class. */ private int findMethodIndex(Method method) { int methodsCount = targetClass.u2methodsCount; Method[] methods = targetClass.methods; for (int index = 0; index < methodsCount; index++) { if (methods[index].equals(method)) { return index; } } return methodsCount; } } proguard4.8/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java0000644000175000017500000000555011736333524027652 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.*; /** * This class can add local variables to a given local variable type table * attribute. * Local variable types to be added must have been filled out beforehand. * * @author Eric Lafortune */ public class LocalVariableTypeTableAttributeEditor { private LocalVariableTypeTableAttribute targetLocalVariableTypeTableAttribute; /** * Creates a new LocalVariableTypeTableAttributeEditor that will edit line numbers * in the given line number table attribute. */ public LocalVariableTypeTableAttributeEditor(LocalVariableTypeTableAttribute targetLocalVariableTypeTableAttribute) { this.targetLocalVariableTypeTableAttribute = targetLocalVariableTypeTableAttribute; } /** * Adds a given line number to the line number table attribute. */ public void addLocalVariableTypeInfo(LocalVariableTypeInfo localVariableTypeInfo) { int localVariableTypeTableLength = targetLocalVariableTypeTableAttribute.u2localVariableTypeTableLength; LocalVariableTypeInfo[] localVariableTypeTable = targetLocalVariableTypeTableAttribute.localVariableTypeTable; // Make sure there is enough space for the new localVariableTypeInfo. if (localVariableTypeTable.length <= localVariableTypeTableLength) { targetLocalVariableTypeTableAttribute.localVariableTypeTable = new LocalVariableTypeInfo[localVariableTypeTableLength+1]; System.arraycopy(localVariableTypeTable, 0, targetLocalVariableTypeTableAttribute.localVariableTypeTable, 0, localVariableTypeTableLength); localVariableTypeTable = targetLocalVariableTypeTableAttribute.localVariableTypeTable; } // Add the localVariableTypeInfo. localVariableTypeTable[targetLocalVariableTypeTableAttribute.u2localVariableTypeTableLength++] = localVariableTypeInfo; } }proguard4.8/src/proguard/classfile/editor/Utf8Shrinker.java0000644000175000017500000003657111736333524022650 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.ConstantPoolRemapper; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; import java.util.Arrays; /** * This ClassVisitor removes UTF-8 constant pool entries that are not used. * * @author Eric Lafortune */ public class Utf8Shrinker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor, InnerClassesInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { // A visitor info flag to indicate the UTF-8 constant pool entry is being used. private static final Object USED = new Object(); private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Mark the UTF-8 entries referenced by the other constant pool entries. programClass.constantPoolEntriesAccept(this); // Mark the UTF-8 entries referenced by the fields and methods. programClass.fieldsAccept(this); programClass.methodsAccept(this); // Mark the UTF-8 entries referenced by the attributes. programClass.attributesAccept(this); // Shift the used constant pool entries together, filling out the // index map. int newConstantPoolCount = shrinkConstantPool(programClass.constantPool, programClass.u2constantPoolCount); // Remap the references to the constant pool if it has shrunk. if (newConstantPoolCount < programClass.u2constantPoolCount) { programClass.u2constantPoolCount = newConstantPoolCount; // Remap all constant pool references. constantPoolRemapper.setConstantIndexMap(constantIndexMap); constantPoolRemapper.visitProgramClass(programClass); } } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { // Mark the name and descriptor UTF-8 entries. markCpUtf8Entry(programClass, programMember.u2nameIndex); markCpUtf8Entry(programClass, programMember.u2descriptorIndex); // Mark the UTF-8 entries referenced by the attributes. programMember.attributesAccept(programClass, this); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { markCpUtf8Entry(clazz, stringConstant.u2stringIndex); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { markCpUtf8Entry(clazz, classConstant.u2nameIndex); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { markCpUtf8Entry(clazz, nameAndTypeConstant.u2nameIndex); markCpUtf8Entry(clazz, nameAndTypeConstant.u2descriptorIndex); } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { // This is the best we can do for unknown attributes. markCpUtf8Entry(clazz, unknownAttribute.u2attributeNameIndex); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { markCpUtf8Entry(clazz, sourceFileAttribute.u2attributeNameIndex); markCpUtf8Entry(clazz, sourceFileAttribute.u2sourceFileIndex); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { markCpUtf8Entry(clazz, sourceDirAttribute.u2attributeNameIndex); markCpUtf8Entry(clazz, sourceDirAttribute.u2sourceDirIndex); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { markCpUtf8Entry(clazz, innerClassesAttribute.u2attributeNameIndex); // Mark the UTF-8 entries referenced by the inner classes. innerClassesAttribute.innerClassEntriesAccept(clazz, this); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { markCpUtf8Entry(clazz, enclosingMethodAttribute.u2attributeNameIndex); // These entries have already been marked in the constant pool. //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2classIndex); //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2nameAndTypeIndex); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { markCpUtf8Entry(clazz, deprecatedAttribute.u2attributeNameIndex); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { markCpUtf8Entry(clazz, syntheticAttribute.u2attributeNameIndex); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { markCpUtf8Entry(clazz, signatureAttribute.u2attributeNameIndex); markCpUtf8Entry(clazz, signatureAttribute.u2signatureIndex); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { markCpUtf8Entry(clazz, constantValueAttribute.u2attributeNameIndex); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { markCpUtf8Entry(clazz, exceptionsAttribute.u2attributeNameIndex); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { markCpUtf8Entry(clazz, codeAttribute.u2attributeNameIndex); // Mark the UTF-8 entries referenced by the attributes. codeAttribute.attributesAccept(clazz, method, this); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { markCpUtf8Entry(clazz, stackMapAttribute.u2attributeNameIndex); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { markCpUtf8Entry(clazz, stackMapTableAttribute.u2attributeNameIndex); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { markCpUtf8Entry(clazz, lineNumberTableAttribute.u2attributeNameIndex); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { markCpUtf8Entry(clazz, localVariableTableAttribute.u2attributeNameIndex); // Mark the UTF-8 entries referenced by the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { markCpUtf8Entry(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); // Mark the UTF-8 entries referenced by the local variable types. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { markCpUtf8Entry(clazz, annotationsAttribute.u2attributeNameIndex); // Mark the UTF-8 entries referenced by the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { markCpUtf8Entry(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); // Mark the UTF-8 entries referenced by the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { markCpUtf8Entry(clazz, annotationDefaultAttribute.u2attributeNameIndex); // Mark the UTF-8 entries referenced by the element value. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { if (innerClassesInfo.u2innerNameIndex != 0) { markCpUtf8Entry(clazz, innerClassesInfo.u2innerNameIndex); } } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { markCpUtf8Entry(clazz, localVariableInfo.u2nameIndex); markCpUtf8Entry(clazz, localVariableInfo.u2descriptorIndex); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { markCpUtf8Entry(clazz, localVariableTypeInfo.u2nameIndex); markCpUtf8Entry(clazz, localVariableTypeInfo.u2signatureIndex); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { markCpUtf8Entry(clazz, annotation.u2typeIndex); // Mark the UTF-8 entries referenced by the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { if (constantElementValue.u2elementNameIndex != 0) { markCpUtf8Entry(clazz, constantElementValue.u2elementNameIndex); } // Only the string constant element value refers to a UTF-8 entry. if (constantElementValue.u1tag == ClassConstants.ELEMENT_VALUE_STRING_CONSTANT) { markCpUtf8Entry(clazz, constantElementValue.u2constantValueIndex); } } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { if (enumConstantElementValue.u2elementNameIndex != 0) { markCpUtf8Entry(clazz, enumConstantElementValue.u2elementNameIndex); } markCpUtf8Entry(clazz, enumConstantElementValue.u2typeNameIndex); markCpUtf8Entry(clazz, enumConstantElementValue.u2constantNameIndex); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { if (classElementValue.u2elementNameIndex != 0) { markCpUtf8Entry(clazz, classElementValue.u2elementNameIndex); } markCpUtf8Entry(clazz, classElementValue.u2classInfoIndex); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { if (annotationElementValue.u2elementNameIndex != 0) { markCpUtf8Entry(clazz, annotationElementValue.u2elementNameIndex); } // Mark the UTF-8 entries referenced by the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { if (arrayElementValue.u2elementNameIndex != 0) { markCpUtf8Entry(clazz, arrayElementValue.u2elementNameIndex); } // Mark the UTF-8 entries referenced by the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } // Small utility methods. /** * Marks the given UTF-8 constant pool entry of the given class. */ private void markCpUtf8Entry(Clazz clazz, int index) { markAsUsed((Utf8Constant)((ProgramClass)clazz).getConstant(index)); } /** * Marks the given VisitorAccepter as being used. * In this context, the VisitorAccepter will be a Utf8Constant object. */ private void markAsUsed(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(USED); } /** * Returns whether the given VisitorAccepter has been marked as being used. * In this context, the VisitorAccepter will be a Utf8Constant object. */ private boolean isUsed(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() == USED; } /** * Removes all UTF-8 entries that are not marked as being used * from the given constant pool. * @return the new number of entries. */ private int shrinkConstantPool(Constant[] constantPool, int length) { // Create a new index map, if necessary. if (constantIndexMap.length < length) { constantIndexMap = new int[length]; } int counter = 1; boolean isUsed = false; // Shift the used constant pool entries together. for (int index = 1; index < length; index++) { constantIndexMap[index] = counter; Constant constant = constantPool[index]; // Don't update the flag if this is the second half of a long entry. if (constant != null) { isUsed = constant.getTag() != ClassConstants.CONSTANT_Utf8 || isUsed(constant); } if (isUsed) { constantPool[counter++] = constant; } } // Clear the remaining constant pool elements. Arrays.fill(constantPool, counter, length, null); return counter; } } proguard4.8/src/proguard/classfile/editor/ClassMemberSorter.java0000644000175000017500000000464111736333524023701 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; import java.util.*; /** * This ClassVisitor sorts the class members of the classes that it visits. * The sorting order is based on the access flags, the names, and the * descriptors. * * @author Eric Lafortune */ public class ClassMemberSorter implements ClassVisitor, Comparator { // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Sort the fields. Arrays.sort(programClass.fields, 0, programClass.u2fieldsCount, this); // Sort the methods. Arrays.sort(programClass.methods, 0, programClass.u2methodsCount, this); } public void visitLibraryClass(LibraryClass libraryClass) { } // Implementations for Comparator. public int compare(Object object1, Object object2) { ProgramMember member1 = (ProgramMember)object1; ProgramMember member2 = (ProgramMember)object2; return member1.u2accessFlags < member2.u2accessFlags ? -1 : member1.u2accessFlags > member2.u2accessFlags ? 1 : member1.u2nameIndex < member2.u2nameIndex ? -1 : member1.u2nameIndex > member2.u2nameIndex ? 1 : member1.u2descriptorIndex < member2.u2descriptorIndex ? -1 : member1.u2descriptorIndex > member2.u2descriptorIndex ? 1 : 0; } } proguard4.8/src/proguard/classfile/editor/CodeAttributeEditor.java0000644000175000017500000011401311736333524024205 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import java.util.Arrays; /** * This AttributeVisitor accumulates specified changes to code, and then applies * these accumulated changes to the code attributes that it visits. * * @author Eric Lafortune */ public class CodeAttributeEditor extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LineNumberInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private boolean updateFrameSizes; private int codeLength; private boolean modified; private boolean simple; /*private*/public Instruction[] preInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH]; /*private*/public Instruction[] replacements = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH]; /*private*/public Instruction[] postInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH]; /*private*/public boolean[] deleted = new boolean[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] instructionOffsetMap = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private int newOffset; private boolean lengthIncreased; private int expectedStackMapFrameOffset; private final StackSizeUpdater stackSizeUpdater = new StackSizeUpdater(); private final VariableSizeUpdater variableSizeUpdater = new VariableSizeUpdater(); private final InstructionWriter instructionWriter = new InstructionWriter(); public CodeAttributeEditor() { this(true); } public CodeAttributeEditor(boolean updateFrameSizes) { this.updateFrameSizes = updateFrameSizes; } /** * Resets the accumulated code changes. * @param codeLength the length of the code that will be edited next. */ public void reset(int codeLength) { this.codeLength = codeLength; // Try to reuse the previous arrays. if (preInsertions.length < codeLength) { preInsertions = new Instruction[codeLength]; replacements = new Instruction[codeLength]; postInsertions = new Instruction[codeLength]; deleted = new boolean[codeLength]; } else { Arrays.fill(preInsertions, 0, codeLength, null); Arrays.fill(replacements, 0, codeLength, null); Arrays.fill(postInsertions, 0, codeLength, null); Arrays.fill(deleted, 0, codeLength, false); } modified = false; simple = true; } /** * Remembers to place the given instruction right before the instruction * at the given offset. * @param instructionOffset the offset of the instruction. * @param instruction the new instruction. */ public void insertBeforeInstruction(int instructionOffset, Instruction instruction) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } preInsertions[instructionOffset] = instruction; modified = true; simple = false; } /** * Remembers to place the given instructions right before the instruction * at the given offset. * @param instructionOffset the offset of the instruction. * @param instructions the new instructions. */ public void insertBeforeInstruction(int instructionOffset, Instruction[] instructions) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } preInsertions[instructionOffset] = new CompositeInstruction(instructions); modified = true; simple = false; } /** * Remembers to replace the instruction at the given offset by the given * instruction. * @param instructionOffset the offset of the instruction to be replaced. * @param instruction the new instruction. */ public void replaceInstruction(int instructionOffset, Instruction instruction) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } replacements[instructionOffset] = instruction; modified = true; } /** * Remembers to replace the instruction at the given offset by the given * instructions. * @param instructionOffset the offset of the instruction to be replaced. * @param instructions the new instructions. */ public void replaceInstruction(int instructionOffset, Instruction[] instructions) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } replacements[instructionOffset] = new CompositeInstruction(instructions); modified = true; } /** * Remembers to place the given instruction right after the instruction * at the given offset. * @param instructionOffset the offset of the instruction. * @param instruction the new instruction. */ public void insertAfterInstruction(int instructionOffset, Instruction instruction) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } postInsertions[instructionOffset] = instruction; modified = true; simple = false; } /** * Remembers to place the given instructions right after the instruction * at the given offset. * @param instructionOffset the offset of the instruction. * @param instructions the new instructions. */ public void insertAfterInstruction(int instructionOffset, Instruction[] instructions) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } postInsertions[instructionOffset] = new CompositeInstruction(instructions); modified = true; simple = false; } /** * Remembers to delete the instruction at the given offset. * @param instructionOffset the offset of the instruction to be deleted. */ public void deleteInstruction(int instructionOffset) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } deleted[instructionOffset] = true; modified = true; simple = false; } /** * Remembers not to delete the instruction at the given offset. * @param instructionOffset the offset of the instruction not to be deleted. */ public void undeleteInstruction(int instructionOffset) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } deleted[instructionOffset] = false; } /** * Returns whether the instruction at the given offset has been modified * in any way. */ public boolean isModified(int instructionOffset) { return preInsertions[instructionOffset] != null || replacements[instructionOffset] != null || postInsertions[instructionOffset] != null || deleted[instructionOffset]; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // TODO: Remove this when the code has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while editing code:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); throw ex; } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (DEBUG) { System.out.println("CodeAttributeEditor: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); } // Do we have to update the code? if (modified) { // Can we perform a faster simple replacement of instructions? if (canPerformSimpleReplacements(codeAttribute)) { if (DEBUG) { System.out.println(" Simple editing"); } // Simply overwrite the instructions. performSimpleReplacements(codeAttribute); } else { if (DEBUG) { System.out.println(" Full editing"); } // Move and remap the instructions. codeAttribute.u4codeLength = updateInstructions(clazz, method, codeAttribute); // Remap the exception table. codeAttribute.exceptionsAccept(clazz, method, this); // Remove exceptions with empty code blocks. codeAttribute.u2exceptionTableLength = removeEmptyExceptions(codeAttribute.exceptionTable, codeAttribute.u2exceptionTableLength); // Remap the line number table and the local variable tables. codeAttribute.attributesAccept(clazz, method, this); } // Make sure instructions are widened if necessary. instructionWriter.visitCodeAttribute(clazz, method, codeAttribute); } // Update the maximum stack size and local variable frame size. if (updateFrameSizes) { stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute); variableSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute); } } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { // Remap all stack map entries. expectedStackMapFrameOffset = -1; stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { // Remap all stack map table entries. expectedStackMapFrameOffset = 0; stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { // Remap all line number table entries. lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this); // Remove line numbers with empty code blocks. lineNumberTableAttribute.u2lineNumberTableLength = removeEmptyLineNumbers(lineNumberTableAttribute.lineNumberTable, lineNumberTableAttribute.u2lineNumberTableLength, codeAttribute.u4codeLength); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Remap all local variable table entries. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Remap all local variable table entries. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } /** * Checks if it is possible to modifies the given code without having to * update any offsets. * @param codeAttribute the code to be changed. * @return the new code length. */ private boolean canPerformSimpleReplacements(CodeAttribute codeAttribute) { if (!simple) { return false; } byte[] code = codeAttribute.code; int codeLength = codeAttribute.u4codeLength; // Go over all replacement instructions. for (int offset = 0; offset < codeLength; offset++) { // Check if the replacement instruction, if any, has a different // length than the original instruction. Instruction replacementInstruction = replacements[offset]; if (replacementInstruction != null && replacementInstruction.length(offset) != InstructionFactory.create(code, offset).length(offset)) { return false; } } return true; } /** * Modifies the given code without updating any offsets. * @param codeAttribute the code to be changed. */ private void performSimpleReplacements(CodeAttribute codeAttribute) { int codeLength = codeAttribute.u4codeLength; // Go over all replacement instructions. for (int offset = 0; offset < codeLength; offset++) { // Overwrite the original instruction with the replacement // instruction if any. Instruction replacementInstruction = replacements[offset]; if (replacementInstruction != null) { replacementInstruction.write(codeAttribute, offset); if (DEBUG) { System.out.println(" Replaced "+replacementInstruction.toString(newOffset)); } } } } /** * Modifies the given code based on the previously specified changes. * @param clazz the class file of the code to be changed. * @param method the method of the code to be changed. * @param codeAttribute the code to be changed. * @return the new code length. */ private int updateInstructions(Clazz clazz, Method method, CodeAttribute codeAttribute) { byte[] oldCode = codeAttribute.code; int oldLength = codeAttribute.u4codeLength; // Make sure there is a sufficiently large instruction offset map. if (instructionOffsetMap.length < oldLength + 1) { instructionOffsetMap = new int[oldLength + 1]; } // Fill out the instruction offset map. int newLength = mapInstructions(oldCode, oldLength); // Create a new code array if necessary. if (lengthIncreased) { codeAttribute.code = new byte[newLength]; } // Prepare for possible widening of instructions. instructionWriter.reset(newLength); // Move the instructions into the new code array. moveInstructions(clazz, method, codeAttribute, oldCode, oldLength); // We can return the new length. return newLength; } /** * Fills out the instruction offset map for the given code block. * @param oldCode the instructions to be moved. * @param oldLength the code length. * @return the new code length. */ private int mapInstructions(byte[] oldCode, int oldLength) { // Start mapping instructions at the beginning. newOffset = 0; lengthIncreased = false; int oldOffset = 0; do { // Get the next instruction. Instruction instruction = InstructionFactory.create(oldCode, oldOffset); // Compute the mapping of the instruction. mapInstruction(oldOffset, instruction); oldOffset += instruction.length(oldOffset); if (newOffset > oldOffset) { lengthIncreased = true; } } while (oldOffset < oldLength); // Also add an entry for the first offset after the code. instructionOffsetMap[oldOffset] = newOffset; return newOffset; } /** * Fills out the instruction offset map for the given instruction. * @param oldOffset the instruction's old offset. * @param instruction the instruction to be moved. */ private void mapInstruction(int oldOffset, Instruction instruction) { instructionOffsetMap[oldOffset] = newOffset; // Account for the pre-inserted instruction, if any. Instruction preInstruction = preInsertions[oldOffset]; if (preInstruction != null) { newOffset += preInstruction.length(newOffset); } // Account for the replacement instruction, or for the current // instruction, if it shouldn't be deleted. Instruction replacementInstruction = replacements[oldOffset]; if (replacementInstruction != null) { newOffset += replacementInstruction.length(newOffset); } else if (!deleted[oldOffset]) { // Note that the instruction's length may change at its new offset, // e.g. if it is a switch instruction. newOffset += instruction.length(newOffset); } // Account for the post-inserted instruction, if any. Instruction postInstruction = postInsertions[oldOffset]; if (postInstruction != null) { newOffset += postInstruction.length(newOffset); } } /** * Moves the given code block to the new offsets. * @param clazz the class file of the code to be changed. * @param method the method of the code to be changed. * @param codeAttribute the code to be changed. * @param oldCode the original code to be moved. * @param oldLength the original code length. */ private void moveInstructions(Clazz clazz, Method method, CodeAttribute codeAttribute, byte[] oldCode, int oldLength) { // Start writing instructions at the beginning. newOffset = 0; int oldOffset = 0; do { // Get the next instruction. Instruction instruction = InstructionFactory.create(oldCode, oldOffset); // Move the instruction to its new offset. moveInstruction(clazz, method, codeAttribute, oldOffset, instruction); oldOffset += instruction.length(oldOffset); } while (oldOffset < oldLength); } /** * Moves the given instruction to its new offset. * @param clazz the class file of the code to be changed. * @param method the method of the code to be changed. * @param codeAttribute the code to be changed. * @param oldOffset the original instruction offset. * @param instruction the original instruction. */ private void moveInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int oldOffset, Instruction instruction) { // Remap and insert the pre-inserted instruction, if any. Instruction preInstruction = preInsertions[oldOffset]; if (preInstruction != null) { if (DEBUG) { System.out.println(" Pre-inserted "+preInstruction.toString(newOffset)); } // Remap the instruction. preInstruction.accept(clazz, method, codeAttribute, oldOffset, this); } // Remap and insert the replacement instruction, or the current // instruction, if it shouldn't be deleted. Instruction replacementInstruction = replacements[oldOffset]; if (replacementInstruction != null) { if (DEBUG) { System.out.println(" Replaced "+replacementInstruction.toString(newOffset)); } // Remap the instruction. replacementInstruction.accept(clazz, method, codeAttribute, oldOffset, this); } else if (!deleted[oldOffset]) { if (DEBUG) { System.out.println(" Copied "+instruction.toString(newOffset)); } // Remap the instruction. instruction.accept(clazz, method, codeAttribute, oldOffset, this); } // Remap and insert the post-inserted instruction, if any. Instruction postInstruction = postInsertions[oldOffset]; if (postInstruction != null) { if (DEBUG) { System.out.println(" Post-inserted "+postInstruction.toString(newOffset)); } // Remap the instruction. postInstruction.accept(clazz, method, codeAttribute, oldOffset, this); } } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Write out the instruction. instructionWriter.visitSimpleInstruction(clazz, method, codeAttribute, newOffset, simpleInstruction); newOffset += simpleInstruction.length(newOffset); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Write out the instruction. instructionWriter.visitConstantInstruction(clazz, method, codeAttribute, newOffset, constantInstruction); newOffset += constantInstruction.length(newOffset); } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Write out the instruction. instructionWriter.visitVariableInstruction(clazz, method, codeAttribute, newOffset, variableInstruction); newOffset += variableInstruction.length(newOffset); } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Adjust the branch offset. branchInstruction.branchOffset = remapBranchOffset(offset, branchInstruction.branchOffset); // Write out the instruction. instructionWriter.visitBranchInstruction(clazz, method, codeAttribute, newOffset, branchInstruction); newOffset += branchInstruction.length(newOffset); } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { // Adjust the default jump offset. tableSwitchInstruction.defaultOffset = remapBranchOffset(offset, tableSwitchInstruction.defaultOffset); // Adjust the jump offsets. remapJumpOffsets(offset, tableSwitchInstruction.jumpOffsets); // Write out the instruction. instructionWriter.visitTableSwitchInstruction(clazz, method, codeAttribute, newOffset, tableSwitchInstruction); newOffset += tableSwitchInstruction.length(newOffset); } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { // Adjust the default jump offset. lookUpSwitchInstruction.defaultOffset = remapBranchOffset(offset, lookUpSwitchInstruction.defaultOffset); // Adjust the jump offsets. remapJumpOffsets(offset, lookUpSwitchInstruction.jumpOffsets); // Write out the instruction. instructionWriter.visitLookUpSwitchInstruction(clazz, method, codeAttribute, newOffset, lookUpSwitchInstruction); newOffset += lookUpSwitchInstruction.length(newOffset); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { // Remap the code offsets. Note that the instruction offset map also has // an entry for the first offset after the code, for u2endPC. exceptionInfo.u2startPC = remapInstructionOffset(exceptionInfo.u2startPC); exceptionInfo.u2endPC = remapInstructionOffset(exceptionInfo.u2endPC); exceptionInfo.u2handlerPC = remapInstructionOffset(exceptionInfo.u2handlerPC); } // Implementations for StackMapFrameVisitor. public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) { // Remap the stack map frame offset. int stackMapFrameOffset = remapInstructionOffset(offset); int offsetDelta = stackMapFrameOffset; // Compute the offset delta if the frame is part of a stack map frame // table (for JDK 6.0) instead of a stack map (for Java Micro Edition). if (expectedStackMapFrameOffset >= 0) { offsetDelta -= expectedStackMapFrameOffset; expectedStackMapFrameOffset = stackMapFrameOffset + 1; } stackMapFrame.u2offsetDelta = offsetDelta; } public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { // Remap the stack map frame offset. visitAnyStackMapFrame(clazz, method, codeAttribute, offset, sameOneFrame); // Remap the verification type offset. sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { // Remap the stack map frame offset. visitAnyStackMapFrame(clazz, method, codeAttribute, offset, moreZeroFrame); // Remap the verification type offsets. moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { // Remap the stack map frame offset. visitAnyStackMapFrame(clazz, method, codeAttribute, offset, fullFrame); // Remap the verification type offsets. fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType) { // Remap the offset of the 'new' instruction. uninitializedType.u2newInstructionOffset = remapInstructionOffset(uninitializedType.u2newInstructionOffset); } // Implementations for LineNumberInfoVisitor. public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) { // Remap the code offset. lineNumberInfo.u2startPC = remapInstructionOffset(lineNumberInfo.u2startPC); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Remap the code offset and length. int newStartPC = remapInstructionOffset(localVariableInfo.u2startPC); int newEndPC = remapInstructionOffset(localVariableInfo.u2startPC + localVariableInfo.u2length); localVariableInfo.u2length = newEndPC - newStartPC; localVariableInfo.u2startPC = newStartPC; } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { // Remap the code offset and length. int newStartPC = remapInstructionOffset(localVariableTypeInfo.u2startPC); int newEndPC = remapInstructionOffset(localVariableTypeInfo.u2startPC + localVariableTypeInfo.u2length); localVariableTypeInfo.u2length = newEndPC - newStartPC; localVariableTypeInfo.u2startPC = newStartPC; } // Small utility methods. /** * Adjusts the given jump offsets for the instruction at the given offset. */ private void remapJumpOffsets(int offset, int[] jumpOffsets) { for (int index = 0; index < jumpOffsets.length; index++) { jumpOffsets[index] = remapBranchOffset(offset, jumpOffsets[index]); } } /** * Computes the new branch offset for the instruction at the given offset * with the given branch offset. */ private int remapBranchOffset(int offset, int branchOffset) { return remapInstructionOffset(offset + branchOffset) - newOffset; } /** * Computes the new instruction offset for the instruction at the given offset. */ private int remapInstructionOffset(int offset) { if (offset < 0 || offset > codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+offset+"] in code with length ["+codeLength+"]"); } return instructionOffsetMap[offset]; } /** * Returns the given list of exceptions, without the ones that have empty * code blocks. */ private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos, int exceptionInfoCount) { // Overwrite all empty exceptions. int newIndex = 0; for (int index = 0; index < exceptionInfoCount; index++) { ExceptionInfo exceptionInfo = exceptionInfos[index]; if (exceptionInfo.u2startPC < exceptionInfo.u2endPC) { exceptionInfos[newIndex++] = exceptionInfo; } } return newIndex; } /** * Returns the given list of line numbers, without the ones that have empty * code blocks or that exceed the code size. */ private int removeEmptyLineNumbers(LineNumberInfo[] lineNumberInfos, int lineNumberInfoCount, int codeLength) { // Overwrite all empty line number entries. int newIndex = 0; for (int index = 0; index < lineNumberInfoCount; index++) { LineNumberInfo lineNumberInfo = lineNumberInfos[index]; int startPC = lineNumberInfo.u2startPC; if (startPC < codeLength && (index == 0 || startPC > lineNumberInfos[index-1].u2startPC)) { lineNumberInfos[newIndex++] = lineNumberInfo; } } return newIndex; } private class CompositeInstruction extends Instruction { private Instruction[] instructions; private CompositeInstruction(Instruction[] instructions) { this.instructions = instructions; } // Implementations for Instruction. public Instruction shrink() { for (int index = 0; index < instructions.length; index++) { instructions[index] = instructions[index].shrink(); } return this; } public void write(byte[] code, int offset) { for (int index = 0; index < instructions.length; index++) { Instruction instruction = instructions[index]; instruction.write(code, offset); offset += instruction.length(offset); } } protected void readInfo(byte[] code, int offset) { throw new UnsupportedOperationException("Can't read composite instruction"); } protected void writeInfo(byte[] code, int offset) { throw new UnsupportedOperationException("Can't write composite instruction"); } public int length(int offset) { int newOffset = offset; for (int index = 0; index < instructions.length; index++) { newOffset += instructions[index].length(newOffset); } return newOffset - offset; } public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) { if (instructionVisitor != CodeAttributeEditor.this) { throw new UnsupportedOperationException("Unexpected visitor ["+instructionVisitor+"]"); } for (int index = 0; index < instructions.length; index++) { Instruction instruction = instructions[index]; instruction.accept(clazz, method, codeAttribute, offset, CodeAttributeEditor.this); offset += instruction.length(offset); } } // Implementations for Object. public String toString() { StringBuffer stringBuffer = new StringBuffer(); for (int index = 0; index < instructions.length; index++) { stringBuffer.append(instructions[index].toString()).append("; "); } return stringBuffer.toString(); } } } proguard4.8/src/proguard/classfile/editor/InterfaceAdder.java0000644000175000017500000000407711736333524023150 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.constant.ClassConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This ConstantVisitor adds all interfaces that it visits to the given * target class. * * @author Eric Lafortune */ public class InterfaceAdder extends SimplifiedVisitor implements ConstantVisitor { private final ConstantAdder constantAdder; private final InterfacesEditor interfacesEditor; /** * Creates a new InterfaceAdder that will add interfaces to the given * target class. */ public InterfaceAdder(ProgramClass targetClass) { constantAdder = new ConstantAdder(targetClass); interfacesEditor = new InterfacesEditor(targetClass); } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { interfacesEditor.addInterface(constantAdder.addConstant(clazz, classConstant)); } }proguard4.8/src/proguard/classfile/editor/VariableCleaner.java0000664000175000017500000002445511736333524023333 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; import java.util.Arrays; /** * This AttributeVisitor cleans up variable tables in all code attributes that * it visits. It trims overlapping local variables. It removes empty local * variables and empty local variable tables. * * @author Eric Lafortune */ public class VariableCleaner extends SimplifiedVisitor implements AttributeVisitor { private boolean deleteLocalVariableTableAttribute; private boolean deleteLocalVariableTypeTableAttribute; // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { deleteLocalVariableTableAttribute = false; deleteLocalVariableTypeTableAttribute = false; // Trim the local variable table and the local variable type table. codeAttribute.attributesAccept(clazz, method, this); // Delete the local variable table if it ended up empty. if (deleteLocalVariableTableAttribute) { AttributesEditor editor = new AttributesEditor((ProgramClass)clazz, (ProgramMember)method, codeAttribute, true); editor.deleteAttribute(ClassConstants.ATTR_LocalVariableTable); } // Delete the local variable type table if it ended up empty. if (deleteLocalVariableTypeTableAttribute) { AttributesEditor editor = new AttributesEditor((ProgramClass)clazz, (ProgramMember)method, codeAttribute, true); editor.deleteAttribute(ClassConstants.ATTR_LocalVariableTypeTable); } } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Clean up local variables that aren't used. localVariableTableAttribute.u2localVariableTableLength = removeUnusedLocalVariables(localVariableTableAttribute.localVariableTable, localVariableTableAttribute.u2localVariableTableLength, codeAttribute.u2maxLocals); // Trim the code blocks of the local variables. trimLocalVariables(localVariableTableAttribute.localVariableTable, localVariableTableAttribute.u2localVariableTableLength, codeAttribute.u2maxLocals); // Delete the attribute in a moment, if it is empty. if (localVariableTableAttribute.u2localVariableTableLength == 0) { deleteLocalVariableTableAttribute = true; } } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Clean up local variables that aren't used. localVariableTypeTableAttribute.u2localVariableTypeTableLength = removeUnusedLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, localVariableTypeTableAttribute.u2localVariableTypeTableLength, codeAttribute.u2maxLocals); // Trim the code blocks of the local variables. trimLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, localVariableTypeTableAttribute.u2localVariableTypeTableLength, codeAttribute.u2maxLocals); // Delete the attribute in a moment, if it is empty. if (localVariableTypeTableAttribute.u2localVariableTypeTableLength == 0) { deleteLocalVariableTypeTableAttribute = true; } } // Small utility methods. /** * Returns the given list of local variables, without the ones that aren't * used. */ private int removeUnusedLocalVariables(LocalVariableInfo[] localVariableInfos, int localVariableInfoCount, int maxLocals) { // Overwrite all empty local variable entries. // Do keep parameter entries. int newIndex = 0; for (int index = 0; index < localVariableInfoCount; index++) { LocalVariableInfo localVariableInfo = localVariableInfos[index]; if (localVariableInfo.u2index >= 0 && localVariableInfo.u2index < maxLocals && (localVariableInfo.u2startPC == 0 || localVariableInfo.u2length > 0)) { localVariableInfos[newIndex++] = localVariableInfos[index]; } } // Clean up any remaining array elements. Arrays.fill(localVariableInfos, newIndex, localVariableInfoCount, null); return newIndex; } /** * Returns the given list of local variable types, without the ones that * aren't used. */ private int removeUnusedLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, int localVariableTypeInfoCount, int maxLocals) { // Overwrite all empty local variable type entries. // Do keep parameter entries. int newIndex = 0; for (int index = 0; index < localVariableTypeInfoCount; index++) { LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; if (localVariableTypeInfo.u2index >= 0 && localVariableTypeInfo.u2index < maxLocals && (localVariableTypeInfo.u2startPC == 0 || localVariableTypeInfo.u2length > 0)) { localVariableTypeInfos[newIndex++] = localVariableTypeInfos[index]; } } // Clean up any remaining array elements. Arrays.fill(localVariableTypeInfos, newIndex, localVariableTypeInfoCount, null); return newIndex; } /** * Sorts the given list of local variables and trims their code blocks * when necessary. The block is trimmed at the end, which is a bit * arbitrary. */ private void trimLocalVariables(LocalVariableInfo[] localVariableInfos, int localVariableInfoCount, int maxLocals) { // Sort the local variable entries. Arrays.sort(localVariableInfos, 0, localVariableInfoCount); int[] startPCs = createMaxArray(maxLocals); // Trim the local variable entries, starting at the last one. for (int index = localVariableInfoCount-1; index >= 0; index--) { LocalVariableInfo localVariableInfo = localVariableInfos[index]; // Make sure the variable's code block doesn't overlap with the // next one for the same variable. int maxLength = startPCs[localVariableInfo.u2index] - localVariableInfo.u2startPC; if (localVariableInfo.u2length > maxLength) { localVariableInfo.u2length = maxLength; } startPCs[localVariableInfo.u2index] = localVariableInfo.u2startPC; } } /** * Sorts the given list of local variable types and trims their code blocks * when necessary. The block is trimmed at the end, which is a bit * arbitrary. */ private void trimLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, int localVariableTypeInfoCount, int maxLocals) { // Sort the local variable entries. Arrays.sort(localVariableTypeInfos, 0, localVariableTypeInfoCount); int[] startPCs = createMaxArray(maxLocals); // Trim the local variable entries, starting at the last one. for (int index = localVariableTypeInfoCount-1; index >= 0; index--) { LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; // Make sure the variable's code block doesn't overlap with the // next one for the same variable. int maxLength = startPCs[localVariableTypeInfo.u2index] - localVariableTypeInfo.u2startPC; if (localVariableTypeInfo.u2length > maxLength) { localVariableTypeInfo.u2length = maxLength; } startPCs[localVariableTypeInfo.u2index] = localVariableTypeInfo.u2startPC; } } /** * Creates an integer array of the given length, initialized with * Integer.MAX_VALUE. */ private int[] createMaxArray(int length) { int[] startPCs = new int[length]; for (int index = 0; index < length; index++) { startPCs[index] = Integer.MAX_VALUE; } return startPCs; } }proguard4.8/src/proguard/classfile/editor/ExceptionAdder.java0000644000175000017500000000453311736333524023203 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.ExceptionsAttribute; import proguard.classfile.constant.ClassConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This ConstantVisitor adds all class constants that it visits to the given * target exceptions attribute. * * @author Eric Lafortune */ public class ExceptionAdder extends SimplifiedVisitor implements ConstantVisitor { private final ConstantAdder constantAdder; private final ExceptionsAttributeEditor exceptionsAttributeEditor; /** * Creates a new ExceptionAdder that will copy classes into the given * target exceptions attribute. */ public ExceptionAdder(ProgramClass targetClass, ExceptionsAttribute targetExceptionsAttribute) { constantAdder = new ConstantAdder(targetClass); exceptionsAttributeEditor = new ExceptionsAttributeEditor(targetExceptionsAttribute); } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Add a class constant to the constant pool. constantAdder.visitClassConstant(clazz, classConstant); // Add the index of the class constant to the list of exceptions. exceptionsAttributeEditor.addException(constantAdder.getConstantIndex()); } } proguard4.8/src/proguard/classfile/editor/VariableRemapper.java0000644000175000017500000001300211736333524023515 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor remaps variable indexes in all attributes that it * visits, based on a given index map. * * @author Eric Lafortune */ public class VariableRemapper extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor { private static final boolean DEBUG = false; private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); private int[] variableMap; /** * Sets the given mapping of old variable indexes to their new indexes. * Variables that should disappear can be mapped to -1. */ public void setVariableMap(int[] variableMap) { this.variableMap = variableMap; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (DEBUG) { System.out.println("VariableRemapper: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); for (int index= 0; index < codeAttribute.u2maxLocals; index++) { System.out.println(" v"+index+" -> "+variableMap[index]); } } // Remap the variables of the attributes, before editing the code and // cleaning up its local variable frame. codeAttribute.attributesAccept(clazz, method, this); // Initially, the code attribute editor doesn't contain any changes. codeAttributeEditor.reset(codeAttribute.u4codeLength); // Remap the variables of the instructions. codeAttribute.instructionsAccept(clazz, method, this); // Apply the code atribute editor. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Remap the variable references of the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Remap the variable references of the local variables. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { localVariableInfo.u2index = remapVariable(localVariableInfo.u2index); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { localVariableTypeInfo.u2index = remapVariable(localVariableTypeInfo.u2index); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Is the new variable index different from the original one? int oldVariableIndex = variableInstruction.variableIndex; int newVariableIndex = remapVariable(oldVariableIndex); if (newVariableIndex != oldVariableIndex) { // Replace the instruction. Instruction replacementInstruction = new VariableInstruction(variableInstruction.opcode, newVariableIndex, variableInstruction.constant).shrink(); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); } } // Small utility methods. /** * Returns the new variable index of the given variable. */ private int remapVariable(int variableIndex) { return variableMap[variableIndex]; } } proguard4.8/src/proguard/classfile/editor/MemberReferenceFixer.java0000644000175000017500000004067111736333524024334 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** * This ClassVisitor fixes constant pool field and method references to fields * and methods whose names or descriptors have changed. * * @author Eric Lafortune */ public class MemberReferenceFixer extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, MemberVisitor, AttributeVisitor, AnnotationVisitor, ElementValueVisitor { private static final boolean DEBUG = false; private final StackSizeUpdater stackSizeUpdater = new StackSizeUpdater(); // Parameter for the visitor methods. private int constantIndex; // Return values for the visitor methods. private boolean isInterfaceMethod; private boolean stackSizesMayHaveChanged; // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { stackSizesMayHaveChanged = false; // Fix the constant pool entries. for (int index = 1; index < programClass.u2constantPoolCount; index++) { Constant constant = programClass.constantPool[index]; if (constant != null) { // Fix the entry, replacing it entirely if needed. this.constantIndex = index; constant.accept(programClass, this); } } // Fix the class members. programClass.fieldsAccept(this); programClass.methodsAccept(this); // Fix the attributes. programClass.attributesAccept(this); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Does the string refer to a class member, due to a // Class.get[Declared]{Field,Method} construct? Member referencedMember = stringConstant.referencedMember; if (referencedMember != null) { Clazz referencedClass = stringConstant.referencedClass; // Does it have a new name? String newName = referencedMember.getName(referencedClass); if (!stringConstant.getString(clazz).equals(newName)) { if (DEBUG) { debug(clazz, stringConstant, referencedClass, referencedMember); } // Update the name. stringConstant.u2stringIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newName); } } } public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { // Do we know the referenced field? Member referencedMember = fieldrefConstant.referencedMember; if (referencedMember != null) { Clazz referencedClass = fieldrefConstant.referencedClass; // Does it have a new name or type? String newName = referencedMember.getName(referencedClass); String newType = referencedMember.getDescriptor(referencedClass); if (!fieldrefConstant.getName(clazz).equals(newName) || !fieldrefConstant.getType(clazz).equals(newType)) { if (DEBUG) { debug(clazz, fieldrefConstant, referencedClass, referencedMember); } // Update the name and type index. fieldrefConstant.u2nameAndTypeIndex = new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName, newType); } } } public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) { // Do we know the referenced interface method? Member referencedMember = interfaceMethodrefConstant.referencedMember; if (referencedMember != null) { Clazz referencedClass = interfaceMethodrefConstant.referencedClass; // Does it have a new name or type? String newName = referencedMember.getName(referencedClass); String newType = referencedMember.getDescriptor(referencedClass); if (!interfaceMethodrefConstant.getName(clazz).equals(newName) || !interfaceMethodrefConstant.getType(clazz).equals(newType)) { if (DEBUG) { debug(clazz, interfaceMethodrefConstant, referencedClass, referencedMember); } // Update the name and type index. interfaceMethodrefConstant.u2nameAndTypeIndex = new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName, newType); // Remember that the stack sizes of the methods in this class // may have changed. stackSizesMayHaveChanged = true; } // Check if this is an interface method. isInterfaceMethod = true; clazz.constantPoolEntryAccept(interfaceMethodrefConstant.u2classIndex, this); // Has the method become a non-interface method? if (!isInterfaceMethod) { if (DEBUG) { System.out.println("MemberReferenceFixer:"); System.out.println(" Class file = "+clazz.getName()); System.out.println(" Ref class = "+referencedClass.getName()); System.out.println(" Ref method = "+interfaceMethodrefConstant.getName(clazz)+interfaceMethodrefConstant.getType(clazz)); System.out.println(" -> ordinary method"); } // Replace the interface method reference by a method reference. ((ProgramClass)clazz).constantPool[this.constantIndex] = new MethodrefConstant(interfaceMethodrefConstant.u2classIndex, interfaceMethodrefConstant.u2nameAndTypeIndex, referencedClass, referencedMember); } } } public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { // Do we know the referenced method? Member referencedMember = methodrefConstant.referencedMember; if (referencedMember != null) { Clazz referencedClass = methodrefConstant.referencedClass; // Does it have a new name or type? String newName = referencedMember.getName(referencedClass); String newType = referencedMember.getDescriptor(referencedClass); if (!methodrefConstant.getName(clazz).equals(newName) || !methodrefConstant.getType(clazz).equals(newType)) { if (DEBUG) { debug(clazz, methodrefConstant, referencedClass, referencedMember); } // Update the name and type index. methodrefConstant.u2nameAndTypeIndex = new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName, newType); // Remember that the stack sizes of the methods in this class // may have changed. stackSizesMayHaveChanged = true; } // Check if this is an interface method. isInterfaceMethod = false; clazz.constantPoolEntryAccept(methodrefConstant.u2classIndex, this); // Has the method become an interface method? if (isInterfaceMethod) { if (DEBUG) { System.out.println("MemberReferenceFixer:"); System.out.println(" Class file = "+clazz.getName()); System.out.println(" Ref class = "+referencedClass.getName()); System.out.println(" Ref method = "+methodrefConstant.getName(clazz)+methodrefConstant.getType(clazz)); System.out.println(" -> interface method"); } // Replace the method reference by an interface method reference. ((ProgramClass)clazz).constantPool[this.constantIndex] = new InterfaceMethodrefConstant(methodrefConstant.u2classIndex, methodrefConstant.u2nameAndTypeIndex, referencedClass, referencedMember); } } } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Check if this class entry is an array type. if (ClassUtil.isInternalArrayType(classConstant.getName(clazz))) { isInterfaceMethod = false; } else { // Check if this class entry refers to an interface class. Clazz referencedClass = classConstant.referencedClass; if (referencedClass != null) { isInterfaceMethod = (referencedClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0; } } } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { // Fix the attributes. programMember.attributesAccept(programClass, this); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { Member referencedMember = enclosingMethodAttribute.referencedMethod; if (referencedMember != null) { Clazz referencedClass = enclosingMethodAttribute.referencedClass; // Does it have a new name or type? String newName = referencedMember.getName(referencedClass); String newType = referencedMember.getDescriptor(referencedClass); if (!enclosingMethodAttribute.getName(clazz).equals(newName) || !enclosingMethodAttribute.getType(clazz).equals(newType)) { // Update the name and type index. enclosingMethodAttribute.u2nameAndTypeIndex = new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName, newType); } } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Recompute the maximum stack size if necessary. if (stackSizesMayHaveChanged) { stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute); } // Fix the nested attributes. codeAttribute.attributesAccept(clazz, method, this); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Fix the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Fix the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Fix the annotation. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { // Fix the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { fixElementValue(clazz, annotation, constantElementValue); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { fixElementValue(clazz, annotation, enumConstantElementValue); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { fixElementValue(clazz, annotation, classElementValue); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { fixElementValue(clazz, annotation, annotationElementValue); // Fix the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { fixElementValue(clazz, annotation, arrayElementValue); // Fix the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } // Small utility methods. /** * Fixes the method reference of the element value, if any. */ private void fixElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) { // Do we know the referenced method? Member referencedMember = elementValue.referencedMethod; if (referencedMember != null) { // Does it have a new name or type? String methodName = elementValue.getMethodName(clazz); String newMethodName = referencedMember.getName(elementValue.referencedClass); if (!methodName.equals(newMethodName)) { // Update the element name index. elementValue.u2elementNameIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newMethodName); } } } private void debug(Clazz clazz, StringConstant stringConstant, Clazz referencedClass, Member referencedMember) { System.out.println("MemberReferenceFixer:"); System.out.println(" ["+clazz.getName()+"]: String ["+ stringConstant.getString(clazz)+"] -> ["+ referencedClass.getName()+"."+referencedMember.getName(referencedClass)+" "+referencedMember.getDescriptor(referencedClass)+"]"); } private void debug(Clazz clazz, RefConstant refConstant, Clazz referencedClass, Member referencedMember) { System.out.println("MemberReferenceFixer:"); System.out.println(" ["+clazz.getName()+"]: ["+ refConstant.getClassName(clazz)+"."+refConstant.getName(clazz)+" "+refConstant.getType(clazz)+"] -> ["+ referencedClass.getName()+"."+referencedMember.getName(referencedClass)+" "+referencedMember.getDescriptor(referencedClass)+"]"); } } proguard4.8/src/proguard/classfile/editor/ConstantPoolSorter.java0000644000175000017500000001131411736333524024122 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.constant.Constant; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; import java.util.Arrays; /** * This ClassVisitor sorts the constant pool entries of the program classes * that it visits. The sorting order is based on the types of the constant pool * entries in the first place, and on their contents in the second place. * * @author Eric Lafortune */ public class ConstantPoolSorter extends SimplifiedVisitor implements ClassVisitor { private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; private ComparableConstant[] comparableConstantPool = new ComparableConstant[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; private Constant[] newConstantPool = new Constant[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { int constantPoolCount = programClass.u2constantPoolCount; // Sort the constant pool and set up an index map. if (constantIndexMap.length < constantPoolCount) { constantIndexMap = new int[constantPoolCount]; comparableConstantPool = new ComparableConstant[constantPoolCount]; newConstantPool = new Constant[constantPoolCount]; } // Initialize an array whose elements can be compared. int sortLength = 0; for (int oldIndex = 1; oldIndex < constantPoolCount; oldIndex++) { Constant constant = programClass.constantPool[oldIndex]; if (constant != null) { comparableConstantPool[sortLength++] = new ComparableConstant(programClass, oldIndex, constant); } } // Sort the array. Arrays.sort(comparableConstantPool, 0, sortLength); // Save the sorted elements. int newLength = 1; int newIndex = 1; ComparableConstant previousComparableConstant = null; for (int sortIndex = 0; sortIndex < sortLength; sortIndex++) { ComparableConstant comparableConstant = comparableConstantPool[sortIndex]; // Isn't this a duplicate of the previous constant? if (!comparableConstant.equals(previousComparableConstant)) { // Remember the index of the new entry. newIndex = newLength; // Copy the sorted constant pool entry over to the constant pool. Constant constant = comparableConstant.getConstant(); newConstantPool[newLength++] = constant; // Long entries take up two slots, the second of which is null. int tag = constant.getTag(); if (tag == ClassConstants.CONSTANT_Long || tag == ClassConstants.CONSTANT_Double) { newConstantPool[newLength++] = null; } previousComparableConstant = comparableConstant; } // Fill out the map array. constantIndexMap[comparableConstant.getIndex()] = newIndex; } // Copy the new constant pool over. System.arraycopy(newConstantPool, 0, programClass.constantPool, 0, newLength); // Clear any remaining entries. Arrays.fill(programClass.constantPool, newLength, constantPoolCount, null); programClass.u2constantPoolCount = newLength; // Remap all constant pool references. constantPoolRemapper.setConstantIndexMap(constantIndexMap); constantPoolRemapper.visitProgramClass(programClass); } } proguard4.8/src/proguard/classfile/editor/ElementValuesEditor.java0000644000175000017500000002075311736333524024227 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.annotation.*; /** * This class can add and delete element values to and from a given target * annotation default attribute, annotation, or array element value. Element * values to be added must be filled out beforehand, including their references * to the constant pool. * * @author Eric Lafortune */ public class ElementValuesEditor { private final ProgramClass targetClass; private final Annotation targetAnnotation; private final ArrayElementValue targetArrayElementValue; private final boolean replaceElementValues; /** * Creates a new ElementValuesEditor that will edit element values in the * given target annotation. */ public ElementValuesEditor(ProgramClass targetClass, Annotation targetAnnotation, boolean replaceElementValues) { this.targetClass = targetClass; this.targetAnnotation = targetAnnotation; this.targetArrayElementValue = null; this.replaceElementValues = replaceElementValues; } /** * Creates a new ElementValuesEditor that will edit element values in the * given target array element value. */ public ElementValuesEditor(ProgramClass targetClass, ArrayElementValue targetArrayElementValue, boolean replaceElementValues) { this.targetClass = targetClass; this.targetAnnotation = null; this.targetArrayElementValue = targetArrayElementValue; this.replaceElementValues = replaceElementValues; } /** * Adds the given elementValue to the target. */ public void addElementValue(ElementValue elementValue) { // What's the target? if (targetAnnotation != null) { // Try to replace an existing element value. if (!replaceElementValues || !replaceElementValue(targetAnnotation.u2elementValuesCount, targetAnnotation.elementValues, elementValue)) { // Otherwise append the element value. targetAnnotation.elementValues = addElementValue(targetAnnotation.u2elementValuesCount, targetAnnotation.elementValues, elementValue); targetAnnotation.u2elementValuesCount++; } } else { // Try to replace an existing element value. if (!replaceElementValues || !replaceElementValue(targetArrayElementValue.u2elementValuesCount, targetArrayElementValue.elementValues, elementValue)) { // Otherwise append the element value. targetArrayElementValue.elementValues = addElementValue(targetArrayElementValue.u2elementValuesCount, targetArrayElementValue.elementValues, elementValue); targetArrayElementValue.u2elementValuesCount++; } } } /** * Deletes the given elementValue to the target. */ public void deleteElementValue(String elementValueMethodName) { // What's the target? if (targetAnnotation != null) { // Delete the element value to the target annotation. targetAnnotation.u2elementValuesCount = deleteElementValue(targetAnnotation.u2elementValuesCount, targetAnnotation.elementValues, elementValueMethodName); } else { // Delete the element value to the target array element value. targetArrayElementValue.u2elementValuesCount = deleteElementValue(targetArrayElementValue.u2elementValuesCount, targetArrayElementValue.elementValues, elementValueMethodName); } } // Small utility methods. /** * Tries put the given element value in place of an existing element value * of the same name, returning whether it was present. */ private boolean replaceElementValue(int elementValuesCount, ElementValue[] elementValues, ElementValue elementValue) { // Find the element value with the same name. int index = findElementValue(elementValuesCount, elementValues, elementValue.getMethodName(targetClass)); if (index < 0) { return false; } elementValues[index] = elementValue; return true; } /** * Appends the given element value to the given array of element values, * creating a new array if necessary. */ private ElementValue[] addElementValue(int elementValuesCount, ElementValue[] elementValues, ElementValue elementValue) { // Is the array too small to contain the additional elementValue? if (elementValues.length <= elementValuesCount) { // Create a new array and copy the elementValues into it. ElementValue[] newElementValues = new ElementValue[elementValuesCount + 1]; System.arraycopy(elementValues, 0, newElementValues, 0, elementValuesCount); elementValues = newElementValues; } // Append the elementValue. elementValues[elementValuesCount] = elementValue; return elementValues; } /** * Deletes the element values with the given name from the given array of * element values, returning the new number of element values. */ private int deleteElementValue(int elementValuesCount, ElementValue[] elementValues, String elementValueMethodName) { // Find the element value. int index = findElementValue(elementValuesCount, elementValues, elementValueMethodName); if (index < 0) { return elementValuesCount; } // Shift the other element values in the array. System.arraycopy(elementValues, index + 1, elementValues, index, elementValuesCount - index - 1); // Clear the last entry in the array. elementValues[--elementValuesCount] = null; return elementValuesCount; } /** * Finds the index of the element value with the given name in the given * array of element values. */ private int findElementValue(int elementValuesCount, ElementValue[] elementValues, String elementValueName) { for (int index = 0; index < elementValuesCount; index++) { if (elementValues[index].getMethodName(targetClass).equals(elementValueName)) { return index; } } return -1; } }proguard4.8/src/proguard/classfile/editor/ElementValueAdder.java0000644000175000017500000002245011736333524023631 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; /** * This AnnotationVisitor adds all element values that it visits to the given * target annotation default attribute, annotation, or element value. * * @author Eric Lafortune */ public class ElementValueAdder implements ElementValueVisitor { private static final ElementValue[] EMPTY_ELEMENT_VALUES = new ElementValue[0]; private final ProgramClass targetClass; private final AnnotationDefaultAttribute targetAnnotationDefaultAttribute; private final ConstantAdder constantAdder; private final ElementValuesEditor elementValuesEditor; /** * Creates a new ElementValueAdder that will copy element values into the * given target annotation default attribute value. */ public ElementValueAdder(ProgramClass targetClass, AnnotationDefaultAttribute targetAnnotationDefaultAttribute, boolean replaceElementValues) { this.targetClass = targetClass; this.targetAnnotationDefaultAttribute = targetAnnotationDefaultAttribute; constantAdder = new ConstantAdder(targetClass); elementValuesEditor = null; } /** * Creates a new ElementValueAdder that will copy element values into the * given target annotation. */ public ElementValueAdder(ProgramClass targetClass, Annotation targetAnnotation, boolean replaceElementValues) { this.targetClass = targetClass; this.targetAnnotationDefaultAttribute = null; constantAdder = new ConstantAdder(targetClass); elementValuesEditor = new ElementValuesEditor(targetClass, targetAnnotation, replaceElementValues); } /** * Creates a new ElementValueAdder that will copy element values into the * given target element value. */ public ElementValueAdder(ProgramClass targetClass, ArrayElementValue targetArrayElementValue, boolean replaceElementValues) { this.targetClass = targetClass; this.targetAnnotationDefaultAttribute = null; constantAdder = new ConstantAdder(targetClass); elementValuesEditor = new ElementValuesEditor(targetClass, targetArrayElementValue, replaceElementValues); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { // Create a copy of the element value. ConstantElementValue newConstantElementValue = new ConstantElementValue(constantElementValue.u1tag, constantElementValue.u2elementNameIndex == 0 ? 0 : constantAdder.addConstant(clazz, constantElementValue.u2elementNameIndex), constantAdder.addConstant(clazz, constantElementValue.u2constantValueIndex)); newConstantElementValue.referencedClass = constantElementValue.referencedClass; newConstantElementValue.referencedMethod = constantElementValue.referencedMethod; // Add it to the target. addElementValue(newConstantElementValue); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { // Create a copy of the element value. EnumConstantElementValue newEnumConstantElementValue = new EnumConstantElementValue(enumConstantElementValue.u2elementNameIndex == 0 ? 0 : constantAdder.addConstant(clazz, enumConstantElementValue.u2elementNameIndex), constantAdder.addConstant(clazz, enumConstantElementValue.u2typeNameIndex), constantAdder.addConstant(clazz, enumConstantElementValue.u2constantNameIndex)); newEnumConstantElementValue.referencedClass = enumConstantElementValue.referencedClass; newEnumConstantElementValue.referencedMethod = enumConstantElementValue.referencedMethod; // TODO: Clone array. newEnumConstantElementValue.referencedClasses = enumConstantElementValue.referencedClasses; // Add it to the target. addElementValue(newEnumConstantElementValue); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { // Create a copy of the element value. ClassElementValue newClassElementValue = new ClassElementValue(classElementValue.u2elementNameIndex == 0 ? 0 : constantAdder.addConstant(clazz, classElementValue.u2elementNameIndex), constantAdder.addConstant(clazz, classElementValue.u2classInfoIndex)); newClassElementValue.referencedClass = classElementValue.referencedClass; newClassElementValue.referencedMethod = classElementValue.referencedMethod; // TODO: Clone array. newClassElementValue.referencedClasses = classElementValue.referencedClasses; // Add it to the target. addElementValue(newClassElementValue); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { // Create a copy of the element value. AnnotationElementValue newAnnotationElementValue = new AnnotationElementValue(annotationElementValue.u2elementNameIndex == 0 ? 0 : constantAdder.addConstant(clazz, annotationElementValue.u2elementNameIndex), new Annotation()); newAnnotationElementValue.referencedClass = annotationElementValue.referencedClass; newAnnotationElementValue.referencedMethod = annotationElementValue.referencedMethod; annotationElementValue.annotationAccept(clazz, new AnnotationAdder(targetClass, newAnnotationElementValue)); // Add it to the target. addElementValue(newAnnotationElementValue); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { // Create a copy of the element value. ArrayElementValue newArrayElementValue = new ArrayElementValue(arrayElementValue.u2elementNameIndex == 0 ? 0 : constantAdder.addConstant(clazz, arrayElementValue.u2elementNameIndex), 0, arrayElementValue.u2elementValuesCount > 0 ? new ElementValue[arrayElementValue.u2elementValuesCount] : EMPTY_ELEMENT_VALUES); newArrayElementValue.referencedClass = arrayElementValue.referencedClass; newArrayElementValue.referencedMethod = arrayElementValue.referencedMethod; arrayElementValue.elementValuesAccept(clazz, annotation, new ElementValueAdder(targetClass, newArrayElementValue, false)); // Add it to the target. addElementValue(newArrayElementValue); } // Small utility methods. private void addElementValue(ElementValue newElementValue) { // What's the target? if (targetAnnotationDefaultAttribute != null) { // Simply set the completed element value. targetAnnotationDefaultAttribute.defaultValue = newElementValue; } else { // Add it to the target. elementValuesEditor.addElementValue(newElementValue); } } }proguard4.8/src/proguard/classfile/editor/AttributeAdder.java0000664000175000017500000005227611740562157023222 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor adds all attributes that it visits to the given * target class, class member, or attribute. * * @author Eric Lafortune */ public class AttributeAdder extends SimplifiedVisitor implements AttributeVisitor { private static final byte[] EMPTY_BYTES = new byte[0]; private static final int[] EMPTY_INTS = new int[0]; private static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0]; private static final ExceptionInfo[] EMPTY_EXCEPTIONS = new ExceptionInfo[0]; private final ProgramClass targetClass; private final ProgramMember targetMember; private final CodeAttribute targetCodeAttribute; private final boolean replaceAttributes; private final ConstantAdder constantAdder; private final AttributesEditor attributesEditor; /** * Creates a new AttributeAdder that will copy attributes into the given * target class. */ public AttributeAdder(ProgramClass targetClass, boolean replaceAttributes) { this(targetClass, null, null, replaceAttributes); } /** * Creates a new AttributeAdder that will copy attributes into the given * target class member. */ public AttributeAdder(ProgramClass targetClass, ProgramMember targetMember, boolean replaceAttributes) { this(targetClass, targetMember, null, replaceAttributes); } /** * Creates a new AttributeAdder that will copy attributes into the given * target attribute. */ public AttributeAdder(ProgramClass targetClass, ProgramMember targetMember, CodeAttribute targetCodeAttribute, boolean replaceAttributes) { this.targetClass = targetClass; this.targetMember = targetMember; this.targetCodeAttribute = targetCodeAttribute; this.replaceAttributes = replaceAttributes; constantAdder = new ConstantAdder(targetClass); attributesEditor = new AttributesEditor(targetClass, targetMember, targetCodeAttribute, replaceAttributes); } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { // Create a copy of the attribute. UnknownAttribute newUnknownAttribute = new UnknownAttribute(constantAdder.addConstant(clazz, unknownAttribute.u2attributeNameIndex), unknownAttribute.u4attributeLength, unknownAttribute.info); // Add it to the target class. attributesEditor.addAttribute(newUnknownAttribute); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { // Create a copy of the attribute. SourceFileAttribute newSourceFileAttribute = new SourceFileAttribute(constantAdder.addConstant(clazz, sourceFileAttribute.u2attributeNameIndex), constantAdder.addConstant(clazz, sourceFileAttribute.u2sourceFileIndex)); // Add it to the target class. attributesEditor.addAttribute(newSourceFileAttribute); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { // Create a copy of the attribute. SourceDirAttribute newSourceDirAttribute = new SourceDirAttribute(constantAdder.addConstant(clazz, sourceDirAttribute.u2attributeNameIndex), constantAdder.addConstant(clazz, sourceDirAttribute.u2sourceDirIndex)); // Add it to the target class. attributesEditor.addAttribute(newSourceDirAttribute); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Create a copy of the attribute. InnerClassesAttribute newInnerClassesAttribute = new InnerClassesAttribute(constantAdder.addConstant(clazz, innerClassesAttribute.u2attributeNameIndex), 0, null); // Add it to the target class. attributesEditor.addAttribute(newInnerClassesAttribute); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { // Create a copy of the attribute. EnclosingMethodAttribute newEnclosingMethodAttribute = new EnclosingMethodAttribute(constantAdder.addConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex), constantAdder.addConstant(clazz, enclosingMethodAttribute.u2classIndex), enclosingMethodAttribute.u2nameAndTypeIndex == 0 ? 0 : constantAdder.addConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex)); newEnclosingMethodAttribute.referencedClass = enclosingMethodAttribute.referencedClass; newEnclosingMethodAttribute.referencedMethod = enclosingMethodAttribute.referencedMethod; // Add it to the target class. attributesEditor.addAttribute(newEnclosingMethodAttribute); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { // Create a copy of the attribute. DeprecatedAttribute newDeprecatedAttribute = new DeprecatedAttribute(constantAdder.addConstant(clazz, deprecatedAttribute.u2attributeNameIndex)); // Add it to the target. attributesEditor.addAttribute(newDeprecatedAttribute); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { // Create a copy of the attribute. SyntheticAttribute newSyntheticAttribute = new SyntheticAttribute(constantAdder.addConstant(clazz, syntheticAttribute.u2attributeNameIndex)); // Add it to the target. attributesEditor.addAttribute(newSyntheticAttribute); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { // Create a copy of the attribute. SignatureAttribute newSignatureAttribute = new SignatureAttribute(constantAdder.addConstant(clazz, signatureAttribute.u2attributeNameIndex), constantAdder.addConstant(clazz, signatureAttribute.u2signatureIndex)); newSignatureAttribute.referencedClasses = signatureAttribute.referencedClasses; // Add it to the target. attributesEditor.addAttribute(newSignatureAttribute); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { // Create a copy of the attribute. ConstantValueAttribute newConstantValueAttribute = new ConstantValueAttribute(constantAdder.addConstant(clazz, constantValueAttribute.u2attributeNameIndex), constantAdder.addConstant(clazz, constantValueAttribute.u2constantValueIndex)); // Add it to the target field. attributesEditor.addAttribute(newConstantValueAttribute); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { // Create a new exceptions attribute. ExceptionsAttribute newExceptionsAttribute = new ExceptionsAttribute(constantAdder.addConstant(clazz, exceptionsAttribute.u2attributeNameIndex), 0, exceptionsAttribute.u2exceptionIndexTableLength > 0 ? new int[exceptionsAttribute.u2exceptionIndexTableLength] : EMPTY_INTS); // Add the exceptions. exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, new ExceptionAdder(targetClass, newExceptionsAttribute)); // Add it to the target method. attributesEditor.addAttribute(newExceptionsAttribute); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Create a new code attribute. CodeAttribute newCodeAttribute = new CodeAttribute(constantAdder.addConstant(clazz, codeAttribute.u2attributeNameIndex), codeAttribute.u2maxStack, codeAttribute.u2maxLocals, 0, EMPTY_BYTES, 0, codeAttribute.u2exceptionTableLength > 0 ? new ExceptionInfo[codeAttribute.u2exceptionTableLength] : EMPTY_EXCEPTIONS, 0, codeAttribute.u2attributesCount > 0 ? new Attribute[codeAttribute.u2attributesCount] : EMPTY_ATTRIBUTES); CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(); codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength + 32); // Add the instructions. codeAttribute.instructionsAccept(clazz, method, new InstructionAdder(targetClass, codeAttributeComposer)); // Append a label just after the code. codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); // Add the exceptions. codeAttribute.exceptionsAccept(clazz, method, new ExceptionInfoAdder(targetClass, codeAttributeComposer)); codeAttributeComposer.endCodeFragment(); // Add the attributes. codeAttribute.attributesAccept(clazz, method, new AttributeAdder(targetClass, targetMember, newCodeAttribute, replaceAttributes)); // Apply these changes to the new code attribute. codeAttributeComposer.visitCodeAttribute(targetClass, (Method)targetMember, newCodeAttribute); // Add the completed code attribute to the target method. attributesEditor.addAttribute(newCodeAttribute); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { // TODO: Implement method. } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { // TODO: Implement method. } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { // Create a new line number table attribute. LineNumberTableAttribute newLineNumberTableAttribute = new LineNumberTableAttribute(constantAdder.addConstant(clazz, lineNumberTableAttribute.u2attributeNameIndex), 0, new LineNumberInfo[lineNumberTableAttribute.u2lineNumberTableLength]); // Add the line numbers. lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, new LineNumberInfoAdder(newLineNumberTableAttribute)); // Add it to the target. attributesEditor.addAttribute(newLineNumberTableAttribute); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Create a new local variable table attribute. LocalVariableTableAttribute newLocalVariableTableAttribute = new LocalVariableTableAttribute(constantAdder.addConstant(clazz, localVariableTableAttribute.u2attributeNameIndex), 0, new LocalVariableInfo[localVariableTableAttribute.u2localVariableTableLength]); // Add the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, new LocalVariableInfoAdder(targetClass, newLocalVariableTableAttribute)); // Add it to the target. attributesEditor.addAttribute(newLocalVariableTableAttribute); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Create a new local variable type table attribute. LocalVariableTypeTableAttribute newLocalVariableTypeTableAttribute = new LocalVariableTypeTableAttribute(constantAdder.addConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex), 0, new LocalVariableTypeInfo[localVariableTypeTableAttribute.u2localVariableTypeTableLength]); // Add the local variable types. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, new LocalVariableTypeInfoAdder(targetClass, newLocalVariableTypeTableAttribute)); // Add it to the target. attributesEditor.addAttribute(newLocalVariableTypeTableAttribute); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { // Create a new annotations attribute. RuntimeVisibleAnnotationsAttribute newAnnotationsAttribute = new RuntimeVisibleAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleAnnotationsAttribute.u2attributeNameIndex), 0, new Annotation[runtimeVisibleAnnotationsAttribute.u2annotationsCount]); // Add the annotations. runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, new AnnotationAdder(targetClass, newAnnotationsAttribute)); // Add it to the target. attributesEditor.addAttribute(newAnnotationsAttribute); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { // Create a new annotations attribute. RuntimeInvisibleAnnotationsAttribute newAnnotationsAttribute = new RuntimeInvisibleAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleAnnotationsAttribute.u2attributeNameIndex), 0, new Annotation[runtimeInvisibleAnnotationsAttribute.u2annotationsCount]); // Add the annotations. runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, new AnnotationAdder(targetClass, newAnnotationsAttribute)); // Add it to the target. attributesEditor.addAttribute(newAnnotationsAttribute); } public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute) { // Create a new annotations attribute. RuntimeVisibleParameterAnnotationsAttribute newParameterAnnotationsAttribute = new RuntimeVisibleParameterAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleParameterAnnotationsAttribute.u2attributeNameIndex), 0, new int[runtimeVisibleParameterAnnotationsAttribute.u2parametersCount], new Annotation[runtimeVisibleParameterAnnotationsAttribute.u2parametersCount][]); // Add the annotations. runtimeVisibleParameterAnnotationsAttribute.annotationsAccept(clazz, method, new AnnotationAdder(targetClass, newParameterAnnotationsAttribute)); // Add it to the target. attributesEditor.addAttribute(newParameterAnnotationsAttribute); } public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute) { // Create a new annotations attribute. RuntimeInvisibleParameterAnnotationsAttribute newParameterAnnotationsAttribute = new RuntimeInvisibleParameterAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleParameterAnnotationsAttribute.u2attributeNameIndex), 0, new int[runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount], new Annotation[runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount][]); // Add the annotations. runtimeInvisibleParameterAnnotationsAttribute.annotationsAccept(clazz, method, new AnnotationAdder(targetClass, newParameterAnnotationsAttribute)); // Add it to the target. attributesEditor.addAttribute(newParameterAnnotationsAttribute); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Create a new annotation default attribute. AnnotationDefaultAttribute newAnnotationDefaultAttribute = new AnnotationDefaultAttribute(constantAdder.addConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex), null); // Add the annotations. annotationDefaultAttribute.defaultValueAccept(clazz, new ElementValueAdder(targetClass, newAnnotationDefaultAttribute, false)); // Add it to the target. attributesEditor.addAttribute(newAnnotationDefaultAttribute); } } proguard4.8/src/proguard/classfile/editor/BridgeMethodFixer.java0000644000175000017500000001021611736333524023633 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** * This MemberVisitor fixes all inappropriate bridge access flags of the * program methods that it visits, checking whether the methods to which they * bridge have the same name. Some compilers, like in Eclipse and in later * versions of JDK 1.6, complain if they can't find the method with the same * name. * * @author Eric Lafortune */ public class BridgeMethodFixer extends SimplifiedVisitor implements MemberVisitor, AttributeVisitor, InstructionVisitor, ConstantVisitor { private static final boolean DEBUG = false; // Return values for the visitor methods. private String bridgedMethodName; // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if ((programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_BRIDGE) != 0) { programMethod.attributesAccept(programClass, this); } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Go over the instructions of the bridge method. codeAttribute.instructionsAccept(clazz, method, this); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { switch (constantInstruction.opcode) { case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: // Get the name of the bridged method. clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); // Check if the name is different. if (!method.getName(clazz).equals(bridgedMethodName)) { if (DEBUG) { System.out.println("BridgeMethodFixer: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] does not bridge to ["+bridgedMethodName+"]"); } // Clear the bridge flag. ((ProgramMethod)method).u2accessFlags &= ~ClassConstants.INTERNAL_ACC_BRIDGE; } break; } } // Implementations for ConstantVisitor. public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) { bridgedMethodName = refConstant.getName(clazz); } }proguard4.8/src/proguard/classfile/editor/StackSizeUpdater.java0000644000175000017500000000352511736333524023532 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor computes and updates the maximum stack size of the * code attributes that it visits. * * @author Eric Lafortune */ public class StackSizeUpdater extends SimplifiedVisitor implements AttributeVisitor { private final StackSizeComputer stackSizeComputer = new StackSizeComputer(); // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Compute the stack sizes. stackSizeComputer.visitCodeAttribute(clazz, method, codeAttribute); // Update the maximum stack size. codeAttribute.u2maxStack = stackSizeComputer.getMaxStackSize(); } } proguard4.8/src/proguard/classfile/editor/ClassElementSorter.java0000644000175000017500000000363311736333524024063 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.ProgramClass; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor sorts the various elements of the classes that it visits: * interfaces, constants, fields, methods, and attributes. * * @author Eric Lafortune */ public class ClassElementSorter extends SimplifiedVisitor implements ClassVisitor { private final ClassVisitor interfaceSorter = new InterfaceSorter(); private final ClassVisitor constantPoolSorter = new ConstantPoolSorter(); // private ClassVisitor classMemberSorter = new ClassMemberSorter(); private final ClassVisitor attributeSorter = new AttributeSorter(); // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.accept(constantPoolSorter); programClass.accept(interfaceSorter); // programClass.accept(classMemberSorter); programClass.accept(attributeSorter); } } proguard4.8/src/proguard/classfile/editor/ConstantPoolRemapper.java0000644000175000017500000005720211736333524024425 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor remaps all possible references to constant pool entries * of the classes that it visits, based on a given index map. It is assumed that * the constant pool entries themselves have already been remapped. * * @author Eric Lafortune */ public class ConstantPoolRemapper extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, MemberVisitor, AttributeVisitor, BootstrapMethodInfoVisitor, InnerClassesInfoVisitor, ExceptionInfoVisitor, InstructionVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); private int[] constantIndexMap; /** * Sets the given mapping of old constant pool entry indexes to their new * indexes. */ public void setConstantIndexMap(int[] constantIndexMap) { this.constantIndexMap = constantIndexMap; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Remap the local constant pool references. programClass.u2thisClass = remapConstantIndex(programClass.u2thisClass); programClass.u2superClass = remapConstantIndex(programClass.u2superClass); remapConstantIndexArray(programClass.u2interfaces, programClass.u2interfacesCount); // Remap the references of the contant pool entries themselves. programClass.constantPoolEntriesAccept(this); // Remap the references in all fields, methods, and attributes. programClass.fieldsAccept(this); programClass.methodsAccept(this); programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { // Nothing to do. } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { // Nothing to do. } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { // Nothing to do. } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { // Nothing to do. } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { stringConstant.u2stringIndex = remapConstantIndex(stringConstant.u2stringIndex); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { // Nothing to do. } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { invokeDynamicConstant.u2nameAndTypeIndex = remapConstantIndex(invokeDynamicConstant.u2nameAndTypeIndex); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { methodHandleConstant.u2referenceIndex = remapConstantIndex(methodHandleConstant.u2referenceIndex); } public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { fieldrefConstant.u2classIndex = remapConstantIndex(fieldrefConstant.u2classIndex); fieldrefConstant.u2nameAndTypeIndex = remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex); } public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) { interfaceMethodrefConstant.u2classIndex = remapConstantIndex(interfaceMethodrefConstant.u2classIndex); interfaceMethodrefConstant.u2nameAndTypeIndex = remapConstantIndex(interfaceMethodrefConstant.u2nameAndTypeIndex); } public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { methodrefConstant.u2classIndex = remapConstantIndex(methodrefConstant.u2classIndex); methodrefConstant.u2nameAndTypeIndex = remapConstantIndex(methodrefConstant.u2nameAndTypeIndex); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.u2nameIndex = remapConstantIndex(classConstant.u2nameIndex); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { methodTypeConstant.u2descriptorIndex = remapConstantIndex(methodTypeConstant.u2descriptorIndex); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { nameAndTypeConstant.u2nameIndex = remapConstantIndex(nameAndTypeConstant.u2nameIndex); nameAndTypeConstant.u2descriptorIndex = remapConstantIndex(nameAndTypeConstant.u2descriptorIndex); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { visitMember(programClass, programField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { visitMember(programClass, programMethod); } private void visitMember(ProgramClass programClass, ProgramMember programMember) { // Remap the local constant pool references. programMember.u2nameIndex = remapConstantIndex(programMember.u2nameIndex); programMember.u2descriptorIndex = remapConstantIndex(programMember.u2descriptorIndex); // Remap the constant pool references of the remaining attributes. programMember.attributesAccept(programClass, this); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { // Library classes are left unchanged. } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { // Library classes are left unchanged. } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { unknownAttribute.u2attributeNameIndex = remapConstantIndex(unknownAttribute.u2attributeNameIndex); // There's not much else we can do with unknown attributes. } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { bootstrapMethodsAttribute.u2attributeNameIndex = remapConstantIndex(bootstrapMethodsAttribute.u2attributeNameIndex); // Remap the constant pool references of the bootstrap method entries. bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { sourceFileAttribute.u2attributeNameIndex = remapConstantIndex(sourceFileAttribute.u2attributeNameIndex); sourceFileAttribute.u2sourceFileIndex = remapConstantIndex(sourceFileAttribute.u2sourceFileIndex); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { sourceDirAttribute.u2attributeNameIndex = remapConstantIndex(sourceDirAttribute.u2attributeNameIndex); sourceDirAttribute.u2sourceDirIndex = remapConstantIndex(sourceDirAttribute.u2sourceDirIndex); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { innerClassesAttribute.u2attributeNameIndex = remapConstantIndex(innerClassesAttribute.u2attributeNameIndex); // Remap the constant pool references of the inner classes. innerClassesAttribute.innerClassEntriesAccept(clazz, this); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { enclosingMethodAttribute.u2attributeNameIndex = remapConstantIndex(enclosingMethodAttribute.u2attributeNameIndex); enclosingMethodAttribute.u2classIndex = remapConstantIndex(enclosingMethodAttribute.u2classIndex); enclosingMethodAttribute.u2nameAndTypeIndex = remapConstantIndex(enclosingMethodAttribute.u2nameAndTypeIndex); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { deprecatedAttribute.u2attributeNameIndex = remapConstantIndex(deprecatedAttribute.u2attributeNameIndex); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { syntheticAttribute.u2attributeNameIndex = remapConstantIndex(syntheticAttribute.u2attributeNameIndex); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { signatureAttribute.u2attributeNameIndex = remapConstantIndex(signatureAttribute.u2attributeNameIndex); signatureAttribute.u2signatureIndex = remapConstantIndex(signatureAttribute.u2signatureIndex); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { constantValueAttribute.u2attributeNameIndex = remapConstantIndex(constantValueAttribute.u2attributeNameIndex); constantValueAttribute.u2constantValueIndex = remapConstantIndex(constantValueAttribute.u2constantValueIndex); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { exceptionsAttribute.u2attributeNameIndex = remapConstantIndex(exceptionsAttribute.u2attributeNameIndex); // Remap the constant pool references of the exceptions. remapConstantIndexArray(exceptionsAttribute.u2exceptionIndexTable, exceptionsAttribute.u2exceptionIndexTableLength); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { codeAttribute.u2attributeNameIndex = remapConstantIndex(codeAttribute.u2attributeNameIndex); // Initially, the code attribute editor doesn't contain any changes. codeAttributeEditor.reset(codeAttribute.u4codeLength); // Remap the constant pool references of the instructions. codeAttribute.instructionsAccept(clazz, method, this); // Apply the code atribute editor. It will only contain any changes if // the code length is changing at any point. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); // Remap the constant pool references of the exceptions and attributes. codeAttribute.exceptionsAccept(clazz, method, this); codeAttribute.attributesAccept(clazz, method, this); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { stackMapAttribute.u2attributeNameIndex = remapConstantIndex(stackMapAttribute.u2attributeNameIndex); // Remap the constant pool references of the stack map frames. stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { stackMapTableAttribute.u2attributeNameIndex = remapConstantIndex(stackMapTableAttribute.u2attributeNameIndex); // Remap the constant pool references of the stack map frames. stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { lineNumberTableAttribute.u2attributeNameIndex = remapConstantIndex(lineNumberTableAttribute.u2attributeNameIndex); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { localVariableTableAttribute.u2attributeNameIndex = remapConstantIndex(localVariableTableAttribute.u2attributeNameIndex); // Remap the constant pool references of the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { localVariableTypeTableAttribute.u2attributeNameIndex = remapConstantIndex(localVariableTypeTableAttribute.u2attributeNameIndex); // Remap the constant pool references of the local variables. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { annotationsAttribute.u2attributeNameIndex = remapConstantIndex(annotationsAttribute.u2attributeNameIndex); // Remap the constant pool references of the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { parameterAnnotationsAttribute.u2attributeNameIndex = remapConstantIndex(parameterAnnotationsAttribute.u2attributeNameIndex); // Remap the constant pool references of the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { annotationDefaultAttribute.u2attributeNameIndex = remapConstantIndex(annotationDefaultAttribute.u2attributeNameIndex); // Remap the constant pool references of the annotations. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { bootstrapMethodInfo.u2methodHandleIndex = remapConstantIndex(bootstrapMethodInfo.u2methodHandleIndex); // Remap the constant pool references of the bootstrap methods.. remapConstantIndexArray(bootstrapMethodInfo.u2methodArguments, bootstrapMethodInfo.u2methodArgumentCount); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { if (innerClassesInfo.u2innerClassIndex != 0) { innerClassesInfo.u2innerClassIndex = remapConstantIndex(innerClassesInfo.u2innerClassIndex); } if (innerClassesInfo.u2outerClassIndex != 0) { innerClassesInfo.u2outerClassIndex = remapConstantIndex(innerClassesInfo.u2outerClassIndex); } if (innerClassesInfo.u2innerNameIndex != 0) { innerClassesInfo.u2innerNameIndex = remapConstantIndex(innerClassesInfo.u2innerNameIndex); } } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { if (exceptionInfo.u2catchType != 0) { exceptionInfo.u2catchType = remapConstantIndex(exceptionInfo.u2catchType); } } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Is the new constant pool index different from the original one? int newConstantIndex = remapConstantIndex(constantInstruction.constantIndex); if (newConstantIndex != constantInstruction.constantIndex) { // Replace the instruction. Instruction replacementInstruction = new ConstantInstruction(constantInstruction.opcode, newConstantIndex, constantInstruction.constant).shrink(); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); } } // Implementations for StackMapFrameVisitor. public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {} public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { // Remap the constant pool references of the verification types. sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { // Remap the constant pool references of the verification types. moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { // Remap the constant pool references of the verification types. fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) { objectType.u2classIndex = remapConstantIndex(objectType.u2classIndex); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { localVariableInfo.u2nameIndex = remapConstantIndex(localVariableInfo.u2nameIndex); localVariableInfo.u2descriptorIndex = remapConstantIndex(localVariableInfo.u2descriptorIndex); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { localVariableTypeInfo.u2nameIndex = remapConstantIndex(localVariableTypeInfo.u2nameIndex); localVariableTypeInfo.u2signatureIndex = remapConstantIndex(localVariableTypeInfo.u2signatureIndex); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { annotation.u2typeIndex = remapConstantIndex(annotation.u2typeIndex); // Remap the constant pool references of the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { constantElementValue.u2elementNameIndex = remapConstantIndex(constantElementValue.u2elementNameIndex); constantElementValue.u2constantValueIndex = remapConstantIndex(constantElementValue.u2constantValueIndex); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { enumConstantElementValue.u2elementNameIndex = remapConstantIndex(enumConstantElementValue.u2elementNameIndex); enumConstantElementValue.u2typeNameIndex = remapConstantIndex(enumConstantElementValue.u2typeNameIndex); enumConstantElementValue.u2constantNameIndex = remapConstantIndex(enumConstantElementValue.u2constantNameIndex); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { classElementValue.u2elementNameIndex = remapConstantIndex(classElementValue.u2elementNameIndex); classElementValue.u2classInfoIndex = remapConstantIndex(classElementValue.u2classInfoIndex); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { annotationElementValue.u2elementNameIndex = remapConstantIndex(annotationElementValue.u2elementNameIndex); // Remap the constant pool references of the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { arrayElementValue.u2elementNameIndex = remapConstantIndex(arrayElementValue.u2elementNameIndex); // Remap the constant pool references of the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } // Small utility methods. /** * Remaps all constant pool indices in the given array. */ private void remapConstantIndexArray(int[] array, int length) { for (int index = 0; index < length; index++) { array[index] = remapConstantIndex(array[index]); } } /** * Returns the new constant pool index of the entry at the * given index. */ private int remapConstantIndex(int constantIndex) { return constantIndexMap[constantIndex]; } } proguard4.8/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java0000644000175000017500000000527711736333524027016 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.attribute.*; /** * This class can add local variables to a given local variable table attribute. * Local variables to be added must have been filled out beforehand. * * @author Eric Lafortune */ public class LocalVariableTableAttributeEditor { private LocalVariableTableAttribute targetLocalVariableTableAttribute; /** * Creates a new LocalVariableTableAttributeEditor that will edit line numbers * in the given line number table attribute. */ public LocalVariableTableAttributeEditor(LocalVariableTableAttribute targetLocalVariableTableAttribute) { this.targetLocalVariableTableAttribute = targetLocalVariableTableAttribute; } /** * Adds a given line number to the line number table attribute. */ public void addLocalVariableInfo(LocalVariableInfo localVariableInfo) { int localVariableTableLength = targetLocalVariableTableAttribute.u2localVariableTableLength; LocalVariableInfo[] localVariableTable = targetLocalVariableTableAttribute.localVariableTable; // Make sure there is enough space for the new localVariableInfo. if (localVariableTable.length <= localVariableTableLength) { targetLocalVariableTableAttribute.localVariableTable = new LocalVariableInfo[localVariableTableLength+1]; System.arraycopy(localVariableTable, 0, targetLocalVariableTableAttribute.localVariableTable, 0, localVariableTableLength); localVariableTable = targetLocalVariableTableAttribute.localVariableTable; } // Add the localVariableInfo. localVariableTable[targetLocalVariableTableAttribute.u2localVariableTableLength++] = localVariableInfo; } }proguard4.8/src/proguard/classfile/editor/CodeAttributeComposer.java0000664000175000017500000007544611736333524024570 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import java.util.Arrays; /** * This AttributeVisitor accumulates instructions and exceptions, and then * copies them into code attributes that it visits. * * @author Eric Lafortune */ public class CodeAttributeComposer extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LineNumberInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor { //* private static final boolean DEBUG = false; /*/ public static boolean DEBUG = false; //*/ private static final int MAXIMUM_LEVELS = 32; private static final int INVALID = -1; private boolean allowExternalExceptionHandlers; private int maximumCodeLength; private int codeLength; private int exceptionTableLength; private int level = -1; private byte[] code = new byte[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] oldInstructionOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private final int[] codeFragmentOffsets = new int[MAXIMUM_LEVELS]; private final int[] codeFragmentLengths = new int[MAXIMUM_LEVELS]; private final int[][] instructionOffsetMap = new int[MAXIMUM_LEVELS][ClassConstants.TYPICAL_CODE_LENGTH + 1]; private ExceptionInfo[] exceptionTable = new ExceptionInfo[ClassConstants.TYPICAL_EXCEPTION_TABLE_LENGTH]; private int expectedStackMapFrameOffset; private final StackSizeUpdater stackSizeUpdater = new StackSizeUpdater(); private final VariableSizeUpdater variableSizeUpdater = new VariableSizeUpdater(); // private final InstructionWriter instructionWriter = new InstructionWriter(); /** * Creates a new CodeAttributeComposer that doesn't allow external exception * handlers. */ public CodeAttributeComposer() { this(false); } /** * Creates a new CodeAttributeComposer that optionally allows external * exception handlers. */ public CodeAttributeComposer(boolean allowExternalExceptionHandlers) { this.allowExternalExceptionHandlers = allowExternalExceptionHandlers; } /** * Starts a new code definition. */ public void reset() { maximumCodeLength = 0; codeLength = 0; exceptionTableLength = 0; level = -1; } /** * Starts a new code fragment. Branch instructions that are added are * assumed to be relative within such code fragments. * @param maximumCodeFragmentLength the maximum length of the code that will * be added as part of this fragment. */ public void beginCodeFragment(int maximumCodeFragmentLength) { level++; if (level >= MAXIMUM_LEVELS) { throw new IllegalArgumentException("Maximum number of code fragment levels exceeded ["+level+"]"); } // // TODO: Figure out some length. // if (level == 0) // { // // Prepare for possible widening of instructions. // instructionWriter.reset(2 * maximumCodeFragmentLength); // } // Make sure there is sufficient space for adding the code fragment. maximumCodeLength += maximumCodeFragmentLength; ensureCodeLength(maximumCodeLength); // Try to reuse the previous array for this code fragment. if (instructionOffsetMap[level].length <= maximumCodeFragmentLength) { instructionOffsetMap[level] = new int[maximumCodeFragmentLength + 1]; } // Initialize the offset map. for (int index = 0; index <= maximumCodeFragmentLength; index++) { instructionOffsetMap[level][index] = INVALID; } // Remember the location of the code fragment. codeFragmentOffsets[level] = codeLength; codeFragmentLengths[level] = maximumCodeFragmentLength; } /** * Appends the given instruction with the given old offset. * @param oldInstructionOffset the old offset of the instruction, to which * branches and other references in the current * code fragment are pointing. * @param instruction the instruction to be appended. */ public void appendInstruction(int oldInstructionOffset, Instruction instruction) { if (DEBUG) { println("["+codeLength+"] <- ", instruction.toString(oldInstructionOffset)); } // Make sure the code array is large enough. int newCodeLength = codeLength + instruction.length(codeLength); ensureCodeLength(newCodeLength); // Remember the old offset of the appended instruction. oldInstructionOffsets[codeLength] = oldInstructionOffset; // Write the instruction. // instruction.accept(null, // null, // new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null), // codeLength, // instructionWriter); instruction.write(code, codeLength); // Fill out the new offset of the appended instruction. instructionOffsetMap[level][oldInstructionOffset] = codeLength; // Continue appending at the next instruction offset. codeLength = newCodeLength; } /** * Appends the given label with the given old offset. * @param oldInstructionOffset the old offset of the label, to which * branches and other references in the current * code fragment are pointing. */ public void appendLabel(int oldInstructionOffset) { if (DEBUG) { println("["+codeLength+"] <- ", "[" + oldInstructionOffset + "] (label)"); } // Fill out the new offset of the appended instruction. instructionOffsetMap[level][oldInstructionOffset] = codeLength; } /** * Appends the given exception to the exception table. * @param exceptionInfo the exception to be appended. */ public void appendException(ExceptionInfo exceptionInfo) { if (DEBUG) { print(" ", "Exception ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+": "+exceptionInfo.u2handlerPC+"]"); } // Remap the exception right away. visitExceptionInfo(null, null, null, exceptionInfo); if (DEBUG) { System.out.println(" -> ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+": "+exceptionInfo.u2handlerPC+"]"); } // Don't add the exception if its instruction range is empty. if (exceptionInfo.u2startPC == exceptionInfo.u2endPC) { if (DEBUG) { println(" ", " (not added because of empty instruction range)"); } return; } // Make sure there is sufficient space in the exception table. if (exceptionTable.length <= exceptionTableLength) { ExceptionInfo[] newExceptionTable = new ExceptionInfo[exceptionTableLength+1]; System.arraycopy(exceptionTable, 0, newExceptionTable, 0, exceptionTableLength); exceptionTable = newExceptionTable; } // Add the exception. exceptionTable[exceptionTableLength++] = exceptionInfo; } /** * Wraps up the current code fragment, continuing with the previous one on * the stack. */ public void endCodeFragment() { if (level < 0) { throw new IllegalArgumentException("Code fragment not begun ["+level+"]"); } // Remap the instructions of the code fragment. int instructionOffset = codeFragmentOffsets[level]; while (instructionOffset < codeLength) { // Get the next instruction. Instruction instruction = InstructionFactory.create(code, instructionOffset); // Does this instruction still have to be remapped? if (oldInstructionOffsets[instructionOffset] >= 0) { // Adapt the instruction for its new offset. instruction.accept(null, null, null, instructionOffset, this); // Write the instruction back. // instruction.accept(null, // null, // new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null), // instructionOffset, // instructionWriter); instruction.write(code, instructionOffset); // Don't remap this instruction again. oldInstructionOffsets[instructionOffset] = -1; } // Continue remapping at the next instruction offset. instructionOffset += instruction.length(instructionOffset); } // Correct the estimated maximum code length, now that we know the // actual length of this code fragment. maximumCodeLength += codeLength - codeFragmentOffsets[level] - codeFragmentLengths[level]; // Try to remap the exception handlers that couldn't be remapped before. if (allowExternalExceptionHandlers) { for (int index = 0; index < exceptionTableLength; index++) { ExceptionInfo exceptionInfo = exceptionTable[index]; // Unmapped exception handlers are still negated. int handlerPC = -exceptionInfo.u2handlerPC; if (handlerPC > 0) { if (remappableExceptionHandler(handlerPC)) { exceptionInfo.u2handlerPC = remapInstructionOffset(handlerPC); } else if (level == 0) { throw new IllegalStateException("Couldn't remap exception handler offset ["+handlerPC+"]"); } } } } level--; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (DEBUG) { System.out.println("CodeAttributeComposer: putting results in ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); } if (level != -1) { throw new IllegalArgumentException("Code fragment not ended ["+level+"]"); } level++; // Make sure the code attribute has sufficient space for the composed // code. if (codeAttribute.u4codeLength < codeLength) { codeAttribute.code = new byte[codeLength]; } // Copy the composed code over into the code attribute. codeAttribute.u4codeLength = codeLength; System.arraycopy(code, 0, codeAttribute.code, 0, codeLength); // Remove exceptions with empty code blocks (done before). //exceptionTableLength = // removeEmptyExceptions(exceptionTable, exceptionTableLength); // Make sure the exception table has sufficient space for the composed // exceptions. if (codeAttribute.exceptionTable.length < exceptionTableLength) { codeAttribute.exceptionTable = new ExceptionInfo[exceptionTableLength]; } // Copy the exception table. codeAttribute.u2exceptionTableLength = exceptionTableLength; System.arraycopy(exceptionTable, 0, codeAttribute.exceptionTable, 0, exceptionTableLength); // Update the maximum stack size and local variable frame size. stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute); variableSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute); // Remap the line number table and the local variable table. codeAttribute.attributesAccept(clazz, method, this); // Remap the exception table. //codeAttribute.exceptionsAccept(clazz, method, this); // Remove exceptions with empty code blocks (done before). //codeAttribute.u2exceptionTableLength = // removeEmptyExceptions(codeAttribute.exceptionTable, // codeAttribute.u2exceptionTableLength); // // Make sure instructions are widened if necessary. // instructionWriter.visitCodeAttribute(clazz, method, codeAttribute); level--; } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { // Remap all stack map entries. expectedStackMapFrameOffset = -1; stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { // Remap all stack map table entries. expectedStackMapFrameOffset = 0; stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { // Remap all line number table entries. lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this); // Remove line numbers with empty code blocks. lineNumberTableAttribute.u2lineNumberTableLength = removeEmptyLineNumbers(lineNumberTableAttribute.lineNumberTable, lineNumberTableAttribute.u2lineNumberTableLength, codeAttribute.u4codeLength); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Remap all local variable table entries. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); // Remove local variables with empty code blocks. localVariableTableAttribute.u2localVariableTableLength = removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable, localVariableTableAttribute.u2localVariableTableLength, codeAttribute.u2maxLocals); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Remap all local variable table entries. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); // Remove local variables with empty code blocks. localVariableTypeTableAttribute.u2localVariableTypeTableLength = removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, localVariableTypeTableAttribute.u2localVariableTypeTableLength, codeAttribute.u2maxLocals); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Adjust the branch offset. branchInstruction.branchOffset = remapBranchOffset(offset, branchInstruction.branchOffset); } public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) { // Adjust the default jump offset. switchInstruction.defaultOffset = remapBranchOffset(offset, switchInstruction.defaultOffset); // Adjust the jump offsets. remapJumpOffsets(offset, switchInstruction.jumpOffsets); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { // Remap the code offsets. Note that the instruction offset map also has // an entry for the first offset after the code, for u2endPC. exceptionInfo.u2startPC = remapInstructionOffset(exceptionInfo.u2startPC); exceptionInfo.u2endPC = remapInstructionOffset(exceptionInfo.u2endPC); // See if we can remap the handler right away. Unmapped exception // handlers are negated, in order to mark them as external. int handlerPC = exceptionInfo.u2handlerPC; exceptionInfo.u2handlerPC = !allowExternalExceptionHandlers || remappableExceptionHandler(handlerPC) ? remapInstructionOffset(handlerPC) : -handlerPC; } // Implementations for StackMapFrameVisitor. public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) { // Remap the stack map frame offset. int stackMapFrameOffset = remapInstructionOffset(offset); int offsetDelta = stackMapFrameOffset; // Compute the offset delta if the frame is part of a stack map frame // table (for JDK 6.0) instead of a stack map (for Java Micro Edition). if (expectedStackMapFrameOffset >= 0) { offsetDelta -= expectedStackMapFrameOffset; expectedStackMapFrameOffset = stackMapFrameOffset + 1; } stackMapFrame.u2offsetDelta = offsetDelta; } public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { // Remap the stack map frame offset. visitAnyStackMapFrame(clazz, method, codeAttribute, offset, sameOneFrame); // Remap the verification type offset. sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { // Remap the stack map frame offset. visitAnyStackMapFrame(clazz, method, codeAttribute, offset, moreZeroFrame); // Remap the verification type offsets. moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { // Remap the stack map frame offset. visitAnyStackMapFrame(clazz, method, codeAttribute, offset, fullFrame); // Remap the verification type offsets. fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType) { // Remap the offset of the 'new' instruction. uninitializedType.u2newInstructionOffset = remapInstructionOffset(uninitializedType.u2newInstructionOffset); } // Implementations for LineNumberInfoVisitor. public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) { // Remap the code offset. lineNumberInfo.u2startPC = remapInstructionOffset(lineNumberInfo.u2startPC); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Remap the code offset and length. // TODO: The local variable frame might not be strictly preserved. int startPC = remapInstructionOffset(localVariableInfo.u2startPC); int endPC = remapInstructionOffset(localVariableInfo.u2startPC + localVariableInfo.u2length); localVariableInfo.u2startPC = startPC; localVariableInfo.u2length = endPC - startPC; } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { // Remap the code offset and length. // TODO: The local variable frame might not be strictly preserved. int startPC = remapInstructionOffset(localVariableTypeInfo.u2startPC); int endPC = remapInstructionOffset(localVariableTypeInfo.u2startPC + localVariableTypeInfo.u2length); localVariableTypeInfo.u2startPC = startPC; localVariableTypeInfo.u2length = endPC - startPC; } // Small utility methods. /** * Make sure the code arrays have at least the given size. */ private void ensureCodeLength(int newCodeLength) { if (code.length < newCodeLength) { // Add 20% to avoid extending the arrays too often. newCodeLength = newCodeLength * 6 / 5; byte[] newCode = new byte[newCodeLength]; System.arraycopy(code, 0, newCode, 0, codeLength); code = newCode; int[] newOldInstructionOffsets = new int[newCodeLength]; System.arraycopy(oldInstructionOffsets, 0, newOldInstructionOffsets, 0, codeLength); oldInstructionOffsets = newOldInstructionOffsets; } } /** * Adjusts the given jump offsets for the instruction at the given offset. */ private void remapJumpOffsets(int offset, int[] jumpOffsets) { for (int index = 0; index < jumpOffsets.length; index++) { jumpOffsets[index] = remapBranchOffset(offset, jumpOffsets[index]); } } /** * Computes the new branch offset for the instruction at the given new offset * with the given old branch offset. */ private int remapBranchOffset(int newInstructionOffset, int branchOffset) { if (newInstructionOffset < 0 || newInstructionOffset > codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+newInstructionOffset +"] in code with length ["+codeLength+"]"); } int oldInstructionOffset = oldInstructionOffsets[newInstructionOffset]; return remapInstructionOffset(oldInstructionOffset + branchOffset) - remapInstructionOffset(oldInstructionOffset); } /** * Computes the new instruction offset for the instruction at the given old * offset. */ private int remapInstructionOffset(int oldInstructionOffset) { if (oldInstructionOffset < 0 || oldInstructionOffset > codeFragmentLengths[level]) { throw new IllegalArgumentException("Instruction offset ["+oldInstructionOffset +"] out of range in code fragment with length ["+codeFragmentLengths[level]+"] at level "+level); } int newInstructionOffset = instructionOffsetMap[level][oldInstructionOffset]; if (newInstructionOffset == INVALID) { throw new IllegalArgumentException("Invalid instruction offset ["+oldInstructionOffset +"] in code fragment at level "+level); } return newInstructionOffset; } /** * Returns whether the given old exception handler can be remapped in the * current code fragment. */ private boolean remappableExceptionHandler(int oldInstructionOffset) { if (oldInstructionOffset > codeFragmentLengths[level]) { return false; } int newInstructionOffset = instructionOffsetMap[level][oldInstructionOffset]; return newInstructionOffset > INVALID && newInstructionOffset < codeLength; } /** * Returns the given list of exceptions, without the ones that have empty * code blocks. */ private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos, int exceptionInfoCount) { // Overwrite all empty exceptions. int newIndex = 0; for (int index = 0; index < exceptionInfoCount; index++) { ExceptionInfo exceptionInfo = exceptionInfos[index]; if (exceptionInfo.u2startPC < exceptionInfo.u2endPC) { exceptionInfos[newIndex++] = exceptionInfo; } } // Clear the unused array entries. Arrays.fill(exceptionInfos, newIndex, exceptionInfoCount, null); return newIndex; } /** * Returns the given list of line numbers, without the ones that have empty * code blocks or that exceed the code size. */ private int removeEmptyLineNumbers(LineNumberInfo[] lineNumberInfos, int lineNumberInfoCount, int codeLength) { // Overwrite all empty line number entries. int newIndex = 0; for (int index = 0; index < lineNumberInfoCount; index++) { LineNumberInfo lineNumberInfo = lineNumberInfos[index]; int startPC = lineNumberInfo.u2startPC; if (startPC < codeLength && (index == 0 || startPC > lineNumberInfos[index-1].u2startPC)) { lineNumberInfos[newIndex++] = lineNumberInfo; } } // Clear the unused array entries. Arrays.fill(lineNumberInfos, newIndex, lineNumberInfoCount, null); return newIndex; } /** * Returns the given list of local variables, without the ones that have empty * code blocks or that exceed the actual number of local variables. */ private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos, int localVariableInfoCount, int maxLocals) { // Overwrite all empty local variable entries. int newIndex = 0; for (int index = 0; index < localVariableInfoCount; index++) { LocalVariableInfo localVariableInfo = localVariableInfos[index]; if (localVariableInfo.u2length > 0 && localVariableInfo.u2index < maxLocals) { localVariableInfos[newIndex++] = localVariableInfo; } } // Clear the unused array entries. Arrays.fill(localVariableInfos, newIndex, localVariableInfoCount, null); return newIndex; } /** * Returns the given list of local variable types, without the ones that * have empty code blocks or that exceed the actual number of local variables. */ private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, int localVariableTypeInfoCount, int maxLocals) { // Overwrite all empty local variable type entries. int newIndex = 0; for (int index = 0; index < localVariableTypeInfoCount; index++) { LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; if (localVariableTypeInfo.u2length > 0 && localVariableTypeInfo.u2index < maxLocals) { localVariableTypeInfos[newIndex++] = localVariableTypeInfo; } } // Clear the unused array entries. Arrays.fill(localVariableTypeInfos, newIndex, localVariableTypeInfoCount, null); return newIndex; } private void println(String string1, String string2) { print(string1, string2); System.out.println(); } private void print(String string1, String string2) { System.out.print(string1); for (int index = 0; index < level; index++) { System.out.print(" "); } System.out.print(string2); } public static void main(String[] args) { CodeAttributeComposer composer = new CodeAttributeComposer(); composer.beginCodeFragment(4); composer.appendInstruction(0, new SimpleInstruction(InstructionConstants.OP_ICONST_0)); composer.appendInstruction(1, new VariableInstruction(InstructionConstants.OP_ISTORE, 0)); composer.appendInstruction(2, new BranchInstruction(InstructionConstants.OP_GOTO, 1)); composer.beginCodeFragment(4); composer.appendInstruction(0, new VariableInstruction(InstructionConstants.OP_IINC, 0, 1)); composer.appendInstruction(1, new VariableInstruction(InstructionConstants.OP_ILOAD, 0)); composer.appendInstruction(2, new SimpleInstruction(InstructionConstants.OP_ICONST_5)); composer.appendInstruction(3, new BranchInstruction(InstructionConstants.OP_IFICMPLT, -3)); composer.endCodeFragment(); composer.appendInstruction(3, new SimpleInstruction(InstructionConstants.OP_RETURN)); composer.endCodeFragment(); } } proguard4.8/src/proguard/classfile/editor/ComparableConstant.java0000644000175000017500000002227011736333524024062 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This class is a Comparable wrapper of Constant * objects. It can store an index, in order to identify the constant pool * entry after it has been sorted. The comparison is primarily based on the * types of the constant pool entries, and secondarily on the contents of * the constant pool entries. * * @author Eric Lafortune */ class ComparableConstant extends SimplifiedVisitor implements Comparable, ConstantVisitor { private static final int[] PRIORITIES = new int[19]; static { PRIORITIES[ClassConstants.CONSTANT_Integer] = 0; // Possibly byte index (ldc). PRIORITIES[ClassConstants.CONSTANT_Float] = 1; PRIORITIES[ClassConstants.CONSTANT_String] = 2; PRIORITIES[ClassConstants.CONSTANT_Class] = 3; PRIORITIES[ClassConstants.CONSTANT_Long] = 4; // Always wide index (ldc2_w). PRIORITIES[ClassConstants.CONSTANT_Double] = 5; // Always wide index (ldc2_w). PRIORITIES[ClassConstants.CONSTANT_Fieldref] = 6; // Always wide index (getfield,...). PRIORITIES[ClassConstants.CONSTANT_Methodref] = 7; // Always wide index (invokespecial,...). PRIORITIES[ClassConstants.CONSTANT_InterfaceMethodref] = 8; // Always wide index (invokeinterface). PRIORITIES[ClassConstants.CONSTANT_InvokeDynamic] = 9; // Always wide index (invokedynamic). PRIORITIES[ClassConstants.CONSTANT_MethodHandle] = 10; PRIORITIES[ClassConstants.CONSTANT_NameAndType] = 11; PRIORITIES[ClassConstants.CONSTANT_MethodType] = 12; PRIORITIES[ClassConstants.CONSTANT_Utf8] = 13; } private final Clazz clazz; private final int thisIndex; private final Constant thisConstant; private Constant otherConstant; private int result; public ComparableConstant(Clazz clazz, int index, Constant constant) { this.clazz = clazz; this.thisIndex = index; this.thisConstant = constant; } public int getIndex() { return thisIndex; } public Constant getConstant() { return thisConstant; } // Implementations for Comparable. public int compareTo(Object other) { ComparableConstant otherComparableConstant = (ComparableConstant)other; otherConstant = otherComparableConstant.thisConstant; // Compare based on the original indices, if the actual constant pool // entries are the same. if (thisConstant == otherConstant) { int otherIndex = otherComparableConstant.thisIndex; return thisIndex < otherIndex ? -1 : thisIndex == otherIndex ? 0 : 1; } // Compare based on the tags, if they are different. int thisTag = thisConstant.getTag(); int otherTag = otherConstant.getTag(); if (thisTag != otherTag) { return PRIORITIES[thisTag] < PRIORITIES[otherTag] ? -1 : 1; } // Otherwise compare based on the contents of the Constant objects. thisConstant.accept(clazz, this); return result; } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { int value = integerConstant.getValue(); int otherValue = ((IntegerConstant)otherConstant).getValue(); result = value < otherValue ? -1 : value == otherValue ? 0 : 1; } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { long value = longConstant.getValue(); long otherValue = ((LongConstant)otherConstant).getValue(); result = value < otherValue ? -1 : value == otherValue ? 0 : 1; } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { result = Float.compare(floatConstant.getValue(), ((FloatConstant)otherConstant).getValue()); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { result = Double.compare(doubleConstant.getValue(), ((DoubleConstant)otherConstant).getValue()); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { result = stringConstant.getString(clazz).compareTo(((StringConstant)otherConstant).getString(clazz)); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { result = utf8Constant.getString().compareTo(((Utf8Constant)otherConstant).getString()); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { InvokeDynamicConstant otherInvokeDynamicConstant = (InvokeDynamicConstant)otherConstant; int index = invokeDynamicConstant.getBootstrapMethodAttributeIndex(); int otherIndex = otherInvokeDynamicConstant.getBootstrapMethodAttributeIndex(); result = index < otherIndex ? -1 : index > otherIndex ? 1 : (invokeDynamicConstant.getName(clazz) + ' ' + invokeDynamicConstant.getType(clazz)) .compareTo (otherInvokeDynamicConstant.getName(clazz) + ' ' + otherInvokeDynamicConstant.getType(clazz)); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { MethodHandleConstant otherMethodHandleConstant = (MethodHandleConstant)otherConstant; int kind = methodHandleConstant.getReferenceKind(); int otherKind = methodHandleConstant.getReferenceKind(); result = kind < otherKind ? -1 : kind > otherKind ? 1 : (methodHandleConstant.getName(clazz) + ' ' + methodHandleConstant.getType(clazz)) .compareTo (otherMethodHandleConstant.getName(clazz) + ' ' + otherMethodHandleConstant.getType(clazz)); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { RefConstant otherRefConstant = (RefConstant)otherConstant; result = (refConstant.getClassName(clazz) + ' ' + refConstant.getName(clazz) + ' ' + refConstant.getType(clazz)) .compareTo (otherRefConstant.getClassName(clazz) + ' ' + otherRefConstant.getName(clazz) + ' ' + otherRefConstant.getType(clazz)); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { result = classConstant.getName(clazz).compareTo(((ClassConstant)otherConstant).getName(clazz)); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant MethodTypeConstant) { MethodTypeConstant otherMethodTypeConstant = (MethodTypeConstant)otherConstant; result = MethodTypeConstant.getType(clazz) .compareTo (otherMethodTypeConstant.getType(clazz)); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { NameAndTypeConstant otherNameAndTypeConstant = (NameAndTypeConstant)otherConstant; result = (nameAndTypeConstant.getName(clazz) + ' ' + nameAndTypeConstant.getType(clazz)) .compareTo (otherNameAndTypeConstant.getName(clazz) + ' ' + otherNameAndTypeConstant.getType(clazz)); } // Implementations for Object. public boolean equals(Object other) { return other != null && this.getClass().equals(other.getClass()) && this.getConstant().getClass().equals(((ComparableConstant)other).getConstant().getClass()) && this.compareTo(other) == 0; } public int hashCode() { return this.getClass().hashCode(); } } proguard4.8/src/proguard/classfile/editor/ConstantPoolShrinker.java0000644000175000017500000004655311736333524024446 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; import java.util.Arrays; /** * This ClassVisitor removes all unused entries from the constant pool. * * @author Eric Lafortune */ public class ConstantPoolShrinker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor, BootstrapMethodInfoVisitor, InnerClassesInfoVisitor, ExceptionInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor, InstructionVisitor { // A visitor info flag to indicate the constant is being used. private static final Object USED = new Object(); private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Mark this class's name. markConstant(programClass, programClass.u2thisClass); // Mark the superclass class constant. programClass.superClassConstantAccept(this); // Mark the interface class constants. programClass.interfaceConstantsAccept(this); // Mark the constants referenced by the class members. programClass.fieldsAccept(this); programClass.methodsAccept(this); // Mark the attributes. programClass.attributesAccept(this); // Shift the used constant pool entries together, filling out the // index map. int newConstantPoolCount = shrinkConstantPool(programClass.constantPool, programClass.u2constantPoolCount); // Remap the references to the constant pool if it has shrunk. if (newConstantPoolCount < programClass.u2constantPoolCount) { programClass.u2constantPoolCount = newConstantPoolCount; // Remap all constant pool references. constantPoolRemapper.setConstantIndexMap(constantIndexMap); constantPoolRemapper.visitProgramClass(programClass); } } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { // Mark the name and descriptor. markConstant(programClass, programMember.u2nameIndex); markConstant(programClass, programMember.u2descriptorIndex); // Mark the attributes. programMember.attributesAccept(programClass, this); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) { markAsUsed(constant); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { markAsUsed(stringConstant); markConstant(clazz, stringConstant.u2stringIndex); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { markAsUsed(invokeDynamicConstant); markConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); // Mark the bootstrap methods attribute. clazz.attributesAccept(this); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { markAsUsed(methodHandleConstant); markConstant(clazz, methodHandleConstant.u2referenceIndex); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { markAsUsed(refConstant); markConstant(clazz, refConstant.u2classIndex); markConstant(clazz, refConstant.u2nameAndTypeIndex); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { markAsUsed(classConstant); markConstant(clazz, classConstant.u2nameIndex); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { markAsUsed(methodTypeConstant); markConstant(clazz, methodTypeConstant.u2descriptorIndex); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { markAsUsed(nameAndTypeConstant); markConstant(clazz, nameAndTypeConstant.u2nameIndex); markConstant(clazz, nameAndTypeConstant.u2descriptorIndex); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) { markConstant(clazz, attribute.u2attributeNameIndex); } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { markConstant(clazz, bootstrapMethodsAttribute.u2attributeNameIndex); // Mark the bootstrap method entries. bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { markConstant(clazz, sourceFileAttribute.u2attributeNameIndex); markConstant(clazz, sourceFileAttribute.u2sourceFileIndex); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { markConstant(clazz, sourceDirAttribute.u2attributeNameIndex); markConstant(clazz, sourceDirAttribute.u2sourceDirIndex); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { markConstant(clazz, innerClassesAttribute.u2attributeNameIndex); // Mark the outer class entries. innerClassesAttribute.innerClassEntriesAccept(clazz, this); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { markConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex); markConstant(clazz, enclosingMethodAttribute.u2classIndex); if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) { markConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex); } } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { markConstant(clazz, signatureAttribute.u2attributeNameIndex); markConstant(clazz, signatureAttribute.u2signatureIndex); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { markConstant(clazz, constantValueAttribute.u2attributeNameIndex); markConstant(clazz, constantValueAttribute.u2constantValueIndex); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { markConstant(clazz, exceptionsAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the exceptions. exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { markConstant(clazz, codeAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the instructions, // by the exceptions, and by the attributes. codeAttribute.instructionsAccept(clazz, method, this); codeAttribute.exceptionsAccept(clazz, method, this); codeAttribute.attributesAccept(clazz, method, this); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { markConstant(clazz, stackMapAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the stack map frames. stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { markConstant(clazz, stackMapTableAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the stack map frames. stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the local variable types. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { markConstant(clazz, annotationsAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { markConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex); // Mark the constant pool entries referenced by the element value. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { markConstant(clazz, bootstrapMethodInfo.u2methodHandleIndex); // Mark the constant pool entries referenced by the arguments. bootstrapMethodInfo.methodArgumentsAccept(clazz, this); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { innerClassesInfo.innerClassConstantAccept(clazz, this); innerClassesInfo.outerClassConstantAccept(clazz, this); innerClassesInfo.innerNameConstantAccept(clazz, this); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { if (exceptionInfo.u2catchType != 0) { markConstant(clazz, exceptionInfo.u2catchType); } } // Implementations for StackMapFrameVisitor. public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {} public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { // Mark the constant pool entries referenced by the verification types. sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { // Mark the constant pool entries referenced by the verification types. moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { // Mark the constant pool entries referenced by the verification types. fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) { markConstant(clazz, objectType.u2classIndex); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { markConstant(clazz, localVariableInfo.u2nameIndex); markConstant(clazz, localVariableInfo.u2descriptorIndex); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { markConstant(clazz, localVariableTypeInfo.u2nameIndex); markConstant(clazz, localVariableTypeInfo.u2signatureIndex); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { markConstant(clazz, annotation.u2typeIndex); // Mark the constant pool entries referenced by the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { if (constantElementValue.u2elementNameIndex != 0) { markConstant(clazz, constantElementValue.u2elementNameIndex); } markConstant(clazz, constantElementValue.u2constantValueIndex); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { if (enumConstantElementValue.u2elementNameIndex != 0) { markConstant(clazz, enumConstantElementValue.u2elementNameIndex); } markConstant(clazz, enumConstantElementValue.u2typeNameIndex); markConstant(clazz, enumConstantElementValue.u2constantNameIndex); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { if (classElementValue.u2elementNameIndex != 0) { markConstant(clazz, classElementValue.u2elementNameIndex); } markConstant(clazz, classElementValue.u2classInfoIndex); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { if (annotationElementValue.u2elementNameIndex != 0) { markConstant(clazz, annotationElementValue.u2elementNameIndex); } // Mark the constant pool entries referenced by the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { if (arrayElementValue.u2elementNameIndex != 0) { markConstant(clazz, arrayElementValue.u2elementNameIndex); } // Mark the constant pool entries referenced by the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { markConstant(clazz, constantInstruction.constantIndex); } // Small utility methods. /** * Marks the given constant pool entry of the given class. This includes * visiting any referenced objects. */ private void markConstant(Clazz clazz, int index) { clazz.constantPoolEntryAccept(index, this); } /** * Marks the given visitor accepter as being used. */ private void markAsUsed(Constant constant) { constant.setVisitorInfo(USED); } /** * Returns whether the given visitor accepter has been marked as being used. */ private boolean isUsed(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() == USED; } /** * Removes all constants that are not marked as being used from the given * constant pool. * @return the new number of entries. */ private int shrinkConstantPool(Constant[] constantPool, int length) { // Create a new index map, if necessary. if (constantIndexMap.length < length) { constantIndexMap = new int[length]; } int counter = 1; boolean isUsed = false; // Shift the used constant pool entries together. for (int index = 1; index < length; index++) { constantIndexMap[index] = counter; Constant constant = constantPool[index]; // Don't update the flag if this is the second half of a long entry. if (constant != null) { isUsed = isUsed(constant); } if (isUsed) { constantPool[counter++] = constant; } } // Clear the remaining constant pool elements. Arrays.fill(constantPool, counter, length, null); return counter; } } proguard4.8/src/proguard/classfile/LibraryMember.java0000644000175000017500000000527411736333524021556 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.visitor.MemberVisitor; /** * Representation of a field or method from a library class. * * @author Eric Lafortune */ public abstract class LibraryMember implements Member { private static final int ACC_VISIBLE = ClassConstants.INTERNAL_ACC_PUBLIC | ClassConstants.INTERNAL_ACC_PROTECTED; public int u2accessFlags; public String name; public String descriptor; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Creates an uninitialized LibraryMember. */ protected LibraryMember() { } /** * Creates an initialized LibraryMember. */ protected LibraryMember(int u2accessFlags, String name, String descriptor) { this.u2accessFlags = u2accessFlags; this.name = name; this.descriptor = descriptor; } /** * Accepts the given member info visitor. */ public abstract void accept(LibraryClass libraryClass, MemberVisitor memberVisitor); // Implementations for Member. public int getAccessFlags() { return u2accessFlags; } public String getName(Clazz clazz) { return name; } public String getDescriptor(Clazz clazz) { return descriptor; } public void accept(Clazz clazz, MemberVisitor memberVisitor) { accept((LibraryClass)clazz, memberVisitor); } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } proguard4.8/src/proguard/classfile/util/0000775000175000017500000000000011760503005017114 5ustar ericericproguard4.8/src/proguard/classfile/util/package.html0000644000175000017500000000012111736333524021377 0ustar ericeric This package contains utility classes for processing class files. proguard4.8/src/proguard/classfile/util/MemberFinder.java0000644000175000017500000001347311736333524022336 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.visitor.*; /** * This class provides methods to find class members in a given class or in its * hierarchy. * * @author Eric Lafortune */ public class MemberFinder extends SimplifiedVisitor implements MemberVisitor { private static class MemberFoundException extends RuntimeException {} private static final MemberFoundException MEMBER_FOUND = new MemberFoundException(); private Clazz clazz; private Member member; /** * Finds the field with the given name and descriptor in the given * class or its hierarchy. */ public Field findField(Clazz referencingClass, Clazz clazz, String name, String descriptor) { return (Field)findMember(referencingClass, clazz, name, descriptor, true); } /** * Finds the method with the given name and descriptor in the given * class or its hierarchy. */ public Method findMethod(Clazz referencingClass, Clazz clazz, String name, String descriptor) { return (Method)findMember(referencingClass, clazz, name, descriptor, false); } /** * Finds the class member with the given name and descriptor in the given * class or its hierarchy. */ public Member findMember(Clazz referencingClass, Clazz clazz, String name, String descriptor, boolean isField) { // Organize a search in the hierarchy of superclasses and interfaces. // The class member may be in a different class, if the code was // compiled with "-target 1.2" or higher (the default in JDK 1.4). try { this.clazz = null; this.member = null; clazz.hierarchyAccept(true, true, true, false, isField ? (ClassVisitor)new NamedFieldVisitor(name, descriptor, new MemberClassAccessFilter(referencingClass, this)) : (ClassVisitor)new NamedMethodVisitor(name, descriptor, new MemberClassAccessFilter(referencingClass, this))); } catch (MemberFoundException ex) { // We've found the member we were looking for. } return member; } /** * Returns the corresponding class of the most recently found class * member. */ public Clazz correspondingClass() { return clazz; } /** * Returns whether the given method is overridden anywhere down the class * hierarchy. */ public boolean isOverriden(Clazz clazz, Method method) { String name = method.getName(clazz); String descriptor = method.getDescriptor(clazz); // Go looking for the method down the class hierarchy. try { this.clazz = null; this.member = null; clazz.hierarchyAccept(false, false, false, true, new NamedMethodVisitor(name, descriptor, new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this))); } catch (MemberFoundException ex) { // We've found an overriding method. return true; } return false; } /** * Returns whether the given field is shadowed anywhere down the class * hierarchy. */ public boolean isShadowed(Clazz clazz, Field field) { String name = field.getName(clazz); String descriptor = field.getDescriptor(clazz); // Go looking for the field down the class hierarchy. try { this.clazz = null; this.member = null; clazz.hierarchyAccept(false, false, false, true, new NamedFieldVisitor(name, descriptor, new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this))); } catch (MemberFoundException ex) { // We've found a shadowing field. return true; } return false; } // // Implementations for ClassVisitor. // // private void visitAnyClass(Clazz clazz) // { // if (member == null) // { // member = isField ? // (Member)clazz.findField(name, descriptor) : // (Member)clazz.findMethod(name, descriptor); // // if (member != null) // { // this.clazz = clazz; // } // } // } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) { this.clazz = clazz; this.member = member; throw MEMBER_FOUND; } } proguard4.8/src/proguard/classfile/util/InstructionSequenceMatcher.java0000644000175000017500000006345011736333524025315 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import java.util.Arrays; /** * This InstructionVisitor checks whether a given pattern instruction sequence * occurs in the instructions that are visited. The arguments of the * instruction sequence can be wildcards that are matched. * * @author Eric Lafortune */ public class InstructionSequenceMatcher extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor { /* public static boolean DEBUG = true; public static boolean DEBUG_MORE = true; /*/ private static final boolean DEBUG = false; private static final boolean DEBUG_MORE = false; //*/ public static final int X = 0x40000000; public static final int Y = 0x40000001; public static final int Z = 0x40000002; public static final int A = 0x40000003; public static final int B = 0x40000004; public static final int C = 0x40000005; public static final int D = 0x40000006; private final Constant[] patternConstants; private final Instruction[] patternInstructions; private boolean matching; private int patternInstructionIndex; private final int[] matchedInstructionOffsets; private int matchedArgumentFlags; private final int[] matchedArguments = new int[7]; private final long[] matchedConstantFlags; private final int[] matchedConstantIndices; private int constantFlags; private int previousConstantFlags; // Fields acting as a parameter and a return value for visitor methods. private Constant patternConstant; private boolean matchingConstant; /** * Creates a new InstructionSequenceMatcher. * @param patternConstants any constants referenced by the pattern * instruction. * @param patternInstructions the pattern instruction sequence. */ public InstructionSequenceMatcher(Constant[] patternConstants, Instruction[] patternInstructions) { this.patternConstants = patternConstants; this.patternInstructions = patternInstructions; matchedInstructionOffsets = new int[patternInstructions.length]; matchedConstantFlags = new long[(patternConstants.length + 63) / 64]; matchedConstantIndices = new int[patternConstants.length]; } /** * Starts matching from the first instruction again next time. */ public void reset() { patternInstructionIndex = 0; matchedArgumentFlags = 0; Arrays.fill(matchedConstantFlags, 0L); previousConstantFlags = constantFlags; constantFlags = 0; } /** * Returns whether the complete pattern sequence has been matched. */ public boolean isMatching() { return matching; } /** * Returns the number of instructions in the pattern sequence. */ public int instructionCount() { return patternInstructions.length; } /** * Returns the matched instruction offset of the specified pattern * instruction. */ public int matchedInstructionOffset(int index) { return matchedInstructionOffsets[index]; } /** * Returns whether the specified wildcard argument was a constant from * the constant pool in the most recent match. */ public boolean wasConstant(int argument) { return (previousConstantFlags & (1 << (argument - X))) != 0; } /** * Returns the value of the specified matched argument (wildcard or not). */ public int matchedArgument(int argument) { int argumentIndex = argument - X; return argumentIndex < 0 ? argument : matchedArguments[argumentIndex]; } /** * Returns the values of the specified matched arguments (wildcard or not). */ public int[] matchedArguments(int[] arguments) { int[] matchedArguments = new int[arguments.length]; for (int index = 0; index < arguments.length; index++) { matchedArguments[index] = matchedArgument(arguments[index]); } return matchedArguments; } /** * Returns the index of the specified matched constant (wildcard or not). */ public int matchedConstantIndex(int constantIndex) { int argumentIndex = constantIndex - X; return argumentIndex < 0 ? matchedConstantIndices[constantIndex] : matchedArguments[argumentIndex]; } /** * Returns the value of the specified matched branch offset (wildcard or * not). */ public int matchedBranchOffset(int offset, int branchOffset) { int argumentIndex = branchOffset - X; return argumentIndex < 0 ? branchOffset : matchedArguments[argumentIndex] - offset; } /** * Returns the values of the specified matched jump offsets (wildcard or * not). */ public int[] matchedJumpOffsets(int offset, int[] jumpOffsets) { int[] matchedJumpOffsets = new int[jumpOffsets.length]; for (int index = 0; index < jumpOffsets.length; index++) { matchedJumpOffsets[index] = matchedBranchOffset(offset, jumpOffsets[index]); } return matchedJumpOffsets; } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { Instruction patternInstruction = patternInstructions[patternInstructionIndex]; // Check if the instruction matches the next instruction in the sequence. boolean condition = matchingOpcodes(simpleInstruction, patternInstruction) && matchingArguments(simpleInstruction.constant, ((SimpleInstruction)patternInstruction).constant); // Check if the instruction sequence is matching now. checkMatch(condition, clazz, method, codeAttribute, offset, simpleInstruction); } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { Instruction patternInstruction = patternInstructions[patternInstructionIndex]; // Check if the instruction matches the next instruction in the sequence. boolean condition = matchingOpcodes(variableInstruction, patternInstruction) && matchingArguments(variableInstruction.variableIndex, ((VariableInstruction)patternInstruction).variableIndex) && matchingArguments(variableInstruction.constant, ((VariableInstruction)patternInstruction).constant); // Check if the instruction sequence is matching now. checkMatch(condition, clazz, method, codeAttribute, offset, variableInstruction); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { Instruction patternInstruction = patternInstructions[patternInstructionIndex]; // Check if the instruction matches the next instruction in the sequence. boolean condition = matchingOpcodes(constantInstruction, patternInstruction) && matchingConstantIndices(clazz, constantInstruction.constantIndex, ((ConstantInstruction)patternInstruction).constantIndex) && matchingArguments(constantInstruction.constant, ((ConstantInstruction)patternInstruction).constant); // Check if the instruction sequence is matching now. checkMatch(condition, clazz, method, codeAttribute, offset, constantInstruction); } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { Instruction patternInstruction = patternInstructions[patternInstructionIndex]; // Check if the instruction matches the next instruction in the from // sequence. boolean condition = matchingOpcodes(branchInstruction, patternInstruction) && matchingBranchOffsets(offset, branchInstruction.branchOffset, ((BranchInstruction)patternInstruction).branchOffset); // Check if the instruction sequence is matching now. checkMatch(condition, clazz, method, codeAttribute, offset, branchInstruction); } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { Instruction patternInstruction = patternInstructions[patternInstructionIndex]; // Check if the instruction matches the next instruction in the sequence. boolean condition = matchingOpcodes(tableSwitchInstruction, patternInstruction) && matchingBranchOffsets(offset, tableSwitchInstruction.defaultOffset, ((TableSwitchInstruction)patternInstruction).defaultOffset) && matchingArguments(tableSwitchInstruction.lowCase, ((TableSwitchInstruction)patternInstruction).lowCase) && matchingArguments(tableSwitchInstruction.highCase, ((TableSwitchInstruction)patternInstruction).highCase) && matchingJumpOffsets(offset, tableSwitchInstruction.jumpOffsets, ((TableSwitchInstruction)patternInstruction).jumpOffsets); // Check if the instruction sequence is matching now. checkMatch(condition, clazz, method, codeAttribute, offset, tableSwitchInstruction); } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { Instruction patternInstruction = patternInstructions[patternInstructionIndex]; // Check if the instruction matches the next instruction in the sequence. boolean condition = matchingOpcodes(lookUpSwitchInstruction, patternInstruction) && matchingBranchOffsets(offset, lookUpSwitchInstruction.defaultOffset, ((LookUpSwitchInstruction)patternInstruction).defaultOffset) && matchingArguments(lookUpSwitchInstruction.cases, ((LookUpSwitchInstruction)patternInstruction).cases) && matchingJumpOffsets(offset, lookUpSwitchInstruction.jumpOffsets, ((LookUpSwitchInstruction)patternInstruction).jumpOffsets); // Check if the instruction sequence is matching now. checkMatch(condition, clazz, method, codeAttribute, offset, lookUpSwitchInstruction); } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { IntegerConstant integerPatternConstant = (IntegerConstant)patternConstant; // Compare the integer values. matchingConstant = integerConstant.getValue() == integerPatternConstant.getValue(); } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { LongConstant longPatternConstant = (LongConstant)patternConstant; // Compare the long values. matchingConstant = longConstant.getValue() == longPatternConstant.getValue(); } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { FloatConstant floatPatternConstant = (FloatConstant)patternConstant; // Compare the float values. matchingConstant = floatConstant.getValue() == floatPatternConstant.getValue(); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { DoubleConstant doublePatternConstant = (DoubleConstant)patternConstant; // Compare the double values. matchingConstant = doubleConstant.getValue() == doublePatternConstant.getValue(); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { StringConstant stringPatternConstant = (StringConstant)patternConstant; // Check the UTF-8 constant. matchingConstant = matchingConstantIndices(clazz, stringConstant.u2stringIndex, stringPatternConstant.u2stringIndex); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { Utf8Constant utf8PatternConstant = (Utf8Constant)patternConstant; // Compare the actual strings. matchingConstant = utf8Constant.getString().equals( utf8PatternConstant.getString()); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { InvokeDynamicConstant invokeDynamicPatternConstant = (InvokeDynamicConstant)patternConstant; // Check the bootstrap method and the name and type. matchingConstant = matchingConstantIndices(clazz, invokeDynamicConstant.getBootstrapMethodAttributeIndex(), invokeDynamicPatternConstant.getBootstrapMethodAttributeIndex()) && matchingConstantIndices(clazz, invokeDynamicConstant.getNameAndTypeIndex(), invokeDynamicPatternConstant.getNameAndTypeIndex()); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { MethodHandleConstant methodHandlePatternConstant = (MethodHandleConstant)patternConstant; // Check the handle type and the name and type. matchingConstant = matchingArguments(methodHandleConstant.getReferenceKind(), methodHandlePatternConstant.getReferenceKind()) && matchingConstantIndices(clazz, methodHandleConstant.getReferenceIndex(), methodHandlePatternConstant.getReferenceIndex()); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { RefConstant refPatternConstant = (RefConstant)patternConstant; // Check the class and the name and type. matchingConstant = matchingConstantIndices(clazz, refConstant.getClassIndex(), refPatternConstant.getClassIndex()) && matchingConstantIndices(clazz, refConstant.getNameAndTypeIndex(), refPatternConstant.getNameAndTypeIndex()); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { ClassConstant classPatternConstant = (ClassConstant)patternConstant; // Check the class name. matchingConstant = matchingConstantIndices(clazz, classConstant.u2nameIndex, classPatternConstant.u2nameIndex); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { MethodTypeConstant typePatternConstant = (MethodTypeConstant)patternConstant; // Check the descriptor. matchingConstant = matchingConstantIndices(clazz, methodTypeConstant.u2descriptorIndex, typePatternConstant.u2descriptorIndex); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { NameAndTypeConstant typePatternConstant = (NameAndTypeConstant)patternConstant; // Check the name and the descriptor. matchingConstant = matchingConstantIndices(clazz, nameAndTypeConstant.u2nameIndex, typePatternConstant.u2nameIndex) && matchingConstantIndices(clazz, nameAndTypeConstant.u2descriptorIndex, typePatternConstant.u2descriptorIndex); } // Small utility methods. private boolean matchingOpcodes(Instruction instruction1, Instruction instruction2) { // Check the opcode. return instruction1.opcode == instruction2.opcode || instruction1.canonicalOpcode() == instruction2.opcode; } private boolean matchingArguments(int argument1, int argument2) { int argumentIndex = argument2 - X; if (argumentIndex < 0) { // Check the literal argument. return argument1 == argument2; } else if (!isMatchingArgumentIndex(argumentIndex)) { // Store the wildcard argument. setMatchingArgument(argumentIndex, argument1); return true; } else { // Check the previously stored wildcard argument. return matchedArguments[argumentIndex] == argument1; } } /** * Marks the specified argument (by index) as matching the specified * argument value. */ private void setMatchingArgument(int argumentIndex, int argument) { matchedArguments[argumentIndex] = argument; matchedArgumentFlags |= 1 << argumentIndex; } /** * Returns whether the specified wildcard argument (by index) has been * matched. */ private boolean isMatchingArgumentIndex(int argumentIndex) { return (matchedArgumentFlags & (1 << argumentIndex)) != 0; } private boolean matchingArguments(int[] arguments1, int[] arguments2) { if (arguments1.length != arguments2.length) { return false; } for (int index = 0; index < arguments1.length; index++) { if (!matchingArguments(arguments1[index], arguments2[index])) { return false; } } return true; } private boolean matchingConstantIndices(Clazz clazz, int constantIndex1, int constantIndex2) { if (constantIndex2 >= X) { // Remember that we are trying to match a constant. constantFlags |= 1 << (constantIndex2 - X); // Check the constant index. return matchingArguments(constantIndex1, constantIndex2); } else if (!isMatchingConstantIndex(constantIndex2)) { // Check the actual constant. matchingConstant = false; patternConstant = patternConstants[constantIndex2]; if (clazz.getTag(constantIndex1) == patternConstant.getTag()) { clazz.constantPoolEntryAccept(constantIndex1, this); if (matchingConstant) { // Store the constant index. setMatchingConstant(constantIndex2, constantIndex1); } } return matchingConstant; } else { // Check a previously stored constant index. return matchedConstantIndices[constantIndex2] == constantIndex1; } } /** * Marks the specified constant (by index) as matching the specified * constant index value. */ private void setMatchingConstant(int constantIndex, int constantIndex1) { matchedConstantIndices[constantIndex] = constantIndex1; matchedConstantFlags[constantIndex / 64] |= 1L << constantIndex; } /** * Returns whether the specified wildcard constant has been matched. */ private boolean isMatchingConstantIndex(int constantIndex) { return (matchedConstantFlags[constantIndex / 64] & (1L << constantIndex)) != 0; } private boolean matchingBranchOffsets(int offset, int branchOffset1, int branchOffset2) { int argumentIndex = branchOffset2 - X; if (argumentIndex < 0) { // Check the literal argument. return branchOffset1 == branchOffset2; } else if (!isMatchingArgumentIndex(argumentIndex)) { // Store a wildcard argument. setMatchingArgument(argumentIndex, offset + branchOffset1); return true; } else { // Check the previously stored wildcard argument. return matchedArguments[argumentIndex] == offset + branchOffset1; } } private boolean matchingJumpOffsets(int offset, int[] jumpOffsets1, int[] jumpOffsets2) { if (jumpOffsets1.length != jumpOffsets2.length) { return false; } for (int index = 0; index < jumpOffsets1.length; index++) { if (!matchingBranchOffsets(offset, jumpOffsets1[index], jumpOffsets2[index])) { return false; } } return true; } private void checkMatch(boolean condition, Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { if (DEBUG_MORE) { System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+patternInstructions[patternInstructionIndex].toString(patternInstructionIndex)+(condition?"\t== ":"\t ")+instruction.toString(offset)); } // Did the instruction match? if (condition) { // Remember the offset of the matching instruction. matchedInstructionOffsets[patternInstructionIndex] = offset; // Try to match the next instruction next time. patternInstructionIndex++; // Did we match all instructions in the sequence? matching = patternInstructionIndex == patternInstructions.length; if (matching) { if (DEBUG) { System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); for (int index = 0; index < patternInstructionIndex; index++) { System.out.println(" "+InstructionFactory.create(codeAttribute.code, matchedInstructionOffsets[index]).toString(matchedInstructionOffsets[index])); } } // Start matching from the first instruction again next time. reset(); } } else { // The instruction didn't match. matching = false; // Is this a failed second instruction? boolean retry = patternInstructionIndex == 1; // Start matching from the first instruction next time. reset(); // Retry a failed second instruction as a first instruction. if (retry) { instruction.accept(clazz, method, codeAttribute, offset, this); } } } } proguard4.8/src/proguard/classfile/util/AccessUtil.java0000644000175000017500000000753711736333524022042 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.ClassConstants; /** * Utility methods for working with access flags. For convenience, this class * defines access levels, in ascending order: PRIVATE, * PACKAGE_VISIBLE, PROTECTED, and PUBLIC. * * @author Eric Lafortune */ public class AccessUtil { public static final int PRIVATE = 0; public static final int PACKAGE_VISIBLE = 1; public static final int PROTECTED = 2; public static final int PUBLIC = 3; // The mask of access flags. private static final int ACCESS_MASK = ClassConstants.INTERNAL_ACC_PUBLIC | ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_PROTECTED; /** * Returns the corresponding access level of the given access flags. * @param accessFlags the internal access flags. * @return the corresponding access level: PRIVATE, * PACKAGE_VISIBLE, PROTECTED, or * PUBLIC. */ public static int accessLevel(int accessFlags) { switch (accessFlags & ACCESS_MASK) { case ClassConstants.INTERNAL_ACC_PRIVATE: return PRIVATE; default: return PACKAGE_VISIBLE; case ClassConstants.INTERNAL_ACC_PROTECTED: return PROTECTED; case ClassConstants.INTERNAL_ACC_PUBLIC: return PUBLIC; } } /** * Returns the corresponding access flags of the given access level. * @param accessLevel the access level: PRIVATE, * PACKAGE_VISIBLE, PROTECTED, * or PUBLIC. * @return the corresponding internal access flags, the internal access * flags as a logical bit mask of INTERNAL_ACC_PRIVATE, * INTERNAL_ACC_PROTECTED, and * INTERNAL_ACC_PUBLIC. */ public static int accessFlags(int accessLevel) { switch (accessLevel) { case PRIVATE: return ClassConstants.INTERNAL_ACC_PRIVATE; default: return 0; case PROTECTED: return ClassConstants.INTERNAL_ACC_PROTECTED; case PUBLIC: return ClassConstants.INTERNAL_ACC_PUBLIC; } } /** * Replaces the access part of the given access flags. * @param accessFlags the internal access flags. * @param accessFlags the new internal access flags. */ public static int replaceAccessFlags(int accessFlags, int newAccessFlags) { // A private class member should not be explicitly final. if (newAccessFlags == ClassConstants.INTERNAL_ACC_PRIVATE) { accessFlags &= ~ClassConstants.INTERNAL_ACC_FINAL; } return (accessFlags & ~ACCESS_MASK) | (newAccessFlags & ACCESS_MASK); } } proguard4.8/src/proguard/classfile/util/ClassReferenceInitializer.java0000644000175000017500000005153511736333524025070 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor initializes the references of all classes that * it visits. *

* All class constant pool entries get direct references to the corresponding * classes. These references make it more convenient to travel up and across * the class hierarchy. *

* All field and method reference constant pool entries get direct references * to the corresponding classes, fields, and methods. *

* All name and type constant pool entries get a list of direct references to * the classes listed in the type. *

* This visitor optionally prints warnings if some items can't be found. *

* The class hierarchy must be initialized before using this visitor. * * @author Eric Lafortune */ public class ClassReferenceInitializer extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { private final ClassPool programClassPool; private final ClassPool libraryClassPool; private final WarningPrinter missingClassWarningPrinter; private final WarningPrinter missingMemberWarningPrinter; private final WarningPrinter dependencyWarningPrinter; private final MemberFinder memberFinder = new MemberFinder(); /** * Creates a new ClassReferenceInitializer that initializes the references * of all visited class files, optionally printing warnings if some classes * or class members can't be found or if they are in the program class pool. */ public ClassReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter missingClassWarningPrinter, WarningPrinter missingMemberWarningPrinter, WarningPrinter dependencyWarningPrinter) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; this.missingClassWarningPrinter = missingClassWarningPrinter; this.missingMemberWarningPrinter = missingMemberWarningPrinter; this.dependencyWarningPrinter = dependencyWarningPrinter; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Initialize the constant pool entries. programClass.constantPoolEntriesAccept(this); // Initialize all fields and methods. programClass.fieldsAccept(this); programClass.methodsAccept(this); // Initialize the attributes. programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { // Initialize all fields and methods. libraryClass.fieldsAccept(this); libraryClass.methodsAccept(this); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { programField.referencedClass = findReferencedClass(programClass.getName(), programField.getDescriptor(programClass)); // Initialize the attributes. programField.attributesAccept(programClass, this); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { programMethod.referencedClasses = findReferencedClasses(programClass.getName(), programMethod.getDescriptor(programClass)); // Initialize the attributes. programMethod.attributesAccept(programClass, this); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { libraryField.referencedClass = findReferencedClass(libraryClass.getName(), libraryField.getDescriptor(libraryClass)); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { libraryMethod.referencedClasses = findReferencedClasses(libraryClass.getName(), libraryMethod.getDescriptor(libraryClass)); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Fill out the String class. stringConstant.javaLangStringClass = findClass(clazz.getName(), ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { // Fill out the MethodHandle class. methodHandleConstant.javaLangInvokeMethodHandleClass = findClass(clazz.getName(), ClassConstants.INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_HANDLE); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { String className = refConstant.getClassName(clazz); // Methods for array types should be found in the Object class. if (ClassUtil.isInternalArrayType(className)) { className = ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT; } // See if we can find the referenced class. // Unresolved references are assumed to refer to library classes // that will not change anyway. Clazz referencedClass = findClass(clazz.getName(), className); if (referencedClass != null) { String name = refConstant.getName(clazz); String type = refConstant.getType(clazz); boolean isFieldRef = refConstant.getTag() == ClassConstants.CONSTANT_Fieldref; // See if we can find the referenced class member somewhere in the // hierarchy. refConstant.referencedMember = memberFinder.findMember(clazz, referencedClass, name, type, isFieldRef); refConstant.referencedClass = memberFinder.correspondingClass(); if (refConstant.referencedMember == null) { // We haven't found the class member anywhere in the hierarchy. missingMemberWarningPrinter.print(clazz.getName(), className, "Warning: " + ClassUtil.externalClassName(clazz.getName()) + ": can't find referenced " + (isFieldRef ? "field '" + ClassUtil.externalFullFieldDescription(0, name, type) : "method '" + ClassUtil.externalFullMethodDescription(className, 0, name, type)) + "' in class " + ClassUtil.externalClassName(className)); } } } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { String className = clazz.getName(); // Fill out the referenced class. classConstant.referencedClass = findClass(className, ClassUtil.internalClassNameFromClassType(classConstant.getName(clazz))); // Fill out the Class class. classConstant.javaLangClassClass = findClass(className, ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { // Fill out the MethodType class. methodTypeConstant.javaLangInvokeMethodTypeClass = findClass(clazz.getName(), ClassConstants.INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_TYPE); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { String className = clazz.getName(); String enclosingClassName = enclosingMethodAttribute.getClassName(clazz); // See if we can find the referenced class. enclosingMethodAttribute.referencedClass = findClass(className, enclosingClassName); if (enclosingMethodAttribute.referencedClass != null) { // Is there an enclosing method? Otherwise it's just initialization // code outside of the constructors. if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) { String name = enclosingMethodAttribute.getName(clazz); String type = enclosingMethodAttribute.getType(clazz); // See if we can find the method in the referenced class. enclosingMethodAttribute.referencedMethod = enclosingMethodAttribute.referencedClass.findMethod(name, type); if (enclosingMethodAttribute.referencedMethod == null) { // We couldn't find the enclosing method. missingMemberWarningPrinter.print(className, enclosingClassName, "Warning: " + ClassUtil.externalClassName(className) + ": can't find enclosing method '" + ClassUtil.externalFullMethodDescription(enclosingClassName, 0, name, type) + "' in class " + ClassUtil.externalClassName(enclosingClassName)); } } } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Initialize the nested attributes. codeAttribute.attributesAccept(clazz, method, this); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Initialize the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Initialize the local variable types. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { signatureAttribute.referencedClasses = findReferencedClasses(clazz.getName(), clazz.getString(signatureAttribute.u2signatureIndex)); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Initialize the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Initialize the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Initialize the annotation. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { localVariableInfo.referencedClass = findReferencedClass(clazz.getName(), clazz.getString(localVariableInfo.u2descriptorIndex)); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { localVariableTypeInfo.referencedClasses = findReferencedClasses(clazz.getName(), clazz.getString(localVariableTypeInfo.u2signatureIndex)); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { annotation.referencedClasses = findReferencedClasses(clazz.getName(), clazz.getString(annotation.u2typeIndex)); // Initialize the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { initializeElementValue(clazz, annotation, constantElementValue); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { initializeElementValue(clazz, annotation, enumConstantElementValue); enumConstantElementValue.referencedClasses = findReferencedClasses(clazz.getName(), clazz.getString(enumConstantElementValue.u2typeNameIndex)); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { initializeElementValue(clazz, annotation, classElementValue); classElementValue.referencedClasses = findReferencedClasses(clazz.getName(), clazz.getString(classElementValue.u2classInfoIndex)); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { initializeElementValue(clazz, annotation, annotationElementValue); // Initialize the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { initializeElementValue(clazz, annotation, arrayElementValue); // Initialize the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } /** * Initializes the referenced method of an element value, if any. */ private void initializeElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) { // See if we have a referenced class. if (annotation != null && annotation.referencedClasses != null && elementValue.u2elementNameIndex != 0) { // See if we can find the method in the referenced class // (ignoring the descriptor). String name = clazz.getString(elementValue.u2elementNameIndex); Clazz referencedClass = annotation.referencedClasses[0]; elementValue.referencedClass = referencedClass; elementValue.referencedMethod = referencedClass.findMethod(name, null); } } // Small utility methods. /** * Returns the single class referenced by the given descriptor, or * null if there isn't any useful reference. */ private Clazz findReferencedClass(String referencingClassName, String descriptor) { DescriptorClassEnumeration enumeration = new DescriptorClassEnumeration(descriptor); enumeration.nextFluff(); if (enumeration.hasMoreClassNames()) { return findClass(referencingClassName, enumeration.nextClassName()); } return null; } /** * Returns an array of classes referenced by the given descriptor, or * null if there aren't any useful references. */ private Clazz[] findReferencedClasses(String referencingClassName, String descriptor) { DescriptorClassEnumeration enumeration = new DescriptorClassEnumeration(descriptor); int classCount = enumeration.classCount(); if (classCount > 0) { Clazz[] referencedClasses = new Clazz[classCount]; boolean foundReferencedClasses = false; for (int index = 0; index < classCount; index++) { String fluff = enumeration.nextFluff(); String name = enumeration.nextClassName(); Clazz referencedClass = findClass(referencingClassName, name); if (referencedClass != null) { referencedClasses[index] = referencedClass; foundReferencedClasses = true; } } if (foundReferencedClasses) { return referencedClasses; } } return null; } /** * Returns the class with the given name, either for the program class pool * or from the library class pool, or null if it can't be found. */ private Clazz findClass(String referencingClassName, String name) { // Is it an array type? if (ClassUtil.isInternalArrayType(name)) { // Ignore any primitive array types. if (!ClassUtil.isInternalClassType(name)) { return null; } // Strip the array part. name = ClassUtil.internalClassNameFromClassType(name); } // First look for the class in the program class pool. Clazz clazz = programClassPool.getClass(name); // Otherwise look for the class in the library class pool. if (clazz == null) { clazz = libraryClassPool.getClass(name); if (clazz == null && missingClassWarningPrinter != null) { // We didn't find the superclass or interface. Print a warning. missingClassWarningPrinter.print(referencingClassName, name, "Warning: " + ClassUtil.externalClassName(referencingClassName) + ": can't find referenced class " + ClassUtil.externalClassName(name)); } } else if (dependencyWarningPrinter != null) { // The superclass or interface was found in the program class pool. // Print a warning. dependencyWarningPrinter.print(referencingClassName, name, "Warning: library class " + ClassUtil.externalClassName(referencingClassName) + " depends on program class " + ClassUtil.externalClassName(name)); } return clazz; } } proguard4.8/src/proguard/classfile/util/ClassUtil.java0000664000175000017500000014563211740606107021702 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.ClassConstants; import java.util.List; /** * Utility methods for converting between internal and external representations * of names and descriptions. * * @author Eric Lafortune */ public class ClassUtil { private static final String EMPTY_STRING = ""; /** * Checks whether the given class magic number is correct. * @param magicNumber the magic number. * @throws UnsupportedOperationException when the magic number is incorrect. */ public static void checkMagicNumber(int magicNumber) throws UnsupportedOperationException { if (magicNumber != ClassConstants.MAGIC) { throw new UnsupportedOperationException("Invalid magic number ["+Integer.toHexString(magicNumber)+"] in class"); } } /** * Returns the combined class version number. * @param majorVersion the major part of the class version number. * @param minorVersion the minor part of the class version number. * @return the combined class version number. */ public static int internalClassVersion(int majorVersion, int minorVersion) { return (majorVersion << 16) | minorVersion; } /** * Returns the major part of the given class version number. * @param classVersion the combined class version number. * @return the major part of the class version number. */ public static int internalMajorClassVersion(int classVersion) { return classVersion >>> 16; } /** * Returns the internal class version number. * @param classVersion the external class version number. * @return the internal class version number. */ public static int internalMinorClassVersion(int classVersion) { return classVersion & 0xffff; } /** * Returns the internal class version number. * @param classVersion the external class version number. * @return the internal class version number. */ public static int internalClassVersion(String classVersion) { return classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_0) || classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_1) ? ClassConstants.INTERNAL_CLASS_VERSION_1_0 : classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_2) ? ClassConstants.INTERNAL_CLASS_VERSION_1_2 : classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_3) ? ClassConstants.INTERNAL_CLASS_VERSION_1_3 : classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_4) ? ClassConstants.INTERNAL_CLASS_VERSION_1_4 : classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_5_ALIAS) || classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_5) ? ClassConstants.INTERNAL_CLASS_VERSION_1_5 : classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_6_ALIAS) || classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_6) ? ClassConstants.INTERNAL_CLASS_VERSION_1_6 : classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_7_ALIAS) || classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_7) ? ClassConstants.INTERNAL_CLASS_VERSION_1_7 : 0; } /** * Returns the minor part of the given class version number. * @param classVersion the combined class version number. * @return the minor part of the class version number. */ public static String externalClassVersion(int classVersion) { switch (classVersion) { case ClassConstants.INTERNAL_CLASS_VERSION_1_0: return ClassConstants.EXTERNAL_CLASS_VERSION_1_0; case ClassConstants.INTERNAL_CLASS_VERSION_1_2: return ClassConstants.EXTERNAL_CLASS_VERSION_1_2; case ClassConstants.INTERNAL_CLASS_VERSION_1_3: return ClassConstants.EXTERNAL_CLASS_VERSION_1_3; case ClassConstants.INTERNAL_CLASS_VERSION_1_4: return ClassConstants.EXTERNAL_CLASS_VERSION_1_4; case ClassConstants.INTERNAL_CLASS_VERSION_1_5: return ClassConstants.EXTERNAL_CLASS_VERSION_1_5; case ClassConstants.INTERNAL_CLASS_VERSION_1_6: return ClassConstants.EXTERNAL_CLASS_VERSION_1_6; case ClassConstants.INTERNAL_CLASS_VERSION_1_7: return ClassConstants.EXTERNAL_CLASS_VERSION_1_7; default: return null; } } /** * Checks whether the given class version number is supported. * @param classVersion the combined class version number. * @throws UnsupportedOperationException when the version is not supported. */ public static void checkVersionNumbers(int classVersion) throws UnsupportedOperationException { if (classVersion < ClassConstants.INTERNAL_CLASS_VERSION_1_0 || classVersion > ClassConstants.INTERNAL_CLASS_VERSION_1_7) { throw new UnsupportedOperationException("Unsupported class version number ["+ internalMajorClassVersion(classVersion)+"."+ internalMinorClassVersion(classVersion)+"] (maximum "+ ClassConstants.INTERNAL_CLASS_VERSION_1_7_MAJOR+"."+ ClassConstants.INTERNAL_CLASS_VERSION_1_7_MINOR+", Java "+ ClassConstants.EXTERNAL_CLASS_VERSION_1_7+")"); } } /** * Converts an external class name into an internal class name. * @param externalClassName the external class name, * e.g. "java.lang.Object" * @return the internal class name, * e.g. "java/lang/Object". */ public static String internalClassName(String externalClassName) { return externalClassName.replace(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR, ClassConstants.INTERNAL_PACKAGE_SEPARATOR); } /** * Converts an internal class description into an external class description. * @param accessFlags the access flags of the class. * @param internalClassName the internal class name, * e.g. "java/lang/Object". * @return the external class description, * e.g. "public java.lang.Object". */ public static String externalFullClassDescription(int accessFlags, String internalClassName) { return externalClassAccessFlags(accessFlags) + externalClassName(internalClassName); } /** * Converts an internal class name into an external class name. * @param internalClassName the internal class name, * e.g. "java/lang/Object". * @return the external class name, * e.g. "java.lang.Object". */ public static String externalClassName(String internalClassName) { return //internalClassName.startsWith(ClassConstants.INTERNAL_PACKAGE_JAVA_LANG) && //internalClassName.indexOf(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, ClassConstants.INTERNAL_PACKAGE_JAVA_LANG.length() + 1) < 0 ? //internalClassName.substring(ClassConstants.INTERNAL_PACKAGE_JAVA_LANG.length()) : internalClassName.replace(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, ClassConstants.EXTERNAL_PACKAGE_SEPARATOR); } /** * Returns the external base type of an external array type, dropping any * array brackets. * @param externalArrayType the external array type, * e.g. "java.lang.Object[][]" * @return the external base type, * e.g. "java.lang.Object". */ public static String externalBaseType(String externalArrayType) { int index = externalArrayType.indexOf(ClassConstants.EXTERNAL_TYPE_ARRAY); return index >= 0 ? externalArrayType.substring(0, index) : externalArrayType; } /** * Returns the external short class name of an external class name, dropping * the package specification. * @param externalClassName the external class name, * e.g. "java.lang.Object" * @return the external short class name, * e.g. "Object". */ public static String externalShortClassName(String externalClassName) { int index = externalClassName.lastIndexOf(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR); return externalClassName.substring(index+1); } /** * Returns whether the given internal type is an array type. * @param internalType the internal type, * e.g. "[[Ljava/lang/Object;". * @return true if the given type is an array type, * false otherwise. */ public static boolean isInternalArrayType(String internalType) { return internalType.length() > 1 && internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY; } /** * Returns the number of dimensions of the given internal type. * @param internalType the internal type, * e.g. "[[Ljava/lang/Object;". * @return the number of dimensions, e.g. 2. */ public static int internalArrayTypeDimensionCount(String internalType) { int dimensions = 0; while (internalType.charAt(dimensions) == ClassConstants.INTERNAL_TYPE_ARRAY) { dimensions++; } return dimensions; } /** * Returns whether the given internal class name is one of the interfaces * that is implemented by all array types. These class names are * "java/lang/Object", "java/lang/Cloneable", and * "java/io/Serializable" * @param internalClassName the internal class name, * e.g. "java/lang/Object". * @return true if the given type is an array interface name, * false otherwise. */ public static boolean isInternalArrayInterfaceName(String internalClassName) { return ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT.equals(internalClassName) || ClassConstants.INTERNAL_NAME_JAVA_LANG_CLONEABLE.equals(internalClassName) || ClassConstants.INTERNAL_NAME_JAVA_IO_SERIALIZABLE.equals(internalClassName); } /** * Returns whether the given internal type is a plain primitive type * (not void). * @param internalType the internal type, * e.g. "I". * @return true if the given type is a class type, * false otherwise. */ public static boolean isInternalPrimitiveType(char internalType) { return internalType == ClassConstants.INTERNAL_TYPE_BOOLEAN || internalType == ClassConstants.INTERNAL_TYPE_BYTE || internalType == ClassConstants.INTERNAL_TYPE_CHAR || internalType == ClassConstants.INTERNAL_TYPE_SHORT || internalType == ClassConstants.INTERNAL_TYPE_INT || internalType == ClassConstants.INTERNAL_TYPE_FLOAT || internalType == ClassConstants.INTERNAL_TYPE_LONG || internalType == ClassConstants.INTERNAL_TYPE_DOUBLE; } /** * Returns whether the given internal type is a primitive Category 2 type. * @param internalType the internal type, * e.g. "L". * @return true if the given type is a Category 2 type, * false otherwise. */ public static boolean isInternalCategory2Type(String internalType) { return internalType.length() == 1 && (internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_LONG || internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_DOUBLE); } /** * Returns whether the given internal type is a plain class type * (including an array type of a plain class type). * @param internalType the internal type, * e.g. "Ljava/lang/Object;". * @return true if the given type is a class type, * false otherwise. */ public static boolean isInternalClassType(String internalType) { int length = internalType.length(); return length > 1 && // internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_CLASS_START && internalType.charAt(length-1) == ClassConstants.INTERNAL_TYPE_CLASS_END; } /** * Returns the internal type of a given class name. * @param internalClassName the internal class name, * e.g. "java/lang/Object". * @return the internal type, * e.g. "Ljava/lang/Object;". */ public static String internalTypeFromClassName(String internalClassName) { return internalArrayTypeFromClassName(internalClassName, 0); } /** * Returns the internal array type of a given class name with a given number * of dimensions. If the number of dimensions is 0, the class name itself is * returned. * @param internalClassName the internal class name, * e.g. "java/lang/Object". * @param dimensionCount the number of array dimensions. * @return the internal array type of the array elements, * e.g. "Ljava/lang/Object;". */ public static String internalArrayTypeFromClassName(String internalClassName, int dimensionCount) { StringBuffer buffer = new StringBuffer(internalClassName.length() + dimensionCount + 2); for (int dimension = 0; dimension < dimensionCount; dimension++) { buffer.append(ClassConstants.INTERNAL_TYPE_ARRAY); } return buffer.append(ClassConstants.INTERNAL_TYPE_CLASS_START) .append(internalClassName) .append(ClassConstants.INTERNAL_TYPE_CLASS_END) .toString(); } /** * Returns the internal element type of a given internal array type. * @param internalArrayType the internal array type, * e.g. "[[Ljava/lang/Object;" or * "[I". * @return the internal type of the array elements, * e.g. "Ljava/lang/Object;" or * "I". */ public static String internalTypeFromArrayType(String internalArrayType) { int index = internalArrayType.lastIndexOf(ClassConstants.INTERNAL_TYPE_ARRAY); return internalArrayType.substring(index+1); } /** * Returns the internal class name of a given internal class type * (including an array type). Types involving primitive types are returned * unchanged. * @param internalClassType the internal class type, * e.g. "[Ljava/lang/Object;", * "Ljava/lang/Object;", or * "java/lang/Object". * @return the internal class name, * e.g. "java/lang/Object". */ public static String internalClassNameFromClassType(String internalClassType) { return isInternalClassType(internalClassType) ? internalClassType.substring(internalClassType.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1, internalClassType.length()-1) : internalClassType; } /** * Returns the internal class name of any given internal descriptor type, * disregarding array prefixes. * @param internalClassType the internal class type, * e.g. "Ljava/lang/Object;" or * "[[I". * @return the internal class name, * e.g. "java/lang/Object" or * null. */ public static String internalClassNameFromType(String internalClassType) { if (!isInternalClassType(internalClassType)) { return null; } // Is it an array type? if (isInternalArrayType(internalClassType)) { internalClassType = internalTypeFromArrayType(internalClassType); } return internalClassNameFromClassType(internalClassType); } /** * Returns whether the given method name refers to a class initializer or * an instance initializer. * @param internalMethodName the internal method name, * e.g. "<clinit>". * @return whether the method name refers to an initializer, * e.g. true. */ public static boolean isInitializer(String internalMethodName) { return internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) || internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT); } /** * Returns the internal type of the given internal method descriptor. * @param internalMethodDescriptor the internal method descriptor, * e.g. "(II)Z". * @return the internal return type, * e.g. "Z". */ public static String internalMethodReturnType(String internalMethodDescriptor) { int index = internalMethodDescriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); return internalMethodDescriptor.substring(index + 1); } /** * Returns the number of parameters of the given internal method descriptor. * @param internalMethodDescriptor the internal method descriptor, * e.g. "(ID)Z". * @return the number of parameters, * e.g. 2. */ public static int internalMethodParameterCount(String internalMethodDescriptor) { InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(internalMethodDescriptor); int counter = 0; while (internalTypeEnumeration.hasMoreTypes()) { internalTypeEnumeration.nextType(); counter++; } return counter; } /** * Returns the size taken up on the stack by the parameters of the given * internal method descriptor. This accounts for long and double parameters * taking up two entries. * @param internalMethodDescriptor the internal method descriptor, * e.g. "(ID)Z". * @return the size taken up on the stack, * e.g. 3. */ public static int internalMethodParameterSize(String internalMethodDescriptor) { return internalMethodParameterSize(internalMethodDescriptor, true); } /** * Returns the size taken up on the stack by the parameters of the given * internal method descriptor. This accounts for long and double parameters * taking up two entries, and a non-static method taking up an additional * entry. * @param internalMethodDescriptor the internal method descriptor, * e.g. "(ID)Z". * @param accessFlags the access flags of the method, * e.g. 0. * @return the size taken up on the stack, * e.g. 4. */ public static int internalMethodParameterSize(String internalMethodDescriptor, int accessFlags) { return internalMethodParameterSize(internalMethodDescriptor, (accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0); } /** * Returns the size taken up on the stack by the parameters of the given * internal method descriptor. This accounts for long and double parameters * taking up two spaces, and a non-static method taking up an additional * entry. * @param internalMethodDescriptor the internal method descriptor, * e.g. "(ID)Z". * @param isStatic specifies whether the method is static, * e.g. false. * @return the size taken up on the stack, * e.g. 4. */ public static int internalMethodParameterSize(String internalMethodDescriptor, boolean isStatic) { InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(internalMethodDescriptor); int size = isStatic ? 0 : 1; while (internalTypeEnumeration.hasMoreTypes()) { String internalType = internalTypeEnumeration.nextType(); size += internalTypeSize(internalType); } return size; } /** * Returns the size taken up on the stack by the given internal type. * The size is 1, except for long and double types, for which it is 2, * and for the void type, for which 0 is returned. * @param internalType the internal type, * e.g. "I". * @return the size taken up on the stack, * e.g. 1. */ public static int internalTypeSize(String internalType) { if (internalType.length() == 1) { char internalPrimitiveType = internalType.charAt(0); if (internalPrimitiveType == ClassConstants.INTERNAL_TYPE_LONG || internalPrimitiveType == ClassConstants.INTERNAL_TYPE_DOUBLE) { return 2; } else if (internalPrimitiveType == ClassConstants.INTERNAL_TYPE_VOID) { return 0; } } return 1; } /** * Converts an external type into an internal type. * @param externalType the external type, * e.g. "java.lang.Object[][]" or * "int[]". * @return the internal type, * e.g. "[[Ljava/lang/Object;" or * "[I". */ public static String internalType(String externalType) { // Strip the array part, if any. int dimensionCount = externalArrayTypeDimensionCount(externalType); if (dimensionCount > 0) { externalType = externalType.substring(0, externalType.length() - dimensionCount * ClassConstants.EXTERNAL_TYPE_ARRAY.length()); } // Analyze the actual type part. char internalTypeChar = externalType.equals(ClassConstants.EXTERNAL_TYPE_VOID ) ? ClassConstants.INTERNAL_TYPE_VOID : externalType.equals(ClassConstants.EXTERNAL_TYPE_BOOLEAN) ? ClassConstants.INTERNAL_TYPE_BOOLEAN : externalType.equals(ClassConstants.EXTERNAL_TYPE_BYTE ) ? ClassConstants.INTERNAL_TYPE_BYTE : externalType.equals(ClassConstants.EXTERNAL_TYPE_CHAR ) ? ClassConstants.INTERNAL_TYPE_CHAR : externalType.equals(ClassConstants.EXTERNAL_TYPE_SHORT ) ? ClassConstants.INTERNAL_TYPE_SHORT : externalType.equals(ClassConstants.EXTERNAL_TYPE_INT ) ? ClassConstants.INTERNAL_TYPE_INT : externalType.equals(ClassConstants.EXTERNAL_TYPE_FLOAT ) ? ClassConstants.INTERNAL_TYPE_FLOAT : externalType.equals(ClassConstants.EXTERNAL_TYPE_LONG ) ? ClassConstants.INTERNAL_TYPE_LONG : externalType.equals(ClassConstants.EXTERNAL_TYPE_DOUBLE ) ? ClassConstants.INTERNAL_TYPE_DOUBLE : externalType.equals("%" ) ? '%' : (char)0; String internalType = internalTypeChar != 0 ? String.valueOf(internalTypeChar) : ClassConstants.INTERNAL_TYPE_CLASS_START + internalClassName(externalType) + ClassConstants.INTERNAL_TYPE_CLASS_END; // Prepend the array part, if any. for (int count = 0; count < dimensionCount; count++) { internalType = ClassConstants.INTERNAL_TYPE_ARRAY + internalType; } return internalType; } /** * Returns the number of dimensions of the given external type. * @param externalType the external type, * e.g. "[[Ljava/lang/Object;". * @return the number of dimensions, e.g. 2. */ public static int externalArrayTypeDimensionCount(String externalType) { int dimensions = 0; int length = ClassConstants.EXTERNAL_TYPE_ARRAY.length(); int offset = externalType.length() - length; while (externalType.regionMatches(offset, ClassConstants.EXTERNAL_TYPE_ARRAY, 0, length)) { dimensions++; offset -= length; } return dimensions; } /** * Converts an internal type into an external type. * @param internalType the internal type, * e.g. "[[Ljava/lang/Object;" or * "[I". * @return the external type, * e.g. "java.lang.Object[][]" or * "int[]". */ public static String externalType(String internalType) { // Strip the array part, if any. int dimensionCount = internalArrayTypeDimensionCount(internalType); if (dimensionCount > 0) { internalType = internalType.substring(dimensionCount); } // Analyze the actual type part. char internalTypeChar = internalType.charAt(0); String externalType = internalTypeChar == ClassConstants.INTERNAL_TYPE_VOID ? ClassConstants.EXTERNAL_TYPE_VOID : internalTypeChar == ClassConstants.INTERNAL_TYPE_BOOLEAN ? ClassConstants.EXTERNAL_TYPE_BOOLEAN : internalTypeChar == ClassConstants.INTERNAL_TYPE_BYTE ? ClassConstants.EXTERNAL_TYPE_BYTE : internalTypeChar == ClassConstants.INTERNAL_TYPE_CHAR ? ClassConstants.EXTERNAL_TYPE_CHAR : internalTypeChar == ClassConstants.INTERNAL_TYPE_SHORT ? ClassConstants.EXTERNAL_TYPE_SHORT : internalTypeChar == ClassConstants.INTERNAL_TYPE_INT ? ClassConstants.EXTERNAL_TYPE_INT : internalTypeChar == ClassConstants.INTERNAL_TYPE_FLOAT ? ClassConstants.EXTERNAL_TYPE_FLOAT : internalTypeChar == ClassConstants.INTERNAL_TYPE_LONG ? ClassConstants.EXTERNAL_TYPE_LONG : internalTypeChar == ClassConstants.INTERNAL_TYPE_DOUBLE ? ClassConstants.EXTERNAL_TYPE_DOUBLE : internalTypeChar == '%' ? "%" : internalTypeChar == ClassConstants.INTERNAL_TYPE_CLASS_START ? externalClassName(internalType.substring(1, internalType.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_END))) : null; if (externalType == null) { throw new IllegalArgumentException("Unknown type ["+internalType+"]"); } // Append the array part, if any. for (int count = 0; count < dimensionCount; count++) { externalType += ClassConstants.EXTERNAL_TYPE_ARRAY; } return externalType; } /** * Returns whether the given internal descriptor String represents a method * descriptor. * @param internalDescriptor the internal descriptor String, * e.g. "(II)Z". * @return true if the given String is a method descriptor, * false otherwise. */ public static boolean isInternalMethodDescriptor(String internalDescriptor) { return internalDescriptor.charAt(0) == ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN; } /** * Returns whether the given member String represents an external method * name with arguments. * @param externalMemberNameAndArguments the external member String, * e.g. "myField" or * e.g. "myMethod(int,int)". * @return true if the given String refers to a method, * false otherwise. */ public static boolean isExternalMethodNameAndArguments(String externalMemberNameAndArguments) { return externalMemberNameAndArguments.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN) > 0; } /** * Returns the name part of the given external method name and arguments. * @param externalMethodNameAndArguments the external method name and arguments, * e.g. "myMethod(int,int)". * @return the name part of the String, e.g. "myMethod". */ public static String externalMethodName(String externalMethodNameAndArguments) { ExternalTypeEnumeration externalTypeEnumeration = new ExternalTypeEnumeration(externalMethodNameAndArguments); return externalTypeEnumeration.methodName(); } /** * Converts the given external method return type and name and arguments to * an internal method descriptor. * @param externalReturnType the external method return type, * e.g. "boolean". * @param externalMethodNameAndArguments the external method name and arguments, * e.g. "myMethod(int,int)". * @return the internal method descriptor, * e.g. "(II)Z". */ public static String internalMethodDescriptor(String externalReturnType, String externalMethodNameAndArguments) { StringBuffer internalMethodDescriptor = new StringBuffer(); internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN); ExternalTypeEnumeration externalTypeEnumeration = new ExternalTypeEnumeration(externalMethodNameAndArguments); while (externalTypeEnumeration.hasMoreTypes()) { internalMethodDescriptor.append(internalType(externalTypeEnumeration.nextType())); } internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); internalMethodDescriptor.append(internalType(externalReturnType)); return internalMethodDescriptor.toString(); } /** * Converts the given external method return type and List of arguments to * an internal method descriptor. * @param externalReturnType the external method return type, * e.g. "boolean". * @param externalArguments the external method arguments, * e.g. { "int", "int" }. * @return the internal method descriptor, * e.g. "(II)Z". */ public static String internalMethodDescriptor(String externalReturnType, List externalArguments) { StringBuffer internalMethodDescriptor = new StringBuffer(); internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN); for (int index = 0; index < externalArguments.size(); index++) { internalMethodDescriptor.append(internalType((String)externalArguments.get(index))); } internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); internalMethodDescriptor.append(internalType(externalReturnType)); return internalMethodDescriptor.toString(); } /** * Converts an internal field description into an external full field description. * @param accessFlags the access flags of the field. * @param fieldName the field name, * e.g. "myField". * @param internalFieldDescriptor the internal field descriptor, * e.g. "Z". * @return the external full field description, * e.g. "public boolean myField". */ public static String externalFullFieldDescription(int accessFlags, String fieldName, String internalFieldDescriptor) { return externalFieldAccessFlags(accessFlags) + externalType(internalFieldDescriptor) + ' ' + fieldName; } /** * Converts an internal method description into an external full method description. * @param internalClassName the internal name of the class of the method, * e.g. "mypackage/MyClass". * @param accessFlags the access flags of the method. * @param internalMethodName the internal method name, * e.g. "myMethod" or * "<init>". * @param internalMethodDescriptor the internal method descriptor, * e.g. "(II)Z". * @return the external full method description, * e.g. "public boolean myMethod(int,int)" or * "public MyClass(int,int)". */ public static String externalFullMethodDescription(String internalClassName, int accessFlags, String internalMethodName, String internalMethodDescriptor) { return externalMethodAccessFlags(accessFlags) + externalMethodReturnTypeAndName(internalClassName, internalMethodName, internalMethodDescriptor) + ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN + externalMethodArguments(internalMethodDescriptor) + ClassConstants.EXTERNAL_METHOD_ARGUMENTS_CLOSE; } /** * Converts internal class access flags into an external access description. * @param accessFlags the class access flags. * @return the external class access description, * e.g. "public final ". */ public static String externalClassAccessFlags(int accessFlags) { return externalClassAccessFlags(accessFlags, ""); } /** * Converts internal class access flags into an external access description. * @param accessFlags the class access flags. * @param prefix a prefix that is added to each access modifier. * @return the external class access description, * e.g. "public final ". */ public static String externalClassAccessFlags(int accessFlags, String prefix) { if (accessFlags == 0) { return EMPTY_STRING; } StringBuffer string = new StringBuffer(50); if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0) { // Only in InnerClasses attributes. string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0) { // Only in InnerClasses attributes. string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0) { // Only in InnerClasses attributes. string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_ANNOTATTION) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ANNOTATION); } if ((accessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_INTERFACE).append(' '); } else if ((accessFlags & ClassConstants.INTERNAL_ACC_ENUM) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ENUM).append(' '); } else if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ABSTRACT).append(' '); } else if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' '); } return string.toString(); } /** * Converts internal field access flags into an external access description. * @param accessFlags the field access flags. * @return the external field access description, * e.g. "public volatile ". */ public static String externalFieldAccessFlags(int accessFlags) { return externalFieldAccessFlags(accessFlags, ""); } /** * Converts internal field access flags into an external access description. * @param accessFlags the field access flags. * @param prefix a prefix that is added to each access modifier. * @return the external field access description, * e.g. "public volatile ". */ public static String externalFieldAccessFlags(int accessFlags, String prefix) { if (accessFlags == 0) { return EMPTY_STRING; } StringBuffer string = new StringBuffer(50); if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_VOLATILE) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_VOLATILE).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_TRANSIENT) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_TRANSIENT).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' '); } return string.toString(); } /** * Converts internal method access flags into an external access description. * @param accessFlags the method access flags. * @return the external method access description, * e.g. "public synchronized ". */ public static String externalMethodAccessFlags(int accessFlags) { return externalMethodAccessFlags(accessFlags, ""); } /** * Converts internal method access flags into an external access description. * @param accessFlags the method access flags. * @param prefix a prefix that is added to each access modifier. * @return the external method access description, * e.g. "public synchronized ". */ public static String externalMethodAccessFlags(int accessFlags, String prefix) { if (accessFlags == 0) { return EMPTY_STRING; } StringBuffer string = new StringBuffer(50); if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNCHRONIZED) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_BRIDGE) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_BRIDGE).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_VARARGS) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_VARARGS).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_NATIVE) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_NATIVE).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ABSTRACT).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_STRICT) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STRICT).append(' '); } if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0) { string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' '); } return string.toString(); } /** * Converts an internal method descriptor into an external method return type. * @param internalMethodDescriptor the internal method descriptor, * e.g. "(II)Z". * @return the external method return type, * e.g. "boolean". */ public static String externalMethodReturnType(String internalMethodDescriptor) { return externalType(internalMethodReturnType(internalMethodDescriptor)); } /** * Converts an internal class name, method name, and method descriptor to * an external method return type and name. * @param internalClassName the internal name of the class of the method, * e.g. "mypackage/MyClass". * @param internalMethodName the internal method name, * e.g. "myMethod" or * "<init>". * @param internalMethodDescriptor the internal method descriptor, * e.g. "(II)Z". * @return the external method return type and name, * e.g. "boolean myMethod" or * "MyClass". */ private static String externalMethodReturnTypeAndName(String internalClassName, String internalMethodName, String internalMethodDescriptor) { return internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ? externalShortClassName(externalClassName(internalClassName)) : (externalMethodReturnType(internalMethodDescriptor) + ' ' + internalMethodName); } /** * Converts an internal method descriptor into an external method argument * description. * @param internalMethodDescriptor the internal method descriptor, * e.g. "(II)Z". * @return the external method argument description, * e.g. "int,int". */ public static String externalMethodArguments(String internalMethodDescriptor) { StringBuffer externalMethodNameAndArguments = new StringBuffer(); InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(internalMethodDescriptor); while (internalTypeEnumeration.hasMoreTypes()) { externalMethodNameAndArguments.append(externalType(internalTypeEnumeration.nextType())); if (internalTypeEnumeration.hasMoreTypes()) { externalMethodNameAndArguments.append(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_SEPARATOR); } } return externalMethodNameAndArguments.toString(); } /** * Returns the internal package name of the given internal class name. * @param internalClassName the internal class name, * e.g. "java/lang/Object". * @return the internal package name, * e.g. "java/lang". */ public static String internalPackageName(String internalClassName) { String internalPackagePrefix = internalPackagePrefix(internalClassName); int length = internalPackagePrefix.length(); return length > 0 ? internalPackagePrefix.substring(0, length - 1) : ""; } /** * Returns the internal package prefix of the given internal class name. * @param internalClassName the internal class name, * e.g. "java/lang/Object". * @return the internal package prefix, * e.g. "java/lang/". */ public static String internalPackagePrefix(String internalClassName) { return internalClassName.substring(0, internalClassName.lastIndexOf(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, internalClassName.length() - 2) + 1); } /** * Returns the external package name of the given external class name. * @param externalClassName the external class name, * e.g. "java.lang.Object". * @return the external package name, * e.g. "java.lang". */ public static String externalPackageName(String externalClassName) { String externalPackagePrefix = externalPackagePrefix(externalClassName); int length = externalPackagePrefix.length(); return length > 0 ? externalPackagePrefix.substring(0, length - 1) : ""; } /** * Returns the external package prefix of the given external class name. * @param externalClassName the external class name, * e.g. "java.lang.Object". * @return the external package prefix, * e.g. "java.lang.". */ public static String externalPackagePrefix(String externalClassName) { return externalClassName.substring(0, externalClassName.lastIndexOf(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR, externalClassName.length() - 2) + 1); } } proguard4.8/src/proguard/classfile/util/DynamicMemberReferenceInitializer.java0000644000175000017500000013202311736333524026527 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.visitor.*; import proguard.util.StringMatcher; /** * This InstructionVisitor initializes any constant * Class.get[Declared]{Field,Method} references of all instructions * it visits. More specifically, it fills out the references of string constant * pool entries that refer to a class member in the program class pool or in the * library class pool. *

* It optionally prints notes if on usage of * (SomeClass)Class.forName(variable).newInstance(). *

* The class hierarchy and references must be initialized before using this * visitor. * * @see ClassSuperHierarchyInitializer * @see ClassReferenceInitializer * * @author Eric Lafortune */ public class DynamicMemberReferenceInitializer extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, AttributeVisitor, MemberVisitor { /* private static boolean DEBUG = true; /*/ private static final boolean DEBUG = false; //*/ public static final int CLASS_INDEX = InstructionSequenceMatcher.X; public static final int MEMBER_NAME_INDEX = InstructionSequenceMatcher.Y; public static final int TYPE_CLASS_INDEX = InstructionSequenceMatcher.Z; public static final int PARAMETER0_CLASS_INDEX = InstructionSequenceMatcher.A; public static final int PARAMETER1_CLASS_INDEX = InstructionSequenceMatcher.B; public static final int PARAMETER2_CLASS_INDEX = InstructionSequenceMatcher.C; public static final int PARAMETER3_CLASS_INDEX = InstructionSequenceMatcher.D; private final Constant[] GET_FIELD_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_FIELD), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_FIELD), }; private final Constant[] GET_DECLARED_FIELD_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD), }; private final Constant[] GET_CONSTRUCTOR_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_CONSTRUCTOR), new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_CONSTRUCTOR), }; private final Constant[] GET_DECLARED_CONSTRUCTOR_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_DECLARED_CONSTRUCTOR), new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_DECLARED_CONSTRUCTOR), }; private final Constant[] GET_METHOD_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_METHOD), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_METHOD), }; private final Constant[] GET_DECLARED_METHOD_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD), }; private final Constant[] NEW_INTEGER_UPDATER_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_INTEGER_UPDATER), }; private final Constant[] NEW_LONG_UPDATER_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_LONG_UPDATER), }; private final Constant[] NEW_REFERENCE_UPDATER_CONSTANTS = new Constant[] { new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_REFERENCE_UPDATER), }; // SomeClass.class.get[Declared]Field("someField"). private final Instruction[] CONSTANT_GET_FIELD_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // // SomeClass.class.get[Declared]Constructor(new Class[] {}). // private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[] // { // new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), // new SimpleInstruction(InstructionConstants.OP_ICONST_0), // new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), // new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), // }; // // // SomeClass.class.get[Declared]Constructor(new Class[] { A.class }). // private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[] // { // new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), // new SimpleInstruction(InstructionConstants.OP_ICONST_1), // new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), // new SimpleInstruction(InstructionConstants.OP_DUP), // new SimpleInstruction(InstructionConstants.OP_ICONST_0), // new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX), // new SimpleInstruction(InstructionConstants.OP_AASTORE), // new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), // }; // // // SomeClass.class.get[Declared]Constructor(new Class[] { A.class, B.class }). // private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[] // { // new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), // new SimpleInstruction(InstructionConstants.OP_ICONST_2), // new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), // new SimpleInstruction(InstructionConstants.OP_DUP), // new SimpleInstruction(InstructionConstants.OP_ICONST_0), // new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX), // new SimpleInstruction(InstructionConstants.OP_AASTORE), // new SimpleInstruction(InstructionConstants.OP_DUP), // new SimpleInstruction(InstructionConstants.OP_ICONST_1), // new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX), // new SimpleInstruction(InstructionConstants.OP_AASTORE), // new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), // }; // SomeClass.class.get[Declared]Method("someMethod", new Class[] {}). private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS0 = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class }). private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS1 = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new SimpleInstruction(InstructionConstants.OP_ICONST_1), new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class, B.class }). private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS2 = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new SimpleInstruction(InstructionConstants.OP_ICONST_2), new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_1), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // AtomicIntegerFieldUpdater.newUpdater(A.class, "someField"). // AtomicLongFieldUpdater.newUpdater(A.class, "someField"). private final Instruction[] CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), }; // AtomicReferenceFieldUpdater.newUpdater(A.class, B.class, "someField"). private final Instruction[] CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX), new ConstantInstruction(InstructionConstants.OP_LDC, TYPE_CLASS_INDEX), new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), }; // get[Declared]Field("someField"). private final Instruction[] GET_FIELD_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // // get[Declared]Constructor(new Class[] {}). // private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[] // { // new SimpleInstruction(InstructionConstants.OP_ICONST_0), // new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), // new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), // }; // get[Declared]Constructor(new Class[] { A.class }). private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[] { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // get[Declared]Constructor(new Class[] { A.class, B.class }). private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[] { new SimpleInstruction(InstructionConstants.OP_ICONST_2), new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_1), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // get[Declared]Method("someMethod", new Class[] {}). private final Instruction[] GET_METHOD_INSTRUCTIONS0 = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // get[Declared]Method("someMethod", new Class[] { A.class }). private final Instruction[] GET_METHOD_INSTRUCTIONS1 = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new SimpleInstruction(InstructionConstants.OP_ICONST_1), new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // get[Declared]Method("someMethod", new Class[] { A.class, B.class }). private final Instruction[] GET_METHOD_INSTRUCTIONS2 = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new SimpleInstruction(InstructionConstants.OP_ICONST_2), new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new SimpleInstruction(InstructionConstants.OP_DUP), new SimpleInstruction(InstructionConstants.OP_ICONST_1), new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX), new SimpleInstruction(InstructionConstants.OP_AASTORE), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), }; // AtomicIntegerFieldUpdater.newUpdater(..., "someField"). // AtomicLongFieldUpdater.newUpdater(..., "someField"). // AtomicReferenceFieldUpdater.newUpdater(..., "someField"). private final Instruction[] NEW_UPDATER_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), }; private final ClassPool programClassPool; private final ClassPool libraryClassPool; private final WarningPrinter notePrinter; private final StringMatcher noteFieldExceptionMatcher; private final StringMatcher noteMethodExceptionMatcher; private final InstructionSequenceMatcher constantGetFieldMatcher = new InstructionSequenceMatcher(GET_FIELD_CONSTANTS, CONSTANT_GET_FIELD_INSTRUCTIONS); private final InstructionSequenceMatcher constantGetDeclaredFieldMatcher = new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS, CONSTANT_GET_FIELD_INSTRUCTIONS); // private final InstructionSequenceMatcher constantGetConstructorMatcher0 = // new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS, // CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0); // // private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher0 = // new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS, // CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0); // // private final InstructionSequenceMatcher constantGetConstructorMatcher1 = // new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS, // CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1); // // private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher1 = // new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS, // CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1); // // private final InstructionSequenceMatcher constantGetConstructorMatcher2 = // new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS, // CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2); // // private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher2 = // new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS, // CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2); private final InstructionSequenceMatcher constantGetMethodMatcher0 = new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, CONSTANT_GET_METHOD_INSTRUCTIONS0); private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher0 = new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, CONSTANT_GET_METHOD_INSTRUCTIONS0); private final InstructionSequenceMatcher constantGetMethodMatcher1 = new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, CONSTANT_GET_METHOD_INSTRUCTIONS1); private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher1 = new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, CONSTANT_GET_METHOD_INSTRUCTIONS1); private final InstructionSequenceMatcher constantGetMethodMatcher2 = new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, CONSTANT_GET_METHOD_INSTRUCTIONS2); private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher2 = new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, CONSTANT_GET_METHOD_INSTRUCTIONS2); private final InstructionSequenceMatcher constantGetIntegerUpdaterMatcher = new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS, CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS); private final InstructionSequenceMatcher constantGetLongUpdaterMatcher = new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS, CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS); private final InstructionSequenceMatcher constantGetReferenceUpdaterMatcher = new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS, CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS); private final InstructionSequenceMatcher getFieldMatcher = new InstructionSequenceMatcher(GET_FIELD_CONSTANTS, GET_FIELD_INSTRUCTIONS); private final InstructionSequenceMatcher getDeclaredFieldMatcher = new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS, GET_FIELD_INSTRUCTIONS); // private final InstructionSequenceMatcher getConstructorMatcher0 = // new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS, // GET_CONSTRUCTOR_INSTRUCTIONS0); // // private final InstructionSequenceMatcher getDeclaredConstructorMatcher0 = // new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS, // GET_CONSTRUCTOR_INSTRUCTIONS0); private final InstructionSequenceMatcher getConstructorMatcher1 = new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS, GET_CONSTRUCTOR_INSTRUCTIONS1); private final InstructionSequenceMatcher getDeclaredConstructorMatcher1 = new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS, GET_CONSTRUCTOR_INSTRUCTIONS1); private final InstructionSequenceMatcher getConstructorMatcher2 = new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS, GET_CONSTRUCTOR_INSTRUCTIONS2); private final InstructionSequenceMatcher getDeclaredConstructorMatcher2 = new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS, GET_CONSTRUCTOR_INSTRUCTIONS2); private final InstructionSequenceMatcher getMethodMatcher0 = new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, GET_METHOD_INSTRUCTIONS0); private final InstructionSequenceMatcher getDeclaredMethodMatcher0 = new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, GET_METHOD_INSTRUCTIONS0); private final InstructionSequenceMatcher getMethodMatcher1 = new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, GET_METHOD_INSTRUCTIONS1); private final InstructionSequenceMatcher getDeclaredMethodMatcher1 = new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, GET_METHOD_INSTRUCTIONS1); private final InstructionSequenceMatcher getMethodMatcher2 = new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, GET_METHOD_INSTRUCTIONS2); private final InstructionSequenceMatcher getDeclaredMethodMatcher2 = new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, GET_METHOD_INSTRUCTIONS2); private final InstructionSequenceMatcher getIntegerUpdaterMatcher = new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS, NEW_UPDATER_INSTRUCTIONS); private final InstructionSequenceMatcher getLongUpdaterMatcher = new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS, NEW_UPDATER_INSTRUCTIONS); private final InstructionSequenceMatcher getReferenceUpdaterMatcher = new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS, NEW_UPDATER_INSTRUCTIONS); private final MemberFinder memberFinder = new MemberFinder(); // Fields acting as parameters for the visitors. private Clazz referencedClass; private String descriptor; private boolean isDeclared; private boolean isField; /** * Creates a new DynamicMemberReferenceInitializer. */ public DynamicMemberReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter notePrinter, StringMatcher noteFieldExceptionMatcher, StringMatcher noteMethodExceptionMatcher) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; this.notePrinter = notePrinter; this.noteFieldExceptionMatcher = noteFieldExceptionMatcher; this.noteMethodExceptionMatcher = noteMethodExceptionMatcher; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { // Try to match the SomeClass.class.getField("someField") construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetFieldMatcher, getFieldMatcher, true, false, null, null); // Try to match the SomeClass.class.getDeclaredField("someField") construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetDeclaredFieldMatcher, getDeclaredFieldMatcher, true, true, null, null); // // Try to match the SomeClass.class.getConstructor(new Class[] // // {}) construct. // matchGetMember(clazz, method, codeAttribute, offset, instruction, // cnull, //onstantGetConstructorMatcher0, // getConstructorMatcher0, false, false, // ClassConstants.INTERNAL_METHOD_NAME_INIT, null); // // // Try to match the SomeClass.class.getDeclaredConstructor(new Class[] // // {}) construct. // matchGetMember(clazz, method, codeAttribute, offset, instruction, // null, //constantGetDeclaredConstructorMatcher0, // getDeclaredConstructorMatcher0, false, true, // ClassConstants.INTERNAL_METHOD_NAME_INIT, null); // Try to match the SomeClass.class.getConstructor(new Class[] // { A.class }) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, null, //constantGetConstructorMatcher1, getConstructorMatcher1, false, false, ClassConstants.INTERNAL_METHOD_NAME_INIT, null); // Try to match the SomeClass.class.getDeclaredConstructor(new Class[] // { A.class }) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, null, //constantGetDeclaredConstructorMatcher1, getDeclaredConstructorMatcher1, false, true, ClassConstants.INTERNAL_METHOD_NAME_INIT, null); // Try to match the SomeClass.class.getConstructor(new Class[] // { A.class, B.class }) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, null, //constantGetConstructorMatcher2, getConstructorMatcher2, false, false, ClassConstants.INTERNAL_METHOD_NAME_INIT, null); // Try to match the SomeClass.class.getDeclaredConstructor(new Class[] // { A.class, B.class }) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, null, //constantGetDeclaredConstructorMatcher2, getDeclaredConstructorMatcher2, false, true, ClassConstants.INTERNAL_METHOD_NAME_INIT, null); // Try to match the SomeClass.class.getMethod("someMethod", new Class[] // {}) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetMethodMatcher0, getMethodMatcher0, false, false, null, null); // Try to match the SomeClass.class.getDeclaredMethod("someMethod", // new Class[] {}) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetDeclaredMethodMatcher0, getDeclaredMethodMatcher0, false, true, null, null); // Try to match the SomeClass.class.getMethod("someMethod", new Class[] // { A.class }) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetMethodMatcher1, getMethodMatcher1, false, false, null, null); // Try to match the SomeClass.class.getDeclaredMethod("someMethod", // new Class[] { A.class }) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetDeclaredMethodMatcher1, getDeclaredMethodMatcher1, false, true, null, null); // Try to match the SomeClass.class.getMethod("someMethod", new Class[] // { A.class, B.class }) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetMethodMatcher2, getMethodMatcher2, false, false, null, null); // Try to match the SomeClass.class.getDeclaredMethod("someMethod", // new Class[] { A.class, B.class }) construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetDeclaredMethodMatcher2, getDeclaredMethodMatcher2, false, true, null, null); // Try to match the AtomicIntegerFieldUpdater.newUpdater( // SomeClass.class, "someField") construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetIntegerUpdaterMatcher, getIntegerUpdaterMatcher, true, false, null, "" + ClassConstants.INTERNAL_TYPE_INT); // Try to match the AtomicLongFieldUpdater.newUpdater( // SomeClass.class, "someField") construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetLongUpdaterMatcher, getLongUpdaterMatcher, true, false, null, "" + ClassConstants.INTERNAL_TYPE_LONG); // Try to match the AtomicReferenceFieldUpdater.newUpdater( // SomeClass.class, SomeClass.class, "someField") construct. matchGetMember(clazz, method, codeAttribute, offset, instruction, constantGetReferenceUpdaterMatcher, getReferenceUpdaterMatcher, true, false, null, null); } /** * Tries to match the next instruction and fills out the string constant * or prints out a note accordingly. */ private void matchGetMember(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction, InstructionSequenceMatcher constantSequenceMatcher, InstructionSequenceMatcher variableSequenceMatcher, boolean isField, boolean isDeclared, String defaultName, String defaultDescriptor) { if (constantSequenceMatcher != null) { // Try to match the next instruction in the constant sequence. instruction.accept(clazz, method, codeAttribute, offset, constantSequenceMatcher); // Did we find a match to fill out the string constant? if (constantSequenceMatcher.isMatching()) { initializeStringReference(clazz, constantSequenceMatcher, isField, isDeclared, defaultDescriptor); // Don't look for the dynamic construct. variableSequenceMatcher.reset(); } } // Try to match the next instruction in the variable sequence. instruction.accept(clazz, method, codeAttribute, offset, variableSequenceMatcher); // Did we find a match to print out a note? if (variableSequenceMatcher.isMatching()) { // Print out a note about the dynamic invocation. printDynamicInvocationNote(clazz, variableSequenceMatcher, isField, isDeclared, defaultName, defaultDescriptor); } } /** * Initializes the reference of the matched string constant to the * referenced class member and its class. */ private void initializeStringReference(Clazz clazz, InstructionSequenceMatcher constantSequenceMatcher, boolean isField, boolean isDeclared, String defaultDescriptor) { this.isField = isField; this.isDeclared = isDeclared; // Get the member's class. int classIndex = constantSequenceMatcher.matchedConstantIndex(CLASS_INDEX); clazz.constantPoolEntryAccept(classIndex, this); // Get the field's reference type, if applicable. int typeClassIndex = constantSequenceMatcher.matchedConstantIndex(TYPE_CLASS_INDEX); descriptor = typeClassIndex <= 0 ? defaultDescriptor : ClassUtil.internalTypeFromClassName(clazz.getClassName(typeClassIndex)); // Fill out the matched string constant. int memberNameIndex = constantSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX); clazz.constantPoolEntryAccept(memberNameIndex, this); } // Implementations for ConstantVisitor. /** * Remembers the referenced class. */ public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { if (DEBUG) { System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched class ["+classConstant.getName(clazz)+"]"); } // Remember the referenced class. referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ? null : classConstant.referencedClass; } /** * Fills out the link to the referenced class member. */ public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { if (referencedClass != null) { String name = stringConstant.getString(clazz); if (DEBUG) { System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched string ["+name+"]"); } // See if we can find the referenced class member locally, or // somewhere in the hierarchy. Member referencedMember = isDeclared ? isField ? (Member)referencedClass.findField(name, descriptor) : (Member)referencedClass.findMethod(name, descriptor) : (Member)memberFinder.findMember(clazz, referencedClass, name, descriptor, isField); if (referencedMember != null) { stringConstant.referencedMember = referencedMember; stringConstant.referencedClass = isDeclared ? referencedClass : memberFinder.correspondingClass(); } } } // Small utility methods. /** * Prints out a note on the matched dynamic invocation, if necessary. */ private void printDynamicInvocationNote(Clazz clazz, InstructionSequenceMatcher noteSequenceMatcher, boolean isField, boolean isDeclared, String defaultName, String defaultDescriptor) { // Print out a note about the dynamic invocation. if (notePrinter != null && notePrinter.accepts(clazz.getName())) { // Is the class member name in the list of exceptions? StringMatcher noteExceptionMatcher = isField ? noteFieldExceptionMatcher : noteMethodExceptionMatcher; int memberNameIndex = noteSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX); String memberName = memberNameIndex <= 0 ? defaultName : clazz.getStringString(memberNameIndex); if (noteExceptionMatcher == null || !noteExceptionMatcher.matches(memberName)) { // Compose the external member name and partial descriptor. String externalMemberDescription = memberName; if (!isField) { externalMemberDescription += '('; for (int count = 0; count < 2; count++) { int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex( PARAMETER0_CLASS_INDEX + count); if (memberArgumentIndex > 0) { if (count > 0) { externalMemberDescription += ','; } String className = clazz.getClassName(memberArgumentIndex); externalMemberDescription += ClassUtil.isInternalArrayType(className) ? ClassUtil.externalType(className) : ClassUtil.externalClassName(className); } } externalMemberDescription += ')'; } // Print out the actual note. notePrinter.print(clazz.getName(), "Note: " + ClassUtil.externalClassName(clazz.getName()) + " accesses a " + (isDeclared ? "declared " : "") + (isField ? "field" : memberName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ? "constructor" : "method") + " '" + externalMemberDescription + "' dynamically"); // Print out notes about potential candidates. ClassVisitor classVisitor; if (isField) { classVisitor = defaultDescriptor == null ? new AllFieldVisitor( new MemberNameFilter(memberName, this)) : new AllFieldVisitor( new MemberNameFilter(memberName, new MemberDescriptorFilter(defaultDescriptor, this))); } else { // Compose the partial method descriptor. String methodDescriptor = "("; for (int count = 0; count < 2; count++) { int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(PARAMETER0_CLASS_INDEX + count); if (memberArgumentIndex > 0) { String className = clazz.getClassName(memberArgumentIndex); methodDescriptor += ClassUtil.isInternalArrayType(className) ? className : ClassUtil.internalTypeFromClassName(className); } } methodDescriptor += ")L***;"; classVisitor = new AllMethodVisitor( new MemberNameFilter(memberName, new MemberDescriptorFilter(methodDescriptor, this))); } programClassPool.classesAcceptAlphabetically(classVisitor); libraryClassPool.classesAcceptAlphabetically(classVisitor); } } } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (notePrinter.accepts(programClass.getName())) { System.out.println(" Maybe this is program field '" + ClassUtil.externalFullClassDescription(0, programClass.getName()) + " { " + ClassUtil.externalFullFieldDescription(0, programField.getName(programClass), programField.getDescriptor(programClass)) + "; }'"); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (notePrinter.accepts(programClass.getName())) { System.out.println(" Maybe this is program method '" + ClassUtil.externalFullClassDescription(0, programClass.getName()) + " { " + ClassUtil.externalFullMethodDescription(programClass.getName(), 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) + "; }'"); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (notePrinter.accepts(libraryClass.getName())) { System.out.println(" Maybe this is library field '" + ClassUtil.externalFullClassDescription(0, libraryClass.getName()) + " { " + ClassUtil.externalFullFieldDescription(0, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass)) + "; }'"); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (notePrinter.accepts(libraryClass.getName())) { System.out.println(" Maybe this is library method '" + ClassUtil.externalFullClassDescription(0, libraryClass.getName()) + " { " + ClassUtil.externalFullMethodDescription(libraryClass.getName(), 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) + "; }'"); } } }proguard4.8/src/proguard/classfile/util/InternalTypeEnumeration.java0000644000175000017500000001251011736333524024613 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.ClassConstants; /** * An InternalTypeEnumeration provides an enumeration of all * parameter types listed in a given internal method descriptor or signature. * The signature can also be a class signature. The return type of a method * descriptor can be retrieved separately. * * @author Eric Lafortune */ public class InternalTypeEnumeration { private String descriptor; private int firstIndex; private int lastIndex; private int index; /** * Creates a new InternalTypeEnumeration for the given method descriptor. */ public InternalTypeEnumeration(String descriptor) { this.descriptor = descriptor; this.firstIndex = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN); this.lastIndex = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); this.index = firstIndex + 1; if (lastIndex < 0) { lastIndex = descriptor.length(); } } /** * Returns the formal type parameters from the descriptor, assuming it's a * method descriptor. */ public String formalTypeParameters() { return descriptor.substring(0, firstIndex); } /** * Returns whether the enumeration can provide more types from the method * descriptor. */ public boolean hasMoreTypes() { return index < lastIndex; } /** * Returns the next type from the method descriptor. */ public String nextType() { int startIndex = index; skipArray(); char c = descriptor.charAt(index++); switch (c) { case ClassConstants.INTERNAL_TYPE_CLASS_START: case ClassConstants.INTERNAL_TYPE_GENERIC_VARIABLE_START: { skipClass(); break; } case ClassConstants.INTERNAL_TYPE_GENERIC_START: { skipGeneric(); break; } } return descriptor.substring(startIndex, index); } /** * Returns the return type from the descriptor, assuming it's a method * descriptor. */ public String returnType() { return descriptor.substring(lastIndex + 1); } // Small utility methods. private void skipArray() { while (descriptor.charAt(index) == ClassConstants.INTERNAL_TYPE_ARRAY) { index++; } } private void skipClass() { while (true) { char c = descriptor.charAt(index++); switch (c) { case ClassConstants.INTERNAL_TYPE_GENERIC_START: skipGeneric(); break; case ClassConstants.INTERNAL_TYPE_CLASS_END: return; } } } private void skipGeneric() { int nestingLevel = 1; do { char c = descriptor.charAt(index++); switch (c) { case ClassConstants.INTERNAL_TYPE_GENERIC_START: nestingLevel++; break; case ClassConstants.INTERNAL_TYPE_GENERIC_END: nestingLevel--; break; } } while (nestingLevel > 0); } /** * A main method for testing the type enumeration. */ public static void main(String[] args) { try { for (int index = 0; index < args.length; index++) { String descriptor = args[index]; System.out.println("Descriptor ["+descriptor+"]"); InternalTypeEnumeration enumeration = new InternalTypeEnumeration(descriptor); if (enumeration.firstIndex >= 0) { System.out.println(" Formal type parameters ["+enumeration.formalTypeParameters()+"]"); } while (enumeration.hasMoreTypes()) { System.out.println(" Type ["+enumeration.nextType()+"]"); } if (enumeration.lastIndex < descriptor.length()) { System.out.println(" Return type ["+enumeration.returnType()+"]"); } } } catch (Exception ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java0000644000175000017500000001404711736333524026124 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.constant.ClassConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor initializes the superclass hierarchy of all classes that * it visits. *

* Visited library classes get direct references to their superclasses and * interfaces, replacing the superclass names and interface names. The direct * references are equivalent to the names, but they are more efficient to work * with. *

* This visitor optionally prints warnings if some superclasses can't be found * or if they are in the program class pool. * * @author Eric Lafortune */ public class ClassSuperHierarchyInitializer extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor { private final ClassPool programClassPool; private final ClassPool libraryClassPool; private final WarningPrinter missingWarningPrinter; private final WarningPrinter dependencyWarningPrinter; /** * Creates a new ClassSuperHierarchyInitializer that initializes the super * hierarchy of all visited class files, optionally printing warnings if * some classes can't be found or if they are in the program class pool. */ public ClassSuperHierarchyInitializer(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter missingWarningPrinter, WarningPrinter dependencyWarningPrinter) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; this.missingWarningPrinter = missingWarningPrinter; this.dependencyWarningPrinter = dependencyWarningPrinter; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Link to the super class. programClass.superClassConstantAccept(this); // Link to the interfaces. programClass.interfaceConstantsAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { String className = libraryClass.getName(); // Link to the super class. String superClassName = libraryClass.superClassName; if (superClassName != null) { // Keep a reference to the superclass. libraryClass.superClass = findClass(className, superClassName); } // Link to the interfaces. if (libraryClass.interfaceNames != null) { String[] interfaceNames = libraryClass.interfaceNames; Clazz[] interfaceClasses = new Clazz[interfaceNames.length]; for (int index = 0; index < interfaceNames.length; index++) { // Keep a reference to the interface class. interfaceClasses[index] = findClass(className, interfaceNames[index]); } libraryClass.interfaceClasses = interfaceClasses; } } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.referencedClass = findClass(clazz.getName(), classConstant.getName(clazz)); } // Small utility methods. /** * Returns the class with the given name, either for the program class pool * or from the library class pool, or null if it can't be found. */ private Clazz findClass(String referencingClassName, String name) { // First look for the class in the program class pool. Clazz clazz = programClassPool.getClass(name); // Otherwise look for the class in the library class pool. if (clazz == null) { clazz = libraryClassPool.getClass(name); if (clazz == null && missingWarningPrinter != null) { // We didn't find the superclass or interface. Print a warning. missingWarningPrinter.print(referencingClassName, name, "Warning: " + ClassUtil.externalClassName(referencingClassName) + ": can't find superclass or interface " + ClassUtil.externalClassName(name)); } } else if (dependencyWarningPrinter != null) { // The superclass or interface was found in the program class pool. // Print a warning. dependencyWarningPrinter.print(referencingClassName, name, "Warning: library class " + ClassUtil.externalClassName(referencingClassName) + " extends or implements program class " + ClassUtil.externalClassName(name)); } return clazz; } } proguard4.8/src/proguard/classfile/util/MethodLinker.java0000644000175000017500000001222311736333524022354 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.visitor.*; import java.util.*; /** * This ClassVisitor links all corresponding non-private, non-static, * non-initializer methods in the class hierarchies of all visited classes. * Visited classes are typically all class files that are not being subclassed. * Chains of links that have been created in previous invocations are merged * with new chains of links, in order to create a consistent set of chains. * * @author Eric Lafortune */ public class MethodLinker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor { // An object that is reset and reused every time. // The map: [class member name+' '+descriptor - class member info] private final Map memberMap = new HashMap(); // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { // Collect all non-private members in this class hierarchy. clazz.hierarchyAccept(true, true, true, false, new AllMethodVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC, this))); // Clean up for the next class hierarchy. memberMap.clear(); } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) { // Get the class member's name and descriptor. String name = member.getName(clazz); String descriptor = member.getDescriptor(clazz); // Special cases: and are always kept unchanged. // We can ignore them here. if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) || name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { return; } // See if we've already come across a method with the same name and // descriptor. String key = name + ' ' + descriptor; Member otherMember = (Member)memberMap.get(key); if (otherMember == null) { // Get the last method in the chain. Member thisLastMember = lastMember(member); // Store the new class method in the map. memberMap.put(key, thisLastMember); } else { // Link both members. link(member, otherMember); } } // Small utility methods. /** * Links the two given class members. */ private static void link(Member member1, Member member2) { // Get the last methods in the both chains. Member lastMember1 = lastMember(member1); Member lastMember2 = lastMember(member2); // Check if both link chains aren't already ending in the same element. if (!lastMember1.equals(lastMember2)) { // Merge the two chains, with the library members last. if (lastMember2 instanceof LibraryMember) { lastMember1.setVisitorInfo(lastMember2); } else { lastMember2.setVisitorInfo(lastMember1); } } } /** * Finds the last class member in the linked list of related class members. * @param member the given class member. * @return the last class member in the linked list. */ public static Member lastMember(Member member) { Member lastMember = member; while (lastMember.getVisitorInfo() != null && lastMember.getVisitorInfo() instanceof Member) { lastMember = (Member)lastMember.getVisitorInfo(); } return lastMember; } /** * Finds the last visitor accepter in the linked list of visitors. * @param visitorAccepter the given method. * @return the last method in the linked list. */ public static VisitorAccepter lastVisitorAccepter(VisitorAccepter visitorAccepter) { VisitorAccepter lastVisitorAccepter = visitorAccepter; while (lastVisitorAccepter.getVisitorInfo() != null && lastVisitorAccepter.getVisitorInfo() instanceof VisitorAccepter) { lastVisitorAccepter = (VisitorAccepter)lastVisitorAccepter.getVisitorInfo(); } return lastVisitorAccepter; } } proguard4.8/src/proguard/classfile/util/ClassSubHierarchyInitializer.java0000644000175000017500000000502211736333524025550 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor adds all classes that it visits to the list of subclasses * of their superclass. These subclass lists make it more convenient to travel * * @author Eric Lafortune */ public class ClassSubHierarchyInitializer implements ClassVisitor { // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Add this class to the subclasses of its superclass. addSubclass(programClass, programClass.getSuperClass()); // Add this class to the subclasses of its interfaces. for (int index = 0; index < programClass.u2interfacesCount; index++) { addSubclass(programClass, programClass.getInterface(index)); } } public void visitLibraryClass(LibraryClass libraryClass) { // Add this class to the subclasses of its superclass, addSubclass(libraryClass, libraryClass.superClass); // Add this class to the subclasses of its interfaces. Clazz[] interfaceClasses = libraryClass.interfaceClasses; if (interfaceClasses != null) { for (int index = 0; index < interfaceClasses.length; index++) { // Add this class to the subclasses of the interface class. addSubclass(libraryClass, interfaceClasses[index]); } } } // Small utility methods. private void addSubclass(Clazz subclass, Clazz clazz) { if (clazz != null) { clazz.addSubClass(subclass); } } } proguard4.8/src/proguard/classfile/util/DynamicClassReferenceInitializer.java0000644000175000017500000004706611736333524026401 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.util.StringMatcher; /** * This InstructionVisitor initializes any constant Class.forName or * .class references of all classes it visits. More specifically, * it fills out the references of string constant pool entries that refer to a * class in the program class pool or in the library class pool. *

* It optionally prints notes if on usage of * (SomeClass)Class.forName(variable).newInstance(). *

* The class hierarchy must be initialized before using this visitor. * * @see ClassSuperHierarchyInitializer * * @author Eric Lafortune */ public class DynamicClassReferenceInitializer extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, AttributeVisitor { public static final int X = InstructionSequenceMatcher.X; public static final int Y = InstructionSequenceMatcher.Y; public static final int Z = InstructionSequenceMatcher.Z; public static final int A = InstructionSequenceMatcher.A; public static final int B = InstructionSequenceMatcher.B; public static final int C = InstructionSequenceMatcher.C; public static final int D = InstructionSequenceMatcher.D; private final Constant[] CLASS_FOR_NAME_CONSTANTS = new Constant[] { // 0 new MethodrefConstant(1, 2, null, null), new ClassConstant(3, null), new NameAndTypeConstant(4, 5), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_FOR_NAME), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_FOR_NAME), // 6 new MethodrefConstant(1, 7, null, null), new NameAndTypeConstant(8, 9), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_INSTANCE), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_INSTANCE), // 10 new MethodrefConstant(1, 11, null, null), new NameAndTypeConstant(12, 13), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_COMPONENT_TYPE), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_COMPONENT_TYPE), }; // Class.forName("SomeClass"). private final Instruction[] CONSTANT_CLASS_FOR_NAME_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, X), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), }; // (SomeClass)Class.forName(someName).newInstance(). private final Instruction[] CLASS_FOR_NAME_CAST_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 6), new ConstantInstruction(InstructionConstants.OP_CHECKCAST, X), }; // private Constant[] DOT_CLASS_JAVAC_CONSTANTS = new Constant[] // { // new MethodrefConstant(A, 1, null, null), // new NameAndTypeConstant(2, 3), // new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_DOT_CLASS_JAVAC), // new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC), // }; private final Constant[] DOT_CLASS_JAVAC_CONSTANTS = new Constant[] { new MethodrefConstant(A, 1, null, null), new NameAndTypeConstant(B, 2), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC), }; // SomeClass.class = class$("SomeClass") (javac). private final Instruction[] DOT_CLASS_JAVAC_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, X), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), }; // private Constant[] DOT_CLASS_JIKES_CONSTANTS = new Constant[] // { // new MethodrefConstant(A, 1, null, null), // new NameAndTypeConstant(2, 3), // new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_DOT_CLASS_JIKES), // new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES), // }; private final Constant[] DOT_CLASS_JIKES_CONSTANTS = new Constant[] { new MethodrefConstant(A, 1, null, null), new NameAndTypeConstant(B, 2), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES), }; // SomeClass.class = class("SomeClass", false) (jikes). private final Instruction[] DOT_CLASS_JIKES_INSTRUCTIONS = new Instruction[] { new ConstantInstruction(InstructionConstants.OP_LDC, X), new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), }; // return Class.forName(v0). private final Instruction[] DOT_CLASS_JAVAC_IMPLEMENTATION_INSTRUCTIONS = new Instruction[] { new VariableInstruction(InstructionConstants.OP_ALOAD_0), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), new SimpleInstruction(InstructionConstants.OP_ARETURN), }; // return Class.forName(v0), if (!v1) .getComponentType(). private final Instruction[] DOT_CLASS_JIKES_IMPLEMENTATION_INSTRUCTIONS = new Instruction[] { new VariableInstruction(InstructionConstants.OP_ALOAD_0), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), new VariableInstruction(InstructionConstants.OP_ALOAD_1), new BranchInstruction(InstructionConstants.OP_IFNE, +6), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 10), new SimpleInstruction(InstructionConstants.OP_ARETURN), }; // return Class.forName(v0).getComponentType(). private final Instruction[] DOT_CLASS_JIKES_IMPLEMENTATION_INSTRUCTIONS2 = new Instruction[] { new VariableInstruction(InstructionConstants.OP_ALOAD_0), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 10), new SimpleInstruction(InstructionConstants.OP_ARETURN), }; private final ClassPool programClassPool; private final ClassPool libraryClassPool; private final WarningPrinter missingNotePrinter; private final WarningPrinter dependencyWarningPrinter; private final WarningPrinter notePrinter; private final StringMatcher noteExceptionMatcher; private final InstructionSequenceMatcher constantClassForNameMatcher = new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, CONSTANT_CLASS_FOR_NAME_INSTRUCTIONS); private final InstructionSequenceMatcher classForNameCastMatcher = new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, CLASS_FOR_NAME_CAST_INSTRUCTIONS); private final InstructionSequenceMatcher dotClassJavacMatcher = new InstructionSequenceMatcher(DOT_CLASS_JAVAC_CONSTANTS, DOT_CLASS_JAVAC_INSTRUCTIONS); private final InstructionSequenceMatcher dotClassJikesMatcher = new InstructionSequenceMatcher(DOT_CLASS_JIKES_CONSTANTS, DOT_CLASS_JIKES_INSTRUCTIONS); private final InstructionSequenceMatcher dotClassJavacImplementationMatcher = new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, DOT_CLASS_JAVAC_IMPLEMENTATION_INSTRUCTIONS); private final InstructionSequenceMatcher dotClassJikesImplementationMatcher = new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, DOT_CLASS_JIKES_IMPLEMENTATION_INSTRUCTIONS); private final InstructionSequenceMatcher dotClassJikesImplementationMatcher2 = new InstructionSequenceMatcher(CLASS_FOR_NAME_CONSTANTS, DOT_CLASS_JIKES_IMPLEMENTATION_INSTRUCTIONS2); // A field acting as a return variable for the visitors. private boolean isClassForNameInvocation; /** * Creates a new DynamicClassReferenceInitializer that optionally prints * warnings and notes, with optional class specifications for which never * to print notes. */ public DynamicClassReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter missingNotePrinter, WarningPrinter dependencyWarningPrinter, WarningPrinter notePrinter, StringMatcher noteExceptionMatcher) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; this.missingNotePrinter = missingNotePrinter; this.dependencyWarningPrinter = dependencyWarningPrinter; this.notePrinter = notePrinter; this.noteExceptionMatcher = noteExceptionMatcher; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { // Try to match the Class.forName("SomeClass") construct. instruction.accept(clazz, method, codeAttribute, offset, constantClassForNameMatcher); // Did we find a match? if (constantClassForNameMatcher.isMatching()) { // Fill out the matched string constant. clazz.constantPoolEntryAccept(constantClassForNameMatcher.matchedConstantIndex(X), this); // Don't look for the dynamic construct. classForNameCastMatcher.reset(); } // Try to match the (SomeClass)Class.forName(someName).newInstance() // construct. instruction.accept(clazz, method, codeAttribute, offset, classForNameCastMatcher); // Did we find a match? if (classForNameCastMatcher.isMatching()) { // Print out a note about the construct. clazz.constantPoolEntryAccept(classForNameCastMatcher.matchedConstantIndex(X), this); } // Try to match the javac .class construct. instruction.accept(clazz, method, codeAttribute, offset, dotClassJavacMatcher); // Did we find a match? if (dotClassJavacMatcher.isMatching() && isDotClassMethodref(clazz, dotClassJavacMatcher.matchedConstantIndex(0))) { // Fill out the matched string constant. clazz.constantPoolEntryAccept(dotClassJavacMatcher.matchedConstantIndex(X), this); } // Try to match the jikes .class construct. instruction.accept(clazz, method, codeAttribute, offset, dotClassJikesMatcher); // Did we find a match? if (dotClassJikesMatcher.isMatching() && isDotClassMethodref(clazz, dotClassJikesMatcher.matchedConstantIndex(0))) { // Fill out the matched string constant. clazz.constantPoolEntryAccept(dotClassJikesMatcher.matchedConstantIndex(X), this); } } // Implementations for ConstantVisitor. /** * Fills out the link to the referenced class. */ public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Save a reference to the corresponding class. String externalClassName = stringConstant.getString(clazz); String internalClassName = ClassUtil.internalClassName( ClassUtil.externalBaseType(externalClassName)); stringConstant.referencedClass = findClass(clazz.getName(), internalClassName); } /** * Prints out a note about the class cast to this class, if applicable. */ public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Print out a note about the class cast. if (noteExceptionMatcher == null || !noteExceptionMatcher.matches(classConstant.getName(clazz))) { notePrinter.print(clazz.getName(), classConstant.getName(clazz), "Note: " + ClassUtil.externalClassName(clazz.getName()) + " calls '(" + ClassUtil.externalClassName(classConstant.getName(clazz)) + ")Class.forName(variable).newInstance()'"); } } /** * Checks whether the referenced method is a .class method. */ public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { String methodType = methodrefConstant.getType(clazz); // Do the method's class and type match? if (methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC) || methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES)) { String methodName = methodrefConstant.getName(clazz); // Does the method's name match one of the special names? isClassForNameInvocation = methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_DOT_CLASS_JAVAC) || methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_DOT_CLASS_JIKES); if (isClassForNameInvocation) { return; } String className = methodrefConstant.getClassName(clazz); // Note that we look for the class by name, since the referenced // class has not been initialized yet. Clazz referencedClass = programClassPool.getClass(className); if (referencedClass != null) { // Check if the code of the referenced method is .class code. // Note that we look for the method by name and type, since the // referenced method has not been initialized yet. referencedClass.methodAccept(methodName, methodType, new AllAttributeVisitor(this)); } } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Check whether this is class$(String), as generated by javac, or // class(String, boolean), as generated by jikes, or an optimized // version. isClassForNameInvocation = isDotClassMethodCode(clazz, method, codeAttribute, dotClassJavacImplementationMatcher, 5) || isDotClassMethodCode(clazz, method, codeAttribute, dotClassJikesImplementationMatcher, 12) || isDotClassMethodCode(clazz, method, codeAttribute, dotClassJikesImplementationMatcher2, 8); } // Small utility methods. /** * Returns whether the given method reference corresponds to a .class * method, as generated by javac or by jikes. */ private boolean isDotClassMethodref(Clazz clazz, int methodrefConstantIndex) { isClassForNameInvocation = false; // Check if the code of the referenced method is .class code. clazz.constantPoolEntryAccept(methodrefConstantIndex, this); return isClassForNameInvocation; } /** * Returns whether the first whether the first instructions of the * given code attribute match with the given instruction matcher. */ private boolean isDotClassMethodCode(Clazz clazz, Method method, CodeAttribute codeAttribute, InstructionSequenceMatcher codeMatcher, int codeLength) { // Check the minimum code length. if (codeAttribute.u4codeLength < codeLength) { return false; } // Check the actual instructions. codeMatcher.reset(); codeAttribute.instructionsAccept(clazz, method, 0, codeLength, codeMatcher); return codeMatcher.isMatching(); } /** * Returns the class with the given name, either for the program class pool * or from the library class pool, or null if it can't be found. */ private Clazz findClass(String referencingClassName, String name) { // Is it an array type? if (ClassUtil.isInternalArrayType(name)) { // Ignore any primitive array types. if (!ClassUtil.isInternalClassType(name)) { return null; } // Strip the array part. name = ClassUtil.internalClassNameFromClassType(name); } // First look for the class in the program class pool. Clazz clazz = programClassPool.getClass(name); // Otherwise look for the class in the library class pool. if (clazz == null) { clazz = libraryClassPool.getClass(name); if (clazz == null && missingNotePrinter != null) { // We didn't find the superclass or interface. Print a note. missingNotePrinter.print(referencingClassName, name, "Note: " + ClassUtil.externalClassName(referencingClassName) + ": can't find dynamically referenced class " + ClassUtil.externalClassName(name)); } } else if (dependencyWarningPrinter != null) { // The superclass or interface was found in the program class pool. // Print a warning. dependencyWarningPrinter.print(referencingClassName, name, "Warning: library class " + ClassUtil.externalClassName(referencingClassName) + " depends dynamically on program class " + ClassUtil.externalClassName(name)); } return clazz; } } proguard4.8/src/proguard/classfile/util/SimplifiedVisitor.java0000644000175000017500000006713611736333524023451 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.constant.*; import proguard.classfile.instruction.*; /** * This abstract utility class allows to implement various visitor interfaces * with simplified methods. The provided methods delegate to other versions * with fewer arguments or more general arguments. * * @author Eric Lafortune * @noinspection AbstractClassWithoutAbstractMethods */ public abstract class SimplifiedVisitor { // Simplifications for ClassVisitor. /** * Visits any type of class member of the given class. */ public void visitAnyClass(Clazz clazz) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } public void visitProgramClass(ProgramClass programClass) { visitAnyClass(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { visitAnyClass(libraryClass); } // Simplifications for MemberVisitor. /** * Visits any type of class member of the given class. */ public void visitAnyMember(Clazz clazz, Member member) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } /** * Visits any type of class member of the given program class. */ public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { visitAnyMember(programClass, programMember); } public void visitProgramField(ProgramClass programClass, ProgramField programField) { visitProgramMember(programClass, programField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { visitProgramMember(programClass, programMethod); } /** * Visits any type of class member of the given library class. */ public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) { visitAnyMember(libraryClass, libraryMember); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { visitLibraryMember(libraryClass, libraryField); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { visitLibraryMember(libraryClass, libraryMethod); } // Simplifications for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { visitAnyConstant(clazz, integerConstant); } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { visitAnyConstant(clazz, longConstant); } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { visitAnyConstant(clazz, floatConstant); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { visitAnyConstant(clazz, doubleConstant); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { visitAnyConstant(clazz, stringConstant); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { visitAnyConstant(clazz, utf8Constant); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { visitAnyConstant(clazz, invokeDynamicConstant); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { visitAnyConstant(clazz, methodHandleConstant); } /** * Visits any type of RefConstant of the given class. */ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { visitAnyConstant(clazz, refConstant); } public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { visitAnyRefConstant(clazz, fieldrefConstant); } /** * Visits any type of method RefConstant of the given class. */ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) { visitAnyRefConstant(clazz, refConstant); } public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) { visitAnyMethodrefConstant(clazz, interfaceMethodrefConstant); } public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { visitAnyMethodrefConstant(clazz, methodrefConstant); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { visitAnyConstant(clazz, classConstant); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { visitAnyConstant(clazz, methodTypeConstant); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { visitAnyConstant(clazz, nameAndTypeConstant); } // Simplifications for AttributeVisitor. /** * Visit any type of attribute. */ public void visitAnyAttribute(Clazz clazz, Attribute attribute) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { visitAnyAttribute(clazz, unknownAttribute); } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { visitAnyAttribute(clazz, bootstrapMethodsAttribute); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { visitAnyAttribute(clazz, sourceFileAttribute); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { visitAnyAttribute(clazz, sourceDirAttribute); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { visitAnyAttribute(clazz, innerClassesAttribute); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { visitAnyAttribute(clazz, enclosingMethodAttribute); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { visitAnyAttribute(clazz, deprecatedAttribute); } /** * Visits the given DeprecatedAttribute of any type of class member. */ public void visitDeprecatedAttribute(Clazz clazz, Member member, DeprecatedAttribute deprecatedAttribute) { visitDeprecatedAttribute(clazz, deprecatedAttribute); } public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute) { visitDeprecatedAttribute(clazz, (Member)field, deprecatedAttribute); } public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute) { visitDeprecatedAttribute(clazz, (Member)method, deprecatedAttribute); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { visitAnyAttribute(clazz, syntheticAttribute); } /** * Visits the given SyntheticAttribute of any type of class member. */ public void visitSyntheticAttribute(Clazz clazz, Member member, SyntheticAttribute syntheticAttribute) { visitSyntheticAttribute(clazz, syntheticAttribute); } public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute) { visitSyntheticAttribute(clazz, (Member)field, syntheticAttribute); } public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute) { visitSyntheticAttribute(clazz, (Member)method, syntheticAttribute); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { visitAnyAttribute(clazz, signatureAttribute); } /** * Visits the given SignatureAttribute of any type of class member. */ public void visitSignatureAttribute(Clazz clazz, Member member, SignatureAttribute signatureAttribute) { visitSignatureAttribute(clazz, signatureAttribute); } public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute signatureAttribute) { visitSignatureAttribute(clazz, (Member)field, signatureAttribute); } public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute) { visitSignatureAttribute(clazz, (Member)method, signatureAttribute); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { visitAnyAttribute(clazz, constantValueAttribute); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { visitAnyAttribute(clazz, exceptionsAttribute); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { visitAnyAttribute(clazz, codeAttribute); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { visitAnyAttribute(clazz, stackMapAttribute); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { visitAnyAttribute(clazz, stackMapTableAttribute); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { visitAnyAttribute(clazz, lineNumberTableAttribute); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { visitAnyAttribute(clazz, localVariableTableAttribute); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { visitAnyAttribute(clazz, localVariableTypeTableAttribute); } /** * Visits any type of AnnotationsAttribute of a class. */ public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { visitAnyAttribute(clazz, annotationsAttribute); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { visitAnyAnnotationsAttribute(clazz, runtimeVisibleAnnotationsAttribute); } /** * Visits the given RuntimeVisibleAnnotationsAttribute of any type of class member. */ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Member member, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { visitRuntimeVisibleAnnotationsAttribute(clazz, runtimeVisibleAnnotationsAttribute); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { visitRuntimeVisibleAnnotationsAttribute(clazz, (Member)field, runtimeVisibleAnnotationsAttribute); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { visitRuntimeVisibleAnnotationsAttribute(clazz, (Member)method, runtimeVisibleAnnotationsAttribute); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { visitAnyAnnotationsAttribute(clazz, runtimeInvisibleAnnotationsAttribute); } /** * Visits the given RuntimeInvisibleAnnotationsAttribute of any type of class member. */ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Member member, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { visitRuntimeInvisibleAnnotationsAttribute(clazz, runtimeInvisibleAnnotationsAttribute); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { visitRuntimeInvisibleAnnotationsAttribute(clazz, (Member)field, runtimeInvisibleAnnotationsAttribute); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { visitRuntimeInvisibleAnnotationsAttribute(clazz, (Member)method, runtimeInvisibleAnnotationsAttribute); } /** * Visits any type of ParameterAnnotationsAttribute. */ public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { visitAnyAttribute(clazz, parameterAnnotationsAttribute); } public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute) { visitAnyParameterAnnotationsAttribute(clazz, method, runtimeVisibleParameterAnnotationsAttribute); } public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute) { visitAnyParameterAnnotationsAttribute(clazz, method, runtimeInvisibleParameterAnnotationsAttribute); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { visitAnyAttribute(clazz, annotationDefaultAttribute); } // Simplifications for InstructionVisitor. /** * Visits any type of Instruction. */ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { visitAnyInstruction(clazz, method, codeAttribute, offset, simpleInstruction); } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { visitAnyInstruction(clazz, method, codeAttribute, offset, variableInstruction); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { visitAnyInstruction(clazz, method, codeAttribute, offset, constantInstruction); } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { visitAnyInstruction(clazz, method, codeAttribute, offset, branchInstruction); } /** * Visits either type of SwitchInstruction. */ public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) { visitAnyInstruction(clazz, method, codeAttribute, offset, switchInstruction); } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { visitAnySwitchInstruction(clazz, method, codeAttribute, offset, tableSwitchInstruction); } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { visitAnySwitchInstruction(clazz, method, codeAttribute, offset, lookUpSwitchInstruction); } // Simplifications for StackMapFrameVisitor. /** * Visits any type of VerificationType. */ public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } public void visitSameZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameZeroFrame sameZeroFrame) { visitAnyStackMapFrame(clazz, method, codeAttribute, offset, sameZeroFrame); } public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { visitAnyStackMapFrame(clazz, method, codeAttribute, offset, sameOneFrame); } public void visitLessZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LessZeroFrame lessZeroFrame) { visitAnyStackMapFrame(clazz, method, codeAttribute, offset, lessZeroFrame); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { visitAnyStackMapFrame(clazz, method, codeAttribute, offset, moreZeroFrame); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { visitAnyStackMapFrame(clazz, method, codeAttribute, offset, fullFrame); } // Simplifications for VerificationTypeVisitor. /** * Visits any type of VerificationType. */ public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } public void visitIntegerType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, IntegerType integerType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, integerType); } public void visitFloatType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FloatType floatType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, floatType); } public void visitLongType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LongType longType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, longType); } public void visitDoubleType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, DoubleType doubleType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, doubleType); } public void visitTopType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TopType topType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, topType); } public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, objectType); } public void visitNullType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, NullType nullType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, nullType); } public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, uninitializedType); } public void visitUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedThisType uninitializedThisType) { visitAnyVerificationType(clazz, method, codeAttribute, offset, uninitializedThisType); } public void visitStackIntegerType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, IntegerType integerType) { visitIntegerType(clazz, method, codeAttribute, offset, integerType); } public void visitStackFloatType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, FloatType floatType) { visitFloatType(clazz, method, codeAttribute, offset, floatType); } public void visitStackLongType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, LongType longType) { visitLongType(clazz, method, codeAttribute, offset, longType); } public void visitStackDoubleType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, DoubleType doubleType) { visitDoubleType(clazz, method, codeAttribute, offset, doubleType); } public void visitStackTopType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, TopType topType) { visitTopType(clazz, method, codeAttribute, offset, topType); } public void visitStackObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, ObjectType objectType) { visitObjectType(clazz, method, codeAttribute, offset, objectType); } public void visitStackNullType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, NullType nullType) { visitNullType(clazz, method, codeAttribute, offset, nullType); } public void visitStackUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, UninitializedType uninitializedType) { visitUninitializedType(clazz, method, codeAttribute, offset, uninitializedType); } public void visitStackUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, UninitializedThisType uninitializedThisType) { visitUninitializedThisType(clazz, method, codeAttribute, offset, uninitializedThisType); } public void visitVariablesIntegerType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, IntegerType integerType) { visitIntegerType(clazz, method, codeAttribute, offset, integerType); } public void visitVariablesFloatType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, FloatType floatType) { visitFloatType(clazz, method, codeAttribute, offset, floatType); } public void visitVariablesLongType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, LongType longType) { visitLongType(clazz, method, codeAttribute, offset, longType); } public void visitVariablesDoubleType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, DoubleType doubleType) { visitDoubleType(clazz, method, codeAttribute, offset, doubleType); } public void visitVariablesTopType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, TopType topType) { visitTopType(clazz, method, codeAttribute, offset, topType); } public void visitVariablesObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, ObjectType objectType) { visitObjectType(clazz, method, codeAttribute, offset, objectType); } public void visitVariablesNullType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, NullType nullType) { visitNullType(clazz, method, codeAttribute, offset, nullType); } public void visitVariablesUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, UninitializedType uninitializedType) { visitUninitializedType(clazz, method, codeAttribute, offset, uninitializedType); } public void visitVariablesUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int index, UninitializedThisType uninitializedThisType) { visitUninitializedThisType(clazz, method, codeAttribute, offset, uninitializedThisType); } // Simplifications for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } /** * Visits the given Annotation of any type of class member. */ public void visitAnnotation(Clazz clazz, Member member, Annotation annotation) { visitAnnotation(clazz, annotation); } public void visitAnnotation(Clazz clazz, Field field, Annotation annotation) { visitAnnotation(clazz, (Member)field, annotation); } public void visitAnnotation(Clazz clazz, Method method, Annotation annotation) { visitAnnotation(clazz, (Member)method, annotation); } public void visitAnnotation(Clazz clazz, Method method, int parameterIndex, Annotation annotation) { visitAnnotation(clazz, method, annotation); } // Simplifications for ElementValueVisitor. public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) { throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called"); } public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { visitAnyElementValue(clazz, annotation, constantElementValue); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { visitAnyElementValue(clazz, annotation, enumConstantElementValue); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { visitAnyElementValue(clazz, annotation, classElementValue); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { visitAnyElementValue(clazz, annotation, annotationElementValue); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { visitAnyElementValue(clazz, annotation, arrayElementValue); } } proguard4.8/src/proguard/classfile/util/ExternalTypeEnumeration.java0000644000175000017500000000564511736333524024634 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.ClassConstants; /** * An ExternalTypeEnumeration provides an enumeration of all * types listed in a given external descriptor string. The method name can * be retrieved separately. *

* A ExternalTypeEnumeration object can be reused for processing * different subsequent descriptors, by means of the setDescriptor * method. * * @author Eric Lafortune */ public class ExternalTypeEnumeration { private String descriptor; private int index; public ExternalTypeEnumeration(String descriptor) { setDescriptor(descriptor); } ExternalTypeEnumeration() { } void setDescriptor(String descriptor) { this.descriptor = descriptor; reset(); } public void reset() { index = descriptor.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN) + 1; if (index < 1) { throw new IllegalArgumentException("Missing opening parenthesis in descriptor ["+descriptor+"]"); } } public boolean hasMoreTypes() { return index < descriptor.length() - 1; } public String nextType() { int startIndex = index; // Find the next separating comma. index = descriptor.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_SEPARATOR, startIndex); // Otherwise find the closing parenthesis. if (index < 0) { index = descriptor.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_CLOSE, startIndex); if (index < 0) { throw new IllegalArgumentException("Missing closing parenthesis in descriptor ["+descriptor+"]"); } } return descriptor.substring(startIndex, index++).trim(); } public String methodName() { return descriptor.substring(0, descriptor.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN)).trim(); } } proguard4.8/src/proguard/classfile/util/DescriptorClassEnumeration.java0000644000175000017500000001606511736333524025312 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.ClassConstants; import java.util.Stack; /** * A DescriptorClassEnumeration provides an enumeration of all * classes mentioned in a given descriptor or signature. * * @author Eric Lafortune */ public class DescriptorClassEnumeration { private String descriptor; private int index; private int nestingLevel; private boolean isInnerClassName; private String accumulatedClassName; private Stack accumulatedClassNames; /** * Creates a new DescriptorClassEnumeration for the given descriptor. */ public DescriptorClassEnumeration(String descriptor) { this.descriptor = descriptor; } /** * Returns the number of classes contained in the descriptor. This * is the number of class names that the enumeration will return. */ public int classCount() { int count = 0; nextFluff(); while (hasMoreClassNames()) { count++; nextClassName(); nextFluff(); } index = 0; return count; } /** * Returns whether the enumeration can provide more class names from the * descriptor. */ public boolean hasMoreClassNames() { return index < descriptor.length(); } /** * Returns the next fluff (surrounding class names) from the descriptor. */ public String nextFluff() { int fluffStartIndex = index; // Find the first token marking the start of a class name 'L' or '.'. loop: while (index < descriptor.length()) { switch (descriptor.charAt(index++)) { case ClassConstants.INTERNAL_TYPE_GENERIC_START: { nestingLevel++; // Make sure we have a stack. if (accumulatedClassNames == null) { accumulatedClassNames = new Stack(); } // Remember the accumulated class name. accumulatedClassNames.push(accumulatedClassName); break; } case ClassConstants.INTERNAL_TYPE_GENERIC_END: { nestingLevel--; // Return to the accumulated class name outside the // generic block. accumulatedClassName = (String)accumulatedClassNames.pop(); continue loop; } case ClassConstants.INTERNAL_TYPE_GENERIC_BOUND: { continue loop; } case ClassConstants.INTERNAL_TYPE_CLASS_START: { // We've found the start of an ordinary class name. nestingLevel += 2; isInnerClassName = false; break loop; } case ClassConstants.INTERNAL_TYPE_CLASS_END: { nestingLevel -= 2; break; } case ClassConstants.EXTERNAL_INNER_CLASS_SEPARATOR: { // We've found the start of an inner class name in a signature. isInnerClassName = true; break loop; } case ClassConstants.INTERNAL_TYPE_GENERIC_VARIABLE_START: { // We've found the start of a type identifier. Skip to the end. while (descriptor.charAt(index++) != ClassConstants.INTERNAL_TYPE_CLASS_END); break; } } if (nestingLevel == 1 && descriptor.charAt(index) != ClassConstants.INTERNAL_TYPE_GENERIC_END) { // We're at the start of a type parameter. Skip to the start // of the bounds. while (descriptor.charAt(index++) != ClassConstants.INTERNAL_TYPE_GENERIC_BOUND); } } return descriptor.substring(fluffStartIndex, index); } /** * Returns the next class name from the descriptor. */ public String nextClassName() { int classNameStartIndex = index; // Find the first token marking the end of a class name '<' or ';'. loop: while (true) { switch (descriptor.charAt(index)) { case ClassConstants.INTERNAL_TYPE_GENERIC_START: case ClassConstants.INTERNAL_TYPE_CLASS_END: case ClassConstants.EXTERNAL_INNER_CLASS_SEPARATOR: { break loop; } } index++; } String className = descriptor.substring(classNameStartIndex, index); // Recompose the inner class name if necessary. accumulatedClassName = isInnerClassName ? accumulatedClassName + ClassConstants.INTERNAL_INNER_CLASS_SEPARATOR + className : className; return accumulatedClassName; } /** * Returns whether the most recently returned class name was a recomposed * inner class name from a signature. */ public boolean isInnerClassName() { return isInnerClassName; } /** * A main method for testing the class name enumeration. */ public static void main(String[] args) { try { for (int index = 0; index < args.length; index++) { String descriptor = args[index]; System.out.println("Descriptor ["+descriptor+"]"); DescriptorClassEnumeration enumeration = new DescriptorClassEnumeration(descriptor); System.out.println(" Fluff: ["+enumeration.nextFluff()+"]"); while (enumeration.hasMoreClassNames()) { System.out.println(" Name: ["+enumeration.nextClassName()+"]"); System.out.println(" Fluff: ["+enumeration.nextFluff()+"]"); } } } catch (Exception ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/classfile/util/WarningPrinter.java0000644000175000017500000000677411736333524022756 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.util.*; import java.io.PrintStream; import java.util.List; /** * This class prints out and counts warnings. * * @author Eric Lafortune */ public class WarningPrinter { private final PrintStream printStream; private final StringMatcher classFilter; private int warningCount; /** * Creates a new WarningPrinter that prints to the System.err print stream. */ public WarningPrinter() { this(System.err); } /** * Creates a new WarningPrinter that prints to the given print stream. */ public WarningPrinter(PrintStream printStream) { this.printStream = printStream; this.classFilter = null; } /** * Creates a new WarningPrinter that prints to the given print stream, * except if the names of any involved classes matches the given filter. */ public WarningPrinter(PrintStream printStream, List classFilter) { this.printStream = printStream; this.classFilter = classFilter == null ? null : new ListParser(new ClassNameParser()).parse(classFilter); } /** * Prints out the given warning and increments the warning count, if * the given class name passes the class name filter. */ public void print(String className, String warning) { if (accepts(className)) { print(warning); } } /** * Returns whether the given class name passes the class name filter. */ public boolean accepts(String className) { return classFilter == null || !classFilter.matches(className); } /** * Prints out the given warning and increments the warning count, if * the given class names pass the class name filter. */ public void print(String className1, String className2, String warning) { if (accepts(className1, className2)) { print(warning); } } /** * Returns whether the given class names pass the class name filter. */ public boolean accepts(String className1, String className2) { return classFilter == null || !(classFilter.matches(className1) || classFilter.matches(className2)); } /** * Prints out the given warning and increments the warning count. */ private void print(String warning) { printStream.println(warning); warningCount++; } /** * Returns the number of warnings printed so far. */ public int getWarningCount() { return warningCount; } } proguard4.8/src/proguard/classfile/util/StringReferenceInitializer.java0000644000175000017500000000563311736333524025267 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This ConstantVisitor initializes any class references of all string constants * it visits. More specifically, it fills out the references of string constant * pool entries that happen to refer to a class in the program class pool or in * the library class pool. * * @author Eric Lafortune */ public class StringReferenceInitializer extends SimplifiedVisitor implements ConstantVisitor { private final ClassPool programClassPool; private final ClassPool libraryClassPool; /** * Creates a new StringReferenceInitializer. */ public StringReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { if (stringConstant.referencedClass == null) { // See if we can find the referenced class. stringConstant.referencedClass = findClass(ClassUtil.internalClassName( ClassUtil.externalBaseType(stringConstant.getString(clazz)))); } } // Small utility methods. /** * Returns the class with the given name, either for the program class pool * or from the library class pool, or null if it can't be found. */ private Clazz findClass(String name) { // First look for the class in the program class pool. Clazz clazz = programClassPool.getClass(name); // Otherwise look for the class in the library class pool. if (clazz == null) { clazz = libraryClassPool.getClass(name); } return clazz; } }proguard4.8/src/proguard/classfile/util/StringSharer.java0000644000175000017500000001320111736333524022377 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.util; import proguard.classfile.*; import proguard.classfile.attribute.Attribute; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor shares strings in the class files that it visits. * * @author Eric Lafortune */ public class StringSharer extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, AttributeVisitor { // A fields acting as an argument for the visitor methods. private String name; private String type; // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Replace name strings in the constant pool by shared strings. programClass.constantPoolEntriesAccept(this); // Replace attribute name strings in the constant pool by internalized // strings. programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { // Replace the super class name string by the shared name string. Clazz superClass = libraryClass.superClass; if (superClass != null) { libraryClass.superClassName = superClass.getName(); } // Replace the interface name strings by the shared name strings. if (libraryClass.interfaceNames != null) { String[] interfaceNames = libraryClass.interfaceNames; Clazz[] interfaceClasses = new Clazz[interfaceNames.length]; for (int index = 0; index < interfaceNames.length; index++) { // Keep a reference to the interface class. Clazz interfaceClass = interfaceClasses[index]; if (interfaceClass != null) { interfaceNames[index] = interfaceClass.getName(); } } } } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { Member referencedMember = stringConstant.referencedMember; if (referencedMember != null) { Clazz referencedClass = stringConstant.referencedClass; // Put the actual class member's name in the class pool. name = referencedMember.getName(referencedClass); clazz.constantPoolEntryAccept(stringConstant.u2stringIndex, this); } } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { Member referencedMember = refConstant.referencedMember; if (referencedMember != null) { Clazz referencedClass = refConstant.referencedClass; // Put the actual class member's name and type strings in the class // pool. name = referencedMember.getName(referencedClass); type = referencedMember.getDescriptor(referencedClass); clazz.constantPoolEntryAccept(refConstant.u2nameAndTypeIndex, this); } } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { if (name != null) { // Put the actual class member's name and type strings in the class // pool. clazz.constantPoolEntryAccept(nameAndTypeConstant.u2nameIndex, this); name = type; clazz.constantPoolEntryAccept(nameAndTypeConstant.u2descriptorIndex, this); } } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { Clazz referencedClass = classConstant.referencedClass; if (referencedClass != null) { // Put the actual class's name string in the class pool. name = referencedClass.getName(); clazz.constantPoolEntryAccept(classConstant.u2nameIndex, this); } } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { // Do we have a new string to put into this constant? if (name != null) { // Replace the string, if it's actually the same. if (name.equals(utf8Constant.getString())) { utf8Constant.setString(name); } name = null; } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) { // Put the internalized attribute's name string in the class pool. name = attribute.getAttributeName(clazz).intern(); clazz.constantPoolEntryAccept(attribute.u2attributeNameIndex, this); } } proguard4.8/src/proguard/classfile/visitor/0000775000175000017500000000000011760503005017636 5ustar ericericproguard4.8/src/proguard/classfile/visitor/package.html0000644000175000017500000000437311736333524022136 0ustar ericeric This package contains interfaces and classes for processing class files from the {@link proguard.classfile proguard.classfile} package using the visitor pattern. Cfr., for instance, "Design Patterns, Elements of Reusable OO Software", by Gamma, Helm, Johnson, and Vlissider.

Why the visitor pattern? Class files frequently contain lists of elements of various mixed types: class items, constant pool entries, attributes,... These lists and types are largely fixed; they won't change much in future releases of the Java class file specifications. On the other hand, the kinds of operations that we may wish to perform on the class files may change and expand. We want to separate the objects and the operations performed upon them. This is a good place to use the visitor pattern.

Visitor interfaces avoid having to do series of instanceof tests on the elements of a list, followed by type casts and the proper operations. Every list element is a visitor accepter. When its accept method is called by a visitor, it calls its corresponding visitX method in the visitor, passing itself as an argument. This technique is called double-dispatch.

As already mentioned, the main advantage is avoiding lots of instanceof tests and type casts. Also, implementing a visitor interface ensures you're handling all possible visitor accepter types. Each type has its own method, which you simply have to implement.

A disadvantage is that the visitor methods always get the same names, specified by the visitor interface. These names aren't descriptive at all, making code harder to read. It's the visitor classes that describe the operations now.

Also, the visitor methods always have the same parameters and return values, as specified by the visitor interfaces. Passing additional parameters is done by means of extra fields in the visitor, which is somewhat of a kludge.

Because objects (the visitor accepters) and the operations performed upon them (the visitors) are now separated, it becomes harder to associate some state with the objects. For convenience, we always provide an extra visitor info field in visitor accepters, in which visitors can put any temporary information they want. proguard4.8/src/proguard/classfile/visitor/MemberCounter.java0000644000175000017500000000367111736333524023267 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This MemberVisitor counts the number of class members that have been visited. * * @author Eric Lafortune */ public class MemberCounter implements MemberVisitor { private int count; /** * Returns the number of class members that has been visited so far. */ public int getCount() { return count; } // Implementations for MemberVisitor. public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { count++; } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { count++; } public void visitProgramField(ProgramClass programClass, ProgramField programField) { count++; } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { count++; } } proguard4.8/src/proguard/classfile/visitor/MemberToClassVisitor.java0000644000175000017500000000503411736333524024573 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This MemberVisitor delegates all visits to a given ClassVisitor. * The latter visits the class of each visited class member, although * never twice in a row. * * @author Eric Lafortune */ public class MemberToClassVisitor implements MemberVisitor { private final ClassVisitor classVisitor; private Clazz lastVisitedClass; public MemberToClassVisitor(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (!programClass.equals(lastVisitedClass)) { classVisitor.visitProgramClass(programClass); lastVisitedClass = programClass; } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (!programClass.equals(lastVisitedClass)) { classVisitor.visitProgramClass(programClass); lastVisitedClass = programClass; } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (!libraryClass.equals(lastVisitedClass)) { classVisitor.visitLibraryClass(libraryClass); lastVisitedClass = libraryClass; } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (!libraryClass.equals(lastVisitedClass)) { classVisitor.visitLibraryClass(libraryClass); lastVisitedClass = libraryClass; } } } proguard4.8/src/proguard/classfile/visitor/DotClassClassVisitor.java0000644000175000017500000000605711736333524024603 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor lets a given ClassVisitor visit all * classes involved in any .class constructs that it visits. *

* Note that before JDK 1.5, .class constructs are actually * compiled differently, using Class.forName constructs. * * @author Eric Lafortune */ public class DotClassClassVisitor extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor { private final ClassVisitor classVisitor; /** * Creates a new ClassHierarchyTraveler. * @param classVisitor the ClassVisitor to which visits will * be delegated. */ public DotClassClassVisitor(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { byte opcode = constantInstruction.opcode; // Could this instruction be a .class construct? if (opcode == InstructionConstants.OP_LDC || opcode == InstructionConstants.OP_LDC_W) { clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); } } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Visit the referenced class from the .class construct. classConstant.referencedClassAccept(classVisitor); } } proguard4.8/src/proguard/classfile/visitor/ImplementedClassFilter.java0000644000175000017500000000444511736333524025117 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, except for classes that extend or implement * a given class. * * @author Eric Lafortune */ public class ImplementedClassFilter implements ClassVisitor { private final Clazz implementedClass; private final ClassVisitor classVisitor; /** * Creates a new ImplementedClassFilter. * @param implementedClass the class whose implementations will not be * visited. * @param classVisitor the ClassVisitor to which visits will * be delegated. */ public ImplementedClassFilter(Clazz implementedClass, ClassVisitor classVisitor) { this.implementedClass = implementedClass; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (!programClass.extendsOrImplements(implementedClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (!libraryClass.extendsOrImplements(implementedClass)) { classVisitor.visitLibraryClass(libraryClass); } } }proguard4.8/src/proguard/classfile/visitor/SimilarMemberVisitor.java0000644000175000017500000001332711736333524024627 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This MemberVisitor lets a given MemberVisitor * visit all members that have the same name and type as the visited methods * in the class hierarchy of a given target class. * * @author Eric Lafortune */ public class SimilarMemberVisitor implements MemberVisitor { private final Clazz targetClass; private final boolean visitThisMember; private final boolean visitSuperMembers; private final boolean visitInterfaceMembers; private final boolean visitOverridingMembers; private final MemberVisitor memberVisitor; /** * Creates a new SimilarMemberVisitor. * @param targetClass the class in whose hierarchy to look for * the visited class members. * @param visitThisMember specifies whether to visit the class * members in the target class itself. * @param visitSuperMembers specifies whether to visit the class * members in the super classes of the target * class. * @param visitInterfaceMembers specifies whether to visit the class * members in the interface classes of the * target class. * @param visitOverridingMembers specifies whether to visit the class * members in the subclasses of the target * class. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public SimilarMemberVisitor(Clazz targetClass, boolean visitThisMember, boolean visitSuperMembers, boolean visitInterfaceMembers, boolean visitOverridingMembers, MemberVisitor memberVisitor) { this.targetClass = targetClass; this.visitThisMember = visitThisMember; this.visitSuperMembers = visitSuperMembers; this.visitInterfaceMembers = visitInterfaceMembers; this.visitOverridingMembers = visitOverridingMembers; this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { targetClass.hierarchyAccept(visitThisMember, visitSuperMembers, visitInterfaceMembers, visitOverridingMembers, new NamedFieldVisitor(programField.getName(programClass), programField.getDescriptor(programClass), memberVisitor)); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { targetClass.hierarchyAccept(visitThisMember, visitSuperMembers, visitInterfaceMembers, visitOverridingMembers, new NamedFieldVisitor(libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass), memberVisitor)); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { targetClass.hierarchyAccept(visitThisMember, visitSuperMembers, visitInterfaceMembers, visitOverridingMembers, new NamedMethodVisitor(programMethod.getName(programClass), programMethod.getDescriptor(programClass), memberVisitor)); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { targetClass.hierarchyAccept(visitThisMember, visitSuperMembers, visitInterfaceMembers, visitOverridingMembers, new NamedMethodVisitor(libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass), memberVisitor)); } }proguard4.8/src/proguard/classfile/visitor/MemberAccessFilter.java0000644000175000017500000001036011736333524024210 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when the visited member has the proper * access flags. *

* If conflicting access flags (public/private/protected) are specified, * having one of them set will be considered sufficient. * * @see ClassConstants * * @author Eric Lafortune */ public class MemberAccessFilter implements MemberVisitor { // A mask of conflicting access flags. These are interpreted in a special // way if more of them are required at the same time. In that case, one // of them being set is sufficient. private static final int ACCESS_MASK = ClassConstants.INTERNAL_ACC_PUBLIC | ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_PROTECTED; private final int requiredSetAccessFlags; private final int requiredUnsetAccessFlags; private final int requiredOneSetAccessFlags; private final MemberVisitor memberVisitor; /** * Creates a new MemberAccessFilter. * @param requiredSetAccessFlags the class access flags that should be * set. * @param requiredUnsetAccessFlags the class access flags that should be * unset. * @param memberVisitor the MemberVisitor to * which visits will be delegated. */ public MemberAccessFilter(int requiredSetAccessFlags, int requiredUnsetAccessFlags, MemberVisitor memberVisitor) { this.requiredSetAccessFlags = requiredSetAccessFlags & ~ACCESS_MASK; this.requiredUnsetAccessFlags = requiredUnsetAccessFlags; this.requiredOneSetAccessFlags = requiredSetAccessFlags & ACCESS_MASK; this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (accepted(programField.getAccessFlags())) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (accepted(programMethod.getAccessFlags())) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (accepted(libraryField.getAccessFlags())) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (accepted(libraryMethod.getAccessFlags())) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } // Small utility methods. private boolean accepted(int accessFlags) { return (requiredSetAccessFlags & ~accessFlags) == 0 && (requiredUnsetAccessFlags & accessFlags) == 0 && (requiredOneSetAccessFlags == 0 || (requiredOneSetAccessFlags & accessFlags) != 0); } } proguard4.8/src/proguard/classfile/visitor/VariableMemberVisitor.java0000644000175000017500000000503211736333524024746 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This MemberVisitor delegates all method calls to a MemberVisitor * that can be changed at any time. * * @author Eric Lafortune */ public class VariableMemberVisitor implements MemberVisitor { private MemberVisitor memberVisitor; public VariableMemberVisitor() { this(null); } public VariableMemberVisitor(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } public void setMemberVisitor(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } public MemberVisitor getMemberVisitor() { return memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (memberVisitor != null) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (memberVisitor != null) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (memberVisitor != null) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (memberVisitor != null) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } } proguard4.8/src/proguard/classfile/visitor/SubclassTraveler.java0000644000175000017500000000344311736333524024001 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor lets a given ClassVisitor * travel to direct subclasses of the visited class. * * @author Eric Lafortune */ public class SubclassTraveler implements ClassVisitor { private final ClassVisitor classVisitor; /** * Creates a new ClassHierarchyTraveler. * @param classVisitor the ClassVisitor to * which visits will be delegated. */ public SubclassTraveler(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.subclassesAccept(classVisitor); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.subclassesAccept(classVisitor); } }proguard4.8/src/proguard/classfile/visitor/ExceptionRangeFilter.java0000644000175000017500000000510211736333524024570 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.ExceptionInfoVisitor; /** * This ExceptionInfoVisitor delegates its visits to another given * ExceptionInfoVisitor, but only when the visited exception * overlaps with the given instruction range. * * @author Eric Lafortune */ public class ExceptionRangeFilter implements ExceptionInfoVisitor { private final int startOffset; private final int endOffset; private final ExceptionInfoVisitor exceptionInfoVisitor; /** * Creates a new ExceptionRangeFilter. * @param startOffset the start offset of the instruction range. * @param endOffset the end offset of the instruction range. * @param exceptionInfoVisitor the ExceptionInfoVisitor to which visits * will be delegated. */ public ExceptionRangeFilter(int startOffset, int endOffset, ExceptionInfoVisitor exceptionInfoVisitor) { this.startOffset = startOffset; this.endOffset = endOffset; this.exceptionInfoVisitor = exceptionInfoVisitor; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { if (exceptionInfo.isApplicable(startOffset, endOffset)) { exceptionInfoVisitor.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo); } } } proguard4.8/src/proguard/classfile/visitor/ExceptionOffsetFilter.java0000644000175000017500000000452411736333524024771 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.ExceptionInfoVisitor; /** * This ExceptionInfoVisitor delegates its visits to another given * ExceptionInfoVisitor, but only when the visited exception * covers the instruction at the given offset. * * @author Eric Lafortune */ public class ExceptionOffsetFilter implements ExceptionInfoVisitor { private final int instructionOffset; private final ExceptionInfoVisitor exceptionInfoVisitor; /** * Creates a new ExceptionOffsetFilter. * @param instructionOffset the instruction offset. * @param exceptionInfoVisitor the ExceptionInfoVisitor to which visits * will be delegated. */ public ExceptionOffsetFilter(int instructionOffset, ExceptionInfoVisitor exceptionInfoVisitor) { this.instructionOffset = instructionOffset; this.exceptionInfoVisitor = exceptionInfoVisitor; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { if (exceptionInfo.isApplicable(instructionOffset)) { exceptionInfoVisitor.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo); } } } proguard4.8/src/proguard/classfile/visitor/ClassVersionSetter.java0000644000175000017500000000474611736333524024326 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import java.util.Set; /** * This ClassVisitor sets the version number of the program classes * that it visits. * * @author Eric Lafortune */ public class ClassVersionSetter implements ClassVisitor { private final int classVersion; private final Set newerClassVersions; /** * Creates a new ClassVersionSetter. * @param classVersion the class version number. */ public ClassVersionSetter(int classVersion) { this(classVersion, null); } /** * Creates a new ClassVersionSetter that also stores any newer class version * numbers that it encounters while visiting program classes. * @param classVersion the class version number. * @param newerClassVersions the Set in which newer class * version numbers can be collected. */ public ClassVersionSetter(int classVersion, Set newerClassVersions) { this.classVersion = classVersion; this.newerClassVersions = newerClassVersions; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (programClass.u4version > classVersion && newerClassVersions != null) { newerClassVersions.add(new Integer(programClass.u4version)); } programClass.u4version = classVersion; } public void visitLibraryClass(LibraryClass libraryClass) { // Library classes don't have version numbers. } } proguard4.8/src/proguard/classfile/visitor/ProgramMemberFilter.java0000644000175000017500000000435011736333524024420 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when visiting members of program * classes. * * @author Eric Lafortune */ public class ProgramMemberFilter implements MemberVisitor { private final MemberVisitor memberVisitor; /** * Creates a new ProgramMemberFilter. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public ProgramMemberFilter(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { memberVisitor.visitProgramField(programClass, programField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { memberVisitor.visitProgramMethod(programClass, programMethod); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { // Don't delegate visits to library members. } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { // Don't delegate visits to library members. } } proguard4.8/src/proguard/classfile/visitor/ClassHierarchyTraveler.java0000644000175000017500000000655011736333524025130 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor lets a given ClassVisitor * optionally travel to the visited class, its superclass, its interfaces, and * its subclasses. * * @author Eric Lafortune */ public class ClassHierarchyTraveler implements ClassVisitor { private final boolean visitThisClass; private final boolean visitSuperClass; private final boolean visitInterfaces; private final boolean visitSubclasses; private final ClassVisitor classVisitor; /** * Creates a new ClassHierarchyTraveler. * @param visitThisClass specifies whether to visit the originally visited * classes. * @param visitSuperClass specifies whether to visit the super classes of * the visited classes. * @param visitInterfaces specifies whether to visit the interfaces of * the visited classes. * @param visitSubclasses specifies whether to visit the subclasses of * the visited classes. * @param classVisitor the ClassVisitor to * which visits will be delegated. */ public ClassHierarchyTraveler(boolean visitThisClass, boolean visitSuperClass, boolean visitInterfaces, boolean visitSubclasses, ClassVisitor classVisitor) { this.visitThisClass = visitThisClass; this.visitSuperClass = visitSuperClass; this.visitInterfaces = visitInterfaces; this.visitSubclasses = visitSubclasses; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.hierarchyAccept(visitThisClass, visitSuperClass, visitInterfaces, visitSubclasses, classVisitor); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.hierarchyAccept(visitThisClass, visitSuperClass, visitInterfaces, visitSubclasses, classVisitor); } } proguard4.8/src/proguard/classfile/visitor/ExceptClassesFilter.java0000644000175000017500000000500611736333524024426 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, except for classes are in a given list. * * @author Eric Lafortune */ public class ExceptClassesFilter implements ClassVisitor { private final Clazz[] exceptClasses; private final ClassVisitor classVisitor; /** * Creates a new ExceptClassesFilter. * @param exceptClasses the classes that will not be visited. * @param classVisitor the ClassVisitor to which visits will * be delegated. */ public ExceptClassesFilter(Clazz[] exceptClasses, ClassVisitor classVisitor) { this.exceptClasses = exceptClasses; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (!present(programClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (!present(libraryClass)) { classVisitor.visitLibraryClass(libraryClass); } } // Small utility methods. private boolean present(Clazz clazz) { if (exceptClasses == null) { return false; } for (int index = 0; index < exceptClasses.length; index++) { if (exceptClasses[index].equals(clazz)) { return true; } } return false; } }proguard4.8/src/proguard/classfile/visitor/AllClassVisitor.java0000644000175000017500000000265111736333524023573 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.ClassPool; /** * This ClassPoolVisitor lets a given ClassVisitor visit all Clazz * objects of the class pools it visits. * * @author Eric Lafortune */ public class AllClassVisitor implements ClassPoolVisitor { private final ClassVisitor classVisitor; public AllClassVisitor(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } public void visitClassPool(ClassPool classPool) { classPool.classesAccept(classVisitor); } } proguard4.8/src/proguard/classfile/visitor/MethodImplementationTraveler.java0000644000175000017500000001263411736333524026352 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; /** * This MemberVisitor lets a given MemberVisitor * travel to all concrete and abstract implementations of the visited methods * in their class hierarchies. * * @author Eric Lafortune */ public class MethodImplementationTraveler extends SimplifiedVisitor implements MemberVisitor { private final boolean visitThisMethod; private final boolean visitSuperMethods; private final boolean visitInterfaceMethods; private final boolean visitOverridingMethods; private final MemberVisitor memberVisitor; /** * Creates a new MethodImplementationTraveler. * @param visitThisMethod specifies whether to visit the originally * visited methods. * @param visitSuperMethods specifies whether to visit the method in * the super classes. * @param visitInterfaceMethods specifies whether to visit the method in * the interface classes. * @param visitOverridingMethods specifies whether to visit the method in * the subclasses. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public MethodImplementationTraveler(boolean visitThisMethod, boolean visitSuperMethods, boolean visitInterfaceMethods, boolean visitOverridingMethods, MemberVisitor memberVisitor) { this.visitThisMethod = visitThisMethod; this.visitSuperMethods = visitSuperMethods; this.visitInterfaceMethods = visitInterfaceMethods; this.visitOverridingMethods = visitOverridingMethods; this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (visitThisMethod) { programMethod.accept(programClass, memberVisitor); } if (!isSpecial(programClass, programMethod)) { programClass.hierarchyAccept(false, visitSuperMethods, visitInterfaceMethods, visitOverridingMethods, new NamedMethodVisitor(programMethod.getName(programClass), programMethod.getDescriptor(programClass), new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC, memberVisitor))); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (visitThisMethod) { libraryMethod.accept(libraryClass, memberVisitor); } if (!isSpecial(libraryClass, libraryMethod)) { libraryClass.hierarchyAccept(false, visitSuperMethods, visitInterfaceMethods, visitOverridingMethods, new NamedMethodVisitor(libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass), new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC, memberVisitor))); } } // Small utility methods. private boolean isSpecial(Clazz clazz, Method method) { return (method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC)) != 0 || method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT); } } proguard4.8/src/proguard/classfile/visitor/ReferencedClassVisitor.java0000644000175000017500000002122311736333524025121 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor, etc. * lets a given ClassVisitor visit all the referenced classes of the elements * that it visits. Only downstream elements are considered (in order to avoid * loops and repeated visits). * * @author Eric Lafortune */ public class ReferencedClassVisitor extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { private final ClassVisitor classVisitor; public ReferencedClassVisitor(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Visit the constant pool entries. programClass.constantPoolEntriesAccept(this); // Visit the fields and methods. programClass.fieldsAccept(this); programClass.methodsAccept(this); // Visit the attributes. programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { // Visit the superclass and interfaces. libraryClass.superClassAccept(classVisitor); libraryClass.interfacesAccept(classVisitor); // Visit the fields and methods. libraryClass.fieldsAccept(this); libraryClass.methodsAccept(this); } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { // Let the visitor visit the classes referenced in the descriptor string. programMember.referencedClassesAccept(classVisitor); // Visit the attributes. programMember.attributesAccept(programClass, this); } public void visitLibraryMember(LibraryClass programClass, LibraryMember libraryMember) { // Let the visitor visit the classes referenced in the descriptor string. libraryMember.referencedClassesAccept(classVisitor); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Let the visitor visit the class referenced in the string constant. stringConstant.referencedClassAccept(classVisitor); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { // Let the visitor visit the class referenced in the reference constant. refConstant.referencedClassAccept(classVisitor); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { // Let the visitor visit the class referenced in the reference constant. invokeDynamicConstant.referencedClassesAccept(classVisitor); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Let the visitor visit the class referenced in the class constant. classConstant.referencedClassAccept(classVisitor); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { // Let the visitor visit the class of the enclosing method. enclosingMethodAttribute.referencedClassAccept(classVisitor); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Visit the attributes of the code attribute. codeAttribute.attributesAccept(clazz, method, this); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Visit the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Visit the local variable types. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { // Let the visitor visit the classes referenced in the signature string. signatureAttribute.referencedClassesAccept(classVisitor); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Visit the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Visit the parameter annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Visit the default element value. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Let the visitor visit the class referenced in the local variable. localVariableInfo.referencedClassAccept(classVisitor); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { // Let the visitor visit the classes referenced in the local variable type. localVariableTypeInfo.referencedClassesAccept(classVisitor); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { // Let the visitor visit the classes referenced in the annotation. annotation.referencedClassesAccept(classVisitor); // Visit the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) {} public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { // Let the visitor visit the classes referenced in the constant element value. enumConstantElementValue.referencedClassesAccept(classVisitor); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { // Let the visitor visit the classes referenced in the class element value. classElementValue.referencedClassesAccept(classVisitor); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { // Visit the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } } proguard4.8/src/proguard/classfile/visitor/NamedClassVisitor.java0000644000175000017500000000276411736333524024114 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.ClassPool; /** * This class visits Clazz objects with the given name. * * @author Eric Lafortune */ public class NamedClassVisitor implements ClassPoolVisitor { private final ClassVisitor classVisitor; private final String name; public NamedClassVisitor(ClassVisitor classVisitor, String name) { this.classVisitor = classVisitor; this.name = name; } public void visitClassPool(ClassPool classPool) { classPool.classAccept(name, classVisitor); } } proguard4.8/src/proguard/classfile/visitor/AllMethodVisitor.java0000644000175000017500000000313711736333524023746 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor lets a given MemberVisitor visit all MethodMember * objects of the classes it visits. * * @author Eric Lafortune */ public class AllMethodVisitor implements ClassVisitor { private final MemberVisitor memberVisitor; public AllMethodVisitor(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.methodsAccept(memberVisitor); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.methodsAccept(memberVisitor); } } proguard4.8/src/proguard/classfile/visitor/ClassCleaner.java0000644000175000017500000001752711736333524023064 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.Constant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This ClassVisitor removes all visitor information of the * classes it visits. * * @author Eric Lafortune */ public class ClassCleaner extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, MemberVisitor, AttributeVisitor, ExceptionInfoVisitor, InnerClassesInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, AnnotationVisitor, ElementValueVisitor { // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { clean(programClass); programClass.constantPoolEntriesAccept(this); programClass.fieldsAccept(this); programClass.methodsAccept(this); programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { clean(libraryClass); libraryClass.fieldsAccept(this); libraryClass.methodsAccept(this); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) { clean(constant); } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { clean(programMember); programMember.attributesAccept(programClass, this); } public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) { clean(libraryMember); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) { clean(attribute); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { clean(innerClassesAttribute); innerClassesAttribute.innerClassEntriesAccept(clazz, this); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { clean(exceptionsAttribute); exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { clean(codeAttribute); codeAttribute.exceptionsAccept(clazz, method, this); codeAttribute.attributesAccept(clazz, method, this); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { clean(stackMapAttribute); stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { clean(stackMapTableAttribute); stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { clean(annotationsAttribute); annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { clean(parameterAnnotationsAttribute); parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { clean(annotationDefaultAttribute); annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { clean(innerClassesInfo); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { clean(exceptionInfo); } // Implementations for StackMapFrameVisitor. public void visitSameZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameZeroFrame sameZeroFrame) { clean(sameZeroFrame); } public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { clean(sameOneFrame); sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); } public void visitLessZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LessZeroFrame lessZeroFrame) { clean(lessZeroFrame); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { clean(moreZeroFrame); moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { clean(fullFrame); fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); } // Implementations for VerificationTypeVisitor. public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) { clean(verificationType); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { clean(annotation); annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) { clean(elementValue); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { clean(annotationElementValue); annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { clean(arrayElementValue); } // Small utility methods. private void clean(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(null); } } proguard4.8/src/proguard/classfile/visitor/MethodImplementationFilter.java0000644000175000017500000000441311736333524026007 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; /** * This MemberVisitor delegates its visits to methods to * another given MemberVisitor, but only when the visited * method may have implementations. * * @see Clazz#mayHaveImplementations(Method) * @author Eric Lafortune */ public class MethodImplementationFilter extends SimplifiedVisitor implements MemberVisitor { private final MemberVisitor memberVisitor; /** * Creates a new MethodImplementationFilter. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public MethodImplementationFilter(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (programClass.mayHaveImplementations(programMethod)) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (libraryClass.mayHaveImplementations(libraryMethod)) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } } proguard4.8/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java0000644000175000017500000000502211736333524026621 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.constant.ClassConstant; import proguard.classfile.util.SimplifiedVisitor; /** * This ConstantVisitor delegates its visits to class constants * to another given ConstantVisitor, except for classes that * extend or implement a given class. This exception includes the class itself. * * @author Eric Lafortune */ public class ImplementedClassConstantFilter extends SimplifiedVisitor implements ConstantVisitor { private final Clazz implementedClass; private final ConstantVisitor constantVisitor; /** * Creates a new ImplementedClassConstantFilter. * @param implementedClass the class whose implementations will not be * visited. * @param constantVisitor the ConstantVisitor to which visits * will be delegated. */ public ImplementedClassConstantFilter(Clazz implementedClass, ConstantVisitor constantVisitor) { this.implementedClass = implementedClass; this.constantVisitor = constantVisitor; } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { Clazz referencedClass = classConstant.referencedClass; if (referencedClass == null || !referencedClass.extendsOrImplements(implementedClass)) { constantVisitor.visitClassConstant(clazz, classConstant); } } }proguard4.8/src/proguard/classfile/visitor/ExceptClassFilter.java0000644000175000017500000000416611736333524024104 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, except for one given class. * * @author Eric Lafortune */ public class ExceptClassFilter implements ClassVisitor { private final Clazz exceptClass; private final ClassVisitor classVisitor; /** * Creates a new ClassNameFilter. * @param exceptClass the class that will not be visited. * @param classVisitor the ClassVisitor to which visits will * be delegated. */ public ExceptClassFilter(Clazz exceptClass, ClassVisitor classVisitor) { this.exceptClass = exceptClass; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (!programClass.equals(exceptClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (!libraryClass.equals(exceptClass)) { classVisitor.visitLibraryClass(libraryClass); } } }proguard4.8/src/proguard/classfile/visitor/ClassVisitor.java0000644000175000017500000000234211736333524023137 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This interface specifies the methods for a visitor of * Clazz objects. * * @author Eric Lafortune */ public interface ClassVisitor { public void visitProgramClass(ProgramClass programClass); public void visitLibraryClass(LibraryClass libraryClass); } proguard4.8/src/proguard/classfile/visitor/ClassPoolVisitor.java0000644000175000017500000000247511736333524024000 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.ClassPool; /** * This interface specifies the methods for a visitor of * ClassPool objects. Note that there is only a single * implementation of ClassPool, such that this interface * is not strictly necessary as a visitor. * * @author Eric Lafortune */ public interface ClassPoolVisitor { public void visitClassPool(ClassPool classPool); } proguard4.8/src/proguard/classfile/visitor/ClassPresenceFilter.java0000644000175000017500000000614311736333524024415 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to one of two * ClassVisitor instances, depending on whether the name of * the visited class file is present in a given ClassPool or not. * * @author Eric Lafortune */ public class ClassPresenceFilter implements ClassVisitor { private final ClassPool classPool; private final ClassVisitor presentClassVisitor; private final ClassVisitor missingClassVisitor; /** * Creates a new ClassPresenceFilter. * @param classPool the ClassPool in which the * presence will be tested. * @param presentClassVisitor the ClassVisitor to which visits * of present class files will be delegated. * @param missingClassVisitor the ClassVisitor to which visits * of missing class files will be delegated. */ public ClassPresenceFilter(ClassPool classPool, ClassVisitor presentClassVisitor, ClassVisitor missingClassVisitor) { this.classPool = classPool; this.presentClassVisitor = presentClassVisitor; this.missingClassVisitor = missingClassVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { ClassVisitor classFileVisitor = classFileVisitor(programClass); if (classFileVisitor != null) { classFileVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { ClassVisitor classFileVisitor = classFileVisitor(libraryClass); if (classFileVisitor != null) { classFileVisitor.visitLibraryClass(libraryClass); } } // Small utility methods. /** * Returns the appropriate ClassVisitor. */ private ClassVisitor classFileVisitor(Clazz clazz) { return classPool.getClass(clazz.getName()) != null ? presentClassVisitor : missingClassVisitor; } } proguard4.8/src/proguard/classfile/visitor/MultiMemberVisitor.java0000644000175000017500000000650411736333524024320 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This MemberVisitor delegates all visits to each MemberVisitor * in a given list. * * @author Eric Lafortune */ public class MultiMemberVisitor implements MemberVisitor { private static final int ARRAY_SIZE_INCREMENT = 5; private MemberVisitor[] memberVisitors; private int memberVisitorCount; public MultiMemberVisitor() { } public MultiMemberVisitor(MemberVisitor[] memberVisitors) { this.memberVisitors = memberVisitors; this.memberVisitorCount = memberVisitors.length; } public void addMemberVisitor(MemberVisitor memberVisitor) { ensureArraySize(); memberVisitors[memberVisitorCount++] = memberVisitor; } private void ensureArraySize() { if (memberVisitors == null) { memberVisitors = new MemberVisitor[ARRAY_SIZE_INCREMENT]; } else if (memberVisitors.length == memberVisitorCount) { MemberVisitor[] newMemberVisitors = new MemberVisitor[memberVisitorCount + ARRAY_SIZE_INCREMENT]; System.arraycopy(memberVisitors, 0, newMemberVisitors, 0, memberVisitorCount); memberVisitors = newMemberVisitors; } } public void visitProgramField(ProgramClass programClass, ProgramField programField) { for (int index = 0; index < memberVisitorCount; index++) { memberVisitors[index].visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { for (int index = 0; index < memberVisitorCount; index++) { memberVisitors[index].visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { for (int index = 0; index < memberVisitorCount; index++) { memberVisitors[index].visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { for (int index = 0; index < memberVisitorCount; index++) { memberVisitors[index].visitLibraryMethod(libraryClass, libraryMethod); } } } proguard4.8/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java0000644000175000017500000000457511736333524026455 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.ExceptionInfoVisitor; /** * This ExceptionInfoVisitor delegates its visits to another given * ExceptionInfoVisitor, but only when the visited exception * does not cover the instruction at the given offset. * * @author Eric Lafortune */ public class ExceptionExcludedOffsetFilter implements ExceptionInfoVisitor { private final int instructionOffset; private final ExceptionInfoVisitor exceptionInfoVisitor; /** * Creates a new ExceptionExcludedOffsetFilter. * @param instructionOffset the instruction offset. * @param exceptionInfoVisitor the ExceptionInfoVisitor to which visits * will be delegated. */ public ExceptionExcludedOffsetFilter(int instructionOffset, ExceptionInfoVisitor exceptionInfoVisitor) { this.instructionOffset = instructionOffset; this.exceptionInfoVisitor = exceptionInfoVisitor; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { if (!exceptionInfo.isApplicable(instructionOffset)) { exceptionInfoVisitor.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo); } } } proguard4.8/src/proguard/classfile/visitor/SimpleClassPrinter.java0000644000175000017500000001355411736333524024304 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.util.ClassUtil; import java.io.PrintStream; /** * This ClassVisitor and MemberVisitor * prints out the class names of the classes it visits, and the full class * member descriptions of the class members it visits. The names are printed * in a readable, Java-like format. The access modifiers can be included or not. * * @author Eric Lafortune */ public class SimpleClassPrinter implements ClassVisitor, MemberVisitor { private final boolean printAccessModifiers; private final PrintStream ps; /** * Creates a new SimpleClassPrinter that prints to * System.out, including the access modifiers. */ public SimpleClassPrinter() { this(true); } /** * Creates a new SimpleClassPrinter that prints to * System.out, with or without the access modifiers. */ public SimpleClassPrinter(boolean printAccessModifiers) { this(printAccessModifiers, System.out); } /** * Creates a new SimpleClassPrinter that prints to the given * PrintStream, with or without the access modifiers. */ public SimpleClassPrinter(boolean printAccessModifiers, PrintStream printStream) { this.printAccessModifiers = printAccessModifiers; this.ps = printStream; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { ps.println(ClassUtil.externalFullClassDescription( printAccessModifiers ? programClass.getAccessFlags() : 0, programClass.getName())); } public void visitLibraryClass(LibraryClass libraryClass) { ps.println(ClassUtil.externalFullClassDescription( printAccessModifiers ? libraryClass.getAccessFlags() : 0, libraryClass.getName())); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { ps.println(ClassUtil.externalFullClassDescription( printAccessModifiers ? programClass.getAccessFlags() : 0, programClass.getName()) + ": " + ClassUtil.externalFullFieldDescription( printAccessModifiers ? programField.getAccessFlags() : 0, programField.getName(programClass), programField.getDescriptor(programClass))); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { ps.println(ClassUtil.externalFullClassDescription( printAccessModifiers ? programClass.getAccessFlags() : 0, programClass.getName()) + ": " + ClassUtil.externalFullMethodDescription( programClass.getName(), printAccessModifiers ? programMethod.getAccessFlags() : 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass))); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { ps.println(ClassUtil.externalFullClassDescription( printAccessModifiers ? libraryClass.getAccessFlags() : 0, libraryClass.getName()) + ": " + ClassUtil.externalFullFieldDescription( printAccessModifiers ? libraryField.getAccessFlags() : 0, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass))); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { ps.println(ClassUtil.externalFullClassDescription( printAccessModifiers ? libraryClass.getAccessFlags() : 0, libraryClass.getName()) + ": " + ClassUtil.externalFullMethodDescription( libraryClass.getName(), printAccessModifiers ? libraryMethod.getAccessFlags() : 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass))); } } proguard4.8/src/proguard/classfile/visitor/ReferencedMemberVisitor.java0000644000175000017500000000450711736333524025271 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.Clazz; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This ConstantVisitor and ElementValueVisitor lets a given MemberVisitor * visit all the referenced class members of the elements that it visits. * * @author Eric Lafortune */ public class ReferencedMemberVisitor extends SimplifiedVisitor implements ConstantVisitor, ElementValueVisitor { private final MemberVisitor memberVisitor; public ReferencedMemberVisitor(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { stringConstant.referencedMemberAccept(memberVisitor); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { refConstant.referencedMemberAccept(memberVisitor); } // Implementations for ElementValueVisitor. public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) { elementValue.referencedMethodAccept(memberVisitor); } } proguard4.8/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java0000644000175000017500000000413311736333524027040 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.ExceptionInfoVisitor; /** * This ExceptionInfoVisitor lets a given * ConstantVisitor visit all catch class constants of exceptions * that it visits. * * @author Eric Lafortune */ public class ExceptionHandlerConstantVisitor implements ExceptionInfoVisitor { private final ConstantVisitor constantVisitor; /** * Creates a new ExceptionHandlerConstantVisitor. * @param constantVisitor the ConstantVisitor that will visit the catch * class constants. */ public ExceptionHandlerConstantVisitor(ConstantVisitor constantVisitor) { this.constantVisitor = constantVisitor; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { int catchType = exceptionInfo.u2catchType; if (catchType != 0) { clazz.constantPoolEntryAccept(catchType, constantVisitor); } } }proguard4.8/src/proguard/classfile/visitor/BottomClassFilter.java0000644000175000017500000000411611736333524024113 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, but only when visiting classes that don't * have any subclasses. * * @author Eric Lafortune */ public class BottomClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; /** * Creates a new ProgramClassFilter. * @param classVisitor the ClassVisitor to which visits * will be delegated. */ public BottomClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Is this a bottom class in the class hierarchy? if (programClass.subClasses == null) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { // Is this a bottom class in the class hierarchy? if (libraryClass.subClasses == null) { classVisitor.visitLibraryClass(libraryClass); } } } proguard4.8/src/proguard/classfile/visitor/ProgramClassFilter.java0000644000175000017500000000346711736333524024266 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, but only when visiting program classes. * * @author Eric Lafortune */ public class ProgramClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; /** * Creates a new ProgramClassFilter. * @param classVisitor the ClassVisitor to which visits * will be delegated. */ public ProgramClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { classVisitor.visitProgramClass(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { // Don't delegate visits to library classes. } } proguard4.8/src/proguard/classfile/visitor/MemberDescriptorFilter.java0000644000175000017500000000733611736333524025136 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.util.*; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when the visited member * has a descriptor that matches a given regular expression. * * @author Eric Lafortune */ public class MemberDescriptorFilter implements MemberVisitor { private final StringMatcher regularExpressionMatcher; private final MemberVisitor memberVisitor; /** * Creates a new MemberDescriptorFilter. * @param regularExpression the regular expression against which member * descriptors will be matched. * @param memberVisitor the MemberVisitor to which visits * will be delegated. */ public MemberDescriptorFilter(String regularExpression, MemberVisitor memberVisitor) { this(new ClassNameParser().parse(regularExpression), memberVisitor); } /** * Creates a new MemberDescriptorFilter. * @param regularExpressionMatcher the regular expression against which * member descriptors will be matched. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public MemberDescriptorFilter(StringMatcher regularExpressionMatcher, MemberVisitor memberVisitor) { this.regularExpressionMatcher = regularExpressionMatcher; this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (accepted(programField.getDescriptor(programClass))) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (accepted(programMethod.getDescriptor(programClass))) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (accepted(libraryField.getDescriptor(libraryClass))) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (accepted(libraryMethod.getDescriptor(libraryClass))) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } // Small utility methods. private boolean accepted(String name) { return regularExpressionMatcher.matches(name); } } proguard4.8/src/proguard/classfile/visitor/ClassAccessFilter.java0000644000175000017500000000555011736333524024053 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, but only when the visited class * has the proper access flags. * * @see ClassConstants * * @author Eric Lafortune */ public class ClassAccessFilter implements ClassVisitor { private final int requiredSetAccessFlags; private final int requiredUnsetAccessFlags; private final ClassVisitor classVisitor; /** * Creates a new ClassAccessFilter. * @param requiredSetAccessFlags the class access flags that should be * set. * @param requiredUnsetAccessFlags the class access flags that should be * unset. * @param classVisitor the ClassVisitor to * which visits will be delegated. */ public ClassAccessFilter(int requiredSetAccessFlags, int requiredUnsetAccessFlags, ClassVisitor classVisitor) { this.requiredSetAccessFlags = requiredSetAccessFlags; this.requiredUnsetAccessFlags = requiredUnsetAccessFlags; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (accepted(programClass.getAccessFlags())) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (accepted(libraryClass.getAccessFlags())) { classVisitor.visitLibraryClass(libraryClass); } } // Small utility methods. private boolean accepted(int accessFlags) { return (requiredSetAccessFlags & ~accessFlags) == 0 && (requiredUnsetAccessFlags & accessFlags) == 0; } } proguard4.8/src/proguard/classfile/visitor/NamedFieldVisitor.java0000644000175000017500000000360311736333524024063 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This class visits ProgramMember objects referring to fields, identified by * a name and descriptor pair. * * @author Eric Lafortune */ public class NamedFieldVisitor implements ClassVisitor { private final String name; private final String descriptor; private final MemberVisitor memberVisitor; public NamedFieldVisitor(String name, String descriptor, MemberVisitor memberVisitor) { this.name = name; this.descriptor = descriptor; this.memberVisitor = memberVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.fieldAccept(name, descriptor, memberVisitor); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.fieldAccept(name, descriptor, memberVisitor); } } proguard4.8/src/proguard/classfile/visitor/AllMemberVisitor.java0000644000175000017500000000327511736333524023740 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor lets a given MemberVisitor visit all Member * objects of the classes it visits. * * @author Eric Lafortune */ public class AllMemberVisitor implements ClassVisitor { private final MemberVisitor memberVisitor; public AllMemberVisitor(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.fieldsAccept(memberVisitor); programClass.methodsAccept(memberVisitor); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.fieldsAccept(memberVisitor); libraryClass.methodsAccept(memberVisitor); } } proguard4.8/src/proguard/classfile/visitor/ExceptionHandlerFilter.java0000644000175000017500000000522511736333524025117 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.ExceptionInfoVisitor; /** * This ExceptionInfoVisitor delegates its visits to another given * ExceptionInfoVisitor, but only when the visited exception * targets an instruction in the given range of offsets. * * @author Eric Lafortune */ public class ExceptionHandlerFilter implements ExceptionInfoVisitor { private final int startOffset; private final int endOffset; private final ExceptionInfoVisitor exceptionInfoVisitor; /** * Creates a new ExceptionHandlerFilter. * @param startOffset the start of the instruction offset range. * @param endOffset the end of the instruction offset range. * @param exceptionInfoVisitor the ExceptionInfoVisitor to which visits * will be delegated. */ public ExceptionHandlerFilter(int startOffset, int endOffset, ExceptionInfoVisitor exceptionInfoVisitor) { this.startOffset = startOffset; this.endOffset = endOffset; this.exceptionInfoVisitor = exceptionInfoVisitor; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { int handlerPC = exceptionInfo.u2handlerPC; if (handlerPC >= startOffset && handlerPC < endOffset) { exceptionInfoVisitor.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo); } } }proguard4.8/src/proguard/classfile/visitor/MultiClassVisitor.java0000644000175000017500000000531611736333524024156 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates all visits to each ClassVisitor * in a given list. * * @author Eric Lafortune */ public class MultiClassVisitor implements ClassVisitor { private static final int ARRAY_SIZE_INCREMENT = 5; private ClassVisitor[] classVisitors; private int classVisitorCount; public MultiClassVisitor() { } public MultiClassVisitor(ClassVisitor[] classVisitors) { this.classVisitors = classVisitors; this.classVisitorCount = classVisitors.length; } public void addClassVisitor(ClassVisitor classVisitor) { ensureArraySize(); classVisitors[classVisitorCount++] = classVisitor; } private void ensureArraySize() { if (classVisitors == null) { classVisitors = new ClassVisitor[ARRAY_SIZE_INCREMENT]; } else if (classVisitors.length == classVisitorCount) { ClassVisitor[] newClassVisitors = new ClassVisitor[classVisitorCount + ARRAY_SIZE_INCREMENT]; System.arraycopy(classVisitors, 0, newClassVisitors, 0, classVisitorCount); classVisitors = newClassVisitors; } } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { for (int index = 0; index < classVisitorCount; index++) { classVisitors[index].visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { for (int index = 0; index < classVisitorCount; index++) { classVisitors[index].visitLibraryClass(libraryClass); } } } proguard4.8/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java0000644000175000017500000000616711736333524025610 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor lets a given ClassVisitor * travel to the first concrete subclasses down in its hierarchy of abstract * classes and concrete classes. * * @author Eric Lafortune */ public class ConcreteClassDownTraveler implements ClassVisitor { private final ClassVisitor classVisitor; /** * Creates a new ConcreteClassDownTraveler. * @param classVisitor the ClassVisitor to * which visits will be delegated. */ public ConcreteClassDownTraveler(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Is this an abstract class or an interface? if ((programClass.getAccessFlags() & (ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) != 0) { // Travel down the hierarchy. Clazz[] subClasses = programClass.subClasses; if (subClasses != null) { for (int index = 0; index < subClasses.length; index++) { subClasses[index].accept(this); } } } else { // Visit the class. Don't descend any further. programClass.accept(classVisitor); } } public void visitLibraryClass(LibraryClass libraryClass) { // Is this an abstract class or interface? if ((libraryClass.getAccessFlags() & (ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) != 0) { // Travel down the hierarchy. Clazz[] subClasses = libraryClass.subClasses; if (subClasses != null) { for (int index = 0; index < subClasses.length; index++) { subClasses[index].accept(this); } } } else { // Visit the class. Don't descend any further. libraryClass.accept(classVisitor); } } } proguard4.8/src/proguard/classfile/visitor/LibraryMemberFilter.java0000644000175000017500000000435011736333524024415 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when visiting members of library * classes. * * @author Eric Lafortune */ public class LibraryMemberFilter implements MemberVisitor { private final MemberVisitor memberVisitor; /** * Creates a new ProgramMemberFilter. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public LibraryMemberFilter(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Don't delegate visits to program members. } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Don't delegate visits to program members. } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { memberVisitor.visitLibraryField(libraryClass, libraryField); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } proguard4.8/src/proguard/classfile/visitor/ClassCollector.java0000644000175000017500000000315411736333524023430 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.Clazz; import proguard.classfile.util.SimplifiedVisitor; import java.util.Set; /** * This ClassVisitor collects the classes that it visits in the * given collection. * * @author Eric Lafortune */ public class ClassCollector extends SimplifiedVisitor implements ClassVisitor { private final Set set; /** * Creates a new ClassCollector. * @param set the Set in which all class names will be * collected. */ public ClassCollector(Set set) { this.set = set; } // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { set.add(clazz); } } proguard4.8/src/proguard/classfile/visitor/NamedMethodVisitor.java0000644000175000017500000000361211736333524024260 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This class visits ProgramMember objects referring to methods, identified by * a name and descriptor pair. * * @author Eric Lafortune */ public class NamedMethodVisitor implements ClassVisitor { private final String name; private final String descriptor; private final MemberVisitor memberVisitor; public NamedMethodVisitor(String name, String descriptor, MemberVisitor memberVisitor) { this.name = name; this.descriptor = descriptor; this.memberVisitor = memberVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.methodAccept(name, descriptor, memberVisitor); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.methodAccept(name, descriptor, memberVisitor); } } proguard4.8/src/proguard/classfile/visitor/MemberCollector.java0000644000175000017500000000332111736333524023566 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import java.util.Set; /** * This MemberVisitor collects the concatenated name/descriptor strings of * class members that have been visited. * * @author Eric Lafortune */ public class MemberCollector extends SimplifiedVisitor implements MemberVisitor { private final Set set; /** * Creates a new MemberCollector. * @param set the Set in which all method names/descriptor * strings will be collected. */ public MemberCollector(Set set) { this.set = set; } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) { set.add(member.getName(clazz) + member.getDescriptor(clazz)); } }proguard4.8/src/proguard/classfile/visitor/AllFieldVisitor.java0000644000175000017500000000313211736333524023544 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor lets a given MemberVisitor visit all FieldMember * objects of the classes it visits. * * @author Eric Lafortune */ public class AllFieldVisitor implements ClassVisitor { private final MemberVisitor memberVisitor; public AllFieldVisitor(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.fieldsAccept(memberVisitor); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.fieldsAccept(memberVisitor); } } proguard4.8/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java0000644000175000017500000000507211736333524027013 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.constant.ClassConstant; import proguard.classfile.util.SimplifiedVisitor; /** * This ConstantVisitor delegates its visits to class constants * to another given ConstantVisitor, except for classes that * are extended or implemented by a given class. This exception includes the * class itself. * * @author Eric Lafortune */ public class ImplementingClassConstantFilter extends SimplifiedVisitor implements ConstantVisitor { private final Clazz implementingClass; private final ConstantVisitor constantVisitor; /** * Creates a new ImplementingClassConstantFilter. * @param implementingClass the class whose superclasses and interfaces will * not be visited. * @param constantVisitor the ConstantVisitor to which visits * will be delegated. */ public ImplementingClassConstantFilter(Clazz implementingClass, ConstantVisitor constantVisitor) { this.implementingClass = implementingClass; this.constantVisitor = constantVisitor; } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { Clazz referencedClass = classConstant.referencedClass; if (referencedClass == null || !implementingClass.extendsOrImplements(referencedClass)) { constantVisitor.visitClassConstant(clazz, classConstant); } } }proguard4.8/src/proguard/classfile/visitor/ClassPoolFiller.java0000644000175000017500000000301711736333524023547 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; /** * This ClassVisitor collects all the classes it visits in a given * class pool. * * @author Eric Lafortune */ public class ClassPoolFiller extends SimplifiedVisitor implements ClassVisitor { private final ClassPool classPool; /** * Creates a new ClassPoolFiller. */ public ClassPoolFiller(ClassPool classPool) { this.classPool = classPool; } // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { classPool.addClass(clazz); } } proguard4.8/src/proguard/classfile/visitor/VariableClassVisitor.java0000644000175000017500000000372511736333524024613 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates all method calls to a ClassVisitor * that can be changed at any time. * * @author Eric Lafortune */ public class VariableClassVisitor implements ClassVisitor { private ClassVisitor classVisitor; public VariableClassVisitor() { this(null); } public VariableClassVisitor(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } public void setClassVisitor(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } public ClassVisitor getClassVisitor() { return classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (classVisitor != null) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (classVisitor != null) { classVisitor.visitLibraryClass(libraryClass); } } } proguard4.8/src/proguard/classfile/visitor/MemberClassAccessFilter.java0000644000175000017500000000744511736333524025210 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.util.*; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when the visited member is accessible * from the given referencing class. * * @author Eric Lafortune */ public class MemberClassAccessFilter implements MemberVisitor { private final Clazz referencingClass; private final MemberVisitor memberVisitor; /** * Creates a new MemberAccessFilter. * @param referencingClass the class that is accessing the member. * @param memberVisitor the MemberVisitor to which visits * will be delegated. */ public MemberClassAccessFilter(Clazz referencingClass, MemberVisitor memberVisitor) { this.referencingClass = referencingClass; this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (accepted(programClass, programField.getAccessFlags())) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (accepted(programClass, programMethod.getAccessFlags())) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (accepted(libraryClass, libraryField.getAccessFlags())) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (accepted(libraryClass, libraryMethod.getAccessFlags())) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } // Small utility methods. private boolean accepted(Clazz clazz, int memberAccessFlags) { int accessLevel = AccessUtil.accessLevel(memberAccessFlags); return (accessLevel >= AccessUtil.PUBLIC ) || (accessLevel >= AccessUtil.PRIVATE && referencingClass.equals(clazz) ) || (accessLevel >= AccessUtil.PACKAGE_VISIBLE && (ClassUtil.internalPackageName(referencingClass.getName()).equals( ClassUtil.internalPackageName(clazz.getName())))) || (accessLevel >= AccessUtil.PROTECTED && (referencingClass.extends_(clazz) || referencingClass.extendsOrImplements(clazz)) ); } } proguard4.8/src/proguard/classfile/visitor/ExceptionCounter.java0000644000175000017500000000313711736333524024013 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.ExceptionInfoVisitor; /** * This ExceptionInfoVisitor counts the number of exceptions that has been visited. * * @author Eric Lafortune */ public class ExceptionCounter implements ExceptionInfoVisitor { private int count; /** * Returns the number of exceptions that has been visited so far. */ public int getCount() { return count; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { count++; } } proguard4.8/src/proguard/classfile/visitor/ClassNameFilter.java0000664000175000017500000000712211740563614023531 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.util.*; import java.util.List; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, but only when the visited class has a name that * matches a given regular expression. * * @author Eric Lafortune */ public class ClassNameFilter implements ClassVisitor { private final StringMatcher regularExpressionMatcher; private final ClassVisitor classVisitor; /** * Creates a new ClassNameFilter. * @param regularExpression the regular expression against which class names * will be matched. * @param classVisitor the ClassVisitor to which visits * will be delegated. */ public ClassNameFilter(String regularExpression, ClassVisitor classVisitor) { this(new ListParser(new ClassNameParser()).parse(regularExpression), classVisitor); } /** * Creates a new ClassNameFilter. * @param regularExpression the regular expression against which class names * will be matched. * @param classVisitor the ClassVisitor to which visits * will be delegated. */ public ClassNameFilter(List regularExpression, ClassVisitor classVisitor) { this(new ListParser(new ClassNameParser()).parse(regularExpression), classVisitor); } /** * Creates a new ClassNameFilter. * @param regularExpressionMatcher the string matcher against which * class names will be matched. * @param classVisitor the ClassVisitor to which * visits will be delegated. */ public ClassNameFilter(StringMatcher regularExpressionMatcher, ClassVisitor classVisitor) { this.regularExpressionMatcher = regularExpressionMatcher; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (accepted(programClass.getName())) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (accepted(libraryClass.getName())) { classVisitor.visitLibraryClass(libraryClass); } } // Small utility methods. private boolean accepted(String name) { return regularExpressionMatcher.matches(name); } } proguard4.8/src/proguard/classfile/visitor/MemberVisitor.java0000644000175000017500000000301011736333524023272 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This interface specifies the methods for a visitor of * ProgramMember objects and LibraryMember * objects. * * @author Eric Lafortune */ public interface MemberVisitor { public void visitProgramField( ProgramClass programClass, ProgramField programField); public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod); public void visitLibraryField( LibraryClass libraryClass, LibraryField libraryField); public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod); } proguard4.8/src/proguard/classfile/visitor/ClassPrinter.java0000644000175000017500000010734711736333524023136 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import java.io.PrintStream; /** * This ClassVisitor prints out the complete internal * structure of the classes it visits. * * @author Eric Lafortune */ public class ClassPrinter extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, MemberVisitor, AttributeVisitor, BootstrapMethodInfoVisitor, InnerClassesInfoVisitor, ExceptionInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LineNumberInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor, InstructionVisitor { private static final String INDENTATION = " "; private final PrintStream ps; private int indentation; /** * Creates a new ClassPrinter that prints to System.out. */ public ClassPrinter() { this(System.out); } /** * Creates a new ClassPrinter that prints to the given * PrintStream. */ public ClassPrinter(PrintStream printStream) { ps = printStream; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { println("_____________________________________________________________________"); println(visitorInfo(programClass) + " " + "Program class: " + programClass.getName()); indent(); println("Superclass: " + programClass.getSuperName()); println("Major version: 0x" + Integer.toHexString(ClassUtil.internalMajorClassVersion(programClass.u4version))); println("Minor version: 0x" + Integer.toHexString(ClassUtil.internalMinorClassVersion(programClass.u4version))); println("Access flags: 0x" + Integer.toHexString(programClass.u2accessFlags)); println(" = " + ((programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ANNOTATTION) != 0 ? "@ " : "") + ClassUtil.externalClassAccessFlags(programClass.u2accessFlags) + ((programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ENUM) != 0 ? "enum " : (programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) == 0 ? "class " : "") + ClassUtil.externalClassName(programClass.getName()) + (programClass.u2superClass == 0 ? "" : " extends " + ClassUtil.externalClassName(programClass.getSuperName()))); outdent(); println(); println("Interfaces (count = " + programClass.u2interfacesCount + "):"); indent(); programClass.interfaceConstantsAccept(this); outdent(); println(); println("Constant Pool (count = " + programClass.u2constantPoolCount + "):"); indent(); programClass.constantPoolEntriesAccept(this); outdent(); println(); println("Fields (count = " + programClass.u2fieldsCount + "):"); indent(); programClass.fieldsAccept(this); outdent(); println(); println("Methods (count = " + programClass.u2methodsCount + "):"); indent(); programClass.methodsAccept(this); outdent(); println(); println("Class file attributes (count = " + programClass.u2attributesCount + "):"); indent(); programClass.attributesAccept(this); outdent(); println(); } public void visitLibraryClass(LibraryClass libraryClass) { println("_____________________________________________________________________"); println(visitorInfo(libraryClass) + " " + "Library class: " + libraryClass.getName()); indent(); println("Superclass: " + libraryClass.getSuperName()); println("Access flags: 0x" + Integer.toHexString(libraryClass.u2accessFlags)); println(" = " + ((libraryClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ANNOTATTION) != 0 ? "@ " : "") + ClassUtil.externalClassAccessFlags(libraryClass.u2accessFlags) + ((libraryClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ENUM) != 0 ? "enum " : (libraryClass.u2accessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) == 0 ? "class " : "") + ClassUtil.externalClassName(libraryClass.getName()) + (libraryClass.getSuperName() == null ? "" : " extends " + ClassUtil.externalClassName(libraryClass.getSuperName()))); outdent(); println(); println("Interfaces (count = " + libraryClass.interfaceClasses.length + "):"); for (int index = 0; index < libraryClass.interfaceClasses.length; index++) { Clazz interfaceClass = libraryClass.interfaceClasses[index]; if (interfaceClass != null) { println(" + " + interfaceClass.getName()); } } println("Fields (count = " + libraryClass.fields.length + "):"); libraryClass.fieldsAccept(this); println("Methods (count = " + libraryClass.methods.length + "):"); libraryClass.methodsAccept(this); } // Implementations for ConstantVisitor. public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { println(visitorInfo(integerConstant) + " Integer [" + integerConstant.getValue() + "]"); } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { println(visitorInfo(longConstant) + " Long [" + longConstant.getValue() + "]"); } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { println(visitorInfo(floatConstant) + " Float [" + floatConstant.getValue() + "]"); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { println(visitorInfo(doubleConstant) + " Double [" + doubleConstant.getValue() + "]"); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { println(visitorInfo(stringConstant) + " String [" + clazz.getString(stringConstant.u2stringIndex) + "]"); } public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { println(visitorInfo(utf8Constant) + " Utf8 [" + utf8Constant.getString() + "]"); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { println(visitorInfo(invokeDynamicConstant) + " InvokeDynamic [bootstrap method index = " + invokeDynamicConstant.u2bootstrapMethodAttributeIndex + "]:"); indent(); clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this); outdent(); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { println(visitorInfo(methodHandleConstant) + " MethodHandle [kind = " + methodHandleConstant.u1referenceKind + "]:"); indent(); clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); outdent(); } public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { println(visitorInfo(fieldrefConstant) + " Fieldref [" + clazz.getClassName(fieldrefConstant.u2classIndex) + "." + clazz.getName(fieldrefConstant.u2nameAndTypeIndex) + " " + clazz.getType(fieldrefConstant.u2nameAndTypeIndex) + "]"); } public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) { println(visitorInfo(interfaceMethodrefConstant) + " InterfaceMethodref [" + clazz.getClassName(interfaceMethodrefConstant.u2classIndex) + "." + clazz.getName(interfaceMethodrefConstant.u2nameAndTypeIndex) + " " + clazz.getType(interfaceMethodrefConstant.u2nameAndTypeIndex) + "]"); } public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { println(visitorInfo(methodrefConstant) + " Methodref [" + clazz.getClassName(methodrefConstant.u2classIndex) + "." + clazz.getName(methodrefConstant.u2nameAndTypeIndex) + " " + clazz.getType(methodrefConstant.u2nameAndTypeIndex) + "]"); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { println(visitorInfo(classConstant) + " Class [" + clazz.getString(classConstant.u2nameIndex) + "]"); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { println(visitorInfo(methodTypeConstant) + " MethodType [" + clazz.getString(methodTypeConstant.u2descriptorIndex) + "]"); } public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { println(visitorInfo(nameAndTypeConstant) + " NameAndType [" + clazz.getString(nameAndTypeConstant.u2nameIndex) + " " + clazz.getString(nameAndTypeConstant.u2descriptorIndex) + "]"); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { println(visitorInfo(programField) + " " + "Field: " + programField.getName(programClass) + " " + programField.getDescriptor(programClass)); indent(); println("Access flags: 0x" + Integer.toHexString(programField.u2accessFlags)); println(" = " + ClassUtil.externalFullFieldDescription(programField.u2accessFlags, programField.getName(programClass), programField.getDescriptor(programClass))); visitMember(programClass, programField); outdent(); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { println(visitorInfo(programMethod) + " " + "Method: " + programMethod.getName(programClass) + programMethod.getDescriptor(programClass)); indent(); println("Access flags: 0x" + Integer.toHexString(programMethod.u2accessFlags)); println(" = " + ClassUtil.externalFullMethodDescription(programClass.getName(), programMethod.u2accessFlags, programMethod.getName(programClass), programMethod.getDescriptor(programClass))); visitMember(programClass, programMethod); outdent(); } private void visitMember(ProgramClass programClass, ProgramMember programMember) { if (programMember.u2attributesCount > 0) { println("Class member attributes (count = " + programMember.u2attributesCount + "):"); programMember.attributesAccept(programClass, this); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { println(visitorInfo(libraryField) + " " + "Field: " + libraryField.getName(libraryClass) + " " + libraryField.getDescriptor(libraryClass)); indent(); println("Access flags: 0x" + Integer.toHexString(libraryField.u2accessFlags)); println(" = " + ClassUtil.externalFullFieldDescription(libraryField.u2accessFlags, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass))); outdent(); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { println(visitorInfo(libraryMethod) + " " + "Method: " + libraryMethod.getName(libraryClass) + " " + libraryMethod.getDescriptor(libraryClass)); indent(); println("Access flags: 0x" + Integer.toHexString(libraryMethod.u2accessFlags)); println(" = " + ClassUtil.externalFullMethodDescription(libraryClass.getName(), libraryMethod.u2accessFlags, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass))); outdent(); } // Implementations for AttributeVisitor. // Note that attributes are typically only referenced once, so we don't // test if they are marked already. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { println(visitorInfo(unknownAttribute) + " Unknown attribute (" + clazz.getString(unknownAttribute.u2attributeNameIndex) + ")"); } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { println(visitorInfo(bootstrapMethodsAttribute) + " Bootstrap methods attribute (count = " + bootstrapMethodsAttribute.u2bootstrapMethodsCount + "):"); indent(); bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this); outdent(); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { println(visitorInfo(sourceFileAttribute) + " Source file attribute:"); indent(); clazz.constantPoolEntryAccept(sourceFileAttribute.u2sourceFileIndex, this); outdent(); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { println(visitorInfo(sourceDirAttribute) + " Source dir attribute:"); indent(); clazz.constantPoolEntryAccept(sourceDirAttribute.u2sourceDirIndex, this); outdent(); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { println(visitorInfo(innerClassesAttribute) + " Inner classes attribute (count = " + innerClassesAttribute.u2classesCount + ")"); indent(); innerClassesAttribute.innerClassEntriesAccept(clazz, this); outdent(); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { println(visitorInfo(enclosingMethodAttribute) + " Enclosing method attribute:"); indent(); clazz.constantPoolEntryAccept(enclosingMethodAttribute.u2classIndex, this); if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) { clazz.constantPoolEntryAccept(enclosingMethodAttribute.u2nameAndTypeIndex, this); } outdent(); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { println(visitorInfo(deprecatedAttribute) + " Deprecated attribute"); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { println(visitorInfo(syntheticAttribute) + " Synthetic attribute"); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { println(visitorInfo(signatureAttribute) + " Signature attribute:"); indent(); clazz.constantPoolEntryAccept(signatureAttribute.u2signatureIndex, this); outdent(); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { println(visitorInfo(constantValueAttribute) + " Constant value attribute:"); clazz.constantPoolEntryAccept(constantValueAttribute.u2constantValueIndex, this); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { println(visitorInfo(exceptionsAttribute) + " Exceptions attribute (count = " + exceptionsAttribute.u2exceptionIndexTableLength + ")"); indent(); exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this); outdent(); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { println(visitorInfo(codeAttribute) + " Code attribute instructions (code length = "+ codeAttribute.u4codeLength + ", locals = "+ codeAttribute.u2maxLocals + ", stack = "+ codeAttribute.u2maxStack + "):"); indent(); codeAttribute.instructionsAccept(clazz, method, this); println("Code attribute exceptions (count = " + codeAttribute.u2exceptionTableLength + "):"); codeAttribute.exceptionsAccept(clazz, method, this); println("Code attribute attributes (attribute count = " + codeAttribute.u2attributesCount + "):"); codeAttribute.attributesAccept(clazz, method, this); outdent(); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { println(visitorInfo(codeAttribute) + " Stack map attribute (count = "+ stackMapAttribute.u2stackMapFramesCount + "):"); indent(); stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); outdent(); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { println(visitorInfo(codeAttribute) + " Stack map table attribute (count = "+ stackMapTableAttribute.u2stackMapFramesCount + "):"); indent(); stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); outdent(); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { println(visitorInfo(lineNumberTableAttribute) + " Line number table attribute (count = " + lineNumberTableAttribute.u2lineNumberTableLength + ")"); indent(); lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this); outdent(); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { println(visitorInfo(localVariableTableAttribute) + " Local variable table attribute (count = " + localVariableTableAttribute.u2localVariableTableLength + ")"); indent(); localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); outdent(); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { println(visitorInfo(localVariableTypeTableAttribute) + " Local variable type table attribute (count = "+ localVariableTypeTableAttribute.u2localVariableTypeTableLength + ")"); indent(); localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); outdent(); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { println(visitorInfo(runtimeVisibleAnnotationsAttribute) + " Runtime visible annotations attribute:"); indent(); runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, this); outdent(); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { println(visitorInfo(runtimeInvisibleAnnotationsAttribute) + " Runtime invisible annotations attribute:"); indent(); runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, this); outdent(); } public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute) { println(visitorInfo(runtimeVisibleParameterAnnotationsAttribute) + " Runtime visible parameter annotations attribute (parameter count = " + runtimeVisibleParameterAnnotationsAttribute.u2parametersCount + "):"); indent(); runtimeVisibleParameterAnnotationsAttribute.annotationsAccept(clazz, method, this); outdent(); } public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute) { println(visitorInfo(runtimeInvisibleParameterAnnotationsAttribute) + " Runtime invisible parameter annotations attribute (parameter count = " + runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount + "):"); indent(); runtimeInvisibleParameterAnnotationsAttribute.annotationsAccept(clazz, method, this); outdent(); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { println(visitorInfo(annotationDefaultAttribute) + " Annotation default attribute:"); indent(); annotationDefaultAttribute.defaultValueAccept(clazz, this); outdent(); } // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { println(visitorInfo(bootstrapMethodInfo) + " BootstrapMethodInfo (argument count = " + bootstrapMethodInfo.u2methodArgumentCount+ "):"); indent(); clazz.constantPoolEntryAccept(bootstrapMethodInfo.u2methodHandleIndex, this); bootstrapMethodInfo.methodArgumentsAccept(clazz, this); outdent(); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { println(visitorInfo(innerClassesInfo) + " InnerClassesInfo:"); indent(); println("Access flags: 0x" + Integer.toHexString(innerClassesInfo.u2innerClassAccessFlags) + " = " + ClassUtil.externalClassAccessFlags(innerClassesInfo.u2innerClassAccessFlags)); innerClassesInfo.innerClassConstantAccept(clazz, this); innerClassesInfo.outerClassConstantAccept(clazz, this); innerClassesInfo.innerNameConstantAccept(clazz, this); outdent(); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { println(instruction.toString(offset)); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { println(constantInstruction.toString(offset)); indent(); clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); outdent(); } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { println(tableSwitchInstruction.toString(offset)); indent(); int[] jumpOffsets = tableSwitchInstruction.jumpOffsets; for (int index = 0; index < jumpOffsets.length; index++) { int jumpOffset = jumpOffsets[index]; println(Integer.toString(tableSwitchInstruction.lowCase + index) + ": offset = " + jumpOffset + ", target = " + (offset + jumpOffset)); } int defaultOffset = tableSwitchInstruction.defaultOffset; println("default: offset = " + defaultOffset + ", target = "+ (offset + defaultOffset)); outdent(); } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { println(lookUpSwitchInstruction.toString(offset)); indent(); int[] cases = lookUpSwitchInstruction.cases; int[] jumpOffsets = lookUpSwitchInstruction.jumpOffsets; for (int index = 0; index < jumpOffsets.length; index++) { int jumpOffset = jumpOffsets[index]; println(Integer.toString(cases[index]) + ": offset = " + jumpOffset + ", target = " + (offset + jumpOffset)); } int defaultOffset = lookUpSwitchInstruction.defaultOffset; println("default: offset = " + defaultOffset + ", target = "+ (offset + defaultOffset)); outdent(); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { println(visitorInfo(exceptionInfo) + " ExceptionInfo (" + exceptionInfo.u2startPC + " -> " + exceptionInfo.u2endPC + ": " + exceptionInfo.u2handlerPC + "):"); if (exceptionInfo.u2catchType != 0) { clazz.constantPoolEntryAccept(exceptionInfo.u2catchType, this); } } // Implementations for StackMapFrameVisitor. public void visitSameZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameZeroFrame sameZeroFrame) { println(visitorInfo(sameZeroFrame) + " [" + offset + "]" + " Var: ..., Stack: (empty)"); } public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) { print(visitorInfo(sameOneFrame) + " [" + offset + "]" + " Var: ..., Stack: "); sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); println(); } public void visitLessZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LessZeroFrame lessZeroFrame) { println(visitorInfo(lessZeroFrame) + " [" + offset + "]" + " Var: -" + lessZeroFrame.choppedVariablesCount + ", Stack: (empty)"); } public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) { print(visitorInfo(moreZeroFrame) + " [" + offset + "]" + " Var: ..."); moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); ps.println(", Stack: (empty)"); } public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) { print(visitorInfo(fullFrame) + " [" + offset + "]" + " Var: "); fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); ps.print(", Stack: "); fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); println(); } // Implementations for VerificationTypeVisitor. public void visitIntegerType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, IntegerType integerType) { ps.print("[i]"); } public void visitFloatType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FloatType floatType) { ps.print("[f]"); } public void visitLongType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LongType longType) { ps.print("[l]"); } public void visitDoubleType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, DoubleType doubleType) { ps.print("[d]"); } public void visitTopType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TopType topType) { ps.print("[T]"); } public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) { ps.print("[a:" + clazz.getClassName(objectType.u2classIndex) + "]"); } public void visitNullType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, NullType nullType) { ps.print("[n]"); } public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType) { ps.print("[u:" + uninitializedType.u2newInstructionOffset + "]"); } public void visitUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedThisType uninitializedThisType) { ps.print("[u:this]"); } // Implementations for LineNumberInfoVisitor. public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) { println("[" + lineNumberInfo.u2startPC + "] -> line " + lineNumberInfo.u2lineNumber); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { println("v" + localVariableInfo.u2index + ": " + localVariableInfo.u2startPC + " -> " + (localVariableInfo.u2startPC + localVariableInfo.u2length) + " [" + clazz.getString(localVariableInfo.u2descriptorIndex) + " " + clazz.getString(localVariableInfo.u2nameIndex) + "]"); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { println("v" + localVariableTypeInfo.u2index + ": " + localVariableTypeInfo.u2startPC + " -> " + (localVariableTypeInfo.u2startPC + localVariableTypeInfo.u2length) + " [" + clazz.getString(localVariableTypeInfo.u2signatureIndex) + " " + clazz.getString(localVariableTypeInfo.u2nameIndex) + "]"); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { println(visitorInfo(annotation) + " Annotation [" + clazz.getString(annotation.u2typeIndex) + "]:"); indent(); annotation.elementValuesAccept(clazz, this); outdent(); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { println(visitorInfo(constantElementValue) + " Constant element value [" + (constantElementValue.u2elementNameIndex == 0 ? "(default)" : clazz.getString(constantElementValue.u2elementNameIndex)) + " '" + constantElementValue.u1tag + "']"); indent(); clazz.constantPoolEntryAccept(constantElementValue.u2constantValueIndex, this); outdent(); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { println(visitorInfo(enumConstantElementValue) + " Enum constant element value [" + (enumConstantElementValue.u2elementNameIndex == 0 ? "(default)" : clazz.getString(enumConstantElementValue.u2elementNameIndex)) + ", " + clazz.getString(enumConstantElementValue.u2typeNameIndex) + ", " + clazz.getString(enumConstantElementValue.u2constantNameIndex) + "]"); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { println(visitorInfo(classElementValue) + " Class element value [" + (classElementValue.u2elementNameIndex == 0 ? "(default)" : clazz.getString(classElementValue.u2elementNameIndex)) + ", " + clazz.getString(classElementValue.u2classInfoIndex) + "]"); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { println(visitorInfo(annotationElementValue) + " Annotation element value [" + (annotationElementValue.u2elementNameIndex == 0 ? "(default)" : clazz.getString(annotationElementValue.u2elementNameIndex)) + "]:"); indent(); annotationElementValue.annotationAccept(clazz, this); outdent(); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { println(visitorInfo(arrayElementValue) + " Array element value [" + (arrayElementValue.u2elementNameIndex == 0 ? "(default)" : clazz.getString(arrayElementValue.u2elementNameIndex)) + "]:"); indent(); arrayElementValue.elementValuesAccept(clazz, annotation, this); outdent(); } // Small utility methods. private void indent() { indentation++; } private void outdent() { indentation--; } private void println(String string) { print(string); println(); } private void print(String string) { for (int index = 0; index < indentation; index++) { ps.print(INDENTATION); } ps.print(string); } private void println() { ps.println(); } private String visitorInfo(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() == null ? "-" : "+"; } } proguard4.8/src/proguard/classfile/visitor/SubclassFilter.java0000644000175000017500000000503311736333524023437 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, except for classes that have a given class as * direct subclass. * * @author Eric Lafortune */ public class SubclassFilter implements ClassVisitor { private final Clazz subclass; private final ClassVisitor classVisitor; /** * Creates a new SubclassFilter. * @param subclass the class whose superclasses will not be visited. * @param classVisitor the ClassVisitor to which visits will * be delegated. */ public SubclassFilter(Clazz subclass, ClassVisitor classVisitor) { this.subclass = subclass; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (!present(programClass.subClasses)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (!present(libraryClass.subClasses)) { classVisitor.visitLibraryClass(libraryClass); } } // Small utility methods. private boolean present(Clazz[] subclasses) { if (subclasses == null) { return false; } for (int index = 0; index < subclasses.length; index++) { if (subclasses[index].equals(subclass)) { return true; } } return false; } }proguard4.8/src/proguard/classfile/visitor/MemberNameFilter.java0000644000175000017500000000720511736333524023673 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; import proguard.util.*; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when the visited member * has a name that matches a given regular expression. * * @author Eric Lafortune */ public class MemberNameFilter implements MemberVisitor { private final StringMatcher regularExpressionMatcher; private final MemberVisitor memberVisitor; /** * Creates a new MemberNameFilter. * @param regularExpression the regular expression against which member * names will be matched. * @param memberVisitor the MemberVisitor to which visits * will be delegated. */ public MemberNameFilter(String regularExpression, MemberVisitor memberVisitor) { this(new NameParser().parse(regularExpression), memberVisitor); } /** * Creates a new MemberNameFilter. * @param regularExpressionMatcher the regular expression against which * member names will be matched. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public MemberNameFilter(StringMatcher regularExpressionMatcher, MemberVisitor memberVisitor) { this.regularExpressionMatcher = regularExpressionMatcher; this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (accepted(programField.getName(programClass))) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (accepted(programMethod.getName(programClass))) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (accepted(libraryField.getName(libraryClass))) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (accepted(libraryMethod.getName(libraryClass))) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } // Small utility methods. private boolean accepted(String name) { return regularExpressionMatcher.matches(name); } } proguard4.8/src/proguard/classfile/visitor/ClassCounter.java0000644000175000017500000000276411736333524023127 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor counts the number of classes that has been visited. * * @author Eric Lafortune */ public class ClassCounter implements ClassVisitor { private int count; /** * Returns the number of classes that has been visited so far. */ public int getCount() { return count; } // Implementations for ClassVisitor. public void visitLibraryClass(LibraryClass libraryClass) { count++; } public void visitProgramClass(ProgramClass programClass) { count++; } } proguard4.8/src/proguard/classfile/visitor/LibraryClassFilter.java0000644000175000017500000000346711736333524024263 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to another given * ClassVisitor, but only when visiting library classes. * * @author Eric Lafortune */ public class LibraryClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; /** * Creates a new LibraryClassFilter. * @param classVisitor the ClassVisitor to which visits * will be delegated. */ public LibraryClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Don't delegate visits to program classes. } public void visitLibraryClass(LibraryClass libraryClass) { classVisitor.visitLibraryClass(libraryClass); } } proguard4.8/src/proguard/classfile/visitor/MultiClassPoolVisitor.java0000644000175000017500000000520211736333524025002 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.ClassPool; /** * This ClassPoolVisitor delegates all visits to each ClassPoolVisitor * in a given list. * * @author Eric Lafortune */ public class MultiClassPoolVisitor implements ClassPoolVisitor { private static final int ARRAY_SIZE_INCREMENT = 5; private ClassPoolVisitor[] classPoolVisitors; private int classPoolVisitorCount; public MultiClassPoolVisitor() { } public MultiClassPoolVisitor(ClassPoolVisitor[] classPoolVisitors) { this.classPoolVisitors = classPoolVisitors; this.classPoolVisitorCount = classPoolVisitors.length; } public void addClassPoolVisitor(ClassPoolVisitor classPoolVisitor) { ensureArraySize(); classPoolVisitors[classPoolVisitorCount++] = classPoolVisitor; } private void ensureArraySize() { if (classPoolVisitors == null) { classPoolVisitors = new ClassPoolVisitor[ARRAY_SIZE_INCREMENT]; } else if (classPoolVisitors.length == classPoolVisitorCount) { ClassPoolVisitor[] newClassPoolVisitors = new ClassPoolVisitor[classPoolVisitorCount + ARRAY_SIZE_INCREMENT]; System.arraycopy(classPoolVisitors, 0, newClassPoolVisitors, 0, classPoolVisitorCount); classPoolVisitors = newClassPoolVisitors; } } // Implementations for ClassPoolVisitor. public void visitClassPool(ClassPool classPool) { for (int index = 0; index < classPoolVisitorCount; index++) { classPoolVisitors[index].visitClassPool(classPool); } } } proguard4.8/src/proguard/classfile/visitor/ClassVersionFilter.java0000644000175000017500000000571311736333524024300 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.visitor; import proguard.classfile.*; /** * This ClassVisitor delegates its visits to program classes to * another given ClassVisitor, but only when the class version * number of the visited program class lies in a given range. * * @author Eric Lafortune */ public class ClassVersionFilter implements ClassVisitor { private final int minimumClassVersion; private final int maximumClassVersion; private final ClassVisitor classVisitor; /** * Creates a new ClassVersionFilter. * @param minimumClassVersion the minimum class version number. * @param classVisitor the ClassVisitor to which visits * will be delegated. */ public ClassVersionFilter(int minimumClassVersion, ClassVisitor classVisitor) { this(minimumClassVersion, Integer.MAX_VALUE, classVisitor); } /** * Creates a new ClassVersionFilter. * @param minimumClassVersion the minimum class version number. * @param maximumClassVersion the maximum class version number. * @param classVisitor the ClassVisitor to which visits * will be delegated. */ public ClassVersionFilter(int minimumClassVersion, int maximumClassVersion, ClassVisitor classVisitor) { this.minimumClassVersion = minimumClassVersion; this.maximumClassVersion = maximumClassVersion; this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (programClass.u4version >= minimumClassVersion && programClass.u4version <= maximumClassVersion) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { // Library classes don't have version numbers. } } proguard4.8/src/proguard/classfile/ProgramMember.java0000644000175000017500000001115111736333524021550 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.visitor.MemberVisitor; /** * Representation of a field or method from a program class. * * @author Eric Lafortune */ public abstract class ProgramMember implements Member { public int u2accessFlags; public int u2nameIndex; public int u2descriptorIndex; public int u2attributesCount; public Attribute[] attributes; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Creates an uninitialized ProgramMember. */ protected ProgramMember() { } /** * Creates an initialized ProgramMember. */ protected ProgramMember(int u2accessFlags, int u2nameIndex, int u2descriptorIndex, int u2attributesCount, Attribute[] attributes) { this.u2accessFlags = u2accessFlags; this.u2nameIndex = u2nameIndex; this.u2descriptorIndex = u2descriptorIndex; this.u2attributesCount = u2attributesCount; this.attributes = attributes; } /** * Returns the line number range of the given class member as "m:n", * if it can find it, or null otherwise. */ public String getLineNumberRange(Clazz clazz) { CodeAttribute codeAttribute = (CodeAttribute)getAttribute(clazz, ClassConstants.ATTR_Code); if (codeAttribute == null) { return null; } LineNumberTableAttribute lineNumberTableAttribute = (LineNumberTableAttribute)codeAttribute.getAttribute(clazz, ClassConstants.ATTR_LineNumberTable); if (lineNumberTableAttribute == null) { return null; } return "" + lineNumberTableAttribute.getLineNumber(0) + ":" + lineNumberTableAttribute.getLineNumber(Integer.MAX_VALUE); } /** * Returns the (first) attribute with the given name. */ private Attribute getAttribute(Clazz clazz, String name) { for (int index = 0; index < u2attributesCount; index++) { Attribute attribute = attributes[index]; if (attribute.getAttributeName(clazz).equals(name)) { return attribute; } } return null; } /** * Accepts the given member info visitor. */ public abstract void accept(ProgramClass programClass, MemberVisitor memberVisitor); /** * Lets the given attribute info visitor visit all the attributes of * this member info. */ public abstract void attributesAccept(ProgramClass programClass, AttributeVisitor attributeVisitor); // Implementations for Member. public int getAccessFlags() { return u2accessFlags; } public String getName(Clazz clazz) { return clazz.getString(u2nameIndex); } public String getDescriptor(Clazz clazz) { return clazz.getString(u2descriptorIndex); } public void accept(Clazz clazz, MemberVisitor memberVisitor) { accept((ProgramClass)clazz, memberVisitor); } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } proguard4.8/src/proguard/classfile/VisitorAccepter.java0000644000175000017500000000307011736333524022120 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; /** * This interface is a base interface for visitor accepters. It allows * visitors to set and get any temporary information they desire on the * objects they are visiting. Note that every visitor accepter has only one * such property, so visitors will have to take care not to overwrite each * other's information, if it is still required. * * @author Eric Lafortune */ public interface VisitorAccepter { /** * Gets the visitor information of the visitor accepter. */ public Object getVisitorInfo(); /** * Sets the visitor information of the visitor accepter. */ public void setVisitorInfo(Object visitorInfo); } proguard4.8/src/proguard/classfile/LibraryField.java0000644000175000017500000000425711736333524021372 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.visitor.*; /** * Representation of a field from a class-file. * * @author Eric Lafortune */ public class LibraryField extends LibraryMember implements Field { /** * An extra field pointing to the Clazz object referenced in the * descriptor string. This field is filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz referencedClass; /** * Creates an uninitialized LibraryField. */ public LibraryField() { } /** * Creates an initialized LibraryField. */ public LibraryField(int u2accessFlags, String name, String descriptor) { super(u2accessFlags, name, descriptor); } // Implementations for LibraryMember. public void accept(LibraryClass libraryClass, MemberVisitor memberVisitor) { memberVisitor.visitLibraryField(libraryClass, this); } // Implementations for Member. public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClass != null) { referencedClass.accept(classVisitor); } } } proguard4.8/src/proguard/classfile/Field.java0000644000175000017500000000203411736333524020034 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; /** * Representation of a field from a class. * * @author Eric Lafortune */ public interface Field extends Member { } proguard4.8/src/proguard/classfile/ProgramClass.java0000644000175000017500000003730411736333524021416 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.attribute.Attribute; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.ClassSubHierarchyInitializer; import proguard.classfile.visitor.*; /** * This Clazz is a complete representation of the data in a Java class. * * @author Eric Lafortune */ public class ProgramClass implements Clazz { public int u4magic; public int u4version; public int u2constantPoolCount; public Constant[] constantPool; public int u2accessFlags; public int u2thisClass; public int u2superClass; public int u2interfacesCount; public int[] u2interfaces; public int u2fieldsCount; public ProgramField[] fields; public int u2methodsCount; public ProgramMethod[] methods; public int u2attributesCount; public Attribute[] attributes; /** * An extra field pointing to the subclasses of this class. * This field is filled out by the {@link ClassSubHierarchyInitializer}. */ public Clazz[] subClasses; /** * An extra field in which visitors can store information. */ public Object visitorInfo; /** * Creates an uninitialized ProgramClass. */ public ProgramClass() {} /** * Returns the Constant at the given index in the constant pool. */ public Constant getConstant(int constantIndex) { return constantPool[constantIndex]; } // Implementations for Clazz. public int getAccessFlags() { return u2accessFlags; } public String getName() { return getClassName(u2thisClass); } public String getSuperName() { return u2superClass == 0 ? null : getClassName(u2superClass); } public int getInterfaceCount() { return u2interfacesCount; } public String getInterfaceName(int index) { return getClassName(u2interfaces[index]); } public int getTag(int constantIndex) { return constantPool[constantIndex].getTag(); } public String getString(int constantIndex) { try { return ((Utf8Constant)constantPool[constantIndex]).getString(); } catch (ClassCastException ex) { throw ((IllegalStateException)new IllegalStateException("Expected Utf8Constant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); } } public String getStringString(int constantIndex) { try { return ((StringConstant)constantPool[constantIndex]).getString(this); } catch (ClassCastException ex) { throw ((IllegalStateException)new IllegalStateException("Expected StringConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); } } public String getClassName(int constantIndex) { try { return ((ClassConstant)constantPool[constantIndex]).getName(this); } catch (ClassCastException ex) { throw ((IllegalStateException)new IllegalStateException("Expected ClassConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); } } public String getName(int constantIndex) { try { return ((NameAndTypeConstant)constantPool[constantIndex]).getName(this); } catch (ClassCastException ex) { throw ((IllegalStateException)new IllegalStateException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); } } public String getType(int constantIndex) { try { return ((NameAndTypeConstant)constantPool[constantIndex]).getType(this); } catch (ClassCastException ex) { throw ((IllegalStateException)new IllegalStateException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); } } public String getRefName(int constantIndex) { try { return ((RefConstant)constantPool[constantIndex]).getName(this); } catch (ClassCastException ex) { throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); } } public String getRefType(int constantIndex) { try { return ((RefConstant)constantPool[constantIndex]).getType(this); } catch (ClassCastException ex) { throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex)); } } public void addSubClass(Clazz clazz) { if (subClasses == null) { subClasses = new Clazz[1]; } else { // Copy the old elements into new larger array. Clazz[] temp = new Clazz[subClasses.length+1]; System.arraycopy(subClasses, 0, temp, 0, subClasses.length); subClasses = temp; } subClasses[subClasses.length-1] = clazz; } public Clazz getSuperClass() { return u2superClass != 0 ? ((ClassConstant)constantPool[u2superClass]).referencedClass : null; } public Clazz getInterface(int index) { return ((ClassConstant)constantPool[u2interfaces[index]]).referencedClass; } public boolean extends_(Clazz clazz) { if (this.equals(clazz)) { return true; } Clazz superClass = getSuperClass(); return superClass != null && superClass.extends_(clazz); } public boolean extends_(String className) { if (getName().equals(className)) { return true; } Clazz superClass = getSuperClass(); return superClass != null && superClass.extends_(className); } public boolean extendsOrImplements(Clazz clazz) { if (this.equals(clazz)) { return true; } Clazz superClass = getSuperClass(); if (superClass != null && superClass.extendsOrImplements(clazz)) { return true; } for (int index = 0; index < u2interfacesCount; index++) { Clazz interfaceClass = getInterface(index); if (interfaceClass != null && interfaceClass.extendsOrImplements(clazz)) { return true; } } return false; } public boolean extendsOrImplements(String className) { if (getName().equals(className)) { return true; } Clazz superClass = getSuperClass(); if (superClass != null && superClass.extendsOrImplements(className)) { return true; } for (int index = 0; index < u2interfacesCount; index++) { Clazz interfaceClass = getInterface(index); if (interfaceClass != null && interfaceClass.extendsOrImplements(className)) { return true; } } return false; } public Field findField(String name, String descriptor) { for (int index = 0; index < u2fieldsCount; index++) { Field field = fields[index]; if ((name == null || field.getName(this).equals(name)) && (descriptor == null || field.getDescriptor(this).equals(descriptor))) { return field; } } return null; } public Method findMethod(String name, String descriptor) { for (int index = 0; index < u2methodsCount; index++) { Method method = methods[index]; if ((name == null || method.getName(this).equals(name)) && (descriptor == null || method.getDescriptor(this).equals(descriptor))) { return method; } } return null; } public void accept(ClassVisitor classVisitor) { classVisitor.visitProgramClass(this); } public void hierarchyAccept(boolean visitThisClass, boolean visitSuperClass, boolean visitInterfaces, boolean visitSubclasses, ClassVisitor classVisitor) { // First visit the current classfile. if (visitThisClass) { accept(classVisitor); } // Then visit its superclass, recursively. if (visitSuperClass) { Clazz superClass = getSuperClass(); if (superClass != null) { superClass.hierarchyAccept(true, true, visitInterfaces, false, classVisitor); } } // Then visit its interfaces, recursively. if (visitInterfaces) { // Visit the interfaces of the superclasses, if we haven't done so yet. if (!visitSuperClass) { Clazz superClass = getSuperClass(); if (superClass != null) { superClass.hierarchyAccept(false, false, true, false, classVisitor); } } // Visit the interfaces. for (int index = 0; index < u2interfacesCount; index++) { Clazz interfaceClass = getInterface(index); if (interfaceClass != null) { interfaceClass.hierarchyAccept(true, false, true, false, classVisitor); } } } // Then visit its subclasses, recursively. if (visitSubclasses) { if (subClasses != null) { for (int index = 0; index < subClasses.length; index++) { Clazz subClass = subClasses[index]; subClass.hierarchyAccept(true, false, false, true, classVisitor); } } } } public void subclassesAccept(ClassVisitor classVisitor) { if (subClasses != null) { for (int index = 0; index < subClasses.length; index++) { subClasses[index].accept(classVisitor); } } } public void constantPoolEntriesAccept(ConstantVisitor constantVisitor) { for (int index = 1; index < u2constantPoolCount; index++) { if (constantPool[index] != null) { constantPool[index].accept(this, constantVisitor); } } } public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor) { constantPool[index].accept(this, constantVisitor); } public void thisClassConstantAccept(ConstantVisitor constantVisitor) { constantPool[u2thisClass].accept(this, constantVisitor); } public void superClassConstantAccept(ConstantVisitor constantVisitor) { if (u2superClass != 0) { constantPool[u2superClass].accept(this, constantVisitor); } } public void interfaceConstantsAccept(ConstantVisitor constantVisitor) { for (int index = 0; index < u2interfacesCount; index++) { constantPool[u2interfaces[index]].accept(this, constantVisitor); } } public void fieldsAccept(MemberVisitor memberVisitor) { for (int index = 0; index < u2fieldsCount; index++) { fields[index].accept(this, memberVisitor); } } public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor) { Field field = findField(name, descriptor); if (field != null) { field.accept(this, memberVisitor); } } public void methodsAccept(MemberVisitor memberVisitor) { for (int index = 0; index < u2methodsCount; index++) { methods[index].accept(this, memberVisitor); } } public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor) { Method method = findMethod(name, descriptor); if (method != null) { method.accept(this, memberVisitor); } } public boolean mayHaveImplementations(Method method) { return (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 && (method == null || ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_FINAL)) == 0 && !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))); } public void attributesAccept(AttributeVisitor attributeVisitor) { for (int index = 0; index < u2attributesCount; index++) { attributes[index].accept(this, attributeVisitor); } } public void attributeAccept(String name, AttributeVisitor attributeVisitor) { for (int index = 0; index < u2attributesCount; index++) { Attribute attribute = attributes[index]; if (attribute.getAttributeName(this).equals(name)) { attribute.accept(this, attributeVisitor); } } } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } // Implementations for Object. public String toString() { return "ProgramClass("+getName()+")"; } } proguard4.8/src/proguard/classfile/Member.java0000644000175000017500000000324511736333524020225 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.visitor.*; /** * Representation of a field or method from a class. * * @author Eric Lafortune */ public interface Member extends VisitorAccepter { /** * Returns the access flags. */ public int getAccessFlags(); /** * Returns the class member name. */ public String getName(Clazz clazz); /** * Returns the class member's descriptor. */ public String getDescriptor(Clazz clazz); /** * Accepts the given class visitor. */ public void accept(Clazz clazz, MemberVisitor memberVisitor); /** * Lets the Clazz objects referenced in the descriptor string * accept the given visitor. */ public void referencedClassesAccept(ClassVisitor classVisitor); } proguard4.8/src/proguard/classfile/Method.java0000644000175000017500000000203611736333524020233 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; /** * Representation of a method from a class. * * @author Eric Lafortune */ public interface Method extends Member { } proguard4.8/src/proguard/classfile/ProgramMethod.java0000644000175000017500000000605711736333524021572 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.attribute.Attribute; import proguard.classfile.visitor.*; /** * Representation of a method from a program class. * * @author Eric Lafortune */ public class ProgramMethod extends ProgramMember implements Method { /** * An extra field pointing to the Clazz objects referenced in the * descriptor string. This field is filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz[] referencedClasses; /** * Creates an uninitialized ProgramMethod. */ public ProgramMethod() { } /** * Creates an initialized ProgramMethod. */ public ProgramMethod(int u2accessFlags, int u2nameIndex, int u2descriptorIndex, int u2attributesCount, Attribute[] attributes, Clazz[] referencedClasses) { super(u2accessFlags, u2nameIndex, u2descriptorIndex, u2attributesCount, attributes); this.referencedClasses = referencedClasses; } // Implementations for ProgramMember. public void accept(ProgramClass programClass, MemberVisitor memberVisitor) { memberVisitor.visitProgramMethod(programClass, this); } public void attributesAccept(ProgramClass programClass, AttributeVisitor attributeVisitor) { for (int index = 0; index < u2attributesCount; index++) { attributes[index].accept(programClass, this, attributeVisitor); } } // Implementations for Member. public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { for (int index = 0; index < referencedClasses.length; index++) { if (referencedClasses[index] != null) { referencedClasses[index].accept(classVisitor); } } } } } proguard4.8/src/proguard/classfile/constant/0000775000175000017500000000000011760503005017770 5ustar ericericproguard4.8/src/proguard/classfile/constant/LongConstant.java0000644000175000017500000000370511736333524023261 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a long constant in the constant pool. * * @author Eric Lafortune */ public class LongConstant extends Constant { public long u8value; /** * Creates an uninitialized LongConstant. */ public LongConstant() { } /** * Creates a new LongConstant with the given long value. */ public LongConstant(long value) { u8value = value; } /** * Returns the long value of this LongConstant. */ public long getValue() { return u8value; } /** * Sets the long value of this LongConstant. */ public void setValue(long value) { u8value = value; } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_Long; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitLongConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/NameAndTypeConstant.java0000644000175000017500000000562211736333524024527 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a name and type constant in the constant pool. * * @author Eric Lafortune */ public class NameAndTypeConstant extends Constant { public int u2nameIndex; public int u2descriptorIndex; /** * Creates an uninitialized NameAndTypeConstant. */ public NameAndTypeConstant() { } /** * Creates a new NameAndTypeConstant with the given name and type indices. * @param u2nameIndex the index of the name in the constant pool. * @param u2descriptorIndex the index of the descriptor in the constant * pool. */ public NameAndTypeConstant(int u2nameIndex, int u2descriptorIndex) { this.u2nameIndex = u2nameIndex; this.u2descriptorIndex = u2descriptorIndex; } /** * Returns the name index. */ protected int getNameIndex() { return u2nameIndex; } /** * Sets the name index. */ protected void setNameIndex(int index) { u2nameIndex = index; } /** * Returns the descriptor index. */ protected int getDescriptorIndex() { return u2descriptorIndex; } /** * Sets the descriptor index. */ protected void setDescriptorIndex(int index) { u2descriptorIndex = index; } /** * Returns the name. */ public String getName(Clazz clazz) { return clazz.getString(u2nameIndex); } /** * Returns the type. */ public String getType(Clazz clazz) { return clazz.getString(u2descriptorIndex); } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_NameAndType; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitNameAndTypeConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/MethodrefConstant.java0000644000175000017500000000453311736333524024277 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a method reference constant in the constant pool. * * @author Eric Lafortune */ public class MethodrefConstant extends RefConstant { /** * Creates an uninitialized MethodrefConstant. */ public MethodrefConstant() { } /** * Creates a new MethodrefConstant with the given name and type indices. * @param u2classIndex the index of the class in the constant pool. * @param u2nameAndTypeIndex the index of the name and type entry in the constant pool. * @param referencedClass the referenced class. * @param referencedMember the referenced member info. */ public MethodrefConstant(int u2classIndex, int u2nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { this.u2classIndex = u2classIndex; this.u2nameAndTypeIndex = u2nameAndTypeIndex; this.referencedClass = referencedClass; this.referencedMember = referencedMember; } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_Methodref; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitMethodrefConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/FloatConstant.java0000644000175000017500000000372611736333524023432 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a float constant in the constant pool. * * @author Eric Lafortune */ public class FloatConstant extends Constant { public float f4value; /** * Creates an uninitialized FloatConstant. */ public FloatConstant() { } /** * Creates a new FloatConstant with the given float value. */ public FloatConstant(float value) { f4value = value; } /** * Returns the float value of this FloatConstant. */ public float getValue() { return f4value; } /** * Sets the float value of this FloatConstant. */ public void setValue(float value) { f4value = value; } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_Float; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitFloatConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/Constant.java0000644000175000017500000000363111736333524022437 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This abstract class represents an entry in the ConstantPool. Specific types * of entries are subclassed from it. * * @author Eric Lafortune */ public abstract class Constant implements VisitorAccepter { //public int u1tag; //public byte info[]; /** * An extra field in which visitors can store information. */ public Object visitorInfo; // Abstract methods to be implemented by extensions. /** * Returns the constant pool info tag that specifies the entry type. */ public abstract int getTag(); /** * Accepts the given visitor. */ public abstract void accept(Clazz clazz, ConstantVisitor constantVisitor); // Implementations for VisitorAccepter. public Object getVisitorInfo() { return visitorInfo; } public void setVisitorInfo(Object visitorInfo) { this.visitorInfo = visitorInfo; } } proguard4.8/src/proguard/classfile/constant/Utf8Constant.java0000644000175000017500000002211311736333524023202 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; import java.io.UnsupportedEncodingException; /** * This Constant represents a UTF-8 constant in the constant pool. * * @author Eric Lafortune */ public class Utf8Constant extends Constant { private static final char TWO_BYTE_LIMIT = 0x80; private static final int TWO_BYTE_CONSTANT1 = 0xc0; private static final int TWO_BYTE_CONSTANT2 = 0x80; private static final int TWO_BYTE_SHIFT1 = 6; private static final int TWO_BYTE_MASK1 = 0x1f; private static final int TWO_BYTE_MASK2 = 0x3f; private static final char THREE_BYTE_LIMIT = 0x800; private static final int THREE_BYTE_CONSTANT1 = 0xe0; private static final int THREE_BYTE_CONSTANT2 = 0x80; private static final int THREE_BYTE_CONSTANT3 = 0x80; private static final int THREE_BYTE_SHIFT1 = 12; private static final int THREE_BYTE_SHIFT2 = 6; private static final int THREE_BYTE_MASK1 = 0x0f; private static final int THREE_BYTE_MASK2 = 0x3f; private static final int THREE_BYTE_MASK3 = 0x3f; // There are a lot of Utf8Constant objects, so we're optimising their storage. // Initially, we're storing the UTF-8 bytes in a byte array. // When the corresponding String is requested, we ditch the array and just // store the String. //private int u2length; private byte[] bytes; private String string; /** * Creates an uninitialized Utf8Constant. * */ public Utf8Constant() { } /** * Creates a Utf8Constant containing the given string. */ public Utf8Constant(String string) { this.bytes = null; this.string = string; } /** * Initializes the UTF-8 data with an array of bytes. */ public void setBytes(byte[] bytes) { this.bytes = bytes; this.string = null; } /** * Returns the UTF-8 data as an array of bytes. */ public byte[] getBytes() { try { switchToByteArrayRepresentation(); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex.getMessage()); } return bytes; } /** * Initializes the UTF-8 data with a String. */ public void setString(String utf8String) { this.bytes = null; this.string = utf8String; } /** * Returns the UTF-8 data as a String. */ public String getString() { try { switchToStringRepresentation(); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex.getMessage()); } return string; } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_Utf8; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitUtf8Constant(clazz, this); } // Small utility methods. /** * Switches to a byte array representation of the UTF-8 data. */ private void switchToByteArrayRepresentation() throws UnsupportedEncodingException { if (bytes == null) { bytes = getByteArrayRepresentation(string); string = null; } } /** * Switches to a String representation of the UTF-8 data. */ private void switchToStringRepresentation() throws UnsupportedEncodingException { if (string == null) { string = getStringRepresentation(bytes); bytes = null; } } /** * Returns the modified UTF-8 byte array representation of the given string. */ private byte[] getByteArrayRepresentation(String string) throws UnsupportedEncodingException { // We're computing the byte array ourselves, because the implementation // of String.getBytes("UTF-8") has a bug, at least up to JRE 1.4.2. // Also note the special treatment of the 0 character. // Compute the byte array length. int byteLength = 0; int stringLength = string.length(); for (int stringIndex = 0; stringIndex < stringLength; stringIndex++) { char c = string.charAt(stringIndex); // The character is represented by one, two, or three bytes. byteLength += c == 0 ? 2 : c < TWO_BYTE_LIMIT ? 1 : c < THREE_BYTE_LIMIT ? 2 : 3; } // Allocate the byte array with the computed length. byte[] bytes = new byte[byteLength]; // Fill out the array. int byteIndex = 0; for (int stringIndex = 0; stringIndex < stringLength; stringIndex++) { char c = string.charAt(stringIndex); if (c == 0) { // The 0 character gets a two-byte representation in classes. bytes[byteIndex++] = (byte)TWO_BYTE_CONSTANT1; bytes[byteIndex++] = (byte)TWO_BYTE_CONSTANT2; } else if (c < TWO_BYTE_LIMIT) { // The character is represented by a single byte. bytes[byteIndex++] = (byte)c; } else if (c < THREE_BYTE_LIMIT) { // The character is represented by two bytes. bytes[byteIndex++] = (byte)(TWO_BYTE_CONSTANT1 | ((c >>> TWO_BYTE_SHIFT1) & TWO_BYTE_MASK1)); bytes[byteIndex++] = (byte)(TWO_BYTE_CONSTANT2 | ( c & TWO_BYTE_MASK2)); } else { // The character is represented by three bytes. bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT1 | ((c >>> THREE_BYTE_SHIFT1) & THREE_BYTE_MASK1)); bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT2 | ((c >>> THREE_BYTE_SHIFT2) & THREE_BYTE_MASK2)); bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT3 | ( c & THREE_BYTE_MASK3)); } } return bytes; } /** * Returns the String representation of the given modified UTF-8 byte array. */ private String getStringRepresentation(byte[] bytes) throws UnsupportedEncodingException { // We're computing the string ourselves, because the implementation // of "new String(bytes)" doesn't honor the special treatment of // the 0 character in JRE 1.6_u11. // Allocate the byte array with the computed length. char[] chars = new char[bytes.length]; // Fill out the array. int charIndex = 0; int byteIndex = 0; while (byteIndex < bytes.length) { int b = bytes[byteIndex++] & 0xff; // Depending on the flag bits in the first byte, the character // is represented by a single byte, by two bytes, or by three // bytes. We're not checking the redundant flag bits in the // second byte and the third byte. try { chars[charIndex++] = (char)(b < TWO_BYTE_CONSTANT1 ? b : b < THREE_BYTE_CONSTANT1 ? ((b & TWO_BYTE_MASK1) << TWO_BYTE_SHIFT1) | ((bytes[byteIndex++] & TWO_BYTE_MASK2) ) : ((b & THREE_BYTE_MASK1) << THREE_BYTE_SHIFT1) | ((bytes[byteIndex++] & THREE_BYTE_MASK2) << THREE_BYTE_SHIFT2) | ((bytes[byteIndex++] & THREE_BYTE_MASK3) )); } catch (ArrayIndexOutOfBoundsException e) { throw new UnsupportedEncodingException("Missing UTF-8 bytes after initial byte [0x"+Integer.toHexString(b)+"] in string ["+new String(chars, 0, charIndex)+"]"); } } return new String(chars, 0, charIndex); } } proguard4.8/src/proguard/classfile/constant/FieldrefConstant.java0000644000175000017500000000453011736333524024077 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a field reference constant in the constant pool. * * @author Eric Lafortune */ public class FieldrefConstant extends RefConstant { /** * Creates an uninitialized FieldrefConstant. */ public FieldrefConstant() { } /** * Creates a new FieldrefConstant with the given name and type indices. * @param u2classIndex the index of the class in the constant pool. * @param u2nameAndTypeIndex the index of the name and type entry in the constant pool. * @param referencedClass the referenced class. * @param referencedMember the referenced member info. */ public FieldrefConstant(int u2classIndex, int u2nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { this.u2classIndex = u2classIndex; this.u2nameAndTypeIndex = u2nameAndTypeIndex; this.referencedClass = referencedClass; this.referencedMember = referencedMember; } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_Fieldref; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitFieldrefConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/ClassConstant.java0000644000175000017500000000562411736333524023431 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This Constant represents a class constant in the constant pool. * * @author Eric Lafortune */ public class ClassConstant extends Constant { public int u2nameIndex; /** * An extra field pointing to the referenced Clazz object. * This field is filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}. */ public Clazz referencedClass; /** * An extra field pointing to the java.lang.Class Clazz object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}.. */ public Clazz javaLangClassClass; /** * Creates an uninitialized ClassConstant. */ public ClassConstant() { } /** * Creates a new ClassConstant with the given name index. * @param u2nameIndex the index of the name in the constant pool. * @param referencedClass the referenced class. */ public ClassConstant(int u2nameIndex, Clazz referencedClass) { this.u2nameIndex = u2nameIndex; this.referencedClass = referencedClass; } /** * Returns the name. */ public String getName(Clazz clazz) { return clazz.getString(u2nameIndex); } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_Class; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitClassConstant(clazz, this); } /** * Lets the referenced class accept the given visitor. */ public void referencedClassAccept(ClassVisitor classVisitor) { if (referencedClass != null) { referencedClass.accept(classVisitor); } } } proguard4.8/src/proguard/classfile/constant/DoubleConstant.java0000644000175000017500000000374711736333524023602 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a double constant in the constant pool. * * @author Eric Lafortune */ public class DoubleConstant extends Constant { public double f8value; /** * Creates an uninitialized DoubleConstant. */ public DoubleConstant() { } /** * Creates a new DoubleConstant with the given double value. */ public DoubleConstant(double value) { f8value = value; } /** * Returns the double value of this DoubleConstant. */ public double getValue() { return f8value; } /** * Sets the double value of this DoubleConstant. */ public void setValue(double value) { f8value = value; } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_Double; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitDoubleConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/InvokeDynamicConstant.java0000755000175000017500000001072211736333524025122 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.*; import proguard.classfile.visitor.*; /** * This Constant represents an invoke dynamic constant in the constant pool. * * @author Eric Lafortune */ public class InvokeDynamicConstant extends Constant { public int u2bootstrapMethodAttributeIndex; public int u2nameAndTypeIndex; /** * An extra field pointing to the Clazz objects referenced in the * descriptor string. This field is filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}. * References to primitive types are ignored. */ public Clazz[] referencedClasses; /** * Creates an uninitialized InvokeDynamicConstant. */ public InvokeDynamicConstant() { } /** * Creates a new InvokeDynamicConstant with the given bootstrap method * and name-and-type indices. * @param u2bootstrapMethodAttributeIndex the index of the bootstrap method * entry in the bootstrap methods * attribute. * @param u2nameAndTypeIndex the index of the name and type * entry in the constant pool. * @param referencedClasses the classes referenced by the * type. */ public InvokeDynamicConstant(int u2bootstrapMethodAttributeIndex, int u2nameAndTypeIndex, Clazz[] referencedClasses) { this.u2bootstrapMethodAttributeIndex = u2bootstrapMethodAttributeIndex; this.u2nameAndTypeIndex = u2nameAndTypeIndex; this.referencedClasses = referencedClasses; } /** * Returns the index of the bootstrap method in the bootstrap methods * attribute of the class. */ public int getBootstrapMethodAttributeIndex() { return u2bootstrapMethodAttributeIndex; } /** * Returns the name-and-type index. */ public int getNameAndTypeIndex() { return u2nameAndTypeIndex; } /** * Returns the method name. */ public String getName(Clazz clazz) { return clazz.getName(u2nameAndTypeIndex); } /** * Returns the method type. */ public String getType(Clazz clazz) { return clazz.getType(u2nameAndTypeIndex); } /** * Lets the Clazz objects referenced in the descriptor string * accept the given visitor. */ public void referencedClassesAccept(ClassVisitor classVisitor) { if (referencedClasses != null) { for (int index = 0; index < referencedClasses.length; index++) { if (referencedClasses[index] != null) { referencedClasses[index].accept(classVisitor); } } } } /** * Lets the bootstrap method handle constant accept the given visitor. */ public void bootstrapMethodHandleAccept(Clazz clazz, ConstantVisitor constantVisitor) { new BootstrapMethodHandleTraveler(constantVisitor).visitInvokeDynamicConstant(clazz, this); } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_InvokeDynamic; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitInvokeDynamicConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/visitor/0000775000175000017500000000000011760503005021467 5ustar ericericproguard4.8/src/proguard/classfile/constant/visitor/package.html0000644000175000017500000000010311736333524023752 0ustar ericeric This package contains visitors for class constants. proguard4.8/src/proguard/classfile/constant/visitor/MethodrefTraveler.java0000644000175000017500000000400411736333524025762 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant.visitor; import proguard.classfile.Clazz; import proguard.classfile.attribute.*; import proguard.classfile.constant.*; import proguard.classfile.util.SimplifiedVisitor; /** * This ConstantVisitor travels from any method handle constants that it visits * to their methodref constants, and applies a given constant visitor. * * @author Eric Lafortune */ public class MethodrefTraveler extends SimplifiedVisitor implements ConstantVisitor { private ConstantVisitor methodrefConstantVisitor; /** * Creates a new v that will delegate to the given constant visitor. */ public MethodrefTraveler(ConstantVisitor methodrefConstantVisitor) { this.methodrefConstantVisitor = methodrefConstantVisitor; } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, methodrefConstantVisitor); } } proguard4.8/src/proguard/classfile/constant/visitor/ConstantVisitor.java0000644000175000017500000000517711736333524025525 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant.visitor; import proguard.classfile.Clazz; import proguard.classfile.constant.*; /** * This interface specifies the methods for a visitor of Constant * objects. * * @author Eric Lafortune */ public interface ConstantVisitor { public void visitIntegerConstant( Clazz clazz, IntegerConstant integerConstant); public void visitLongConstant( Clazz clazz, LongConstant longConstant); public void visitFloatConstant( Clazz clazz, FloatConstant floatConstant); public void visitDoubleConstant( Clazz clazz, DoubleConstant doubleConstant); public void visitStringConstant( Clazz clazz, StringConstant stringConstant); public void visitUtf8Constant( Clazz clazz, Utf8Constant utf8Constant); public void visitInvokeDynamicConstant( Clazz clazz, InvokeDynamicConstant invokeDynamicConstant); public void visitMethodHandleConstant( Clazz clazz, MethodHandleConstant methodHandleConstant); public void visitFieldrefConstant( Clazz clazz, FieldrefConstant fieldrefConstant); public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant); public void visitMethodrefConstant( Clazz clazz, MethodrefConstant methodrefConstant); public void visitClassConstant( Clazz clazz, ClassConstant classConstant); public void visitMethodTypeConstant( Clazz clazz, MethodTypeConstant methodTypeConstant); public void visitNameAndTypeConstant( Clazz clazz, NameAndTypeConstant nameAndTypeConstant); } proguard4.8/src/proguard/classfile/constant/visitor/ConstantTagFilter.java0000644000175000017500000000553611736333524025746 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant.visitor; import proguard.classfile.Clazz; import proguard.classfile.constant.*; import proguard.classfile.util.SimplifiedVisitor; /** * This ConstantVisitor delegates its visits to one or more * specified types of constants. * * @author Eric Lafortune */ public class ConstantTagFilter extends SimplifiedVisitor implements ConstantVisitor { private final int constantTagMask; private final ConstantVisitor constantVisitor; /** * Creates a new ConstantTagFilter. * @param constantTag the type of constants for which visits will be * delegated. * @param constantVisitor the ConstantVisitor to which visits * will be delegated. */ public ConstantTagFilter(int constantTag, ConstantVisitor constantVisitor) { this.constantTagMask = 1 << constantTag; this.constantVisitor = constantVisitor; } /** * Creates a new ConstantTagFilter. * @param constantTags the types of constants for which visits will be * delegated. * @param constantVisitor the ConstantVisitor to which visits * will be delegated. */ public ConstantTagFilter(int[] constantTags, ConstantVisitor constantVisitor) { int constantTagMask = 0; for (int index = 0; index < constantTags.length; index++) { constantTagMask |= 1 << constantTags[index]; } this.constantTagMask = constantTagMask; this.constantVisitor = constantVisitor; } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) { if (((1 << constant.getTag()) & constantTagMask) != 0) { constant.accept(clazz, constantVisitor); } } }proguard4.8/src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java0000644000175000017500000000673411736333524030313 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant.visitor; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; import proguard.optimize.info.MethodOptimizationInfo; /** * This ConstantVisitor and BootstrapMethodInfoVisitor travels from any invoke * dynamic constants or bootstrap method info entries that it visits to their * bootstrap method handle constants, and applies a given constant visitor. * * @author Eric Lafortune */ public class BootstrapMethodHandleTraveler extends SimplifiedVisitor implements ConstantVisitor, AttributeVisitor, BootstrapMethodInfoVisitor { private ConstantVisitor bootstrapMethodHandleVisitor; // Field serving as a method argument. int bootstrapMethodAttributeIndex; /** * Creates a new BootstrapMethodHandleVisitor that will delegate to the * given constant visitor. */ public BootstrapMethodHandleTraveler(ConstantVisitor bootstrapMethodHandleVisitor) { this.bootstrapMethodHandleVisitor = bootstrapMethodHandleVisitor; } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { // Pass the method index. bootstrapMethodAttributeIndex = invokeDynamicConstant.u2bootstrapMethodAttributeIndex; // Delegate to the bootstrap method. clazz.attributesAccept(this); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { // Check bootstrap methods. bootstrapMethodsAttribute.bootstrapMethodEntryAccept(clazz, bootstrapMethodAttributeIndex, this); } // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { // Check bootstrap method. clazz.constantPoolEntryAccept(bootstrapMethodInfo.u2methodHandleIndex, bootstrapMethodHandleVisitor); } } proguard4.8/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java0000644000175000017500000000473511736333524027451 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant.visitor; import proguard.classfile.*; import proguard.classfile.editor.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.constant.ClassConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This ConstantVisitor delegates its visits to class constants * to another given ConstantVisitor, except for one given class. * * @author Eric Lafortune */ public class ExceptClassConstantFilter extends SimplifiedVisitor implements ConstantVisitor { private final String exceptClassName; private final ConstantVisitor constantVisitor; /** * Creates a new ExceptClassConstantFilter. * @param exceptClassName the name of the class that will not be visited. * @param constantVisitor the ConstantVisitor to which visits * will be delegated. */ public ExceptClassConstantFilter(String exceptClassName, ConstantVisitor constantVisitor) { this.exceptClassName = exceptClassName; this.constantVisitor = constantVisitor; } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { if (!classConstant.getName(clazz).equals(exceptClassName)) { constantVisitor.visitClassConstant(clazz, classConstant); } } }proguard4.8/src/proguard/classfile/constant/visitor/AllConstantVisitor.java0000644000175000017500000000320011736333524026137 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant.visitor; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor lets a given ConstantVisitor visit all constant pool * entries of the program classes it visits. * * @author Eric Lafortune */ public class AllConstantVisitor implements ClassVisitor { private final ConstantVisitor constantVisitor; public AllConstantVisitor(ConstantVisitor constantVisitor) { this.constantVisitor = constantVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.constantPoolEntriesAccept(constantVisitor); } public void visitLibraryClass(LibraryClass libraryClass) {} } proguard4.8/src/proguard/classfile/constant/StringConstant.java0000644000175000017500000001006511736333524023625 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.visitor.*; /** * This Constant represents a string constant in the constant pool. * * @author Eric Lafortune */ public class StringConstant extends Constant { public int u2stringIndex; /** * An extra field pointing to the referenced Clazz object, if this * string is being used in Class.forName(), .class, or * Class.getDeclaredField/Method constructs. * This field is typically filled out by the {@link * proguard.classfile.util.DynamicClassReferenceInitializer * DynamicClassReferenceInitializer} or by the {@link * proguard.classfile.util.DynamicMemberReferenceInitializer * DynamicMemberReferenceInitializer}. */ public Clazz referencedClass; /** * An extra field pointing to the referenced Member object, if this * string is being used in Class.getDeclaredField/Method constructs. * This field is typically filled out by the {@link * proguard.classfile.util.DynamicMemberReferenceInitializer * DynamicMemberReferenceInitializer}. */ public Member referencedMember; /** * An extra field pointing to the java.lang.String Clazz object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}.. */ public Clazz javaLangStringClass; /** * Creates an uninitialized StringConstant. */ public StringConstant() { } /** * Creates a new StringConstant with the given string index. * @param u2stringIndex the index of the string in the constant pool. * @param referencedClass the referenced class, if any. * @param referenceMember the referenced class member, if any. */ public StringConstant(int u2stringIndex, Clazz referencedClass, Member referenceMember) { this.u2stringIndex = u2stringIndex; this.referencedClass = referencedClass; this.referencedMember = referenceMember; } /** * Returns the string value. */ public String getString(Clazz clazz) { return clazz.getString(u2stringIndex); } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_String; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitStringConstant(clazz, this); } /** * Lets the referenced class accept the given visitor. */ public void referencedClassAccept(ClassVisitor classVisitor) { if (referencedClass != null && referencedMember == null) { referencedClass.accept(classVisitor); } } /** * Lets the referenced member accept the given visitor. */ public void referencedMemberAccept(MemberVisitor memberVisitor) { if (referencedMember != null) { referencedMember.accept(referencedClass, memberVisitor); } } } proguard4.8/src/proguard/classfile/constant/MethodTypeConstant.java0000644000175000017500000000473311736333524024446 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a method handle constant in the constant pool. * * @author Eric Lafortune */ public class MethodTypeConstant extends Constant { public int u2descriptorIndex; /** * An extra field pointing to the java.lang.invoke.MethodType Clazz object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}.. */ public Clazz javaLangInvokeMethodTypeClass; /** * Creates an uninitialized MethodTypeConstant. */ public MethodTypeConstant() { } /** * Creates a new MethodTypeConstant with the given descriptor index. * @param u2descriptorIndex the index of the descriptor in the constant * pool. */ public MethodTypeConstant(int u2descriptorIndex) { this.u2descriptorIndex = u2descriptorIndex; } /** * Returns the descriptor index. */ public int getDescriptorIndex() { return u2descriptorIndex; } /** * Returns the type. */ public String getType(Clazz clazz) { return clazz.getString(u2descriptorIndex); } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_MethodType; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitMethodTypeConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/InterfaceMethodrefConstant.java0000644000175000017500000000470311736333524026117 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a interface method reference constant in the constant pool. * * @author Eric Lafortune */ public class InterfaceMethodrefConstant extends RefConstant { /** * Creates an uninitialized InterfaceMethodrefConstant. */ public InterfaceMethodrefConstant() { } /** * Creates a new InterfaceMethodrefConstant with the given name and type indices. * @param u2classIndex the index of the class in the constant pool. * @param u2nameAndTypeIndex the index of the name and type entry in the constant pool. * @param referencedClass the referenced class. * @param referencedMember the referenced member info. */ public InterfaceMethodrefConstant(int u2classIndex, int u2nameAndTypeIndex, Clazz referencedClass, Member referencedMember) { this.u2classIndex = u2classIndex; this.u2nameAndTypeIndex = u2nameAndTypeIndex; this.referencedClass = referencedClass; this.referencedMember = referencedMember; } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_InterfaceMethodref; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitInterfaceMethodrefConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/RefConstant.java0000644000175000017500000000632311736333524023075 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.visitor.*; /** * This Constant represents a ref constant in the constant pool. * * @author Eric Lafortune */ public abstract class RefConstant extends Constant { public int u2classIndex; public int u2nameAndTypeIndex; /** * An extra field pointing to the referenced Clazz object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}. */ public Clazz referencedClass; /** * An extra field optionally pointing to the referenced Member object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}. */ public Member referencedMember; protected RefConstant() { } /** * Returns the class index. */ public int getClassIndex() { return u2classIndex; } /** * Returns the name-and-type index. */ public int getNameAndTypeIndex() { return u2nameAndTypeIndex; } /** * Sets the name-and-type index. */ public void setNameAndTypeIndex(int index) { u2nameAndTypeIndex = index; } /** * Returns the class name. */ public String getClassName(Clazz clazz) { return clazz.getClassName(u2classIndex); } /** * Returns the method/field name. */ public String getName(Clazz clazz) { return clazz.getName(u2nameAndTypeIndex); } /** * Returns the type. */ public String getType(Clazz clazz) { return clazz.getType(u2nameAndTypeIndex); } /** * Lets the referenced class accept the given visitor. */ public void referencedClassAccept(ClassVisitor classVisitor) { if (referencedClass != null) { referencedClass.accept(classVisitor); } } /** * Lets the referenced class member accept the given visitor. */ public void referencedMemberAccept(MemberVisitor memberVisitor) { if (referencedMember != null) { referencedMember.accept(referencedClass, memberVisitor); } } } proguard4.8/src/proguard/classfile/constant/MethodHandleConstant.java0000755000175000017500000000721211736333524024716 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a method handle constant in the constant pool. * * @author Eric Lafortune */ public class MethodHandleConstant extends Constant { public int u1referenceKind; public int u2referenceIndex; /** * An extra field pointing to the java.lang.invoke.MethodHandle Clazz object. * This field is typically filled out by the {@link * proguard.classfile.util.ClassReferenceInitializer * ClassReferenceInitializer}.. */ public Clazz javaLangInvokeMethodHandleClass; /** * Creates an uninitialized MethodHandleConstant. */ public MethodHandleConstant() { } /** * Creates a new MethodHandleConstant with the given type and method ref * index. * @param u1referenceKind the reference kind. * @param u2referenceIndex the index of the field ref constant, interface * method ref constant, or method ref constant in * the constant pool. */ public MethodHandleConstant(int u1referenceKind, int u2referenceIndex) { this.u1referenceKind = u1referenceKind; this.u2referenceIndex = u2referenceIndex; } /** * Returns the kind of reference to which this constant is pointing. * @return One of * {@link ClassConstants#REF_getField }, * {@link ClassConstants#REF_getStatic }, * {@link ClassConstants#REF_putField }, * {@link ClassConstants#REF_putStatic }, * {@link ClassConstants#REF_invokeVirtual }, * {@link ClassConstants#REF_invokeStatic }, * {@link ClassConstants#REF_invokeSpecial }, * {@link ClassConstants#REF_newInvokeSpecial}, or * {@link ClassConstants#REF_invokeInterface }. */ public int getReferenceKind() { return u1referenceKind; } /** * Returns the field ref, interface method ref, or method ref index. */ public int getReferenceIndex() { return u2referenceIndex; } /** * Returns the method/field name. */ public String getName(Clazz clazz) { return clazz.getRefName(u2referenceIndex); } /** * Returns the type. */ public String getType(Clazz clazz) { return clazz.getRefType(u2referenceIndex); } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_MethodHandle; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitMethodHandleConstant(clazz, this); } } proguard4.8/src/proguard/classfile/constant/IntegerConstant.java0000644000175000017500000000375011736333524023757 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.classfile.constant; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; /** * This Constant represents a integer constant in the constant pool. * * @author Eric Lafortune */ public class IntegerConstant extends Constant { public int u4value; /** * Creates an uninitialized IntegerConstant. */ public IntegerConstant() { } /** * Creates a new IntegerConstant with the given integer value. */ public IntegerConstant(int value) { u4value = value; } /** * Returns the integer value of this IntegerConstant. */ public int getValue() { return u4value; } /** * Sets the integer value of this IntegerConstant. */ public void setValue(int value) { u4value = value; } // Implementations for Constant. public int getTag() { return ClassConstants.CONSTANT_Integer; } public void accept(Clazz clazz, ConstantVisitor constantVisitor) { constantVisitor.visitIntegerConstant(clazz, this); } } proguard4.8/src/proguard/ClassPath.java0000644000175000017500000000451411736333524016733 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.util.*; /** * This class represents a class path, as a list of ClassPathEntry objects. * * @author Eric Lafortune */ public class ClassPath { private final List classPathEntries = new ArrayList(); /** * Returns whether the class path contains any output entries. */ public boolean hasOutput() { for (int index = 0; index < classPathEntries.size(); index++) { if (((ClassPathEntry)classPathEntries.get(index)).isOutput()) { return true; } } return false; } // Delegates to List. public void clear() { classPathEntries.clear(); } public void add(int index, ClassPathEntry classPathEntry) { classPathEntries.add(index, classPathEntry); } public boolean add(ClassPathEntry classPathEntry) { return classPathEntries.add(classPathEntry); } public boolean addAll(ClassPath classPath) { return classPathEntries.addAll(classPath.classPathEntries); } public ClassPathEntry get(int index) { return (ClassPathEntry)classPathEntries.get(index); } public ClassPathEntry remove(int index) { return (ClassPathEntry)classPathEntries.remove(index); } public boolean isEmpty() { return classPathEntries.isEmpty(); } public int size() { return classPathEntries.size(); } } proguard4.8/src/proguard/ClassSpecificationVisitorFactory.java0000644000175000017500000005016411736333524023531 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.AllAttributeVisitor; import proguard.classfile.visitor.*; import java.util.List; /** * This factory creates visitors to efficiently travel to specified classes and * class members. * * @author Eric Lafortune */ public class ClassSpecificationVisitorFactory { /** * Constructs a ClassPoolVisitor to efficiently travel to the specified * classes and class members. * * @param keepClassSpecifications the list of KeepClassSpecification * instances, defining of the classes and * class members to visit. * @param classVisitor the ClassVisitor to be applied to matching * classes. * @param memberVisitor the MemberVisitor to be applied to matching * class members. */ public static ClassPoolVisitor createClassPoolVisitor(List keepClassSpecifications, ClassVisitor classVisitor, MemberVisitor memberVisitor, boolean shrinking, boolean optimizing, boolean obfuscating) { MultiClassPoolVisitor multiClassPoolVisitor = new MultiClassPoolVisitor(); if (keepClassSpecifications != null) { for (int index = 0; index < keepClassSpecifications.size(); index++) { KeepClassSpecification keepClassSpecification = (KeepClassSpecification)keepClassSpecifications.get(index); if ((shrinking && !keepClassSpecification.allowShrinking) || (optimizing && !keepClassSpecification.allowOptimization) || (obfuscating && !keepClassSpecification.allowObfuscation)) { multiClassPoolVisitor.addClassPoolVisitor( createClassPoolVisitor(keepClassSpecification, classVisitor, memberVisitor)); } } } return multiClassPoolVisitor; } /** * Constructs a ClassPoolVisitor to efficiently travel to the specified * classes and class members. * * @param classSpecifications the list of ClassSpecification instances, * defining of the classes and class members to * visit. * @param classVisitor the ClassVisitor to be applied to matching * classes. * @param memberVisitor the MemberVisitor to be applied to matching * class members. */ public static ClassPoolVisitor createClassPoolVisitor(List classSpecifications, ClassVisitor classVisitor, MemberVisitor memberVisitor) { MultiClassPoolVisitor multiClassPoolVisitor = new MultiClassPoolVisitor(); if (classSpecifications != null) { for (int index = 0; index < classSpecifications.size(); index++) { ClassSpecification classSpecification = (ClassSpecification)classSpecifications.get(index); multiClassPoolVisitor.addClassPoolVisitor( createClassPoolVisitor(classSpecification, classVisitor, memberVisitor)); } } return multiClassPoolVisitor; } /** * Constructs a ClassPoolVisitor to efficiently travel to the specified * classes and class members. * * @param keepClassSpecification the specifications of the class(es) and class * members to visit. * @param classVisitor the ClassVisitor to be applied to matching * classes. * @param memberVisitor the MemberVisitor to be applied to matching * class members. */ private static ClassPoolVisitor createClassPoolVisitor(KeepClassSpecification keepClassSpecification, ClassVisitor classVisitor, MemberVisitor memberVisitor) { // Don't visit the classes if not specified. if (!keepClassSpecification.markClasses && !keepClassSpecification.markConditionally) { classVisitor = null; } // If specified, let the marker visit the class and its class // members conditionally. if (keepClassSpecification.markConditionally) { // Combine both visitors. ClassVisitor composedClassVisitor = createCombinedClassVisitor(keepClassSpecification, classVisitor, memberVisitor); // Replace the class visitor. classVisitor = createClassMemberTester(keepClassSpecification, composedClassVisitor); // Discard the member visitor, because it has already been included. memberVisitor = null; } return createClassPoolVisitor((ClassSpecification)keepClassSpecification, classVisitor, memberVisitor); } /** * Constructs a ClassPoolVisitor to efficiently travel to the specified * classes and class members. * * @param classSpecification the specifications of the class(es) and class * members to visit. * @param classVisitor the ClassVisitor to be applied to matching * classes. * @param memberVisitor the MemberVisitor to be applied to matching * class members. */ private static ClassPoolVisitor createClassPoolVisitor(ClassSpecification classSpecification, ClassVisitor classVisitor, MemberVisitor memberVisitor) { // Combine both visitors. ClassVisitor composedClassVisitor = createCombinedClassVisitor(classSpecification, classVisitor, memberVisitor); // By default, start visiting from the named class name, if specified. String className = classSpecification.className; // Although we may have to start from the extended class. String extendsAnnotationType = classSpecification.extendsAnnotationType; String extendsClassName = classSpecification.extendsClassName; // If wildcarded, only visit classes with matching names. if (className != null && (extendsAnnotationType != null || extendsClassName != null || containsWildCards(className))) { composedClassVisitor = new ClassNameFilter(className, composedClassVisitor); // We'll have to visit all classes now. className = null; } // If specified, only visit classes with the right annotation. String annotationType = classSpecification.annotationType; if (annotationType != null) { composedClassVisitor = new AllAttributeVisitor( new AllAnnotationVisitor( new AnnotationTypeFilter(annotationType, new AnnotatedClassVisitor(composedClassVisitor)))); } // If specified, only visit classes with the right access flags. if (classSpecification.requiredSetAccessFlags != 0 || classSpecification.requiredUnsetAccessFlags != 0) { composedClassVisitor = new ClassAccessFilter(classSpecification.requiredSetAccessFlags, classSpecification.requiredUnsetAccessFlags, composedClassVisitor); } // If it's specified, start visiting from the extended class. if (extendsAnnotationType != null || extendsClassName != null) { // Start visiting from the extended class. composedClassVisitor = new ClassHierarchyTraveler(false, false, false, true, composedClassVisitor); // If specified, only visit extended classes with the right annotation. if (extendsAnnotationType != null) { composedClassVisitor = new AllAttributeVisitor( new AllAnnotationVisitor( new AnnotationTypeFilter(extendsAnnotationType, new AnnotatedClassVisitor(composedClassVisitor)))); } // If specified, only visit extended classes with matching names. if (extendsClassName != null) { // If wildcarded, only visit extended classes with matching names. if (containsWildCards(extendsClassName)) { composedClassVisitor = new ClassNameFilter(extendsClassName, composedClassVisitor); } else { // Start visiting from the named extended class. className = extendsClassName; } } } // If specified, visit a single named class, otherwise visit all classes. return className != null ? (ClassPoolVisitor)new NamedClassVisitor(composedClassVisitor, className) : (ClassPoolVisitor)new AllClassVisitor(composedClassVisitor); } /** * Constructs a ClassVisitor to efficiently travel to the specified * classes and class members. * * @param classSpecification the specifications of the class(es) and class * members to visit. * @param classVisitor the ClassVisitor to be applied to matching * classes. * @param memberVisitor the MemberVisitor to be applied to matching * class members. */ private static ClassVisitor createCombinedClassVisitor(ClassSpecification classSpecification, ClassVisitor classVisitor, MemberVisitor memberVisitor) { // Don't visit any members if there aren't any member specifications. if (classSpecification.fieldSpecifications == null && classSpecification.methodSpecifications == null) { memberVisitor = null; } // The class visitor for classes and their members. MultiClassVisitor multiClassVisitor = new MultiClassVisitor(); // If specified, let the class visitor visit the class itself. if (classVisitor != null) { // This class visitor may be the only one. if (memberVisitor == null) { return classVisitor; } multiClassVisitor.addClassVisitor(classVisitor); } // If specified, let the member info visitor visit the class members. if (memberVisitor != null) { ClassVisitor memberClassVisitor = createClassVisitor(classSpecification, memberVisitor); // This class visitor may be the only one. if (classVisitor == null) { return memberClassVisitor; } multiClassVisitor.addClassVisitor(memberClassVisitor); } return multiClassVisitor; } /** * Constructs a ClassVisitor to efficiently travel to the specified class * members. * * @param classSpecification the specifications of the class members to visit. * @param memberVisitor the MemberVisitor to be applied to matching * class members. */ private static ClassVisitor createClassVisitor(ClassSpecification classSpecification, MemberVisitor memberVisitor) { MultiClassVisitor multiClassVisitor = new MultiClassVisitor(); addMemberVisitors(classSpecification.fieldSpecifications, true, multiClassVisitor, memberVisitor); addMemberVisitors(classSpecification.methodSpecifications, false, multiClassVisitor, memberVisitor); // Mark the class member in this class and in super classes. return new ClassHierarchyTraveler(true, true, false, false, multiClassVisitor); } /** * Adds elements to the given MultiClassVisitor, to apply the given * MemberVisitor to all class members that match the given List * of options (of the given type). */ private static void addMemberVisitors(List memberSpecifications, boolean isField, MultiClassVisitor multiClassVisitor, MemberVisitor memberVisitor) { if (memberSpecifications != null) { for (int index = 0; index < memberSpecifications.size(); index++) { MemberSpecification memberSpecification = (MemberSpecification)memberSpecifications.get(index); multiClassVisitor.addClassVisitor( createClassVisitor(memberSpecification, isField, memberVisitor)); } } } /** * Constructs a ClassVisitor that conditionally applies the given * ClassVisitor to all classes that contain the given class members. */ private static ClassVisitor createClassMemberTester(ClassSpecification classSpecification, ClassVisitor classVisitor) { // Create a linked list of conditional visitors, for fields and for // methods. return createClassMemberTester(classSpecification.fieldSpecifications, true, createClassMemberTester(classSpecification.methodSpecifications, false, classVisitor)); } /** * Constructs a ClassVisitor that conditionally applies the given * ClassVisitor to all classes that contain the given List of class * members (of the given type). */ private static ClassVisitor createClassMemberTester(List memberSpecifications, boolean isField, ClassVisitor classVisitor) { // Create a linked list of conditional visitors. if (memberSpecifications != null) { for (int index = 0; index < memberSpecifications.size(); index++) { MemberSpecification memberSpecification = (MemberSpecification)memberSpecifications.get(index); classVisitor = createClassVisitor(memberSpecification, isField, new MemberToClassVisitor(classVisitor)); } } return classVisitor; } /** * Creates a new ClassVisitor to efficiently travel to the specified class * members. * * @param memberSpecification the specification of the class member(s) to * visit. * @param memberVisitor the MemberVisitor to be applied to matching * class member(s). */ private static ClassVisitor createClassVisitor(MemberSpecification memberSpecification, boolean isField, MemberVisitor memberVisitor) { String name = memberSpecification.name; String descriptor = memberSpecification.descriptor; // If name or descriptor are not fully specified, only visit matching // class members. boolean fullySpecified = name != null && descriptor != null && !containsWildCards(name) && !containsWildCards(descriptor); if (!fullySpecified) { if (descriptor != null) { memberVisitor = new MemberDescriptorFilter(descriptor, memberVisitor); } if (name != null) { memberVisitor = new MemberNameFilter(name, memberVisitor); } } // If specified, only visit class members with the right annotation. if (memberSpecification.annotationType != null) { memberVisitor = new AllAttributeVisitor( new AllAnnotationVisitor( new AnnotationTypeFilter(memberSpecification.annotationType, new AnnotationToMemberVisitor(memberVisitor)))); } // If any access flags are specified, only visit matching class members. if (memberSpecification.requiredSetAccessFlags != 0 || memberSpecification.requiredUnsetAccessFlags != 0) { memberVisitor = new MemberAccessFilter(memberSpecification.requiredSetAccessFlags, memberSpecification.requiredUnsetAccessFlags, memberVisitor); } // Depending on what's specified, visit a single named class member, // or all class members, filtering the matching ones. return isField ? fullySpecified ? (ClassVisitor)new NamedFieldVisitor(name, descriptor, memberVisitor) : (ClassVisitor)new AllFieldVisitor(memberVisitor) : fullySpecified ? (ClassVisitor)new NamedMethodVisitor(name, descriptor, memberVisitor) : (ClassVisitor)new AllMethodVisitor(memberVisitor); } // Small utility methods. private static boolean containsWildCards(String string) { return string != null && (string.indexOf('!') >= 0 || string.indexOf('*') >= 0 || string.indexOf('?') >= 0 || string.indexOf('%') >= 0 || string.indexOf(',') >= 0 || string.indexOf("///") >= 0); } } proguard4.8/src/proguard/io/0000775000175000017500000000000011760503005014601 5ustar ericericproguard4.8/src/proguard/io/package.html0000644000175000017500000000020411736333524017066 0ustar ericeric This package contains classes to read and write files, optionally wrapped in jars, wars, ears, zips, directories,... proguard4.8/src/proguard/io/FilteredDataEntryReader.java0000664000175000017500000000661711736333524022165 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.IOException; /** * This DataEntryReader delegates to one of two other DataEntryReader instances, * depending on whether the data entry passes through a given data entry filter * or not. * * @author Eric Lafortune */ public class FilteredDataEntryReader implements DataEntryReader { private final DataEntryFilter dataEntryFilter; private final DataEntryReader acceptedDataEntryReader; private final DataEntryReader rejectedDataEntryReader; /** * Creates a new FilteredDataEntryReader with only a reader for accepted * data entries. * @param dataEntryFilter the data entry filter. * @param acceptedDataEntryReader the DataEntryReader to which the reading * will be delegated if the filter accepts * the data entry. May be null. */ public FilteredDataEntryReader(DataEntryFilter dataEntryFilter, DataEntryReader acceptedDataEntryReader) { this(dataEntryFilter, acceptedDataEntryReader, null); } /** * Creates a new FilteredDataEntryReader. * @param dataEntryFilter the data entry filter. * @param acceptedDataEntryReader the DataEntryReader to which the reading * will be delegated if the filter accepts * the data entry. May be null. * @param rejectedDataEntryReader the DataEntryReader to which the reading * will be delegated if the filter does not * accept the data entry. May be * null. */ public FilteredDataEntryReader(DataEntryFilter dataEntryFilter, DataEntryReader acceptedDataEntryReader, DataEntryReader rejectedDataEntryReader) { this.dataEntryFilter = dataEntryFilter; this.acceptedDataEntryReader = acceptedDataEntryReader; this.rejectedDataEntryReader = rejectedDataEntryReader; } // Implementations for DataEntryReader. public void read(DataEntry dataEntry) throws IOException { DataEntryReader dataEntryReader = dataEntryFilter.accepts(dataEntry) ? acceptedDataEntryReader : rejectedDataEntryReader; if (dataEntryReader != null) { dataEntryReader.read(dataEntry); } } } proguard4.8/src/proguard/io/ZipDataEntry.java0000644000175000017500000000507611736333524020042 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.ClassConstants; import java.io.*; import java.util.zip.*; /** * This DataEntry represents a ZIP entry. * * @author Eric Lafortune */ public class ZipDataEntry implements DataEntry { private final DataEntry parent; private final ZipEntry zipEntry; private ZipInputStream zipInputStream; public ZipDataEntry(DataEntry parent, ZipEntry zipEntry, ZipInputStream zipInputStream) { this.parent = parent; this.zipEntry = zipEntry; this.zipInputStream = zipInputStream; } // Implementations for DataEntry. public String getName() { // Get the right separators. String name = zipEntry.getName() .replace(File.separatorChar, ClassConstants.INTERNAL_PACKAGE_SEPARATOR); // Chop the trailing directory slash, if any. int length = name.length(); return length > 0 && name.charAt(length-1) == ClassConstants.INTERNAL_PACKAGE_SEPARATOR ? name.substring(0, length -1) : name; } public boolean isDirectory() { return zipEntry.isDirectory(); } public InputStream getInputStream() throws IOException { return zipInputStream; } public void closeInputStream() throws IOException { zipInputStream.closeEntry(); zipInputStream = null; } public DataEntry getParent() { return parent; } // Implementations for Object. public String toString() { return parent.toString() + ':' + getName(); } } proguard4.8/src/proguard/io/NameFilter.java0000644000175000017500000000552311736333524017507 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.util.*; import java.util.List; /** * This DataEntryReader delegates to one of two other DataEntryReader instances, * depending on the name of the data entry. * * @author Eric Lafortune */ public class NameFilter extends FilteredDataEntryReader { /** * Creates a new NameFilter that delegates to the given reader, depending * on the given list of filters. */ public NameFilter(String regularExpression, DataEntryReader acceptedDataEntryReader) { this(regularExpression, acceptedDataEntryReader, null); } /** * Creates a new NameFilter that delegates to either of the two given * readers, depending on the given list of filters. */ public NameFilter(String regularExpression, DataEntryReader acceptedDataEntryReader, DataEntryReader rejectedDataEntryReader) { super(new DataEntryNameFilter(new ListParser(new FileNameParser()).parse(regularExpression)), acceptedDataEntryReader, rejectedDataEntryReader); } /** * Creates a new NameFilter that delegates to the given reader, depending * on the given list of filters. */ public NameFilter(List regularExpressions, DataEntryReader acceptedDataEntryReader) { this(regularExpressions, acceptedDataEntryReader, null); } /** * Creates a new NameFilter that delegates to either of the two given * readers, depending on the given list of filters. */ public NameFilter(List regularExpressions, DataEntryReader acceptedDataEntryReader, DataEntryReader rejectedDataEntryReader) { super(new DataEntryNameFilter(new ListParser(new FileNameParser()).parse(regularExpressions)), acceptedDataEntryReader, rejectedDataEntryReader); } }proguard4.8/src/proguard/io/DirectoryWriter.java0000644000175000017500000001102711736333524020616 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.ClassConstants; import java.io.*; /** * This DataEntryWriter writes data entries to individual files in a given * directory. * * @author Eric Lafortune */ public class DirectoryWriter implements DataEntryWriter { private final File baseFile; private final boolean isFile; private File currentFile; private OutputStream currentOutputStream; private Finisher currentFinisher; /** * Creates a new DirectoryWriter. * @param baseFile the base directory to which all files will be written. */ public DirectoryWriter(File baseFile, boolean isFile) { this.baseFile = baseFile; this.isFile = isFile; } // Implementations for DataEntryWriter. public boolean createDirectory(DataEntry dataEntry) throws IOException { // Should we close the current file? if (!isFile && currentFile != null) { closeEntry(); } File directory = getFile(dataEntry); if (!directory.exists() && !directory.mkdirs()) { throw new IOException("Can't create directory [" + directory.getPath() + "]"); } return true; } public OutputStream getOutputStream(DataEntry dataEntry) throws IOException { return getOutputStream(dataEntry, null); } public OutputStream getOutputStream(DataEntry dataEntry, Finisher finisher) throws IOException { File file = getFile(dataEntry); // Should we close the current file? if (!isFile && currentFile != null && !currentFile.equals(file)) { closeEntry(); } // Do we need a new stream? if (currentOutputStream == null) { // Make sure the parent directories exist. File parentDirectory = file.getParentFile(); if (parentDirectory != null && !parentDirectory.exists() && !parentDirectory.mkdirs()) { throw new IOException("Can't create directory [" + parentDirectory.getPath() + "]"); } // Open a new output stream for writing to the file. currentOutputStream = new BufferedOutputStream( new FileOutputStream(file)); currentFinisher = finisher; currentFile = file; } return currentOutputStream; } public void close() throws IOException { // Close the file stream, if any. closeEntry(); } // Small utility methods. /** * Returns the file for the given data entry. */ private File getFile(DataEntry dataEntry) { // Use the specified file, or construct a new file. return isFile ? baseFile : new File(baseFile, dataEntry.getName().replace(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, File.separatorChar)); } /** * Closes the previous file, if any. */ private void closeEntry() throws IOException { // Close the file stream, if any. if (currentOutputStream != null) { // Let any finisher finish up first. if (currentFinisher != null) { currentFinisher.finish(); currentFinisher = null; } currentOutputStream.close(); currentOutputStream = null; currentFile = null; } } } proguard4.8/src/proguard/io/FileDataEntry.java0000644000175000017500000000460011736333524020147 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.ClassConstants; import java.io.*; /** * This DataEntry represents a file. * * @author Eric Lafortune */ public class FileDataEntry implements DataEntry { private final File directory; private final File file; private InputStream inputStream; public FileDataEntry(File directory, File file) { this.directory = directory; this.file = file; } // Implementations for DataEntry. public String getName() { // Chop the directory name from the file name and get the right separators. return file.equals(directory) ? file.getName() : file.getPath() .substring(directory.getPath().length() + File.separator.length()) .replace(File.separatorChar, ClassConstants.INTERNAL_PACKAGE_SEPARATOR); } public boolean isDirectory() { return file.isDirectory(); } public InputStream getInputStream() throws IOException { if (inputStream == null) { inputStream = new BufferedInputStream(new FileInputStream(file)); } return inputStream; } public void closeInputStream() throws IOException { inputStream.close(); inputStream = null; } public DataEntry getParent() { return null; } // Implementations for Object. public String toString() { return getName(); } } proguard4.8/src/proguard/io/DirectoryPump.java0000644000175000017500000000432311736333524020264 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.*; /** * This class can read a given file or directory, recursively, applying a given * DataEntryReader to all files it comes across. * * @author Eric Lafortune */ public class DirectoryPump implements DataEntryPump { private final File directory; public DirectoryPump(File directory) { this.directory = directory; } // Implementations for DataEntryPump. public void pumpDataEntries(DataEntryReader dataEntryReader) throws IOException { if (!directory.exists()) { throw new IOException("No such file or directory"); } readFiles(directory, dataEntryReader); } /** * Reads the given subdirectory recursively, applying the given DataEntryReader * to all files that are encountered. */ private void readFiles(File file, DataEntryReader dataEntryReader) throws IOException { // Pass the file data entry to the reader. dataEntryReader.read(new FileDataEntry(directory, file)); if (file.isDirectory()) { // Recurse into the subdirectory. File[] files = file.listFiles(); for (int index = 0; index < files.length; index++) { readFiles(files[index], dataEntryReader); } } } } proguard4.8/src/proguard/io/DataEntryRenamer.java0000644000175000017500000000716411736333524020671 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.ClassConstants; import java.io.IOException; import java.util.Map; /** * This DataEntryReader delegates to another DataEntryReader, renaming the * data entries based on the given map. Entries whose name does not appear * in the map may be passed to an alternative DataEntryReader. * * @author Eric Lafortune */ public class DataEntryRenamer implements DataEntryReader { private final Map nameMap; private final DataEntryReader renamedDataEntryReader; private final DataEntryReader missingDataEntryReader; /** * Creates a new DataEntryRenamer. * @param nameMap the map from old names to new names. * @param renamedDataEntryReader the DataEntryReader to which renamed data * entries will be passed. */ public DataEntryRenamer(Map nameMap, DataEntryReader renamedDataEntryReader) { this(nameMap, renamedDataEntryReader, null); } /** * Creates a new DataEntryRenamer. * @param nameMap the map from old names to new names. * @param renamedDataEntryReader the DataEntryReader to which renamed data * entries will be passed. * @param missingDataEntryReader the optional DataEntryReader to which data * entries that can't be renamed will be * passed. */ public DataEntryRenamer(Map nameMap, DataEntryReader renamedDataEntryReader, DataEntryReader missingDataEntryReader) { this.nameMap = nameMap; this.renamedDataEntryReader = renamedDataEntryReader; this.missingDataEntryReader = missingDataEntryReader; } // Implementations for DataEntryReader. public void read(DataEntry dataEntry) throws IOException { String name = dataEntry.getName(); // Add a directory separator if necessary. if (dataEntry.isDirectory() && name.length() > 0) { name += ClassConstants.INTERNAL_PACKAGE_SEPARATOR; } String newName = (String)nameMap.get(name); if (newName != null) { // Remove the directory separator if necessary. if (dataEntry.isDirectory() && newName.length() > 0) { newName = newName.substring(0, newName.length() - 1); } renamedDataEntryReader.read(new RenamedDataEntry(dataEntry, newName)); } else if (missingDataEntryReader != null) { missingDataEntryReader.read(dataEntry); } } } proguard4.8/src/proguard/io/ClassRewriter.java0000644000175000017500000000544311736333524020253 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.*; import proguard.classfile.io.ProgramClassWriter; import java.io.*; /** * This DataEntryReader reads class entries and writes their corresponding * versions from the ClassPool to a given DataEntryWriter. * * @author Eric Lafortune */ public class ClassRewriter implements DataEntryReader { private final ClassPool classPool; private final DataEntryWriter dataEntryWriter; public ClassRewriter(ClassPool classPool, DataEntryWriter dataEntryWriter) { this.classPool = classPool; this.dataEntryWriter = dataEntryWriter; } // Implementations for DataEntryReader. public void read(DataEntry dataEntry) throws IOException { String inputName = dataEntry.getName(); String className = inputName.substring(0, inputName.length() - ClassConstants.CLASS_FILE_EXTENSION.length()); // Find the modified class corrsponding to the input entry. ProgramClass programClass = (ProgramClass)classPool.getClass(className); if (programClass != null) { // Rename the data entry if necessary. String newClassName = programClass.getName(); if (!className.equals(newClassName)) { dataEntry = new RenamedDataEntry(dataEntry, newClassName + ClassConstants.CLASS_FILE_EXTENSION); } // Get the output entry corresponding to this input entry. OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry); if (outputStream != null) { // Write the class to the output entry. DataOutputStream classOutputStream = new DataOutputStream(outputStream); new ProgramClassWriter(classOutputStream).visitProgramClass(programClass); classOutputStream.flush(); } } } } proguard4.8/src/proguard/io/ParentDataEntryWriter.java0000644000175000017500000000431311736333524021717 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.*; /** * This DataEntryWriter lets another DataEntryWriter write the parent data * entries. * * @author Eric Lafortune */ public class ParentDataEntryWriter implements DataEntryWriter { private DataEntryWriter dataEntryWriter; /** * Creates a new ParentDataEntryWriter. * @param dataEntryWriter the DataEntryWriter to which the writing will be * delegated, passing the data entries' parents. */ public ParentDataEntryWriter(DataEntryWriter dataEntryWriter) { this.dataEntryWriter = dataEntryWriter; } // Implementations for DataEntryWriter. public boolean createDirectory(DataEntry dataEntry) throws IOException { return getOutputStream(dataEntry) != null; } public OutputStream getOutputStream(DataEntry dataEntry) throws IOException { return getOutputStream(dataEntry, null); } public OutputStream getOutputStream(DataEntry dataEntry, Finisher finisher) throws IOException { return dataEntryWriter.getOutputStream(dataEntry.getParent(), finisher); } public void close() throws IOException { dataEntryWriter.close(); dataEntryWriter = null; } } proguard4.8/src/proguard/io/ClassReader.java0000644000175000017500000001034411736333524017646 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.*; import proguard.classfile.io.*; import proguard.classfile.util.*; import proguard.classfile.visitor.ClassVisitor; import java.io.*; /** * This DataEntryReader applies a given ClassVisitor to the class * definitions that it reads. *

* Class files are read as ProgramClass objects or LibraryClass objects, * depending on the isLibrary flag. *

* In case of libraries, only public classes are considered, if the * skipNonPublicLibraryClasses flag is set. * * @author Eric Lafortune */ public class ClassReader implements DataEntryReader { private final boolean isLibrary; private final boolean skipNonPublicLibraryClasses; private final boolean skipNonPublicLibraryClassMembers; private final WarningPrinter warningPrinter; private final ClassVisitor classVisitor; /** * Creates a new DataEntryClassFilter for reading the specified * Clazz objects. */ public ClassReader(boolean isLibrary, boolean skipNonPublicLibraryClasses, boolean skipNonPublicLibraryClassMembers, WarningPrinter warningPrinter, ClassVisitor classVisitor) { this.isLibrary = isLibrary; this.skipNonPublicLibraryClasses = skipNonPublicLibraryClasses; this.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembers; this.warningPrinter = warningPrinter; this.classVisitor = classVisitor; } // Implementations for DataEntryReader. public void read(DataEntry dataEntry) throws IOException { try { // Get the input stream. InputStream inputStream = dataEntry.getInputStream(); // Wrap it into a data input stream. DataInputStream dataInputStream = new DataInputStream(inputStream); // Create a Clazz representation. Clazz clazz; if (isLibrary) { clazz = new LibraryClass(); clazz.accept(new LibraryClassReader(dataInputStream, skipNonPublicLibraryClasses, skipNonPublicLibraryClassMembers)); } else { clazz = new ProgramClass(); clazz.accept(new ProgramClassReader(dataInputStream)); } // Apply the visitor, if we have a real class. String className = clazz.getName(); if (className != null) { if (!dataEntry.getName().replace(File.pathSeparatorChar, ClassConstants.INTERNAL_PACKAGE_SEPARATOR).equals(className+ClassConstants.CLASS_FILE_EXTENSION) && warningPrinter != null) { warningPrinter.print(className, "Warning: class [" + dataEntry.getName() + "] unexpectedly contains class [" + ClassUtil.externalClassName(className) + "]"); } clazz.accept(classVisitor); } dataEntry.closeInputStream(); } catch (Exception ex) { throw (IOException)new IOException("Can't process class ["+dataEntry.getName()+"] ("+ex.getMessage()+")").initCause(ex); } } } proguard4.8/src/proguard/io/DirectoryFilter.java0000644000175000017500000000347111736333524020573 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.ClassConstants; import proguard.util.ExtensionMatcher; import java.io.IOException; /** * This DataEntryReader delegates to one of two other DataEntryReader instances, * depending on whether the data entry represents a directory or not. * * @author Eric Lafortune */ public class DirectoryFilter extends FilteredDataEntryReader { /** * Creates a new ClassFilter that delegates reading directories to the * given reader. */ public DirectoryFilter(DataEntryReader directoryReader) { this (directoryReader, null); } /** * Creates a new ClassFilter that delegates to either of the two given * readers. */ public DirectoryFilter(DataEntryReader directoryReader, DataEntryReader otherReader) { super(new DataEntryDirectoryFilter(), directoryReader, otherReader); } }proguard4.8/src/proguard/io/JarReader.java0000644000175000017500000000440211736333524017313 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.IOException; import java.util.zip.*; /** * This DataEntryReader lets a given DataEntryReader read all data entries of * the read jar/war/zip data entries. * * @author Eric Lafortune */ public class JarReader implements DataEntryReader { private final DataEntryReader dataEntryReader; /** * Creates a new JarReader. */ public JarReader(DataEntryReader dataEntryReader) { this.dataEntryReader = dataEntryReader; } // Implementation for DataEntryReader. public void read(DataEntry dataEntry) throws IOException { ZipInputStream zipInputStream = new ZipInputStream(dataEntry.getInputStream()); try { // Get all entries from the input jar. while (true) { // Can we get another entry? ZipEntry zipEntry = zipInputStream.getNextEntry(); if (zipEntry == null) { break; } // Delegate the actual reading to the data entry reader. dataEntryReader.read(new ZipDataEntry(dataEntry, zipEntry, zipInputStream)); } } finally { dataEntry.closeInputStream(); } } } proguard4.8/src/proguard/io/FilteredDataEntryWriter.java0000644000175000017500000001074411736333524022231 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.*; /** * This DataEntryWriter delegates to one of two other DataEntryWriter instances, * depending on whether the data entry passes through a given data entry filter * or not. * * @author Eric Lafortune */ public class FilteredDataEntryWriter implements DataEntryWriter { private final DataEntryFilter dataEntryFilter; private DataEntryWriter acceptedDataEntryWriter; private DataEntryWriter rejectedDataEntryWriter; /** * Creates a new FilteredDataEntryWriter with only a writer for accepted * data entries. * @param dataEntryFilter the data entry filter. * @param acceptedDataEntryWriter the DataEntryWriter to which the writing * will be delegated if the filter accepts * the data entry. May be null. */ public FilteredDataEntryWriter(DataEntryFilter dataEntryFilter, DataEntryWriter acceptedDataEntryWriter) { this(dataEntryFilter, acceptedDataEntryWriter, null); } /** * Creates a new FilteredDataEntryWriter. * @param dataEntryFilter the data entry filter. * @param acceptedDataEntryWriter the DataEntryWriter to which the writing * will be delegated if the filter accepts * the data entry. May be null. * @param rejectedDataEntryWriter the DataEntryWriter to which the writing * will be delegated if the filter does not * accept the data entry. May be * null. */ public FilteredDataEntryWriter(DataEntryFilter dataEntryFilter, DataEntryWriter acceptedDataEntryWriter, DataEntryWriter rejectedDataEntryWriter) { this.dataEntryFilter = dataEntryFilter; this.acceptedDataEntryWriter = acceptedDataEntryWriter; this.rejectedDataEntryWriter = rejectedDataEntryWriter; } // Implementations for DataEntryWriter. public boolean createDirectory(DataEntry dataEntry) throws IOException { // Get the right data entry writer. DataEntryWriter dataEntryWriter = dataEntryFilter.accepts(dataEntry) ? acceptedDataEntryWriter : rejectedDataEntryWriter; // Delegate to it, if it's not null. return dataEntryWriter != null && dataEntryWriter.createDirectory(dataEntry); } public OutputStream getOutputStream(DataEntry dataEntry) throws IOException { return getOutputStream(dataEntry, null); } public OutputStream getOutputStream(DataEntry dataEntry, Finisher finisher) throws IOException { // Get the right data entry writer. DataEntryWriter dataEntryWriter = dataEntryFilter.accepts(dataEntry) ? acceptedDataEntryWriter : rejectedDataEntryWriter; // Delegate to it, if it's not null. return dataEntryWriter != null ? dataEntryWriter.getOutputStream(dataEntry, finisher) : null; } public void close() throws IOException { if (acceptedDataEntryWriter != null) { acceptedDataEntryWriter.close(); acceptedDataEntryWriter = null; } if (rejectedDataEntryWriter != null) { rejectedDataEntryWriter.close(); rejectedDataEntryWriter = null; } } } proguard4.8/src/proguard/io/CascadingDataEntryWriter.java0000644000175000017500000000621311736333524022343 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.*; /** * This DataEntryWriter delegates to a given DataEntryWriter, or failing that, * to another given DataEntryWriter. * * @author Eric Lafortune */ public class CascadingDataEntryWriter implements DataEntryWriter { private DataEntryWriter dataEntryWriter1; private DataEntryWriter dataEntryWriter2; /** * Creates a new CascadingDataEntryWriter. * @param dataEntryWriter1 the DataEntryWriter to which the writing will be * delegated first. * @param dataEntryWriter2 the DataEntryWriter to which the writing will be * delegated, if the first one can't provide an * output stream. */ public CascadingDataEntryWriter(DataEntryWriter dataEntryWriter1, DataEntryWriter dataEntryWriter2) { this.dataEntryWriter1 = dataEntryWriter1; this.dataEntryWriter2 = dataEntryWriter2; } // Implementations for DataEntryWriter. public boolean createDirectory(DataEntry dataEntry) throws IOException { // Try to create a directory with the first data entry writer, or // otherwise with the second data entry writer. return dataEntryWriter1.createDirectory(dataEntry) || dataEntryWriter2.createDirectory(dataEntry); } public OutputStream getOutputStream(DataEntry dataEntry) throws IOException { return getOutputStream(dataEntry, null); } public OutputStream getOutputStream(DataEntry dataEntry, Finisher finisher) throws IOException { // Try to get an output stream from the first data entry writer. OutputStream outputStream = dataEntryWriter1.getOutputStream(dataEntry, finisher); // Return it, if it's not null. Otherwise try to get an output stream // from the second data entry writer. return outputStream != null ? outputStream : dataEntryWriter2.getOutputStream(dataEntry, finisher); } public void close() throws IOException { dataEntryWriter1.close(); dataEntryWriter2.close(); dataEntryWriter1 = null; dataEntryWriter2 = null; } } proguard4.8/src/proguard/io/DataEntryParentFilter.java0000644000175000017500000000316011736333524021667 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; /** * This DataEntryFilter delegates filtering to a DataEntryFilter for its parent. * * @author Eric Lafortune */ public class DataEntryParentFilter implements DataEntryFilter { private final DataEntryFilter dataEntryFilter; /** * Creates a new ParentFilter. * @param dataEntryFilter the filter that will be applied to the data * entry's parent. */ public DataEntryParentFilter(DataEntryFilter dataEntryFilter) { this.dataEntryFilter = dataEntryFilter; } // Implementations for DataEntryFilter. public boolean accepts(DataEntry dataEntry) { return dataEntry != null && dataEntryFilter.accepts(dataEntry.getParent()); } } proguard4.8/src/proguard/io/JarWriter.java0000644000175000017500000001536311736333524017375 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.ClassConstants; import java.io.*; import java.util.*; import java.util.jar.*; import java.util.zip.*; /** * This DataEntryWriter sends data entries to a given jar/zip file. * The manifest and comment properties can optionally be set. * * @author Eric Lafortune */ public class JarWriter implements DataEntryWriter, Finisher { private final DataEntryWriter dataEntryWriter; private final Manifest manifest; private final String comment; private OutputStream currentParentOutputStream; private ZipOutputStream currentJarOutputStream; private Finisher currentFinisher; private DataEntry currentDataEntry; // The names of the jar entries that are already in the jar. private final Set jarEntryNames = new HashSet(); /** * Creates a new JarWriter without manifest or comment. */ public JarWriter(DataEntryWriter dataEntryWriter) { this(dataEntryWriter, null, null); } /** * Creates a new JarWriter. */ public JarWriter(DataEntryWriter dataEntryWriter, Manifest manifest, String comment) { this.dataEntryWriter = dataEntryWriter; this.manifest = manifest; this.comment = comment; } // Implementations for DataEntryWriter. public boolean createDirectory(DataEntry dataEntry) throws IOException { //Make sure we can start with a new entry. if (!prepareEntry(dataEntry)) { return false; } // Close the previous ZIP entry, if any. closeEntry(); // Get the directory entry name. String name = dataEntry.getName() + ClassConstants.INTERNAL_PACKAGE_SEPARATOR; // We have to check if the name is already used, because // ZipOutputStream doesn't handle this case properly (it throws // an exception which can be caught, but the ZipDataEntry is // remembered anyway). if (jarEntryNames.add(name)) { // Create a new directory entry. currentJarOutputStream.putNextEntry(new ZipEntry(name)); currentJarOutputStream.closeEntry(); } // Clear the finisher. currentFinisher = null; currentDataEntry = null; return true; } public OutputStream getOutputStream(DataEntry dataEntry) throws IOException { return getOutputStream(dataEntry, null); } public OutputStream getOutputStream(DataEntry dataEntry, Finisher finisher) throws IOException { //Make sure we can start with a new entry. if (!prepareEntry(dataEntry)) { return null; } // Do we need a new entry? if (!dataEntry.equals(currentDataEntry)) { // Close the previous ZIP entry, if any. closeEntry(); // Get the entry name. String name = dataEntry.getName(); // We have to check if the name is already used, because // ZipOutputStream doesn't handle this case properly (it throws // an exception which can be caught, but the ZipDataEntry is // remembered anyway). if (!jarEntryNames.add(name)) { throw new IOException("Duplicate zip entry ["+dataEntry+"]"); } // Create a new entry. currentJarOutputStream.putNextEntry(new ZipEntry(name)); // Set up the finisher for the entry. currentFinisher = finisher; currentDataEntry = dataEntry; } return currentJarOutputStream; } public void finish() throws IOException { // Finish the entire ZIP stream, if any. if (currentJarOutputStream != null) { // Close the previous ZIP entry, if any. closeEntry(); // Finish the entire ZIP stream. currentJarOutputStream.finish(); currentJarOutputStream = null; currentParentOutputStream = null; jarEntryNames.clear(); } } public void close() throws IOException { // Close the parent stream. dataEntryWriter.close(); } // Small utility methods. /** * Makes sure the current output stream is set up for the given entry. */ private boolean prepareEntry(DataEntry dataEntry) throws IOException { // Get the parent stream, new or exisiting. // This may finish our own jar output stream. OutputStream parentOutputStream = dataEntryWriter.getOutputStream(dataEntry.getParent(), this); // Did we get a stream? if (parentOutputStream == null) { return false; } // Do we need a new stream? if (currentParentOutputStream == null) { currentParentOutputStream = parentOutputStream; // Create a new jar stream, with a manifest, if set. currentJarOutputStream = manifest != null ? new JarOutputStream(parentOutputStream, manifest) : new ZipOutputStream(parentOutputStream); // Add a comment, if set. if (comment != null) { currentJarOutputStream.setComment(comment); } } return true; } /** * Closes the previous ZIP entry, if any. */ private void closeEntry() throws IOException { if (currentDataEntry != null) { // Let any finisher finish up first. if (currentFinisher != null) { currentFinisher.finish(); currentFinisher = null; } currentJarOutputStream.closeEntry(); currentDataEntry = null; } } } proguard4.8/src/proguard/io/DataEntryRewriter.java0000644000175000017500000001036111736333524021074 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.*; import java.io.*; /** * This DataEntryReader writes the resource data entries that it reads to a * given DataEntryWriter, updating their contents based on the renamed classes * in the given ClassPool. * * @author Eric Lafortune */ public class DataEntryRewriter extends DataEntryCopier { private final ClassPool classPool; /** * Creates a new DataEntryRewriter. */ public DataEntryRewriter(ClassPool classPool, DataEntryWriter dataEntryWriter) { super(dataEntryWriter); this.classPool = classPool; } // Implementations for DataEntryCopier. protected void copyData(InputStream inputStream, OutputStream outputStream) throws IOException { Reader reader = new BufferedReader(new InputStreamReader(inputStream)); Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream)); copyData(reader, writer); writer.flush(); outputStream.flush(); } /** * Copies all data that it can read from the given reader to the given * writer. */ protected void copyData(Reader reader, Writer writer) throws IOException { StringBuffer word = new StringBuffer(); while (true) { int i = reader.read(); if (i < 0) { break; } // Is the character part of a word? char c = (char)i; if (Character.isJavaIdentifierPart(c) || c == '.' || c == '-') { // Collect the characters in this word. word.append(c); } else { // Write out the updated word, if any. writeUpdatedWord(writer, word.toString()); word.setLength(0); // Write out the character that terminated it. writer.write(c); } } // Write out the final word. writeUpdatedWord(writer, word.toString()); } // Small utility methods. /** * Writes the given word to the given writer, after having adapted it, * based on the renamed class names. */ private void writeUpdatedWord(Writer writer, String word) throws IOException { if (word.length() > 0) { String newWord = word; boolean containsDots = word.indexOf('.') >= 0; // Replace dots by forward slashes. String className = containsDots ? word.replace('.', ClassConstants.INTERNAL_PACKAGE_SEPARATOR) : word; // Find the class corrsponding to the word. Clazz clazz = classPool.getClass(className); if (clazz != null) { // Update the word if necessary. String newClassName = clazz.getName(); if (!className.equals(newClassName)) { // Replace forward slashes by dots. newWord = containsDots ? newClassName.replace(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, '.') : newClassName; } } writer.write(newWord); } } } proguard4.8/src/proguard/io/DataEntryFilter.java0000644000175000017500000000246611736333524020525 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; /** * This interface provides a method to filter data entries. * * @author Eric Lafortune */ public interface DataEntryFilter { /** * Checks whether the filter accepts the given data entry. * @param dataEntry the data entry to filter. * @return a boolean indicating whether the filter accepts the given data * entry. */ public boolean accepts(DataEntry dataEntry); } proguard4.8/src/proguard/io/RenamedDataEntry.java0000664000175000017500000000373411740564025020651 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.*; /** * This DataEntry wraps another data entry, returning a different name instead * of the wrapped data entry's name. * * @author Eric Lafortune */ public class RenamedDataEntry implements DataEntry { private final DataEntry dataEntry; private final String name; public RenamedDataEntry(DataEntry dataEntry, String name) { this.dataEntry = dataEntry; this.name = name; } // Implementations for DataEntry. public String getName() { return name; } public boolean isDirectory() { return dataEntry.isDirectory(); } public InputStream getInputStream() throws IOException { return dataEntry.getInputStream(); } public void closeInputStream() throws IOException { dataEntry.closeInputStream(); } public DataEntry getParent() { return dataEntry.getParent(); } // Implementations for Object. public String toString() { return name + " == " + dataEntry; } } proguard4.8/src/proguard/io/DataEntryReader.java0000644000175000017500000000237411736333524020500 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.IOException; /** * This interface provides methods for reading data entries. The implementation * determines what to do with the read data, if anything. * * @author Eric Lafortune */ public interface DataEntryReader { /** * Reads the given data entry. */ public void read(DataEntry dataEntry) throws IOException; } proguard4.8/src/proguard/io/DataEntryWriter.java0000644000175000017500000000547411736333524020556 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.*; /** * This interface provides methods for writing data entries, such as ZIP entries * or files. The implementation determines to which type of data entry the * data will be written. * * @author Eric Lafortune */ public interface DataEntryWriter { /** * Creates a directory. * @param dataEntry the data entry for which the directory is to be created. * @return whether the directory has been created. */ public boolean createDirectory(DataEntry dataEntry) throws IOException; /** * Returns an output stream for writing data. The caller must not close * the output stream; closing the output stream is the responsibility of * the implementation of this interface. * @param dataEntry the data entry for which the output stream is to be created. * @return the output stream. The stream may be null to indicate * that the data entry should not be written. */ public OutputStream getOutputStream(DataEntry dataEntry) throws IOException; /** * Returns an output stream for writing data. The caller must not close * the output stream; closing the output stream is the responsibility of * the implementation of this interface. * @param dataEntry the data entry for which the output stream is to be created. * @param finisher the optional finisher that will be called before this * class closes the output stream (at some later point in * time) that will be returned (now). * @return the output stream. The stream may be null to indicate * that the data entry should not be written. */ public OutputStream getOutputStream(DataEntry dataEntry, Finisher finisher) throws IOException; /** * Finishes writing all data entries. */ public void close() throws IOException; } proguard4.8/src/proguard/io/ManifestRewriter.java0000664000175000017500000001300211736333524020744 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.*; import java.io.*; /** * This DataEntryReader writes the manifest data entries that it reads to a * given DataEntryWriter, updating their contents based on the renamed classes * in the given ClassPool. * * @author Eric Lafortune */ public class ManifestRewriter extends DataEntryRewriter { /** * Creates a new ManifestRewriter. */ public ManifestRewriter(ClassPool classPool, DataEntryWriter dataEntryWriter) { super(classPool, dataEntryWriter); } // Implementations for DataEntryRewriter. protected void copyData(Reader reader, Writer writer) throws IOException { super.copyData(new SplitLineReader(reader), new SplitLineWriter(writer)); } /** * This Reader reads manifest files, joining any split lines. It replaces * the allowed CR/LF/CR+LF alternatives by simple LF in the process. */ private static class SplitLineReader extends FilterReader { private static final int NONE = -2; private int bufferedCharacter = NONE; public SplitLineReader(Reader reader) { super(reader); } // Implementations for Reader. public int read() throws IOException { while (true) { // Get the buffered character or the first character. int c1 = bufferedCharacter != NONE ? bufferedCharacter : super.read(); // Clear the buffered character. bufferedCharacter = NONE; // Return it if it's an ordinary character. if (c1 != '\n' && c1 != '\r') { return c1; } // It's a newline. Read the second character to see if it's a // continuation. int c2 = super.read(); // Skip any corresponding, redundant \n or \r. if ((c2 == '\n' || c2 == '\r') && c1 != c2) { c2 = super.read(); } // Isn't it a continuation after all? if (c2 != ' ') { // Buffer the second character and return a newline. bufferedCharacter = c2; return '\n'; } // Just continue after the continuation characters. } } public int read(char[] cbuf, int off, int len) throws IOException { // Delegate to reading a single character at a time. int count = 0; while (count < len) { int c = read(); if (c == -1) { break; } cbuf[off + count++] = (char)c; } return count; } public long skip(long n) throws IOException { // Delegate to reading a single character at a time. int count = 0; while (count < n) { int c = read(); if (c == -1) { break; } count++; } return count; } } /** * This Writer writes manifest files, splitting any long lines. */ private static class SplitLineWriter extends FilterWriter { private int counter = 0; public SplitLineWriter(Writer writer) { super(writer); } // Implementations for Reader. public void write(int c) throws IOException { // TODO: We should actually count the Utf-8 bytes, not the characters. if (c == '\n') { // Reset the character count. counter = 0; } else if (counter == 70) { // Insert a newline and a space. super.write('\n'); super.write(' '); counter = 2; } else { counter++; } super.write(c); } public void write(char[] cbuf, int off, int len) throws IOException { for (int count = 0; count < len; count++) { write(cbuf[off + count]); } } public void write(String str, int off, int len) throws IOException { write(str.toCharArray(), off, len); } } }proguard4.8/src/proguard/io/DataEntryPump.java0000644000175000017500000000305511736333524020214 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.IOException; /** * This interface provides a method to pump data entries. The implementation * determines the source and the type of the data entries. Typical examples * are zip entries coming from a zip file of file entries coming from a * directory structure. The reader can for instance collect the classes, * or copy the resource files that are presented. * * @author Eric Lafortune */ public interface DataEntryPump { /** * Applies the given DataEntryReader to all data entries that the * implementation can provide. */ public void pumpDataEntries(DataEntryReader dataEntryReader) throws IOException; } proguard4.8/src/proguard/io/ClassFilter.java0000644000175000017500000000351311736333524017671 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.ClassConstants; import proguard.util.ExtensionMatcher; import java.io.IOException; /** * This DataEntryReader delegates to one of two other DataEntryReader instances, * depending on the extension of the data entry. * * @author Eric Lafortune */ public class ClassFilter extends FilteredDataEntryReader { /** * Creates a new ClassFilter that delegates reading classes to the * given reader. */ public ClassFilter(DataEntryReader classReader) { this(classReader, null); } /** * Creates a new ClassFilter that delegates to either of the two given * readers. */ public ClassFilter(DataEntryReader classReader, DataEntryReader dataEntryReader) { super(new DataEntryNameFilter( new ExtensionMatcher(ClassConstants.CLASS_FILE_EXTENSION)), classReader, dataEntryReader); } } proguard4.8/src/proguard/io/DataEntryObfuscator.java0000644000175000017500000001230611736333524021401 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.*; import proguard.classfile.util.ClassUtil; import java.io.IOException; import java.util.Map; /** * This DataEntryReader delegates to another DataEntryReader, renaming the * data entries based on the renamed classes in the given ClassPool. * * @author Eric Lafortune */ public class DataEntryObfuscator implements DataEntryReader { private final ClassPool classPool; private final Map packagePrefixMap; private final DataEntryReader dataEntryReader; /** * Creates a new DataEntryObfuscator. * @param classPool the class pool that maps from old names to new * names. * @param packagePrefixMap the map from old package prefixes to new package * prefixes. * @param dataEntryReader the DataEntryReader to which calls will be * delegated. */ public DataEntryObfuscator(ClassPool classPool, Map packagePrefixMap, DataEntryReader dataEntryReader) { this.classPool = classPool; this.packagePrefixMap = packagePrefixMap; this.dataEntryReader = dataEntryReader; } // Implementations for DataEntryReader. public void read(DataEntry dataEntry) throws IOException { // Delegate to the actual data entry reader. dataEntryReader.read(renamedDataEntry(dataEntry)); } /** * Create a renamed data entry, if possible. */ private DataEntry renamedDataEntry(DataEntry dataEntry) { String dataEntryName = dataEntry.getName(); // Try to find a corresponding class name by removing increasingly // long suffixes. for (int suffixIndex = dataEntryName.length() - 1; suffixIndex > 0; suffixIndex--) { char c = dataEntryName.charAt(suffixIndex); if (!Character.isLetterOrDigit(c)) { // Chop off the suffix. String className = dataEntryName.substring(0, suffixIndex); // Did we get to the package separator? if (c == ClassConstants.INTERNAL_PACKAGE_SEPARATOR) { break; } // Is there a class corresponding to the data entry? Clazz clazz = classPool.getClass(className); if (clazz != null) { // Did the class get a new name? String newClassName = clazz.getName(); if (!className.equals(newClassName)) { // Return a renamed data entry. String newDataEntryName = newClassName + dataEntryName.substring(suffixIndex); return new RenamedDataEntry(dataEntry, newDataEntryName); } else { // Otherwise stop looking. return dataEntry; } } } } // Try to find a corresponding package name by increasingly removing // more subpackages. String packagePrefix = dataEntryName; do { // Chop off the class name or the last subpackage name. packagePrefix = ClassUtil.internalPackagePrefix(packagePrefix); // Is there a package corresponding to the package prefix? String newPackagePrefix = (String)packagePrefixMap.get(packagePrefix); if (newPackagePrefix != null) { // Did the package get a new name? if (!packagePrefix.equals(newPackagePrefix)) { // Return a renamed data entry. String newDataEntryName = newPackagePrefix + dataEntryName.substring(packagePrefix.length()); return new RenamedDataEntry(dataEntry, newDataEntryName); } else { // Otherwise stop looking. return dataEntry; } } } while (packagePrefix.length() > 0); return dataEntry; } } proguard4.8/src/proguard/io/Finisher.java0000644000175000017500000000233311736333524017224 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.IOException; /** * This interface specifies a listener that is called to finish an output stream * before it is closed. * * @author Eric Lafortune */ public interface Finisher { /** * Finishes an output stream right before it is closed. */ public void finish() throws IOException; } proguard4.8/src/proguard/io/DataEntryNameFilter.java0000664000175000017500000000326411736333524021325 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.util.StringMatcher; /** * This DataEntryFilter filters data entries based on whether their names match * a given StringMatcher. * * @author Eric Lafortune */ public class DataEntryNameFilter implements DataEntryFilter { private final StringMatcher stringMatcher; /** * Creates a new DataEntryNameFilter. * @param stringMatcher the string matcher that will be applied to the names * of the filtered data entries. */ public DataEntryNameFilter(StringMatcher stringMatcher) { this.stringMatcher = stringMatcher; } // Implementations for DataEntryFilter. public boolean accepts(DataEntry dataEntry) { return dataEntry != null && stringMatcher.matches(dataEntry.getName()); } } proguard4.8/src/proguard/io/DataEntryCopier.java0000644000175000017500000002032311736333524020511 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.util.ExtensionMatcher; import java.io.*; /** * This DataEntryReader writes the ZIP entries and files that it reads to a * given DataEntryWriter. * * @author Eric Lafortune */ public class DataEntryCopier implements DataEntryReader { private static final int BUFFER_SIZE = 1024; private final DataEntryWriter dataEntryWriter; private final byte[] buffer = new byte[BUFFER_SIZE]; public DataEntryCopier(DataEntryWriter dataEntryWriter) { this.dataEntryWriter = dataEntryWriter; } // Implementations for DataEntryReader. public void read(DataEntry dataEntry) throws IOException { try { if (dataEntry.isDirectory()) { dataEntryWriter.createDirectory(dataEntry); } else { // Get the output entry corresponding to this input entry. OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry); if (outputStream != null) { InputStream inputStream = dataEntry.getInputStream(); // Copy the data from the input entry to the output entry. copyData(inputStream, outputStream); // Close the data entries. dataEntry.closeInputStream(); } } } catch (IOException ex) { System.err.println("Warning: can't write resource [" + dataEntry.getName() + "] (" + ex.getMessage() + ")"); } } /** * Copies all data that it can read from the given input stream to the * given output stream. */ protected void copyData(InputStream inputStream, OutputStream outputStream) throws IOException { while (true) { int count = inputStream.read(buffer); if (count < 0) { break; } outputStream.write(buffer, 0, count); } outputStream.flush(); } /** * A main method for testing file/jar/war/directory copying. */ public static void main(String[] args) { try { String input = args[0]; String output = args[1]; boolean outputIsJar = output.endsWith(".jar"); boolean outputIsWar = output.endsWith(".war"); boolean outputIsEar = output.endsWith(".ear"); boolean outputIsZip = output.endsWith(".zip"); DataEntryWriter writer = new DirectoryWriter(new File(output), outputIsJar || outputIsWar || outputIsEar || outputIsZip); if (!outputIsJar) { // Zip up any zips, if necessary. DataEntryWriter zipWriter = new JarWriter(writer); if (outputIsZip) { // Always zip. writer = zipWriter; } else { // Only zip up zips. writer = new FilteredDataEntryWriter(new DataEntryParentFilter( new DataEntryNameFilter( new ExtensionMatcher(".zip"))), zipWriter, writer); } // Zip up any wars, if necessary. DataEntryWriter warWriter = new JarWriter(writer); if (outputIsWar) { // Always zip. writer = warWriter; } else { // Only zip up wars. writer = new FilteredDataEntryWriter(new DataEntryParentFilter( new DataEntryNameFilter( new ExtensionMatcher(".war"))), warWriter, writer); } } // Zip up any jars, if necessary. DataEntryWriter jarWriter = new JarWriter(writer); if (outputIsJar) { // Always zip. writer = jarWriter; } else { // Only zip up jars. writer = new FilteredDataEntryWriter(new DataEntryParentFilter( new DataEntryNameFilter( new ExtensionMatcher(".jar"))), jarWriter, writer); } // Create the copying DataEntryReader. DataEntryReader reader = new DataEntryCopier(writer); boolean inputIsJar = input.endsWith(".jar"); boolean inputIsWar = input.endsWith(".war"); boolean inputIsZip = input.endsWith(".zip"); // Unzip any jars, if necessary. DataEntryReader jarReader = new JarReader(reader); if (inputIsJar) { // Always unzip. reader = jarReader; } else { // Only unzip jar entries. reader = new FilteredDataEntryReader(new DataEntryNameFilter( new ExtensionMatcher(".jar")), jarReader, reader); // Unzip any wars, if necessary. DataEntryReader warReader = new JarReader(reader); if (inputIsWar) { // Always unzip. reader = warReader; } else { // Only unzip war entries. reader = new FilteredDataEntryReader(new DataEntryNameFilter( new ExtensionMatcher(".war")), warReader, reader); } // Unzip any zips, if necessary. DataEntryReader zipReader = new JarReader(reader); if (inputIsZip) { // Always unzip. reader = zipReader; } else { // Only unzip zip entries. reader = new FilteredDataEntryReader(new DataEntryNameFilter( new ExtensionMatcher(".zip")), zipReader, reader); } } DirectoryPump directoryReader = new DirectoryPump(new File(input)); directoryReader.pumpDataEntries(reader); writer.close(); } catch (Exception ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/io/DataEntryClassWriter.java0000644000175000017500000000563111736333524021537 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.classfile.*; import proguard.classfile.io.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.io.*; /** * This ClassVisitor writes out the ProgramClass objects that it visits to the * given DataEntry, modified to have the correct name. * * @author Eric Lafortune */ public class DataEntryClassWriter extends SimplifiedVisitor implements ClassVisitor { private final DataEntryWriter dataEntryWriter; private final DataEntry templateDataEntry; /** * Creates a new DataEntryClassWriter for writing to the given * DataEntryWriter, based on the given template DataEntry. */ public DataEntryClassWriter(DataEntryWriter dataEntryWriter, DataEntry templateDataEntry) { this.dataEntryWriter = dataEntryWriter; this.templateDataEntry = templateDataEntry; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Rename the data entry if necessary. String actualClassName = programClass.getName(); DataEntry actualDataEntry = new RenamedDataEntry(templateDataEntry, actualClassName + ClassConstants.CLASS_FILE_EXTENSION); try { // Get the output entry corresponding to this input entry. OutputStream outputStream = dataEntryWriter.getOutputStream(actualDataEntry); if (outputStream != null) { // Write the class to the output entry. DataOutputStream classOutputStream = new DataOutputStream(outputStream); new ProgramClassWriter(classOutputStream).visitProgramClass(programClass); classOutputStream.flush(); } } catch (IOException e) { throw new RuntimeException("Can't write program class ["+actualClassName+"] to ["+actualDataEntry+"] ("+e.getMessage()+")", e); } } } proguard4.8/src/proguard/io/DataEntry.java0000644000175000017500000000336211736333524017353 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import java.io.*; /** * This interface describes a data entry, e.g. a ZIP entry, a file, or a * directory. * * @author Eric Lafortune */ public interface DataEntry { /** * Returns the name of this data entry. */ public String getName(); /** * Returns whether the data entry represents a directory. */ public boolean isDirectory(); /** * Returns an input stream for reading the content of this data entry. * The data entry may not represent a directory. */ public InputStream getInputStream() throws IOException; /** * Closes the previously retrieved InputStream. */ public void closeInputStream() throws IOException; /** * Returns the parent of this data entry, or null if it doesn't * have one. */ public DataEntry getParent(); } proguard4.8/src/proguard/io/DataEntryDirectoryFilter.java0000644000175000017500000000245411736333524022407 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.io; import proguard.util.StringMatcher; /** * This DataEntryFilter filters data entries based on whether they represent * directories. * * @author Eric Lafortune */ public class DataEntryDirectoryFilter implements DataEntryFilter { // Implementations for DataEntryFilter. public boolean accepts(DataEntry dataEntry) { return dataEntry != null && dataEntry.isDirectory(); } }proguard4.8/src/proguard/gui/0000775000175000017500000000000011760503005014756 5ustar ericericproguard4.8/src/proguard/gui/package.html0000644000175000017500000000010511736333524017243 0ustar ericeric This package contains a GUI for ProGuard and ReTrace. proguard4.8/src/proguard/gui/ReTraceRunnable.java0000644000175000017500000001173211736333524020651 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.retrace.ReTrace; import javax.swing.*; import java.awt.*; import java.io.*; /** * This Runnable runs ReTrace, sending console output to a text * area and any exceptions to message dialogs. * * @see ReTrace * @author Eric Lafortune */ final class ReTraceRunnable implements Runnable { private final JTextArea consoleTextArea; private final boolean verbose; private final File mappingFile; private final String stackTrace; /** * Creates a new ProGuardRunnable object. * @param consoleTextArea the text area to send the console output to. * @param verbose specifies whether the de-obfuscated stack trace * should be verbose. * @param mappingFile the mapping file that was written out by ProGuard. */ public ReTraceRunnable(JTextArea consoleTextArea, boolean verbose, File mappingFile, String stackTrace) { this.consoleTextArea = consoleTextArea; this.verbose = verbose; this.mappingFile = mappingFile; this.stackTrace = stackTrace; } // Implementation for Runnable. public void run() { consoleTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); consoleTextArea.setText(""); // Redirect the stack trace string to the System's in stream, and the // out and err streams to the console text area. InputStream oldIn = System.in; PrintStream oldOut = System.out; PrintStream oldErr = System.err; ByteArrayInputStream inputStream = new ByteArrayInputStream(stackTrace.getBytes()); PrintStream printStream = new PrintStream(new TextAreaOutputStream(consoleTextArea), true); System.setIn(inputStream); System.setOut(printStream); System.setErr(printStream); try { // Create a new ProGuard object with the GUI's configuration. ReTrace reTrace = new ReTrace(ReTrace.STACK_TRACE_EXPRESSION, verbose, mappingFile); // Run it. reTrace.execute(); } catch (Exception ex) { // Print out the exception message. System.out.println(ex.getMessage()); // Show a dialog as well. MessageDialogRunnable.showMessageDialog(consoleTextArea, ex.getMessage(), msg("errorReTracing"), JOptionPane.ERROR_MESSAGE); } catch (OutOfMemoryError er) { // Forget about the ProGuard object as quickly as possible. System.gc(); // Print out a message suggesting what to do next. System.out.println(msg("outOfMemory")); // Show a dialog as well. MessageDialogRunnable.showMessageDialog(consoleTextArea, msg("outOfMemory"), msg("errorReTracing"), JOptionPane.ERROR_MESSAGE); } // Make sure all output has been sent to the console text area. printStream.flush(); // Restore the old System's in, out, and err streams. System.setIn(oldIn); System.setOut(oldOut); System.setErr(oldErr); consoleTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); consoleTextArea.setCaretPosition(0); // Reset the global static redirection lock. ProGuardGUI.systemOutRedirected = false; } // Small utility methods. /** * Returns the message from the GUI resources that corresponds to the given * key. */ private String msg(String messageKey) { return GUIResources.getMessage(messageKey); } } proguard4.8/src/proguard/gui/ClassSpecificationsPanel.java0000644000175000017500000001603311736333524022545 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.ClassSpecification; import proguard.classfile.util.ClassUtil; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; /** * This ListPanel allows the user to add, edit, move, and remove * ClassSpecification entries in a list. * * @author Eric Lafortune */ class ClassSpecificationsPanel extends ListPanel { protected final ClassSpecificationDialog classSpecificationDialog; public ClassSpecificationsPanel(JFrame owner, boolean fullKeepOptions) { super(); list.setCellRenderer(new MyListCellRenderer()); classSpecificationDialog = new ClassSpecificationDialog(owner, fullKeepOptions); addAddButton(); addEditButton(); addRemoveButton(); addUpButton(); addDownButton(); enableSelectionButtons(); } protected void addAddButton() { JButton addButton = new JButton(msg("add")); addButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setClassSpecification(createClassSpecification()); int returnValue = classSpecificationDialog.showDialog(); if (returnValue == ClassSpecificationDialog.APPROVE_OPTION) { // Add the new element. addElement(getClassSpecification()); } } }); addButton(tip(addButton, "addTip")); } protected void addEditButton() { JButton editButton = new JButton(msg("edit")); editButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ClassSpecification selectedClassSpecification = (ClassSpecification)list.getSelectedValue(); setClassSpecification(selectedClassSpecification); int returnValue = classSpecificationDialog.showDialog(); if (returnValue == ClassSpecificationDialog.APPROVE_OPTION) { // Replace the old element. setElementAt(getClassSpecification(), list.getSelectedIndex()); } } }); addButton(tip(editButton, "editTip")); } protected ClassSpecification createClassSpecification() { return new ClassSpecification(); } protected void setClassSpecification(ClassSpecification classSpecification) { classSpecificationDialog.setClassSpecification(classSpecification); } protected ClassSpecification getClassSpecification() { return classSpecificationDialog.getClassSpecification(); } /** * Sets the ClassSpecification objects to be represented in this panel. */ public void setClassSpecifications(List classSpecifications) { listModel.clear(); if (classSpecifications != null) { for (int index = 0; index < classSpecifications.size(); index++) { listModel.addElement(classSpecifications.get(index)); } } // Make sure the selection buttons are properly enabled, // since the clear method doesn't seem to notify the listener. enableSelectionButtons(); } /** * Returns the ClassSpecification objects currently represented in this panel. */ public List getClassSpecifications() { int size = listModel.size(); if (size == 0) { return null; } List classSpecifications = new ArrayList(size); for (int index = 0; index < size; index++) { classSpecifications.add(listModel.get(index)); } return classSpecifications; } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } /** * This ListCellRenderer renders ClassSpecification objects. */ private static class MyListCellRenderer implements ListCellRenderer { private final JLabel label = new JLabel(); // Implementations for ListCellRenderer. public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { ClassSpecification classSpecification = (ClassSpecification)value; String comments = classSpecification.comments; label.setText(comments != null ? comments.trim() : classSpecification.className != null ? (msg("class") + ' ' + ClassUtil.externalClassName(classSpecification.className)) : classSpecification.extendsClassName != null ? (msg("extensionsOf") + ' ' + ClassUtil.externalClassName(classSpecification.extendsClassName)) : (msg("specificationNumber") + index)); if (isSelected) { label.setBackground(list.getSelectionBackground()); label.setForeground(list.getSelectionForeground()); } else { label.setBackground(list.getBackground()); label.setForeground(list.getForeground()); } label.setOpaque(true); return label; } } } proguard4.8/src/proguard/gui/MemberSpecificationsPanel.java0000644000175000017500000002432111736333524022706 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.*; import proguard.classfile.ClassConstants; import proguard.classfile.util.ClassUtil; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; /** * This ListPanel allows the user to add, edit, move, and remove * MemberSpecification entries in a list. * * @author Eric Lafortune */ final class MemberSpecificationsPanel extends ListPanel { private final MemberSpecificationDialog fieldSpecificationDialog; private final MemberSpecificationDialog methodSpecificationDialog; public MemberSpecificationsPanel(JDialog owner, boolean fullKeepOptions) { super(); super.firstSelectionButton = fullKeepOptions ? 3 : 2; list.setCellRenderer(new MyListCellRenderer()); fieldSpecificationDialog = new MemberSpecificationDialog(owner, true); methodSpecificationDialog = new MemberSpecificationDialog(owner, false); if (fullKeepOptions) { addAddFieldButton(); } addAddMethodButton(); addEditButton(); addRemoveButton(); addUpButton(); addDownButton(); enableSelectionButtons(); } protected void addAddFieldButton() { JButton addFieldButton = new JButton(msg("addField")); addFieldButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { fieldSpecificationDialog.setMemberSpecification(new MemberSpecification()); int returnValue = fieldSpecificationDialog.showDialog(); if (returnValue == MemberSpecificationDialog.APPROVE_OPTION) { // Add the new element. addElement(new MyMemberSpecificationWrapper(fieldSpecificationDialog.getMemberSpecification(), true)); } } }); addButton(tip(addFieldButton, "addFieldTip")); } protected void addAddMethodButton() { JButton addMethodButton = new JButton(msg("addMethod")); addMethodButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { methodSpecificationDialog.setMemberSpecification(new MemberSpecification()); int returnValue = methodSpecificationDialog.showDialog(); if (returnValue == MemberSpecificationDialog.APPROVE_OPTION) { // Add the new element. addElement(new MyMemberSpecificationWrapper(methodSpecificationDialog.getMemberSpecification(), false)); } } }); addButton(tip(addMethodButton, "addMethodTip")); } protected void addEditButton() { JButton editButton = new JButton(msg("edit")); editButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { MyMemberSpecificationWrapper wrapper = (MyMemberSpecificationWrapper)list.getSelectedValue(); MemberSpecificationDialog memberSpecificationDialog = wrapper.isField ? fieldSpecificationDialog : methodSpecificationDialog; memberSpecificationDialog.setMemberSpecification(wrapper.memberSpecification); int returnValue = memberSpecificationDialog.showDialog(); if (returnValue == MemberSpecificationDialog.APPROVE_OPTION) { // Replace the old element. wrapper.memberSpecification = memberSpecificationDialog.getMemberSpecification(); setElementAt(wrapper, list.getSelectedIndex()); } } }); addButton(tip(editButton, "editTip")); } /** * Sets the MemberSpecification instances to be represented in this panel. */ public void setMemberSpecifications(List fieldSpecifications, List methodSpecifications) { listModel.clear(); if (fieldSpecifications != null) { for (int index = 0; index < fieldSpecifications.size(); index++) { listModel.addElement( new MyMemberSpecificationWrapper((MemberSpecification)fieldSpecifications.get(index), true)); } } if (methodSpecifications != null) { for (int index = 0; index < methodSpecifications.size(); index++) { listModel.addElement( new MyMemberSpecificationWrapper((MemberSpecification)methodSpecifications.get(index), false)); } } // Make sure the selection buttons are properly enabled, // since the clear method doesn't seem to notify the listener. enableSelectionButtons(); } /** * Returns the MemberSpecification instances currently represented in * this panel, referring to fields or to methods. * * @param isField specifies whether specifications referring to fields or * specifications referring to methods should be returned. */ public List getMemberSpecifications(boolean isField) { int size = listModel.size(); if (size == 0) { return null; } List memberSpecifications = new ArrayList(size); for (int index = 0; index < size; index++) { MyMemberSpecificationWrapper wrapper = (MyMemberSpecificationWrapper)listModel.get(index); if (wrapper.isField == isField) { memberSpecifications.add(wrapper.memberSpecification); } } return memberSpecifications; } /** * This ListCellRenderer renders MemberSpecification objects. */ private static class MyListCellRenderer implements ListCellRenderer { private final JLabel label = new JLabel(); // Implementations for ListCellRenderer. public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { MyMemberSpecificationWrapper wrapper = (MyMemberSpecificationWrapper)value; MemberSpecification option = wrapper.memberSpecification; String name = option.name; String descriptor = option.descriptor; label.setText(wrapper.isField ? (descriptor == null ? name == null ? "" : "***" + ' ' + name : ClassUtil.externalFullFieldDescription(0, name == null ? "*" : name, descriptor)) : (descriptor == null ? name == null ? "" : "***" + ' ' + name + "(...)" : ClassUtil.externalFullMethodDescription(ClassConstants.INTERNAL_METHOD_NAME_INIT, 0, name == null ? "*" : name, descriptor))); if (isSelected) { label.setBackground(list.getSelectionBackground()); label.setForeground(list.getSelectionForeground()); } else { label.setBackground(list.getBackground()); label.setForeground(list.getForeground()); } label.setOpaque(true); return label; } } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } /** * This class wraps a MemberSpecification, additionally storing whether * the option refers to a field or to a method. */ private static class MyMemberSpecificationWrapper { public MemberSpecification memberSpecification; public final boolean isField; public MyMemberSpecificationWrapper(MemberSpecification memberSpecification, boolean isField) { this.memberSpecification = memberSpecification; this.isField = isField; } } } proguard4.8/src/proguard/gui/ListPanel.java0000644000175000017500000002363211736333524017532 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import java.awt.*; import java.awt.event.*; import java.util.List; import java.util.*; import javax.swing.*; import javax.swing.event.*; /** * This Jpanel allows the user to move and remove entries in a * list and between lists. Extensions of this class should add buttons to add * and possibly edit entries, and to set and get the resulting list. * * @author Eric Lafortune */ abstract class ListPanel extends JPanel { protected final DefaultListModel listModel = new DefaultListModel(); protected final JList list = new JList(listModel); protected int firstSelectionButton = 2; protected ListPanel() { GridBagLayout layout = new GridBagLayout(); setLayout(layout); GridBagConstraints listConstraints = new GridBagConstraints(); listConstraints.gridheight = GridBagConstraints.REMAINDER; listConstraints.fill = GridBagConstraints.BOTH; listConstraints.weightx = 1.0; listConstraints.weighty = 1.0; listConstraints.anchor = GridBagConstraints.NORTHWEST; listConstraints.insets = new Insets(0, 2, 0, 2); // Make sure some buttons are disabled or enabled depending on whether // the selection is empty or not. list.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { enableSelectionButtons(); } }); add(new JScrollPane(list), listConstraints); // something like the following calls are up to the extending class: //addAddButton(); //addEditButton(); //addRemoveButton(); //addUpButton(); //addDownButton(); // //enableSelectionButtons(); } protected void addRemoveButton() { JButton removeButton = new JButton(msg("remove")); removeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Remove the selected elements. removeElementsAt(list.getSelectedIndices()); } }); addButton(tip(removeButton, "removeTip")); } protected void addUpButton() { JButton upButton = new JButton(msg("moveUp")); upButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int[] selectedIndices = list.getSelectedIndices(); if (selectedIndices.length > 0 && selectedIndices[0] > 0) { // Move the selected elements up. moveElementsAt(selectedIndices, -1); } } }); addButton(tip(upButton, "moveUpTip")); } protected void addDownButton() { JButton downButton = new JButton(msg("moveDown")); downButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int[] selectedIndices = list.getSelectedIndices(); if (selectedIndices.length > 0 && selectedIndices[selectedIndices.length-1] < listModel.getSize()-1) { // Move the selected elements down. moveElementsAt(selectedIndices, 1); } } }); addButton(tip(downButton, "moveDownTip")); } /** * Adds a button that allows to copy or move entries to another ListPanel. * * @param buttonTextKey the button text key. * @param tipKey the tool tip key. * @param panel the other ListPanel. */ public void addCopyToPanelButton(String buttonTextKey, String tipKey, final ListPanel panel) { JButton moveButton = new JButton(msg(buttonTextKey)); moveButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int[] selectedIndices = list.getSelectedIndices(); Object[] selectedElements = list.getSelectedValues(); // Remove the selected elements from this panel. removeElementsAt(selectedIndices); // Add the elements to the other panel. panel.addElements(selectedElements); } }); addButton(tip(moveButton, tipKey)); } protected void addButton(JComponent button) { GridBagConstraints buttonConstraints = new GridBagConstraints(); buttonConstraints.gridwidth = GridBagConstraints.REMAINDER; buttonConstraints.fill = GridBagConstraints.HORIZONTAL; buttonConstraints.anchor = GridBagConstraints.NORTHWEST; buttonConstraints.insets = new Insets(0, 2, 0, 2); add(button, buttonConstraints); } /** * Returns a list of all right-hand side buttons. */ public List getButtons() { List list = new ArrayList(getComponentCount()-1); // Add all buttons. for (int index = 1; index < getComponentCount(); index++) { list.add(getComponent(index)); } return list; } protected void addElement(Object element) { listModel.addElement(element); // Make sure it is selected. list.setSelectedIndex(listModel.size() - 1); } protected void addElements(Object[] elements) { // Add the elements one by one. for (int index = 0; index < elements.length; index++) { listModel.addElement(elements[index]); } // Make sure they are selected. int[] selectedIndices = new int[elements.length]; for (int index = 0; index < selectedIndices.length; index++) { selectedIndices[index] = listModel.size() - selectedIndices.length + index; } list.setSelectedIndices(selectedIndices); } protected void moveElementsAt(int[] indices, int offset) { // Remember the selected elements. Object[] selectedElements = list.getSelectedValues(); // Remove the selected elements. removeElementsAt(indices); // Update the element indices. for (int index = 0; index < indices.length; index++) { indices[index] += offset; } // Reinsert the selected elements. insertElementsAt(selectedElements, indices); } protected void insertElementsAt(Object[] elements, int[] indices) { for (int index = 0; index < elements.length; index++) { listModel.insertElementAt(elements[index], indices[index]); } // Make sure they are selected. list.setSelectedIndices(indices); } protected void setElementAt(Object element, int index) { listModel.setElementAt(element, index); // Make sure it is selected. list.setSelectedIndex(index); } protected void setElementsAt(Object[] elements, int[] indices) { for (int index = 0; index < elements.length; index++) { listModel.setElementAt(elements[index], indices[index]); } // Make sure they are selected. list.setSelectedIndices(indices); } protected void removeElementsAt(int[] indices) { for (int index = indices.length - 1; index >= 0; index--) { listModel.removeElementAt(indices[index]); } // Make sure nothing is selected. list.clearSelection(); // Make sure the selection buttons are properly enabled, // since the above method doesn't seem to notify the listener. enableSelectionButtons(); } protected void removeAllElements() { listModel.removeAllElements(); // Make sure the selection buttons are properly enabled, // since the above method doesn't seem to notify the listener. enableSelectionButtons(); } /** * Enables or disables the buttons that depend on a selection. */ protected void enableSelectionButtons() { boolean selected = !list.isSelectionEmpty(); // Loop over all components, except the list itself and the Add button. for (int index = firstSelectionButton; index < getComponentCount(); index++) { getComponent(index).setEnabled(selected); } } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } } proguard4.8/src/proguard/gui/TabbedPane.java0000644000175000017500000001504011736333524017616 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import javax.swing.*; import java.awt.*; import java.awt.event.*; /** * This Jpanel is similar to a JTabbedPane. * It uses buttons on the left-hand side to switch between panels. * An image can be added below these buttons. * Some methods are provided to switch between tabs. * * @author Eric Lafortune */ public class TabbedPane extends JPanel { private final CardLayout cardLayout = new CardLayout(); private final JPanel cardPanel = new JPanel(cardLayout); private final ButtonGroup buttonGroup = new ButtonGroup(); /** * Creates a new TabbedPane. */ public TabbedPane() { GridBagLayout layout = new GridBagLayout(); setLayout(layout); GridBagConstraints cardConstraints = new GridBagConstraints(); cardConstraints.gridx = 1; cardConstraints.gridy = 0; cardConstraints.gridheight = GridBagConstraints.REMAINDER; cardConstraints.fill = GridBagConstraints.BOTH; cardConstraints.weightx = 1.0; cardConstraints.weighty = 1.0; cardConstraints.anchor = GridBagConstraints.NORTHWEST; add(cardPanel, cardConstraints); } /** * Adds a component with a given title to the tabbed pane. * * @param title the title that will be used in the tab button. * @param component the component that will be added as a tab. */ public Component add(final String title, Component component) { GridBagConstraints buttonConstraints = new GridBagConstraints(); buttonConstraints.gridx = 0; buttonConstraints.fill = GridBagConstraints.HORIZONTAL; buttonConstraints.anchor = GridBagConstraints.NORTHWEST; buttonConstraints.ipadx = 10; buttonConstraints.ipady = 4; JToggleButton button = new JToggleButton(title); // Let the button react on the mouse press, instead of waiting for the // mouse release. button.setModel(new JToggleButton.ToggleButtonModel() { public void setPressed(boolean b) { if ((isPressed() == b) || !isEnabled()) { return; } if (!b && isArmed()) { setSelected(!this.isSelected()); } if (b) { stateMask |= PRESSED; } else { stateMask &= ~PRESSED; } fireStateChanged(); if (isPressed()) { fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand())); } } }); // Switch to the tab on a button press. button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { cardLayout.show(cardPanel, title); } }); // Only one button can be selected at the same time. buttonGroup.add(button); // If this is the first tab, make sure its button is selected. if (cardPanel.getComponentCount() == 0) { button.setSelected(true); } // Add the button and its panel. add(button, buttonConstraints); cardPanel.add(title, component); return component; } /** * Adds an image below the tab buttons, after all tabs have been added. * The image will only be as visible as permitted by the available space. * * @param image the image. * @return the component containing the image. */ public Component addImage(final Image image) { GridBagConstraints imageConstraints = new GridBagConstraints(); imageConstraints.gridx = 0; imageConstraints.weighty = 1.0; imageConstraints.fill = GridBagConstraints.BOTH; imageConstraints.anchor = GridBagConstraints.SOUTHWEST; JButton component = new JButton(new ImageIcon(image)); component.setFocusPainted(false); component.setFocusable(false); component.setRequestFocusEnabled(false); component.setRolloverEnabled(false); component.setMargin(new Insets(0, 0, 0, 0)); component.setHorizontalAlignment(JButton.LEFT); component.setVerticalAlignment(JButton.BOTTOM); component.setPreferredSize(new Dimension(0, 0)); add(component, imageConstraints); return component; } /** * Selects the first tab. */ public void first() { cardLayout.first(cardPanel); updateButtonSelection(); } /** * Selects the last tab. */ public void last() { cardLayout.last(cardPanel); updateButtonSelection(); } /** * Selects the previous tab. */ public void previous() { cardLayout.previous(cardPanel); updateButtonSelection(); } /** * Selects the next tab. */ public void next() { cardLayout.next(cardPanel); updateButtonSelection(); } /** * Lets the button selection reflect the currently visible panel. */ private void updateButtonSelection() { int count = cardPanel.getComponentCount(); for (int index = 0 ; index < count ; index++) { Component card = cardPanel.getComponent(index); if (card.isShowing()) { JToggleButton button = (JToggleButton)getComponent(index+1); button.setSelected(true); } } } } proguard4.8/src/proguard/gui/boilerplate.pro0000644000175000017500000004115211163773611020014 0ustar ericeric# Keep - Applications. Keep all application classes, along with their 'main' # methods. -keepclasseswithmembers public class * { public static void main(java.lang.String[]); } # Keep - Applets. Keep all extensions of java.applet.Applet. -keep public class * extends java.applet.Applet # Keep - Servlets. Keep all extensions of javax.servlet.Servlet. -keep public class * extends javax.servlet.Servlet # Keep - Midlets. Keep all extensions of javax.microedition.midlet.MIDlet. -keep public class * extends javax.microedition.midlet.MIDlet # Keep - Xlets. Keep all extensions of javax.tv.xlet.Xlet. -keep public class * extends javax.tv.xlet.Xlet # Keep - Library. Keep all public and protected classes, fields, and methods. -keep public class * { public protected ; public protected ; } # Also keep - Enumerations. Keep the special static methods that are required in # enumeration classes. -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } # Also keep - Serialization code. Keep all fields and methods that are used for # serialization. -keepclassmembers class * extends java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Also keep - BeanInfo classes. Keep all implementations of java.beans.BeanInfo. -keep class * implements java.beans.BeanInfo # Also keep - Bean classes. Keep all specified classes, along with their getters # and setters. -keep class * { void set*(***); void set*(int,***); boolean is*(); boolean is*(int); *** get*(); *** get*(int); } # Also keep - Database drivers. Keep all implementations of java.sql.Driver. -keep class * implements java.sql.Driver # Also keep - Swing UI L&F. Keep all extensions of javax.swing.plaf.ComponentUI, # along with the special 'createUI' method. -keep class * extends javax.swing.plaf.ComponentUI { public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent); } # Also keep - RMI interfaces. Keep all interfaces that extend the # java.rmi.Remote interface, and their methods. -keep interface * extends java.rmi.Remote { ; } # Also keep - RMI implementations. Keep all implementations of java.rmi.Remote, # including any explicit or implicit implementations of Activatable, with their # two-argument constructors. -keep class * implements java.rmi.Remote { (java.rmi.activation.ActivationID,java.rmi.MarshalledObject); } # Keep names - Native method names. Keep all native class/method names. -keepclasseswithmembernames class * { native ; } # Keep names - _class method names. Keep all .class method names. This may be # useful for libraries that will be obfuscated again with different obfuscators. -keepclassmembernames class * { java.lang.Class class$(java.lang.String); java.lang.Class class$(java.lang.String,boolean); } # Remove - System method calls. Remove all invocations of System # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.System { public static long currentTimeMillis(); static java.lang.Class getCallerClass(); public static int identityHashCode(java.lang.Object); public static java.lang.SecurityManager getSecurityManager(); public static java.util.Properties getProperties(); public static java.lang.String getProperty(java.lang.String); public static java.lang.String getenv(java.lang.String); public static java.lang.String mapLibraryName(java.lang.String); public static java.lang.String getProperty(java.lang.String,java.lang.String); } # Remove - Math method calls. Remove all invocations of Math # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.Math { public static double sin(double); public static double cos(double); public static double tan(double); public static double asin(double); public static double acos(double); public static double atan(double); public static double toRadians(double); public static double toDegrees(double); public static double exp(double); public static double log(double); public static double log10(double); public static double sqrt(double); public static double cbrt(double); public static double IEEEremainder(double,double); public static double ceil(double); public static double floor(double); public static double rint(double); public static double atan2(double,double); public static double pow(double,double); public static int round(float); public static long round(double); public static double random(); public static int abs(int); public static long abs(long); public static float abs(float); public static double abs(double); public static int max(int,int); public static long max(long,long); public static float max(float,float); public static double max(double,double); public static int min(int,int); public static long min(long,long); public static float min(float,float); public static double min(double,double); public static double ulp(double); public static float ulp(float); public static double signum(double); public static float signum(float); public static double sinh(double); public static double cosh(double); public static double tanh(double); public static double hypot(double,double); public static double expm1(double); public static double log1p(double); } # Remove - Number method calls. Remove all invocations of Number # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.* extends java.lang.Number { public static java.lang.String toString(byte); public static java.lang.Byte valueOf(byte); public static byte parseByte(java.lang.String); public static byte parseByte(java.lang.String,int); public static java.lang.Byte valueOf(java.lang.String,int); public static java.lang.Byte valueOf(java.lang.String); public static java.lang.Byte decode(java.lang.String); public int compareTo(java.lang.Byte); public static java.lang.String toString(short); public static short parseShort(java.lang.String); public static short parseShort(java.lang.String,int); public static java.lang.Short valueOf(java.lang.String,int); public static java.lang.Short valueOf(java.lang.String); public static java.lang.Short valueOf(short); public static java.lang.Short decode(java.lang.String); public static short reverseBytes(short); public int compareTo(java.lang.Short); public static java.lang.String toString(int,int); public static java.lang.String toHexString(int); public static java.lang.String toOctalString(int); public static java.lang.String toBinaryString(int); public static java.lang.String toString(int); public static int parseInt(java.lang.String,int); public static int parseInt(java.lang.String); public static java.lang.Integer valueOf(java.lang.String,int); public static java.lang.Integer valueOf(java.lang.String); public static java.lang.Integer valueOf(int); public static java.lang.Integer getInteger(java.lang.String); public static java.lang.Integer getInteger(java.lang.String,int); public static java.lang.Integer getInteger(java.lang.String,java.lang.Integer); public static java.lang.Integer decode(java.lang.String); public static int highestOneBit(int); public static int lowestOneBit(int); public static int numberOfLeadingZeros(int); public static int numberOfTrailingZeros(int); public static int bitCount(int); public static int rotateLeft(int,int); public static int rotateRight(int,int); public static int reverse(int); public static int signum(int); public static int reverseBytes(int); public int compareTo(java.lang.Integer); public static java.lang.String toString(long,int); public static java.lang.String toHexString(long); public static java.lang.String toOctalString(long); public static java.lang.String toBinaryString(long); public static java.lang.String toString(long); public static long parseLong(java.lang.String,int); public static long parseLong(java.lang.String); public static java.lang.Long valueOf(java.lang.String,int); public static java.lang.Long valueOf(java.lang.String); public static java.lang.Long valueOf(long); public static java.lang.Long decode(java.lang.String); public static java.lang.Long getLong(java.lang.String); public static java.lang.Long getLong(java.lang.String,long); public static java.lang.Long getLong(java.lang.String,java.lang.Long); public static long highestOneBit(long); public static long lowestOneBit(long); public static int numberOfLeadingZeros(long); public static int numberOfTrailingZeros(long); public static int bitCount(long); public static long rotateLeft(long,int); public static long rotateRight(long,int); public static long reverse(long); public static int signum(long); public static long reverseBytes(long); public int compareTo(java.lang.Long); public static java.lang.String toString(float); public static java.lang.String toHexString(float); public static java.lang.Float valueOf(java.lang.String); public static java.lang.Float valueOf(float); public static float parseFloat(java.lang.String); public static boolean isNaN(float); public static boolean isInfinite(float); public static int floatToIntBits(float); public static int floatToRawIntBits(float); public static float intBitsToFloat(int); public static int compare(float,float); public boolean isNaN(); public boolean isInfinite(); public int compareTo(java.lang.Float); public static java.lang.String toString(double); public static java.lang.String toHexString(double); public static java.lang.Double valueOf(java.lang.String); public static java.lang.Double valueOf(double); public static double parseDouble(java.lang.String); public static boolean isNaN(double); public static boolean isInfinite(double); public static long doubleToLongBits(double); public static long doubleToRawLongBits(double); public static double longBitsToDouble(long); public static int compare(double,double); public boolean isNaN(); public boolean isInfinite(); public int compareTo(java.lang.Double); public (byte); public (short); public (int); public (long); public (float); public (double); public (java.lang.String); public byte byteValue(); public short shortValue(); public int intValue(); public long longValue(); public float floatValue(); public double doubleValue(); public int compareTo(java.lang.Object); public boolean equals(java.lang.Object); public int hashCode(); public java.lang.String toString(); } # Remove - String method calls. Remove all invocations of String # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.String { public java.lang.String(); public java.lang.String(byte[]); public java.lang.String(byte[],int); public java.lang.String(byte[],int,int); public java.lang.String(byte[],int,int,int); public java.lang.String(byte[],int,int,java.lang.String); public java.lang.String(byte[],java.lang.String); public java.lang.String(char[]); public java.lang.String(char[],int,int); public java.lang.String(java.lang.String); public java.lang.String(java.lang.StringBuffer); public static java.lang.String copyValueOf(char[]); public static java.lang.String copyValueOf(char[],int,int); public static java.lang.String valueOf(boolean); public static java.lang.String valueOf(char); public static java.lang.String valueOf(char[]); public static java.lang.String valueOf(char[],int,int); public static java.lang.String valueOf(double); public static java.lang.String valueOf(float); public static java.lang.String valueOf(int); public static java.lang.String valueOf(java.lang.Object); public static java.lang.String valueOf(long); public boolean contentEquals(java.lang.StringBuffer); public boolean endsWith(java.lang.String); public boolean equalsIgnoreCase(java.lang.String); public boolean equals(java.lang.Object); public boolean matches(java.lang.String); public boolean regionMatches(boolean,int,java.lang.String,int,int); public boolean regionMatches(int,java.lang.String,int,int); public boolean startsWith(java.lang.String); public boolean startsWith(java.lang.String,int); public byte[] getBytes(); public byte[] getBytes(java.lang.String); public char charAt(int); public char[] toCharArray(); public int compareToIgnoreCase(java.lang.String); public int compareTo(java.lang.Object); public int compareTo(java.lang.String); public int hashCode(); public int indexOf(int); public int indexOf(int,int); public int indexOf(java.lang.String); public int indexOf(java.lang.String,int); public int lastIndexOf(int); public int lastIndexOf(int,int); public int lastIndexOf(java.lang.String); public int lastIndexOf(java.lang.String,int); public int length(); public java.lang.CharSequence subSequence(int,int); public java.lang.String concat(java.lang.String); public java.lang.String replaceAll(java.lang.String,java.lang.String); public java.lang.String replace(char,char); public java.lang.String replaceFirst(java.lang.String,java.lang.String); public java.lang.String[] split(java.lang.String); public java.lang.String[] split(java.lang.String,int); public java.lang.String substring(int); public java.lang.String substring(int,int); public java.lang.String toLowerCase(); public java.lang.String toLowerCase(java.util.Locale); public java.lang.String toString(); public java.lang.String toUpperCase(); public java.lang.String toUpperCase(java.util.Locale); public java.lang.String trim(); } # Remove - StringBuffer method calls. Remove all invocations of StringBuffer # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.StringBuffer { public java.lang.StringBuffer(); public java.lang.StringBuffer(int); public java.lang.StringBuffer(java.lang.String); public java.lang.StringBuffer(java.lang.CharSequence); public java.lang.String toString(); public char charAt(int); public int capacity(); public int codePointAt(int); public int codePointBefore(int); public int indexOf(java.lang.String,int); public int lastIndexOf(java.lang.String); public int lastIndexOf(java.lang.String,int); public int length(); public java.lang.String substring(int); public java.lang.String substring(int,int); } # Remove - StringBuilder method calls. Remove all invocations of StringBuilder # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.StringBuilder { public java.lang.StringBuilder(); public java.lang.StringBuilder(int); public java.lang.StringBuilder(java.lang.String); public java.lang.StringBuilder(java.lang.CharSequence); public java.lang.String toString(); public char charAt(int); public int capacity(); public int codePointAt(int); public int codePointBefore(int); public int indexOf(java.lang.String,int); public int lastIndexOf(java.lang.String); public int lastIndexOf(java.lang.String,int); public int length(); public java.lang.String substring(int); public java.lang.String substring(int,int); } # Remove debugging - Throwable_printStackTrace calls. Remove all invocations of # Throwable.printStackTrace(). -assumenosideeffects public class java.lang.Throwable { public void printStackTrace(); } # Remove debugging - Thread_dumpStack calls. Remove all invocations of # Thread.dumpStack(). -assumenosideeffects public class java.lang.Thread { public static void dumpStack(); } # Remove debugging - All logging API calls. Remove all invocations of the # logging API whose return values are not used. -assumenosideeffects public class java.util.logging.* { ; } # Remove debugging - All Log4j API calls. Remove all invocations of the # Log4j API whose return values are not used. -assumenosideeffects public class org.apache.log4j.** { ; } proguard4.8/src/proguard/gui/SwingUtil.java0000644000175000017500000000477111736333524017567 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import javax.swing.*; import java.lang.reflect.InvocationTargetException; /** * This utility class provides variants of the invocation method from the * SwingUtilities class. * * @see SwingUtilities * @author Eric Lafortune */ public class SwingUtil { /** * Invokes the given Runnable in the AWT event dispatching thread, * and waits for it to finish. This method may be called from any thread, * including the event dispatching thread itself. * @see SwingUtilities#invokeAndWait(Runnable) * @param runnable the Runnable to be executed. */ public static void invokeAndWait(Runnable runnable) throws InterruptedException, InvocationTargetException { try { if (SwingUtilities.isEventDispatchThread()) { runnable.run(); } else { SwingUtilities.invokeAndWait(runnable); } } catch (Exception ex) { // Ignore any exceptions. } } /** * Invokes the given Runnable in the AWT event dispatching thread, not * necessarily right away. This method may be called from any thread, * including the event dispatching thread itself. * @see SwingUtilities#invokeLater(Runnable) * @param runnable the Runnable to be executed. */ public static void invokeLater(Runnable runnable) { if (SwingUtilities.isEventDispatchThread()) { runnable.run(); } else { SwingUtilities.invokeLater(runnable); } } } proguard4.8/src/proguard/gui/default.pro0000644000175000017500000003302111163773611017132 0ustar ericeric# The default configuration when starting up the GUI. -libraryjars /lib/rt.jar # Keep - Applications. Keep all application classes, along with their 'main' # methods. -keepclasseswithmembers public class * { public static void main(java.lang.String[]); } # Also keep - Enumerations. Keep the special static methods that are required in # enumeration classes. -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } # Also keep - Database drivers. Keep all implementations of java.sql.Driver. -keep class * extends java.sql.Driver # Also keep - Swing UI L&F. Keep all extensions of javax.swing.plaf.ComponentUI, # along with the special 'createUI' method. -keep class * extends javax.swing.plaf.ComponentUI { public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent); } # Keep names - Native method names. Keep all native class/method names. -keepclasseswithmembers,allowshrinking class * { native ; } # Remove - System method calls. Remove all invocations of System # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.System { public static long currentTimeMillis(); static java.lang.Class getCallerClass(); public static int identityHashCode(java.lang.Object); public static java.lang.SecurityManager getSecurityManager(); public static java.util.Properties getProperties(); public static java.lang.String getProperty(java.lang.String); public static java.lang.String getenv(java.lang.String); public static java.lang.String mapLibraryName(java.lang.String); public static java.lang.String getProperty(java.lang.String,java.lang.String); } # Remove - Math method calls. Remove all invocations of Math # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.Math { public static double sin(double); public static double cos(double); public static double tan(double); public static double asin(double); public static double acos(double); public static double atan(double); public static double toRadians(double); public static double toDegrees(double); public static double exp(double); public static double log(double); public static double log10(double); public static double sqrt(double); public static double cbrt(double); public static double IEEEremainder(double,double); public static double ceil(double); public static double floor(double); public static double rint(double); public static double atan2(double,double); public static double pow(double,double); public static int round(float); public static long round(double); public static double random(); public static int abs(int); public static long abs(long); public static float abs(float); public static double abs(double); public static int max(int,int); public static long max(long,long); public static float max(float,float); public static double max(double,double); public static int min(int,int); public static long min(long,long); public static float min(float,float); public static double min(double,double); public static double ulp(double); public static float ulp(float); public static double signum(double); public static float signum(float); public static double sinh(double); public static double cosh(double); public static double tanh(double); public static double hypot(double,double); public static double expm1(double); public static double log1p(double); } # Remove - Number method calls. Remove all invocations of Number # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.* extends java.lang.Number { public static java.lang.String toString(byte); public static java.lang.Byte valueOf(byte); public static byte parseByte(java.lang.String); public static byte parseByte(java.lang.String,int); public static java.lang.Byte valueOf(java.lang.String,int); public static java.lang.Byte valueOf(java.lang.String); public static java.lang.Byte decode(java.lang.String); public int compareTo(java.lang.Byte); public static java.lang.String toString(short); public static short parseShort(java.lang.String); public static short parseShort(java.lang.String,int); public static java.lang.Short valueOf(java.lang.String,int); public static java.lang.Short valueOf(java.lang.String); public static java.lang.Short valueOf(short); public static java.lang.Short decode(java.lang.String); public static short reverseBytes(short); public int compareTo(java.lang.Short); public static java.lang.String toString(int,int); public static java.lang.String toHexString(int); public static java.lang.String toOctalString(int); public static java.lang.String toBinaryString(int); public static java.lang.String toString(int); public static int parseInt(java.lang.String,int); public static int parseInt(java.lang.String); public static java.lang.Integer valueOf(java.lang.String,int); public static java.lang.Integer valueOf(java.lang.String); public static java.lang.Integer valueOf(int); public static java.lang.Integer getInteger(java.lang.String); public static java.lang.Integer getInteger(java.lang.String,int); public static java.lang.Integer getInteger(java.lang.String,java.lang.Integer); public static java.lang.Integer decode(java.lang.String); public static int highestOneBit(int); public static int lowestOneBit(int); public static int numberOfLeadingZeros(int); public static int numberOfTrailingZeros(int); public static int bitCount(int); public static int rotateLeft(int,int); public static int rotateRight(int,int); public static int reverse(int); public static int signum(int); public static int reverseBytes(int); public int compareTo(java.lang.Integer); public static java.lang.String toString(long,int); public static java.lang.String toHexString(long); public static java.lang.String toOctalString(long); public static java.lang.String toBinaryString(long); public static java.lang.String toString(long); public static long parseLong(java.lang.String,int); public static long parseLong(java.lang.String); public static java.lang.Long valueOf(java.lang.String,int); public static java.lang.Long valueOf(java.lang.String); public static java.lang.Long valueOf(long); public static java.lang.Long decode(java.lang.String); public static java.lang.Long getLong(java.lang.String); public static java.lang.Long getLong(java.lang.String,long); public static java.lang.Long getLong(java.lang.String,java.lang.Long); public static long highestOneBit(long); public static long lowestOneBit(long); public static int numberOfLeadingZeros(long); public static int numberOfTrailingZeros(long); public static int bitCount(long); public static long rotateLeft(long,int); public static long rotateRight(long,int); public static long reverse(long); public static int signum(long); public static long reverseBytes(long); public int compareTo(java.lang.Long); public static java.lang.String toString(float); public static java.lang.String toHexString(float); public static java.lang.Float valueOf(java.lang.String); public static java.lang.Float valueOf(float); public static float parseFloat(java.lang.String); public static boolean isNaN(float); public static boolean isInfinite(float); public static int floatToIntBits(float); public static int floatToRawIntBits(float); public static float intBitsToFloat(int); public static int compare(float,float); public boolean isNaN(); public boolean isInfinite(); public int compareTo(java.lang.Float); public static java.lang.String toString(double); public static java.lang.String toHexString(double); public static java.lang.Double valueOf(java.lang.String); public static java.lang.Double valueOf(double); public static double parseDouble(java.lang.String); public static boolean isNaN(double); public static boolean isInfinite(double); public static long doubleToLongBits(double); public static long doubleToRawLongBits(double); public static double longBitsToDouble(long); public static int compare(double,double); public boolean isNaN(); public boolean isInfinite(); public int compareTo(java.lang.Double); public (byte); public (short); public (int); public (long); public (float); public (double); public (java.lang.String); public byte byteValue(); public short shortValue(); public int intValue(); public long longValue(); public float floatValue(); public double doubleValue(); public int compareTo(java.lang.Object); public boolean equals(java.lang.Object); public int hashCode(); public java.lang.String toString(); } # Remove - String method calls. Remove all invocations of String # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.String { public (); public (byte[]); public (byte[],int); public (byte[],int,int); public (byte[],int,int,int); public (byte[],int,int,java.lang.String); public (byte[],java.lang.String); public (char[]); public (char[],int,int); public (java.lang.String); public (java.lang.StringBuffer); public static java.lang.String copyValueOf(char[]); public static java.lang.String copyValueOf(char[],int,int); public static java.lang.String valueOf(boolean); public static java.lang.String valueOf(char); public static java.lang.String valueOf(char[]); public static java.lang.String valueOf(char[],int,int); public static java.lang.String valueOf(double); public static java.lang.String valueOf(float); public static java.lang.String valueOf(int); public static java.lang.String valueOf(java.lang.Object); public static java.lang.String valueOf(long); public boolean contentEquals(java.lang.StringBuffer); public boolean endsWith(java.lang.String); public boolean equalsIgnoreCase(java.lang.String); public boolean equals(java.lang.Object); public boolean matches(java.lang.String); public boolean regionMatches(boolean,int,java.lang.String,int,int); public boolean regionMatches(int,java.lang.String,int,int); public boolean startsWith(java.lang.String); public boolean startsWith(java.lang.String,int); public byte[] getBytes(); public byte[] getBytes(java.lang.String); public char charAt(int); public char[] toCharArray(); public int compareToIgnoreCase(java.lang.String); public int compareTo(java.lang.Object); public int compareTo(java.lang.String); public int hashCode(); public int indexOf(int); public int indexOf(int,int); public int indexOf(java.lang.String); public int indexOf(java.lang.String,int); public int lastIndexOf(int); public int lastIndexOf(int,int); public int lastIndexOf(java.lang.String); public int lastIndexOf(java.lang.String,int); public int length(); public java.lang.CharSequence subSequence(int,int); public java.lang.String concat(java.lang.String); public java.lang.String replaceAll(java.lang.String,java.lang.String); public java.lang.String replace(char,char); public java.lang.String replaceFirst(java.lang.String,java.lang.String); public java.lang.String[] split(java.lang.String); public java.lang.String[] split(java.lang.String,int); public java.lang.String substring(int); public java.lang.String substring(int,int); public java.lang.String toLowerCase(); public java.lang.String toLowerCase(java.util.Locale); public java.lang.String toString(); public java.lang.String toUpperCase(); public java.lang.String toUpperCase(java.util.Locale); public java.lang.String trim(); } # Remove - StringBuffer method calls. Remove all invocations of StringBuffer # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.StringBuffer { public (); public (int); public (java.lang.String); public (java.lang.CharSequence); public java.lang.String toString(); public char charAt(int); public int capacity(); public int codePointAt(int); public int codePointBefore(int); public int indexOf(java.lang.String,int); public int lastIndexOf(java.lang.String); public int lastIndexOf(java.lang.String,int); public int length(); public java.lang.String substring(int); public java.lang.String substring(int,int); } # Remove - StringBuilder method calls. Remove all invocations of StringBuilder # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.StringBuilder { public (); public (int); public (java.lang.String); public (java.lang.CharSequence); public java.lang.String toString(); public char charAt(int); public int capacity(); public int codePointAt(int); public int codePointBefore(int); public int indexOf(java.lang.String,int); public int lastIndexOf(java.lang.String); public int lastIndexOf(java.lang.String,int); public int length(); public java.lang.String substring(int); public java.lang.String substring(int,int); } proguard4.8/src/proguard/gui/ClassSpecificationDialog.java0000644000175000017500000006273111736333525022531 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.*; import proguard.classfile.ClassConstants; import proguard.classfile.util.ClassUtil; import javax.swing.*; import javax.swing.border.*; import java.awt.*; import java.awt.event.*; import java.util.List; /** * This JDialog allows the user to enter a String. * * @author Eric Lafortune */ final class ClassSpecificationDialog extends JDialog { /** * Return value if the dialog is canceled (with the Cancel button or by * closing the dialog window). */ public static final int CANCEL_OPTION = 1; /** * Return value if the dialog is approved (with the Ok button). */ public static final int APPROVE_OPTION = 0; private final JTextArea commentsTextArea = new JTextArea(4, 20); private final JRadioButton keepClassesAndMembersRadioButton = new JRadioButton(msg("keep")); private final JRadioButton keepClassMembersRadioButton = new JRadioButton(msg("keepClassMembers")); private final JRadioButton keepClassesWithMembersRadioButton = new JRadioButton(msg("keepClassesWithMembers")); private final JCheckBox allowShrinkingCheckBox = new JCheckBox(msg("allowShrinking")); private final JCheckBox allowOptimizationCheckBox = new JCheckBox(msg("allowOptimization")); private final JCheckBox allowObfuscationCheckBox = new JCheckBox(msg("allowObfuscation")); private final JRadioButton[] publicRadioButtons; private final JRadioButton[] finalRadioButtons; private final JRadioButton[] abstractRadioButtons; private final JRadioButton[] interfaceRadioButtons; private final JRadioButton[] annotationRadioButtons; private final JRadioButton[] enumRadioButtons; private final JRadioButton[] syntheticRadioButtons; private final JTextField annotationTypeTextField = new JTextField(20); private final JTextField classNameTextField = new JTextField(20); private final JTextField extendsAnnotationTypeTextField = new JTextField(20); private final JTextField extendsClassNameTextField = new JTextField(20); private final MemberSpecificationsPanel memberSpecificationsPanel; private int returnValue; public ClassSpecificationDialog(JFrame owner, boolean fullKeepOptions) { super(owner, msg("specifyClasses"), true); setResizable(true); // Create some constraints that can be reused. GridBagConstraints constraints = new GridBagConstraints(); constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(1, 2, 1, 2); GridBagConstraints constraintsStretch = new GridBagConstraints(); constraintsStretch.fill = GridBagConstraints.HORIZONTAL; constraintsStretch.weightx = 1.0; constraintsStretch.anchor = GridBagConstraints.WEST; constraintsStretch.insets = constraints.insets; GridBagConstraints constraintsLast = new GridBagConstraints(); constraintsLast.gridwidth = GridBagConstraints.REMAINDER; constraintsLast.anchor = GridBagConstraints.WEST; constraintsLast.insets = constraints.insets; GridBagConstraints constraintsLastStretch = new GridBagConstraints(); constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER; constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL; constraintsLastStretch.weightx = 1.0; constraintsLastStretch.anchor = GridBagConstraints.WEST; constraintsLastStretch.insets = constraints.insets; GridBagConstraints panelConstraints = new GridBagConstraints(); panelConstraints.gridwidth = GridBagConstraints.REMAINDER; panelConstraints.fill = GridBagConstraints.HORIZONTAL; panelConstraints.weightx = 1.0; panelConstraints.weighty = 0.0; panelConstraints.anchor = GridBagConstraints.NORTHWEST; panelConstraints.insets = constraints.insets; GridBagConstraints stretchPanelConstraints = new GridBagConstraints(); stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER; stretchPanelConstraints.fill = GridBagConstraints.BOTH; stretchPanelConstraints.weightx = 1.0; stretchPanelConstraints.weighty = 1.0; stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST; stretchPanelConstraints.insets = constraints.insets; GridBagConstraints labelConstraints = new GridBagConstraints(); labelConstraints.anchor = GridBagConstraints.CENTER; labelConstraints.insets = new Insets(2, 10, 2, 10); GridBagConstraints lastLabelConstraints = new GridBagConstraints(); lastLabelConstraints.gridwidth = GridBagConstraints.REMAINDER; lastLabelConstraints.anchor = GridBagConstraints.CENTER; lastLabelConstraints.insets = labelConstraints.insets; GridBagConstraints advancedButtonConstraints = new GridBagConstraints(); advancedButtonConstraints.weightx = 1.0; advancedButtonConstraints.weighty = 1.0; advancedButtonConstraints.anchor = GridBagConstraints.SOUTHWEST; advancedButtonConstraints.insets = new Insets(4, 4, 8, 4); GridBagConstraints okButtonConstraints = new GridBagConstraints(); okButtonConstraints.weightx = 1.0; okButtonConstraints.weighty = 1.0; okButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; okButtonConstraints.insets = advancedButtonConstraints.insets; GridBagConstraints cancelButtonConstraints = new GridBagConstraints(); cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER; cancelButtonConstraints.weighty = 1.0; cancelButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; cancelButtonConstraints.insets = advancedButtonConstraints.insets; GridBagLayout layout = new GridBagLayout(); Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); // Create the comments panel. JPanel commentsPanel = new JPanel(layout); commentsPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("comments"))); JScrollPane commentsScrollPane = new JScrollPane(commentsTextArea); commentsScrollPane.setBorder(classNameTextField.getBorder()); commentsPanel.add(tip(commentsScrollPane, "commentsTip"), constraintsLastStretch); // Create the keep option panel. ButtonGroup keepButtonGroup = new ButtonGroup(); keepButtonGroup.add(keepClassesAndMembersRadioButton); keepButtonGroup.add(keepClassMembersRadioButton); keepButtonGroup.add(keepClassesWithMembersRadioButton); JPanel keepOptionPanel = new JPanel(layout); keepOptionPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("keepTitle"))); keepOptionPanel.add(tip(keepClassesAndMembersRadioButton, "keepTip"), constraintsLastStretch); keepOptionPanel.add(tip(keepClassMembersRadioButton, "keepClassMembersTip"), constraintsLastStretch); keepOptionPanel.add(tip(keepClassesWithMembersRadioButton, "keepClassesWithMembersTip"), constraintsLastStretch); // Create the allow option panel. final JPanel allowOptionPanel = new JPanel(layout); allowOptionPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("allowTitle"))); allowOptionPanel.add(tip(allowShrinkingCheckBox, "allowShrinkingTip"), constraintsLastStretch); allowOptionPanel.add(tip(allowOptimizationCheckBox, "allowOptimizationTip"), constraintsLastStretch); allowOptionPanel.add(tip(allowObfuscationCheckBox, "allowObfuscationTip"), constraintsLastStretch); // Create the access panel. JPanel accessPanel = new JPanel(layout); accessPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("access"))); accessPanel.add(Box.createGlue(), labelConstraints); accessPanel.add(tip(new JLabel(msg("required")), "requiredTip"), labelConstraints); accessPanel.add(tip(new JLabel(msg("not")), "notTip"), labelConstraints); accessPanel.add(tip(new JLabel(msg("dontCare")), "dontCareTip"), labelConstraints); accessPanel.add(Box.createGlue(), constraintsLastStretch); publicRadioButtons = addRadioButtonTriplet("Public", accessPanel); finalRadioButtons = addRadioButtonTriplet("Final", accessPanel); abstractRadioButtons = addRadioButtonTriplet("Abstract", accessPanel); interfaceRadioButtons = addRadioButtonTriplet("Interface", accessPanel); annotationRadioButtons = addRadioButtonTriplet("Annotation", accessPanel); enumRadioButtons = addRadioButtonTriplet("Enum", accessPanel); syntheticRadioButtons = addRadioButtonTriplet("Synthetic", accessPanel); // Create the annotation type panel. final JPanel annotationTypePanel = new JPanel(layout); annotationTypePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("annotation"))); annotationTypePanel.add(tip(annotationTypeTextField, "classNameTip"), constraintsLastStretch); // Create the class name panel. JPanel classNamePanel = new JPanel(layout); classNamePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("class"))); classNamePanel.add(tip(classNameTextField, "classNameTip"), constraintsLastStretch); // Create the extends annotation type panel. final JPanel extendsAnnotationTypePanel = new JPanel(layout); extendsAnnotationTypePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("extendsImplementsAnnotation"))); extendsAnnotationTypePanel.add(tip(extendsAnnotationTypeTextField, "classNameTip"), constraintsLastStretch); // Create the extends class name panel. JPanel extendsClassNamePanel = new JPanel(layout); extendsClassNamePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("extendsImplementsClass"))); extendsClassNamePanel.add(tip(extendsClassNameTextField, "classNameTip"), constraintsLastStretch); // Create the class member list panel. memberSpecificationsPanel = new MemberSpecificationsPanel(this, fullKeepOptions); memberSpecificationsPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("classMembers"))); // Create the Advanced button. final JButton advancedButton = new JButton(msg("basic")); advancedButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { boolean visible = !allowOptionPanel.isVisible(); allowOptionPanel .setVisible(visible); annotationTypePanel .setVisible(visible); extendsAnnotationTypePanel.setVisible(visible); advancedButton.setText(msg(visible ? "basic" : "advanced")); pack(); } }); advancedButton.doClick(); // Create the Ok button. JButton okButton = new JButton(msg("ok")); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { returnValue = APPROVE_OPTION; hide(); } }); // Create the Cancel button. JButton cancelButton = new JButton(msg("cancel")); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { hide(); } }); // Add all panels to the main panel. JPanel mainPanel = new JPanel(layout); mainPanel.add(tip(commentsPanel, "commentsTip"), panelConstraints); if (fullKeepOptions) { mainPanel.add(tip(keepOptionPanel, "keepTitleTip"), panelConstraints); mainPanel.add(tip(allowOptionPanel, "allowTitleTip"), panelConstraints); } mainPanel.add(tip(accessPanel, "accessTip"), panelConstraints); mainPanel.add(tip(annotationTypePanel, "annotationTip"), panelConstraints); mainPanel.add(tip(classNamePanel, "classTip"), panelConstraints); mainPanel.add(tip(extendsAnnotationTypePanel, "extendsImplementsAnnotationTip"), panelConstraints); mainPanel.add(tip(extendsClassNamePanel, "extendsImplementsClassTip"), panelConstraints); mainPanel.add(tip(memberSpecificationsPanel, "classMembersTip"), stretchPanelConstraints); mainPanel.add(tip(advancedButton, "advancedTip"), advancedButtonConstraints); mainPanel.add(okButton, okButtonConstraints); mainPanel.add(cancelButton, cancelButtonConstraints); getContentPane().add(new JScrollPane(mainPanel)); } /** * Adds a JLabel and three JRadioButton instances in a ButtonGroup to the * given panel with a GridBagLayout, and returns the buttons in an array. */ private JRadioButton[] addRadioButtonTriplet(String labelText, JPanel panel) { GridBagConstraints labelConstraints = new GridBagConstraints(); labelConstraints.anchor = GridBagConstraints.WEST; labelConstraints.insets = new Insets(2, 10, 2, 10); GridBagConstraints buttonConstraints = new GridBagConstraints(); buttonConstraints.insets = labelConstraints.insets; GridBagConstraints lastGlueConstraints = new GridBagConstraints(); lastGlueConstraints.gridwidth = GridBagConstraints.REMAINDER; lastGlueConstraints.weightx = 1.0; // Create the radio buttons. JRadioButton radioButton0 = new JRadioButton(); JRadioButton radioButton1 = new JRadioButton(); JRadioButton radioButton2 = new JRadioButton(); // Put them in a button group. ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(radioButton0); buttonGroup.add(radioButton1); buttonGroup.add(radioButton2); // Add the label and the buttons to the panel. panel.add(new JLabel(labelText), labelConstraints); panel.add(radioButton0, buttonConstraints); panel.add(radioButton1, buttonConstraints); panel.add(radioButton2, buttonConstraints); panel.add(Box.createGlue(), lastGlueConstraints); return new JRadioButton[] { radioButton0, radioButton1, radioButton2 }; } /** * Sets the KeepClassSpecification to be represented in this dialog. */ public void setKeepSpecification(KeepClassSpecification keepClassSpecification) { boolean markClasses = keepClassSpecification.markClasses; boolean markConditionally = keepClassSpecification.markConditionally; boolean allowShrinking = keepClassSpecification.allowShrinking; boolean allowOptimization = keepClassSpecification.allowOptimization; boolean allowObfuscation = keepClassSpecification.allowObfuscation; // Figure out the proper keep radio button and set it. JRadioButton keepOptionRadioButton = markConditionally ? keepClassesWithMembersRadioButton : markClasses ? keepClassesAndMembersRadioButton : keepClassMembersRadioButton; keepOptionRadioButton.setSelected(true); // Set the allow radio buttons. allowShrinkingCheckBox .setSelected(allowShrinking); allowOptimizationCheckBox.setSelected(allowOptimization); allowObfuscationCheckBox .setSelected(allowObfuscation); setClassSpecification(keepClassSpecification); } /** * Sets the ClassSpecification to be represented in this dialog. */ public void setClassSpecification(ClassSpecification classSpecification) { String comments = classSpecification.comments; String annotationType = classSpecification.annotationType; String className = classSpecification.className; String extendsAnnotationType = classSpecification.extendsAnnotationType; String extendsClassName = classSpecification.extendsClassName; List keepFieldOptions = classSpecification.fieldSpecifications; List keepMethodOptions = classSpecification.methodSpecifications; // Set the comments text area. commentsTextArea.setText(comments == null ? "" : comments); // Set the access radio buttons. setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_INTERFACE, interfaceRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ANNOTATTION, annotationRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ENUM, enumRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_SYNTHETIC, syntheticRadioButtons); // Set the class and annotation text fields. annotationTypeTextField .setText(annotationType == null ? "" : ClassUtil.externalType(annotationType)); classNameTextField .setText(className == null ? "*" : ClassUtil.externalClassName(className)); extendsAnnotationTypeTextField.setText(extendsAnnotationType == null ? "" : ClassUtil.externalType(extendsAnnotationType)); extendsClassNameTextField .setText(extendsClassName == null ? "" : ClassUtil.externalClassName(extendsClassName)); // Set the keep class member option list. memberSpecificationsPanel.setMemberSpecifications(keepFieldOptions, keepMethodOptions); } /** * Returns the KeepClassSpecification currently represented in this dialog. */ public KeepClassSpecification getKeepSpecification() { boolean markClasses = !keepClassMembersRadioButton .isSelected(); boolean markConditionally = keepClassesWithMembersRadioButton.isSelected(); boolean allowShrinking = allowShrinkingCheckBox .isSelected(); boolean allowOptimization = allowOptimizationCheckBox .isSelected(); boolean allowObfuscation = allowObfuscationCheckBox .isSelected(); return new KeepClassSpecification(markClasses, markConditionally, allowShrinking, allowOptimization, allowObfuscation, getClassSpecification()); } /** * Returns the ClassSpecification currently represented in this dialog. */ public ClassSpecification getClassSpecification() { String comments = commentsTextArea.getText(); String annotationType = annotationTypeTextField.getText(); String className = classNameTextField.getText(); String extendsAnnotationType = extendsAnnotationTypeTextField.getText(); String extendsClassName = extendsClassNameTextField.getText(); ClassSpecification classSpecification = new ClassSpecification(comments.equals("") ? null : comments, 0, 0, annotationType.equals("") ? null : ClassUtil.internalType(annotationType), className.equals("") || className.equals("*") ? null : ClassUtil.internalClassName(className), extendsAnnotationType.equals("") ? null : ClassUtil.internalType(extendsAnnotationType), extendsClassName.equals("") ? null : ClassUtil.internalClassName(extendsClassName)); // Also get the access radio button settings. getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_INTERFACE, interfaceRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ANNOTATTION, annotationRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ENUM, enumRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_SYNTHETIC, syntheticRadioButtons); // Get the keep class member option lists. classSpecification.fieldSpecifications = memberSpecificationsPanel.getMemberSpecifications(true); classSpecification.methodSpecifications = memberSpecificationsPanel.getMemberSpecifications(false); return classSpecification; } /** * Shows this dialog. This method only returns when the dialog is closed. * * @return CANCEL_OPTION or APPROVE_OPTION, * depending on the choice of the user. */ public int showDialog() { returnValue = CANCEL_OPTION; // Open the dialog in the right place, then wait for it to be closed, // one way or another. pack(); setLocationRelativeTo(getOwner()); show(); return returnValue; } /** * Sets the appropriate radio button of a given triplet, based on the access * flags of the given keep option. */ private void setClassSpecificationRadioButtons(ClassSpecification classSpecification, int flag, JRadioButton[] radioButtons) { int index = (classSpecification.requiredSetAccessFlags & flag) != 0 ? 0 : (classSpecification.requiredUnsetAccessFlags & flag) != 0 ? 1 : 2; radioButtons[index].setSelected(true); } /** * Updates the access flag of the given keep option, based on the given radio * button triplet. */ private void getClassSpecificationRadioButtons(ClassSpecification classSpecification, int flag, JRadioButton[] radioButtons) { if (radioButtons[0].isSelected()) { classSpecification.requiredSetAccessFlags |= flag; } else if (radioButtons[1].isSelected()) { classSpecification.requiredUnsetAccessFlags |= flag; } } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } } proguard4.8/src/proguard/gui/KeepSpecificationsPanel.java0000644000175000017500000000534411736333525022370 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.*; import javax.swing.*; /** * This ListPanel allows the user to add, edit, move, and remove * KeepClassSpecification entries in a list. * * @author Eric Lafortune */ final class KeepSpecificationsPanel extends ClassSpecificationsPanel { private final boolean markClasses; private final boolean markConditionally; private final boolean allowShrinking; private final boolean allowOptimization; private final boolean allowObfuscation; public KeepSpecificationsPanel(JFrame owner, boolean markClasses, boolean markConditionally, boolean allowShrinking, boolean allowOptimization, boolean allowObfuscation) { super(owner, true); this.markClasses = markClasses; this.markConditionally = markConditionally; this.allowShrinking = allowShrinking; this.allowOptimization = allowOptimization; this.allowObfuscation = allowObfuscation; } // Factory methods for ClassSpecificationsPanel. protected ClassSpecification createClassSpecification() { return new KeepClassSpecification(markClasses, markConditionally, allowShrinking, allowOptimization, allowObfuscation); } protected void setClassSpecification(ClassSpecification classSpecification) { classSpecificationDialog.setKeepSpecification((KeepClassSpecification)classSpecification); } protected ClassSpecification getClassSpecification() { return classSpecificationDialog.getKeepSpecification(); } } proguard4.8/src/proguard/gui/splash/0000775000175000017500000000000011760503005016250 5ustar ericericproguard4.8/src/proguard/gui/splash/package.html0000644000175000017500000000022311736333525020537 0ustar ericeric This package contains a library for creating splash screens and animations with text, graphical elements, and some special effects. proguard4.8/src/proguard/gui/splash/TypeWriterString.java0000644000175000017500000000414411736333525022434 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This VariableString produces a String that grows linearly with respect to its * Timing, as if it is being written on a typewriter. A cursor at the end * precedes the typed characters. * * @author Eric Lafortune */ public class TypeWriterString implements VariableString { private final String string; private final Timing timing; private int cachedLength = -1; private String cachedString; /** * Creates a new TypeWriterString. * @param string the basic String. * @param timing the applied timing. */ public TypeWriterString(String string, Timing timing) { this.string = string; this.timing = timing; } // Implementation for VariableString. public String getString(long time) { double t = timing.getTiming(time); int stringLength = string.length(); int length = (int)(stringLength * t + 0.5); if (length != cachedLength) { cachedLength = length; cachedString = string.substring(0, length); if (t > 0.0 && length < stringLength) { cachedString += "_"; } } return cachedString; } } proguard4.8/src/proguard/gui/splash/TimeSwitchSprite.java0000644000175000017500000000425311736333525022377 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite displays another Sprite in a given time interval. * The time of the encapsulated Sprite is shifted by the start time. * * @author Eric Lafortune */ public class TimeSwitchSprite implements Sprite { private final long onTime; private final long offTime; private final Sprite sprite; /** * Creates a new TimeSwitchSprite for displaying a given Sprite starting at * a given time. * @param onTime the start time. * @param sprite the toggled Sprite. */ public TimeSwitchSprite(long onTime, Sprite sprite) { this(onTime, 0L, sprite); } /** * Creates a new TimeSwitchSprite for displaying a given Sprite in a given * time interval. * @param onTime the start time. * @param offTime the stop time. * @param sprite the toggled Sprite. */ public TimeSwitchSprite(long onTime, long offTime, Sprite sprite) { this.onTime = onTime; this.offTime = offTime; this.sprite = sprite; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { if (time >= onTime && (offTime <= 0 || time <= offTime)) { sprite.paint(graphics, time - onTime); } } } proguard4.8/src/proguard/gui/splash/RectangleSprite.java0000644000175000017500000001010711736333525022216 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite represents an animated rounded rectangle. It can optionally be filled. * * @author Eric Lafortune */ public class RectangleSprite implements Sprite { private final boolean filled; private final VariableColor color; private final VariableInt x; private final VariableInt y; private final VariableInt width; private final VariableInt height; private final VariableInt arcWidth; private final VariableInt arcHeight; /** * Creates a new rectangular RectangleSprite. * @param filled specifies whether the rectangle should be filled. * @param color the variable color of the rectangle. * @param x the variable x-ordinate of the upper-left corner of the rectangle. * @param y the variable y-ordinate of the upper-left corner of the rectangle. * @param width the variable width of the rectangle. * @param height the variable height of the rectangle. */ public RectangleSprite(boolean filled, VariableColor color, VariableInt x, VariableInt y, VariableInt width, VariableInt height) { this(filled, color, x, y, width, height, new ConstantInt(0), new ConstantInt(0)); } /** * Creates a new RectangleSprite with rounded corners. * @param filled specifies whether the rectangle should be filled. * @param color the variable color of the rectangle. * @param x the variable x-ordinate of the upper-left corner of the rectangle. * @param y the variable y-ordinate of the upper-left corner of the rectangle. * @param width the variable width of the rectangle. * @param height the variable height of the rectangle. * @param arcWidth the variable width of the corner arcs. * @param arcHeight the variable height of the corner arcs. */ public RectangleSprite(boolean filled, VariableColor color, VariableInt x, VariableInt y, VariableInt width, VariableInt height, VariableInt arcWidth, VariableInt arcHeight) { this.filled = filled; this.color = color; this.x = x; this.y = y; this.width = width; this.height = height; this.arcWidth = arcWidth; this.arcHeight = arcHeight; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { graphics.setColor(color.getColor(time)); int xt = x.getInt(time); int yt = y.getInt(time); int w = width.getInt(time); int h = height.getInt(time); int aw = arcWidth.getInt(time); int ah = arcHeight.getInt(time); if (filled) { graphics.fillRoundRect(xt, yt, w, h, aw, ah); } else { graphics.drawRoundRect(xt, yt, w, h, aw, ah); } } } proguard4.8/src/proguard/gui/splash/OverrideGraphics2D.java0000644000175000017500000003471411736333525022563 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; import java.awt.RenderingHints.Key; import java.awt.font.*; import java.awt.geom.AffineTransform; import java.awt.image.*; import java.awt.image.renderable.RenderableImage; import java.text.AttributedCharacterIterator; import java.util.Map; /** * This Graphics2D allows to fix some basic settings (Color, Font, Paint, Stroke, * XORMode) of a delegate Graphics2D, overriding any subsequent attempts to * change those settings. * * @author Eric Lafortune * @noinspection deprecation */ final class OverrideGraphics2D extends Graphics2D { private final Graphics2D graphics; private Color overrideColor; private Font overrideFont; private Paint overridePaint; private Stroke overrideStroke; private Color overrideXORMode; private Color color; private Font font; private Paint paint; private Stroke stroke; /** * Creates a new OverrideGraphics2D. * @param graphics the delegate Graphics2D. */ public OverrideGraphics2D(Graphics2D graphics) { this.graphics = graphics; this.color = graphics.getColor(); this.font = graphics.getFont(); this.paint = graphics.getPaint(); this.stroke = graphics.getStroke(); } /** * Fixes the Color of the Graphics2D. * * @param color the fixed Color, or null to undo the fixing. */ public void setOverrideColor(Color color) { this.overrideColor = color; graphics.setColor(color != null ? color : this.color); } /** * Fixes the Font of the Graphics2D. * * @param font the fixed Font, or null to undo the fixing. */ public void setOverrideFont(Font font) { this.overrideFont = font; graphics.setFont(font != null ? font : this.font); } /** * Fixes the Paint of the Graphics2D. * * @param paint the fixed Paint, or null to undo the fixing. */ public void setOverridePaint(Paint paint) { this.overridePaint = paint; graphics.setPaint(paint != null ? paint : this.paint); } /** * Fixes the Stroke of the Graphics2D. * * @param stroke the fixed Stroke, or null to undo the fixing. */ public void setOverrideStroke(Stroke stroke) { this.overrideStroke = stroke; graphics.setStroke(stroke != null ? stroke : this.stroke); } /** * Fixes the XORMode of the Graphics2D. * * @param color the fixed XORMode Color, or null to undo the fixing. */ public void setOverrideXORMode(Color color) { this.overrideXORMode = color; if (color != null) { graphics.setXORMode(color); } else { graphics.setPaintMode(); } } // Implementations for Graphics2D. public void setColor(Color color) { this.color = color; if (overrideColor == null) { graphics.setColor(color); } } public void setFont(Font font) { this.font = font; if (overrideFont == null) { graphics.setFont(font); } } public void setPaint(Paint paint) { this.paint = paint; if (overridePaint == null) { graphics.setPaint(paint); } } public void setStroke(Stroke stroke) { this.stroke = stroke; if (overrideStroke == null) { graphics.setStroke(stroke); } } public void setXORMode(Color color) { if (overrideXORMode == null) { graphics.setXORMode(color); } } public void setPaintMode() { if (overrideXORMode == null) { graphics.setPaintMode(); } } public Color getColor() { return overrideColor != null ? color : graphics.getColor(); } public Font getFont() { return overrideFont != null ? font : graphics.getFont(); } public Paint getPaint() { return overridePaint != null ? paint : graphics.getPaint(); } public Stroke getStroke() { return overrideStroke != null ? stroke : graphics.getStroke(); } public Graphics create() { OverrideGraphics2D g = new OverrideGraphics2D((Graphics2D)graphics.create()); g.setOverrideColor(overrideColor); g.setOverrideFont(overrideFont); g.setOverridePaint(overridePaint); g.setOverrideStroke(overrideStroke); return g; } public Graphics create(int x, int y, int width, int height) { OverrideGraphics2D g = new OverrideGraphics2D((Graphics2D)graphics.create(x, y, width, height)); g.setOverrideColor(overrideColor); g.setOverrideFont(overrideFont); g.setOverridePaint(overridePaint); g.setOverrideStroke(overrideStroke); return g; } // Delegation for Graphics2D public void addRenderingHints(Map hints) { graphics.addRenderingHints(hints); } public void clearRect(int x, int y, int width, int height) { graphics.clearRect(x, y, width, height); } public void clip(Shape s) { graphics.clip(s); } public void clipRect(int x, int y, int width, int height) { graphics.clipRect(x, y, width, height); } public void copyArea(int x, int y, int width, int height, int dx, int dy) { graphics.copyArea(x, y, width, height, dx, dy); } public void dispose() { graphics.dispose(); } public void draw(Shape s) { graphics.draw(s); } public void draw3DRect(int x, int y, int width, int height, boolean raised) { graphics.draw3DRect(x, y, width, height, raised); } public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { graphics.drawArc(x, y, width, height, startAngle, arcAngle); } public void drawBytes(byte[] data, int offset, int length, int x, int y) { graphics.drawBytes(data, offset, length, x, y); } public void drawChars(char[] data, int offset, int length, int x, int y) { graphics.drawChars(data, offset, length, x, y); } public void drawGlyphVector(GlyphVector g, float x, float y) { graphics.drawGlyphVector(g, x, y); } public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { return graphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); } public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { return graphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); } public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { return graphics.drawImage(img, x, y, width, height, bgcolor, observer); } public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { return graphics.drawImage(img, x, y, width, height, observer); } public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { return graphics.drawImage(img, x, y, bgcolor, observer); } public boolean drawImage(Image img, int x, int y, ImageObserver observer) { return graphics.drawImage(img, x, y, observer); } public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { return graphics.drawImage(img, xform, obs); } public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { graphics.drawImage(img, op, x, y); } public void drawLine(int x1, int y1, int x2, int y2) { graphics.drawLine(x1, y1, x2, y2); } public void drawOval(int x, int y, int width, int height) { graphics.drawOval(x, y, width, height); } public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { graphics.drawPolygon(xPoints, yPoints, nPoints); } public void drawPolygon(Polygon p) { graphics.drawPolygon(p); } public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { graphics.drawPolyline(xPoints, yPoints, nPoints); } public void drawRect(int x, int y, int width, int height) { graphics.drawRect(x, y, width, height); } public void drawRenderableImage(RenderableImage img, AffineTransform xform) { graphics.drawRenderableImage(img, xform); } public void drawRenderedImage(RenderedImage img, AffineTransform xform) { graphics.drawRenderedImage(img, xform); } public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { graphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight); } public void drawString(String s, float x, float y) { graphics.drawString(s, x, y); } public void drawString(String str, int x, int y) { graphics.drawString(str, x, y); } public void drawString(AttributedCharacterIterator iterator, float x, float y) { graphics.drawString(iterator, x, y); } public void drawString(AttributedCharacterIterator iterator, int x, int y) { graphics.drawString(iterator, x, y); } public boolean equals(Object obj) { return graphics.equals(obj); } public void fill(Shape s) { graphics.fill(s); } public void fill3DRect(int x, int y, int width, int height, boolean raised) { graphics.fill3DRect(x, y, width, height, raised); } public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { graphics.fillArc(x, y, width, height, startAngle, arcAngle); } public void fillOval(int x, int y, int width, int height) { graphics.fillOval(x, y, width, height); } public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { graphics.fillPolygon(xPoints, yPoints, nPoints); } public void fillPolygon(Polygon p) { graphics.fillPolygon(p); } public void fillRect(int x, int y, int width, int height) { graphics.fillRect(x, y, width, height); } public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { graphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight); } public Color getBackground() { return graphics.getBackground(); } public Shape getClip() { return graphics.getClip(); } public Rectangle getClipBounds() { return graphics.getClipBounds(); } public Rectangle getClipBounds(Rectangle r) { return graphics.getClipBounds(r); } public Rectangle getClipRect() { return graphics.getClipRect(); } public Composite getComposite() { return graphics.getComposite(); } public GraphicsConfiguration getDeviceConfiguration() { return graphics.getDeviceConfiguration(); } public FontMetrics getFontMetrics() { return graphics.getFontMetrics(); } public FontMetrics getFontMetrics(Font f) { return graphics.getFontMetrics(f); } public FontRenderContext getFontRenderContext() { return graphics.getFontRenderContext(); } public Object getRenderingHint(Key hintKey) { return graphics.getRenderingHint(hintKey); } public RenderingHints getRenderingHints() { return graphics.getRenderingHints(); } public AffineTransform getTransform() { return graphics.getTransform(); } public int hashCode() { return graphics.hashCode(); } public boolean hit(Rectangle rect, Shape s, boolean onStroke) { return graphics.hit(rect, s, onStroke); } public boolean hitClip(int x, int y, int width, int height) { return graphics.hitClip(x, y, width, height); } public void rotate(double theta) { graphics.rotate(theta); } public void rotate(double theta, double x, double y) { graphics.rotate(theta, x, y); } public void scale(double sx, double sy) { graphics.scale(sx, sy); } public void setBackground(Color color) { graphics.setBackground(color); } public void setClip(int x, int y, int width, int height) { graphics.setClip(x, y, width, height); } public void setClip(Shape clip) { graphics.setClip(clip); } public void setComposite(Composite comp) { graphics.setComposite(comp); } public void setRenderingHint(Key hintKey, Object hintValue) { graphics.setRenderingHint(hintKey, hintValue); } public void setRenderingHints(Map hints) { graphics.setRenderingHints(hints); } public void setTransform(AffineTransform Tx) { graphics.setTransform(Tx); } public void shear(double shx, double shy) { graphics.shear(shx, shy); } public String toString() { return graphics.toString(); } public void transform(AffineTransform Tx) { graphics.transform(Tx); } public void translate(double tx, double ty) { graphics.translate(tx, ty); } public void translate(int x, int y) { graphics.translate(x, y); } } proguard4.8/src/proguard/gui/splash/ConstantFont.java0000644000175000017500000000242711736333525021551 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This VariableFont is constant over time. * * @author Eric Lafortune */ public class ConstantFont implements VariableFont { private final Font value; public ConstantFont(Font value) { this.value = value; } // Implementation for VariableFont. public Font getFont(long time) { return value; } } proguard4.8/src/proguard/gui/splash/SplashPanel.java0000644000175000017500000001561611736333525021347 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import proguard.gui.SwingUtil; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.lang.reflect.InvocationTargetException; /** * This JPanel renders an animated Sprite. * * @author Eric Lafortune */ public class SplashPanel extends JPanel { private final MyAnimator animator = new MyAnimator(); private final MyRepainter repainter = new MyRepainter(); private final Sprite sprite; private final double sleepFactor; private long startTime = Long.MAX_VALUE; private final long stopTime; private volatile Thread animationThread; /** * Creates a new SplashPanel with the given Sprite, which will be animated * indefinitely. * @param sprite the Sprite that will be animated. * @param processorLoad the fraction of processing time to be spend on * animating the Sprite (between 0 and 1). */ public SplashPanel(Sprite sprite, double processorLoad) { this(sprite, processorLoad, (long)Integer.MAX_VALUE); } /** * Creates a new SplashPanel with the given Sprite, which will be animated * for a limited period of time. * @param sprite the Sprite that will be animated. * @param processorLoad the fraction of processing time to be spend on * animating the Sprite (between 0 and 1). * @param stopTime the number of milliseconds after which the * animation will be stopped automatically. */ public SplashPanel(Sprite sprite, double processorLoad, long stopTime) { this.sprite = sprite; this.sleepFactor = (1.0-processorLoad) / processorLoad; this.stopTime = stopTime; // Restart the animation on a mouse click. addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { SplashPanel.this.start(); } }); } /** * Starts the animation. */ public void start() { // Go to the beginning of the animation. startTime = System.currentTimeMillis(); // Make sure we have an animation thread running. if (animationThread == null) { animationThread = new Thread(animator); animationThread.start(); } } /** * Stops the animation. */ public void stop() { // Go to the end of the animation. startTime = 0L; // Let the animation thread stop itself. animationThread = null; // Repaint the SplashPanel one last time. try { SwingUtil.invokeAndWait(repainter); } catch (InterruptedException ex) { // Nothing. } catch (InvocationTargetException ex) { // Nothing. } } // Implementation for JPanel. public void paintComponent(Graphics graphics) { super.paintComponent(graphics); sprite.paint(graphics, System.currentTimeMillis() - startTime); } /** * This Runnable makes sure its SplashPanel gets repainted regularly, * depending on the targeted processor load. */ private class MyAnimator implements Runnable { public void run() { try { while (animationThread != null) { // Check if we should stop the animation. long time = System.currentTimeMillis(); if (time > startTime + stopTime) { animationThread = null; } // Do a repaint and time it. SwingUtil.invokeAndWait(repainter); // Sleep for a proportional while. long repaintTime = System.currentTimeMillis() - time; long sleepTime = (long)(sleepFactor * repaintTime); if (sleepTime < 10L) { sleepTime = 10L; } Thread.sleep(sleepTime); } } catch (InterruptedException ex) { // Nothing. } catch (InvocationTargetException ex) { // Nothing. } } } /** * This Runnable repaints its SplashPanel. */ private class MyRepainter implements Runnable { public void run() { SplashPanel.this.repaint(); } } /** * A main method for testing the splash panel. */ public static void main(String[] args) { JFrame frame = new JFrame(); frame.setTitle("Animation"); frame.setSize(800, 600); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = frame.getSize(); frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); Sprite sprite = new ClipSprite( new ConstantColor(Color.white), new ConstantColor(Color.lightGray), new CircleSprite(true, new LinearInt(200, 600, new SineTiming(2345L, 0L)), new LinearInt(200, 400, new SineTiming(3210L, 0L)), new ConstantInt(150)), new ColorSprite(new ConstantColor(Color.gray), new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 90)), new TextSprite(new ConstantString("ProGuard"), new ConstantInt(200), new ConstantInt(300))))); SplashPanel panel = new SplashPanel(sprite, 0.5); panel.setBackground(Color.white); frame.getContentPane().add(panel); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); panel.start(); } } proguard4.8/src/proguard/gui/splash/Sprite.java0000644000175000017500000000255411736333525020400 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This interface describes objects that can paint themselves, possibly varying * as a function of time. * * @author Eric Lafortune */ public interface Sprite { /** * Paints the object. * * @param graphics the Graphics to paint on. * @param time the time since the start of the animation, expressed in * milliseconds. */ public void paint(Graphics graphics, long time); } proguard4.8/src/proguard/gui/splash/LinearInt.java0000644000175000017500000000334611736333525021017 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This VariableColor varies linearly with respect to its Timing. * * @author Eric Lafortune */ public class LinearInt implements VariableInt { private final int fromValue; private final int toValue; private final Timing timing; /** * Creates a new LinearInt. * @param fromValue the value that corresponds to a timing of 0. * @param toValue the value that corresponds to a timing of 1. * @param timing the applied timing. */ public LinearInt(int fromValue, int toValue, Timing timing) { this.fromValue = fromValue; this.toValue = toValue; this.timing = timing; } // Implementation for VariableInt. public int getInt(long time) { return (int) (fromValue + timing.getTiming(time) * (toValue - fromValue)); } } proguard4.8/src/proguard/gui/splash/ShadowedSprite.java0000644000175000017500000000701311736333525022052 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite adds a drop shadow to another Sprite. * * @author Eric Lafortune */ public class ShadowedSprite implements Sprite { private final VariableInt xOffset; private final VariableInt yOffset; private final VariableDouble alpha; private final VariableInt blur; private final Sprite sprite; private float cachedAlpha = -1.0f; private Color cachedColor; /** * Creates a new ShadowedSprite. * @param xOffset the variable x-offset of the shadow, relative to the sprite itself. * @param yOffset the variable y-offset of the shadow, relative to the sprite itself. * @param alpha the variable darkness of the shadow (between 0 and 1). * @param blur the variable blur of the shadow (0 for sharp shadows, 1 or * more for increasingly blurry shadows). * @param sprite the Sprite to be painted with its shadow. */ public ShadowedSprite(VariableInt xOffset, VariableInt yOffset, VariableDouble alpha, VariableInt blur, Sprite sprite) { this.xOffset = xOffset; this.yOffset = yOffset; this.alpha = alpha; this.blur = blur; this.sprite = sprite; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { double l = alpha.getDouble(time); int b = blur.getInt(time) + 1; float a = 1.0f - (float)Math.pow(1.0 - l, 1.0/(b*b)); if (a != cachedAlpha) { cachedAlpha = a; cachedColor = new Color(0f, 0f, 0f, a); } // Set up the shadow graphics. //OverrideGraphics2D g = new OverrideGraphics2D((Graphics2D)graphics); //g.setOverrideColor(cachedColor); // Set the shadow color. Color actualColor = graphics.getColor(); graphics.setColor(cachedColor); int xo = xOffset.getInt(time) - b/2; int yo = yOffset.getInt(time) - b/2; // Draw the sprite's shadow. for (int x = 0; x < b; x++) { for (int y = 0; y < b; y++) { int xt = xo + x; int yt = yo + y; graphics.translate(xt, yt); sprite.paint(graphics, time); graphics.translate(-xt, -yt); } } // Restore the actual sprite color. graphics.setColor(actualColor); // Draw the sprite itself in the ordinary graphics. sprite.paint(graphics, time); } } proguard4.8/src/proguard/gui/splash/LinearDouble.java0000644000175000017500000000337211736333525021476 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This VariableDouble varies linearly with respect to its Timing. * * @author Eric Lafortune */ public class LinearDouble implements VariableDouble { private final double fromValue; private final double toValue; private final Timing timing; /** * Creates a new LinearDouble. * @param fromValue the value that corresponds to a timing of 0. * @param toValue the value that corresponds to a timing of 1. * @param timing the applied timing. */ public LinearDouble(double fromValue, double toValue, Timing timing) { this.fromValue = fromValue; this.toValue = toValue; this.timing = timing; } // Implementation for VariableDouble. public double getDouble(long time) { return fromValue + timing.getTiming(time) * (toValue - fromValue); } } proguard4.8/src/proguard/gui/splash/VariableColor.java0000644000175000017500000000222511736333525021651 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This interface represents a Color that varies with time. * * @author Eric Lafortune */ interface VariableColor { /** * Returns the Color for the given time. */ public Color getColor(long time); } proguard4.8/src/proguard/gui/splash/SawToothTiming.java0000644000175000017500000000323111736333525022043 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This Timing ramps up linearly from 0 to 1 in a given repeated time interval. * * @author Eric Lafortune */ public class SawToothTiming implements Timing { private final long period; private final long phase; /** * Creates a new SawToothTiming. * @param period the time period for a full cycle. * @param phase the phase of the cycle, which is added to the actual time. */ public SawToothTiming(long period, long phase) { this.period = period; this.phase = phase; } // Implementation for Timing. public double getTiming(long time) { // Compute the translated and scaled saw-tooth function. return (double)((time + phase) % period) / (double)period; } } proguard4.8/src/proguard/gui/splash/ConstantTiming.java0000644000175000017500000000300511736333525022063 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This Timing is constant over time. * * @author Eric Lafortune */ public class ConstantTiming implements Timing { private final double timing; /** * Creates a new ConstantTiming with a value of 0. */ public ConstantTiming() { this(0.0); } /** * Creates a new ConstantTiming with a given value. * @param timing the constant value of the timing. */ public ConstantTiming(double timing) { this.timing = timing; } // Implementation for Timing. public double getTiming(long time) { return timing; } } proguard4.8/src/proguard/gui/splash/ClipSprite.java0000644000175000017500000000561011736333525021204 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite encapsulates another Sprite, which is clipped by a clip Sprite. * * @author Eric Lafortune */ public class ClipSprite implements Sprite { private final VariableColor insideClipColor; private final VariableColor outsideClipColor; private final Sprite clipSprite; private final Sprite sprite; /** * Creates a new ClipSprite. * @param insideClipColor the background color inside the clip sprite. * @param outsideClipColor the background color outside the clip sprite. * @param clipSprite the clip Sprite. * @param sprite the clipped Sprite. */ public ClipSprite(VariableColor insideClipColor, VariableColor outsideClipColor, Sprite clipSprite, Sprite sprite) { this.insideClipColor = insideClipColor; this.outsideClipColor = outsideClipColor; this.clipSprite = clipSprite; this.sprite = sprite; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { // Clear the background. Color outsideColor = outsideClipColor.getColor(time); Rectangle clip = graphics.getClipBounds(); graphics.setPaintMode(); graphics.setColor(outsideColor); graphics.fillRect(0, 0, clip.width, clip.height); // Draw the sprite in XOR mode. OverrideGraphics2D g = new OverrideGraphics2D((Graphics2D)graphics); Color insideColor = insideClipColor.getColor(time); g.setOverrideXORMode(insideColor); sprite.paint(g, time); g.setOverrideXORMode(null); // Clear the clip area. g.setOverrideColor(insideColor); clipSprite.paint(g, time); g.setOverrideColor(null); // Draw the sprite in XOR mode. g.setOverrideXORMode(insideColor); sprite.paint(g, time); g.setOverrideXORMode(null); } } proguard4.8/src/proguard/gui/splash/SmoothTiming.java0000644000175000017500000000364211736333525021552 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This Timing ramps up smoothly from 0 to 1 in a given time interval. * * @author Eric Lafortune */ public class SmoothTiming implements Timing { private final long fromTime; private final long toTime; /** * Creates a new SmoothTiming. * @param fromTime the time at which the timing starts ramping up from 0. * @param toTime the time at which the timing stops ramping up at 1. */ public SmoothTiming(long fromTime, long toTime) { this.fromTime = fromTime; this.toTime = toTime; } // Implementation for Timing. public double getTiming(long time) { if (time <= fromTime) { return 0.0; } if (time >= toTime) { return 1.0; } // Compute the linear interpolation. double timing = (double) (time - fromTime) / (double) (toTime - fromTime); // Smooth the interpolation at the ends. return timing * timing * (3.0 - 2.0 * timing); } } proguard4.8/src/proguard/gui/splash/VariableFont.java0000644000175000017500000000222011736333525021474 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This interface represents a Font that varies with time. * * @author Eric Lafortune */ interface VariableFont { /** * Returns the Font for the given time. */ public Font getFont(long time); } proguard4.8/src/proguard/gui/splash/Timing.java0000644000175000017500000000220711736333525020354 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This interface maps a time to a normalized timing between 0 and 1. * * @author Eric Lafortune */ interface Timing { /** * Returns the timing for the given time. */ public double getTiming(long time); } proguard4.8/src/proguard/gui/splash/VariableSizeFont.java0000644000175000017500000000342611736333525022340 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This VariableFont varies in size with respect to its Timing. * * @author Eric Lafortune */ public class VariableSizeFont implements VariableFont { private final Font font; private final VariableDouble size; private float cachedSize = -1.0f; private Font cachedFont; /** * Creates a new VariableSizeFont * @param font the base font. * @param size the variable size of the font. */ public VariableSizeFont(Font font, VariableDouble size) { this.font = font; this.size = size; } // Implementation for VariableFont. public Font getFont(long time) { float s = (float)size.getDouble(time); if (s != cachedSize) { cachedSize = s; cachedFont = font.deriveFont((float)s); } return cachedFont; } } proguard4.8/src/proguard/gui/splash/ConstantString.java0000644000175000017500000000256311736333525022112 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This VariableString is constant over time. * * @author Eric Lafortune */ public class ConstantString implements VariableString { private final String value; /** * Creates a new ConstantString. * @param value the constant value. */ public ConstantString(String value) { this.value = value; } // Implementation for VariableString. public String getString(long time) { return value; } } proguard4.8/src/proguard/gui/splash/ConstantDouble.java0000644000175000017500000000256311736333525022056 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This VariableDouble is constant over time. * * @author Eric Lafortune */ public class ConstantDouble implements VariableDouble { private final double value; /** * Creates a new ConstantDouble. * @param value the constant value. */ public ConstantDouble(double value) { this.value = value; } // Implementation for VariableDouble. public double getDouble(long time) { return value; } } proguard4.8/src/proguard/gui/splash/CompositeSprite.java0000644000175000017500000000323011736333525022253 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite is the composition of a list of Sprite objects. * * @author Eric Lafortune */ public class CompositeSprite implements Sprite { private final Sprite[] sprites; /** * Creates a new CompositeSprite. * @param sprites the array of Sprite objects to which the painting will * be delegated, starting with the first element. */ public CompositeSprite(Sprite[] sprites) { this.sprites = sprites; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { // Draw the sprites. for (int index = 0; index < sprites.length; index++) { sprites[index].paint(graphics, time); } } } proguard4.8/src/proguard/gui/splash/LinearTiming.java0000644000175000017500000000340511736333525021510 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This Timing ramps up linearly from 0 to 1 in a given time interval. * * @author Eric Lafortune */ public class LinearTiming implements Timing { private final long fromTime; private final long toTime; /** * Creates a new LinearTiming. * @param fromTime the time at which the timing starts ramping up from 0. * @param toTime the time at which the timing stops ramping up at 1. */ public LinearTiming(long fromTime, long toTime) { this.fromTime = fromTime; this.toTime = toTime; } // Implementation for Timing. public double getTiming(long time) { // Compute the clamped linear interpolation. return time <= fromTime ? 0.0 : time >= toTime ? 1.0 : (double)(time - fromTime) / (double)(toTime - fromTime); } } proguard4.8/src/proguard/gui/splash/FontSprite.java0000644000175000017500000000355311736333525021227 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite sets the font for another given sprite. * * @author Eric Lafortune */ public class FontSprite implements Sprite { private final VariableFont font; private final Sprite sprite; /** * Creates a new FontSprite. * @param font the variable Font of the given sprite. * @param sprite the sprite that will be provided of a font and painted. */ public FontSprite(VariableFont font, Sprite sprite) { this.font = font; this.sprite = sprite; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { // Save the old font. Font oldFont = graphics.getFont(); // Set the new font. graphics.setFont(font.getFont(time)); // Paint the actual sprite. sprite.paint(graphics, time); // Restore the old font. graphics.setFont(oldFont); } } proguard4.8/src/proguard/gui/splash/BufferedSprite.java0000644000175000017500000001214011736333525022033 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; import java.awt.image.BufferedImage; /** * This Sprite encapsulates another Sprite, which is then buffered in an Image. * * @author Eric Lafortune */ public class BufferedSprite implements Sprite { private final int bufferX; private final int bufferY; private final Image bufferImage; private final Color backgroundColor; private final Sprite sprite; private final VariableInt x; private final VariableInt y; private long cachedTime = -1; /** * Creates a new BufferedSprite with an ABGR image. * @param bufferX the x offset of the buffer image. * @param bufferY the y offset of the buffer image. * @param width the width of the buffer image. * @param height the height of the buffer image. * @param sprite the Sprite that is painted in the buffer. * @param x the variable x ordinate of the image buffer for painting. * @param y the variable y ordinate of the image buffer for painting. * */ public BufferedSprite(int bufferX, int bufferY, int width, int height, Sprite sprite, VariableInt x, VariableInt y) { this(bufferX, bufferY, new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR), null, sprite, x, y); } /** * Creates a new BufferedSprite with the given image. * @param bufferX the x offset of the buffer image. * @param bufferY the y offset of the buffer image. * @param bufferImage the Image that is used for the buffering. * @param backgroundColor the background color that is used for the buffer. * @param sprite the Sprite that is painted in the buffer. * @param x the variable x ordinate of the image buffer for * painting. * @param y the variable y ordinate of the image buffer for * painting. */ public BufferedSprite(int bufferX, int bufferY, Image bufferImage, Color backgroundColor, Sprite sprite, VariableInt x, VariableInt y) { this.bufferX = bufferX; this.bufferY = bufferY; this.bufferImage = bufferImage; this.backgroundColor = backgroundColor; this.sprite = sprite; this.x = x; this.y = y; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { if (time != cachedTime) { Graphics bufferGraphics = bufferImage.getGraphics(); // Clear the background. if (backgroundColor != null) { Graphics2D bufferGraphics2D = (Graphics2D)bufferGraphics; bufferGraphics2D.setComposite(AlphaComposite.Clear); bufferGraphics.fillRect(0, 0, bufferImage.getWidth(null), bufferImage.getHeight(null)); bufferGraphics2D.setComposite(AlphaComposite.Src); } else { bufferGraphics.setColor(backgroundColor); bufferGraphics.fillRect(0, 0, bufferImage.getWidth(null), bufferImage.getHeight(null)); } // Set up the buffer graphics. bufferGraphics.translate(-bufferX, -bufferY); bufferGraphics.setColor(graphics.getColor()); bufferGraphics.setFont(graphics.getFont()); // Draw the sprite. sprite.paint(bufferGraphics, time); bufferGraphics.dispose(); cachedTime = time; } // Draw the buffer image. graphics.drawImage(bufferImage, bufferX + x.getInt(time), bufferY + y.getInt(time), null); } } proguard4.8/src/proguard/gui/splash/VariableDouble.java0000644000175000017500000000220611736333525022004 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This interface represents a double that varies with time. * * @author Eric Lafortune */ interface VariableDouble { /** * Returns the double for the given time. */ public double getDouble(long time); } proguard4.8/src/proguard/gui/splash/VariableString.java0000644000175000017500000000220611736333525022040 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This interface represents a String that varies with time. * * @author Eric Lafortune */ interface VariableString { /** * Returns the String for the given time. */ public String getString(long time); } proguard4.8/src/proguard/gui/splash/ConstantColor.java0000644000175000017500000000257511736333525021725 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This VariableColor is constant over time. * * @author Eric Lafortune */ public class ConstantColor implements VariableColor { private final Color value; /** * Creates a new ConstantColor. * @param value the constant value. */ public ConstantColor(Color value) { this.value = value; } // Implementation for VariableColor. public Color getColor(long time) { return value; } } proguard4.8/src/proguard/gui/splash/ColorSprite.java0000644000175000017500000000355411736333525021400 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite colors another given sprite. * * @author Eric Lafortune */ public class ColorSprite implements Sprite { private final VariableColor color; private final Sprite sprite; /** * Creates a new ColorSprite. * @param color the variable color of the given sprite. * @param sprite the sprite that will be colored and painted. */ public ColorSprite(VariableColor color, Sprite sprite) { this.color = color; this.sprite = sprite; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { // Save the old color. Color oldColor = graphics.getColor(); // Set the new color. graphics.setColor(color.getColor(time)); // Paint the actual sprite. sprite.paint(graphics, time); // Restore the old color. graphics.setColor(oldColor); } } proguard4.8/src/proguard/gui/splash/CircleSprite.java0000644000175000017500000000434011736333525021515 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite represents an animated circle. It can optionally be filled. * * @author Eric Lafortune */ public class CircleSprite implements Sprite { private final boolean filled; private final VariableInt x; private final VariableInt y; private final VariableInt radius; /** * Creates a new CircleSprite. * @param filled specifies whether the rectangle should be filled. * @param x the variable x-coordinate of the center of the circle. * @param y the variable y-coordinate of the center of the circle. * @param radius the variable radius of the circle. */ public CircleSprite(boolean filled, VariableInt x, VariableInt y, VariableInt radius) { this.filled = filled; this.x = x; this.y = y; this.radius = radius; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { int xt = x.getInt(time); int yt = y.getInt(time); int r = radius.getInt(time); if (filled) { graphics.fillOval(xt - r, yt - r, 2 * r, 2 * r); } else { graphics.drawOval(xt - r, yt - r, 2 * r, 2 * r); } } } proguard4.8/src/proguard/gui/splash/LinearColor.java0000644000175000017500000000453511736333525021344 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This VariableColor varies linearly with respect to its Timing. * * @author Eric Lafortune */ public class LinearColor implements VariableColor { private final Color fromValue; private final Color toValue; private final Timing timing; private double cachedTiming = -1.0; private Color cachedColor; /** * Creates a new LinearColor. * @param fromValue the value that corresponds to a timing of 0. * @param toValue the value that corresponds to a timing of 1. * @param timing the applied timing. */ public LinearColor(Color fromValue, Color toValue, Timing timing) { this.fromValue = fromValue; this.toValue = toValue; this.timing = timing; } // Implementation for VariableColor. public Color getColor(long time) { double t = timing.getTiming(time); if (t != cachedTiming) { cachedTiming = t; cachedColor = t == 0.0 ? fromValue : t == 1.0 ? toValue : new Color((int)(fromValue.getRed() + t * (toValue.getRed() - fromValue.getRed())), (int)(fromValue.getGreen() + t * (toValue.getGreen() - fromValue.getGreen())), (int)(fromValue.getBlue() + t * (toValue.getBlue() - fromValue.getBlue()))); } return cachedColor; } } proguard4.8/src/proguard/gui/splash/ConstantInt.java0000644000175000017500000000252511736333525021374 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This VariableInt is constant over time. * * @author Eric Lafortune */ public class ConstantInt implements VariableInt { private final int value; /** * Creates a new ConstantInt. * @param value the constant value. */ public ConstantInt(int value) { this.value = value; } // Implementation for VariableInt. public int getInt(long time) { return value; } } proguard4.8/src/proguard/gui/splash/VariableInt.java0000644000175000017500000000220011736333525021316 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This interface represents an integer that varies with time. * * @author Eric Lafortune */ interface VariableInt { /** * Returns the integer for the given time. */ public int getInt(long time); } proguard4.8/src/proguard/gui/splash/ImageSprite.java0000644000175000017500000000465611736333525021350 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite represents an animated image. * * @author Eric Lafortune */ public class ImageSprite implements Sprite { private final Image image; private final VariableInt x; private final VariableInt y; private final VariableDouble scaleX; private final VariableDouble scaleY; /** * Creates a new ImageSprite. * @param image the Image to be painted. * @param x the variable x-coordinate of the upper-left corner of the image. * @param y the variable y-coordinate of the upper-left corner of the image. * @param scaleX the variable x-scale of the image. * @param scaleY the variable y-scale of the image. */ public ImageSprite(Image image, VariableInt x, VariableInt y, VariableDouble scaleX, VariableDouble scaleY) { this.image = image; this.x = x; this.y = y; this.scaleX = scaleX; this.scaleY = scaleY; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { int xt = x.getInt(time); int yt = y.getInt(time); double scale_x = scaleX.getDouble(time); double scale_y = scaleY.getDouble(time); int width = (int)(image.getWidth(null) * scale_x); int height = (int)(image.getHeight(null) * scale_y); graphics.drawImage(image, xt, yt, width, height, null); } } proguard4.8/src/proguard/gui/splash/SineTiming.java0000644000175000017500000000320411736333525021171 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; /** * This Timing varies between 0 and 1, as a sine wave over time. * * @author Eric Lafortune */ public class SineTiming implements Timing { private final long period; private final long phase; /** * Creates a new SineTiming. * @param period the time period for a full cycle. * @param phase the phase of the cycle, which is added to the actual time. */ public SineTiming(long period, long phase) { this.period = period; this.phase = phase; } // Implementation for Timing. public double getTiming(long time) { // Compute the translated and scaled sine function. return 0.5 + 0.5 * Math.sin(2.0 * Math.PI * (time + phase) / period); } } proguard4.8/src/proguard/gui/splash/TextSprite.java0000644000175000017500000000546211736333525021246 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui.splash; import java.awt.*; /** * This Sprite represents a text. * * @author Eric Lafortune */ public class TextSprite implements Sprite { private final VariableString[] text; private final VariableInt spacing; private final VariableInt x; private final VariableInt y; /** * Creates a new TextSprite containing a single line of text. * @param text the variable text string. * @param x the variable x-coordinate of the lower-left corner of the text. * @param y the variable y-coordinate of the lower-left corner of the text. */ public TextSprite(VariableString text, VariableInt x, VariableInt y) { this(new VariableString[] { text }, new ConstantInt(0), x, y); } /** * Creates a new TextSprite containing a multiple lines of text. * @param text the variable text strings. * @param spacing the variable spacing between the lines of text. * @param x the variable x-coordinate of the lower-left corner of the * first line of text. * @param y the variable y-coordinate of the lower-left corner of the * first line of text. */ public TextSprite(VariableString[] text, VariableInt spacing, VariableInt x, VariableInt y) { this.text = text; this.spacing = spacing; this.x = x; this.y = y; } // Implementation for Sprite. public void paint(Graphics graphics, long time) { int xt = x.getInt(time); int yt = y.getInt(time); int spacingt = spacing.getInt(time); for (int index = 0; index < text.length; index++) { graphics.drawString(text[index].getString(time), xt, yt + index * spacingt); } } } proguard4.8/src/proguard/gui/MANIFEST.MF0000644000175000017500000000014011163773611016412 0ustar ericericManifest-Version: 1.0 Main-Class: proguard.gui.ProGuardGUI Class-Path: proguard.jar retrace.jar proguard4.8/src/proguard/gui/vtitle.png0000644000175000017500000005542111170666104017005 0ustar ericericPNG  IHDRHޫsRGB IDATx}ɒ82fzILZh%-Izꪮ;I@`2H`v+ ӏ I} q휏gx;;1?qkq0%{p|60g7Qqag$w̅Um7QѾPX mT ;pfT-<%>",f;_lBP^l>ⓌҌSЬf$o퉛VL*ڋ8O3Ό+%ȵ5)O>a)}RZ<#Yڋ^իZ{*}Fiw2(`o.x}ϒLG>Y'uVԔJp^.CL*^Ef}%|-l>1v%qJ#3S3MM13\ kF8B!Ar63(cib)*Vwq>+4U|QhqJBЌ X rC I\.V-aE3 )ԬUgeإ#l)>K9=Ka+Crq#DXN j%(5wdT)t,{q&/V'LrP}eh-RK[hSXv(hJaqo~]6Wõ w"ИWjbs'W5 WG,lС S6oLSf0 Ne>Kh5vA tN fJ{mKB:h?u# SM)>({f9YC~bSAqqz?#;R>`^y|sKN Jq L PUIh ߥA:)!eN΅'KBi@iHppNΚef^6gna^*gjpSGec:F:F7rhcMN1*~vNK3]:p oW+F$eKaaM4Ug!#lUca{<"х7t#Qft2P01>h̐#AP7#|%jxkWowp;'}V)B6E\ wR{IњXڜNiR! ϼ:4BǜzحҧFEKѐe%U>) Jʝ/21>ߟUS&ڢMs㕚$2+W{HX XX [j)?^K;RX": 8ЙFmdE0S5D_qMLY]E͘guNa(GO^C^u1Ijڋ@|S$m–9Dv}8Oބ SjZLBA14LUfQ3K1bb5=ͮp)KtYg&4E RФV܋(ʂ*e4 ͓s#5fHCj|F.&:bWqeƒ0q>Ũya3k|V VzdE~.,&K4K;|>$9-|B^zg''sXu`{sG5 I/ 95_4-7YO 9Jd]J}Ni}ڇ 5eZ fqjjLڌ拵f*,X1FR2pt&2*07bw{xm5] U,I mT"lQk(r76Csz܆;Ka5 *ʛwYL{šq\%V8_Ŧ 蟕4ԛK]$q%R-2 X6<&SP/5xJa6R8*ɩOBlaD`3Cgj S7M>O9P cvKe!gìܾ֞^ܦء:/?(}O'kB3$iB3VFxsR_Y!8f7/)_l&{kTLz?ĕl4O~5Ƒ$RWS9 Y-n>c#$Upt!m{[Bi 84\ZɝJՔmVyn\=1>(^y ԍ~p#o 0)4?q+ѻYN|pVi[&pߖ-Y0x^(I XbX*gtR~؊r\ /i#.qA*L.D= = J/ncWZ4UWD W)Ҧ8ՁPE´ań\m`gkAK߽LɋLf<Hn)Ԭ2CnNF _|-4XE ` lGikjDL:qߒXW~-&֝3[G:qA.X4kq'fQS|hڊ .)C X9|%C:-1K)= lju Q1w('ՅflPb>%w\`>Wph,gje"K b2 VCVtxhkaPQ쇑V!&>f[^i_QZڬL&j7 (͍(M%#BM儣dҥ,ۅ}V0Hߗ%27oEAlCuVXa' L#~Kf&P_oAJڡB*5wx)6 Ө|,4_X +-tGysM엣8В>wwk8fiFiF&3`r54A2ʫZzb~Ϙ]sP0ixٚ'\eaV9^L۪S/TJᄍ7RWB *4%|}ϒL:VݬK۱C۰Zc|vӵI<םr&峴iځ23 /F WC.QD[,$7y梶4ff#wwZj.m^WMGM)gS%J[<5A&YV//=V4Ш˿an >?,̶,CPhFZ.Flʲ(aiϵԖD\2*!$w+y>*ĆV`@XR0)W~p'eVڲqZf]8e8ʡe.8^\[Ľuȟ_ J3܉@cZmaSs1k%PC{|f[p<sj8;{ Up*YqZY:'gvapVny !aK?=֛# S͂-9({f9YC~bSAqq*4RJ,|#W74M.MlK|6/=XkKlK捛 NF}4R4>^j]Qb,mҭܸ֫\'6m-.J *uL#IM6*3t23ȺjM~uZ;D[vORm:FB5㱴9ڦ2>/1vi\A킢hHPڲ*BW%h[l/|u!kinv|xk% 䞁c2;+!vlk*)@(6 -B3@gJiL]"}362}gk t>˨sR CP&PEcfdl|S4=-s$jL%ph?vԴ2DL3c:RsibQ'ګ̌f8bĚA|E8kz]R fˡgN04E R$mjS<7-H'ɓŵ\4rrtiVGx/;ΪYK|cblX Ok>c6•litWi\?qꓐ0!X8Œ g,3} 2Cv@s|u|K(mӖI@]֚*YT1&ǣ!C+X]>`{$MW3G߿|b8{8z73˩rG+U󖻾 FeK$L$39$+x ʛU31A._dTG;?_Q+?5m%::hY#"L?O|dg@O˱%:cՕ5+UJ)Nu .ehѪ0jX15ױC.sZPwo#Eb7-s>ۺj 5̐۷'1>F{>5 Vj%47X,[Qښ@91m¹ԒXW~-&֝3[G:qA.X4kq'fQS|hڊ .)C X9|%C:-1K)= lju Q1w('ՅflPb>%w\`>Wph,gje"K b2 VCVtxhkaPQ쇑V!&>f[^i_QZڬL&j7 (͍(M%#BM儣dҥ,ۅ}V0Hߗ%27oEAlCuVXa' L#~Kf&P_oAJڡB*5wx)6 Ө|,4_X +-tGysM엣8В>wwk8fiFiF&3`r54A2ʫZzb~Ϙ]sP0ixٚ'\eaV9^L۪S/TJᄍ7RWB *4%|}ϒL:VݬK۱C۰Zc|vӵI<םr&峴iځ23 /F WC.QD[,$7y梶4ff#wwZj.m^WMGM)gS%J[<5A&YV//=V4Ш˿an >?,̶,CPhFZ.Flʲ(aiϵԖD\2*!$w+y>*ĆV`@XR0)W~p'eVڲqZf]8e8ʡe.8^\[Ľuȟ_ J3܉@cZmaSs1k%PC{|f[p<sj8;{ Up*YqZY:'gvapVny !aK?=֛# S͂-9({f9YC~bSAqq*4RJ,|#W74M.MlK|6/=XkKlK捛 NF}4R4>^j]Qb,mҭܸ֫\'6m-.J *uL#IM6*3t23ȺjM~uZ;D[vORm:FB5㱴9ڦ2>/1vi\A킢hHPڲ*BW%h[l/|u!kinv|xk% 䞁c2;+!vlk*)@(6 -B3@gJiL]"}362}gk t>˨sR CP&PEcfdl|S4=-s$jL%ph?vԴ2DL3c:RsibQ'ګ̌f8bĚA|E8kz]R fˡgN04E R$mjS<7-H'ɓŵ\4rrtiVGx/;ΪYK|cblX Ok>c6•litWi\?qꓐ0!X8Œ g,3} 2Cv@s|u|K(mӖI@]֚*YT1&ǣ!C+X]>`{$MW3G߿|b8{8z73˩rG+U󖻾 FeK$L$39$+x ʛU31A._dTG;?_Q+?5m%::hY#"L?O|dg@O˱%:cՕ5+UJ)Nu .ehѪ0jX15ױC.sZPwo#Eb7-s>ۺj 5̐۷'1>F{>5 Vj%47X,[Qښ@91m¹ԒXW~-&֝3[G:qA.X4kq'fQS|hڊ .)C X9|%C:-1K)= lju Q1w('ՅflPb>%w\`>Wph,gje"K b2 VCVtxhkaPQ쇑V!&>f[^i_QZڬL&j7 (͍(M%#BM儣dҥ,ۅ}V0Hߗ%27oEAlCuVXa' L#~Kf&P_oAJڡB*5wx)6 Ө|,4_X +-tGysM엣8В>wwk8fiFiF&3`r54A2ʫ?fE IDATZzb~Ϙ]sP0ixٚ'\eaV9^L۪S/TJᄍ7RWB *4%|}ϒL:VݬK۱C۰Zc|vӵI<םr&峴iځ23 /F WC.QD[,$7y梶4ff#wwZj.m^WMGM)gS%J[<5A&YV//=V4Ш˿an >?,̶,CPhFZ.Flʲ(aiϵԖD\2*!$w+y>*ĆV`@XR0)W~p'eVڲqZf]8e8ʡe.8^\[Ľuȟ_ J3܉@cZmaSs1k%PC{|f[p<sj8;{ Up*YqZY:'gvapVny !aK?=֛# S͂-9({f9YC~bSAqq*4RJ,|#W74M.MlK|6/=XkKlK捛 NF}4R4>^j]Qb,mҭܸ֫\'6m-.J *uL#IM6*3t23ȺjM~uZ;D[vORm:FB5㱴9ڦ2>/1vi\A킢hHPڲ*BW%h[l/|u!kinv|xk% 䞁c2;+!vlk*)@(6 -B3@gJiL]"}362}gk t>˨sR CP&PEcfdl|S4=-s$jL%ph?vԴ2DL3c:RsibQ'ګ̌f8bĚA|E8kz]R fˡgN04E R$mjS<7-H'ɓŵ\4rrtiVGx/;ΪYK|cblX Ok>c6•litWi\?qꓐ0!X8Œ g,3} 2Cv@s|u|K(mӖI@]֚*YT1&ǣ!C+X]>`{$MW3G߿|b8{8z73˩rG+U󖻾 FeK$L$39$+x ʛU31A._dTG;?_Q+?5m%::hY#"L?O|dg@O˱%:cՕ5+UJ)Nu .ehѪ0jX15ױC.sZPwo#Eb7-s>ۺj 5̐۷'1>F{>5 Vj%47X,[Qښ@91m¹ԒXW~-&֝3[G:qA.X4kq'fQS|hڊ .)C X9|%C:-1K)= lju Q1w('ՅflPb>%w\`>Wph,gje"K b2 VCVtxhkaPQ쇑V!&>f[^i_QZڬL&j7 (͍(M%#BM儣dҥ,ۅ}V0Hߗ%27oEAlCuVXa' L#~Kf&P_oAJڡB*5wx)6 Ө|,4_X +-tGysM엣8В>wwk8fiFiF&3`r54A2ʫZzb~Ϙ]sP0ixٚ'\eaV9^L۪S/TJᄍ7RWB *4%|}ϒL:VݬK۱C۰Zc|vӵI<םr&峴iځ23 /F WC.QD[,$7y梶4ff#wwZj.m^WMGM)gS%J[<5A&YV//=V4Ш˿an >?,̶,CPhFZ.Flʲ(aiϵԖD\2*!$w+y>*ĆV`@XR0)W~p'eVڲqZf]8e8ʡe.8^\[Ľuȟ_ J3܉@cZmaSs1k%PC{|f[p<sj8;{ Up*YqZY:'gvapVny !aK?=֛# S͂-9({f9YC~bSAqq*431k&򛗱ߒAgR9=ZTQM.MlK|6^ >tQ ,jȍkJubORR;@ӇbZJִyꈂllU߸ɲ}ܧ+^l=KXʼVc|Cu|'Xնw"h8!Yo_S=ea7 / kT^p <(YFcYW '`G{8h'lfqEC K.>U & =R-7tXcp+'W`Ml=|@88\c Y~ZəNAoq >b;|+jC췸Ϩqt #2:luMHzI",}5zGV;h $Wx$ÕˮP禛n^S>+U\GNX|WhPkx hZTI/!:zFј7jQ#> x ~<\ͮ@F0K8}h?pG\alP5ꀷşq=~!bs'a ̘\XT 3K;K c[qBg{C5ⳌXs<#/g -[,{{|A{ @# O#}G, !S| Ag [%(Za 7h+,nq5Z#FP'xlF|UiWQrRB'wxGl8юSyo"Ao4tP6H5pgܡ~019 R@ & )^śr^5 8+NXZ,fZ6!' UrY\{|5n{'vVNtio'87->I!W4ǽA(zTdjSS7q9Nv8 :8lp7WޏhZ SxT Gb[QwȺB3g3Tz1~M\anr 5jYK[7 =^bgkz}XcTf$FMm)͊UXh;#.7ܢ 7ы ;4)WJNn=CL4¢<إ^{~4io@O 2Jks,B&uPhco8a7 d`zuOQFiof0?krxKtHOYvC`ngŖf?@DX!43'Z|lla;Xp (.?+i7In:l H|EoC,T‹tk 6:\VpufW XkR>`$pJPfnL@ř͆mdo"'8\.Qhr~Q8 õwW9t;~U/|G/d97sy48^BXAв"b *'\㈇~Gb8%E7D19W m-vp8HB3$iB3V\阃=L%/[x At<gU,sBc|=TV\YP_A{Mψ\mra ,jb5o6Mu8a- d `KcKCT7hRaDӹ{?}6=%m{㣴b%PiYo={< 9v8$t =_;Y'8aa =NDrW=^{;|ⶒ*ƿ,a[|vޛ$?úRX!ܸe hӻ7hD7ߢ )4?q+ч?pBx7|+z0D. Xov0yT}dkWc%#KI3vl /iMҩK+|+H5IR Ur}%+8K sòq~\aJ Fױq5+UC9A_LR*5ߵ*LVLxuo҂R{.x/[찅E3̱ؾ^BNjVEaQX)@#q_pM(釜mW8`q@u͌w5K3"ik3> ?X%;77"%thΥĺ2xd8hzW|gT¯{϶ϰ>sL.qA.X4O}{+|xCoJ>|4mE3ϊt7ͪ1(V$A(ii$vxokHGϩü1t3)WdnĄ|Yo*e\Z``a#N`'xLRvVޚxPxEäoeRӡ<޽Ɵ=Xcz\VXc/+(ȫ-q+-.7`7sL?hafZ^1SC!wzLr3Va+h{\PQŁ~'U: rq :L{ >N߇nH:lo |,@Ҋ7p;ԨG[[n/hqG.GynaYa5b'͠ϸj{<{-hqﳳ, PO/ oh` w/:xFgGT|ZGT*n}=<C] h%Bk68J׮,tGysGg}0* GT]jw&g}J,wʶA +'l=j+{S}3:Mʋ?ub~x! NhcQ l^'x,[}yxL3Zjp;x,m^,, ES1?أEu_(`*%-S*פ<តN`KC87gi9\9GV̯^}6\;waɠ@:M2'ZwK`-WJKg|rU7v6,<>B7iAn `n2}Lgi kW >j4*g~Ե,sG vlZS_d67_ӘiE}Sú U&j|QhqJL+%(W`3YOk2uZn(aiGkF<7Cf|-Io(4FX[cc3أͬ,l H;WRT̶,(}g௫Q&3~yG7Z9xr>t5}]"qɨL\6yhzlq j|UY8fZlal0b 6Cgd!s#mf*>6XWUZ'qw{j>D:/Ga4 o=*T'tN^ׅk#~5\+0ܘxO8`#3#5~gb/-la.aj>`?{3أB%BppZZ/o+Vz ~ >2VAk̐kZJeB=?Hn*ll5?O$8 p%7%CN rg\7\CV3QG;q{ܡ!N͐`-ݑEc|OiU?jmMm;?l_8Βc6f8gZH+whqxĥ$j(J;H!xyq(|ڇE eJڍEfTEѼ MPi*Jj ߥA%Mu2'_Uj_QTbhRڹR4>^j]Q bϴf=;l*pQ!+,qV\'6Jx\ K.ڵ8Z# ȲU|{SgZ{a\ex`'~7HZ*pW3>8X57\OXp-)Ö8*?+ӶʕZSx'@Eʔe.{yMU]重Pg4^Z> EƿOT$n$*/POxQq& $]#t{~IDAT23ȺjM̷kTfHS¨U;; /h[vO,;XGj7E5mKR֌jWn^=S%С9n!=Ҭ J[V^Zkf3vŻ*,nG7b-(뾽f%.m,DKTH|V+ uOpL) yƻx| y": 3 UP+E6߫;" K*\b?~z>P Wa]a~aE㤀|K|yJbqi˜ū4nDјKv5~kg®?|.Lr5(rZ= .y7xG| (u(|]fx)>! #ft0ۏJhq- Z`Ј532lj٩[X<nitTX '3'LON3٦2lՠtG‡ɍ>BӨ3Fh R,YaA-^p|<՞.xs-s͐*3ԆsV`*a-u2*P0>zg`hgG5O"d+_ N-<:XH#M#qSVj+YKiʹllAǾf6qs-, gn 5NM1&K.m%oPpy@-h'IE:5QaupPu,I`4hO\Uj%3W{Np0X%SoM5 qYWhy"Z=:lp ;xBu:oʞ]e滅ͰklgVXÉ4pٌ *TXd &ඔf*,ނf9GXGQJ[JNn=C6h'CpUi!n8W9šҖsV}#|.0Yӛ-qQ@`:4*AA;-jpET vk-e!=|6pbjcY8S8N+3, Gb"_c h_qtN Ҏ'.䠊3S9Eil:%%RMجk S=Tΰ̺4;u?6(imKϒY<%0 Yy: Xi%S/zuiM C 8)z~/xl m. I0?z:O9P c _po78ggl~ (KI%VkORr'lQMI?co{/=6O!G-,v|PiyqV"WCqR'\wc͈|&ISkA/ʼ} '|8y X ~m<d:VO0tFy6q2>a nNoS =x3hNLJCT7hƼsn+\duj&bvJp̀bJv@s|u|K]|LQlnAk>+RD tI|D /p7%ΥYToULԠ'D .#^y +:jRqD^^TgWAn ͏r3Lu8l陗? o*,?[E5>;&'3ѿ˄emْ5 9>y "ף[g<{t8)^cPlJ<^[xѠ;No {С'8YafejN~>˖š6rFˡC:TCg3 l3>v%c]{}%+8K v0hp[ҵqhjAp쥉!u&bxg׿ Ȭp)CViWÊ S;ʇzz}mdͿ}Tm6rSYed.Nc| `GOh3@q"KinYCߚ %lk\:p+6.[VEs[|5,Nd2L{8oVqԸ?q 'U: 2+6/-,1KwPfłڛ ͹W=TGhֻ ?86IBU(a_IJ(br7?} I4kp𣯰iE{SY/~ a\N`/<9f ͰBq|ik ;ȸ,n_{U_j}ۧtj8h~l<~H=gDE#~8\SMʋ?2/+g|g$</vڱ|­̈́f54ANn _~Vb3$㞏?i-ʗքk/65'\h%]:V=<(Ji zfK5) ',[e=ѽZ}f,-' WopӇ>ex{*}s( 68 LaWȠ@:M2'ZwK:>ys [|3>9}֪ui;vT9£dޟǩ=w4)h $#*l1-8/">}ݺ!w39f2}Lgi ޠ~ǜ7,!igZLyW$Ե,scN}I^k٦,~5Yl;R#nQSO4dIawf|o=j_  BOk2uZn(aigiFxPGV,aE3 VjbR0qw| ;I# ŘO_~ٶ0 uhh-ָ·%RʈkĦ,ˉ6M3w4*l<Ÿq_-2J4%ÝgXlnq͚ w8 %_3nVv7=n MA|mv +9"/T*8N\Ɍjc@TsC˶gM(hw;hamQׅk#~5\+p7ʷ'QS|B3|v`8=ϸjt:X2u~"ZZ/o+V p8fOj|fhvbEE@C3X^҂\4PnY I +~` gk\c/dҚ?p+V Nnc3?8r ~,K^Z] ߧL*]}C7?apBl; mS< T|1>K!ײ-*\&o7x/}fTQ 9{ԛU\ wR{IњX+\ﳘ1;a*aoJWO)% "pzرp&+ʇ/hHPڲAx:qYXG+PKs~)ϪbG-V<U/s: ka"wٰD'w`p:4d?e) }\EXu Z}<5vÃ:".J7ufOI2 =hGIi9cOZSXDf,tJNݬ/9G.ET*tTNڿCx0j)PPAF xeFc|<_\`! I#!JJƁ"Piyq|&NR壟ۣdr 23Ki\?qꓐ0!X8Œ g,3} 2Cv@s|u|K(8rfpRd/[{vr+UҐ ?4)-z5|@jfQ2t)뙩 Gt`8Sh~7)ցWw3 +w`,Y=om[dMD:s3LYoǠXx>c嫓,p/StYִsT8ej&X"A_c7JV1+-t]/(0Y: 2hUv5ر.:&0|0>c`28Ϳ}Tm6rSYeUG bYsR2P+d,a-hIND̤C AVE4+(L̙e#z[8M擌X{R Ѵ\S'9J s7J,t*63pXSz|R]hƆ/3_rywZh|"<VvZ&4!I.y`51aiv=rMt T#!BZM'|͔r*ҚYBMOU_dУ474tKh 5]KRl9K;xRX _+_jܤ8ؾIENDB`proguard4.8/src/proguard/gui/ClassPathPanel.java0000644000175000017500000003514611736333525020505 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.*; import proguard.util.ListUtil; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.List; /** * This ListPanel allows the user to add, edit, filter, move, and * remove ClassPathEntry objects in a ClassPath object. * * @author Eric Lafortune */ class ClassPathPanel extends ListPanel { private final JFrame owner; private final boolean inputAndOutput; private final JFileChooser chooser; private final FilterDialog filterDialog; public ClassPathPanel(JFrame owner, boolean inputAndOutput) { super(); super.firstSelectionButton = inputAndOutput ? 3 : 2; this.owner = owner; this.inputAndOutput = inputAndOutput; list.setCellRenderer(new MyListCellRenderer()); chooser = new JFileChooser(""); chooser.setMultiSelectionEnabled(true); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.addChoosableFileFilter( new ExtensionFileFilter(msg("jarWarEarZipExtensions"), new String[] { ".jar", ".war", ".ear", ".zip" })); chooser.setApproveButtonText(msg("ok")); filterDialog = new FilterDialog(owner, msg("enterFilter")); addAddButton(inputAndOutput, false); if (inputAndOutput) { addAddButton(inputAndOutput, true); } addEditButton(); addFilterButton(); addRemoveButton(); addUpButton(); addDownButton(); enableSelectionButtons(); } protected void addAddButton(boolean inputAndOutput, final boolean isOutput) { JButton addButton = new JButton(msg(inputAndOutput ? isOutput ? "addOutput" : "addInput" : "add")); addButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { chooser.setDialogTitle(msg("addJars")); chooser.setSelectedFile(null); chooser.setSelectedFiles(null); int returnValue = chooser.showOpenDialog(owner); if (returnValue == JFileChooser.APPROVE_OPTION) { File[] selectedFiles = chooser.getSelectedFiles(); ClassPathEntry[] entries = classPathEntries(selectedFiles, isOutput); // Add the new elements. addElements(entries); } } }); addButton(tip(addButton, inputAndOutput ? isOutput ? "addOutputTip" : "addInputTip" : "addTip")); } protected void addEditButton() { JButton editButton = new JButton(msg("edit")); editButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { boolean isOutput = false; int[] selectedIndices = list.getSelectedIndices(); // Copy the Object array into a File array. File[] selectedFiles = new File[selectedIndices.length]; for (int index = 0; index < selectedFiles.length; index++) { ClassPathEntry entry = (ClassPathEntry)listModel.getElementAt(selectedIndices[index]); isOutput = entry.isOutput(); selectedFiles[index] = entry.getFile(); } chooser.setDialogTitle(msg("chooseJars")); // Up to JDK 1.3.1, setSelectedFiles doesn't show in the file // chooser, so we just use setSelectedFile first. It also sets // the current directory. chooser.setSelectedFile(selectedFiles[0].getAbsoluteFile()); chooser.setSelectedFiles(selectedFiles); int returnValue = chooser.showOpenDialog(owner); if (returnValue == JFileChooser.APPROVE_OPTION) { selectedFiles = chooser.getSelectedFiles(); ClassPathEntry[] entries = classPathEntries(selectedFiles, isOutput); // If there are the same number of files selected now as // there were before, we can just replace the old ones. if (selectedIndices.length == selectedFiles.length) { // Replace the old elements. setElementsAt(entries, selectedIndices); } else { // Remove the old elements. removeElementsAt(selectedIndices); // Add the new elements. addElements(entries); } } } }); addButton(tip(editButton, "editTip")); } protected void addFilterButton() { JButton filterButton = new JButton(msg("filter")); filterButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (!list.isSelectionEmpty()) { int[] selectedIndices = list.getSelectedIndices(); // Put the filters of the first selected entry in the dialog. getFiltersFrom(selectedIndices[0]); int returnValue = filterDialog.showDialog(); if (returnValue == FilterDialog.APPROVE_OPTION) { // Apply the entered filters to all selected entries. setFiltersAt(selectedIndices); } } } }); addButton(tip(filterButton, "filterTip")); } /** * Sets the ClassPath to be represented in this panel. */ public void setClassPath(ClassPath classPath) { listModel.clear(); if (classPath != null) { for (int index = 0; index < classPath.size(); index++) { listModel.addElement(classPath.get(index)); } } // Make sure the selection buttons are properly enabled, // since the clear method doesn't seem to notify the listener. enableSelectionButtons(); } /** * Returns the ClassPath currently represented in this panel. */ public ClassPath getClassPath() { int size = listModel.size(); if (size == 0) { return null; } ClassPath classPath = new ClassPath(); for (int index = 0; index < size; index++) { classPath.add((ClassPathEntry)listModel.get(index)); } return classPath; } /** * Converts the given array of File objects into a corresponding array of * ClassPathEntry objects. */ private ClassPathEntry[] classPathEntries(File[] files, boolean isOutput) { ClassPathEntry[] entries = new ClassPathEntry[files.length]; for (int index = 0; index < entries.length; index++) { entries[index] = new ClassPathEntry(files[index], isOutput); } return entries; } /** * Sets up the filter dialog with the filters from the specified class path * entry. */ private void getFiltersFrom(int index) { ClassPathEntry firstEntry = (ClassPathEntry)listModel.get(index); filterDialog.setFilter(firstEntry.getFilter()); filterDialog.setJarFilter(firstEntry.getJarFilter()); filterDialog.setWarFilter(firstEntry.getWarFilter()); filterDialog.setEarFilter(firstEntry.getEarFilter()); filterDialog.setZipFilter(firstEntry.getZipFilter()); } /** * Applies the entered filter to the specified class path entries. * Any previously set filters are discarded. */ private void setFiltersAt(int[] indices) { for (int index = indices.length - 1; index >= 0; index--) { ClassPathEntry entry = (ClassPathEntry)listModel.get(indices[index]); entry.setFilter(filterDialog.getFilter()); entry.setJarFilter(filterDialog.getJarFilter()); entry.setWarFilter(filterDialog.getWarFilter()); entry.setEarFilter(filterDialog.getEarFilter()); entry.setZipFilter(filterDialog.getZipFilter()); } // Make sure they are selected and thus repainted. list.setSelectedIndices(indices); } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } /** * This ListCellRenderer renders ClassPathEntry objects. */ private class MyListCellRenderer implements ListCellRenderer { private static final String ARROW_IMAGE_FILE = "arrow.gif"; private final JPanel cellPanel = new JPanel(new GridBagLayout()); private final JLabel iconLabel = new JLabel("", JLabel.RIGHT); private final JLabel jarNameLabel = new JLabel("", JLabel.RIGHT); private final JLabel filterLabel = new JLabel("", JLabel.RIGHT); private final Icon arrowIcon; public MyListCellRenderer() { GridBagConstraints jarNameLabelConstraints = new GridBagConstraints(); jarNameLabelConstraints.anchor = GridBagConstraints.WEST; jarNameLabelConstraints.insets = new Insets(1, 2, 1, 2); GridBagConstraints filterLabelConstraints = new GridBagConstraints(); filterLabelConstraints.gridwidth = GridBagConstraints.REMAINDER; filterLabelConstraints.fill = GridBagConstraints.HORIZONTAL; filterLabelConstraints.weightx = 1.0; filterLabelConstraints.anchor = GridBagConstraints.EAST; filterLabelConstraints.insets = jarNameLabelConstraints.insets; arrowIcon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource(ARROW_IMAGE_FILE))); cellPanel.add(iconLabel, jarNameLabelConstraints); cellPanel.add(jarNameLabel, jarNameLabelConstraints); cellPanel.add(filterLabel, filterLabelConstraints); } // Implementations for ListCellRenderer. public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { ClassPathEntry entry = (ClassPathEntry)value; // Prepend an arrow to the output entries. if (inputAndOutput && entry.isOutput()) { iconLabel.setIcon(arrowIcon); } else { iconLabel.setIcon(null); } // Set the entry name text. jarNameLabel.setText(entry.getName()); // Set the filter text. StringBuffer filter = null; filter = appendFilter(filter, entry.getZipFilter()); filter = appendFilter(filter, entry.getEarFilter()); filter = appendFilter(filter, entry.getWarFilter()); filter = appendFilter(filter, entry.getJarFilter()); filter = appendFilter(filter, entry.getFilter()); if (filter != null) { filter.append(')'); } filterLabel.setText(filter != null ? filter.toString() : ""); // Set the colors. if (isSelected) { cellPanel.setBackground(list.getSelectionBackground()); jarNameLabel.setForeground(list.getSelectionForeground()); filterLabel.setForeground(list.getSelectionForeground()); } else { cellPanel.setBackground(list.getBackground()); jarNameLabel.setForeground(list.getForeground()); filterLabel.setForeground(list.getForeground()); } // Make the font color red if this is an input file that can't be read. if (!(inputAndOutput && entry.isOutput()) && !entry.getFile().canRead()) { jarNameLabel.setForeground(Color.red); } cellPanel.setOpaque(true); return cellPanel; } private StringBuffer appendFilter(StringBuffer filter, List additionalFilter) { if (filter != null) { filter.append(';'); } if (additionalFilter != null) { if (filter == null) { filter = new StringBuffer().append('('); } filter.append(ListUtil.commaSeparatedString(additionalFilter, true)); } return filter; } } } proguard4.8/src/proguard/gui/ProGuardRunnable.java0000644000175000017500000001205511736333525021047 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.*; import javax.swing.*; import java.awt.*; import java.io.PrintStream; /** * This Runnable runs ProGuard, sending console output to a text * area and any exceptions to message dialogs. * * @see ProGuard * @author Eric Lafortune */ final class ProGuardRunnable implements Runnable { private final JTextArea consoleTextArea; private final Configuration configuration; private final String configurationFileName; /** * Creates a new ProGuardRunnable object. * @param consoleTextArea the text area to send the console output to. * @param configuration the ProGuard configuration. * @param configurationFileName the optional file name of the configuration, * for informational purposes. */ public ProGuardRunnable(JTextArea consoleTextArea, Configuration configuration, String configurationFileName) { this.consoleTextArea = consoleTextArea; this.configuration = configuration; this.configurationFileName = configurationFileName; } // Implementation for Runnable. public void run() { consoleTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); consoleTextArea.setText(""); // Redirect the System's out and err streams to the console text area. PrintStream oldOut = System.out; PrintStream oldErr = System.err; PrintStream printStream = new PrintStream(new TextAreaOutputStream(consoleTextArea), true); System.setOut(printStream); System.setErr(printStream); try { // Create a new ProGuard object with the GUI's configuration. ProGuard proGuard = new ProGuard(configuration); // Run it. proGuard.execute(); // Print out the completion message. System.out.println("Processing completed successfully"); } catch (Exception ex) { //ex.printStackTrace(); // Print out the exception message. System.out.println(ex.getMessage()); // Show a dialog as well. MessageDialogRunnable.showMessageDialog(consoleTextArea, ex.getMessage(), msg("errorProcessing"), JOptionPane.ERROR_MESSAGE); } catch (OutOfMemoryError er) { // Forget about the ProGuard object as quickly as possible. System.gc(); // Print out a message suggesting what to do next. System.out.println(msg("outOfMemoryInfo", configurationFileName)); // Show a dialog as well. MessageDialogRunnable.showMessageDialog(consoleTextArea, msg("outOfMemory"), msg("errorProcessing"), JOptionPane.ERROR_MESSAGE); } finally { // Make sure all output has been sent to the console text area. printStream.close(); // Restore the old System's out and err streams. System.setOut(oldOut); System.setErr(oldErr); } consoleTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); // Reset the global static redirection lock. ProGuardGUI.systemOutRedirected = false; } // Small utility methods. /** * Returns the message from the GUI resources that corresponds to the given * key. */ private String msg(String messageKey) { return GUIResources.getMessage(messageKey); } /** * Returns the message from the GUI resources that corresponds to the given * key and argument. */ private String msg(String messageKey, Object messageArgument) { return GUIResources.getMessage(messageKey, new Object[] {messageArgument}); } } proguard4.8/src/proguard/gui/ExtensionFileFilter.java0000644000175000017500000000407311736333525021560 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import javax.swing.filechooser.FileFilter; import java.io.File; /** * This FileFilter accepts files that end in one of the given * extensions. * * @author Eric Lafortune */ final class ExtensionFileFilter extends FileFilter { private final String description; private final String[] extensions; /** * Creates a new ExtensionFileFilter. * @param description a description of the filter. * @param extensions an array of acceptable extensions. */ public ExtensionFileFilter(String description, String[] extensions) { this.description = description; this.extensions = extensions; } // Implemntations for FileFilter public String getDescription() { return description; } public boolean accept(File file) { if (file.isDirectory()) { return true; } String fileName = file.getName().toLowerCase(); for (int index = 0; index < extensions.length; index++) { if (fileName.endsWith(extensions[index])) { return true; } } return false; } } proguard4.8/src/proguard/gui/MessageDialogRunnable.java0000644000175000017500000000560411736333525022032 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import javax.swing.*; import java.awt.*; import java.lang.reflect.InvocationTargetException; /** * This Runnable can show a message dialog. * * @author Eric Lafortune */ final class MessageDialogRunnable implements Runnable { private final Component parentComponent; private final Object message; private final String title; private final int messageType; /** * Creates a new MessageDialogRunnable object. * @see JOptionPane#showMessageDialog(Component, Object, String, int) */ public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType) { try { SwingUtil.invokeAndWait(new MessageDialogRunnable(parentComponent, message, title, messageType)); } catch (Exception e) { // Nothing. } } /** * Creates a new MessageDialogRunnable object. * @see JOptionPane#showMessageDialog(Component, Object, String, int) */ public MessageDialogRunnable(Component parentComponent, Object message, String title, int messageType) { this.parentComponent = parentComponent; this.message = message; this.title = title; this.messageType = messageType; } // Implementation for Runnable. public void run() { JOptionPane.showMessageDialog(parentComponent, message, title, messageType); } } proguard4.8/src/proguard/gui/TextAreaOutputStream.java0000644000175000017500000000417311736333525021751 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import javax.swing.*; import java.io.*; import java.lang.reflect.InvocationTargetException; /** * This PrintStream appends its output to a given text area. * * @author Eric Lafortune */ final class TextAreaOutputStream extends FilterOutputStream implements Runnable { private final JTextArea textArea; public TextAreaOutputStream(JTextArea textArea) { super(new ByteArrayOutputStream()); this.textArea = textArea; } // Implementation for FilterOutputStream. public void flush() throws IOException { super.flush(); try { // Append the accumulated buffer contents to the text area. SwingUtil.invokeAndWait(this); } catch (Exception e) { // Nothing. } } // Implementation for Runnable. public void run() { ByteArrayOutputStream out = (ByteArrayOutputStream)super.out; // Has any new text been written? String text = out.toString(); if (text.length() > 0) { // Append the accumulated text to the text area. textArea.append(text); // Clear the buffer. out.reset(); } } } proguard4.8/src/proguard/gui/GUIResources.java0000644000175000017500000000346011736333525020154 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import java.text.MessageFormat; import java.util.ResourceBundle; /** * This class provides some utility methods for working with resource bundles. * * @author Eric Lafortune */ class GUIResources { private static final ResourceBundle messages = ResourceBundle.getBundle(GUIResources.class.getName()); private static final MessageFormat formatter = new MessageFormat(""); /** * Returns an internationalized message, based on its key. */ public static String getMessage(String messageKey) { return messages.getString(messageKey); } /** * Returns an internationalized, formatted message, based on its key, with * the given arguments. */ public static String getMessage(String messageKey, Object[] messageArguments) { formatter.applyPattern(messages.getString(messageKey)); return formatter.format(messageArguments); } } proguard4.8/src/proguard/gui/MemberSpecificationDialog.java0000644000175000017500000005432611736333525022674 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.MemberSpecification; import proguard.classfile.ClassConstants; import proguard.classfile.util.ClassUtil; import proguard.util.ListUtil; import javax.swing.*; import javax.swing.border.*; import java.awt.*; import java.awt.event.*; /** * This JDialog allows the user to enter a String. * * @author Eric Lafortune */ final class MemberSpecificationDialog extends JDialog { /** * Return value if the dialog is canceled (with the Cancel button or by * closing the dialog window). */ public static final int CANCEL_OPTION = 1; /** * Return value if the dialog is approved (with the Ok button). */ public static final int APPROVE_OPTION = 0; private final boolean isField; private final JRadioButton[] publicRadioButtons; private final JRadioButton[] privateRadioButtons; private final JRadioButton[] protectedRadioButtons; private final JRadioButton[] staticRadioButtons; private final JRadioButton[] finalRadioButtons; private final JRadioButton[] syntheticRadioButtons; private JRadioButton[] volatileRadioButtons; private JRadioButton[] transientRadioButtons; private JRadioButton[] synchronizedRadioButtons; private JRadioButton[] nativeRadioButtons; private JRadioButton[] abstractRadioButtons; private JRadioButton[] strictRadioButtons; private JRadioButton[] bridgeRadioButtons; private JRadioButton[] varargsRadioButtons; private final JTextField annotationTypeTextField = new JTextField(20); private final JTextField nameTextField = new JTextField(20); private final JTextField typeTextField = new JTextField(20); private final JTextField argumentTypesTextField = new JTextField(20); private int returnValue; public MemberSpecificationDialog(JDialog owner, boolean isField) { super(owner, msg(isField ? "specifyFields" : "specifyMethods"), true); setResizable(true); // Create some constraints that can be reused. GridBagConstraints constraints = new GridBagConstraints(); constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(1, 2, 1, 2); GridBagConstraints constraintsStretch = new GridBagConstraints(); constraintsStretch.fill = GridBagConstraints.HORIZONTAL; constraintsStretch.weightx = 1.0; constraintsStretch.anchor = GridBagConstraints.WEST; constraintsStretch.insets = constraints.insets; GridBagConstraints constraintsLast = new GridBagConstraints(); constraintsLast.gridwidth = GridBagConstraints.REMAINDER; constraintsLast.anchor = GridBagConstraints.WEST; constraintsLast.insets = constraints.insets; GridBagConstraints constraintsLastStretch = new GridBagConstraints(); constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER; constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL; constraintsLastStretch.weightx = 1.0; constraintsLastStretch.anchor = GridBagConstraints.WEST; constraintsLastStretch.insets = constraints.insets; GridBagConstraints panelConstraints = new GridBagConstraints(); panelConstraints.gridwidth = GridBagConstraints.REMAINDER; panelConstraints.fill = GridBagConstraints.HORIZONTAL; panelConstraints.weightx = 1.0; panelConstraints.weighty = 0.0; panelConstraints.anchor = GridBagConstraints.NORTHWEST; panelConstraints.insets = constraints.insets; GridBagConstraints stretchPanelConstraints = new GridBagConstraints(); stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER; stretchPanelConstraints.fill = GridBagConstraints.BOTH; stretchPanelConstraints.weightx = 1.0; stretchPanelConstraints.weighty = 1.0; stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST; stretchPanelConstraints.insets = constraints.insets; GridBagConstraints labelConstraints = new GridBagConstraints(); labelConstraints.anchor = GridBagConstraints.CENTER; labelConstraints.insets = new Insets(2, 10, 2, 10); GridBagConstraints lastLabelConstraints = new GridBagConstraints(); lastLabelConstraints.gridwidth = GridBagConstraints.REMAINDER; lastLabelConstraints.anchor = GridBagConstraints.CENTER; lastLabelConstraints.insets = labelConstraints.insets; GridBagConstraints advancedButtonConstraints = new GridBagConstraints(); advancedButtonConstraints.weightx = 1.0; advancedButtonConstraints.weighty = 1.0; advancedButtonConstraints.anchor = GridBagConstraints.SOUTHWEST; advancedButtonConstraints.insets = new Insets(4, 4, 8, 4); GridBagConstraints okButtonConstraints = new GridBagConstraints(); okButtonConstraints.weightx = 1.0; okButtonConstraints.weighty = 1.0; okButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; okButtonConstraints.insets = advancedButtonConstraints.insets; GridBagConstraints cancelButtonConstraints = new GridBagConstraints(); cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER; cancelButtonConstraints.weighty = 1.0; cancelButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; cancelButtonConstraints.insets = okButtonConstraints.insets; GridBagLayout layout = new GridBagLayout(); Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); this.isField = isField; // Create the access panel. JPanel accessPanel = new JPanel(layout); accessPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("access"))); accessPanel.add(Box.createGlue(), labelConstraints); accessPanel.add(tip(new JLabel(msg("required")), "requiredTip"), labelConstraints); accessPanel.add(tip(new JLabel(msg("not")), "notTip"), labelConstraints); accessPanel.add(tip(new JLabel(msg("dontCare")), "dontCareTip"), labelConstraints); accessPanel.add(Box.createGlue(), constraintsLastStretch); publicRadioButtons = addRadioButtonTriplet("Public", accessPanel); privateRadioButtons = addRadioButtonTriplet("Private", accessPanel); protectedRadioButtons = addRadioButtonTriplet("Protected", accessPanel); staticRadioButtons = addRadioButtonTriplet("Static", accessPanel); finalRadioButtons = addRadioButtonTriplet("Final", accessPanel); syntheticRadioButtons = addRadioButtonTriplet("Synthetic", accessPanel); if (isField) { volatileRadioButtons = addRadioButtonTriplet("Volatile", accessPanel); transientRadioButtons = addRadioButtonTriplet("Transient", accessPanel); } else { synchronizedRadioButtons = addRadioButtonTriplet("Synchronized", accessPanel); nativeRadioButtons = addRadioButtonTriplet("Native", accessPanel); abstractRadioButtons = addRadioButtonTriplet("Abstract", accessPanel); strictRadioButtons = addRadioButtonTriplet("Strict", accessPanel); bridgeRadioButtons = addRadioButtonTriplet("Bridge", accessPanel); varargsRadioButtons = addRadioButtonTriplet("Varargs", accessPanel); } // Create the type panel. JPanel typePanel = new JPanel(layout); typePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg(isField ? "fieldType" : "returnType"))); typePanel.add(tip(typeTextField, "typeTip"), constraintsLastStretch); // Create the annotation type panel. final JPanel annotationTypePanel = new JPanel(layout); annotationTypePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("annotation"))); annotationTypePanel.add(tip(annotationTypeTextField, "classNameTip"), constraintsLastStretch); // Create the name panel. JPanel namePanel = new JPanel(layout); namePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("name"))); namePanel.add(tip(nameTextField, isField ? "fieldNameTip" : "methodNameTip"), constraintsLastStretch); // Create the arguments panel. JPanel argumentsPanel = new JPanel(layout); argumentsPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("argumentTypes"))); argumentsPanel.add(tip(argumentTypesTextField, "argumentTypes2Tip"), constraintsLastStretch); // Create the Advanced button. final JButton advancedButton = new JButton(msg("basic")); advancedButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { boolean visible = !annotationTypePanel.isVisible(); annotationTypePanel.setVisible(visible); advancedButton.setText(msg(visible ? "basic" : "advanced")); pack(); } }); advancedButton.doClick(); // Create the Ok button. JButton okButton = new JButton(msg("ok")); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { returnValue = APPROVE_OPTION; hide(); } }); // Create the Cancel button. JButton cancelButton = new JButton(msg("cancel")); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { hide(); } }); // Add all panels to the main panel. JPanel mainPanel = new JPanel(layout); mainPanel.add(tip(accessPanel, "accessTip"), panelConstraints); mainPanel.add(tip(annotationTypePanel, "annotationTip"), panelConstraints); mainPanel.add(tip(typePanel, isField ? "fieldTypeTip" : "returnTypeTip"), panelConstraints); mainPanel.add(tip(namePanel, "nameTip"), panelConstraints); if (!isField) { mainPanel.add(tip(argumentsPanel, "argumentTypesTip"), panelConstraints); } mainPanel.add(tip(advancedButton, "advancedTip"), advancedButtonConstraints); mainPanel.add(okButton, okButtonConstraints); mainPanel.add(cancelButton, cancelButtonConstraints); getContentPane().add(new JScrollPane(mainPanel)); } /** * Adds a JLabel and three JRadioButton instances in a ButtonGroup to the * given panel with a GridBagLayout, and returns the buttons in an array. */ private JRadioButton[] addRadioButtonTriplet(String labelText, JPanel panel) { GridBagConstraints labelConstraints = new GridBagConstraints(); labelConstraints.anchor = GridBagConstraints.WEST; labelConstraints.insets = new Insets(2, 10, 2, 10); GridBagConstraints buttonConstraints = new GridBagConstraints(); buttonConstraints.insets = labelConstraints.insets; GridBagConstraints lastGlueConstraints = new GridBagConstraints(); lastGlueConstraints.gridwidth = GridBagConstraints.REMAINDER; lastGlueConstraints.weightx = 1.0; // Create the radio buttons. JRadioButton radioButton0 = new JRadioButton(); JRadioButton radioButton1 = new JRadioButton(); JRadioButton radioButton2 = new JRadioButton(); // Put them in a button group. ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(radioButton0); buttonGroup.add(radioButton1); buttonGroup.add(radioButton2); // Add the label and the buttons to the panel. panel.add(new JLabel(labelText), labelConstraints); panel.add(radioButton0, buttonConstraints); panel.add(radioButton1, buttonConstraints); panel.add(radioButton2, buttonConstraints); panel.add(Box.createGlue(), lastGlueConstraints); return new JRadioButton[] { radioButton0, radioButton1, radioButton2 }; } /** * Sets the MemberSpecification to be represented in this dialog. */ public void setMemberSpecification(MemberSpecification memberSpecification) { String annotationType = memberSpecification.annotationType; String name = memberSpecification.name; String descriptor = memberSpecification.descriptor; // Set the class name text fields. annotationTypeTextField.setText(annotationType == null ? "" : ClassUtil.externalType(annotationType)); // Set the access radio buttons. setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PRIVATE, privateRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNTHETIC, syntheticRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_BRIDGE, bridgeRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VARARGS, varargsRadioButtons); // Set the class name text fields. nameTextField.setText(name == null ? "*" : name); if (isField) { typeTextField .setText(descriptor == null ? "***" : ClassUtil.externalType(descriptor)); } else { typeTextField .setText(descriptor == null ? "***" : ClassUtil.externalMethodReturnType(descriptor)); argumentTypesTextField.setText(descriptor == null ? "..." : ClassUtil.externalMethodArguments(descriptor)); } } /** * Returns the MemberSpecification currently represented in this dialog. */ public MemberSpecification getMemberSpecification() { String annotationType = annotationTypeTextField.getText(); String name = nameTextField.getText(); String type = typeTextField.getText(); String arguments = argumentTypesTextField.getText(); // Convert all class member specifications into the internal format. annotationType = annotationType.equals("") || annotationType.equals("***") ? null : ClassUtil.internalType(annotationType); if (name.equals("") || name.equals("*")) { name = null; } if (isField) { type = type.equals("") || type.equals("***") ? null : ClassUtil.internalType(type); } else { if (type.equals("")) { type = ClassConstants.EXTERNAL_TYPE_VOID; } type = type .equals("***") && arguments.equals("...") ? null : ClassUtil.internalMethodDescriptor(type, ListUtil.commaSeparatedList(arguments)); } MemberSpecification memberSpecification = new MemberSpecification(0, 0, annotationType, name, type); // Also get the access radio button settings. getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PRIVATE, privateRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNTHETIC, syntheticRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_BRIDGE, bridgeRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VARARGS, varargsRadioButtons); return memberSpecification; } /** * Shows this dialog. This method only returns when the dialog is closed. * * @return CANCEL_OPTION or APPROVE_OPTION, * depending on the choice of the user. */ public int showDialog() { returnValue = CANCEL_OPTION; // Open the dialog in the right place, then wait for it to be closed, // one way or another. pack(); setLocationRelativeTo(getOwner()); show(); return returnValue; } /** * Sets the appropriate radio button of a given triplet, based on the access * flags of the given keep option. */ private void setMemberSpecificationRadioButtons(MemberSpecification memberSpecification, int flag, JRadioButton[] radioButtons) { if (radioButtons != null) { int index = (memberSpecification.requiredSetAccessFlags & flag) != 0 ? 0 : (memberSpecification.requiredUnsetAccessFlags & flag) != 0 ? 1 : 2; radioButtons[index].setSelected(true); } } /** * Updates the access flag of the given keep option, based on the given radio * button triplet. */ private void getMemberSpecificationRadioButtons(MemberSpecification memberSpecification, int flag, JRadioButton[] radioButtons) { if (radioButtons != null) { if (radioButtons[0].isSelected()) { memberSpecification.requiredSetAccessFlags |= flag; } else if (radioButtons[1].isSelected()) { memberSpecification.requiredUnsetAccessFlags |= flag; } } } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } } proguard4.8/src/proguard/gui/FilterBuilder.java0000644000175000017500000001431111736333525020366 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import javax.swing.*; /** * This class builds filters corresponding to the selections and names of a * given list of check boxes. */ public class FilterBuilder { private JCheckBox[] checkBoxes; private char separator; /** * Creates a new FilterBuilder. * @param checkBoxes the check boxes with names and selections that should * be reflected in the output filter. * @param separator the separator for the names in the check boxes. */ public FilterBuilder(JCheckBox[] checkBoxes, char separator) { this.checkBoxes = checkBoxes; this.separator = separator; } /** * Builds a filter for the current names and selections of the check boxes. */ public String buildFilter() { StringBuffer positive = new StringBuffer(); StringBuffer negative = new StringBuffer(); buildFilter("", positive, negative); return positive.length() <= negative.length() ? positive.toString() : negative.toString(); } /** * Builds two versions of the filter for the given prefix. * @param prefix the prefix. * @param positive the filter to be extended, assuming the matching * strings are accepted. * @param negative the filter to be extended, assuming the matching * strings are rejected. */ private void buildFilter(String prefix, StringBuffer positive, StringBuffer negative) { int positiveCount = 0; int negativeCount = 0; // Count all selected and unselected check boxes with the prefix. for (int index = 0; index < checkBoxes.length; index++) { JCheckBox checkBox = checkBoxes[index]; String name = checkBox.getText(); if (name.startsWith(prefix)) { if (checkBox.isSelected()) { positiveCount++; } else { negativeCount++; } } } // Are there only unselected check boxes? if (positiveCount == 0) { // Extend the positive filter with exceptions and return. if (positive.length() > 0) { positive.append(','); } positive.append('!').append(prefix); if (prefix.length() == 0 || prefix.charAt(prefix.length()-1) == separator) { positive.append('*'); } return; } // Are there only selected check boxes? if (negativeCount == 0) { // Extend the negative filter with exceptions and return. if (negative.length() > 0) { negative.append(','); } negative.append(prefix); if (prefix.length() == 0 || prefix.charAt(prefix.length()-1) == separator) { negative.append('*'); } return; } // Create new positive and negative filters for names starting with the // prefix only. StringBuffer positiveFilter = new StringBuffer(); StringBuffer negativeFilter = new StringBuffer(); String newPrefix = null; for (int index = 0; index < checkBoxes.length; index++) { String name = checkBoxes[index].getText(); if (name.startsWith(prefix)) { if (newPrefix == null || !name.startsWith(newPrefix)) { int prefixIndex = name.indexOf(separator, prefix.length()+1); newPrefix = prefixIndex >= 0 ? name.substring(0, prefixIndex+1) : name; buildFilter(newPrefix, positiveFilter, negativeFilter); } } } // Extend the positive filter. if (positiveFilter.length() <= negativeFilter.length() + prefix.length() + 3) { if (positive.length() > 0 && positiveFilter.length() > 0) { positive.append(','); } positive.append(positiveFilter); } else { if (positive.length() > 0 && negativeFilter.length() > 0) { positive.append(','); } positive.append(negativeFilter).append(",!").append(prefix).append('*'); } // Extend the negative filter. if (negativeFilter.length() <= positiveFilter.length() + prefix.length() + 4) { if (negative.length() > 0 && negativeFilter.length() > 0) { negative.append(','); } negative.append(negativeFilter); } else { if (negative.length() > 0 && positiveFilter.length() > 0) { negative.append(','); } negative.append(positiveFilter).append(',').append(prefix).append('*'); } } } proguard4.8/src/proguard/gui/FilterDialog.java0000644000175000017500000002546511736333525020213 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.util.ListUtil; import javax.swing.*; import javax.swing.border.*; import java.awt.*; import java.awt.event.*; import java.util.List; /** * This JDialog allows the user to enter a String. * * @author Eric Lafortune */ public class FilterDialog extends JDialog { /** * Return value if the dialog is canceled (with the Cancel button or by * closing the dialog window). */ public static final int CANCEL_OPTION = 1; /** * Return value if the dialog is approved (with the Ok button). */ public static final int APPROVE_OPTION = 0; private static final String DEFAULT_FILTER = "**"; private static final String DEFAULT_JAR_FILTER = "**.jar"; private static final String DEFAULT_WAR_FILTER = "**.war"; private static final String DEFAULT_EAR_FILTER = "**.ear"; private static final String DEFAULT_ZIP_FILTER = "**.zip"; private final JTextField filterTextField = new JTextField(40); private final JTextField jarFilterTextField = new JTextField(40); private final JTextField warFilterTextField = new JTextField(40); private final JTextField earFilterTextField = new JTextField(40); private final JTextField zipFilterTextField = new JTextField(40); private int returnValue; public FilterDialog(JFrame owner, String explanation) { super(owner, true); setResizable(true); // Create some constraints that can be reused. GridBagConstraints textConstraints = new GridBagConstraints(); textConstraints.gridwidth = GridBagConstraints.REMAINDER; textConstraints.fill = GridBagConstraints.HORIZONTAL; textConstraints.weightx = 1.0; textConstraints.weighty = 1.0; textConstraints.anchor = GridBagConstraints.NORTHWEST; textConstraints.insets = new Insets(10, 10, 10, 10); GridBagConstraints labelConstraints = new GridBagConstraints(); labelConstraints.anchor = GridBagConstraints.WEST; labelConstraints.insets = new Insets(1, 2, 1, 2); GridBagConstraints textFieldConstraints = new GridBagConstraints(); textFieldConstraints.gridwidth = GridBagConstraints.REMAINDER; textFieldConstraints.fill = GridBagConstraints.HORIZONTAL; textFieldConstraints.weightx = 1.0; textFieldConstraints.anchor = GridBagConstraints.WEST; textFieldConstraints.insets = labelConstraints.insets; GridBagConstraints panelConstraints = new GridBagConstraints(); panelConstraints.gridwidth = GridBagConstraints.REMAINDER; panelConstraints.fill = GridBagConstraints.HORIZONTAL; panelConstraints.weightx = 1.0; panelConstraints.weighty = 0.0; panelConstraints.anchor = GridBagConstraints.NORTHWEST; panelConstraints.insets = labelConstraints.insets; GridBagConstraints okButtonConstraints = new GridBagConstraints(); okButtonConstraints.weightx = 1.0; okButtonConstraints.weighty = 1.0; okButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; okButtonConstraints.insets = new Insets(4, 4, 8, 4); GridBagConstraints cancelButtonConstraints = new GridBagConstraints(); cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER; cancelButtonConstraints.weighty = 1.0; cancelButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; cancelButtonConstraints.insets = okButtonConstraints.insets; GridBagLayout layout = new GridBagLayout(); Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); // Create the panel with the explanation. JTextArea explanationTextArea = new JTextArea(explanation, 3, 0); explanationTextArea.setOpaque(false); explanationTextArea.setEditable(false); explanationTextArea.setLineWrap(true); explanationTextArea.setWrapStyleWord(true); // Create the filter labels. JLabel filterLabel = new JLabel(msg("nameFilter")); JLabel jarFilterLabel = new JLabel(msg("jarNameFilter")); JLabel warFilterLabel = new JLabel(msg("warNameFilter")); JLabel earFilterLabel = new JLabel(msg("earNameFilter")); JLabel zipFilterLabel = new JLabel(msg("zipNameFilter")); // Create the filter panel. JPanel filterPanel = new JPanel(layout); filterPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg("filters"))); filterPanel.add(explanationTextArea, textConstraints); filterPanel.add(tip(filterLabel, "nameFilterTip"), labelConstraints); filterPanel.add(tip(filterTextField, "fileNameFilterTip"), textFieldConstraints); filterPanel.add(tip(jarFilterLabel, "jarNameFilterTip"), labelConstraints); filterPanel.add(tip(jarFilterTextField, "fileNameFilterTip"), textFieldConstraints); filterPanel.add(tip(warFilterLabel, "warNameFilterTip"), labelConstraints); filterPanel.add(tip(warFilterTextField, "fileNameFilterTip"), textFieldConstraints); filterPanel.add(tip(earFilterLabel, "earNameFilterTip"), labelConstraints); filterPanel.add(tip(earFilterTextField, "fileNameFilterTip"), textFieldConstraints); filterPanel.add(tip(zipFilterLabel, "zipNameFilterTip"), labelConstraints); filterPanel.add(tip(zipFilterTextField, "fileNameFilterTip"), textFieldConstraints); JButton okButton = new JButton(msg("ok")); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { returnValue = APPROVE_OPTION; hide(); } }); JButton cancelButton = new JButton(msg("cancel")); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { hide(); } }); // Add all panels to the main panel. JPanel mainPanel = new JPanel(layout); mainPanel.add(filterPanel, panelConstraints); mainPanel.add(okButton, okButtonConstraints); mainPanel.add(cancelButton, cancelButtonConstraints); getContentPane().add(mainPanel); } /** * Sets the filter to be represented in this dialog. */ public void setFilter(List filter) { filterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_FILTER); } /** * Returns the filter currently represented in this dialog. */ public List getFilter() { String filter = filterTextField.getText(); return filter.equals(DEFAULT_FILTER) ? null : ListUtil.commaSeparatedList(filter); } /** * Sets the jar filter to be represented in this dialog. */ public void setJarFilter(List filter) { jarFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_JAR_FILTER); } /** * Returns the jar filter currently represented in this dialog. */ public List getJarFilter() { String filter = jarFilterTextField.getText(); return filter.equals(DEFAULT_JAR_FILTER) ? null : ListUtil.commaSeparatedList(filter); } /** * Sets the war filter to be represented in this dialog. */ public void setWarFilter(List filter) { warFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_WAR_FILTER); } /** * Returns the war filter currently represented in this dialog. */ public List getWarFilter() { String filter = warFilterTextField.getText(); return filter.equals(DEFAULT_WAR_FILTER) ? null : ListUtil.commaSeparatedList(filter); } /** * Sets the ear filter to be represented in this dialog. */ public void setEarFilter(List filter) { earFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_EAR_FILTER); } /** * Returns the ear filter currently represented in this dialog. */ public List getEarFilter() { String filter = earFilterTextField.getText(); return filter.equals(DEFAULT_EAR_FILTER) ? null : ListUtil.commaSeparatedList(filter); } /** * Sets the zip filter to be represented in this dialog. */ public void setZipFilter(List filter) { zipFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_ZIP_FILTER); } /** * Returns the zip filter currently represented in this dialog. */ public List getZipFilter() { String filter = zipFilterTextField.getText(); return filter.equals(DEFAULT_ZIP_FILTER) ? null : ListUtil.commaSeparatedList(filter); } /** * Shows this dialog. This method only returns when the dialog is closed. * * @return CANCEL_OPTION or APPROVE_OPTION, * depending on the choice of the user. */ public int showDialog() { returnValue = CANCEL_OPTION; // Open the dialog in the right place, then wait for it to be closed, // one way or another. pack(); setLocationRelativeTo(getOwner()); show(); return returnValue; } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } } proguard4.8/src/proguard/gui/ProGuardGUI.java0000664000175000017500000026065211752556537017747 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.*; import proguard.classfile.util.ClassUtil; import proguard.gui.splash.*; import proguard.util.ListUtil; import javax.swing.*; import javax.swing.border.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.URL; import java.util.*; import java.util.List; /** * GUI for configuring and executing ProGuard and ReTrace. * * @author Eric Lafortune */ public class ProGuardGUI extends JFrame { private static final String NO_SPLASH_OPTION = "-nosplash"; private static final String TITLE_IMAGE_FILE = "vtitle.png"; private static final String BOILERPLATE_CONFIGURATION = "boilerplate.pro"; private static final String DEFAULT_CONFIGURATION = "default.pro"; private static final String OPTIMIZATIONS_DEFAULT = "*"; private static final String KEEP_ATTRIBUTE_DEFAULT = "Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod"; private static final String SOURCE_FILE_ATTRIBUTE_DEFAULT = "SourceFile"; private static final String ADAPT_RESOURCE_FILE_NAMES_DEFAULT = "**.properties"; private static final String ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT = "**.properties,META-INF/MANIFEST.MF"; private static final Border BORDER = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); static boolean systemOutRedirected; private final JFileChooser configurationChooser = new JFileChooser(""); private final JFileChooser fileChooser = new JFileChooser(""); private final SplashPanel splashPanel; private final ClassPathPanel programPanel = new ClassPathPanel(this, true); private final ClassPathPanel libraryPanel = new ClassPathPanel(this, false); private KeepClassSpecification[] boilerplateKeep; private final JCheckBox[] boilerplateKeepCheckBoxes; private final JTextField[] boilerplateKeepTextFields; private final KeepSpecificationsPanel additionalKeepPanel = new KeepSpecificationsPanel(this, true, false, false, false, false); private KeepClassSpecification[] boilerplateKeepNames; private final JCheckBox[] boilerplateKeepNamesCheckBoxes; private final JTextField[] boilerplateKeepNamesTextFields; private final KeepSpecificationsPanel additionalKeepNamesPanel = new KeepSpecificationsPanel(this, true, false, true, false, false); private ClassSpecification[] boilerplateNoSideEffectMethods; private final JCheckBox[] boilerplateNoSideEffectMethodCheckBoxes; private final ClassSpecificationsPanel additionalNoSideEffectsPanel = new ClassSpecificationsPanel(this, false); private final ClassSpecificationsPanel whyAreYouKeepingPanel = new ClassSpecificationsPanel(this, false); private final JCheckBox shrinkCheckBox = new JCheckBox(msg("shrink")); private final JCheckBox printUsageCheckBox = new JCheckBox(msg("printUsage")); private final JCheckBox optimizeCheckBox = new JCheckBox(msg("optimize")); private final JCheckBox allowAccessModificationCheckBox = new JCheckBox(msg("allowAccessModification")); private final JCheckBox mergeInterfacesAggressivelyCheckBox = new JCheckBox(msg("mergeInterfacesAggressively")); private final JLabel optimizationsLabel = new JLabel(msg("optimizations")); private final JLabel optimizationPassesLabel = new JLabel(msg("optimizationPasses")); private final JSpinner optimizationPassesSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 9, 1)); private final JCheckBox obfuscateCheckBox = new JCheckBox(msg("obfuscate")); private final JCheckBox printMappingCheckBox = new JCheckBox(msg("printMapping")); private final JCheckBox applyMappingCheckBox = new JCheckBox(msg("applyMapping")); private final JCheckBox obfuscationDictionaryCheckBox = new JCheckBox(msg("obfuscationDictionary")); private final JCheckBox classObfuscationDictionaryCheckBox = new JCheckBox(msg("classObfuscationDictionary")); private final JCheckBox packageObfuscationDictionaryCheckBox = new JCheckBox(msg("packageObfuscationDictionary")); private final JCheckBox overloadAggressivelyCheckBox = new JCheckBox(msg("overloadAggressively")); private final JCheckBox useUniqueClassMemberNamesCheckBox = new JCheckBox(msg("useUniqueClassMemberNames")); private final JCheckBox useMixedCaseClassNamesCheckBox = new JCheckBox(msg("useMixedCaseClassNames")); private final JCheckBox keepPackageNamesCheckBox = new JCheckBox(msg("keepPackageNames")); private final JCheckBox flattenPackageHierarchyCheckBox = new JCheckBox(msg("flattenPackageHierarchy")); private final JCheckBox repackageClassesCheckBox = new JCheckBox(msg("repackageClasses")); private final JCheckBox keepAttributesCheckBox = new JCheckBox(msg("keepAttributes")); private final JCheckBox keepParameterNamesCheckBox = new JCheckBox(msg("keepParameterNames")); private final JCheckBox newSourceFileAttributeCheckBox = new JCheckBox(msg("renameSourceFileAttribute")); private final JCheckBox adaptClassStringsCheckBox = new JCheckBox(msg("adaptClassStrings")); private final JCheckBox adaptResourceFileNamesCheckBox = new JCheckBox(msg("adaptResourceFileNames")); private final JCheckBox adaptResourceFileContentsCheckBox = new JCheckBox(msg("adaptResourceFileContents")); private final JCheckBox preverifyCheckBox = new JCheckBox(msg("preverify")); private final JCheckBox microEditionCheckBox = new JCheckBox(msg("microEdition")); private final JCheckBox targetCheckBox = new JCheckBox(msg("target")); private final JComboBox targetComboBox = new JComboBox(ListUtil.commaSeparatedList(msg("targets")).toArray()); private final JCheckBox verboseCheckBox = new JCheckBox(msg("verbose")); private final JCheckBox noteCheckBox = new JCheckBox(msg("note")); private final JCheckBox warnCheckBox = new JCheckBox(msg("warn")); private final JCheckBox ignoreWarningsCheckBox = new JCheckBox(msg("ignoreWarnings")); private final JCheckBox skipNonPublicLibraryClassesCheckBox = new JCheckBox(msg("skipNonPublicLibraryClasses")); private final JCheckBox skipNonPublicLibraryClassMembersCheckBox = new JCheckBox(msg("skipNonPublicLibraryClassMembers")); private final JCheckBox keepDirectoriesCheckBox = new JCheckBox(msg("keepDirectories")); private final JCheckBox forceProcessingCheckBox = new JCheckBox(msg("forceProcessing")); private final JCheckBox printSeedsCheckBox = new JCheckBox(msg("printSeeds")); private final JCheckBox printConfigurationCheckBox = new JCheckBox(msg("printConfiguration")); private final JCheckBox dumpCheckBox = new JCheckBox(msg("dump")); private final JTextField printUsageTextField = new JTextField(40); private final JTextField optimizationsTextField = new JTextField(40); private final JTextField printMappingTextField = new JTextField(40); private final JTextField applyMappingTextField = new JTextField(40); private final JTextField obfuscationDictionaryTextField = new JTextField(40); private final JTextField classObfuscationDictionaryTextField = new JTextField(40); private final JTextField packageObfuscationDictionaryTextField = new JTextField(40); private final JTextField keepPackageNamesTextField = new JTextField(40); private final JTextField flattenPackageHierarchyTextField = new JTextField(40); private final JTextField repackageClassesTextField = new JTextField(40); private final JTextField keepAttributesTextField = new JTextField(40); private final JTextField newSourceFileAttributeTextField = new JTextField(40); private final JTextField adaptClassStringsTextField = new JTextField(40); private final JTextField adaptResourceFileNamesTextField = new JTextField(40); private final JTextField adaptResourceFileContentsTextField = new JTextField(40); private final JTextField noteTextField = new JTextField(40); private final JTextField warnTextField = new JTextField(40); private final JTextField keepDirectoriesTextField = new JTextField(40); private final JTextField printSeedsTextField = new JTextField(40); private final JTextField printConfigurationTextField = new JTextField(40); private final JTextField dumpTextField = new JTextField(40); private final JTextArea consoleTextArea = new JTextArea(msg("processingInfo"), 3, 40); private final JCheckBox reTraceVerboseCheckBox = new JCheckBox(msg("verbose")); private final JTextField reTraceMappingTextField = new JTextField(40); private final JTextArea stackTraceTextArea = new JTextArea(3, 40); private final JTextArea reTraceTextArea = new JTextArea(msg("reTraceInfo"), 3, 40); /** * Creates a new ProGuardGUI. */ public ProGuardGUI() { setTitle("ProGuard"); setDefaultCloseOperation(EXIT_ON_CLOSE); // Create some constraints that can be reused. GridBagConstraints constraints = new GridBagConstraints(); constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 4, 0, 4); GridBagConstraints constraintsStretch = new GridBagConstraints(); constraintsStretch.fill = GridBagConstraints.HORIZONTAL; constraintsStretch.weightx = 1.0; constraintsStretch.anchor = GridBagConstraints.WEST; constraintsStretch.insets = constraints.insets; GridBagConstraints constraintsLast = new GridBagConstraints(); constraintsLast.gridwidth = GridBagConstraints.REMAINDER; constraintsLast.anchor = GridBagConstraints.WEST; constraintsLast.insets = constraints.insets; GridBagConstraints constraintsLastStretch = new GridBagConstraints(); constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER; constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL; constraintsLastStretch.weightx = 1.0; constraintsLastStretch.anchor = GridBagConstraints.WEST; constraintsLastStretch.insets = constraints.insets; GridBagConstraints splashPanelConstraints = new GridBagConstraints(); splashPanelConstraints.gridwidth = GridBagConstraints.REMAINDER; splashPanelConstraints.fill = GridBagConstraints.BOTH; splashPanelConstraints.weightx = 1.0; splashPanelConstraints.weighty = 0.02; splashPanelConstraints.anchor = GridBagConstraints.NORTHWEST; //splashPanelConstraints.insets = constraints.insets; GridBagConstraints welcomePaneConstraints = new GridBagConstraints(); welcomePaneConstraints.gridwidth = GridBagConstraints.REMAINDER; welcomePaneConstraints.fill = GridBagConstraints.NONE; welcomePaneConstraints.weightx = 1.0; welcomePaneConstraints.weighty = 0.01; welcomePaneConstraints.anchor = GridBagConstraints.CENTER;//NORTHWEST; welcomePaneConstraints.insets = new Insets(20, 40, 20, 40); GridBagConstraints panelConstraints = new GridBagConstraints(); panelConstraints.gridwidth = GridBagConstraints.REMAINDER; panelConstraints.fill = GridBagConstraints.HORIZONTAL; panelConstraints.weightx = 1.0; panelConstraints.anchor = GridBagConstraints.NORTHWEST; panelConstraints.insets = constraints.insets; GridBagConstraints stretchPanelConstraints = new GridBagConstraints(); stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER; stretchPanelConstraints.fill = GridBagConstraints.BOTH; stretchPanelConstraints.weightx = 1.0; stretchPanelConstraints.weighty = 1.0; stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST; stretchPanelConstraints.insets = constraints.insets; GridBagConstraints glueConstraints = new GridBagConstraints(); glueConstraints.fill = GridBagConstraints.BOTH; glueConstraints.weightx = 0.01; glueConstraints.weighty = 0.01; glueConstraints.anchor = GridBagConstraints.NORTHWEST; glueConstraints.insets = constraints.insets; GridBagConstraints bottomButtonConstraints = new GridBagConstraints(); bottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; bottomButtonConstraints.insets = new Insets(2, 2, 4, 6); bottomButtonConstraints.ipadx = 10; bottomButtonConstraints.ipady = 2; GridBagConstraints lastBottomButtonConstraints = new GridBagConstraints(); lastBottomButtonConstraints.gridwidth = GridBagConstraints.REMAINDER; lastBottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; lastBottomButtonConstraints.insets = bottomButtonConstraints.insets; lastBottomButtonConstraints.ipadx = bottomButtonConstraints.ipadx; lastBottomButtonConstraints.ipady = bottomButtonConstraints.ipady; // Leave room for a growBox on Mac OS X. if (System.getProperty("os.name").toLowerCase().startsWith("mac os x")) { lastBottomButtonConstraints.insets = new Insets(2, 2, 4, 6 + 16); } GridBagLayout layout = new GridBagLayout(); configurationChooser.addChoosableFileFilter( new ExtensionFileFilter(msg("proExtension"), new String[] { ".pro" })); // Create the opening panel. Sprite splash = new CompositeSprite(new Sprite[] { new ColorSprite(new ConstantColor(Color.gray), new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 90)), new TextSprite(new ConstantString("ProGuard"), new ConstantInt(160), new LinearInt(-10, 120, new SmoothTiming(500, 1000))))), new ColorSprite(new ConstantColor(Color.white), new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 45)), new ShadowedSprite(new ConstantInt(3), new ConstantInt(3), new ConstantDouble(0.4), new ConstantInt(1), new CompositeSprite(new Sprite[] { new TextSprite(new ConstantString(msg("shrinking")), new LinearInt(1000, 60, new SmoothTiming(1000, 2000)), new ConstantInt(70)), new TextSprite(new ConstantString(msg("optimization")), new LinearInt(1000, 400, new SmoothTiming(1500, 2500)), new ConstantInt(60)), new TextSprite(new ConstantString(msg("obfuscation")), new LinearInt(1000, 10, new SmoothTiming(2000, 3000)), new ConstantInt(145)), new TextSprite(new ConstantString(msg("preverification")), new LinearInt(1000, 350, new SmoothTiming(2500, 3500)), new ConstantInt(140)), new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 30)), new TextSprite(new TypeWriterString(msg("developed"), new LinearTiming(3500, 5500)), new ConstantInt(250), new ConstantInt(200))), })))), }); splashPanel = new SplashPanel(splash, 0.5, 5500L); splashPanel.setPreferredSize(new Dimension(0, 200)); JEditorPane welcomePane = new JEditorPane("text/html", msg("proGuardInfo")); welcomePane.setPreferredSize(new Dimension(640, 350)); // The constant HONOR_DISPLAY_PROPERTIES isn't present yet in JDK 1.4. //welcomePane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE); welcomePane.putClientProperty("JEditorPane.honorDisplayProperties", Boolean.TRUE); welcomePane.setOpaque(false); welcomePane.setEditable(false); welcomePane.setBorder(new EmptyBorder(20, 20, 20, 20)); addBorder(welcomePane, "welcome"); JPanel proGuardPanel = new JPanel(layout); proGuardPanel.add(splashPanel, splashPanelConstraints); proGuardPanel.add(welcomePane, welcomePaneConstraints); // Create the input panel. // TODO: properly clone the ClassPath objects. // This is awkward to implement in the generic ListPanel.addElements(...) // method, since the Object.clone() method is not public. programPanel.addCopyToPanelButton("moveToLibraries", "moveToLibrariesTip", libraryPanel); libraryPanel.addCopyToPanelButton("moveToProgram", "moveToProgramTip", programPanel); // Collect all buttons of these panels and make sure they are equally // sized. List panelButtons = new ArrayList(); panelButtons.addAll(programPanel.getButtons()); panelButtons.addAll(libraryPanel.getButtons()); setCommonPreferredSize(panelButtons); addBorder(programPanel, "programJars" ); addBorder(libraryPanel, "libraryJars" ); JPanel inputOutputPanel = new JPanel(layout); inputOutputPanel.add(tip(programPanel, "programJarsTip"), stretchPanelConstraints); inputOutputPanel.add(tip(libraryPanel, "libraryJarsTip"), stretchPanelConstraints); // Load the boiler plate options. loadBoilerplateConfiguration(); // Create the boiler plate keep panels. boilerplateKeepCheckBoxes = new JCheckBox[boilerplateKeep.length]; boilerplateKeepTextFields = new JTextField[boilerplateKeep.length]; JButton printUsageBrowseButton = createBrowseButton(printUsageTextField, msg("selectUsageFile")); JPanel shrinkingOptionsPanel = new JPanel(layout); addBorder(shrinkingOptionsPanel, "options"); shrinkingOptionsPanel.add(tip(shrinkCheckBox, "shrinkTip"), constraintsLastStretch); shrinkingOptionsPanel.add(tip(printUsageCheckBox, "printUsageTip"), constraints); shrinkingOptionsPanel.add(tip(printUsageTextField, "outputFileTip"), constraintsStretch); shrinkingOptionsPanel.add(tip(printUsageBrowseButton, "selectUsageFile"), constraintsLast); JPanel shrinkingPanel = new JPanel(layout); shrinkingPanel.add(shrinkingOptionsPanel, panelConstraints); addClassSpecifications(extractClassSpecifications(boilerplateKeep), shrinkingPanel, boilerplateKeepCheckBoxes, boilerplateKeepTextFields); addBorder(additionalKeepPanel, "keepAdditional"); shrinkingPanel.add(tip(additionalKeepPanel, "keepAdditionalTip"), stretchPanelConstraints); // Create the boiler plate keep names panels. boilerplateKeepNamesCheckBoxes = new JCheckBox[boilerplateKeepNames.length]; boilerplateKeepNamesTextFields = new JTextField[boilerplateKeepNames.length]; JButton printMappingBrowseButton = createBrowseButton(printMappingTextField, msg("selectPrintMappingFile")); JButton applyMappingBrowseButton = createBrowseButton(applyMappingTextField, msg("selectApplyMappingFile")); JButton obfucationDictionaryBrowseButton = createBrowseButton(obfuscationDictionaryTextField, msg("selectObfuscationDictionaryFile")); JButton classObfucationDictionaryBrowseButton = createBrowseButton(classObfuscationDictionaryTextField, msg("selectObfuscationDictionaryFile")); JButton packageObfucationDictionaryBrowseButton = createBrowseButton(packageObfuscationDictionaryTextField, msg("selectObfuscationDictionaryFile")); JPanel obfuscationOptionsPanel = new JPanel(layout); addBorder(obfuscationOptionsPanel, "options"); obfuscationOptionsPanel.add(tip(obfuscateCheckBox, "obfuscateTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(printMappingCheckBox, "printMappingTip"), constraints); obfuscationOptionsPanel.add(tip(printMappingTextField, "outputFileTip"), constraintsStretch); obfuscationOptionsPanel.add(tip(printMappingBrowseButton, "selectPrintMappingFile"), constraintsLast); obfuscationOptionsPanel.add(tip(applyMappingCheckBox, "applyMappingTip"), constraints); obfuscationOptionsPanel.add(tip(applyMappingTextField, "inputFileTip"), constraintsStretch); obfuscationOptionsPanel.add(tip(applyMappingBrowseButton, "selectApplyMappingFile"), constraintsLast); obfuscationOptionsPanel.add(tip(obfuscationDictionaryCheckBox, "obfuscationDictionaryTip"), constraints); obfuscationOptionsPanel.add(tip(obfuscationDictionaryTextField, "inputFileTip"), constraintsStretch); obfuscationOptionsPanel.add(tip(obfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast); obfuscationOptionsPanel.add(tip(classObfuscationDictionaryCheckBox, "classObfuscationDictionaryTip"), constraints); obfuscationOptionsPanel.add(tip(classObfuscationDictionaryTextField, "inputFileTip"), constraintsStretch); obfuscationOptionsPanel.add(tip(classObfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast); obfuscationOptionsPanel.add(tip(packageObfuscationDictionaryCheckBox, "packageObfuscationDictionaryTip"), constraints); obfuscationOptionsPanel.add(tip(packageObfuscationDictionaryTextField, "inputFileTip"), constraintsStretch); obfuscationOptionsPanel.add(tip(packageObfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast); obfuscationOptionsPanel.add(tip(overloadAggressivelyCheckBox, "overloadAggressivelyTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(useUniqueClassMemberNamesCheckBox, "useUniqueClassMemberNamesTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(useMixedCaseClassNamesCheckBox, "useMixedCaseClassNamesTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(keepPackageNamesCheckBox, "keepPackageNamesTip"), constraints); obfuscationOptionsPanel.add(tip(keepPackageNamesTextField, "packageNamesTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(flattenPackageHierarchyCheckBox, "flattenPackageHierarchyTip"), constraints); obfuscationOptionsPanel.add(tip(flattenPackageHierarchyTextField, "packageTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(repackageClassesCheckBox, "repackageClassesTip"), constraints); obfuscationOptionsPanel.add(tip(repackageClassesTextField, "packageTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(keepAttributesCheckBox, "keepAttributesTip"), constraints); obfuscationOptionsPanel.add(tip(keepAttributesTextField, "attributesTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(keepParameterNamesCheckBox, "keepParameterNamesTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(newSourceFileAttributeCheckBox, "renameSourceFileAttributeTip"), constraints); obfuscationOptionsPanel.add(tip(newSourceFileAttributeTextField, "sourceFileAttributeTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(adaptClassStringsCheckBox, "adaptClassStringsTip"), constraints); obfuscationOptionsPanel.add(tip(adaptClassStringsTextField, "classNamesTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(adaptResourceFileNamesCheckBox, "adaptResourceFileNamesTip"), constraints); obfuscationOptionsPanel.add(tip(adaptResourceFileNamesTextField, "fileNameFilterTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(adaptResourceFileContentsCheckBox, "adaptResourceFileContentsTip"), constraints); obfuscationOptionsPanel.add(tip(adaptResourceFileContentsTextField, "fileNameFilterTip"), constraintsLastStretch); JPanel obfuscationPanel = new JPanel(layout); obfuscationPanel.add(obfuscationOptionsPanel, panelConstraints); addClassSpecifications(extractClassSpecifications(boilerplateKeepNames), obfuscationPanel, boilerplateKeepNamesCheckBoxes, boilerplateKeepNamesTextFields); addBorder(additionalKeepNamesPanel, "keepNamesAdditional"); obfuscationPanel.add(tip(additionalKeepNamesPanel, "keepNamesAdditionalTip"), stretchPanelConstraints); // Create the boiler plate "no side effect methods" panels. boilerplateNoSideEffectMethodCheckBoxes = new JCheckBox[boilerplateNoSideEffectMethods.length]; JPanel optimizationOptionsPanel = new JPanel(layout); addBorder(optimizationOptionsPanel, "options"); JButton optimizationsButton = createOptimizationsButton(optimizationsTextField); optimizationOptionsPanel.add(tip(optimizeCheckBox, "optimizeTip"), constraintsLastStretch); optimizationOptionsPanel.add(tip(allowAccessModificationCheckBox, "allowAccessModificationTip"), constraintsLastStretch); optimizationOptionsPanel.add(tip(mergeInterfacesAggressivelyCheckBox, "mergeInterfacesAggressivelyTip"), constraintsLastStretch); optimizationOptionsPanel.add(tip(optimizationsLabel, "optimizationsTip"), constraints); optimizationOptionsPanel.add(tip(optimizationsTextField, "optimizationsFilterTip"), constraintsStretch); optimizationOptionsPanel.add(tip(optimizationsButton, "optimizationsSelectTip"), constraintsLast); optimizationOptionsPanel.add(tip(optimizationPassesLabel, "optimizationPassesTip"), constraints); optimizationOptionsPanel.add(tip(optimizationPassesSpinner, "optimizationPassesTip"), constraintsLast); JPanel optimizationPanel = new JPanel(layout); optimizationPanel.add(optimizationOptionsPanel, panelConstraints); addClassSpecifications(boilerplateNoSideEffectMethods, optimizationPanel, boilerplateNoSideEffectMethodCheckBoxes, null); addBorder(additionalNoSideEffectsPanel, "assumeNoSideEffectsAdditional"); optimizationPanel.add(tip(additionalNoSideEffectsPanel, "assumeNoSideEffectsAdditionalTip"), stretchPanelConstraints); // Create the options panel. JPanel preverificationOptionsPanel = new JPanel(layout); addBorder(preverificationOptionsPanel, "preverificationAndTargeting"); preverificationOptionsPanel.add(tip(preverifyCheckBox, "preverifyTip"), constraintsLastStretch); preverificationOptionsPanel.add(tip(microEditionCheckBox, "microEditionTip"), constraintsLastStretch); preverificationOptionsPanel.add(tip(targetCheckBox, "targetTip"), constraints); preverificationOptionsPanel.add(tip(targetComboBox, "targetTip"), constraintsLast); JButton printSeedsBrowseButton = createBrowseButton(printSeedsTextField, msg("selectSeedsFile")); JButton printConfigurationBrowseButton = createBrowseButton(printConfigurationTextField, msg( "selectConfigurationFile")); JButton dumpBrowseButton = createBrowseButton(dumpTextField, msg("selectDumpFile")); // Select the most recent target by default. targetComboBox.setSelectedIndex(targetComboBox.getItemCount() - 1); JPanel consistencyPanel = new JPanel(layout); addBorder(consistencyPanel, "consistencyAndCorrectness"); consistencyPanel.add(tip(verboseCheckBox, "verboseTip"), constraintsLastStretch); consistencyPanel.add(tip(noteCheckBox, "noteTip"), constraints); consistencyPanel.add(tip(noteTextField, "noteFilterTip"), constraintsLastStretch); consistencyPanel.add(tip(warnCheckBox, "warnTip"), constraints); consistencyPanel.add(tip(warnTextField, "warnFilterTip"), constraintsLastStretch); consistencyPanel.add(tip(ignoreWarningsCheckBox, "ignoreWarningsTip"), constraintsLastStretch); consistencyPanel.add(tip(skipNonPublicLibraryClassesCheckBox, "skipNonPublicLibraryClassesTip"), constraintsLastStretch); consistencyPanel.add(tip(skipNonPublicLibraryClassMembersCheckBox, "skipNonPublicLibraryClassMembersTip"), constraintsLastStretch); consistencyPanel.add(tip(keepDirectoriesCheckBox, "keepDirectoriesTip"), constraints); consistencyPanel.add(tip(keepDirectoriesTextField, "directoriesTip"), constraintsLastStretch); consistencyPanel.add(tip(forceProcessingCheckBox, "forceProcessingTip"), constraintsLastStretch); consistencyPanel.add(tip(printSeedsCheckBox, "printSeedsTip"), constraints); consistencyPanel.add(tip(printSeedsTextField, "outputFileTip"), constraintsStretch); consistencyPanel.add(tip(printSeedsBrowseButton, "selectSeedsFile"), constraintsLast); consistencyPanel.add(tip(printConfigurationCheckBox, "printConfigurationTip"), constraints); consistencyPanel.add(tip(printConfigurationTextField, "outputFileTip"), constraintsStretch); consistencyPanel.add(tip(printConfigurationBrowseButton, "selectConfigurationFile"), constraintsLast); consistencyPanel.add(tip(dumpCheckBox, "dumpTip"), constraints); consistencyPanel.add(tip(dumpTextField, "outputFileTip"), constraintsStretch); consistencyPanel.add(tip(dumpBrowseButton, "selectDumpFile"), constraintsLast); // Collect all components that are followed by text fields and make // sure they are equally sized. That way the text fields start at the // same horizontal position. setCommonPreferredSize(Arrays.asList(new JComponent[] { printMappingCheckBox, applyMappingCheckBox, flattenPackageHierarchyCheckBox, repackageClassesCheckBox, newSourceFileAttributeCheckBox, })); JPanel optionsPanel = new JPanel(layout); optionsPanel.add(preverificationOptionsPanel, panelConstraints); optionsPanel.add(consistencyPanel, panelConstraints); addBorder(whyAreYouKeepingPanel, "whyAreYouKeeping"); optionsPanel.add(tip(whyAreYouKeepingPanel, "whyAreYouKeepingTip"), stretchPanelConstraints); // Create the process panel. consoleTextArea.setOpaque(false); consoleTextArea.setEditable(false); consoleTextArea.setLineWrap(false); consoleTextArea.setWrapStyleWord(false); JScrollPane consoleScrollPane = new JScrollPane(consoleTextArea); consoleScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1)); addBorder(consoleScrollPane, "processingConsole"); JPanel processPanel = new JPanel(layout); processPanel.add(consoleScrollPane, stretchPanelConstraints); // Create the load, save, and process buttons. JButton loadButton = new JButton(msg("loadConfiguration")); loadButton.addActionListener(new MyLoadConfigurationActionListener()); JButton viewButton = new JButton(msg("viewConfiguration")); viewButton.addActionListener(new MyViewConfigurationActionListener()); JButton saveButton = new JButton(msg("saveConfiguration")); saveButton.addActionListener(new MySaveConfigurationActionListener()); JButton processButton = new JButton(msg("process")); processButton.addActionListener(new MyProcessActionListener()); // Create the ReTrace panel. JPanel reTraceSettingsPanel = new JPanel(layout); addBorder(reTraceSettingsPanel, "reTraceSettings"); JButton reTraceMappingBrowseButton = createBrowseButton(reTraceMappingTextField, msg("selectApplyMappingFile")); JLabel reTraceMappingLabel = new JLabel(msg("mappingFile")); reTraceMappingLabel.setForeground(reTraceVerboseCheckBox.getForeground()); reTraceSettingsPanel.add(tip(reTraceVerboseCheckBox, "verboseTip"), constraintsLastStretch); reTraceSettingsPanel.add(tip(reTraceMappingLabel, "mappingFileTip"), constraints); reTraceSettingsPanel.add(tip(reTraceMappingTextField, "inputFileTip"), constraintsStretch); reTraceSettingsPanel.add(tip(reTraceMappingBrowseButton, "selectApplyMappingFile"), constraintsLast); stackTraceTextArea.setOpaque(true); stackTraceTextArea.setEditable(true); stackTraceTextArea.setLineWrap(false); stackTraceTextArea.setWrapStyleWord(true); JScrollPane stackTraceScrollPane = new JScrollPane(stackTraceTextArea); addBorder(stackTraceScrollPane, "obfuscatedStackTrace"); reTraceTextArea.setOpaque(false); reTraceTextArea.setEditable(false); reTraceTextArea.setLineWrap(true); reTraceTextArea.setWrapStyleWord(true); JScrollPane reTraceScrollPane = new JScrollPane(reTraceTextArea); reTraceScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1)); addBorder(reTraceScrollPane, "deobfuscatedStackTrace"); JPanel reTracePanel = new JPanel(layout); reTracePanel.add(reTraceSettingsPanel, panelConstraints); reTracePanel.add(tip(stackTraceScrollPane, "obfuscatedStackTraceTip"), panelConstraints); reTracePanel.add(reTraceScrollPane, stretchPanelConstraints); // Create the load button. JButton loadStackTraceButton = new JButton(msg("loadStackTrace")); loadStackTraceButton.addActionListener(new MyLoadStackTraceActionListener()); JButton reTraceButton = new JButton(msg("reTrace")); reTraceButton.addActionListener(new MyReTraceActionListener()); // Create the main tabbed pane. TabbedPane tabs = new TabbedPane(); tabs.add(msg("proGuardTab"), proGuardPanel); tabs.add(msg("inputOutputTab"), inputOutputPanel); tabs.add(msg("shrinkingTab"), shrinkingPanel); tabs.add(msg("obfuscationTab"), obfuscationPanel); tabs.add(msg("optimizationTab"), optimizationPanel); tabs.add(msg("informationTab"), optionsPanel); tabs.add(msg("processTab"), processPanel); tabs.add(msg("reTraceTab"), reTracePanel); tabs.addImage(Toolkit.getDefaultToolkit().getImage( this.getClass().getResource(TITLE_IMAGE_FILE))); // Add the bottom buttons to each panel. proGuardPanel .add(Box.createGlue(), glueConstraints); proGuardPanel .add(tip(loadButton, "loadConfigurationTip"), bottomButtonConstraints); proGuardPanel .add(createNextButton(tabs), lastBottomButtonConstraints); inputOutputPanel .add(Box.createGlue(), glueConstraints); inputOutputPanel .add(createPreviousButton(tabs), bottomButtonConstraints); inputOutputPanel .add(createNextButton(tabs), lastBottomButtonConstraints); shrinkingPanel .add(Box.createGlue(), glueConstraints); shrinkingPanel .add(createPreviousButton(tabs), bottomButtonConstraints); shrinkingPanel .add(createNextButton(tabs), lastBottomButtonConstraints); obfuscationPanel .add(Box.createGlue(), glueConstraints); obfuscationPanel .add(createPreviousButton(tabs), bottomButtonConstraints); obfuscationPanel .add(createNextButton(tabs), lastBottomButtonConstraints); optimizationPanel .add(Box.createGlue(), glueConstraints); optimizationPanel .add(createPreviousButton(tabs), bottomButtonConstraints); optimizationPanel .add(createNextButton(tabs), lastBottomButtonConstraints); optionsPanel .add(Box.createGlue(), glueConstraints); optionsPanel .add(createPreviousButton(tabs), bottomButtonConstraints); optionsPanel .add(createNextButton(tabs), lastBottomButtonConstraints); processPanel .add(Box.createGlue(), glueConstraints); processPanel .add(createPreviousButton(tabs), bottomButtonConstraints); processPanel .add(tip(viewButton, "viewConfigurationTip"), bottomButtonConstraints); processPanel .add(tip(saveButton, "saveConfigurationTip"), bottomButtonConstraints); processPanel .add(tip(processButton, "processTip"), lastBottomButtonConstraints); reTracePanel .add(Box.createGlue(), glueConstraints); reTracePanel .add(tip(loadStackTraceButton, "loadStackTraceTip"), bottomButtonConstraints); reTracePanel .add(tip(reTraceButton, "reTraceTip"), lastBottomButtonConstraints); // Initialize the GUI settings to reasonable defaults. loadConfiguration(this.getClass().getResource(DEFAULT_CONFIGURATION)); // Add the main tabs to the frame and pack it. getContentPane().add(tabs); } public void startSplash() { splashPanel.start(); } public void skipSplash() { splashPanel.stop(); } /** * Loads the boilerplate keep class options from the boilerplate file * into the boilerplate array. */ private void loadBoilerplateConfiguration() { try { // Parse the boilerplate configuration file. ConfigurationParser parser = new ConfigurationParser( this.getClass().getResource(BOILERPLATE_CONFIGURATION), System.getProperties()); Configuration configuration = new Configuration(); try { parser.parse(configuration); // We're interested in the keep options. boilerplateKeep = extractKeepSpecifications(configuration.keep, false, false); // We're interested in the keep options. boilerplateKeepNames = extractKeepSpecifications(configuration.keep, true, false); // We're interested in the side effects options. boilerplateNoSideEffectMethods = new ClassSpecification[configuration.assumeNoSideEffects.size()]; configuration.assumeNoSideEffects.toArray(boilerplateNoSideEffectMethods); } finally { parser.close(); } } catch (Exception ex) { ex.printStackTrace(); } } /** * Returns an array containing the ClassSpecifications instances with * matching flags. */ private KeepClassSpecification[] extractKeepSpecifications(List keepSpecifications, boolean allowShrinking, boolean allowObfuscation) { List matches = new ArrayList(); for (int index = 0; index < keepSpecifications.size(); index++) { KeepClassSpecification keepClassSpecification = (KeepClassSpecification)keepSpecifications.get(index); if (keepClassSpecification.allowShrinking == allowShrinking && keepClassSpecification.allowObfuscation == allowObfuscation) { matches.add(keepClassSpecification); } } KeepClassSpecification[] matchingKeepClassSpecifications = new KeepClassSpecification[matches.size()]; matches.toArray(matchingKeepClassSpecifications); return matchingKeepClassSpecifications; } /** * Returns an array containing the ClassSpecification instances of the * given array of KeepClassSpecification instances. */ private ClassSpecification[] extractClassSpecifications(KeepClassSpecification[] keepClassSpecifications) { ClassSpecification[] classSpecifications = new ClassSpecification[keepClassSpecifications.length]; for (int index = 0; index < classSpecifications.length; index++) { classSpecifications[index] = keepClassSpecifications[index]; } return classSpecifications; } /** * Creates a panel with the given boiler plate class specifications. */ private void addClassSpecifications(ClassSpecification[] boilerplateClassSpecifications, JPanel classSpecificationsPanel, JCheckBox[] boilerplateCheckBoxes, JTextField[] boilerplateTextFields) { // Create some constraints that can be reused. GridBagConstraints constraints = new GridBagConstraints(); constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(0, 4, 0, 4); GridBagConstraints constraintsLastStretch = new GridBagConstraints(); constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER; constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL; constraintsLastStretch.weightx = 1.0; constraintsLastStretch.anchor = GridBagConstraints.WEST; constraintsLastStretch.insets = constraints.insets; GridBagConstraints panelConstraints = new GridBagConstraints(); panelConstraints.gridwidth = GridBagConstraints.REMAINDER; panelConstraints.fill = GridBagConstraints.HORIZONTAL; panelConstraints.weightx = 1.0; panelConstraints.anchor = GridBagConstraints.NORTHWEST; panelConstraints.insets = constraints.insets; GridBagLayout layout = new GridBagLayout(); String lastPanelName = null; JPanel keepSubpanel = null; for (int index = 0; index < boilerplateClassSpecifications.length; index++) { // The panel structure is derived from the comments. String comments = boilerplateClassSpecifications[index].comments; int dashIndex = comments.indexOf('-'); int periodIndex = comments.indexOf('.', dashIndex); String panelName = comments.substring(0, dashIndex).trim(); String optionName = comments.substring(dashIndex + 1, periodIndex).replace('_', '.').trim(); String toolTip = comments.substring(periodIndex + 1); if (keepSubpanel == null || !panelName.equals(lastPanelName)) { // Create a new keep subpanel and add it. keepSubpanel = new JPanel(layout); keepSubpanel.setBorder(BorderFactory.createTitledBorder(BORDER, panelName)); classSpecificationsPanel.add(keepSubpanel, panelConstraints); lastPanelName = panelName; } // Add the check box to the subpanel. JCheckBox boilerplateCheckBox = new JCheckBox(optionName); boilerplateCheckBox.setToolTipText(toolTip); boilerplateCheckBoxes[index] = boilerplateCheckBox; keepSubpanel.add(boilerplateCheckBox, boilerplateTextFields != null ? constraints : constraintsLastStretch); if (boilerplateTextFields != null) { // Add the text field to the subpanel. boilerplateTextFields[index] = new JTextField(40); keepSubpanel.add(tip(boilerplateTextFields[index], "classNamesTip"), constraintsLastStretch); } } } /** * Adds a standard border with the title that corresponds to the given key * in the GUI resources. */ private void addBorder(JComponent component, String titleKey) { Border oldBorder = component.getBorder(); Border newBorder = BorderFactory.createTitledBorder(BORDER, msg(titleKey)); component.setBorder(oldBorder == null ? newBorder : new CompoundBorder(newBorder, oldBorder)); } /** * Creates a Previous button for the given tabbed pane. */ private JButton createPreviousButton(final TabbedPane tabbedPane) { JButton browseButton = new JButton(msg("previous")); browseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { tabbedPane.previous(); } }); return browseButton; } /** * Creates a Next button for the given tabbed pane. */ private JButton createNextButton(final TabbedPane tabbedPane) { JButton browseButton = new JButton(msg("next")); browseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { tabbedPane.next(); } }); return browseButton; } /** * Creates a browse button that opens a file browser for the given text field. */ private JButton createBrowseButton(final JTextField textField, final String title) { JButton browseButton = new JButton(msg("browse")); browseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Update the file chooser. fileChooser.setDialogTitle(title); fileChooser.setSelectedFile(new File(textField.getText())); int returnVal = fileChooser.showDialog(ProGuardGUI.this, msg("ok")); if (returnVal == JFileChooser.APPROVE_OPTION) { // Update the text field. textField.setText(fileChooser.getSelectedFile().getPath()); } } }); return browseButton; } protected JButton createOptimizationsButton(final JTextField textField) { final OptimizationsDialog optimizationsDialog = new OptimizationsDialog(ProGuardGUI.this); JButton optimizationsButton = new JButton(msg("select")); optimizationsButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Update the dialog. optimizationsDialog.setFilter(textField.getText()); int returnValue = optimizationsDialog.showDialog(); if (returnValue == OptimizationsDialog.APPROVE_OPTION) { // Update the text field. textField.setText(optimizationsDialog.getFilter()); } } }); return optimizationsButton; } /** * Sets the preferred sizes of the given components to the maximum of their * current preferred sizes. */ private void setCommonPreferredSize(List components) { // Find the maximum preferred size. Dimension maximumSize = null; for (int index = 0; index < components.size(); index++) { JComponent component = (JComponent)components.get(index); Dimension size = component.getPreferredSize(); if (maximumSize == null || size.getWidth() > maximumSize.getWidth()) { maximumSize = size; } } // Set the size that we found as the preferred size for all components. for (int index = 0; index < components.size(); index++) { JComponent component = (JComponent)components.get(index); component.setPreferredSize(maximumSize); } } /** * Updates to GUI settings to reflect the given ProGuard configuration. */ private void setProGuardConfiguration(Configuration configuration) { // Set up the input and output jars and directories. programPanel.setClassPath(configuration.programJars); libraryPanel.setClassPath(configuration.libraryJars); // Set up the boilerplate keep options. for (int index = 0; index < boilerplateKeep.length; index++) { String classNames = findMatchingKeepSpecifications(boilerplateKeep[index], configuration.keep); boilerplateKeepCheckBoxes[index].setSelected(classNames != null); boilerplateKeepTextFields[index].setText(classNames == null ? "*" : classNames); } // Set up the boilerplate keep names options. for (int index = 0; index < boilerplateKeepNames.length; index++) { String classNames = findMatchingKeepSpecifications(boilerplateKeepNames[index], configuration.keep); boilerplateKeepNamesCheckBoxes[index].setSelected(classNames != null); boilerplateKeepNamesTextFields[index].setText(classNames == null ? "*" : classNames); } // Set up the additional keep options. Note that the matched boilerplate // options have been removed from the list. additionalKeepPanel.setClassSpecifications(filteredKeepSpecifications(configuration.keep, false)); // Set up the additional keep options. Note that the matched boilerplate // options have been removed from the list. additionalKeepNamesPanel.setClassSpecifications(filteredKeepSpecifications(configuration.keep, true)); // Set up the boilerplate "no side effect methods" options. for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++) { boolean found = findClassSpecification(boilerplateNoSideEffectMethods[index], configuration.assumeNoSideEffects); boilerplateNoSideEffectMethodCheckBoxes[index].setSelected(found); } // Set up the additional keep options. Note that the matched boilerplate // options have been removed from the list. additionalNoSideEffectsPanel.setClassSpecifications(configuration.assumeNoSideEffects); // Set up the "why are you keeping" options. whyAreYouKeepingPanel.setClassSpecifications(configuration.whyAreYouKeeping); // Set up the other options. shrinkCheckBox .setSelected(configuration.shrink); printUsageCheckBox .setSelected(configuration.printUsage != null); optimizeCheckBox .setSelected(configuration.optimize); allowAccessModificationCheckBox .setSelected(configuration.allowAccessModification); mergeInterfacesAggressivelyCheckBox .setSelected(configuration.mergeInterfacesAggressively); optimizationPassesSpinner.getModel() .setValue(new Integer(configuration.optimizationPasses)); obfuscateCheckBox .setSelected(configuration.obfuscate); printMappingCheckBox .setSelected(configuration.printMapping != null); applyMappingCheckBox .setSelected(configuration.applyMapping != null); obfuscationDictionaryCheckBox .setSelected(configuration.obfuscationDictionary != null); classObfuscationDictionaryCheckBox .setSelected(configuration.classObfuscationDictionary != null); packageObfuscationDictionaryCheckBox .setSelected(configuration.packageObfuscationDictionary != null); overloadAggressivelyCheckBox .setSelected(configuration.overloadAggressively); useUniqueClassMemberNamesCheckBox .setSelected(configuration.useUniqueClassMemberNames); useMixedCaseClassNamesCheckBox .setSelected(configuration.useMixedCaseClassNames); keepPackageNamesCheckBox .setSelected(configuration.keepPackageNames != null); flattenPackageHierarchyCheckBox .setSelected(configuration.flattenPackageHierarchy != null); repackageClassesCheckBox .setSelected(configuration.repackageClasses != null); keepAttributesCheckBox .setSelected(configuration.keepAttributes != null); keepParameterNamesCheckBox .setSelected(configuration.keepParameterNames); newSourceFileAttributeCheckBox .setSelected(configuration.newSourceFileAttribute != null); adaptClassStringsCheckBox .setSelected(configuration.adaptClassStrings != null); adaptResourceFileNamesCheckBox .setSelected(configuration.adaptResourceFileNames != null); adaptResourceFileContentsCheckBox .setSelected(configuration.adaptResourceFileContents != null); preverifyCheckBox .setSelected(configuration.preverify); microEditionCheckBox .setSelected(configuration.microEdition); targetCheckBox .setSelected(configuration.targetClassVersion != 0); verboseCheckBox .setSelected(configuration.verbose); noteCheckBox .setSelected(configuration.note == null || !configuration.note.isEmpty()); warnCheckBox .setSelected(configuration.warn == null || !configuration.warn.isEmpty()); ignoreWarningsCheckBox .setSelected(configuration.ignoreWarnings); skipNonPublicLibraryClassesCheckBox .setSelected(configuration.skipNonPublicLibraryClasses); skipNonPublicLibraryClassMembersCheckBox.setSelected(configuration.skipNonPublicLibraryClassMembers); keepDirectoriesCheckBox .setSelected(configuration.keepDirectories != null); forceProcessingCheckBox .setSelected(configuration.lastModified == Long.MAX_VALUE); printSeedsCheckBox .setSelected(configuration.printSeeds != null); printConfigurationCheckBox .setSelected(configuration.printConfiguration != null); dumpCheckBox .setSelected(configuration.dump != null); printUsageTextField .setText(fileName(configuration.printUsage)); optimizationsTextField .setText(configuration.optimizations == null ? OPTIMIZATIONS_DEFAULT : ListUtil.commaSeparatedString(configuration.optimizations, true)); printMappingTextField .setText(fileName(configuration.printMapping)); applyMappingTextField .setText(fileName(configuration.applyMapping)); obfuscationDictionaryTextField .setText(fileName(configuration.obfuscationDictionary)); classObfuscationDictionaryTextField .setText(fileName(configuration.classObfuscationDictionary)); packageObfuscationDictionaryTextField .setText(fileName(configuration.packageObfuscationDictionary)); keepPackageNamesTextField .setText(configuration.keepPackageNames == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.keepPackageNames, true))); flattenPackageHierarchyTextField .setText(configuration.flattenPackageHierarchy); repackageClassesTextField .setText(configuration.repackageClasses); keepAttributesTextField .setText(configuration.keepAttributes == null ? KEEP_ATTRIBUTE_DEFAULT : ListUtil.commaSeparatedString(configuration.keepAttributes, true)); newSourceFileAttributeTextField .setText(configuration.newSourceFileAttribute == null ? SOURCE_FILE_ATTRIBUTE_DEFAULT : configuration.newSourceFileAttribute); adaptClassStringsTextField .setText(configuration.adaptClassStrings == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.adaptClassStrings, true))); adaptResourceFileNamesTextField .setText(configuration.adaptResourceFileNames == null ? ADAPT_RESOURCE_FILE_NAMES_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileNames, true)); adaptResourceFileContentsTextField .setText(configuration.adaptResourceFileContents == null ? ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileContents, true)); noteTextField .setText(ListUtil.commaSeparatedString(configuration.note, true)); warnTextField .setText(ListUtil.commaSeparatedString(configuration.warn, true)); keepDirectoriesTextField .setText(ListUtil.commaSeparatedString(configuration.keepDirectories, true)); printSeedsTextField .setText(fileName(configuration.printSeeds)); printConfigurationTextField .setText(fileName(configuration.printConfiguration)); dumpTextField .setText(fileName(configuration.dump)); if (configuration.targetClassVersion != 0) { targetComboBox.setSelectedItem(ClassUtil.externalClassVersion(configuration.targetClassVersion)); } else { targetComboBox.setSelectedIndex(targetComboBox.getItemCount() - 1); } if (configuration.printMapping != null) { reTraceMappingTextField.setText(fileName(configuration.printMapping)); } } /** * Returns the ProGuard configuration that reflects the current GUI settings. */ private Configuration getProGuardConfiguration() { Configuration configuration = new Configuration(); // Get the input and output jars and directories. configuration.programJars = programPanel.getClassPath(); configuration.libraryJars = libraryPanel.getClassPath(); List keep = new ArrayList(); // Collect the additional keep options. List additionalKeep = additionalKeepPanel.getClassSpecifications(); if (additionalKeep != null) { keep.addAll(additionalKeep); } // Collect the additional keep names options. List additionalKeepNames = additionalKeepNamesPanel.getClassSpecifications(); if (additionalKeepNames != null) { keep.addAll(additionalKeepNames); } // Collect the boilerplate keep options. for (int index = 0; index < boilerplateKeep.length; index++) { if (boilerplateKeepCheckBoxes[index].isSelected()) { keep.add(classSpecification(boilerplateKeep[index], boilerplateKeepTextFields[index].getText())); } } // Collect the boilerplate keep names options. for (int index = 0; index < boilerplateKeepNames.length; index++) { if (boilerplateKeepNamesCheckBoxes[index].isSelected()) { keep.add(classSpecification(boilerplateKeepNames[index], boilerplateKeepNamesTextFields[index].getText())); } } // Put the list of keep specifications in the configuration. if (keep.size() > 0) { configuration.keep = keep; } // Collect the boilerplate "no side effect methods" options. List noSideEffectMethods = new ArrayList(); for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++) { if (boilerplateNoSideEffectMethodCheckBoxes[index].isSelected()) { noSideEffectMethods.add(boilerplateNoSideEffectMethods[index]); } } // Collect the additional "no side effect methods" options. List additionalNoSideEffectOptions = additionalNoSideEffectsPanel.getClassSpecifications(); if (additionalNoSideEffectOptions != null) { noSideEffectMethods.addAll(additionalNoSideEffectOptions); } // Put the list of "no side effect methods" options in the configuration. if (noSideEffectMethods.size() > 0) { configuration.assumeNoSideEffects = noSideEffectMethods; } // Collect the "why are you keeping" options. configuration.whyAreYouKeeping = whyAreYouKeepingPanel.getClassSpecifications(); // Get the other options. configuration.shrink = shrinkCheckBox .isSelected(); configuration.printUsage = printUsageCheckBox .isSelected() ? new File(printUsageTextField .getText()) : null; configuration.optimize = optimizeCheckBox .isSelected(); configuration.allowAccessModification = allowAccessModificationCheckBox .isSelected(); configuration.mergeInterfacesAggressively = mergeInterfacesAggressivelyCheckBox .isSelected(); configuration.optimizations = optimizationsTextField.getText().length() > 1 ? ListUtil.commaSeparatedList(optimizationsTextField .getText()) : null; configuration.optimizationPasses = ((SpinnerNumberModel)optimizationPassesSpinner.getModel()).getNumber().intValue(); configuration.obfuscate = obfuscateCheckBox .isSelected(); configuration.printMapping = printMappingCheckBox .isSelected() ? new File(printMappingTextField .getText()) : null; configuration.applyMapping = applyMappingCheckBox .isSelected() ? new File(applyMappingTextField .getText()) : null; configuration.obfuscationDictionary = obfuscationDictionaryCheckBox .isSelected() ? new File(obfuscationDictionaryTextField .getText()) : null; configuration.classObfuscationDictionary = classObfuscationDictionaryCheckBox .isSelected() ? new File(classObfuscationDictionaryTextField .getText()) : null; configuration.packageObfuscationDictionary = packageObfuscationDictionaryCheckBox .isSelected() ? new File(packageObfuscationDictionaryTextField .getText()) : null; configuration.overloadAggressively = overloadAggressivelyCheckBox .isSelected(); configuration.useUniqueClassMemberNames = useUniqueClassMemberNamesCheckBox .isSelected(); configuration.useMixedCaseClassNames = useMixedCaseClassNamesCheckBox .isSelected(); configuration.keepPackageNames = keepPackageNamesCheckBox .isSelected() ? keepPackageNamesTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(keepPackageNamesTextField.getText())) : new ArrayList() : null; configuration.flattenPackageHierarchy = flattenPackageHierarchyCheckBox .isSelected() ? ClassUtil.internalClassName(flattenPackageHierarchyTextField .getText()) : null; configuration.repackageClasses = repackageClassesCheckBox .isSelected() ? ClassUtil.internalClassName(repackageClassesTextField .getText()) : null; configuration.keepAttributes = keepAttributesCheckBox .isSelected() ? ListUtil.commaSeparatedList(keepAttributesTextField .getText()) : null; configuration.keepParameterNames = keepParameterNamesCheckBox .isSelected(); configuration.newSourceFileAttribute = newSourceFileAttributeCheckBox .isSelected() ? newSourceFileAttributeTextField .getText() : null; configuration.adaptClassStrings = adaptClassStringsCheckBox .isSelected() ? adaptClassStringsTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(adaptClassStringsTextField.getText())) : new ArrayList() : null; configuration.adaptResourceFileNames = adaptResourceFileNamesCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileNamesTextField .getText()) : null; configuration.adaptResourceFileContents = adaptResourceFileContentsCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileContentsTextField .getText()) : null; configuration.preverify = preverifyCheckBox .isSelected(); configuration.microEdition = microEditionCheckBox .isSelected(); configuration.targetClassVersion = targetCheckBox .isSelected() ? ClassUtil.internalClassVersion(targetComboBox.getSelectedItem().toString()) : 0; configuration.verbose = verboseCheckBox .isSelected(); configuration.note = noteCheckBox .isSelected() ? noteTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(noteTextField.getText())) : null : new ArrayList(); configuration.warn = warnCheckBox .isSelected() ? warnTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(warnTextField.getText())) : null : new ArrayList(); configuration.ignoreWarnings = ignoreWarningsCheckBox .isSelected(); configuration.skipNonPublicLibraryClasses = skipNonPublicLibraryClassesCheckBox .isSelected(); configuration.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembersCheckBox.isSelected(); configuration.keepDirectories = keepDirectoriesCheckBox .isSelected() ? keepDirectoriesTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(keepDirectoriesTextField.getText())) : new ArrayList() : null; configuration.lastModified = forceProcessingCheckBox .isSelected() ? Long.MAX_VALUE : System.currentTimeMillis(); configuration.printSeeds = printSeedsCheckBox .isSelected() ? new File(printSeedsTextField .getText()) : null; configuration.printConfiguration = printConfigurationCheckBox .isSelected() ? new File(printConfigurationTextField .getText()) : null; configuration.dump = dumpCheckBox .isSelected() ? new File(dumpTextField .getText()) : null; return configuration; } /** * Looks in the given list for a class specification that is identical to * the given template. Returns true if it is found, and removes the matching * class specification as a side effect. */ private boolean findClassSpecification(ClassSpecification classSpecificationTemplate, List classSpecifications) { if (classSpecifications == null) { return false; } for (int index = 0; index < classSpecifications.size(); index++) { if (classSpecificationTemplate.equals(classSpecifications.get(index))) { // Remove the matching option as a side effect. classSpecifications.remove(index); return true; } } return false; } /** * Returns the subset of the given list of keep specifications, with * matching shrinking flag. */ private List filteredKeepSpecifications(List keepSpecifications, boolean allowShrinking) { List filteredKeepSpecifications = new ArrayList(); for (int index = 0; index < keepSpecifications.size(); index++) { KeepClassSpecification keepClassSpecification = (KeepClassSpecification)keepSpecifications.get(index); if (keepClassSpecification.allowShrinking == allowShrinking) { filteredKeepSpecifications.add(keepClassSpecification); } } return filteredKeepSpecifications; } /** * Looks in the given list for keep specifications that match the given * template. Returns a comma-separated string of class names from * matching keep specifications, and removes the matching keep * specifications as a side effect. */ private String findMatchingKeepSpecifications(KeepClassSpecification keepClassSpecificationTemplate, List keepSpecifications) { if (keepSpecifications == null) { return null; } StringBuffer buffer = null; for (int index = 0; index < keepSpecifications.size(); index++) { KeepClassSpecification listedKeepClassSpecification = (KeepClassSpecification)keepSpecifications.get(index); String className = listedKeepClassSpecification.className; keepClassSpecificationTemplate.className = className; if (keepClassSpecificationTemplate.equals(listedKeepClassSpecification)) { if (buffer == null) { buffer = new StringBuffer(); } else { buffer.append(','); } buffer.append(className == null ? "*" : ClassUtil.externalClassName(className)); // Remove the matching option as a side effect. keepSpecifications.remove(index--); } } return buffer == null ? null : buffer.toString(); } /** * Returns a class specification or keep specification, based on the given * template and the class name to be filled in. */ private ClassSpecification classSpecification(ClassSpecification classSpecificationTemplate, String className) { // Create a copy of the template. ClassSpecification classSpecification = (ClassSpecification)classSpecificationTemplate.clone(); // Set the class name in the copy. classSpecification.className = className.equals("") || className.equals("*") ? null : ClassUtil.internalClassName(className); // Return the modified copy. return classSpecification; } // Methods and internal classes related to actions. /** * Loads the given ProGuard configuration into the GUI. */ private void loadConfiguration(File file) { // Set the default directory and file in the file choosers. configurationChooser.setSelectedFile(file.getAbsoluteFile()); fileChooser.setCurrentDirectory(file.getAbsoluteFile().getParentFile()); try { // Parse the configuration file. ConfigurationParser parser = new ConfigurationParser(file, System.getProperties()); Configuration configuration = new Configuration(); try { parser.parse(configuration); // Let the GUI reflect the configuration. setProGuardConfiguration(configuration); } catch (ParseException ex) { JOptionPane.showMessageDialog(getContentPane(), msg("cantParseConfigurationFile", file.getPath()), msg("warning"), JOptionPane.ERROR_MESSAGE); } finally { parser.close(); } } catch (IOException ex) { JOptionPane.showMessageDialog(getContentPane(), msg("cantOpenConfigurationFile", file.getPath()), msg("warning"), JOptionPane.ERROR_MESSAGE); } } /** * Loads the given ProGuard configuration into the GUI. */ private void loadConfiguration(URL url) { try { // Parse the configuration file. ConfigurationParser parser = new ConfigurationParser(url, System.getProperties()); Configuration configuration = new Configuration(); try { parser.parse(configuration); // Let the GUI reflect the configuration. setProGuardConfiguration(configuration); } catch (ParseException ex) { JOptionPane.showMessageDialog(getContentPane(), msg("cantParseConfigurationFile", url), msg("warning"), JOptionPane.ERROR_MESSAGE); } finally { parser.close(); } } catch (IOException ex) { JOptionPane.showMessageDialog(getContentPane(), msg("cantOpenConfigurationFile", url), msg("warning"), JOptionPane.ERROR_MESSAGE); } } /** * Saves the current ProGuard configuration to the given file. */ private void saveConfiguration(File file) { try { // Save the configuration file. ConfigurationWriter writer = new ConfigurationWriter(file); writer.write(getProGuardConfiguration()); writer.close(); } catch (Exception ex) { JOptionPane.showMessageDialog(getContentPane(), msg("cantSaveConfigurationFile", file.getPath()), msg("warning"), JOptionPane.ERROR_MESSAGE); } } /** * Loads the given stack trace into the GUI. */ private void loadStackTrace(File file) { try { StringBuffer buffer = new StringBuffer(1024); Reader reader = new BufferedReader(new FileReader(file)); try { while (true) { int c = reader.read(); if (c < 0) { break; } buffer.append(c); } } finally { reader.close(); } // Put the stack trace in the text area. stackTraceTextArea.setText(buffer.toString()); } catch (IOException ex) { JOptionPane.showMessageDialog(getContentPane(), msg("cantOpenStackTraceFile", fileName(file)), msg("warning"), JOptionPane.ERROR_MESSAGE); } } /** * This ActionListener loads a ProGuard configuration file and initializes * the GUI accordingly. */ private class MyLoadConfigurationActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { configurationChooser.setDialogTitle(msg("selectConfigurationFile")); int returnValue = configurationChooser.showOpenDialog(ProGuardGUI.this); if (returnValue == JFileChooser.APPROVE_OPTION) { loadConfiguration(configurationChooser.getSelectedFile()); } } } /** * This ActionListener saves a ProGuard configuration file based on the * current GUI settings. */ private class MySaveConfigurationActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { configurationChooser.setDialogTitle(msg("saveConfigurationFile")); int returnVal = configurationChooser.showSaveDialog(ProGuardGUI.this); if (returnVal == JFileChooser.APPROVE_OPTION) { saveConfiguration(configurationChooser.getSelectedFile()); } } } /** * This ActionListener displays the ProGuard configuration specified by the * current GUI settings. */ private class MyViewConfigurationActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Make sure System.out has not been redirected yet. if (!systemOutRedirected) { consoleTextArea.setText(""); TextAreaOutputStream outputStream = new TextAreaOutputStream(consoleTextArea); try { // TODO: write out relative path names and path names with system properties. // Write the configuration. ConfigurationWriter writer = new ConfigurationWriter(outputStream); try { writer.write(getProGuardConfiguration()); } finally { writer.close(); } } catch (IOException ex) { // This shouldn't happen. } // Scroll to the top of the configuration. consoleTextArea.setCaretPosition(0); } } } /** * This ActionListener executes ProGuard based on the current GUI settings. */ private class MyProcessActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Make sure System.out has not been redirected yet. if (!systemOutRedirected) { systemOutRedirected = true; // Get the informational configuration file name. File configurationFile = configurationChooser.getSelectedFile(); String configurationFileName = configurationFile != null ? configurationFile.getName() : msg("sampleConfigurationFileName"); // Create the ProGuard thread. Thread proGuardThread = new Thread(new ProGuardRunnable(consoleTextArea, getProGuardConfiguration(), configurationFileName)); // Run it. proGuardThread.start(); } } } /** * This ActionListener loads an obfuscated stack trace from a file and puts * it in the proper text area. */ private class MyLoadStackTraceActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { fileChooser.setDialogTitle(msg("selectStackTraceFile")); fileChooser.setSelectedFile(null); int returnValue = fileChooser.showOpenDialog(ProGuardGUI.this); if (returnValue == JFileChooser.APPROVE_OPTION) { loadStackTrace(fileChooser.getSelectedFile()); } } } /** * This ActionListener executes ReTrace based on the current GUI settings. */ private class MyReTraceActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Make sure System.out has not been redirected yet. if (!systemOutRedirected) { systemOutRedirected = true; boolean verbose = reTraceVerboseCheckBox.isSelected(); File retraceMappingFile = new File(reTraceMappingTextField.getText()); String stackTrace = stackTraceTextArea.getText(); // Create the ReTrace runnable. Runnable reTraceRunnable = new ReTraceRunnable(reTraceTextArea, verbose, retraceMappingFile, stackTrace); // Run it in this thread, because it won't take long anyway. reTraceRunnable.run(); } } } // Small utility methods. /** * Returns the canonical file name for the given file, or the empty string * if the file name is empty. */ private String fileName(File file) { if (isFile(file)) { try { return file.getCanonicalPath(); } catch (IOException ex) { return file.getPath(); } } else { return ""; } } /** * Returns whether the given file is actually a file, or just a placeholder * for the standard output. */ private boolean isFile(File file) { return file != null && file.getPath().length() > 0; } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } /** * Returns the message from the GUI resources that corresponds to the given * key and argument. */ private String msg(String messageKey, Object messageArgument) { return GUIResources.getMessage(messageKey, new Object[] {messageArgument}); } /** * The main method for the ProGuard GUI. */ public static void main(final String[] args) { try { SwingUtil.invokeAndWait(new Runnable() { public void run() { try { ProGuardGUI gui = new ProGuardGUI(); gui.pack(); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension guiSize = gui.getSize(); gui.setLocation((screenSize.width - guiSize.width) / 2, (screenSize.height - guiSize.height) / 2); gui.show(); // Start the splash animation, unless specified otherwise. int argIndex = 0; if (argIndex < args.length && NO_SPLASH_OPTION.startsWith(args[argIndex])) { gui.skipSplash(); argIndex++; } else { gui.startSplash(); } // Load an initial configuration, if specified. if (argIndex < args.length) { gui.loadConfiguration(new File(args[argIndex])); argIndex++; } if (argIndex < args.length) { System.out.println(gui.getClass().getName() + ": ignoring extra arguments [" + args[argIndex] + "...]"); } } catch (Exception e) { System.out.println("Internal problem starting the ProGuard GUI (" + e.getMessage() + ")"); } } }); } catch (Exception e) { System.out.println("Internal problem starting the ProGuard GUI (" + e.getMessage() + ")"); } } } proguard4.8/src/proguard/gui/arrow.gif0000644000175000017500000000016011163773611016603 0ustar ericericGIF89a! ,A3X@PveV9wtLֺN~"" asy4yRj ;proguard4.8/src/proguard/gui/OptimizationsDialog.java0000644000175000017500000002152211736333525021625 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.gui; import proguard.optimize.Optimizer; import proguard.util.*; import javax.swing.*; import javax.swing.border.*; import java.awt.*; import java.awt.event.*; /** * This JDialog allows the user to enter a String. * * @author Eric Lafortune */ final class OptimizationsDialog extends JDialog { /** * Return value if the dialog is canceled (with the Cancel button or by * closing the dialog window). */ public static final int CANCEL_OPTION = 1; /** * Return value if the dialog is approved (with the Ok button). */ public static final int APPROVE_OPTION = 0; private final JCheckBox[] optimizationCheckBoxes = new JCheckBox[Optimizer.OPTIMIZATION_NAMES.length]; private int returnValue; public OptimizationsDialog(JFrame owner) { super(owner, msg("selectOptimizations"), true); setResizable(true); // Create some constraints that can be reused. GridBagConstraints constraintsLast = new GridBagConstraints(); constraintsLast.gridwidth = GridBagConstraints.REMAINDER; constraintsLast.anchor = GridBagConstraints.WEST; constraintsLast.insets = new Insets(1, 2, 1, 2); GridBagConstraints constraintsLastStretch = new GridBagConstraints(); constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER; constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL; constraintsLastStretch.weightx = 1.0; constraintsLastStretch.anchor = GridBagConstraints.WEST; constraintsLastStretch.insets = constraintsLast.insets; GridBagConstraints panelConstraints = new GridBagConstraints(); panelConstraints.gridwidth = GridBagConstraints.REMAINDER; panelConstraints.fill = GridBagConstraints.HORIZONTAL; panelConstraints.weightx = 1.0; panelConstraints.weighty = 0.0; panelConstraints.anchor = GridBagConstraints.NORTHWEST; panelConstraints.insets = constraintsLast.insets; GridBagConstraints selectButtonConstraints = new GridBagConstraints(); selectButtonConstraints.weighty = 1.0; selectButtonConstraints.anchor = GridBagConstraints.SOUTHWEST; selectButtonConstraints.insets = new Insets(4, 4, 8, 4); GridBagConstraints okButtonConstraints = new GridBagConstraints(); okButtonConstraints.weightx = 1.0; okButtonConstraints.weighty = 1.0; okButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; okButtonConstraints.insets = selectButtonConstraints.insets; GridBagConstraints cancelButtonConstraints = new GridBagConstraints(); cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER; cancelButtonConstraints.weighty = 1.0; cancelButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; cancelButtonConstraints.insets = selectButtonConstraints.insets; GridBagLayout layout = new GridBagLayout(); Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); // Create the optimizations panel. JPanel optimizationsPanel = new JPanel(layout); JPanel optimizationSubpanel = null; String lastOptimizationPrefix = null; for (int index = 0; index < Optimizer.OPTIMIZATION_NAMES.length; index++) { String optimizationName = Optimizer.OPTIMIZATION_NAMES[index]; String optimizationPrefix = optimizationName.substring(0, optimizationName.indexOf('/')); if (optimizationSubpanel == null || !optimizationPrefix.equals(lastOptimizationPrefix)) { // Create a new keep subpanel and add it. optimizationSubpanel = new JPanel(layout); optimizationSubpanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg(optimizationPrefix))); optimizationsPanel.add(optimizationSubpanel, panelConstraints); lastOptimizationPrefix = optimizationPrefix; } JCheckBox optimizationCheckBox = new JCheckBox(optimizationName); optimizationCheckBoxes[index] = optimizationCheckBox; optimizationSubpanel.add(tip(optimizationCheckBox, optimizationName.replace('/', '_')+"Tip"), constraintsLastStretch); } // Create the Select All button. JButton selectAllButton = new JButton(msg("selectAll")); selectAllButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { for (int index = 0; index < optimizationCheckBoxes.length; index++) { optimizationCheckBoxes[index].setSelected(true); } } }); // Create the Select All button. JButton selectNoneButton = new JButton(msg("selectNone")); selectNoneButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { for (int index = 0; index < optimizationCheckBoxes.length; index++) { optimizationCheckBoxes[index].setSelected(false); } } }); // Create the Ok button. JButton okButton = new JButton(msg("ok")); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { returnValue = APPROVE_OPTION; hide(); } }); // Create the Cancel button. JButton cancelButton = new JButton(msg("cancel")); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { hide(); } }); // Add all panels to the main panel. optimizationsPanel.add(selectAllButton, selectButtonConstraints); optimizationsPanel.add(selectNoneButton, selectButtonConstraints); optimizationsPanel.add(okButton, okButtonConstraints); optimizationsPanel.add(cancelButton, cancelButtonConstraints); getContentPane().add(new JScrollPane(optimizationsPanel)); } /** * Sets the initial optimization filter to be used by the dialog. */ public void setFilter(String optimizations) { StringMatcher filter = optimizations != null && optimizations.length() > 0 ? new ListParser(new NameParser()).parse(optimizations) : new FixedStringMatcher(""); for (int index = 0; index < Optimizer.OPTIMIZATION_NAMES.length; index++) { optimizationCheckBoxes[index].setSelected(filter.matches(Optimizer.OPTIMIZATION_NAMES[index])); } } /** * Returns the optimization filter composed from the settings in the dialog. */ public String getFilter() { return new FilterBuilder(optimizationCheckBoxes, '/').buildFilter(); } /** * Shows this dialog. This method only returns when the dialog is closed. * * @return CANCEL_OPTION or APPROVE_OPTION, * depending on the choice of the user. */ public int showDialog() { returnValue = CANCEL_OPTION; // Open the dialog in the right place, then wait for it to be closed, // one way or another. pack(); setLocationRelativeTo(getOwner()); show(); return returnValue; } /** * Attaches the tool tip from the GUI resources that corresponds to the * given key, to the given component. */ private static JComponent tip(JComponent component, String messageKey) { component.setToolTipText(msg(messageKey)); return component; } /** * Returns the message from the GUI resources that corresponds to the given * key. */ private static String msg(String messageKey) { return GUIResources.getMessage(messageKey); } }proguard4.8/src/proguard/gui/GUIResources.properties0000644000175000017500000006250511757712530021434 0ustar ericeric# ProGuard -- shrinking, optimization, and obfuscation of Java class files. # Copyright (c) 2002-2012 Eric Lafortune (eric@graphics.cornell.edu) # # Tab names. # proGuardTab = ProGuard inputOutputTab = Input/Output shrinkingTab = Shrinking obfuscationTab = Obfuscation optimizationTab = Optimization informationTab = Information processTab = Process reTraceTab = ReTrace # # Splash text. # developed = Developed by Eric Lafortune shrinking = Shrinking optimization = Optimization obfuscation = Obfuscation preverification = Preverification # # Panel titles. # welcome = Welcome to ProGuard, version 4.8 options = Options keepAdditional = Keep additional classes and class members keepNamesAdditional = Keep additional class names and class member names assumeNoSideEffectsAdditional = Assume no side effects for additional methods whyAreYouKeeping = Why are you keeping preverificationAndTargeting = Preverification and targeting consistencyAndCorrectness = Consistency and correctness processingConsole = Processing console reTraceSettings = ReTrace settings deobfuscatedStackTrace = De-obfuscated stack trace keepAdditionalTip = \ If required, keep additional classes, fields, and methods as entry points. keepNamesAdditionalTip = \ If required, keep the names of additional classes, fields, and methods. assumeNoSideEffectsAdditionalTip = \ Optionally specify additional methods that don't have any side effects.
\ Only add entries if you know what you're doing! whyAreYouKeepingTip = \ Ask ProGuard why it is keeping certain classes, fields, or methods. # # Info texts. # proGuardInfo = \ ProGuard is a free class file shrinker, optimizer, obfuscator, and preverifier.\

\ With this GUI, you can create, load, modify, and save ProGuard configurations.\
\ You can then process your code right away, or you can run ProGuard from the \ command line using your saved configuration.\

\ With the ReTrace part of this GUI you can de-obfuscate your stack traces.\

\ ProGuard and ReTrace are written and maintained by Eric Lafortune.\

\ Official site at Sourceforge: \ http://proguard.sourceforge.net/\
\ Professional support by Saikoa: \ http://www.saikoa.com/\

\ Distributed under the GNU General Public License.\
\ Copyright © 2002-2012. processingInfo = \ You can now start processing your code, \ or you can run ProGuard from the command line using your saved configuration. reTraceInfo = \ If you had ProGuard write out a mapping file, \ you can de-obfuscate your obfuscated stack traces with ReTrace!\ \n\n\ You can load an obfuscated stack trace from a file, \ or you can paste it straight into the text area above. # # Titles and labels corresponding to common ProGuard options. # programJars = Program jars, wars, ears, zips, and directories libraryJars = Library jars, wars, ears, zips, and directories shrink = Shrink printUsage = Print usage optimize = Optimize allowAccessModification = Allow access modification mergeInterfacesAggressively = Merge interfaces aggressively optimizations = Optimizations optimizationPasses = Optimization passes obfuscate = Obfuscate printMapping = Print mapping applyMapping = Apply mapping obfuscationDictionary = Obfuscation dictionary classObfuscationDictionary = Class obfuscation dictionary packageObfuscationDictionary = Package obfuscation dictionary overloadAggressively = Overload aggressively useUniqueClassMemberNames = Use unique class member names keepPackageNames = Keep package names flattenPackageHierarchy = Flatten package hierarchy repackageClasses = Repackage classes useMixedCaseClassNames = Use mixed-case class names keepAttributes = Keep attributes keepParameterNames = Keep parameter names renameSourceFileAttribute = Rename SourceFile attribute adaptClassStrings = Adapt class strings adaptResourceFileNames = Adapt resource file names adaptResourceFileContents = Adapt resource file contents preverify = Preverify microEdition = Micro Edition verbose = Verbose note = Note potential mistakes in the configuration warn = Warn about possibly erroneous input ignoreWarnings = Ignore warnings about possibly erroneous input skipNonPublicLibraryClasses = Skip non-public library classes skipNonPublicLibraryClassMembers = Skip non-public library class members keepDirectories = Keep directories forceProcessing = Force processing target = Target targets = 1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7 printSeeds = Print seeds printConfiguration = Print configuration dump = Print class files mappingFile = Mapping file obfuscatedStackTrace = Obfuscated stack trace programJarsTip = \ The input jars (wars, ears, zips, directories), followed by
\ their corresponding output jars (wars, ears, zips, directories). libraryJarsTip = \ The library jars (wars, ears, zips, directories), on which the program jars depend.
\ The library jars are required for processing, but they are not copied to the output. shrinkTip = \ Remove unused classes, fields, and methods from the output. printUsageTip = \ Print out the list of unused classes, fields, and methods. optimizeTip = \ Optimize the bytecode of the processed classes. allowAccessModificationTip = \ Allow the optimization step to modify the access modifiers of classes, fields, and methods. mergeInterfacesAggressivelyTip = \ Allow interfaces to be merged, even if their implementations don't implement all
\ interface methods. This is not allowed in the Java language, but it is allowed in bytecode. optimizationsTip = \ Specify the types of optimizations to be performed. optimizationsFilterTip = \ A filter for the names of the optimizations to be performed. optimizationsSelectTip = \ Select from the currently available optimizations... optimizationPassesTip = \ Specify the number of optimization passes to be performed. obfuscateTip = \ Obfuscate the names of the processed classes, fields, and methods. printMappingTip = \ Print out the obfuscation mapping of original names to obfuscated names. applyMappingTip = \ Apply the given mapping of original names to obfuscated names. obfuscationDictionaryTip = \ Use the words in the given file for obfuscating field names and method names. classObfuscationDictionaryTip = \ Use the words in the given file for obfuscating class names. packageObfuscationDictionaryTip = \ Use the words in the given file for obfuscating package names. overloadAggressivelyTip = \ Allow fields and methods to get the same obfuscated names, even if only their types or
\ return types differ. This is not allowed in the Java language, but it is allowed in bytecode. useUniqueClassMemberNamesTip = \ Make sure fields and methods get the same obfuscation mapping across classes, even
\ if they are unrelated. This is advisable if the output is to be obfuscated incrementally. keepPackageNamesTip = \ Keep the specified package names from being obfuscated. packageNamesTip = \ An optional comma-separated list of package names,
\ e.g. myapplication,mylibrary.**
\ Possible wildcards:\

\ The negator ! is also supported. flattenPackageHierarchyTip = \ Move all packages that are renamed into the given parent package. repackageClassesTip = \ Move all classes that are renamed into the given package. packageTip = \ The optional package name. useMixedCaseClassNamesTip = \ Generate mixed-case obfucated class names. This will complicate unpacking
\ the resulting jars on case-insensitive file systems, should that be necessary. keepAttributesTip = \ Keep the specified optional class file attributes. attributesTip = \ An optional comma-separated list of class file attributes.\ \ The wildcard * and the negator ! are allowed. keepParameterNamesTip = \ Keep parameter names and types in "LocalVariable*Table" attributes
\ in methods that are not obfuscated. renameSourceFileAttributeTip = \ Put the given string in the "SourceFile" attribute of the processed class files.
\ It will appear as the file name of the classes in stack traces. sourceFileAttributeTip = \ The replacement "SourceFile" string. adaptClassStringsTip = \ Adapt string constants in the specified classes, based
\ on the obfuscated names of corresponding classes. adaptResourceFileNamesTip = \ Rename the specified resource files, based on the
\ obfuscated names of the corresponding class files. adaptResourceFileContentsTip = \ Adapt the contents of the specified resource files, based
\ on the obfuscated names of the processed classes. fileNameFilterTip = \ A filter on file names,
\ e.g. mydirectory1/**,mydirectory2/**
\ Possible wildcards:\ \ The negator ! is also supported. preverifyTip = \ Preverify the processed classes, for Java Micro Edition or for Java 6. microEditionTip = \ Target Java Micro Edition. verboseTip = \ Print out verbose messages while processing. noteTip = \ Print out notes about special or unusual input. noteFilterTip = \ A filter matching classes for which no notes should be printed. warnTip = \ Print out warnings about possibly erroneous input.
\ Only unset this option if you know what you're doing! warnFilterTip = \ A filter matching classes for which no warnings should be printed. ignoreWarningsTip = \ Ignore any warnings about possibly erroneous input.
\ Only set this option if you know what you're doing! skipNonPublicLibraryClassesTip = \ Skip reading non-public library classes, for efficiency.
\ You may have to unset this option if ProGuard complains about missing classes. skipNonPublicLibraryClassMembersTip = \ Skip reading non-public library fields and methods, for efficiency.
\ You may have to unset this option if ProGuard complains about missing class members. keepDirectoriesTip = \ Keep the specified directories in the output jars, wars, ears, zips, or directories. directoriesTip = \ A filter on directory names,
\ e.g. mydirectory1,mydirectory2/**
\ Possible wildcards:\ \ The negator ! is also supported. forceProcessingTip = \ Always process the input, even if the output seems up to date. targetTip = \ Target the specified version of Java. printSeedsTip = \ Print out the list of kept classes, fields, and methods. printConfigurationTip = \ Print out the configuration. dumpTip = \ Print out the internal structure of the processed class files. mappingFileTip = \ The file containing the mapping of original names to obfuscated names. obfuscatedStackTraceTip = \ A stack trace produced by previously obfuscated code. # # Titles and labels corresponding to ProGuard keep options. # keepTitle = Keep keep = Keep classes and class members keepClassMembers = Keep class members only keepClassesWithMembers = Keep classes and class members, if members are present allowTitle = Allow allowShrinking = Allow shrinking allowOptimization = Allow optimization allowObfuscation = Allow obfuscation keepTitleTip = Keep the specified classes and/or their fields and methods. keepTip = \ Keep the specified classes, fields, and methods as entry points.
\ This is the most common option. keepClassMembersTip = \ Only keep the specified fields and methods as entry points. keepClassesWithMembersTip = \ Keep the specified classes, fields, and methods,
\ on the condition that the fields and methods are present. allowTitleTip = \ Optionally relax keeping the specified classes, fields, and methods.
\ These are advanced options. allowShrinkingTip = \ Remove the specified classes, fields, and methods anyway, if they are not used. allowOptimizationTip = \ Optimize the specified classes, fields, and methods as entry points anyway.
\ Only set this option if you know what you're doing! allowObfuscationTip = \ Obfuscate the names of the specified classes, fields, and methods anyway.
\ Only set this option if you know what you're doing! # # Further keep titles and labels. # specifyClasses = Specify classes and class members... specifyFields = Specify fields... specifyMethods = Specify methods... comments = Comments access = Access required = Required not = Not dontCare = Don't care annotation = Annotation class = Class extendsImplementsAnnotation = Extends/implements class with annotation extendsImplementsClass = Extends/implements class classMembers = Class members extensionsOf = Extensions of specificationNumber = Specification # fieldType = Field type returnType = Return type name = Name argumentTypes = Argument types commentsTip = \ Optionally add a comment for this option in the configuration file. accessTip = \ Optionally place constraints on the access modifiers of this element.
\ E.g. only match public elements. requiredTip = \ The access modifier has to be set. notTip = \ The access modifier must not be set. dontCareTip = \ The access modifier is irrelevant. annotationTip = \ Optionally require the given annotation to be present on this element.
\ E.g. only match elements that have an annotation myPackage.MyAnnotation.
\ This is an advanced option. classTip = \ The name of the class or interface. extendsImplementsAnnotationTip = \ Optionally require the given annotation to be present on the
\ extended or implemented class or interface.
\ E.g. only match classes that extend a class that has an annotation
\ myPackage.MyAnnotation.
\ This is an advanced option. extendsImplementsClassTip = \ Optionally require the class to implement or extend the given class or interface.
\ E.g. only match classes that implement an interface myPackage.MyInterface. classMembersTip = \ Optionally keep fields and methods as entry points in the matching class or classes.
\ E.g. keep all public 'get*' methods as entry points. fieldTypeTip = The field type. returnTypeTip = The method return type, if any. nameTip = The name. argumentTypesTip = The method argument types, if any. classNameTip = \ The class name, e.g. myPackage.MyClass
\ Possible wildcards:\ classNamesTip = \ A regular expression to further constrain the class names,
\ e.g. myPackage1.MyClass,myPackage2.**
\ Possible wildcards:\ \ The negator ! is also supported. typeTip = \ The type, e.g. int, or java.lang.String[]
\ Possible wildcards:\ fieldNameTip = \ The field name, e.g. myField
\ Possible wildcards:\ methodNameTip = \ The method name, e.g. myMethod
\ Possible wildcards:\ argumentTypes2Tip = \ The comma-separated list of argument types,
\ e.g. java.lang.String[],int,boolean
\ Possible wildcards:\ # # Titles and labels corresponding to optimization options. # selectOptimizations = Select optimizations... field = Field method = Method code = Code class_marking_finalTip = \ Mark classes as final, whenever possible. class_merging_verticalTip = \ Merge classes vertically in the class hierarchy, whenever possible. class_merging_horizontalTip = \ Merge classes horizontally in the class hierarchy, whenever possible. field_removal_writeonlyTip = \ Remove write-only fields. field_marking_privateTip = \ Mark fields as private, whenever possible. field_propagation_valueTip = \ Propagate the values of fields across methods. method_marking_privateTip = \ Mark methods as private, whenever possible (devirtualization). method_marking_staticTip = \ Mark methods as static, whenever possible (devirtualization). method_marking_finalTip = \ Mark methods as final, whenever possible. method_removal_parameterTip = \ Remove unused method parameters. method_propagation_parameterTip = \ Propagate the values of method parameters from method invocations to \ the invoked methods. method_propagation_returnvalueTip = \ Propagate the values of method return values from methods to their \ invocations. method_inlining_shortTip = \ Inline short methods. method_inlining_uniqueTip = \ Inline methods that are only called once. method_inlining_tailrecursionTip = \ Simplify tail recursion calls, whenever possible. code_mergingTip = \ Merge identical blocks of code by modifying branch targets. code_simplification_variableTip = \ Perform peephole optimizations for variable loading and storing. code_simplification_arithmeticTip = \ Perform peephole optimizations for arithmetic instructions. code_simplification_castTip = \ Perform peephole optimizations for casting operations. code_simplification_fieldTip = \ Perform peephole optimizations for field loading and storing. code_simplification_branchTip = \ Perform peephole optimizations for branch instructions. code_simplification_stringTip = \ Perform peephole optimizations for constant strings. code_simplification_advancedTip = \ Simplify code based on control flow analysis and data flow analysis. code_removal_advancedTip = \ Remove dead code based on control flow analysis and data flow analysis. code_removal_simpleTip = \ Remove dead code based on a simple control flow analysis. code_removal_variableTip = \ Remove unused variables from the local variable frame. code_removal_exceptionTip = \ Remove exceptions with empty try blocks. code_allocation_variableTip = \ Optimize variable allocation on the local variable frame. # # File selection titles. # selectConfigurationFile = Select a configuration file... saveConfigurationFile = Save configuration... selectUsageFile = Select a usage output file... selectPrintMappingFile = Select an output mapping file... selectApplyMappingFile = Select an input mapping file... selectObfuscationDictionaryFile = Select an obfuscation dictionary... selectSeedsFile = Select a seeds output file... selectDumpFile = Select a class dump file... selectStackTraceFile = Select a stack trace file... cantOpenConfigurationFile = Can''t open the configuration file [{0}] cantParseConfigurationFile = Can''t parse the configuration file [{0}] cantSaveConfigurationFile = Can''t save the configuration file [{0}] cantOpenStackTraceFile = Can''t open the stack trace file [{0}] jarWarEarZipExtensions = *.jar, *.war, *.ear, *.zip (archives and directories) proExtension = *.pro (ProGuard configurations) addJars = Add one or more jars or directories... chooseJars = Choose different jars or directories... enterFilter = Optionally filter the file names contained in the selected entries. filters = Filters nameFilter = File name filter jarNameFilter = Jar name filter warNameFilter = War name filter earNameFilter = Ear name filter zipNameFilter = Zip name filter outputFileTip = The optional output file. inputFileTip = The input file. nameFilterTip = A filter on plain class file names and resource file names. jarNameFilterTip = A filter on jar file names. warNameFilterTip = A filter on war file names. earNameFilterTip = A filter on ear file names. zipNameFilterTip = A filter on zip file names. # # Simple button texts. # previous = Previous next = Next browse = Browse... advanced = Advanced options basic = Basic options selectAll = Select all selectNone = Select none ok = Ok cancel = Cancel add = Add... addInput = Add input... addOutput = Add output... edit = Edit... filter = Filter... remove = Remove moveUp = Move up moveDown = Move down moveToLibraries = Move to libraries moveToProgram = Move to program addField = Add field... addMethod = Add method... select = Select... loadConfiguration = Load configuration... viewConfiguration = View configuration saveConfiguration = Save configuration... loadStackTrace = Load stack trace... process = Process! reTrace = ReTrace! advancedTip = Toggle between showing basic options and advanced options. addInputTip = Add an input jar, war, ear, zip, or directory. addOutputTip = Add an output jar, war, ear, zip, or directory. addTip = Add an entry. editTip = Edit the selected entries. filterTip = Put filters on the contents of the selected entries. removeTip = Remove the selected entries. moveUpTip = Move the selected entries up in the list. moveDownTip = Move the selected entries down in the list. moveToLibrariesTip = Move to selected entries to the libraries. moveToProgramTip = Move to selected entries to the program. addFieldTip = Add a field to the specification. addMethodTip = Add a method to the specification. loadConfigurationTip = Optionally load an initial configuration. viewConfigurationTip = View the current configuration. saveConfigurationTip = Save the current configuration. loadStackTraceTip = Load a stack trace from a file. processTip = Start processing, based on the current configuration. reTraceTip = De-obfuscate the given stack trace. # # Progress messages and error messages. # warning = Warning outOfMemory = Out of memory outOfMemoryInfo = \n\ You should run the ProGuard GUI with a larger java heap size, \ with a command like\ \n\n\t\ java -Xms128m -Xmx192m -jar proguardgui.jar {0}\ \n\n\ or you can try running ProGuard from the command line. \ with a command like\ \n\n\t\ java -jar proguard.jar @{0} sampleConfigurationFileName = configuration.pro errorProcessing = Error during processing errorReTracing = Error during retracing proguard4.8/src/proguard/preverify/0000775000175000017500000000000011760503005016205 5ustar ericericproguard4.8/src/proguard/preverify/SubroutineInliner.java0000644000175000017500000000440311736333525022542 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.preverify; import proguard.Configuration; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AllAttributeVisitor; import proguard.classfile.visitor.*; /** * This class can inline subroutines in methods. This is generally useful (i.e. * required) for preverifying code. * * @author Eric Lafortune */ public class SubroutineInliner { private final Configuration configuration; /** * Creates a new SubroutineInliner. */ public SubroutineInliner(Configuration configuration) { this.configuration = configuration; } /** * Performs subroutine inlining of the given program class pool. */ public void execute(ClassPool programClassPool) { // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); // Inline all subroutines. ClassVisitor inliner = new AllMethodVisitor( new AllAttributeVisitor( new CodeSubroutineInliner())); // In Java Standard Edition, only class files from Java 6 or higher // should be preverified. if (!configuration.microEdition) { inliner = new ClassVersionFilter(ClassConstants.INTERNAL_CLASS_VERSION_1_6, inliner); } programClassPool.classesAccept(inliner); } } proguard4.8/src/proguard/preverify/Preverifier.java0000644000175000017500000000441511736333525021347 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.preverify; import proguard.Configuration; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AllAttributeVisitor; import proguard.classfile.visitor.*; /** * This class can preverify methods in program class pools, according to a given * configuration. * * @author Eric Lafortune */ public class Preverifier { private final Configuration configuration; /** * Creates a new Preverifier. */ public Preverifier(Configuration configuration) { this.configuration = configuration; } /** * Performs preverification of the given program class pool. */ public void execute(ClassPool programClassPool) { // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); // Preverify all methods. ClassVisitor preverifier = new AllMethodVisitor( new AllAttributeVisitor( new CodePreverifier(configuration.microEdition))); // Classes from Java 6 may optionally be preverified. // Classes from Java 7 or higher must be preverified. if (!configuration.microEdition) { preverifier = new ClassVersionFilter(ClassConstants.INTERNAL_CLASS_VERSION_1_6, preverifier); } programClassPool.classesAccept(preverifier); } } proguard4.8/src/proguard/preverify/CodeSubroutineInliner.java0000644000175000017500000003642611736333525023347 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.preverify; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.editor.CodeAttributeComposer; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; import proguard.optimize.peephole.BranchTargetFinder; /** * This AttributeVisitor inlines local subroutines (jsr/ret) in the code * attributes that it visits. * * @author Eric Lafortune */ public class CodeSubroutineInliner extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(true); private ExceptionInfoVisitor subroutineExceptionInliner = this; private int clipStart = 0; private int clipEnd = Integer.MAX_VALUE; // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // CodeAttributeComposer.DEBUG = DEBUG; // TODO: Remove this when the subroutine inliner has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while inlining subroutines:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); if (DEBUG) { method.accept(clazz, new ClassPrinter()); } throw ex; } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute); // Don't bother if there aren't any subroutines anyway. if (!containsSubroutines(codeAttribute)) { return; } if (DEBUG) { System.out.println("SubroutineInliner: processing ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); } // Append the body of the code. codeAttributeComposer.reset(); codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); // Copy the non-subroutine instructions. int offset = 0; while (offset < codeAttribute.u4codeLength) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); int instructionLength = instruction.length(offset); // Is this returning subroutine? if (branchTargetFinder.isSubroutine(offset) && branchTargetFinder.isSubroutineReturning(offset)) { // Skip the subroutine. if (DEBUG) { System.out.println(" Skipping original subroutine instruction "+instruction.toString(offset)); } // Append a label at this offset instead. codeAttributeComposer.appendLabel(offset); } else { // Copy the instruction, inlining any subroutine call recursively. instruction.accept(clazz, method, codeAttribute, offset, this); } offset += instructionLength; } // Copy the exceptions. Note that exceptions with empty try blocks // are automatically removed. codeAttribute.exceptionsAccept(clazz, method, subroutineExceptionInliner); if (DEBUG) { System.out.println(" Appending label after code at ["+offset+"]"); } // Append a label just after the code. codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); // End and update the code attribute. codeAttributeComposer.endCodeFragment(); codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute); } /** * Returns whether the given code attribute contains any subroutines. */ private boolean containsSubroutines(CodeAttribute codeAttribute) { for (int offset = 0; offset < codeAttribute.u4codeLength; offset++) { if (branchTargetFinder.isSubroutineInvocation(offset)) { return true; } } return false; } /** * Appends the specified subroutine. */ private void inlineSubroutine(Clazz clazz, Method method, CodeAttribute codeAttribute, int subroutineInvocationOffset, int subroutineStart) { int subroutineEnd = branchTargetFinder.subroutineEnd(subroutineStart); if (DEBUG) { System.out.println(" Inlining subroutine ["+subroutineStart+" -> "+subroutineEnd+"] at ["+subroutineInvocationOffset+"]"); } // Don't go inlining exceptions that are already applicable to this // subroutine invocation. ExceptionInfoVisitor oldSubroutineExceptionInliner = subroutineExceptionInliner; int oldClipStart = clipStart; int oldClipEnd = clipEnd; subroutineExceptionInliner = new ExceptionExcludedOffsetFilter(subroutineInvocationOffset, subroutineExceptionInliner); clipStart = subroutineStart; clipEnd = subroutineEnd; codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); // Copy the subroutine instructions, inlining any subroutine calls // recursively. codeAttribute.instructionsAccept(clazz, method, subroutineStart, subroutineEnd, this); if (DEBUG) { System.out.println(" Appending label after inlined subroutine at ["+subroutineEnd+"]"); } // Append a label just after the code. codeAttributeComposer.appendLabel(subroutineEnd); // Inline the subroutine exceptions. codeAttribute.exceptionsAccept(clazz, method, subroutineStart, subroutineEnd, subroutineExceptionInliner); // We can again inline exceptions that are applicable to this // subroutine invocation. subroutineExceptionInliner = oldSubroutineExceptionInliner; clipStart = oldClipStart; clipEnd = oldClipEnd; codeAttributeComposer.endCodeFragment(); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { // Append the instruction. codeAttributeComposer.appendInstruction(offset, instruction.shrink()); } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { byte opcode = variableInstruction.opcode; if (opcode == InstructionConstants.OP_RET) { // Is the return instruction the last instruction of the subroutine? if (branchTargetFinder.subroutineEnd(offset) == offset + variableInstruction.length(offset)) { if (DEBUG) { System.out.println(" Replacing subroutine return at ["+offset+"] by a label"); } // Append a label at this offset instead of the subroutine return. codeAttributeComposer.appendLabel(offset); } else { if (DEBUG) { System.out.println(" Replacing subroutine return at ["+offset+"] by a simple branch"); } // Replace the instruction by a branch. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO, branchTargetFinder.subroutineEnd(offset) - offset).shrink(); codeAttributeComposer.appendInstruction(offset, replacementInstruction); } } else if (branchTargetFinder.isSubroutineStart(offset)) { if (DEBUG) { System.out.println(" Replacing first subroutine instruction at ["+offset+"] by a label"); } // Append a label at this offset instead of saving the subroutine // return address. codeAttributeComposer.appendLabel(offset); } else { // Append the instruction. codeAttributeComposer.appendInstruction(offset, variableInstruction); } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { byte opcode = branchInstruction.opcode; if (opcode == InstructionConstants.OP_JSR || opcode == InstructionConstants.OP_JSR_W) { int branchOffset = branchInstruction.branchOffset; int branchTarget = offset + branchOffset; // Is the subroutine ever returning? if (branchTargetFinder.isSubroutineReturning(branchTarget)) { // Append a label at this offset instead of the subroutine invocation. codeAttributeComposer.appendLabel(offset); // Inline the invoked subroutine. inlineSubroutine(clazz, method, codeAttribute, offset, branchTarget); } else { if (DEBUG) { System.out.println("Replacing subroutine invocation at ["+offset+"] by a simple branch"); } // Replace the subroutine invocation by a simple branch. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO, branchOffset).shrink(); codeAttributeComposer.appendInstruction(offset, replacementInstruction); } } else { // Append the instruction. codeAttributeComposer.appendInstruction(offset, branchInstruction); } } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { int startPC = Math.max(exceptionInfo.u2startPC, clipStart); int endPC = Math.min(exceptionInfo.u2endPC, clipEnd); int handlerPC = exceptionInfo.u2handlerPC; int catchType = exceptionInfo.u2catchType; // Exclude any subroutine invocations that jump out of the try block, // by adding a try block before (and later on, after) each invocation. for (int offset = startPC; offset < endPC; offset++) { if (branchTargetFinder.isSubroutineInvocation(offset)) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); int instructionLength = instruction.length(offset); // Is it a subroutine invocation? if (!exceptionInfo.isApplicable(offset + ((BranchInstruction)instruction).branchOffset)) { if (DEBUG) { System.out.println(" Appending extra exception ["+startPC+" -> "+offset+"] -> "+handlerPC); } // Append a try block that ends before the subroutine invocation. codeAttributeComposer.appendException(new ExceptionInfo(startPC, offset, handlerPC, catchType)); // The next try block will start after the subroutine invocation. startPC = offset + instructionLength; } } } if (DEBUG) { if (startPC == exceptionInfo.u2startPC && endPC == exceptionInfo.u2endPC) { System.out.println(" Appending exception ["+startPC+" -> "+endPC+"] -> "+handlerPC); } else { System.out.println(" Appending clipped exception ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+"] ~> ["+startPC+" -> "+endPC+"] -> "+handlerPC); } } // Append the exception. Note that exceptions with empty try blocks // are automatically ignored. codeAttributeComposer.appendException(new ExceptionInfo(startPC, endPC, handlerPC, catchType)); } } proguard4.8/src/proguard/preverify/CodePreverifier.java0000664000175000017500000006120211736333525022141 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.preverify; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.editor.*; import proguard.classfile.instruction.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.evaluation.*; import java.util.*; /** * This class can preverify methods in program class pools, according to a given * specification. * * @author Eric Lafortune */ public class CodePreverifier extends SimplifiedVisitor implements AttributeVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final boolean microEdition; private final PartialEvaluator partialEvaluator = new PartialEvaluator(); private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(partialEvaluator); private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true); /** * Creates a new CodePreverifier. */ public CodePreverifier(boolean microEdition) { this.microEdition = microEdition; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // TODO: Remove this when the preverifier has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while preverifying:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); throw ex; } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); ProgramClass programClass = (ProgramClass)clazz; ProgramMethod programMethod = (ProgramMethod)method; int codeLength = codeAttribute.u4codeLength; // Evaluate the method. //partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); // We may have to remove unreachable code. codeAttributeEditor.reset(codeLength); // Collect the stack map frames. List stackMapFrameList = new ArrayList(); for (int offset = 0; offset < codeLength; offset++) { // Only store frames at the beginning of code blocks. if (!partialEvaluator.isTraced(offset)) { // Mark the unreachable instruction for deletion. codeAttributeEditor.deleteInstruction(offset); } else if (partialEvaluator.isBranchOrExceptionTarget(offset)) { // Convert the variable values to types. VerificationType[] variableTypes = correspondingVerificationTypes(programClass, programMethod, codeAttribute, offset, partialEvaluator.getVariablesBefore(offset)); // Convert the stack values to types. VerificationType[] stackTypes = correspondingVerificationTypes(programClass, programMethod, codeAttribute, offset, partialEvaluator.getStackBefore(offset)); // Create and store a new frame. stackMapFrameList.add(new FullFrame(offset, variableTypes, stackTypes)); } } // Compress the stack map frames if the target is not Java Micro Edition. if (!microEdition && !stackMapFrameList.isEmpty()) { // Convert the initial variable values to types. VerificationType[] initialVariables = correspondingVerificationTypes(programClass, programMethod, codeAttribute, PartialEvaluator.AT_METHOD_ENTRY, partialEvaluator.getVariablesBefore(0)); // Special case: the method. if (method.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { initialVariables[0] = VerificationTypeFactory.createUninitializedThisType(); } compressStackMapFrames(initialVariables, stackMapFrameList); } // Get the proper name for the attribute to be added/replaced/deleted. String stackMapAttributeName = microEdition ? ClassConstants.ATTR_StackMap : ClassConstants.ATTR_StackMapTable; int frameCount = stackMapFrameList.size(); if (DEBUG) { Attribute originalStackMapAttribute = codeAttribute.getAttribute(clazz, stackMapAttributeName); if (originalStackMapAttribute != null) { int originalFrameCount = microEdition ? ((StackMapAttribute)originalStackMapAttribute).u2stackMapFramesCount : ((StackMapTableAttribute)originalStackMapAttribute).u2stackMapFramesCount; StackMapFrame[] originalFrames = microEdition ? ((StackMapAttribute)originalStackMapAttribute).stackMapFrames : ((StackMapTableAttribute)originalStackMapAttribute).stackMapFrames; if (frameCount != originalFrameCount || !Arrays.equals(stackMapFrameList.toArray(), originalFrames)) { System.out.println("Original preverification ["+clazz.getName()+"]:"); new ClassPrinter().visitProgramMethod(programClass, programMethod); } } else if (frameCount != 0) { System.out.println("Original preverification empty ["+clazz.getName()+"."+method.getName(clazz)+"]"); } } if (frameCount == 0) { // Remove any stack map (table) attribute from the code attribute. new AttributesEditor(programClass, programMethod, codeAttribute, true).deleteAttribute(stackMapAttributeName); } else { Attribute stackMapAttribute; // Create the appropriate attribute. if (microEdition) { // Copy the frames into an array. FullFrame[] stackMapFrames = new FullFrame[frameCount]; stackMapFrameList.toArray(stackMapFrames); // Put the frames into a stack map attribute. stackMapAttribute = new StackMapAttribute(stackMapFrames); } else { // Copy the frames into an array. StackMapFrame[] stackMapFrames = new StackMapFrame[frameCount]; stackMapFrameList.toArray(stackMapFrames); // Put the frames into a stack map table attribute. stackMapAttribute = new StackMapTableAttribute(stackMapFrames); } // Fill out the name of the stack map attribute. stackMapAttribute.u2attributeNameIndex = new ConstantPoolEditor(programClass).addUtf8Constant(stackMapAttributeName); // Add the new stack map (table) attribute to the code attribute. new AttributesEditor(programClass, programMethod, codeAttribute, true).addAttribute(stackMapAttribute); if (DEBUG) { System.out.println("Preverifier ["+programClass.getName()+"."+programMethod.getName(programClass)+"]:"); stackMapAttribute.accept(programClass, programMethod, codeAttribute, new ClassPrinter()); } } // Apply code modifications, deleting unreachable code. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } // Small utility methods. /** * Creates and returns the verification types corresponding to the given * variables. If necessary, class constants are added to the constant pool * of the given class. */ private VerificationType[] correspondingVerificationTypes(ProgramClass programClass, ProgramMethod programMethod, CodeAttribute codeAttribute, int offset, TracedVariables variables) { int maximumVariablesSize = variables.size(); int typeCount = 0; int typeIndex = 0; // Count the the number of verification types, ignoring any nulls at // the end. for (int index = 0; index < maximumVariablesSize; index++) { Value value = variables.getValue(index); typeIndex++; // Remember the maximum live type index. if (value != null && (offset == PartialEvaluator.AT_METHOD_ENTRY || livenessAnalyzer.isAliveBefore(offset, index))) { typeCount = typeIndex; // Category 2 types that are alive are stored as single entries. if (value.isCategory2()) { index++; } } } // Create and fill out the verification types. VerificationType[] types = new VerificationType[typeCount]; typeIndex = 0; // Note the slightly different terminating condition, because the // types may have been truncated. for (int index = 0; typeIndex < typeCount; index++) { Value value = variables.getValue(index); Value producerValue = variables.getProducerValue(index); // Fill out the type. VerificationType type; if (value != null && (offset == PartialEvaluator.AT_METHOD_ENTRY || livenessAnalyzer.isAliveBefore(offset, index))) { type = correspondingVerificationType(programClass, programMethod, codeAttribute, offset, index == 0, value, producerValue); // Category 2 types that are alive are stored as single entries. if (value.isCategory2()) { index++; } } else { type = VerificationTypeFactory.createTopType(); } types[typeIndex++] = type; } return types; } /** * Creates and returns the verification types corresponding to the given * stack. If necessary, class constants are added to the constant pool * of the given class. */ private VerificationType[] correspondingVerificationTypes(ProgramClass programClass, ProgramMethod programMethod, CodeAttribute codeAttribute, int offset, TracedStack stack) { int maximumStackSize = stack.size(); int typeCount = 0; // Count the the number of verification types. for (int index = 0; index < maximumStackSize; index++) { // We have to work down from the top of the stack. Value value = stack.getTop(index); typeCount++; // Category 2 types are stored as single entries. if (value.isCategory2()) { index++; } } // Create and fill out the verification types. VerificationType[] types = new VerificationType[typeCount]; int typeIndex = typeCount; for (int index = 0; index < maximumStackSize; index++) { // We have to work down from the top of the stack. Value value = stack.getTop(index); Value producerValue = stack.getTopProducerValue(index); // Fill out the type. types[--typeIndex] = correspondingVerificationType(programClass, programMethod, codeAttribute, offset, false, value, producerValue); // Category 2 types are stored as single entries. if (value.isCategory2()) { index++; } } return types; } /** * Creates and returns the verification type corresponding to the given * value. If necessary, a class constant is added to the constant pool of * the given class. */ private VerificationType correspondingVerificationType(ProgramClass programClass, ProgramMethod programMethod, CodeAttribute codeAttribute, int offset, boolean isVariable0, Value value, Value producerValue) { if (value == null) { return VerificationTypeFactory.createTopType(); } int type = value.computationalType(); switch (type) { case Value.TYPE_INSTRUCTION_OFFSET: case Value.TYPE_INTEGER: return VerificationTypeFactory.createIntegerType(); case Value.TYPE_LONG: return VerificationTypeFactory.createLongType(); case Value.TYPE_FLOAT: return VerificationTypeFactory.createFloatType(); case Value.TYPE_DOUBLE: return VerificationTypeFactory.createDoubleType(); case Value.TYPE_TOP: return VerificationTypeFactory.createTopType(); case Value.TYPE_REFERENCE: // Is it a Null type? ReferenceValue referenceValue = value.referenceValue(); if (referenceValue.isNull() == Value.ALWAYS) { return VerificationTypeFactory.createNullType(); } // Does the reference type have a single producer? if (offset != PartialEvaluator.AT_METHOD_ENTRY) { InstructionOffsetValue producers = producerValue.instructionOffsetValue(); if (producers.instructionOffsetCount() == 1) { int producerOffset = producers.instructionOffset(0); // Follow any dup or swap instructions. while (producerOffset != PartialEvaluator.AT_METHOD_ENTRY && isDupOrSwap(codeAttribute.code[producerOffset])) { producers = partialEvaluator.getStackBefore(producerOffset).getTopProducerValue(0).instructionOffsetValue(); producerOffset = producers.instructionOffset(0); } // Are we in an instance initialization method, // before the super initialization, loading "this"? if (partialEvaluator.isInitializer() && offset <= partialEvaluator.superInitializationOffset() && (isVariable0 || producerOffset > PartialEvaluator.AT_METHOD_ENTRY && codeAttribute.code[producerOffset] == InstructionConstants.OP_ALOAD_0)) { // It's an UninitializedThis type. return VerificationTypeFactory.createUninitializedThisType(); } // Is the reference type newly created and still // uninitialized? if (producerOffset > PartialEvaluator.AT_METHOD_ENTRY && offset <= partialEvaluator.initializationOffset(producerOffset)) { // It's an Uninitialized type. return VerificationTypeFactory.createUninitializedType(producerOffset); } } } // It's an ordinary Object type. return VerificationTypeFactory.createObjectType(createClassConstant(programClass, referenceValue)); } throw new IllegalArgumentException("Unknown computational type ["+type+"]"); } /** * Finds or creates a class constant for the given reference value, and * returns its index in the constant pool. */ private int createClassConstant(ProgramClass programClass, ReferenceValue referenceValue) { return new ConstantPoolEditor(programClass).addClassConstant(referenceValue.getType(), referenceValue.getReferencedClass()); } /** * Compresses the given list of full frames, for use in a stack map table. */ private void compressStackMapFrames(VerificationType[] initialVariableTypes, List stackMapFrameList) { int previousVariablesCount = initialVariableTypes.length; VerificationType[] previousVariableTypes = initialVariableTypes; int previousOffset = -1; for (int index = 0; index < stackMapFrameList.size(); index++) { FullFrame fullFrame = (FullFrame)stackMapFrameList.get(index); int variablesCount = fullFrame.variablesCount; VerificationType[] variables = fullFrame.variables; int stackCount = fullFrame.stackCount; VerificationType[] stack = fullFrame.stack; // Start computing the compressed frame. // The default is the full frame. StackMapFrame compressedFrame = fullFrame; // Are all variables equal? if (variablesCount == previousVariablesCount && equalVerificationTypes(variables, previousVariableTypes, variablesCount)) { // Are the stacks equal? //if (stackCount == previousStackCount && // equalVerificationTypes(stack, previousStack, stackCount)) //{ // // Remove the identical frame. // stackMapFrameList.remove(index--); // // // Move on to the next frame (at the same index). // continue; //} // Is the new stack empty? //else if (stackCount == 0) { compressedFrame = new SameZeroFrame(); } // Does the new stack contain a single element? else if (stackCount == 1) { compressedFrame = new SameOneFrame(stack[0]); } } // Is the stack empty? else if (stackCount == 0) { int additionalVariablesCount = variablesCount - previousVariablesCount; // Are the variables chopped? if (additionalVariablesCount < 0 && additionalVariablesCount > -4 && equalVerificationTypes(variables, previousVariableTypes, variablesCount)) { compressedFrame = new LessZeroFrame((byte)-additionalVariablesCount); } // Are the variables extended? else if (//previousVariablesCount > 0 && additionalVariablesCount > 0 && additionalVariablesCount < 4 && equalVerificationTypes(variables, previousVariableTypes, previousVariablesCount)) { // Copy the additional variables into an array. VerificationType[] additionalVariables = new VerificationType[additionalVariablesCount]; System.arraycopy(variables, variablesCount - additionalVariablesCount, additionalVariables, 0, additionalVariablesCount); compressedFrame = new MoreZeroFrame(additionalVariables); } } // Compress the instruction offset. int offset = fullFrame.u2offsetDelta; compressedFrame.u2offsetDelta = offset - previousOffset - 1; previousOffset = offset; // Remember this frame. previousVariablesCount = fullFrame.variablesCount; previousVariableTypes = fullFrame.variables; // Replace the full frame. stackMapFrameList.set(index, compressedFrame); } } /** * Returns whether the given arrays of verification types are equal, up to * the given length. */ private boolean equalVerificationTypes(VerificationType[] types1, VerificationType[] types2, int length) { if (length > 0 && (types1.length < length || types2.length < length)) { return false; } for (int index = 0; index < length; index++) { if (!types1[index].equals(types2[index])) { return false; } } return true; } /** * Returns whether the given instruction opcode represents a dup or swap * instruction (dup, dup_x1, dup_x2, dup2, dup2_x1, dup2_x2, swap). */ private boolean isDupOrSwap(int opcode) { return opcode >= InstructionConstants.OP_DUP && opcode <= InstructionConstants.OP_SWAP; } } proguard4.8/src/proguard/GPL.java0000644000175000017500000001473011736333525015475 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.io.*; import java.util.*; /** * This class checks and prints out information about the GPL. * * @author Eric Lafortune */ public class GPL { /** * Prints out a note about the GPL if ProGuard is linked against unknown * code. */ public static void check() { ByteArrayOutputStream out = new ByteArrayOutputStream(); new Exception().printStackTrace(new PrintStream(out)); LineNumberReader reader = new LineNumberReader( new InputStreamReader( new ByteArrayInputStream(out.toByteArray()))); Set unknownPackageNames = unknownPackageNames(reader); if (unknownPackageNames.size() > 0) { String uniquePackageNames = uniquePackageNames(unknownPackageNames); System.out.println("ProGuard is released under the GNU General Public License. You therefore"); System.out.println("must ensure that programs that link to it ("+uniquePackageNames+"...)"); System.out.println("carry the GNU General Public License as well. Alternatively, you can"); System.out.println("apply for an exception with the author of ProGuard."); } } /** * Returns a set of package names from the given stack trace. */ private static Set unknownPackageNames(LineNumberReader reader) { Set packageNames = new HashSet(); try { while (true) { String line = reader.readLine(); if (line == null) { break; } line = line.trim(); if (line.startsWith("at ")) { line = line.substring(2).trim(); line = trimSuffix(line, '('); line = trimSuffix(line, '.'); line = trimSuffix(line, '.'); if (line.length() > 0 && !isKnown(line)) { packageNames.add(line); } } } } catch (IOException ex) { // We'll just stop looking for more names. } return packageNames; } /** * Returns a comma-separated list of package names from the set, excluding * any subpackages of packages in the set. */ private static String uniquePackageNames(Set packageNames) { StringBuffer buffer = new StringBuffer(); Iterator iterator = packageNames.iterator(); while (iterator.hasNext()) { String packageName = (String)iterator.next(); if (!containsPrefix(packageNames, packageName)) { buffer.append(packageName).append(", "); } } return buffer.toString(); } /** * Returns a given string without the suffix, as defined by the given * separator. */ private static String trimSuffix(String string, char separator) { int index = string.lastIndexOf(separator); return index < 0 ? "" : string.substring(0, index); } /** * Returns whether the given set contains a prefix of the given name. */ private static boolean containsPrefix(Set set, String name) { int index = 0; while (!set.contains(name.substring(0, index))) { index = name.indexOf('.', index + 1); if (index < 0) { return false; } } return true; } /** * Returns whether the given package name has been granted an exception * against the GPL linking clause, by the copyright holder of ProGuard. * This method is not legally binding, but of course the actual license is. * Please contact the copyright holder if you would like an exception for * your code as well. */ private static boolean isKnown(String packageName) { return packageName.startsWith("java") || packageName.startsWith("sun.reflect") || packageName.startsWith("proguard") || packageName.startsWith("org.apache.tools.ant") || packageName.startsWith("org.apache.tools.maven") || packageName.startsWith("org.eclipse") || packageName.startsWith("org.netbeans") || packageName.startsWith("com.android") || packageName.startsWith("com.sun.kvem") || packageName.startsWith("net.certiv.proguarddt") || packageName.startsWith("scala") || packageName.startsWith("sbt") || packageName.startsWith("xsbt") || packageName.startsWith("eclipseme") || packageName.startsWith("com.neomades") || packageName.startsWith("jg.j2me") || packageName.startsWith("jg.common") || packageName.startsWith("jg.buildengine"); } public static void main(String[] args) { LineNumberReader reader = new LineNumberReader( new InputStreamReader(System.in)); Set unknownPackageNames = unknownPackageNames(reader); if (unknownPackageNames.size() > 0) { String uniquePackageNames = uniquePackageNames(unknownPackageNames); System.out.println(uniquePackageNames); } } } proguard4.8/src/proguard/ConfigurationConstants.java0000644000175000017500000001754511736333525021566 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; /** * This class provides constants for parsing and writing ProGuard configurations. * * @author Eric Lafortune */ class ConfigurationConstants { public static final String OPTION_PREFIX = "-"; public static final String AT_DIRECTIVE = "@"; public static final String INCLUDE_DIRECTIVE = "-include"; public static final String BASE_DIRECTORY_DIRECTIVE = "-basedirectory"; public static final String INJARS_OPTION = "-injars"; public static final String OUTJARS_OPTION = "-outjars"; public static final String LIBRARYJARS_OPTION = "-libraryjars"; public static final String RESOURCEJARS_OPTION = "-resourcejars"; public static final String KEEP_OPTION = "-keep"; public static final String KEEP_CLASS_MEMBERS_OPTION = "-keepclassmembers"; public static final String KEEP_CLASSES_WITH_MEMBERS_OPTION = "-keepclasseswithmembers"; public static final String KEEP_NAMES_OPTION = "-keepnames"; public static final String KEEP_CLASS_MEMBER_NAMES_OPTION = "-keepclassmembernames"; public static final String KEEP_CLASSES_WITH_MEMBER_NAMES_OPTION = "-keepclasseswithmembernames"; public static final String ALLOW_SHRINKING_SUBOPTION = "allowshrinking"; public static final String ALLOW_OPTIMIZATION_SUBOPTION = "allowoptimization"; public static final String ALLOW_OBFUSCATION_SUBOPTION = "allowobfuscation"; public static final String PRINT_SEEDS_OPTION = "-printseeds"; public static final String DONT_SHRINK_OPTION = "-dontshrink"; public static final String PRINT_USAGE_OPTION = "-printusage"; public static final String WHY_ARE_YOU_KEEPING_OPTION = "-whyareyoukeeping"; public static final String DONT_OPTIMIZE_OPTION = "-dontoptimize"; public static final String OPTIMIZATIONS = "-optimizations"; public static final String OPTIMIZATION_PASSES = "-optimizationpasses"; public static final String ASSUME_NO_SIDE_EFFECTS_OPTION = "-assumenosideeffects"; public static final String ALLOW_ACCESS_MODIFICATION_OPTION = "-allowaccessmodification"; public static final String MERGE_INTERFACES_AGGRESSIVELY_OPTION = "-mergeinterfacesaggressively"; public static final String DONT_OBFUSCATE_OPTION = "-dontobfuscate"; public static final String PRINT_MAPPING_OPTION = "-printmapping"; public static final String APPLY_MAPPING_OPTION = "-applymapping"; public static final String OBFUSCATION_DICTIONARY_OPTION = "-obfuscationdictionary"; public static final String CLASS_OBFUSCATION_DICTIONARY_OPTION = "-classobfuscationdictionary"; public static final String PACKAGE_OBFUSCATION_DICTIONARY_OPTION = "-packageobfuscationdictionary"; public static final String OVERLOAD_AGGRESSIVELY_OPTION = "-overloadaggressively"; public static final String USE_UNIQUE_CLASS_MEMBER_NAMES_OPTION = "-useuniqueclassmembernames"; public static final String DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION = "-dontusemixedcaseclassnames"; public static final String KEEP_PACKAGE_NAMES_OPTION = "-keeppackagenames"; public static final String FLATTEN_PACKAGE_HIERARCHY_OPTION = "-flattenpackagehierarchy"; public static final String REPACKAGE_CLASSES_OPTION = "-repackageclasses"; public static final String DEFAULT_PACKAGE_OPTION = "-defaultpackage"; public static final String KEEP_ATTRIBUTES_OPTION = "-keepattributes"; public static final String KEEP_PARAMETER_NAMES_OPTION = "-keepparameternames"; public static final String RENAME_SOURCE_FILE_ATTRIBUTE_OPTION = "-renamesourcefileattribute"; public static final String ADAPT_CLASS_STRINGS_OPTION = "-adaptclassstrings"; public static final String ADAPT_RESOURCE_FILE_NAMES_OPTION = "-adaptresourcefilenames"; public static final String ADAPT_RESOURCE_FILE_CONTENTS_OPTION = "-adaptresourcefilecontents"; public static final String DONT_PREVERIFY_OPTION = "-dontpreverify"; public static final String MICRO_EDITION_OPTION = "-microedition"; public static final String VERBOSE_OPTION = "-verbose"; public static final String DONT_NOTE_OPTION = "-dontnote"; public static final String DONT_WARN_OPTION = "-dontwarn"; public static final String IGNORE_WARNINGS_OPTION = "-ignorewarnings"; public static final String PRINT_CONFIGURATION_OPTION = "-printconfiguration"; public static final String DUMP_OPTION = "-dump"; public static final String SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION = "-skipnonpubliclibraryclasses"; public static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION = "-dontskipnonpubliclibraryclasses"; public static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION = "-dontskipnonpubliclibraryclassmembers"; public static final String TARGET_OPTION = "-target"; public static final String KEEP_DIRECTORIES_OPTION = "-keepdirectories"; public static final String FORCE_PROCESSING_OPTION = "-forceprocessing"; public static final String ANY_ATTRIBUTE_KEYWORD = "*"; public static final String ATTRIBUTE_SEPARATOR_KEYWORD = ","; public static final String JAR_SEPARATOR_KEYWORD = System.getProperty("path.separator"); public static final char OPEN_SYSTEM_PROPERTY = '<'; public static final char CLOSE_SYSTEM_PROPERTY = '>'; public static final String ANNOTATION_KEYWORD = "@"; public static final String NEGATOR_KEYWORD = "!"; public static final String CLASS_KEYWORD = "class"; public static final String ANY_CLASS_KEYWORD = "*"; public static final String ANY_TYPE_KEYWORD = "***"; public static final String IMPLEMENTS_KEYWORD = "implements"; public static final String EXTENDS_KEYWORD = "extends"; public static final String OPEN_KEYWORD = "{"; public static final String ANY_CLASS_MEMBER_KEYWORD = "*"; public static final String ANY_FIELD_KEYWORD = ""; public static final String ANY_METHOD_KEYWORD = ""; public static final String OPEN_ARGUMENTS_KEYWORD = "("; public static final String ARGUMENT_SEPARATOR_KEYWORD = ","; public static final String ANY_ARGUMENTS_KEYWORD = "..."; public static final String CLOSE_ARGUMENTS_KEYWORD = ")"; public static final String SEPARATOR_KEYWORD = ";"; public static final String CLOSE_KEYWORD = "}"; } proguard4.8/src/proguard/KeepClassMemberChecker.java0000644000175000017500000000616111736333525021341 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.util.*; import proguard.classfile.visitor.ClassVisitor; import java.util.List; /** * This class checks if the user has forgotten to specify class members in * some keep options in the configuration. * * @author Eric Lafortune */ public class KeepClassMemberChecker extends SimplifiedVisitor implements ClassVisitor { private final WarningPrinter notePrinter; /** * Creates a new KeepClassMemberChecker. */ public KeepClassMemberChecker(WarningPrinter notePrinter) { this.notePrinter = notePrinter; } /** * Checks if the given class specifications try to keep class members * without actually specifying any, printing notes if necessary. Returns * the number of notes printed. */ public void checkClassSpecifications(List keepClassSpecifications) { if (keepClassSpecifications != null) { for (int index = 0; index < keepClassSpecifications.size(); index++) { KeepClassSpecification keepClassSpecification = (KeepClassSpecification)keepClassSpecifications.get(index); if (!keepClassSpecification.markClasses && (keepClassSpecification.fieldSpecifications == null || keepClassSpecification.fieldSpecifications.size() == 0) && (keepClassSpecification.methodSpecifications == null || keepClassSpecification.methodSpecifications.size() == 0)) { String className = keepClassSpecification.className; if (className == null) { className = keepClassSpecification.extendsClassName; } if (className != null && notePrinter.accepts(className)) { notePrinter.print(className, "Note: the configuration doesn't specify which class members to keep for class '" + ClassUtil.externalClassName(className) + "'"); } } } } } } proguard4.8/src/proguard/OutputWriter.java0000644000175000017500000002666011736333525017555 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.ClassPool; import proguard.classfile.util.ClassUtil; import proguard.io.*; import java.io.IOException; import java.util.*; /** * This class writes the output class files. * * @author Eric Lafortune */ public class OutputWriter { private final Configuration configuration; /** * Creates a new OutputWriter to write output class files as specified by * the given configuration. */ public OutputWriter(Configuration configuration) { this.configuration = configuration; } /** * Writes the given class pool to class files, based on the current * configuration. */ public void execute(ClassPool programClassPool) throws IOException { ClassPath programJars = configuration.programJars; // Perform a check on the first jar. ClassPathEntry firstEntry = programJars.get(0); if (firstEntry.isOutput()) { throw new IOException("The output jar [" + firstEntry.getName() + "] must be specified after an input jar, or it will be empty."); } // Check if the first of two subsequent the output jars has a filter. for (int index = 0; index < programJars.size() - 1; index++) { ClassPathEntry entry = programJars.get(index); if (entry.isOutput()) { if (entry.getFilter() == null && entry.getJarFilter() == null && entry.getWarFilter() == null && entry.getEarFilter() == null && entry.getZipFilter() == null && programJars.get(index + 1).isOutput()) { throw new IOException("The output jar [" + entry.getName() + "] must have a filter, or all subsequent output jars will be empty."); } } } // Check if the output jar names are different from the input jar names. for (int outIndex = 0; outIndex < programJars.size() - 1; outIndex++) { ClassPathEntry entry = programJars.get(outIndex); if (entry.isOutput()) { for (int inIndex = 0; inIndex < programJars.size(); inIndex++) { ClassPathEntry otherEntry = programJars.get(inIndex); if (!otherEntry.isOutput() && entry.getFile().equals(otherEntry.getFile())) { throw new IOException("The output jar [" + entry.getName() + "] must be different from all input jars."); } } } } // Check for potential problems with mixed-case class names on // case-insensitive file systems. if (configuration.obfuscate && configuration.useMixedCaseClassNames && configuration.classObfuscationDictionary == null && (configuration.note == null || !configuration.note.isEmpty())) { String os = System.getProperty("os.name").toLowerCase(); if (os.startsWith("windows") || os.startsWith("mac os")) { // Go over all program class path entries. for (int index = 0; index < programJars.size(); index++) { // Is it an output directory? ClassPathEntry entry = programJars.get(index); if (entry.isOutput() && !entry.isJar() && !entry.isWar() && !entry.isEar() && !entry.isZip()) { System.out.println("Note: you're writing the processed class files to a directory [" + entry.getName() +"]."); System.out.println(" This will likely cause problems with obfuscated mixed-case class names."); System.out.println(" You should consider writing the output to a jar file, or otherwise"); System.out.println(" specify '-dontusemixedclassnames'."); break; } } } } int firstInputIndex = 0; int lastInputIndex = 0; // Go over all program class path entries. for (int index = 0; index < programJars.size(); index++) { // Is it an input entry? ClassPathEntry entry = programJars.get(index); if (!entry.isOutput()) { // Remember the index of the last input entry. lastInputIndex = index; } else { // Check if this the last output entry in a series. int nextIndex = index + 1; if (nextIndex == programJars.size() || !programJars.get(nextIndex).isOutput()) { // Write the processed input entries to the output entries. writeOutput(programClassPool, programJars, firstInputIndex, lastInputIndex + 1, nextIndex); // Start with the next series of input entries. firstInputIndex = nextIndex; } } } } /** * Transfers the specified input jars to the specified output jars. */ private void writeOutput(ClassPool programClassPool, ClassPath classPath, int fromInputIndex, int fromOutputIndex, int toOutputIndex) throws IOException { try { // Construct the writer that can write jars, wars, ears, zips, and // directories, cascading over the specified output entries. DataEntryWriter writer = DataEntryWriterFactory.createDataEntryWriter(classPath, fromOutputIndex, toOutputIndex); // The writer will be used to write possibly obfuscated class files. DataEntryReader classRewriter = new ClassRewriter(programClassPool, writer); // The writer will also be used to write resource files. DataEntryReader resourceCopier = new DataEntryCopier(writer); DataEntryReader resourceRewriter = resourceCopier; // Wrap the resource writer with a filter and a data entry rewriter, // if required. if (configuration.adaptResourceFileContents != null) { resourceRewriter = new NameFilter(configuration.adaptResourceFileContents, new NameFilter("META-INF/MANIFEST.MF,META-INF/*.SF", new ManifestRewriter(programClassPool, writer), new DataEntryRewriter(programClassPool, writer)), resourceRewriter); } // Wrap the resource writer with a filter and a data entry renamer, // if required. if (configuration.adaptResourceFileNames != null) { Map packagePrefixMap = createPackagePrefixMap(programClassPool); resourceRewriter = new NameFilter(configuration.adaptResourceFileNames, new DataEntryObfuscator(programClassPool, packagePrefixMap, resourceRewriter), resourceRewriter); } DataEntryReader directoryRewriter = null; // Wrap the directory writer with a filter and a data entry renamer, // if required. if (configuration.keepDirectories != null) { Map packagePrefixMap = createPackagePrefixMap(programClassPool); directoryRewriter = new NameFilter(configuration.keepDirectories, new DataEntryRenamer(packagePrefixMap, resourceCopier, resourceCopier)); } // Create the reader that can write class files and copy directories // and resource files to the main writer. DataEntryReader reader = new ClassFilter( classRewriter, new DirectoryFilter(directoryRewriter, resourceRewriter)); // Go over the specified input entries and write their processed // versions. new InputReader(configuration).readInput(" Copying resources from program ", classPath, fromInputIndex, fromOutputIndex, reader); // Close all output entries. writer.close(); } catch (IOException ex) { throw (IOException)new IOException("Can't write [" + classPath.get(fromOutputIndex).getName() + "] (" + ex.getMessage() + ")").initCause(ex); } } /** * Creates a map of old package prefixes to new package prefixes, based on * the given class pool. */ private static Map createPackagePrefixMap(ClassPool classPool) { Map packagePrefixMap = new HashMap(); Iterator iterator = classPool.classNames(); while (iterator.hasNext()) { String className = (String)iterator.next(); String packagePrefix = ClassUtil.internalPackagePrefix(className); String mappedNewPackagePrefix = (String)packagePrefixMap.get(packagePrefix); if (mappedNewPackagePrefix == null || !mappedNewPackagePrefix.equals(packagePrefix)) { String newClassName = classPool.getClass(className).getName(); String newPackagePrefix = ClassUtil.internalPackagePrefix(newClassName); packagePrefixMap.put(packagePrefix, newPackagePrefix); } } return packagePrefixMap; } } proguard4.8/src/proguard/SubclassedClassFilter.java0000644000175000017500000000344411736333525021277 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor delegates all its method calls to another ClassVisitor, * but only for Clazz objects that are being subclassed. * * @author Eric Lafortune */ final class SubclassedClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; public SubclassedClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (programClass.subClasses != null) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (libraryClass.subClasses != null) { classVisitor.visitLibraryClass(libraryClass); } } } proguard4.8/src/proguard/ConfigurationParser.java0000664000175000017500000016407611752562414021051 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.ClassConstants; import proguard.classfile.util.ClassUtil; import proguard.util.ListUtil; import java.io.*; import java.net.URL; import java.util.*; /** * This class parses ProGuard configurations. Configurations can be read from an * array of arguments or from a configuration file or URL. External references * in file names ('<...>') can be resolved against a given set of properties. * * @author Eric Lafortune */ public class ConfigurationParser { private final WordReader reader; private final Properties properties; private String nextWord; private String lastComments; /** * Creates a new ConfigurationParser for the given String arguments and * the given Properties. */ public ConfigurationParser(String[] args, Properties properties) throws IOException { this(args, null, properties); } /** * Creates a new ConfigurationParser for the given String arguments, * with the given base directory and the given Properties. */ public ConfigurationParser(String[] args, File baseDir, Properties properties) throws IOException { this(new ArgumentWordReader(args, baseDir), properties); } /** * Creates a new ConfigurationParser for the given lines, * with the given base directory and the given Properties. */ public ConfigurationParser(String lines, String description, File baseDir, Properties properties) throws IOException { this(new LineWordReader(new LineNumberReader(new StringReader(lines)), description, baseDir), properties); } /** * Creates a new ConfigurationParser for the given file and the given * Properties. */ public ConfigurationParser(File file, Properties properties) throws IOException { this(new FileWordReader(file), properties); } /** * Creates a new ConfigurationParser for the given URL and the given * Properties. */ public ConfigurationParser(URL url, Properties properties) throws IOException { this(new FileWordReader(url), properties); } /** * Creates a new ConfigurationParser for the given word reader and the * given Properties. */ public ConfigurationParser(WordReader reader, Properties properties) throws IOException { this.reader = reader; this.properties = properties; readNextWord(); } /** * Parses and returns the configuration. * @param configuration the configuration that is updated as a side-effect. * @throws ParseException if the any of the configuration settings contains * a syntax error. * @throws IOException if an IO error occurs while reading a configuration. */ public void parse(Configuration configuration) throws ParseException, IOException { while (nextWord != null) { lastComments = reader.lastComments(); // First include directives. if (ConfigurationConstants.AT_DIRECTIVE .startsWith(nextWord) || ConfigurationConstants.INCLUDE_DIRECTIVE .startsWith(nextWord)) configuration.lastModified = parseIncludeArgument(configuration.lastModified); else if (ConfigurationConstants.BASE_DIRECTORY_DIRECTIVE .startsWith(nextWord)) parseBaseDirectoryArgument(); // Then configuration options with or without arguments. else if (ConfigurationConstants.INJARS_OPTION .startsWith(nextWord)) configuration.programJars = parseClassPathArgument(configuration.programJars, false); else if (ConfigurationConstants.OUTJARS_OPTION .startsWith(nextWord)) configuration.programJars = parseClassPathArgument(configuration.programJars, true); else if (ConfigurationConstants.LIBRARYJARS_OPTION .startsWith(nextWord)) configuration.libraryJars = parseClassPathArgument(configuration.libraryJars, false); else if (ConfigurationConstants.RESOURCEJARS_OPTION .startsWith(nextWord)) throw new ParseException("The '-resourcejars' option is no longer supported. Please use the '-injars' option for all input"); else if (ConfigurationConstants.SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION .startsWith(nextWord)) configuration.skipNonPublicLibraryClasses = parseNoArgument(true); else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION .startsWith(nextWord)) configuration.skipNonPublicLibraryClasses = parseNoArgument(false); else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION.startsWith(nextWord)) configuration.skipNonPublicLibraryClassMembers = parseNoArgument(false); else if (ConfigurationConstants.TARGET_OPTION .startsWith(nextWord)) configuration.targetClassVersion = parseClassVersion(); else if (ConfigurationConstants.FORCE_PROCESSING_OPTION .startsWith(nextWord)) configuration.lastModified = parseNoArgument(Long.MAX_VALUE); else if (ConfigurationConstants.KEEP_OPTION .startsWith(nextWord)) configuration.keep = parseKeepClassSpecificationArguments(configuration.keep, true, false, false); else if (ConfigurationConstants.KEEP_CLASS_MEMBERS_OPTION .startsWith(nextWord)) configuration.keep = parseKeepClassSpecificationArguments(configuration.keep, false, false, false); else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBERS_OPTION .startsWith(nextWord)) configuration.keep = parseKeepClassSpecificationArguments(configuration.keep, false, true, false); else if (ConfigurationConstants.KEEP_NAMES_OPTION .startsWith(nextWord)) configuration.keep = parseKeepClassSpecificationArguments(configuration.keep, true, false, true); else if (ConfigurationConstants.KEEP_CLASS_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.keep = parseKeepClassSpecificationArguments(configuration.keep, false, false, true); else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.keep = parseKeepClassSpecificationArguments(configuration.keep, false, true, true); else if (ConfigurationConstants.PRINT_SEEDS_OPTION .startsWith(nextWord)) configuration.printSeeds = parseOptionalFile(); // After '-keep'. else if (ConfigurationConstants.KEEP_DIRECTORIES_OPTION .startsWith(nextWord)) configuration.keepDirectories = parseCommaSeparatedList("directory name", true, true, false, true, false, true, false, false, configuration.keepDirectories); else if (ConfigurationConstants.DONT_SHRINK_OPTION .startsWith(nextWord)) configuration.shrink = parseNoArgument(false); else if (ConfigurationConstants.PRINT_USAGE_OPTION .startsWith(nextWord)) configuration.printUsage = parseOptionalFile(); else if (ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION .startsWith(nextWord)) configuration.whyAreYouKeeping = parseClassSpecificationArguments(configuration.whyAreYouKeeping); else if (ConfigurationConstants.DONT_OPTIMIZE_OPTION .startsWith(nextWord)) configuration.optimize = parseNoArgument(false); else if (ConfigurationConstants.OPTIMIZATION_PASSES .startsWith(nextWord)) configuration.optimizationPasses = parseIntegerArgument(); else if (ConfigurationConstants.OPTIMIZATIONS .startsWith(nextWord)) configuration.optimizations = parseCommaSeparatedList("optimization name", true, false, false, false, false, false, false, false, configuration.optimizations); else if (ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION .startsWith(nextWord)) configuration.assumeNoSideEffects = parseClassSpecificationArguments(configuration.assumeNoSideEffects); else if (ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION .startsWith(nextWord)) configuration.allowAccessModification = parseNoArgument(true); else if (ConfigurationConstants.MERGE_INTERFACES_AGGRESSIVELY_OPTION .startsWith(nextWord)) configuration.mergeInterfacesAggressively = parseNoArgument(true); else if (ConfigurationConstants.DONT_OBFUSCATE_OPTION .startsWith(nextWord)) configuration.obfuscate = parseNoArgument(false); else if (ConfigurationConstants.PRINT_MAPPING_OPTION .startsWith(nextWord)) configuration.printMapping = parseOptionalFile(); else if (ConfigurationConstants.APPLY_MAPPING_OPTION .startsWith(nextWord)) configuration.applyMapping = parseFile(); else if (ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION .startsWith(nextWord)) configuration.obfuscationDictionary = parseFile(); else if (ConfigurationConstants.CLASS_OBFUSCATION_DICTIONARY_OPTION .startsWith(nextWord)) configuration.classObfuscationDictionary = parseFile(); else if (ConfigurationConstants.PACKAGE_OBFUSCATION_DICTIONARY_OPTION .startsWith(nextWord)) configuration.packageObfuscationDictionary = parseFile(); else if (ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION .startsWith(nextWord)) configuration.overloadAggressively = parseNoArgument(true); else if (ConfigurationConstants.USE_UNIQUE_CLASS_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.useUniqueClassMemberNames = parseNoArgument(true); else if (ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION .startsWith(nextWord)) configuration.useMixedCaseClassNames = parseNoArgument(false); else if (ConfigurationConstants.KEEP_PACKAGE_NAMES_OPTION .startsWith(nextWord)) configuration.keepPackageNames = parseCommaSeparatedList("package name", true, true, false, false, true, false, true, false, configuration.keepPackageNames); else if (ConfigurationConstants.FLATTEN_PACKAGE_HIERARCHY_OPTION .startsWith(nextWord)) configuration.flattenPackageHierarchy = ClassUtil.internalClassName(parseOptionalArgument()); else if (ConfigurationConstants.REPACKAGE_CLASSES_OPTION .startsWith(nextWord)) configuration.repackageClasses = ClassUtil.internalClassName(parseOptionalArgument()); else if (ConfigurationConstants.DEFAULT_PACKAGE_OPTION .startsWith(nextWord)) configuration.repackageClasses = ClassUtil.internalClassName(parseOptionalArgument()); else if (ConfigurationConstants.KEEP_ATTRIBUTES_OPTION .startsWith(nextWord)) configuration.keepAttributes = parseCommaSeparatedList("attribute name", true, true, false, false, true, false, false, false, configuration.keepAttributes); else if (ConfigurationConstants.KEEP_PARAMETER_NAMES_OPTION .startsWith(nextWord)) configuration.keepParameterNames = parseNoArgument(true); else if (ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION .startsWith(nextWord)) configuration.newSourceFileAttribute = parseOptionalArgument(); else if (ConfigurationConstants.ADAPT_CLASS_STRINGS_OPTION .startsWith(nextWord)) configuration.adaptClassStrings = parseCommaSeparatedList("class name", true, true, false, false, true, false, true, false, configuration.adaptClassStrings); else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION .startsWith(nextWord)) configuration.adaptResourceFileNames = parseCommaSeparatedList("resource file name", true, true, false, true, false, false, false, false, configuration.adaptResourceFileNames); else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_CONTENTS_OPTION .startsWith(nextWord)) configuration.adaptResourceFileContents = parseCommaSeparatedList("resource file name", true, true, false, true, false, false, false, false, configuration.adaptResourceFileContents); else if (ConfigurationConstants.DONT_PREVERIFY_OPTION .startsWith(nextWord)) configuration.preverify = parseNoArgument(false); else if (ConfigurationConstants.MICRO_EDITION_OPTION .startsWith(nextWord)) configuration.microEdition = parseNoArgument(true); else if (ConfigurationConstants.VERBOSE_OPTION .startsWith(nextWord)) configuration.verbose = parseNoArgument(true); else if (ConfigurationConstants.DONT_NOTE_OPTION .startsWith(nextWord)) configuration.note = parseCommaSeparatedList("class name", true, true, false, false, true, false, true, false, configuration.note); else if (ConfigurationConstants.DONT_WARN_OPTION .startsWith(nextWord)) configuration.warn = parseCommaSeparatedList("class name", true, true, false, false, true, false, true, false, configuration.warn); else if (ConfigurationConstants.IGNORE_WARNINGS_OPTION .startsWith(nextWord)) configuration.ignoreWarnings = parseNoArgument(true); else if (ConfigurationConstants.PRINT_CONFIGURATION_OPTION .startsWith(nextWord)) configuration.printConfiguration = parseOptionalFile(); else if (ConfigurationConstants.DUMP_OPTION .startsWith(nextWord)) configuration.dump = parseOptionalFile(); else { throw new ParseException("Unknown option " + reader.locationDescription()); } } } /** * Closes the configuration. * @throws IOException if an IO error occurs while closing the configuration. */ public void close() throws IOException { if (reader != null) { reader.close(); } } private long parseIncludeArgument(long lastModified) throws ParseException, IOException { // Read the configuation file name. readNextWord("configuration file name", true, false); File file = file(nextWord); reader.includeWordReader(new FileWordReader(file)); readNextWord(); return Math.max(lastModified, file.lastModified()); } private void parseBaseDirectoryArgument() throws ParseException, IOException { // Read the base directory name. readNextWord("base directory name", true, false); reader.setBaseDir(file(nextWord)); readNextWord(); } private ClassPath parseClassPathArgument(ClassPath classPath, boolean isOutput) throws ParseException, IOException { // Create a new List if necessary. if (classPath == null) { classPath = new ClassPath(); } while (true) { // Read the next jar name. readNextWord("jar or directory name", true, false); // Create a new class path entry. ClassPathEntry entry = new ClassPathEntry(file(nextWord), isOutput); // Read the opening parenthesis or the separator, if any. readNextWord(); // Read the optional filters. if (!configurationEnd() && ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(nextWord)) { // Read all filters in an array. List[] filters = new List[5]; int counter = 0; do { // Read the filter. filters[counter++] = parseCommaSeparatedList("filter", true, true, true, true, false, true, false, false, null); } while (counter < filters.length && ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)); // Make sure there is a closing parenthesis. if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord)) { throw new ParseException("Expecting separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + "' or '" + ConfigurationConstants.SEPARATOR_KEYWORD + "', or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD + "' before " + reader.locationDescription()); } // Set all filters from the array on the entry. entry.setFilter(filters[--counter]); if (counter > 0) { entry.setJarFilter(filters[--counter]); if (counter > 0) { entry.setWarFilter(filters[--counter]); if (counter > 0) { entry.setEarFilter(filters[--counter]); if (counter > 0) { entry.setZipFilter(filters[--counter]); } } } } // Read the separator, if any. readNextWord(); } // Add the entry to the list. classPath.add(entry); if (configurationEnd()) { return classPath; } if (!nextWord.equals(ConfigurationConstants.JAR_SEPARATOR_KEYWORD)) { throw new ParseException("Expecting class path separator '" + ConfigurationConstants.JAR_SEPARATOR_KEYWORD + "' before " + reader.locationDescription()); } } } private int parseClassVersion() throws ParseException, IOException { // Read the obligatory target. readNextWord("java version"); int classVersion = ClassUtil.internalClassVersion(nextWord); if (classVersion == 0) { throw new ParseException("Unsupported java version " + reader.locationDescription()); } readNextWord(); return classVersion; } private int parseIntegerArgument() throws ParseException, IOException { try { // Read the obligatory integer. readNextWord("integer"); int integer = Integer.parseInt(nextWord); readNextWord(); return integer; } catch (NumberFormatException e) { throw new ParseException("Expecting integer argument instead of '" + nextWord + "' before " + reader.locationDescription()); } } private File parseFile() throws ParseException, IOException { // Read the obligatory file name. readNextWord("file name", true, false); // Make sure the file is properly resolved. File file = file(nextWord); readNextWord(); return file; } private File parseOptionalFile() throws ParseException, IOException { // Read the optional file name. readNextWord(true); // Didn't the user specify a file name? if (configurationEnd()) { return new File(""); } // Make sure the file is properly resolved. File file = file(nextWord); readNextWord(); return file; } private String parseOptionalArgument() throws IOException { // Read the optional argument. readNextWord(); // Didn't the user specify an argument? if (configurationEnd()) { return ""; } String argument = nextWord; readNextWord(); return argument; } private boolean parseNoArgument(boolean value) throws IOException { readNextWord(); return value; } private long parseNoArgument(long value) throws IOException { readNextWord(); return value; } private List parseKeepClassSpecificationArguments(List keepClassSpecifications, boolean markClasses, boolean markConditionally, boolean allowShrinking) throws ParseException, IOException { // Create a new List if necessary. if (keepClassSpecifications == null) { keepClassSpecifications = new ArrayList(); } //boolean allowShrinking = false; boolean allowOptimization = false; boolean allowObfuscation = false; // Read the keep modifiers. while (true) { readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD + "', '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'", false, true); if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD.equals(nextWord)) { // Not a comma. Stop parsing the keep modifiers. break; } readNextWord("keyword '" + ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION + "', '" + ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION + "', or '" + ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION + "'"); if (ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION .startsWith(nextWord)) { allowShrinking = true; } else if (ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION.startsWith(nextWord)) { allowOptimization = true; } else if (ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION .startsWith(nextWord)) { allowObfuscation = true; } else { throw new ParseException("Expecting keyword '" + ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION + "', '" + ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION + "', or '" + ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION + "' before " + reader.locationDescription()); } } // Read the class configuration. ClassSpecification classSpecification = parseClassSpecificationArguments(); // Create and add the keep configuration. keepClassSpecifications.add(new KeepClassSpecification(markClasses, markConditionally, allowShrinking, allowOptimization, allowObfuscation, classSpecification)); return keepClassSpecifications; } private List parseClassSpecificationArguments(List classSpecifications) throws ParseException, IOException { // Create a new List if necessary. if (classSpecifications == null) { classSpecifications = new ArrayList(); } // Read and add the class configuration. readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD + "', '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'", false, true); classSpecifications.add(parseClassSpecificationArguments()); return classSpecifications; } private ClassSpecification parseClassSpecificationArguments() throws ParseException, IOException { // Clear the annotation type. String annotationType = null; // Clear the class access modifiers. int requiredSetClassAccessFlags = 0; int requiredUnsetClassAccessFlags = 0; // Parse the class annotations and access modifiers until the class keyword. while (!ConfigurationConstants.CLASS_KEYWORD.equals(nextWord)) { // Strip the negating sign, if any. boolean negated = nextWord.startsWith(ConfigurationConstants.NEGATOR_KEYWORD); String strippedWord = negated ? nextWord.substring(1) : nextWord; // Parse the class access modifiers. int accessFlag = strippedWord.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : strippedWord.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : strippedWord.equals(ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE : strippedWord.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : strippedWord.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC : strippedWord.equals(ClassConstants.EXTERNAL_ACC_ANNOTATION) ? ClassConstants.INTERNAL_ACC_ANNOTATTION : strippedWord.equals(ClassConstants.EXTERNAL_ACC_ENUM) ? ClassConstants.INTERNAL_ACC_ENUM : unknownAccessFlag(); // Is it an annotation modifier? if (accessFlag == ClassConstants.INTERNAL_ACC_ANNOTATTION) { // Already read the next word. readNextWord("annotation type or keyword '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "'", false, false); // Is the next word actually an annotation type? if (!nextWord.equals(ClassConstants.EXTERNAL_ACC_INTERFACE) && !nextWord.equals(ClassConstants.EXTERNAL_ACC_ENUM) && !nextWord.equals(ConfigurationConstants.CLASS_KEYWORD)) { // Parse the annotation type. annotationType = ListUtil.commaSeparatedString( parseCommaSeparatedList("annotation type", false, false, false, false, true, false, false, true, null), false); // Continue parsing the access modifier that we just read // in the next cycle. continue; } // Otherwise just handle the annotation modifier. } if (!negated) { requiredSetClassAccessFlags |= accessFlag; } else { requiredUnsetClassAccessFlags |= accessFlag; } if ((requiredSetClassAccessFlags & requiredUnsetClassAccessFlags) != 0) { throw new ParseException("Conflicting class access modifiers for '" + strippedWord + "' before " + reader.locationDescription()); } if (strippedWord.equals(ClassConstants.EXTERNAL_ACC_INTERFACE) || strippedWord.equals(ClassConstants.EXTERNAL_ACC_ENUM) || strippedWord.equals(ConfigurationConstants.CLASS_KEYWORD)) { // The interface or enum keyword. Stop parsing the class flags. break; } // Should we read the next word? if (accessFlag != ClassConstants.INTERNAL_ACC_ANNOTATTION) { readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD + "', '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'", false, true); } } // Parse the class name part. String externalClassName = ListUtil.commaSeparatedString( parseCommaSeparatedList("class name or interface name", true, false, false, false, true, false, false, false, null), false); // For backward compatibility, allow a single "*" wildcard to match any // class. String className = ConfigurationConstants.ANY_CLASS_KEYWORD.equals(externalClassName) ? null : ClassUtil.internalClassName(externalClassName); // Clear the annotation type and the class name of the extends part. String extendsAnnotationType = null; String extendsClassName = null; if (!configurationEnd()) { // Parse 'implements ...' or 'extends ...' part, if any. if (ConfigurationConstants.IMPLEMENTS_KEYWORD.equals(nextWord) || ConfigurationConstants.EXTENDS_KEYWORD.equals(nextWord)) { readNextWord("class name or interface name", false, true); // Parse the annotation type, if any. if (ConfigurationConstants.ANNOTATION_KEYWORD.equals(nextWord)) { extendsAnnotationType = ListUtil.commaSeparatedString( parseCommaSeparatedList("annotation type", true, false, false, false, true, false, false, true, null), false); } String externalExtendsClassName = ListUtil.commaSeparatedString( parseCommaSeparatedList("class name or interface name", false, false, false, false, true, false, false, false, null), false); extendsClassName = ConfigurationConstants.ANY_CLASS_KEYWORD.equals(externalExtendsClassName) ? null : ClassUtil.internalClassName(externalExtendsClassName); } } // Create the basic class specification. ClassSpecification classSpecification = new ClassSpecification(lastComments, requiredSetClassAccessFlags, requiredUnsetClassAccessFlags, annotationType, className, extendsAnnotationType, extendsClassName); // Now add any class members to this class specification. if (!configurationEnd()) { // Check the class member opening part. if (!ConfigurationConstants.OPEN_KEYWORD.equals(nextWord)) { throw new ParseException("Expecting opening '" + ConfigurationConstants.OPEN_KEYWORD + "' at " + reader.locationDescription()); } // Parse all class members. while (true) { readNextWord("class member description" + " or closing '" + ConfigurationConstants.CLOSE_KEYWORD + "'", false, true); if (nextWord.equals(ConfigurationConstants.CLOSE_KEYWORD)) { // The closing brace. Stop parsing the class members. readNextWord(); break; } parseMemberSpecificationArguments(externalClassName, classSpecification); } } return classSpecification; } private void parseMemberSpecificationArguments(String externalClassName, ClassSpecification classSpecification) throws ParseException, IOException { // Clear the annotation name. String annotationType = null; // Parse the class member access modifiers, if any. int requiredSetMemberAccessFlags = 0; int requiredUnsetMemberAccessFlags = 0; while (!configurationEnd(true)) { // Parse the annotation type, if any. if (ConfigurationConstants.ANNOTATION_KEYWORD.equals(nextWord)) { annotationType = ListUtil.commaSeparatedString( parseCommaSeparatedList("annotation type", true, false, false, false, true, false, false, true, null), false); continue; } String strippedWord = nextWord.startsWith("!") ? nextWord.substring(1) : nextWord; // Parse the class member access modifiers. int accessFlag = strippedWord.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : strippedWord.equals(ClassConstants.EXTERNAL_ACC_PRIVATE) ? ClassConstants.INTERNAL_ACC_PRIVATE : strippedWord.equals(ClassConstants.EXTERNAL_ACC_PROTECTED) ? ClassConstants.INTERNAL_ACC_PROTECTED : strippedWord.equals(ClassConstants.EXTERNAL_ACC_STATIC) ? ClassConstants.INTERNAL_ACC_STATIC : strippedWord.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : strippedWord.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED : strippedWord.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE : strippedWord.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT : strippedWord.equals(ClassConstants.EXTERNAL_ACC_BRIDGE) ? ClassConstants.INTERNAL_ACC_BRIDGE : strippedWord.equals(ClassConstants.EXTERNAL_ACC_VARARGS) ? ClassConstants.INTERNAL_ACC_VARARGS : strippedWord.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE : strippedWord.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : strippedWord.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT : strippedWord.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC : 0; if (accessFlag == 0) { // Not a class member access modifier. Stop parsing them. break; } if (strippedWord.equals(nextWord)) { requiredSetMemberAccessFlags |= accessFlag; } else { requiredUnsetMemberAccessFlags |= accessFlag; } // Make sure the user doesn't try to set and unset the same // access flags simultaneously. if ((requiredSetMemberAccessFlags & requiredUnsetMemberAccessFlags) != 0) { throw new ParseException("Conflicting class member access modifiers for " + reader.locationDescription()); } readNextWord("class member description"); } // Parse the class member type and name part. // Did we get a special wildcard? if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord) || ConfigurationConstants.ANY_FIELD_KEYWORD .equals(nextWord) || ConfigurationConstants.ANY_METHOD_KEYWORD .equals(nextWord)) { // Act according to the type of wildcard.. if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord)) { checkFieldAccessFlags(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags); checkMethodAccessFlags(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags); classSpecification.addField( new MemberSpecification(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags, annotationType, null, null)); classSpecification.addMethod( new MemberSpecification(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags, annotationType, null, null)); } else if (ConfigurationConstants.ANY_FIELD_KEYWORD.equals(nextWord)) { checkFieldAccessFlags(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags); classSpecification.addField( new MemberSpecification(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags, annotationType, null, null)); } else if (ConfigurationConstants.ANY_METHOD_KEYWORD.equals(nextWord)) { checkMethodAccessFlags(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags); classSpecification.addMethod( new MemberSpecification(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags, annotationType, null, null)); } // We still have to read the closing separator. readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'"); if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)) { throw new ParseException("Expecting separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "' before " + reader.locationDescription()); } } else { // Make sure we have a proper type. checkJavaIdentifier("java type"); String type = nextWord; readNextWord("class member name"); String name = nextWord; // Did we get just one word before the opening parenthesis? if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(name)) { // This must be a constructor then. // Make sure the type is a proper constructor name. if (!(type.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) || type.equals(externalClassName) || type.equals(ClassUtil.externalShortClassName(externalClassName)))) { throw new ParseException("Expecting type and name " + "instead of just '" + type + "' before " + reader.locationDescription()); } // Assign the fixed constructor type and name. type = ClassConstants.EXTERNAL_TYPE_VOID; name = ClassConstants.INTERNAL_METHOD_NAME_INIT; } else { // It's not a constructor. // Make sure we have a proper name. checkJavaIdentifier("class member name"); // Read the opening parenthesis or the separating // semi-colon. readNextWord("opening '" + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD + "' or separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'"); } // Are we looking at a field, a method, or something else? if (ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)) { // It's a field. checkFieldAccessFlags(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags); // We already have a field descriptor. String descriptor = ClassUtil.internalType(type); // Add the field. classSpecification.addField( new MemberSpecification(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags, annotationType, name, descriptor)); } else if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(nextWord)) { // It's a method. checkMethodAccessFlags(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags); // Parse the method arguments. String descriptor = ClassUtil.internalMethodDescriptor(type, parseCommaSeparatedList("argument", true, true, true, false, true, false, false, false, null)); if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord)) { throw new ParseException("Expecting separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + "' or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD + "' before " + reader.locationDescription()); } // Read the separator after the closing parenthesis. readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'"); if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)) { throw new ParseException("Expecting separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "' before " + reader.locationDescription()); } // Add the method. classSpecification.addMethod( new MemberSpecification(requiredSetMemberAccessFlags, requiredUnsetMemberAccessFlags, annotationType, name, descriptor)); } else { // It doesn't look like a field or a method. throw new ParseException("Expecting opening '" + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD + "' or separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "' before " + reader.locationDescription()); } } } /** * Reads a comma-separated list of java identifiers or of file names. * Examples of invocation arguments: * ("directory n", true, true, false, true, false, true, false, false, ...) * ("optimizatio", true, false, false, false, false, false, false, false, ...) * ("package nam", true, true, false, false, true, false, true, false, ...) * ("attribute n", true, true, false, false, true, false, false, false, ...) * ("class name", true, true, false, false, true, false, true, false, ...) * ("resource fi", true, true, false, true, false, false, false, false, ...) * ("resource fi", true, true, false, true, false, false, false, false, ...) * ("class name", true, true, false, false, true, false, true, false, ...) * ("class name", true, true, false, false, true, false, true, false, ...) * ("filter", true, true, true, true, false, true, false, false, ...) * ("annotation ", false, false, false, false, true, false, false, true, ...) * ("class name ", true, false, false, false, true, false, false, false, ...) * ("annotation ", true, false, false, false, true, false, false, true, ...) * ("class name ", false, false, false, false, true, false, false, false, ...) * ("annotation ", true, false, false, false, true, false, false, true, ...) * ("argument", true, true, true, false, true, false, false, false, ...) */ private List parseCommaSeparatedList(String expectedDescription, boolean readFirstWord, boolean allowEmptyList, boolean expectClosingParenthesis, boolean isFileName, boolean checkJavaIdentifiers, boolean replaceSystemProperties, boolean replaceExternalClassNames, boolean replaceExternalTypes, List list) throws ParseException, IOException { if (list == null) { list = new ArrayList(); } if (readFirstWord) { if (!allowEmptyList) { // Read the first list entry. readNextWord(expectedDescription, isFileName, false); } else if (expectClosingParenthesis) { // Read the first list entry. readNextWord(expectedDescription, isFileName, false); // Return if the entry is actually empty (an empty file name or // a closing parenthesis). if (nextWord.length() == 0) { // Read the closing parenthesis readNextWord("closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD + "'"); return list; } else if (nextWord.equals(ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD)) { return list; } } else { // Read the first list entry, if there is any. readNextWord(isFileName); // Check if the list is empty. if (configurationEnd()) { return list; } } } while (true) { if (checkJavaIdentifiers) { checkJavaIdentifier("java type"); } if (replaceSystemProperties) { nextWord = replaceSystemProperties(nextWord); } if (replaceExternalClassNames) { nextWord = ClassUtil.internalClassName(nextWord); } if (replaceExternalTypes) { nextWord = ClassUtil.internalType(nextWord); } list.add(nextWord); if (expectClosingParenthesis) { // Read a comma (or a closing parenthesis, or a different word). readNextWord("separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + "' or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD + "'"); } else { // Read a comma (or a different word). readNextWord(); } if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD.equals(nextWord)) { return list; } // Read the next list entry. readNextWord(expectedDescription, isFileName, false); } } /** * Throws a ParseException for an unexpected keyword. */ private int unknownAccessFlag() throws ParseException { throw new ParseException("Unexpected keyword " + reader.locationDescription()); } /** * Creates a properly resolved File, based on the given word. */ private File file(String word) throws ParseException { String fileName = replaceSystemProperties(word); File file = new File(fileName); // Try to get an absolute file. if (!file.isAbsolute()) { file = new File(reader.getBaseDir(), fileName); } return file; } /** * Replaces any system properties in the given word by their values * (e.g. the substring "" is replaced by its value). */ private String replaceSystemProperties(String word) throws ParseException { int fromIndex = 0; while (true) { fromIndex = word.indexOf(ConfigurationConstants.OPEN_SYSTEM_PROPERTY, fromIndex); if (fromIndex < 0) { break; } int toIndex = word.indexOf(ConfigurationConstants.CLOSE_SYSTEM_PROPERTY, fromIndex+1); if (toIndex < 0) { throw new ParseException("Expecting closing '" + ConfigurationConstants.CLOSE_SYSTEM_PROPERTY + "' after opening '" + ConfigurationConstants.OPEN_SYSTEM_PROPERTY + "' in " + reader.locationDescription()); } String propertyName = word.substring(fromIndex+1, toIndex); String propertyValue = properties.getProperty(propertyName); if (propertyValue == null) { throw new ParseException("Value of system property '" + propertyName + "' is undefined in " + reader.locationDescription()); } word = word.substring(0, fromIndex) + propertyValue + word.substring(toIndex+1); } return word; } /** * Reads the next word of the configuration in the 'nextWord' field, * throwing an exception if there is no next word. */ private void readNextWord(String expectedDescription) throws ParseException, IOException { readNextWord(expectedDescription, false, false); } /** * Reads the next word of the configuration in the 'nextWord' field, * throwing an exception if there is no next word. */ private void readNextWord(String expectedDescription, boolean isFileName, boolean expectingAtCharacter) throws ParseException, IOException { readNextWord(isFileName); if (configurationEnd(expectingAtCharacter)) { throw new ParseException("Expecting " + expectedDescription + " before " + reader.locationDescription()); } } /** * Reads the next word of the configuration in the 'nextWord' field. */ private void readNextWord() throws IOException { readNextWord(false); } /** * Reads the next word of the configuration in the 'nextWord' field. */ private void readNextWord(boolean isFileName) throws IOException { nextWord = reader.nextWord(isFileName); } /** * Returns whether the end of the configuration has been reached. */ private boolean configurationEnd() { return configurationEnd(false); } /** * Returns whether the end of the configuration has been reached. */ private boolean configurationEnd(boolean expectingAtCharacter) { return nextWord == null || nextWord.startsWith(ConfigurationConstants.OPTION_PREFIX) || (!expectingAtCharacter && nextWord.equals(ConfigurationConstants.AT_DIRECTIVE)); } /** * Checks whether the given word is a valid Java identifier and throws * a ParseException if it isn't. Wildcard characters are accepted. */ private void checkJavaIdentifier(String expectedDescription) throws ParseException { if (!isJavaIdentifier(nextWord)) { throw new ParseException("Expecting " + expectedDescription + " before " + reader.locationDescription()); } } /** * Returns whether the given word is a valid Java identifier. * Wildcard characters are accepted. */ private boolean isJavaIdentifier(String aWord) { if (aWord.length() == 0) { return false; } for (int index = 0; index < aWord.length(); index++) { char c = aWord.charAt(index); if (!(Character.isJavaIdentifierPart(c) || c == '.' || c == '[' || c == ']' || c == '<' || c == '>' || c == '-' || c == '!' || c == '*' || c == '?' || c == '%')) { return false; } } return true; } /** * Checks whether the given access flags are valid field access flags, * throwing a ParseException if they aren't. */ private void checkFieldAccessFlags(int requiredSetMemberAccessFlags, int requiredUnsetMemberAccessFlags) throws ParseException { if (((requiredSetMemberAccessFlags | requiredUnsetMemberAccessFlags) & ~ClassConstants.VALID_INTERNAL_ACC_FIELD) != 0) { throw new ParseException("Invalid method access modifier for field before " + reader.locationDescription()); } } /** * Checks whether the given access flags are valid method access flags, * throwing a ParseException if they aren't. */ private void checkMethodAccessFlags(int requiredSetMemberAccessFlags, int requiredUnsetMemberAccessFlags) throws ParseException { if (((requiredSetMemberAccessFlags | requiredUnsetMemberAccessFlags) & ~ClassConstants.VALID_INTERNAL_ACC_METHOD) != 0) { throw new ParseException("Invalid field access modifier for method before " + reader.locationDescription()); } } /** * A main method for testing configuration parsing. */ public static void main(String[] args) { try { ConfigurationParser parser = new ConfigurationParser(args, System.getProperties()); try { parser.parse(new Configuration()); } catch (ParseException ex) { ex.printStackTrace(); } finally { parser.close(); } } catch (IOException ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/MemberSpecification.java0000644000175000017500000001117611736333525020764 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; /** * This class stores a specification of class members. The specification is * template-based: the class member names and descriptors can contain wildcards. * * @author Eric Lafortune */ public class MemberSpecification { public int requiredSetAccessFlags; public int requiredUnsetAccessFlags; public final String annotationType; public final String name; public final String descriptor; /** * Creates a new option to keep all possible class members. */ public MemberSpecification() { this(0, 0, null, null, null); } /** * Creates a new option to keep the specified class member(s). * * @param requiredSetAccessFlags the class access flags that must be set * in order for the class to apply. * @param requiredUnsetAccessFlags the class access flags that must be unset * in order for the class to apply. * @param annotationType the name of the class that must be an * annotation in order for the class member * to apply. The name may be null to specify * that no annotation is required. * @param name the class member name. The name may be * null to specify any class member or it * may contain "*" or "?" wildcards. * @param descriptor the class member descriptor. The * descriptor may be null to specify any * class member or it may contain * "**", "*", or "?" wildcards. */ public MemberSpecification(int requiredSetAccessFlags, int requiredUnsetAccessFlags, String annotationType, String name, String descriptor) { this.requiredSetAccessFlags = requiredSetAccessFlags; this.requiredUnsetAccessFlags = requiredUnsetAccessFlags; this.annotationType = annotationType; this.name = name; this.descriptor = descriptor; } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } MemberSpecification other = (MemberSpecification)object; return (this.requiredSetAccessFlags == other.requiredSetAccessFlags ) && (this.requiredUnsetAccessFlags == other.requiredUnsetAccessFlags ) && (this.annotationType == null ? other.annotationType == null : this.annotationType.equals(other.annotationType)) && (this.name == null ? other.name == null : this.name.equals(other.name) ) && (this.descriptor == null ? other.descriptor == null : this.descriptor.equals(other.descriptor) ); } public int hashCode() { return (requiredSetAccessFlags ) ^ (requiredUnsetAccessFlags ) ^ (annotationType == null ? 0 : annotationType.hashCode()) ^ (name == null ? 0 : name.hashCode() ) ^ (descriptor == null ? 0 : descriptor.hashCode() ); } } proguard4.8/src/proguard/util/0000775000175000017500000000000011760503005015147 5ustar ericericproguard4.8/src/proguard/util/package.html0000644000175000017500000000013111736333525017434 0ustar ericeric This package contains utility classes for regular expression matching,... proguard4.8/src/proguard/util/ExtensionMatcher.java0000644000175000017500000000356711736333525021316 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher tests whether strings end in a given extension, ignoring * its case. * * @author Eric Lafortune */ public class ExtensionMatcher implements StringMatcher { private final String extension; /** * Creates a new StringMatcher. * @param extension the extension against which strings will be matched. */ public ExtensionMatcher(String extension) { this.extension = extension; } // Implementations for StringMatcher. public boolean matches(String string) { return endsWithIgnoreCase(string, extension); } /** * Returns whether the given string ends with the given suffix, ignoring its * case. */ private static boolean endsWithIgnoreCase(String string, String suffix) { int stringLength = string.length(); int suffixLength = suffix.length(); return string.regionMatches(true, stringLength - suffixLength, suffix, 0, suffixLength); } } proguard4.8/src/proguard/util/StringMatcher.java0000644000175000017500000000251611736333525020601 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This interface provides a method to determine whether strings match a given * criterion, which is specified by the implementation. * * @author Eric Lafortune */ public interface StringMatcher { /** * Checks whether the given string matches. * @param string the string to match. * @return a boolean indicating whether the string matches the criterion. */ public boolean matches(String string); } proguard4.8/src/proguard/util/ListParser.java0000664000175000017500000001106011736333525020113 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; import java.util.List; /** * This StringParser can create StringMatcher instances for regular expressions. * The regular expressions are either presented as a list, or they are * interpreted as comma-separated lists, optionally prefixed with '!' negators. * If an entry with a negator matches, a negative match is returned, without * considering any subsequent entries in the list. The creation of StringMatcher * instances for the entries is delegated to the given StringParser. * * @author Eric Lafortune */ public class ListParser implements StringParser { private final StringParser stringParser; /** * Creates a new ListParser that parses individual elements in the * comma-separated list with the given StringParser. */ public ListParser(StringParser stringParser) { this.stringParser = stringParser; } // Implementations for StringParser. public StringMatcher parse(String regularExpression) { // Does the regular expression contain a ',' list separator? return parse(ListUtil.commaSeparatedList(regularExpression)); } /** * Creates a StringMatcher for the given regular expression, which can * be a list of optionally negated simple entries. *

* An empty list results in a StringMatcher that matches any string. */ public StringMatcher parse(List regularExpressions) { StringMatcher listMatcher = null; // Loop over all simple regular expressions, backward, creating a // linked list of matchers. for (int index = regularExpressions.size()-1; index >= 0; index--) { String regularExpression = (String)regularExpressions.get(index); StringMatcher entryMatcher = parseEntry(regularExpression); // Prepend the entry matcher. listMatcher = listMatcher == null ? (StringMatcher)entryMatcher : isNegated(regularExpression) ? (StringMatcher)new AndMatcher(entryMatcher, listMatcher) : (StringMatcher)new OrMatcher(entryMatcher, listMatcher); } return listMatcher != null ? listMatcher : new ConstantMatcher(true); } // Small utility methods. /** * Creates a StringMatcher for the given regular expression, which is a * an optionally negated simple expression. */ private StringMatcher parseEntry(String regularExpression) { // Wrap the matcher if the regular expression starts with a '!' negator. return isNegated(regularExpression) ? new NotMatcher(stringParser.parse(regularExpression.substring(1))) : stringParser.parse(regularExpression); } /** * Returns whether the given simple regular expression is negated. */ private boolean isNegated(String regularExpression) { return regularExpression.length() > 0 && regularExpression.charAt(0) == '!'; } /** * A main method for testing name matching. */ public static void main(String[] args) { try { System.out.println("Regular expression ["+args[0]+"]"); ListParser parser = new ListParser(new NameParser()); StringMatcher matcher = parser.parse(args[0]); for (int index = 1; index < args.length; index++) { String string = args[index]; System.out.print("String ["+string+"]"); System.out.println(" -> match = "+matcher.matches(args[index])); } } catch (Exception ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/util/EmptyStringMatcher.java0000644000175000017500000000227211736333525021617 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher tests whether strings are empty. * * @author Eric Lafortune */ public class EmptyStringMatcher implements StringMatcher { // Implementations for StringMatcher. public boolean matches(String string) { return string.length() == 0; } } proguard4.8/src/proguard/util/OrMatcher.java0000644000175000017500000000277311736333525017720 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher tests whether strings matches either of the given * StringMatcher instances. * * @author Eric Lafortune */ public class OrMatcher implements StringMatcher { private final StringMatcher matcher1; private final StringMatcher matcher2; public OrMatcher(StringMatcher matcher1, StringMatcher matcher2) { this.matcher1 = matcher1; this.matcher2 = matcher2; } // Implementations for StringMatcher. public boolean matches(String string) { return matcher1.matches(string) || matcher2.matches(string); } } proguard4.8/src/proguard/util/SettableMatcher.java0000644000175000017500000000260511736333525021075 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher delegates to a another StringMatcher that can be set * after this StringMatcher has been constructed. * * @author Eric Lafortune */ public class SettableMatcher implements StringMatcher { private StringMatcher matcher; public void setMatcher(StringMatcher matcher) { this.matcher = matcher; } // Implementations for StringMatcher. public boolean matches(String string) { return matcher.matches(string); } } proguard4.8/src/proguard/util/ListMatcher.java0000644000175000017500000000405711736333525020250 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher tests whether strings match a given list of StringMatcher * instances. The instances are considered sequentially. Each instance in the * list can optionally be negated, meaning that a match makes the entire * remaining match fail. * * @author Eric Lafortune */ public class ListMatcher implements StringMatcher { private final StringMatcher[] matchers; private final boolean[] negate; public ListMatcher(StringMatcher[] matchers) { this(matchers, null); } public ListMatcher(StringMatcher[] matchers, boolean[] negate) { this.matchers = matchers; this.negate = negate; } // Implementations for StringMatcher. public boolean matches(String string) { // Check the list of matchers. for (int index = 0; index < matchers.length; index++) { StringMatcher matcher = matchers[index]; if (matcher.matches(string)) { return negate == null || !negate[index]; } } return negate != null && negate[negate.length - 1]; } } proguard4.8/src/proguard/util/NameParser.java0000644000175000017500000000764211736333525020071 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringParser can create StringMatcher instances for regular expressions * matching names. The regular expressions are interpreted as comma-separated * lists of names, optionally prefixed with '!' negators. * If a name with a negator matches, a negative match is returned, without * considering any subsequent entries in the list. * Names can contain the following wildcards: * '?' for a single character, and * '*' for any number of characters. * * @author Eric Lafortune */ public class NameParser implements StringParser { // Implementations for StringParser. public StringMatcher parse(String regularExpression) { int index; StringMatcher nextMatcher = new EmptyStringMatcher(); // Look for wildcards. for (index = 0; index < regularExpression.length(); index++) { // Is there a '*' wildcard? if (regularExpression.charAt(index) == '*') { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(null, null, 0, Integer.MAX_VALUE, parse(regularExpression.substring(index + 1))); break; } // Is there a '?' wildcard? else if (regularExpression.charAt(index) == '?') { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(null, null, 1, 1, parse(regularExpression.substring(index + 1))); break; } } // Return a matcher for the fixed first part of the regular expression, // if any, and the remainder. return index != 0 ? (StringMatcher)new FixedStringMatcher(regularExpression.substring(0, index), nextMatcher) : (StringMatcher)nextMatcher; } /** * A main method for testing name matching. */ public static void main(String[] args) { try { System.out.println("Regular expression ["+args[0]+"]"); NameParser parser = new NameParser(); StringMatcher matcher = parser.parse(args[0]); for (int index = 1; index < args.length; index++) { String string = args[index]; System.out.print("String ["+string+"]"); System.out.println(" -> match = "+matcher.matches(args[index])); } } catch (Exception ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/util/ListUtil.java0000644000175000017500000001156011736333525017577 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; import java.util.*; /** * This class provides some utility methods for working with * java.util.List objects. * * @author Eric Lafortune */ public class ListUtil { /** * Creates a comma-separated String from the given List of String objects. */ public static String commaSeparatedString(List list, boolean quoteStrings) { if (list == null) { return null; } StringBuffer buffer = new StringBuffer(); for (int index = 0; index < list.size(); index++) { if (index > 0) { buffer.append(','); } String string = (String)list.get(index); if (quoteStrings) { string = quotedString(string); } buffer.append(string); } return buffer.toString(); } /** * Creates a List of String objects from the given comma-separated String. */ public static List commaSeparatedList(String string) { if (string == null) { return null; } List list = new ArrayList(); int index = 0; while ((index = skipWhitespace(string, index)) < string.length()) { int nextIndex; // Do we have an opening quote? if (string.charAt(index) == '\'') { // Parse a quoted string. nextIndex = string.indexOf('\'', index + 1); if (nextIndex < 0) { nextIndex = string.length(); } list.add(string.substring(index + 1, nextIndex)); } else { // Parse a non-quoted string. nextIndex = string.indexOf(',', index); if (nextIndex < 0) { nextIndex = string.length(); } String substring = string.substring(index, nextIndex).trim(); if (substring.length() > 0) { list.add(substring); } } index = nextIndex + 1; } return list; } /** * Skips any whitespace characters. */ private static int skipWhitespace(String string, int index) { while (index < string.length() && Character.isWhitespace(string.charAt(index))) { index++; } return index; } /** * Returns a quoted version of the given string, if necessary. */ private static String quotedString(String string) { return string.length() == 0 || string.indexOf(' ') >= 0 || string.indexOf('@') >= 0 || string.indexOf('{') >= 0 || string.indexOf('}') >= 0 || string.indexOf('(') >= 0 || string.indexOf(')') >= 0 || string.indexOf(':') >= 0 || string.indexOf(';') >= 0 || string.indexOf(',') >= 0 ? ("'" + string + "'") : ( string ); } public static void main(String[] args) { if (args.length == 1) { System.out.println("Input string: ["+args[0]+"]"); List list = commaSeparatedList(args[0]); System.out.println("Resulting list:"); for (int index = 0; index < list.size(); index++) { System.out.println("["+list.get(index)+"]"); } } else { List list = Arrays.asList(args); System.out.println("Input list:"); for (int index = 0; index < list.size(); index++) { System.out.println("["+list.get(index)+"]"); } String string = commaSeparatedString(list, true); System.out.println("Resulting string: ["+string+"]"); } } } proguard4.8/src/proguard/util/FileNameParser.java0000664000175000017500000001111511736333525020661 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; import java.io.File; /** * This StringParser can create StringMatcher instances for regular expressions * matching file names. The regular expressions can contain the following * wildcards: * '?' for a single regular file name character, * '*' for any number of regular file name characters, and * '**' for any number of regular file name characters or directory separator * characters (always including '/'). * * @author Eric Lafortune */ public class FileNameParser implements StringParser { // Implementations for StringParser. public StringMatcher parse(String regularExpression) { int index; StringMatcher nextMatcher = new EmptyStringMatcher(); // Look for wildcards. for (index = 0; index < regularExpression.length(); index++) { // Is there a '**' wildcard? if (regularExpression.regionMatches(index, "**", 0, 2)) { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(null, null, 0, Integer.MAX_VALUE, parse(regularExpression.substring(index + 2))); break; } // Is there a '*' wildcard? else if (regularExpression.charAt(index) == '*') { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(null, new char[] { File.pathSeparatorChar, '/' }, 0, Integer.MAX_VALUE, parse(regularExpression.substring(index + 1))); break; } // Is there a '?' wildcard? else if (regularExpression.charAt(index) == '?') { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(null, new char[] { File.pathSeparatorChar, '/' }, 1, 1, parse(regularExpression.substring(index + 1))); break; } } // Return a matcher for the fixed first part of the regular expression, // if any, and the remainder. return index != 0 ? (StringMatcher)new FixedStringMatcher(regularExpression.substring(0, index), nextMatcher) : (StringMatcher)nextMatcher; } /** * A main method for testing file name matching. */ public static void main(String[] args) { try { System.out.println("Regular expression ["+args[0]+"]"); FileNameParser parser = new FileNameParser(); StringMatcher matcher = parser.parse(args[0]); for (int index = 1; index < args.length; index++) { String string = args[index]; System.out.print("String ["+string+"]"); System.out.println(" -> match = "+matcher.matches(args[index])); } } catch (Exception ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/util/ConstantMatcher.java0000644000175000017500000000260411736333525021122 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher matches any string or no string at all. * * @author Eric Lafortune */ public class ConstantMatcher implements StringMatcher { private boolean matches; /** * Creates a new ConstantMatcher that always returns the given result. */ public ConstantMatcher(boolean matches) { this.matches = matches; } // Implementations for StringMatcher. public boolean matches(String string) { return matches; } }proguard4.8/src/proguard/util/FixedStringMatcher.java0000644000175000017500000000336011736333525021557 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher tests whether strings start with a given fixed string * and then match another optional given StringMatcher. * * @author Eric Lafortune */ public class FixedStringMatcher implements StringMatcher { private final String fixedString; private final StringMatcher nextMatcher; public FixedStringMatcher(String fixedString) { this(fixedString, null); } public FixedStringMatcher(String fixedString, StringMatcher nextMatcher) { this.fixedString = fixedString; this.nextMatcher = nextMatcher; } // Implementations for StringMatcher. public boolean matches(String string) { return string.startsWith(fixedString) && (nextMatcher == null || nextMatcher.matches(string.substring(fixedString.length()))); } } proguard4.8/src/proguard/util/VariableStringMatcher.java0000644000175000017500000000764711736333525022261 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher tests whether strings start with a specified variable * string and then match another given StringMatcher. * * @author Eric Lafortune */ public class VariableStringMatcher implements StringMatcher { private final char[] allowedCharacters; private final char[] disallowedCharacters; private final int minimumLength; private final int maximumLength; private final StringMatcher nextMatcher; public VariableStringMatcher(char[] allowedCharacters, char[] disallowedCharacters, int minimumLength, int maximumLength, StringMatcher nextMatcher) { this.allowedCharacters = allowedCharacters; this.disallowedCharacters = disallowedCharacters; this.minimumLength = minimumLength; this.maximumLength = maximumLength; this.nextMatcher = nextMatcher; } // Implementations for StringMatcher. public boolean matches(String string) { if (string.length() < minimumLength) { return false; } // Check the first minimum number of characters. for (int index = 0; index < minimumLength; index++) { if (!isAllowedCharacter(string.charAt(index))) { return false; } } int maximumLength = Math.min(this.maximumLength, string.length()); // Check the remaining characters, up to the maximum number. for (int index = minimumLength; index < maximumLength; index++) { if (nextMatcher.matches(string.substring(index))) { return true; } if (!isAllowedCharacter(string.charAt(index))) { return false; } } // Check the remaining characters in the string. return nextMatcher.matches(string.substring(maximumLength)); } // Small utility methods. /** * Returns whether the given character is allowed in the variable string. */ private boolean isAllowedCharacter(char character) { // Check the allowed characters. if (allowedCharacters != null) { for (int index = 0; index < allowedCharacters.length; index++) { if (allowedCharacters[index] == character) { return true; } } return false; } // Check the disallowed characters. if (disallowedCharacters != null) { for (int index = 0; index < disallowedCharacters.length; index++) { if (disallowedCharacters[index] == character) { return false; } } } // Any remaining character is allowed. return true; } } proguard4.8/src/proguard/util/AndMatcher.java0000644000175000017500000000276311736333525020041 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher tests whether strings matches both given StringMatcher * instances. * * @author Eric Lafortune */ public class AndMatcher implements StringMatcher { private final StringMatcher matcher1; private final StringMatcher matcher2; public AndMatcher(StringMatcher matcher1, StringMatcher matcher2) { this.matcher1 = matcher1; this.matcher2 = matcher2; } // Implementations for StringMatcher. public boolean matches(String string) { return matcher1.matches(string) && matcher2.matches(string); } } proguard4.8/src/proguard/util/NotMatcher.java0000644000175000017500000000253411736333525020073 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This StringMatcher tests whether strings does not match the given * StringMatcher. * * @author Eric Lafortune */ public class NotMatcher implements StringMatcher { private final StringMatcher matcher; public NotMatcher(StringMatcher matcher) { this.matcher = matcher; } // Implementations for StringMatcher. public boolean matches(String string) { return !matcher.matches(string); } } proguard4.8/src/proguard/util/StringParser.java0000644000175000017500000000231511736333525020447 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; /** * This interface provides a method to create a SringMatcher for a given * regular expression. * * @author Eric Lafortune */ public interface StringParser { /** * Creates a StringMatcher for the given regular expression. */ public StringMatcher parse(String regularExpression); } proguard4.8/src/proguard/util/ClassNameParser.java0000644000175000017500000002105211736333525021046 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util; import proguard.classfile.ClassConstants; /** * This StringParser can create StringMatcher instances for regular expressions * matching internal class names (or descriptors containing class names). * The regular expressions can contain the following wildcards: * '%' for a single internal primitive type character (V, Z, B, C, S, I, F, * J, or D), * '?' for a single regular class name character, * '*' for any number of regular class name characters, * '**' for any number of regular class name characters or package separator * characters ('/'), * 'L***;' for a single internal type (class name or primitive type, * array or non-array), and * 'L///;' for any number of internal types (class names and primitive * types). * * @author Eric Lafortune */ public class ClassNameParser implements StringParser { private static final char[] INTERNAL_PRIMITIVE_TYPES = new char[] { ClassConstants.INTERNAL_TYPE_VOID, ClassConstants.INTERNAL_TYPE_BOOLEAN, ClassConstants.INTERNAL_TYPE_BYTE, ClassConstants.INTERNAL_TYPE_CHAR, ClassConstants.INTERNAL_TYPE_SHORT, ClassConstants.INTERNAL_TYPE_INT, ClassConstants.INTERNAL_TYPE_LONG, ClassConstants.INTERNAL_TYPE_FLOAT, ClassConstants.INTERNAL_TYPE_DOUBLE, }; // Implementations for StringParser. public StringMatcher parse(String regularExpression) { int index; StringMatcher nextMatcher = new EmptyStringMatcher(); // Look for wildcards. for (index = 0; index < regularExpression.length(); index++) { // Is there an 'L///;' wildcard? if (regularExpression.regionMatches(index, "L///;", 0, 5)) { SettableMatcher settableMatcher = new SettableMatcher(); // Create a matcher, recursively, for the remainder of the // string, optionally preceded by any type. nextMatcher = new OrMatcher(parse(regularExpression.substring(index + 5)), createAnyTypeMatcher(settableMatcher)); settableMatcher.setMatcher(nextMatcher); break; } // Is there an 'L***;' wildcard? if (regularExpression.regionMatches(index, "L***;", 0, 5)) { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = createAnyTypeMatcher(parse(regularExpression.substring(index + 5))); break; } // Is there a '**' wildcard? if (regularExpression.regionMatches(index, "**", 0, 2)) { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(null, new char[] { ClassConstants.INTERNAL_TYPE_CLASS_END }, 0, Integer.MAX_VALUE, parse(regularExpression.substring(index + 2))); break; } // Is there a '*' wildcard? else if (regularExpression.charAt(index) == '*') { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(null, new char[] { ClassConstants.INTERNAL_TYPE_CLASS_END, ClassConstants.INTERNAL_PACKAGE_SEPARATOR }, 0, Integer.MAX_VALUE, parse(regularExpression.substring(index + 1))); break; } // Is there a '?' wildcard? else if (regularExpression.charAt(index) == '?') { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(null, new char[] { ClassConstants.INTERNAL_TYPE_CLASS_END, ClassConstants.INTERNAL_PACKAGE_SEPARATOR }, 1, 1, parse(regularExpression.substring(index + 1))); break; } // Is there a '%' wildcard? else if (regularExpression.charAt(index) == '%') { // Create a matcher for the wildcard and, recursively, for the // remainder of the string. nextMatcher = new VariableStringMatcher(INTERNAL_PRIMITIVE_TYPES, null, 1, 1, parse(regularExpression.substring(index + 1))); break; } } // Return a matcher for the fixed first part of the regular expression, // if any, and the remainder. return index != 0 ? (StringMatcher)new FixedStringMatcher(regularExpression.substring(0, index), nextMatcher) : (StringMatcher)nextMatcher; } // Small utility methods. /** * Creates a StringMatcher that matches any type (class or primitive type, * array or non-array) and then the given matcher. */ private VariableStringMatcher createAnyTypeMatcher(StringMatcher nextMatcher) { return new VariableStringMatcher(new char[] { ClassConstants.INTERNAL_TYPE_ARRAY }, null, 0, 255, new OrMatcher( new VariableStringMatcher(INTERNAL_PRIMITIVE_TYPES, null, 1, 1, nextMatcher), new VariableStringMatcher(new char[] { ClassConstants.INTERNAL_TYPE_CLASS_START }, null, 1, 1, new VariableStringMatcher(null, new char[] { ClassConstants.INTERNAL_TYPE_CLASS_END }, 0, Integer.MAX_VALUE, new VariableStringMatcher(new char[] { ClassConstants.INTERNAL_TYPE_CLASS_END }, null, 1, 1, nextMatcher))))); } /** * A main method for testing class name matching. */ public static void main(String[] args) { try { System.out.println("Regular expression ["+args[0]+"]"); ClassNameParser parser = new ClassNameParser(); StringMatcher matcher = parser.parse(args[0]); for (int index = 1; index < args.length; index++) { String string = args[index]; System.out.print("String ["+string+"]"); System.out.println(" -> match = "+matcher.matches(args[index])); } } catch (Exception ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/LineWordReader.java0000644000175000017500000000372611736333525017724 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.io.*; /** * A WordReader that returns words from a line number reader. * * @author Eric Lafortune */ public class LineWordReader extends WordReader { private final LineNumberReader reader; private final String description; /** * Creates a new LineWordReader for the given input. */ public LineWordReader(LineNumberReader lineNumberReader, String description, File baseDir) throws IOException { super(baseDir); this.reader = lineNumberReader; this.description = description; } // Implementations for WordReader. protected String nextLine() throws IOException { return reader.readLine(); } protected String lineLocationDescription() { return "line " + reader.getLineNumber() + " of " + description; } public void close() throws IOException { super.close(); if (reader != null) { reader.close(); } } } proguard4.8/src/proguard/Targeter.java0000644000175000017500000000601111736333525016621 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.ClassPool; import proguard.classfile.util.ClassUtil; import proguard.classfile.visitor.ClassVersionSetter; import java.io.IOException; import java.util.*; /** * This class sets the target version on program classes. * * @author Eric Lafortune */ public class Targeter { private final Configuration configuration; /** * Creates a new Targeter to set the target version on program classes * according to the given configuration. */ public Targeter(Configuration configuration) { this.configuration = configuration; } /** * Sets the target version on classes in the given program class pool. */ public void execute(ClassPool programClassPool) throws IOException { Set newerClassVersions = configuration.warn != null ? null : new HashSet(); programClassPool.classesAccept(new ClassVersionSetter(configuration.targetClassVersion, newerClassVersions)); if (newerClassVersions != null && newerClassVersions.size() > 0) { System.err.print("Warning: some classes have more recent versions ("); Iterator iterator = newerClassVersions.iterator(); while (iterator.hasNext()) { Integer classVersion = (Integer)iterator.next(); System.err.print(ClassUtil.externalClassVersion(classVersion.intValue())); if (iterator.hasNext()) { System.err.print(","); } } System.err.println(")"); System.err.println(" than the target version ("+ClassUtil.externalClassVersion(configuration.targetClassVersion)+")."); if (!configuration.ignoreWarnings) { System.err.println(" If you are sure this is not a problem,"); System.err.println(" you could try your luck using the '-ignorewarnings' option."); throw new IOException("Please correct the above warnings first."); } } } } proguard4.8/src/proguard/InputReader.java0000644000175000017500000002127311736333525017275 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.ClassPool; import proguard.classfile.util.WarningPrinter; import proguard.classfile.visitor.*; import proguard.io.*; import java.io.IOException; /** * This class reads the input class files. * * @author Eric Lafortune */ public class InputReader { private final Configuration configuration; /** * Creates a new InputReader to read input class files as specified by the * given configuration. */ public InputReader(Configuration configuration) { this.configuration = configuration; } /** * Fills the given program class pool and library class pool by reading * class files, based on the current configuration. */ public void execute(ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { // Check if we have at least some input classes. if (configuration.programJars == null) { throw new IOException("The input is empty. You have to specify one or more '-injars' options"); } // Perform some sanity checks on the class paths. checkInputOutput(configuration.libraryJars, configuration.programJars); checkInputOutput(configuration.programJars, configuration.programJars); WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); WarningPrinter notePrinter = new WarningPrinter(System.out, configuration.note); DuplicateClassPrinter duplicateClassPrinter = new DuplicateClassPrinter(notePrinter); // Read the program class files. // Prepare a data entry reader to filter all classes, // which are then decoded to classes by a class reader, // which are then put in the class pool by a class pool filler. readInput("Reading program ", configuration.programJars, new ClassFilter( new ClassReader(false, configuration.skipNonPublicLibraryClasses, configuration.skipNonPublicLibraryClassMembers, warningPrinter, new ClassPresenceFilter(programClassPool, duplicateClassPrinter, new ClassPoolFiller(programClassPool))))); // Check if we have at least some input classes. if (programClassPool.size() == 0) { throw new IOException("The input doesn't contain any classes. Did you specify the proper '-injars' options?"); } // Read the library class files, if any. if (configuration.libraryJars != null) { // Prepare a data entry reader to filter all classes, // which are then decoded to classes by a class reader, // which are then put in the class pool by a class pool filler. readInput("Reading library ", configuration.libraryJars, new ClassFilter( new ClassReader(true, configuration.skipNonPublicLibraryClasses, configuration.skipNonPublicLibraryClassMembers, warningPrinter, new ClassPresenceFilter(programClassPool, duplicateClassPrinter, new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter, new ClassPoolFiller(libraryClassPool)))))); } // Print out a summary of the notes, if necessary. int noteCount = notePrinter.getWarningCount(); if (noteCount > 0) { System.err.println("Note: there were " + noteCount + " duplicate class definitions."); } // Print out a summary of the warnings, if necessary. int warningCount = warningPrinter.getWarningCount(); if (warningCount > 0) { System.err.println("Warning: there were " + warningCount + " classes in incorrectly named files."); System.err.println(" You should make sure all file names correspond to their class names."); System.err.println(" The directory hierarchies must correspond to the package hierarchies."); if (!configuration.ignoreWarnings) { System.err.println(" If you don't mind the mentioned classes not being written out,"); System.err.println(" you could try your luck using the '-ignorewarnings' option."); throw new IOException("Please correct the above warnings first."); } } } /** * Performs some sanity checks on the class paths. */ private void checkInputOutput(ClassPath inputClassPath, ClassPath outputClassPath) throws IOException { if (inputClassPath == null || outputClassPath == null) { return; } for (int index1 = 0; index1 < inputClassPath.size(); index1++) { ClassPathEntry entry1 = inputClassPath.get(index1); if (!entry1.isOutput()) { for (int index2 = 0; index2 < outputClassPath.size(); index2++) { ClassPathEntry entry2 = outputClassPath.get(index2); if (entry2.isOutput() && entry2.getName().equals(entry1.getName())) { throw new IOException("Input jars and output jars must be different ["+entry1.getName()+"]"); } } } } } /** * Reads all input entries from the given class path. */ private void readInput(String messagePrefix, ClassPath classPath, DataEntryReader reader) throws IOException { readInput(messagePrefix, classPath, 0, classPath.size(), reader); } /** * Reads all input entries from the given section of the given class path. */ public void readInput(String messagePrefix, ClassPath classPath, int fromIndex, int toIndex, DataEntryReader reader) throws IOException { for (int index = fromIndex; index < toIndex; index++) { ClassPathEntry entry = classPath.get(index); if (!entry.isOutput()) { readInput(messagePrefix, entry, reader); } } } /** * Reads the given input class path entry. */ private void readInput(String messagePrefix, ClassPathEntry classPathEntry, DataEntryReader dataEntryReader) throws IOException { try { // Create a reader that can unwrap jars, wars, ears, and zips. DataEntryReader reader = DataEntryReaderFactory.createDataEntryReader(messagePrefix, classPathEntry, dataEntryReader); // Create the data entry pump. DirectoryPump directoryPump = new DirectoryPump(classPathEntry.getFile()); // Pump the data entries into the reader. directoryPump.pumpDataEntries(reader); } catch (IOException ex) { throw (IOException)new IOException("Can't read [" + classPathEntry + "] (" + ex.getMessage() + ")").initCause(ex); } } } proguard4.8/src/proguard/FullyQualifiedClassNameChecker.java0000644000175000017500000001414411736333525023045 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.util.List; /** * This class checks if the user has forgotten to fully qualify any classes * in the configuration. * * @author Eric Lafortune */ public class FullyQualifiedClassNameChecker extends SimplifiedVisitor implements ClassVisitor { private final ClassPool programClassPool; private final ClassPool libraryClassPool; private final WarningPrinter notePrinter; /** * Creates a new FullyQualifiedClassNameChecker. */ public FullyQualifiedClassNameChecker(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter notePrinter) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; this.notePrinter = notePrinter; } /** * Checks the classes mentioned in the given class specifications, printing * notes if necessary. */ public void checkClassSpecifications(List classSpecifications) { if (classSpecifications != null) { for (int index = 0; index < classSpecifications.size(); index++) { ClassSpecification classSpecification = (ClassSpecification)classSpecifications.get(index); checkType(classSpecification.annotationType); checkClassName(classSpecification.className); checkType(classSpecification.extendsAnnotationType); checkClassName(classSpecification.extendsClassName); checkMemberSpecifications(classSpecification.fieldSpecifications, true); checkMemberSpecifications(classSpecification.methodSpecifications, false); } } } /** * Checks the classes mentioned in the given class member specifications, * printing notes if necessary. */ private void checkMemberSpecifications(List memberSpecifications, boolean isField) { if (memberSpecifications != null) { for (int index = 0; index < memberSpecifications.size(); index++) { MemberSpecification memberSpecification = (MemberSpecification)memberSpecifications.get(index); checkType(memberSpecification.annotationType); if (isField) { checkType(memberSpecification.descriptor); } else { checkDescriptor(memberSpecification.descriptor); } } } } /** * Checks the classes mentioned in the given class member descriptor, * printing notes if necessary. */ private void checkDescriptor(String descriptor) { if (descriptor != null) { InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); checkType(internalTypeEnumeration.returnType()); while (internalTypeEnumeration.hasMoreTypes()) { checkType(internalTypeEnumeration.nextType()); } } } /** * Checks the class mentioned in the given type (if any), * printing notes if necessary. */ private void checkType(String type) { if (type != null) { checkClassName(ClassUtil.internalClassNameFromType(type)); } } /** * Checks the specified class (if any), * printing notes if necessary. */ private void checkClassName(String className) { if (className != null && !containsWildCards(className) && programClassPool.getClass(className) == null && libraryClassPool.getClass(className) == null && notePrinter.accepts(className)) { notePrinter.print(className, "Note: the configuration refers to the unknown class '" + ClassUtil.externalClassName(className) + "'"); String fullyQualifiedClassName = "**" + ClassConstants.INTERNAL_PACKAGE_SEPARATOR + className.substring(className.lastIndexOf(ClassConstants.INTERNAL_PACKAGE_SEPARATOR)+1); ClassNameFilter classNameFilter = new ClassNameFilter(fullyQualifiedClassName, this); programClassPool.classesAccept(classNameFilter); libraryClassPool.classesAccept(classNameFilter); } } private static boolean containsWildCards(String string) { return string != null && (string.indexOf('!') >= 0 || string.indexOf('*') >= 0 || string.indexOf('?') >= 0 || string.indexOf(',') >= 0 || string.indexOf("///") >= 0); } // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { System.out.println(" Maybe you meant the fully qualified name '" + ClassUtil.externalClassName(clazz.getName()) + "'?"); } } proguard4.8/src/proguard/ConfigurationWriter.java0000644000175000017500000006000711736333525021055 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.ClassConstants; import proguard.classfile.util.ClassUtil; import proguard.util.ListUtil; import java.io.*; import java.util.*; /** * This class writes ProGuard configurations to a file. * * @author Eric Lafortune */ public class ConfigurationWriter { private static final String[] KEEP_OPTIONS = new String[] { ConfigurationConstants.KEEP_OPTION, ConfigurationConstants.KEEP_CLASS_MEMBERS_OPTION, ConfigurationConstants.KEEP_CLASSES_WITH_MEMBERS_OPTION }; private final PrintWriter writer; private File baseDir; /** * Creates a new ConfigurationWriter for the given file name. */ public ConfigurationWriter(File configurationFile) throws IOException { this(new PrintWriter(new FileWriter(configurationFile))); baseDir = configurationFile.getParentFile(); } /** * Creates a new ConfigurationWriter for the given OutputStream. */ public ConfigurationWriter(OutputStream outputStream) throws IOException { this(new PrintWriter(outputStream)); } /** * Creates a new ConfigurationWriter for the given PrintWriter. */ public ConfigurationWriter(PrintWriter writer) throws IOException { this.writer = writer; } /** * Closes this ConfigurationWriter. */ public void close() throws IOException { writer.close(); } /** * Writes the given configuration. * @param configuration the configuration that is to be written out. * @throws IOException if an IO error occurs while writing the configuration. */ public void write(Configuration configuration) throws IOException { // Write the program class path (input and output entries). writeJarOptions(ConfigurationConstants.INJARS_OPTION, ConfigurationConstants.OUTJARS_OPTION, configuration.programJars); writer.println(); // Write the library class path (output entries only). writeJarOptions(ConfigurationConstants.LIBRARYJARS_OPTION, ConfigurationConstants.LIBRARYJARS_OPTION, configuration.libraryJars); writer.println(); // Write the other options. writeOption(ConfigurationConstants.SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION, configuration.skipNonPublicLibraryClasses); writeOption(ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION, !configuration.skipNonPublicLibraryClassMembers); writeOption(ConfigurationConstants.KEEP_DIRECTORIES_OPTION, configuration.keepDirectories); writeOption(ConfigurationConstants.TARGET_OPTION, ClassUtil.externalClassVersion(configuration.targetClassVersion)); writeOption(ConfigurationConstants.FORCE_PROCESSING_OPTION, configuration.lastModified == Long.MAX_VALUE); writeOption(ConfigurationConstants.DONT_SHRINK_OPTION, !configuration.shrink); writeOption(ConfigurationConstants.PRINT_USAGE_OPTION, configuration.printUsage); writeOption(ConfigurationConstants.DONT_OPTIMIZE_OPTION, !configuration.optimize); writeOption(ConfigurationConstants.OPTIMIZATIONS, configuration.optimizations); writeOption(ConfigurationConstants.OPTIMIZATION_PASSES, configuration.optimizationPasses); writeOption(ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION, configuration.allowAccessModification); writeOption(ConfigurationConstants.MERGE_INTERFACES_AGGRESSIVELY_OPTION, configuration.mergeInterfacesAggressively); writeOption(ConfigurationConstants.DONT_OBFUSCATE_OPTION, !configuration.obfuscate); writeOption(ConfigurationConstants.PRINT_MAPPING_OPTION, configuration.printMapping); writeOption(ConfigurationConstants.APPLY_MAPPING_OPTION, configuration.applyMapping); writeOption(ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION, configuration.obfuscationDictionary); writeOption(ConfigurationConstants.CLASS_OBFUSCATION_DICTIONARY_OPTION, configuration.classObfuscationDictionary); writeOption(ConfigurationConstants.PACKAGE_OBFUSCATION_DICTIONARY_OPTION, configuration.packageObfuscationDictionary); writeOption(ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION, configuration.overloadAggressively); writeOption(ConfigurationConstants.USE_UNIQUE_CLASS_MEMBER_NAMES_OPTION, configuration.useUniqueClassMemberNames); writeOption(ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION, !configuration.useMixedCaseClassNames); writeOption(ConfigurationConstants.KEEP_PACKAGE_NAMES_OPTION, configuration.keepPackageNames, true); writeOption(ConfigurationConstants.FLATTEN_PACKAGE_HIERARCHY_OPTION, configuration.flattenPackageHierarchy, true); writeOption(ConfigurationConstants.REPACKAGE_CLASSES_OPTION, configuration.repackageClasses, true); writeOption(ConfigurationConstants.KEEP_ATTRIBUTES_OPTION, configuration.keepAttributes); writeOption(ConfigurationConstants.KEEP_PARAMETER_NAMES_OPTION, configuration.keepParameterNames); writeOption(ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION, configuration.newSourceFileAttribute); writeOption(ConfigurationConstants.ADAPT_CLASS_STRINGS_OPTION, configuration.adaptClassStrings, true); writeOption(ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION, configuration.adaptResourceFileNames); writeOption(ConfigurationConstants.ADAPT_RESOURCE_FILE_CONTENTS_OPTION, configuration.adaptResourceFileContents); writeOption(ConfigurationConstants.DONT_PREVERIFY_OPTION, !configuration.preverify); writeOption(ConfigurationConstants.MICRO_EDITION_OPTION, configuration.microEdition); writeOption(ConfigurationConstants.VERBOSE_OPTION, configuration.verbose); writeOption(ConfigurationConstants.DONT_NOTE_OPTION, configuration.note, true); writeOption(ConfigurationConstants.DONT_WARN_OPTION, configuration.warn, true); writeOption(ConfigurationConstants.IGNORE_WARNINGS_OPTION, configuration.ignoreWarnings); writeOption(ConfigurationConstants.PRINT_CONFIGURATION_OPTION, configuration.printConfiguration); writeOption(ConfigurationConstants.DUMP_OPTION, configuration.dump); writeOption(ConfigurationConstants.PRINT_SEEDS_OPTION, configuration.printSeeds); writer.println(); // Write the "why are you keeping" options. writeOptions(ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION, configuration.whyAreYouKeeping); // Write the keep options. writeOptions(KEEP_OPTIONS, configuration.keep); // Write the "no side effect methods" options. writeOptions(ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION, configuration.assumeNoSideEffects); if (writer.checkError()) { throw new IOException("Can't write configuration"); } } private void writeJarOptions(String inputEntryOptionName, String outputEntryOptionName, ClassPath classPath) { if (classPath != null) { for (int index = 0; index < classPath.size(); index++) { ClassPathEntry entry = classPath.get(index); String optionName = entry.isOutput() ? outputEntryOptionName : inputEntryOptionName; writer.print(optionName); writer.print(' '); writer.print(relativeFileName(entry.getFile())); // Append the filters, if any. boolean filtered = false; filtered = writeFilter(filtered, entry.getZipFilter()); filtered = writeFilter(filtered, entry.getEarFilter()); filtered = writeFilter(filtered, entry.getWarFilter()); filtered = writeFilter(filtered, entry.getJarFilter()); filtered = writeFilter(filtered, entry.getFilter()); if (filtered) { writer.print(ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD); } writer.println(); } } } private boolean writeFilter(boolean filtered, List filter) { if (filtered) { writer.print(ConfigurationConstants.SEPARATOR_KEYWORD); } if (filter != null) { if (!filtered) { writer.print(ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD); } writer.print(ListUtil.commaSeparatedString(filter, true)); filtered = true; } return filtered; } private void writeOption(String optionName, boolean flag) { if (flag) { writer.println(optionName); } } private void writeOption(String optionName, int argument) { if (argument != 1) { writer.print(optionName); writer.print(' '); writer.println(argument); } } private void writeOption(String optionName, List arguments) { writeOption(optionName, arguments, false); } private void writeOption(String optionName, List arguments, boolean replaceInternalClassNames) { if (arguments != null) { if (arguments.isEmpty()) { writer.println(optionName); } else { if (replaceInternalClassNames) { arguments = externalClassNames(arguments); } writer.print(optionName); writer.print(' '); writer.println(ListUtil.commaSeparatedString(arguments, true)); } } } private void writeOption(String optionName, String arguments) { writeOption(optionName, arguments, false); } private void writeOption(String optionName, String arguments, boolean replaceInternalClassNames) { if (arguments != null) { if (replaceInternalClassNames) { arguments = ClassUtil.externalClassName(arguments); } writer.print(optionName); writer.print(' '); writer.println(quotedString(arguments)); } } private void writeOption(String optionName, File file) { if (file != null) { if (file.getPath().length() > 0) { writer.print(optionName); writer.print(' '); writer.println(relativeFileName(file)); } else { writer.println(optionName); } } } private void writeOptions(String[] optionNames, List keepClassSpecifications) { if (keepClassSpecifications != null) { for (int index = 0; index < keepClassSpecifications.size(); index++) { writeOption(optionNames, (KeepClassSpecification)keepClassSpecifications.get(index)); } } } private void writeOption(String[] optionNames, KeepClassSpecification keepClassSpecification) { // Compose the option name. String optionName = optionNames[keepClassSpecification.markConditionally ? 2 : keepClassSpecification.markClasses ? 0 : 1]; if (keepClassSpecification.allowShrinking) { optionName += ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION; } if (keepClassSpecification.allowOptimization) { optionName += ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION; } if (keepClassSpecification.allowObfuscation) { optionName += ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD + ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION; } // Write out the option with the proper class specification. writeOption(optionName, keepClassSpecification); } private void writeOptions(String optionName, List classSpecifications) { if (classSpecifications != null) { for (int index = 0; index < classSpecifications.size(); index++) { writeOption(optionName, (ClassSpecification)classSpecifications.get(index)); } } } private void writeOption(String optionName, ClassSpecification classSpecification) { writer.println(); // Write out the comments for this option. writeComments(classSpecification.comments); writer.print(optionName); writer.print(' '); // Write out the required annotation, if any. if (classSpecification.annotationType != null) { writer.print(ConfigurationConstants.ANNOTATION_KEYWORD); writer.print(ClassUtil.externalType(classSpecification.annotationType)); writer.print(' '); } // Write out the class access flags. writer.print(ClassUtil.externalClassAccessFlags(classSpecification.requiredUnsetAccessFlags, ConfigurationConstants.NEGATOR_KEYWORD)); writer.print(ClassUtil.externalClassAccessFlags(classSpecification.requiredSetAccessFlags)); // Write out the class keyword, if we didn't write the interface // keyword earlier. if (((classSpecification.requiredSetAccessFlags | classSpecification.requiredUnsetAccessFlags) & (ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ENUM)) == 0) { writer.print(ConfigurationConstants.CLASS_KEYWORD); } writer.print(' '); // Write out the class name. writer.print(classSpecification.className != null ? ClassUtil.externalClassName(classSpecification.className) : ConfigurationConstants.ANY_CLASS_KEYWORD); // Write out the extends template, if any. if (classSpecification.extendsAnnotationType != null || classSpecification.extendsClassName != null) { writer.print(' '); writer.print(ConfigurationConstants.EXTENDS_KEYWORD); writer.print(' '); // Write out the required extends annotation, if any. if (classSpecification.extendsAnnotationType != null) { writer.print(ConfigurationConstants.ANNOTATION_KEYWORD); writer.print(ClassUtil.externalType(classSpecification.extendsAnnotationType)); writer.print(' '); } // Write out the extended class name. writer.print(classSpecification.extendsClassName != null ? ClassUtil.externalClassName(classSpecification.extendsClassName) : ConfigurationConstants.ANY_CLASS_KEYWORD); } // Write out the keep field and keep method options, if any. if (classSpecification.fieldSpecifications != null || classSpecification.methodSpecifications != null) { writer.print(' '); writer.println(ConfigurationConstants.OPEN_KEYWORD); writeFieldSpecification( classSpecification.fieldSpecifications); writeMethodSpecification(classSpecification.methodSpecifications); writer.println(ConfigurationConstants.CLOSE_KEYWORD); } else { writer.println(); } } private void writeComments(String comments) { if (comments != null) { int index = 0; while (index < comments.length()) { int breakIndex = comments.indexOf('\n', index); if (breakIndex < 0) { breakIndex = comments.length(); } writer.print('#'); if (comments.charAt(index) != ' ') { writer.print(' '); } writer.println(comments.substring(index, breakIndex)); index = breakIndex + 1; } } } private void writeFieldSpecification(List memberSpecifications) { if (memberSpecifications != null) { for (int index = 0; index < memberSpecifications.size(); index++) { MemberSpecification memberSpecification = (MemberSpecification)memberSpecifications.get(index); writer.print(" "); // Write out the required annotation, if any. if (memberSpecification.annotationType != null) { writer.print(ConfigurationConstants.ANNOTATION_KEYWORD); writer.println(ClassUtil.externalType(memberSpecification.annotationType)); writer.print(" "); } // Write out the field access flags. writer.print(ClassUtil.externalFieldAccessFlags(memberSpecification.requiredUnsetAccessFlags, ConfigurationConstants.NEGATOR_KEYWORD)); writer.print(ClassUtil.externalFieldAccessFlags(memberSpecification.requiredSetAccessFlags)); // Write out the field name and descriptor. String name = memberSpecification.name; String descriptor = memberSpecification.descriptor; writer.print(descriptor == null ? name == null ? ConfigurationConstants.ANY_FIELD_KEYWORD : ConfigurationConstants.ANY_TYPE_KEYWORD + ' ' + name : ClassUtil.externalFullFieldDescription(0, name == null ? ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD : name, descriptor)); writer.println(ConfigurationConstants.SEPARATOR_KEYWORD); } } } private void writeMethodSpecification(List memberSpecifications) { if (memberSpecifications != null) { for (int index = 0; index < memberSpecifications.size(); index++) { MemberSpecification memberSpecification = (MemberSpecification)memberSpecifications.get(index); writer.print(" "); // Write out the required annotation, if any. if (memberSpecification.annotationType != null) { writer.print(ConfigurationConstants.ANNOTATION_KEYWORD); writer.println(ClassUtil.externalType(memberSpecification.annotationType)); writer.print(" "); } // Write out the method access flags. writer.print(ClassUtil.externalMethodAccessFlags(memberSpecification.requiredUnsetAccessFlags, ConfigurationConstants.NEGATOR_KEYWORD)); writer.print(ClassUtil.externalMethodAccessFlags(memberSpecification.requiredSetAccessFlags)); // Write out the method name and descriptor. String name = memberSpecification.name; String descriptor = memberSpecification.descriptor; writer.print(descriptor == null ? name == null ? ConfigurationConstants.ANY_METHOD_KEYWORD : ConfigurationConstants.ANY_TYPE_KEYWORD + ' ' + name + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD + ConfigurationConstants.ANY_ARGUMENTS_KEYWORD + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD : ClassUtil.externalFullMethodDescription(ClassConstants.INTERNAL_METHOD_NAME_INIT, 0, name == null ? ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD : name, descriptor)); writer.println(ConfigurationConstants.SEPARATOR_KEYWORD); } } } /** * Returns a list with external versions of the given list of internal * class names. */ private List externalClassNames(List internalClassNames) { List externalClassNames = new ArrayList(internalClassNames.size()); for (int index = 0; index < internalClassNames.size(); index++) { externalClassNames.add(ClassUtil.externalClassName((String)internalClassNames.get(index))); } return externalClassNames; } /** * Returns a relative file name of the given file, if possible. * The file name is also quoted, if necessary. */ private String relativeFileName(File file) { String fileName = file.getAbsolutePath(); // See if we can convert the file name into a relative file name. if (baseDir != null) { String baseDirName = baseDir.getAbsolutePath() + File.separator; if (fileName.startsWith(baseDirName)) { fileName = fileName.substring(baseDirName.length()); } } return quotedString(fileName); } /** * Returns a quoted version of the given string, if necessary. */ private String quotedString(String string) { return string.length() == 0 || string.indexOf(' ') >= 0 || string.indexOf('@') >= 0 || string.indexOf('{') >= 0 || string.indexOf('}') >= 0 || string.indexOf('(') >= 0 || string.indexOf(')') >= 0 || string.indexOf(':') >= 0 || string.indexOf(';') >= 0 || string.indexOf(',') >= 0 ? ("'" + string + "'") : ( string ); } /** * A main method for testing configuration writing. */ public static void main(String[] args) { try { ConfigurationWriter writer = new ConfigurationWriter(new File(args[0])); writer.write(new Configuration()); } catch (Exception ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/MANIFEST.MF0000644000175000017500000000006411163773610015632 0ustar ericericManifest-Version: 1.0 Main-Class: proguard.ProGuard proguard4.8/src/proguard/ParseException.java0000644000175000017500000000316511736333525020004 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; /** * This Exception signals that a parse exception of some * sort has occurred. * * @author Eric Lafortune */ public class ParseException extends Exception { /** * Constructs a ParseException with null * as its error detail message. */ public ParseException() { super(); } /** * Constructs a ParseException with the specified detail * message. The error message string s can later be * retrieved by the {@link Throwable#getMessage} * method of class Throwable. * * @param s the detail message. */ public ParseException(String s) { super(s); } } proguard4.8/src/proguard/DataEntryWriterFactory.java0000644000175000017500000001374311736333525021476 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.io.*; import proguard.util.*; import java.util.List; /** * This class can create DataEntryWriter instances based on class paths. The * writers will wrap the output in the proper jars, wars, ears, and zips. * * @author Eric Lafortune */ public class DataEntryWriterFactory { /** * Creates a DataEntryWriter that can write to the given class path entries. * * @param classPath the output class path. * @param fromIndex the start index in the class path. * @param toIndex the end index in the class path. * @return a DataEntryWriter for writing to the given class path entries. */ public static DataEntryWriter createDataEntryWriter(ClassPath classPath, int fromIndex, int toIndex) { DataEntryWriter writer = null; // Create a chain of writers, one for each class path entry. for (int index = toIndex - 1; index >= fromIndex; index--) { ClassPathEntry entry = classPath.get(index); writer = createClassPathEntryWriter(entry, writer); } return writer; } /** * Creates a DataEntryWriter that can write to the given class path entry, * or delegate to another DataEntryWriter if its filters don't match. */ private static DataEntryWriter createClassPathEntryWriter(ClassPathEntry classPathEntry, DataEntryWriter alternativeWriter) { boolean isJar = classPathEntry.isJar(); boolean isWar = classPathEntry.isWar(); boolean isEar = classPathEntry.isEar(); boolean isZip = classPathEntry.isZip(); List filter = classPathEntry.getFilter(); List jarFilter = classPathEntry.getJarFilter(); List warFilter = classPathEntry.getWarFilter(); List earFilter = classPathEntry.getEarFilter(); List zipFilter = classPathEntry.getZipFilter(); System.out.println("Preparing output " + (isJar ? "jar" : isWar ? "war" : isEar ? "ear" : isZip ? "zip" : "directory") + " [" + classPathEntry.getName() + "]" + (filter != null || jarFilter != null || warFilter != null || earFilter != null || zipFilter != null ? " (filtered)" : "")); DataEntryWriter writer = new DirectoryWriter(classPathEntry.getFile(), isJar || isWar || isEar || isZip); // Set up the filtered jar writers. writer = wrapInJarWriter(writer, isZip, zipFilter, ".zip", isJar || isWar || isEar); writer = wrapInJarWriter(writer, isEar, earFilter, ".ear", isJar || isWar); writer = wrapInJarWriter(writer, isWar, warFilter, ".war", isJar); writer = wrapInJarWriter(writer, isJar, jarFilter, ".jar", false); // Add a filter, if specified. writer = filter != null? new FilteredDataEntryWriter( new DataEntryNameFilter( new ListParser(new FileNameParser()).parse(filter)), writer) : writer; // Let the writer cascade, if specified. return alternativeWriter != null ? new CascadingDataEntryWriter(writer, alternativeWriter) : writer; } /** * Wraps the given DataEntryWriter in a JarWriter, filtering if necessary. */ private static DataEntryWriter wrapInJarWriter(DataEntryWriter writer, boolean isJar, List jarFilter, String jarExtension, boolean dontWrap) { // Zip up jars, if necessary. DataEntryWriter jarWriter = dontWrap ? (DataEntryWriter)new ParentDataEntryWriter(writer) : (DataEntryWriter)new JarWriter(writer); // Add a filter, if specified. DataEntryWriter filteredJarWriter = jarFilter != null? new FilteredDataEntryWriter( new DataEntryParentFilter( new DataEntryNameFilter( new ListParser(new FileNameParser()).parse(jarFilter))), jarWriter) : jarWriter; // Only zip up jars, unless the output is a jar file itself. return new FilteredDataEntryWriter( new DataEntryParentFilter( new DataEntryNameFilter( new ExtensionMatcher(jarExtension))), filteredJarWriter, isJar ? jarWriter : writer); } } proguard4.8/src/proguard/DuplicateClassPrinter.java0000644000175000017500000000401711736333525021314 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor writes out notes about the class files that it visits * being duplicates. * * @author Eric Lafortune */ public class DuplicateClassPrinter implements ClassVisitor { private final WarningPrinter notePrinter; /** * Creates a new DuplicateClassVisitor. */ public DuplicateClassPrinter(WarningPrinter notePrinter) { this.notePrinter = notePrinter; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { notePrinter.print(programClass.getName(), "Note: duplicate definition of program class [" + ClassUtil.externalClassName(programClass.getName()) + "]"); } public void visitLibraryClass(LibraryClass libraryClass) { notePrinter.print(libraryClass.getName(), "Note: duplicate definition of library class [" + ClassUtil.externalClassName(libraryClass.getName()) + "]"); } } proguard4.8/src/proguard/FileWordReader.java0000644000175000017500000000331011736333525017701 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.io.*; import java.net.URL; /** * A WordReader that returns words from a file or a URL. * * @author Eric Lafortune */ public class FileWordReader extends LineWordReader { /** * Creates a new FileWordReader for the given file. */ public FileWordReader(File file) throws IOException { super(new LineNumberReader(new BufferedReader(new FileReader(file))), "file '" + file.getPath() + "'", file.getParentFile() ); } /** * Creates a new FileWordReader for the given URL. */ public FileWordReader(URL url) throws IOException { super(new LineNumberReader(new BufferedReader(new InputStreamReader(url.openStream()))), "file '" + url.toString() + "'", null); } } proguard4.8/src/proguard/DescriptorKeepChecker.java0000644000175000017500000001457611736333525021273 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.optimize.*; import java.util.List; /** * This class checks whether classes referenced by class members that are * marked to be kept are marked to be kept too. * * @author Eric Lafortune */ public class DescriptorKeepChecker extends SimplifiedVisitor implements MemberVisitor, ClassVisitor { private final ClassPool programClassPool; private final ClassPool libraryClassPool; private final WarningPrinter notePrinter; // Some fields acting as parameters for the class visitor. private Clazz referencingClass; private Member referencingMember; private boolean isField; /** * Creates a new DescriptorKeepChecker. */ public DescriptorKeepChecker(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter notePrinter) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; this.notePrinter = notePrinter; } /** * Checks the classes mentioned in the given keep specifications, printing * notes if necessary. */ public void checkClassSpecifications(List keepSpecifications) { // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); libraryClassPool.classesAccept(new ClassCleaner()); // Create a visitor for marking the seeds. KeepMarker keepMarker = new KeepMarker(); ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(keepSpecifications, keepMarker, keepMarker, false, true, true); // Mark the seeds. programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); // Print out notes about argument types that are not being kept in // class members that are being kept. programClassPool.classesAccept( new AllMemberVisitor( new KeptMemberFilter(this))); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { //referencingClass = programClass; //referencingMember = programField; //isField = true; // // Don't check the type, because it is not required for introspection. //programField.referencedClassesAccept(this); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { referencingClass = programClass; referencingMember = programMethod; isField = false; // Don't check the return type, because it is not required for // introspection (e.g. the return type of the special Enum methods). //programMethod.referencedClassesAccept(this); Clazz[] referencedClasses = programMethod.referencedClasses; if (referencedClasses != null) { int count = referencedClasses.length; // Adapt the count if the return type is a class type (not so // pretty; assuming test just checks for final ';'). if (ClassUtil.isInternalClassType(programMethod.getDescriptor(programClass))) { count--; } for (int index = 0; index < count; index++) { if (referencedClasses[index] != null) { referencedClasses[index].accept(this); } } } } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (!KeepMarker.isKept(programClass)) { notePrinter.print(referencingClass.getName(), programClass.getName(), "Note: the configuration keeps the entry point '" + ClassUtil.externalClassName(referencingClass.getName()) + " { " + (isField ? ClassUtil.externalFullFieldDescription(0, referencingMember.getName(referencingClass), referencingMember.getDescriptor(referencingClass)) : ClassUtil.externalFullMethodDescription(referencingClass.getName(), 0, referencingMember.getName(referencingClass), referencingMember.getDescriptor(referencingClass))) + "; }', but not the descriptor class '" + ClassUtil.externalClassName(programClass.getName()) + "'"); } } public void visitLibraryClass(LibraryClass libraryClass) {} } proguard4.8/src/proguard/ClassSpecification.java0000644000175000017500000002641111736333525020620 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.util.*; /** * This class stores a specification of classes and possibly class members. * The specification is template-based: the class names and class member names * and descriptors can contain wildcards. Classes can be specified explicitly, * or as extensions or implementations in the class hierarchy. * * @author Eric Lafortune */ public class ClassSpecification implements Cloneable { public final String comments; public int requiredSetAccessFlags; public int requiredUnsetAccessFlags; public final String annotationType; public String className; public final String extendsAnnotationType; public final String extendsClassName; public List fieldSpecifications; public List methodSpecifications; /** * Creates a new ClassSpecification for all possible classes, without * comments or class members. */ public ClassSpecification() { this(null, 0, 0, null, null, null, null); } /** * Creates a new ClassSpecification that is a copy of the given specification. */ public ClassSpecification(ClassSpecification classSpecification) { this(classSpecification.comments, classSpecification.requiredSetAccessFlags, classSpecification.requiredUnsetAccessFlags, classSpecification.annotationType, classSpecification.className, classSpecification.extendsAnnotationType, classSpecification.extendsClassName, classSpecification.fieldSpecifications, classSpecification.methodSpecifications); } /** * Creates a new ClassSpecification for the specified class(es), without * class members. * * @param comments provides optional comments on this * specification. * @param requiredSetAccessFlags the class access flags that must be set * in order for the class to apply. * @param requiredUnsetAccessFlags the class access flags that must be * unset in order for the class to apply. * @param annotationType the name of the class that must be an * annotation of the class in order for it * to apply. The name may be null to * specify that no annotation is required. * @param className the class name. The name may be null to * specify any class, or it may contain * "**", "*", or "?" wildcards. * @param extendsAnnotationType the name of the class of that must be * an annotation of the class that the * class must extend or implement in order * to apply. The name may be null to * specify that no annotation is required. * @param extendsClassName the name of the class that the class * must extend or implement in order to * apply. The name may be null to specify * any class. */ public ClassSpecification(String comments, int requiredSetAccessFlags, int requiredUnsetAccessFlags, String annotationType, String className, String extendsAnnotationType, String extendsClassName) { this(comments, requiredSetAccessFlags, requiredUnsetAccessFlags, annotationType, className, extendsAnnotationType, extendsClassName, null, null); } /** * Creates a new ClassSpecification for the specified classes and class * members. * * @param comments provides optional comments on this * specification. * @param requiredSetAccessFlags the class access flags that must be set * in order for the class to apply. * @param requiredUnsetAccessFlags the class access flags that must be * unset in order for the class to apply. * @param annotationType the name of the class that must be an * annotation of the class in order for it * to apply. The name may be null to * specify that no annotation is required. * @param className the class name. The name may be null to * specify any class, or it may contain * "**", "*", or "?" wildcards. * @param extendsAnnotationType the name of the class of that must be * an annotation of the class that the * class must extend or implement in order * to apply. The name may be null to * specify that no annotation is required. * @param extendsClassName the name of the class that the class * must extend or implement in order to * apply. The name may be null to specify * any class. * @param fieldSpecifications the field specifications. * @param methodSpecifications the method specifications. */ public ClassSpecification(String comments, int requiredSetAccessFlags, int requiredUnsetAccessFlags, String annotationType, String className, String extendsAnnotationType, String extendsClassName, List fieldSpecifications, List methodSpecifications) { this.comments = comments; this.requiredSetAccessFlags = requiredSetAccessFlags; this.requiredUnsetAccessFlags = requiredUnsetAccessFlags; this.annotationType = annotationType; this.className = className; this.extendsAnnotationType = extendsAnnotationType; this.extendsClassName = extendsClassName; this.fieldSpecifications = fieldSpecifications; this.methodSpecifications = methodSpecifications; } /** * Specifies to keep the specified field(s) of this option's class(es). * * @param fieldSpecification the field specification. */ public void addField(MemberSpecification fieldSpecification) { if (fieldSpecifications == null) { fieldSpecifications = new ArrayList(); } fieldSpecifications.add(fieldSpecification); } /** * Specifies to keep the specified method(s) of this option's class(es). * * @param methodSpecification the method specification. */ public void addMethod(MemberSpecification methodSpecification) { if (methodSpecifications == null) { methodSpecifications = new ArrayList(); } methodSpecifications.add(methodSpecification); } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } ClassSpecification other = (ClassSpecification)object; return // (this.comments == null ? other.comments == null : this.comments.equals(other.comments) ) && (this.requiredSetAccessFlags == other.requiredSetAccessFlags ) && (this.requiredUnsetAccessFlags == other.requiredUnsetAccessFlags ) && (this.annotationType == null ? other.annotationType == null : this.annotationType.equals(other.annotationType) ) && (this.className == null ? other.className == null : this.className.equals(other.className) ) && (this.extendsAnnotationType == null ? other.extendsAnnotationType == null : this.extendsAnnotationType.equals(other.extendsAnnotationType)) && (this.extendsClassName == null ? other.extendsClassName == null : this.extendsClassName.equals(other.extendsClassName) ) && (this.fieldSpecifications == null ? other.fieldSpecifications == null : this.fieldSpecifications.equals(other.fieldSpecifications) ) && (this.methodSpecifications == null ? other.methodSpecifications == null : this.methodSpecifications.equals(other.methodSpecifications) ); } public int hashCode() { return // (comments == null ? 0 : comments.hashCode() ) ^ (requiredSetAccessFlags ) ^ (requiredUnsetAccessFlags ) ^ (annotationType == null ? 0 : annotationType.hashCode() ) ^ (className == null ? 0 : className.hashCode() ) ^ (extendsAnnotationType == null ? 0 : extendsAnnotationType.hashCode()) ^ (extendsClassName == null ? 0 : extendsClassName.hashCode() ) ^ (fieldSpecifications == null ? 0 : fieldSpecifications.hashCode() ) ^ (methodSpecifications == null ? 0 : methodSpecifications.hashCode() ); } public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { return null; } } } proguard4.8/src/proguard/ant/0000775000175000017500000000000011760503005014754 5ustar ericericproguard4.8/src/proguard/ant/package.html0000644000175000017500000000010011736333525017235 0ustar ericeric This package contains the Ant task for ProGuard. proguard4.8/src/proguard/ant/MemberSpecificationElement.java0000644000175000017500000002002211736333525023046 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.ant; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.DataType; import proguard.MemberSpecification; import proguard.classfile.ClassConstants; import proguard.classfile.util.ClassUtil; import proguard.util.ListUtil; import java.util.*; /** * This DataType represents a class member specification in Ant. * * @author Eric Lafortune */ public class MemberSpecificationElement extends DataType { private String access; private String annotation; private String type; private String name; private String parameters; /** * Adds the contents of this class member specification element to the given * list. * @param memberSpecifications the class member specifications to be * extended. * @param isMethod specifies whether this specification * refers to a method. * @param isConstructor specifies whether this specification * refers to a constructor. */ public void appendTo(List memberSpecifications, boolean isMethod, boolean isConstructor) { // Get the referenced file set, or else this one. MemberSpecificationElement memberSpecificationElement = isReference() ? (MemberSpecificationElement)getCheckedRef(this.getClass(), this.getClass().getName()) : this; // Create a new class specification. String access = memberSpecificationElement.access; String type = memberSpecificationElement.type; String annotation = memberSpecificationElement.annotation; String name = memberSpecificationElement.name; String parameters = memberSpecificationElement.parameters; // Perform some basic conversions and checks on the attributes. if (annotation != null) { annotation = ClassUtil.internalType(annotation); } if (isMethod) { if (isConstructor) { if (type != null) { throw new BuildException("Type attribute not allowed in constructor specification ["+type+"]"); } if (parameters != null) { type = ClassConstants.EXTERNAL_TYPE_VOID; } name = ClassConstants.INTERNAL_METHOD_NAME_INIT; } else if ((type != null) ^ (parameters != null)) { throw new BuildException("Type and parameters attributes must always be present in combination in method specification"); } } else { if (parameters != null) { throw new BuildException("Parameters attribute not allowed in field specification ["+parameters+"]"); } } List parameterList = ListUtil.commaSeparatedList(parameters); String descriptor = parameters != null ? ClassUtil.internalMethodDescriptor(type, parameterList) : type != null ? ClassUtil.internalType(type) : null; MemberSpecification memberSpecification = new MemberSpecification(requiredAccessFlags(true, access), requiredAccessFlags(false, access), annotation, name, descriptor); // Add it to the list. memberSpecifications.add(memberSpecification); } // Ant task attributes. public void setAccess(String access) { this.access = access; } public void setAnnotation(String annotation) { this.annotation = annotation; } public void setType(String type) { this.type = type; } public void setName(String name) { this.name = name; } public void setParameters(String parameters) { this.parameters = parameters; } /** * @deprecated Use {@link #setParameters(String)} instead. */ public void setParam(String parameters) { this.parameters = parameters; } // Small utility methods. private int requiredAccessFlags(boolean set, String access) throws BuildException { int accessFlags = 0; if (access != null) { StringTokenizer tokenizer = new StringTokenizer(access, " ,"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (token.startsWith("!") ^ set) { String strippedToken = token.startsWith("!") ? token.substring(1) : token; int accessFlag = strippedToken.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : strippedToken.equals(ClassConstants.EXTERNAL_ACC_PRIVATE) ? ClassConstants.INTERNAL_ACC_PRIVATE : strippedToken.equals(ClassConstants.EXTERNAL_ACC_PROTECTED) ? ClassConstants.INTERNAL_ACC_PROTECTED : strippedToken.equals(ClassConstants.EXTERNAL_ACC_STATIC) ? ClassConstants.INTERNAL_ACC_STATIC : strippedToken.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED : strippedToken.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE : strippedToken.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT : strippedToken.equals(ClassConstants.EXTERNAL_ACC_BRIDGE) ? ClassConstants.INTERNAL_ACC_BRIDGE : strippedToken.equals(ClassConstants.EXTERNAL_ACC_VARARGS) ? ClassConstants.INTERNAL_ACC_VARARGS : strippedToken.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE : strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : strippedToken.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT : strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC : 0; if (accessFlag == 0) { throw new BuildException("Incorrect class member access modifier ["+strippedToken+"]"); } accessFlags |= accessFlag; } } } return accessFlags; } } proguard4.8/src/proguard/ant/ClassPathElement.java0000644000175000017500000001250411736333525021026 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.ant; import org.apache.tools.ant.*; import org.apache.tools.ant.types.*; import proguard.*; import proguard.util.ListUtil; import java.io.File; /** * This FileSet represents a class path entry (or a set of class path entries) * in Ant. * * @author Eric Lafortune */ public class ClassPathElement extends Path { private String filter; private String jarFilter; private String warFilter; private String earFilter; private String zipFilter; /** * @see Path#Path(Project) */ public ClassPathElement(Project project) { super(project); } /** * Adds the contents of this class path element to the given class path. * @param classPath the class path to be extended. * @param output specifies whether this is an output entry or not. */ public void appendClassPathEntriesTo(ClassPath classPath, boolean output) { File baseDir = getProject().getBaseDir(); String[] fileNames; if (isReference()) { // Get the referenced path or file set. Object referencedObject = getCheckedRef(DataType.class, DataType.class.getName()); if (referencedObject instanceof Path) { Path path = (Path)referencedObject; // Get the names of the files in the referenced path. fileNames = path.list(); } else if (referencedObject instanceof AbstractFileSet) { AbstractFileSet fileSet = (AbstractFileSet)referencedObject; // Get the names of the existing input files in the referenced file set. DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); baseDir = scanner.getBasedir(); fileNames = scanner.getIncludedFiles(); } else { throw new BuildException("The refid attribute doesn't point to a element or a element"); } } else { // Get the names of the files in this path. fileNames = list(); } if (output) { if (fileNames.length != 1) { throw new BuildException("The element must specify exactly one file or directory ["+fileNames.length+"]"); } } //else //{ // if (fileNames.length < 1) // { // throw new BuildException("The element must specify at least one file or directory"); // } //} for (int index = 0; index < fileNames.length; index++) { // Create a new class path entry, with the proper file name and // any filters. String fileName = fileNames[index]; File file = new File(fileName); ClassPathEntry entry = new ClassPathEntry(file.isAbsolute() ? file : new File(baseDir, fileName), output); entry.setFilter(ListUtil.commaSeparatedList(filter)); entry.setJarFilter(ListUtil.commaSeparatedList(jarFilter)); entry.setWarFilter(ListUtil.commaSeparatedList(warFilter)); entry.setEarFilter(ListUtil.commaSeparatedList(earFilter)); entry.setZipFilter(ListUtil.commaSeparatedList(zipFilter)); // Add it to the class path. classPath.add(entry); } } // Ant task attributes. /** * @deprecated Use {@link #setLocation(File)} instead. */ public void setFile(File file) { setLocation(file); } /** * @deprecated Use {@link #setLocation(File)} instead. */ public void setDir(File file) { setLocation(file); } /** * @deprecated Use {@link #setLocation(File)} instead. */ public void setName(File file) { setLocation(file); } public void setFilter(String filter) { this.filter = filter; } public void setJarfilter(String jarFilter) { this.jarFilter = jarFilter; } public void setWarfilter(String warFilter) { this.warFilter = warFilter; } public void setEarfilter(String earFilter) { this.earFilter = earFilter; } public void setZipfilter(String zipFilter) { this.zipFilter = zipFilter; } } proguard4.8/src/proguard/ant/ConfigurationTask.java0000664000175000017500000003766111752561052021275 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.ant; import org.apache.tools.ant.*; import proguard.*; import java.io.IOException; import java.util.*; /** * This Task allows to define a ProGuard configuration from Ant. * * @author Eric Lafortune */ public class ConfigurationTask extends Task { protected final Configuration configuration = new Configuration(); /** * Adds the contents of this configuration task to the given configuration. * @param configuration the configuration to be extended. */ public void appendTo(Configuration configuration) { // Append all of these configuration entries to the given configuration. configuration.programJars = extendClassPath(configuration.programJars, this.configuration.programJars); configuration.libraryJars = extendClassPath(configuration.libraryJars, this.configuration.libraryJars); configuration.keep = extendClassSpecifications(configuration.keep, this.configuration.keep); configuration.keepDirectories = extendList(configuration.keepDirectories, this.configuration.keepDirectories); configuration.whyAreYouKeeping = extendClassSpecifications(configuration.whyAreYouKeeping, this.configuration.whyAreYouKeeping); configuration.optimizations = extendClassSpecifications(configuration.optimizations, this.configuration.optimizations); configuration.assumeNoSideEffects = extendClassSpecifications(configuration.assumeNoSideEffects, this.configuration.assumeNoSideEffects); configuration.keepPackageNames = extendList(configuration.keepPackageNames, this.configuration.keepPackageNames); configuration.keepAttributes = extendList(configuration.keepAttributes, this.configuration.keepAttributes); configuration.adaptClassStrings = extendList(configuration.adaptClassStrings, this.configuration.adaptClassStrings); configuration.adaptResourceFileNames = extendList(configuration.adaptResourceFileNames, this.configuration.adaptResourceFileNames); configuration.adaptResourceFileContents = extendList(configuration.adaptResourceFileContents, this.configuration.adaptResourceFileContents); configuration.note = extendList(configuration.note, this.configuration.note); configuration.warn = extendList(configuration.warn, this.configuration.warn); } // Ant task nested elements. public void addConfiguredInjar(ClassPathElement classPathElement) { configuration.programJars = extendClassPath(configuration.programJars, classPathElement, false); } public void addConfiguredOutjar(ClassPathElement classPathElement) { configuration.programJars = extendClassPath(configuration.programJars, classPathElement, true); } public void addConfiguredLibraryjar(ClassPathElement classPathElement) { configuration.libraryJars = extendClassPath(configuration.libraryJars, classPathElement, false); } public void addConfiguredKeepdirectory(FilterElement filterElement) { configuration.keepDirectories = extendFilter(configuration.keepDirectories, filterElement); } public void addConfiguredKeepdirectories(FilterElement filterElement) { configuration.keepDirectories = extendFilter(configuration.keepDirectories, filterElement); } public void addConfiguredKeep(KeepSpecificationElement keepSpecificationElement) { configuration.keep = extendKeepSpecifications(configuration.keep, keepSpecificationElement, true, false); } public void addConfiguredKeepclassmembers(KeepSpecificationElement keepSpecificationElement) { configuration.keep = extendKeepSpecifications(configuration.keep, keepSpecificationElement, false, false); } public void addConfiguredKeepclasseswithmembers(KeepSpecificationElement keepSpecificationElement) { configuration.keep = extendKeepSpecifications(configuration.keep, keepSpecificationElement, true, true); } public void addConfiguredKeepnames(KeepSpecificationElement keepSpecificationElement) { // Set the shrinking flag, based on the name (backward compatibility). keepSpecificationElement.setAllowshrinking(true); configuration.keep = extendKeepSpecifications(configuration.keep, keepSpecificationElement, true, false); } public void addConfiguredKeepclassmembernames(KeepSpecificationElement keepSpecificationElement) { // Set the shrinking flag, based on the name (backward compatibility). keepSpecificationElement.setAllowshrinking(true); configuration.keep = extendKeepSpecifications(configuration.keep, keepSpecificationElement, false, false); } public void addConfiguredKeepclasseswithmembernames(KeepSpecificationElement keepSpecificationElement) { // Set the shrinking flag, based on the name (backward compatibility). keepSpecificationElement.setAllowshrinking(true); configuration.keep = extendKeepSpecifications(configuration.keep, keepSpecificationElement, true, true); } public void addConfiguredWhyareyoukeeping(ClassSpecificationElement classSpecificationElement) { configuration.whyAreYouKeeping = extendClassSpecifications(configuration.whyAreYouKeeping, classSpecificationElement); } public void addConfiguredAssumenosideeffects(ClassSpecificationElement classSpecificationElement) { configuration.assumeNoSideEffects = extendClassSpecifications(configuration.assumeNoSideEffects, classSpecificationElement); } public void addConfiguredOptimizations(FilterElement filterElement) { addConfiguredOptimization(filterElement); } public void addConfiguredOptimization(FilterElement filterElement) { configuration.optimizations = extendFilter(configuration.optimizations, filterElement); } public void addConfiguredKeeppackagename(FilterElement filterElement) { configuration.keepPackageNames = extendFilter(configuration.keepPackageNames, filterElement, true); } public void addConfiguredKeeppackagenames(FilterElement filterElement) { configuration.keepPackageNames = extendFilter(configuration.keepPackageNames, filterElement, true); } public void addConfiguredKeepattributes(FilterElement filterElement) { addConfiguredKeepattribute(filterElement); } public void addConfiguredKeepattribute(FilterElement filterElement) { configuration.keepAttributes = extendFilter(configuration.keepAttributes, filterElement); } public void addConfiguredAdaptclassstrings(FilterElement filterElement) { configuration.adaptClassStrings = extendFilter(configuration.adaptClassStrings, filterElement, true); } public void addConfiguredAdaptresourcefilenames(FilterElement filterElement) { configuration.adaptResourceFileNames = extendFilter(configuration.adaptResourceFileNames, filterElement); } public void addConfiguredAdaptresourcefilecontents(FilterElement filterElement) { configuration.adaptResourceFileContents = extendFilter(configuration.adaptResourceFileContents, filterElement); } public void addConfiguredDontnote(FilterElement filterElement) { configuration.note = extendFilter(configuration.note, filterElement, true); } public void addConfiguredDontwarn(FilterElement filterElement) { configuration.warn = extendFilter(configuration.warn, filterElement, true); } public void addConfiguredConfiguration(ConfigurationElement configurationElement) { configurationElement.appendTo(configuration); } // Implementations for Task. public void addText(String text) throws BuildException { try { Project project = getProject(); // Replace Ant-style properties ('${...}'). String arg = project.replaceProperties(text); // Get the combined system properties and Ant properties, for // replacing ProGuard-style properties ('<...>'). Properties properties = new Properties(); properties.putAll(project.getProperties()); ConfigurationParser parser = new ConfigurationParser(arg, "embedded configuration", project.getBaseDir(), properties); try { parser.parse(configuration); } catch (ParseException ex) { throw new BuildException(ex.getMessage()); } finally { parser.close(); } } catch (IOException ex) { throw new BuildException(ex.getMessage()); } } // Small utility methods. private ClassPath extendClassPath(ClassPath classPath, ClassPathElement classPathElement, boolean output) { if (classPath == null) { classPath = new ClassPath(); } classPathElement.appendClassPathEntriesTo(classPath, output); return classPath; } private ClassPath extendClassPath(ClassPath classPath, ClassPath additionalClassPath) { if (additionalClassPath != null) { if (classPath == null) { classPath = new ClassPath(); } classPath.addAll(additionalClassPath); } return classPath; } private List extendKeepSpecifications(List keepSpecifications, KeepSpecificationElement keepSpecificationElement, boolean markClasses, boolean markClassesConditionally) { if (keepSpecifications == null) { keepSpecifications = new ArrayList(); } keepSpecificationElement.appendTo(keepSpecifications, markClasses, markClassesConditionally); return keepSpecifications; } private List extendClassSpecifications(List classSpecifications, ClassSpecificationElement classSpecificationElement) { if (classSpecifications == null) { classSpecifications = new ArrayList(); } classSpecificationElement.appendTo(classSpecifications); return classSpecifications; } private List extendClassSpecifications(List classSpecifications, List additionalClassSpecifications) { if (additionalClassSpecifications != null) { if (classSpecifications == null) { classSpecifications = new ArrayList(); } classSpecifications.addAll(additionalClassSpecifications); } return classSpecifications; } private List extendFilter(List filter, FilterElement filterElement) { return extendFilter(filter, filterElement, false); } private List extendFilter(List filter, FilterElement filterElement, boolean internal) { if (filter == null) { filter = new ArrayList(); } filterElement.appendTo(filter, internal); return filter; } private List extendList(List list, List additionalList) { if (additionalList != null) { if (list == null) { list = new ArrayList(); } list.addAll(additionalList); } return list; } } proguard4.8/src/proguard/ant/ClassSpecificationElement.java0000644000175000017500000002123111736333525022707 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.ant; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.DataType; import proguard.*; import proguard.classfile.ClassConstants; import proguard.classfile.util.ClassUtil; import java.util.*; /** * This DataType represents a class specification in Ant. * * @author Eric Lafortune */ public class ClassSpecificationElement extends DataType { private static final String ANY_CLASS_KEYWORD = "*"; private String access; private String annotation; private String type; private String name; private String extendsAnnotation; private String extends_; private List fieldSpecifications = new ArrayList(); private List methodSpecifications = new ArrayList(); /** * Adds the contents of this class specification element to the given list. * @param classSpecifications the class specifications to be extended. */ public void appendTo(List classSpecifications) { // Get the referenced file set, or else this one. ClassSpecificationElement classSpecificationElement = isReference() ? (ClassSpecificationElement)getCheckedRef(this.getClass(), this.getClass().getName()) : this; ClassSpecification classSpecification = createClassSpecification(classSpecificationElement); // Add it to the list. classSpecifications.add(classSpecification); } /** * Creates a new class specification corresponding to the contents of this * class specification element. */ protected ClassSpecification createClassSpecification(ClassSpecificationElement classSpecificationElement) { String access = classSpecificationElement.access; String annotation = classSpecificationElement.annotation; String type = classSpecificationElement.type; String name = classSpecificationElement.name; String extendsAnnotation = classSpecificationElement.extendsAnnotation; String extends_ = classSpecificationElement.extends_; // For backward compatibility, allow a single "*" wildcard to match // any class. if (name != null && name.equals(ANY_CLASS_KEYWORD)) { name = null; } ClassSpecification classSpecification = new ClassSpecification(null, requiredAccessFlags(true, access, type), requiredAccessFlags(false, access, type), annotation != null ? ClassUtil.internalType(annotation) : null, name != null ? ClassUtil.internalClassName(name) : null, extendsAnnotation != null ? ClassUtil.internalType(extendsAnnotation) : null, extends_ != null ? ClassUtil.internalClassName(extends_) : null); for (int index = 0; index < fieldSpecifications.size(); index++) { classSpecification.addField((MemberSpecification)fieldSpecifications.get(index)); } for (int index = 0; index < methodSpecifications.size(); index++) { classSpecification.addMethod((MemberSpecification)methodSpecifications.get(index)); } return classSpecification; } // Ant task attributes. public void setAccess(String access) { this.access = access; } public void setAnnotation(String annotation) { this.annotation = annotation; } public void setType(String type) { this.type = type; } public void setName(String name) { this.name = name; } public void setExtendsannotation(String extendsAnnotation) { this.extendsAnnotation = extendsAnnotation; } public void setExtends(String extends_) { this.extends_ = extends_; } public void setImplements(String implements_) { this.extends_ = implements_; } // Ant task nested elements. public void addConfiguredField(MemberSpecificationElement memberSpecificationElement) { if (fieldSpecifications == null) { fieldSpecifications = new ArrayList(); } memberSpecificationElement.appendTo(fieldSpecifications, false, false); } public void addConfiguredMethod(MemberSpecificationElement memberSpecificationElement) { if (methodSpecifications == null) { methodSpecifications = new ArrayList(); } memberSpecificationElement.appendTo(methodSpecifications, true, false); } public void addConfiguredConstructor(MemberSpecificationElement memberSpecificationElement) { if (methodSpecifications == null) { methodSpecifications = new ArrayList(); } memberSpecificationElement.appendTo(methodSpecifications, true, true); } // Small utility methods. private int requiredAccessFlags(boolean set, String access, String type) throws BuildException { int accessFlags = 0; if (access != null) { StringTokenizer tokenizer = new StringTokenizer(access, " ,"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (token.startsWith("!") ^ set) { String strippedToken = token.startsWith("!") ? token.substring(1) : token; int accessFlag = strippedToken.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : strippedToken.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC : strippedToken.equals(ClassConstants.EXTERNAL_ACC_ANNOTATION) ? ClassConstants.INTERNAL_ACC_ANNOTATTION : 0; if (accessFlag == 0) { throw new BuildException("Incorrect class access modifier ["+strippedToken+"]"); } accessFlags |= accessFlag; } } } if (type != null && (type.startsWith("!") ^ set)) { int accessFlag = type.equals("class") ? 0 : type.equals( ClassConstants.EXTERNAL_ACC_INTERFACE) || type.equals("!" + ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE : type.equals( ClassConstants.EXTERNAL_ACC_ENUM) || type.equals("!" + ClassConstants.EXTERNAL_ACC_ENUM) ? ClassConstants.INTERNAL_ACC_ENUM : -1; if (accessFlag == -1) { throw new BuildException("Incorrect class type ["+type+"]"); } accessFlags |= accessFlag; } return accessFlags; } } proguard4.8/src/proguard/ant/FilterElement.java0000644000175000017500000000464111736333525020374 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.ant; import org.apache.tools.ant.types.DataType; import proguard.classfile.util.ClassUtil; import proguard.util.ListUtil; import java.util.List; /** * This DataType represents a name filter in Ant. * * @author Eric Lafortune */ public class FilterElement extends DataType { private String filter; /** * Adds the contents of this element to the given name filter. * @param filter the list of attributes to be extended. * @param internal specifies whether the filter string should be converted * to internal types. */ public void appendTo(List filter, boolean internal) { // Get the referenced element, or else this one. FilterElement filterElement = isReference() ? (FilterElement)getCheckedRef(this.getClass(), this.getClass().getName()) : this; String filterString = filterElement.filter; if (filterString == null) { // Clear the filter to keep all names. filter.clear(); } else { if (internal) { filterString = ClassUtil.internalClassName(filterString); } // Append the filter. filter.addAll(ListUtil.commaSeparatedList(filterString)); } } // Ant task attributes. public void setName(String name) { this.filter = name; } public void setFilter(String filter) { this.filter = filter; } } proguard4.8/src/proguard/ant/ConfigurationElement.java0000664000175000017500000001050211752706667021762 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.ant; import org.apache.tools.ant.*; import org.apache.tools.ant.types.*; import proguard.*; import proguard.util.ListUtil; import java.io.*; import java.util.Properties; /** * This DataType represents a reference to an XML-style ProGuard configuration * in Ant, or a file set of ProGuard-style configuration files. * * @author Eric Lafortune */ public class ConfigurationElement extends FileSet { /** * Adds the contents of this configuration element to the given * configuration. * @param configuration the configuration to be extended. */ public void appendTo(Configuration configuration) { File baseDir; String[] fileNames; if (isReference()) { // Get the referenced path or file set. Object referencedObject = getCheckedRef(Object.class, Object.class.getName()); if (referencedObject instanceof ConfigurationTask) { // The reference doesn't point to a file set, but to a // configuration task. ConfigurationTask configurationTask = (ConfigurationTask)referencedObject; // Append the contents of the referenced configuration to the // current configuration. configurationTask.appendTo(configuration); return; } else if (referencedObject instanceof AbstractFileSet) { AbstractFileSet fileSet = (AbstractFileSet)referencedObject; // Get the names of the existing input files in the referenced file set. DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); baseDir = scanner.getBasedir(); fileNames = scanner.getIncludedFiles(); } else { throw new BuildException("The refid attribute doesn't point to a element or a element"); } } else { // Get the names of the existing input files in the referenced file set. DirectoryScanner scanner = getDirectoryScanner(getProject()); baseDir = scanner.getBasedir(); fileNames = scanner.getIncludedFiles(); } // Get the combined system properties and Ant properties, for // replacing ProGuard-style properties ('<...>'). Properties properties = new Properties(); properties.putAll(getProject().getProperties()); try { // Append the contents of the configuration files to the current // configuration. for (int index = 0; index < fileNames.length; index++) { File configurationFile = new File(baseDir, fileNames[index]); ConfigurationParser parser = new ConfigurationParser(configurationFile, properties); try { parser.parse(configuration); } catch (ParseException ex) { throw new BuildException(ex.getMessage()); } finally { parser.close(); } } } catch (IOException ex) { throw new BuildException(ex.getMessage()); } } } proguard4.8/src/proguard/ant/task.properties0000644000175000017500000000015111754701155020040 0ustar ericericproguard = proguard.ant.ProGuardTask proguardconfiguration = proguard.ant.ConfigurationTask proguard4.8/src/proguard/ant/KeepSpecificationElement.java0000644000175000017500000000571011736333525022532 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.ant; import proguard.KeepClassSpecification; import java.util.List; /** * This DataType represents a class specification in Ant. * * @author Eric Lafortune */ public class KeepSpecificationElement extends ClassSpecificationElement { private boolean allowShrinking; private boolean allowOptimization; private boolean allowObfuscation; /** * Adds the contents of this class specification element to the given list. * @param keepSpecifications the class specifications to be extended. * @param markClasses specifies whether to mark the classes. * @param markConditionally specifies whether to mark the classes * and class members conditionally. */ public void appendTo(List keepSpecifications, boolean markClasses, boolean markConditionally) { // Get the referenced file set, or else this one. KeepSpecificationElement keepSpecificationElement = isReference() ? (KeepSpecificationElement)getCheckedRef(this.getClass(), this.getClass().getName()) : this; KeepClassSpecification keepClassSpecification = new KeepClassSpecification(markClasses, markConditionally, allowShrinking, allowOptimization, allowObfuscation, createClassSpecification(keepSpecificationElement)); // Add it to the list. keepSpecifications.add(keepClassSpecification); } // Ant task attributes. public void setAllowshrinking(boolean allowShrinking) { this.allowShrinking = allowShrinking; } public void setAllowoptimization(boolean allowOptimization) { this.allowOptimization = allowOptimization; } public void setAllowobfuscation(boolean allowObfuscation) { this.allowObfuscation = allowObfuscation; } } proguard4.8/src/proguard/ant/ProGuardTask.java0000664000175000017500000002230211752561066020200 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.ant; import org.apache.tools.ant.BuildException; import proguard.*; import proguard.classfile.util.ClassUtil; import java.io.*; import java.util.*; /** * This Task allows to configure and run ProGuard from Ant. * * @author Eric Lafortune */ public class ProGuardTask extends ConfigurationTask { // Ant task attributes. public void setConfiguration(File configurationFile) throws BuildException { try { // Get the combined system properties and Ant properties, for // replacing ProGuard-style properties ('<...>'). Properties properties = new Properties(); properties.putAll(getProject().getProperties()); ConfigurationParser parser = new ConfigurationParser(configurationFile, properties); try { parser.parse(configuration); } catch (ParseException ex) { throw new BuildException(ex.getMessage()); } finally { parser.close(); } } catch (IOException ex) { throw new BuildException(ex.getMessage()); } } /** * @deprecated Use the nested outjar element instead. */ public void setOutjar(String parameters) { throw new BuildException("Use the nested element instead of the 'outjar' attribute"); } public void setSkipnonpubliclibraryclasses(boolean skipNonPublicLibraryClasses) { configuration.skipNonPublicLibraryClasses = skipNonPublicLibraryClasses; } public void setSkipnonpubliclibraryclassmembers(boolean skipNonPublicLibraryClassMembers) { configuration.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembers; } public void setTarget(String target) { configuration.targetClassVersion = ClassUtil.internalClassVersion(target); if (configuration.targetClassVersion == 0) { throw new BuildException("Unsupported target '"+target+"'"); } } public void setForceprocessing(boolean forceProcessing) { configuration.lastModified = forceProcessing ? Long.MAX_VALUE : 0; } public void setPrintseeds(File printSeeds) { configuration.printSeeds = optionalFile(printSeeds); } public void setShrink(boolean shrink) { configuration.shrink = shrink; } public void setPrintusage(File printUsage) { configuration.printUsage = optionalFile(printUsage); } public void setOptimize(boolean optimize) { configuration.optimize = optimize; } public void setOptimizationpasses(int optimizationPasses) { configuration.optimizationPasses = optimizationPasses; } public void setAllowaccessmodification(boolean allowAccessModification) { configuration.allowAccessModification = allowAccessModification; } public void setMergeinterfacesaggressively(boolean mergeinterfacesaggressively) { configuration.mergeInterfacesAggressively = mergeinterfacesaggressively; } public void setObfuscate(boolean obfuscate) { configuration.obfuscate = obfuscate; } public void setPrintmapping(File printMapping) { configuration.printMapping = optionalFile(printMapping); } public void setApplymapping(File applyMapping) { configuration.applyMapping = resolvedFile(applyMapping); } public void setObfuscationdictionary(File obfuscationDictionary) { configuration.obfuscationDictionary = resolvedFile(obfuscationDictionary); } public void setClassobfuscationdictionary(File classObfuscationDictionary) { configuration.classObfuscationDictionary = resolvedFile(classObfuscationDictionary); } public void setPackageobfuscationdictionary(File packageObfuscationDictionary) { configuration.packageObfuscationDictionary = resolvedFile(packageObfuscationDictionary); } public void setOverloadaggressively(boolean overloadAggressively) { configuration.overloadAggressively = overloadAggressively; } public void setUseuniqueclassmembernames(boolean useUniqueClassMemberNames) { configuration.useUniqueClassMemberNames = useUniqueClassMemberNames; } public void setUsemixedcaseclassnames(boolean useMixedCaseClassNames) { configuration.useMixedCaseClassNames = useMixedCaseClassNames; } public void setFlattenpackagehierarchy(String flattenPackageHierarchy) { configuration.flattenPackageHierarchy = ClassUtil.internalClassName(flattenPackageHierarchy); } public void setRepackageclasses(String repackageClasses) { configuration.repackageClasses = ClassUtil.internalClassName(repackageClasses); } /** * @deprecated Use the repackageclasses attribute instead. */ public void setDefaultpackage(String defaultPackage) { configuration.repackageClasses = ClassUtil.internalClassName(defaultPackage); } public void setKeepparameternames(boolean keepParameterNames) { configuration.keepParameterNames = keepParameterNames; } public void setRenamesourcefileattribute(String newSourceFileAttribute) { configuration.newSourceFileAttribute = newSourceFileAttribute; } public void setPreverify(boolean preverify) { configuration.preverify = preverify; } public void setMicroedition(boolean microEdition) { configuration.microEdition = microEdition; } public void setVerbose(boolean verbose) { configuration.verbose = verbose; } public void setNote(boolean note) { if (note) { // Switch on notes if they were completely disabled. if (configuration.note != null && configuration.note.isEmpty()) { configuration.note = null; } } else { // Switch off notes. configuration.note = new ArrayList(); } } public void setWarn(boolean warn) { if (warn) { // Switch on warnings if they were completely disabled. if (configuration.warn != null && configuration.warn.isEmpty()) { configuration.warn = null; } } else { // Switch off warnings. configuration.warn = new ArrayList(); } } public void setIgnorewarnings(boolean ignoreWarnings) { configuration.ignoreWarnings = ignoreWarnings; } public void setPrintconfiguration(File printConfiguration) { configuration.printConfiguration = optionalFile(printConfiguration); } public void setDump(File dump) { configuration.dump = optionalFile(dump); } // Implementations for Task. public void execute() throws BuildException { try { ProGuard proGuard = new ProGuard(configuration); proGuard.execute(); } catch (IOException ex) { throw new BuildException(ex.getMessage()); } } // Small utility methods. /** * Returns a file that is properly resolved with respect to the project * directory, or null or empty if its name is actually a * boolean flag. */ private File optionalFile(File file) { String fileName = file.getName(); return fileName.equalsIgnoreCase("false") || fileName.equalsIgnoreCase("no") || fileName.equalsIgnoreCase("off") ? null : fileName.equalsIgnoreCase("true") || fileName.equalsIgnoreCase("yes") || fileName.equalsIgnoreCase("on") ? new File("") : resolvedFile(file); } /** * Returns a file that is properly resolved with respect to the project * directory. */ private File resolvedFile(File file) { return file.isAbsolute() ? file : new File(getProject().getBaseDir(), file.getName()); } } proguard4.8/src/proguard/UpToDateChecker.java0000644000175000017500000001625111736333525020025 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.io.File; /** * This class checks whether the output is up to date. * * @author Eric Lafortune */ public class UpToDateChecker { private final Configuration configuration; /** * Creates a new UpToDateChecker with the given configuration. */ public UpToDateChecker(Configuration configuration) { this.configuration = configuration; } /** * Returns whether the output is up to date, based on the modification times * of the input jars, output jars, and library jars (or directories). */ public boolean check() { try { ModificationTimeChecker checker = new ModificationTimeChecker(); checker.updateInputModificationTime(configuration.lastModified); ClassPath programJars = configuration.programJars; ClassPath libraryJars = configuration.libraryJars; // Check the dates of the program jars, if any. if (programJars != null) { for (int index = 0; index < programJars.size(); index++) { // Update the input and output modification times. ClassPathEntry classPathEntry = programJars.get(index); checker.updateModificationTime(classPathEntry.getFile(), classPathEntry.isOutput()); } } // Check the dates of the library jars, if any. if (libraryJars != null) { for (int index = 0; index < libraryJars.size(); index++) { // Update the input modification time. ClassPathEntry classPathEntry = libraryJars.get(index); checker.updateModificationTime(classPathEntry.getFile(), false); } } // Check the dates of the auxiliary input files. checker.updateInputModificationTime(configuration.applyMapping); checker.updateInputModificationTime(configuration.obfuscationDictionary); checker.updateInputModificationTime(configuration.classObfuscationDictionary); checker.updateInputModificationTime(configuration.packageObfuscationDictionary); // Check the dates of the auxiliary output files. checker.updateOutputModificationTime(configuration.printSeeds); checker.updateOutputModificationTime(configuration.printUsage); checker.updateOutputModificationTime(configuration.printMapping); checker.updateOutputModificationTime(configuration.printConfiguration); checker.updateOutputModificationTime(configuration.dump); } catch (IllegalStateException e) { // The output is outdated. return false; } System.out.println("The output seems up to date"); return true; } /** * This class maintains the modification times of input and output. * The methods throw an IllegalStateException if the output appears * outdated. */ private static class ModificationTimeChecker { private long inputModificationTime = Long.MIN_VALUE; private long outputModificationTime = Long.MAX_VALUE; /** * Updates the input modification time based on the given file or * directory (recursively). */ public void updateInputModificationTime(File file) { if (file != null) { updateModificationTime(file, false); } } /** * Updates the input modification time based on the given file or * directory (recursively). */ public void updateOutputModificationTime(File file) { if (file != null && file.getName().length() > 0) { updateModificationTime(file, true); } } /** * Updates the specified modification time based on the given file or * directory (recursively). */ public void updateModificationTime(File file, boolean isOutput) { // Is it a directory? if (file.isDirectory()) { // Ignore the directory's modification time; just recurse on // its files. File[] files = file.listFiles(); // Still, an empty output directory is probably a sign that it // is not up to date. if (files.length == 0 && isOutput) { updateOutputModificationTime(Long.MIN_VALUE); } for (int index = 0; index < files.length; index++) { updateModificationTime(files[index], isOutput); } } else { // Update with the file's modification time. updateModificationTime(file.lastModified(), isOutput); } } /** * Updates the specified modification time. */ public void updateModificationTime(long time, boolean isOutput) { if (isOutput) { updateOutputModificationTime(time); } else { updateInputModificationTime(time); } } /** * Updates the input modification time. */ public void updateInputModificationTime(long time) { if (inputModificationTime < time) { inputModificationTime = time; checkModificationTimes(); } } /** * Updates the output modification time. */ public void updateOutputModificationTime(long time) { if (outputModificationTime > time) { outputModificationTime = time; checkModificationTimes(); } } private void checkModificationTimes() { if (inputModificationTime > outputModificationTime) { throw new IllegalStateException("The output is outdated"); } } } } proguard4.8/src/proguard/obfuscate/0000775000175000017500000000000011760503005016145 5ustar ericericproguard4.8/src/proguard/obfuscate/AttributeUsageMarker.java0000644000175000017500000000427511736333525023123 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.Attribute; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor marks all attributes that it visits. * * @see AttributeShrinker * * @author Eric Lafortune */ public class AttributeUsageMarker extends SimplifiedVisitor implements AttributeVisitor { // A visitor info flag to indicate the attribute is being used. private static final Object USED = new Object(); // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) { markAsUsed(attribute); } // Small utility methods. /** * Marks the given VisitorAccepter as being used (or useful). * In this context, the VisitorAccepter will be an Attribute object. */ private static void markAsUsed(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(USED); } /** * Returns whether the given VisitorAccepter has been marked as being used. * In this context, the VisitorAccepter will be an Attribute object. */ static boolean isUsed(VisitorAccepter visitorAccepter) { return visitorAccepter.getVisitorInfo() == USED; } } proguard4.8/src/proguard/obfuscate/package.html0000644000175000017500000000012411736333525020434 0ustar ericeric This package contains classes to perform obfuscation of class files. proguard4.8/src/proguard/obfuscate/MapCleaner.java0000644000175000017500000000304711736333525021034 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; import java.util.Map; /** * This ClassVisitor clears a given map whenever it visits a class. * * @author Eric Lafortune */ public class MapCleaner extends SimplifiedVisitor implements ClassVisitor { private final Map map; /** * Creates a new MapCleaner. * @param map the map to be cleared. */ public MapCleaner(Map map) { this.map = map; } // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { map.clear(); } } proguard4.8/src/proguard/obfuscate/MappingProcessor.java0000644000175000017500000000614311736333525022320 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; /** * This interface specifies methods to process name mappings between original * classes and their obfuscated versions. The mappings are typically read * from a mapping file. * * @see MappingReader * * @author Eric Lafortune */ public interface MappingProcessor { /** * Processes the given class name mapping. * * @param className the original class name. * @param newClassName the new class name. * @return whether the processor is interested in receiving mappings of the * class members of this class. */ public boolean processClassMapping(String className, String newClassName); /** * Processes the given field name mapping. * * @param className the original class name. * @param fieldType the original external field type. * @param fieldName the original field name. * @param newFieldName the new field name. */ public void processFieldMapping(String className, String fieldType, String fieldName, String newFieldName); /** * Processes the given method name mapping. * * @param className the original class name. * @param firstLineNumber the first line number of the method, or 0 if it * is not known. * @param lastLineNumber the last line number of the method, or 0 if it * is not known. * @param methodReturnType the original external method return type. * @param methodName the original external method name. * @param methodArguments the original external method arguments. * @param newMethodName the new method name. */ public void processMethodMapping(String className, int firstLineNumber, int lastLineNumber, String methodReturnType, String methodName, String methodArguments, String newMethodName); } proguard4.8/src/proguard/obfuscate/ClassObfuscator.java0000644000175000017500000004642311736333525022127 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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 ClassVisitor 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.INTERNAL_PACKAGE_SEPARATOR; } // First append the package separator if necessary. if (repackageClasses != null && repackageClasses.length() > 0) { repackageClasses += ClassConstants.INTERNAL_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.INTERNAL_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); } } // 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.INTERNAL_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 null if it doesn't * have one yet. */ static String newClassName(Clazz clazz) { Object visitorInfo = clazz.getVisitorInfo(); return visitorInfo instanceof String ? (String)visitorInfo : null; } } proguard4.8/src/proguard/obfuscate/MappingKeeper.java0000644000175000017500000001555411736333525021562 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util.*; import proguard.util.ListUtil; /** * This MappingKeeper applies the mappings that it receives to its class pool, * so these mappings are ensured in a subsequent obfuscation step. * * @author Eric Lafortune */ public class MappingKeeper implements MappingProcessor { private final ClassPool classPool; private final WarningPrinter warningPrinter; // A field acting as a parameter. private Clazz clazz; /** * Creates a new MappingKeeper. * @param classPool the class pool in which class names and class * member names have to be mapped. * @param warningPrinter the optional warning printer to which warnings * can be printed. */ public MappingKeeper(ClassPool classPool, WarningPrinter warningPrinter) { this.classPool = classPool; this.warningPrinter = warningPrinter; } // Implementations for MappingProcessor. public boolean processClassMapping(String className, String newClassName) { // Find the class. String name = ClassUtil.internalClassName(className); clazz = classPool.getClass(name); if (clazz != null) { String newName = ClassUtil.internalClassName(newClassName); // Print out a warning if the mapping conflicts with a name that // was set before. if (warningPrinter != null) { String currentNewName = ClassObfuscator.newClassName(clazz); if (currentNewName != null && !currentNewName.equals(newName)) { warningPrinter.print(name, currentNewName, "Warning: " + className + " is not being kept as '" + ClassUtil.externalClassName(currentNewName) + "', but remapped to '" + newClassName + "'"); } } ClassObfuscator.setNewClassName(clazz, newName); // The class members have to be kept as well. return true; } return false; } public void processFieldMapping(String className, String fieldType, String fieldName, String newFieldName) { if (clazz != null) { // Find the field. String name = fieldName; String descriptor = ClassUtil.internalType(fieldType); Field field = clazz.findField(name, descriptor); if (field != null) { // Print out a warning if the mapping conflicts with a name that // was set before. if (warningPrinter != null) { String currentNewName = MemberObfuscator.newMemberName(field); if (currentNewName != null && !currentNewName.equals(newFieldName)) { warningPrinter.print(ClassUtil.internalClassName(className), "Warning: " + className + ": field '" + fieldType + " " + fieldName + "' is not being kept as '" + currentNewName + "', but remapped to '" + newFieldName + "'"); } } // Make sure the mapping name will be kept. MemberObfuscator.setFixedNewMemberName(field, newFieldName); } } } public void processMethodMapping(String className, int firstLineNumber, int lastLineNumber, String methodReturnType, String methodName, String methodArguments, String newMethodName) { if (clazz != null) { // Find the method. String descriptor = ClassUtil.internalMethodDescriptor(methodReturnType, ListUtil.commaSeparatedList(methodArguments)); Method method = clazz.findMethod(methodName, descriptor); if (method != null) { // Print out a warning if the mapping conflicts with a name that // was set before. if (warningPrinter != null) { String currentNewName = MemberObfuscator.newMemberName(method); if (currentNewName != null && !currentNewName.equals(newMethodName)) { warningPrinter.print(ClassUtil.internalClassName(className), "Warning: " + className + ": method '" + methodReturnType + " " + methodName + ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN + methodArguments + ClassConstants.EXTERNAL_METHOD_ARGUMENTS_CLOSE + "' is not being kept as '" + currentNewName + "', but remapped to '" + newMethodName + "'"); } } // Make sure the mapping name will be kept. MemberObfuscator.setFixedNewMemberName(method, newMethodName); } } } } proguard4.8/src/proguard/obfuscate/AttributeShrinker.java0000644000175000017500000000716511736333525022503 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; import java.util.Arrays; /** * This ClassVisitor removes attributes that are not marked as being used or * required. * * @see AttributeUsageMarker * * @author Eric Lafortune */ public class AttributeShrinker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, AttributeVisitor { // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Compact the array for class attributes. programClass.u2attributesCount = shrinkArray(programClass.attributes, programClass.u2attributesCount); // Compact the attributes in fields, methods, and class attributes, programClass.fieldsAccept(this); programClass.methodsAccept(this); programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { // Library classes are left unchanged. } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { // Compact the attributes array. programMember.u2attributesCount = shrinkArray(programMember.attributes, programMember.u2attributesCount); // Compact any attributes of the remaining attributes. programMember.attributesAccept(programClass, this); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Compact the attributes array. codeAttribute.u2attributesCount = shrinkArray(codeAttribute.attributes, codeAttribute.u2attributesCount); } // Small utility methods. /** * Removes all VisitorAccepter objects that are not marked as being used * from the given array. * @return the new number of VisitorAccepter objects. */ private static int shrinkArray(VisitorAccepter[] array, int length) { int counter = 0; // Shift the used objects together. for (int index = 0; index < length; index++) { if (AttributeUsageMarker.isUsed(array[index])) { array[counter++] = array[index]; } } // Clear the remaining array elements. Arrays.fill(array, counter, length, null); return counter; } } proguard4.8/src/proguard/obfuscate/NameFactory.java0000644000175000017500000000222611736333525021233 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; /** * This interfaces provides methods to generate unique sequences of names. * The names must be valid Java identifiers. * * @author Eric Lafortune */ public interface NameFactory { public void reset(); public String nextName(); } proguard4.8/src/proguard/obfuscate/SourceFileRenamer.java0000644000175000017500000000540611736333525022400 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.AttributeVisitor; import proguard.classfile.editor.ConstantPoolEditor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor changes the name stored in the source file attributes * and source dir attributes of the classes that it visits, if the * attributes are present. * * @author Eric Lafortune */ public class SourceFileRenamer extends SimplifiedVisitor implements ClassVisitor, AttributeVisitor { private final String newSourceFileAttribute; /** * Creates a new SourceFileRenamer. * @param newSourceFileAttribute the new string to be put in the source file * attributes. */ public SourceFileRenamer(String newSourceFileAttribute) { this.newSourceFileAttribute = newSourceFileAttribute; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Only visit the class attributes. programClass.attributesAccept(this); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { // Fix the source file attribute. sourceFileAttribute.u2sourceFileIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSourceFileAttribute); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { // Fix the source file attribute. sourceDirAttribute.u2sourceDirIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSourceFileAttribute); } } proguard4.8/src/proguard/obfuscate/MemberNameCleaner.java0000644000175000017500000000362111736333525022325 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.visitor.MemberVisitor; /** * This MemberVisitor clears the new names of the class members * that it visits. * * @see MemberObfuscator * * @author Eric Lafortune */ public class MemberNameCleaner implements MemberVisitor { // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { MemberObfuscator.setNewMemberName(programField, null); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { MemberObfuscator.setNewMemberName(programMethod, null); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { MemberObfuscator.setNewMemberName(libraryField, null); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { MemberObfuscator.setNewMemberName(libraryMethod, null); } } proguard4.8/src/proguard/obfuscate/NameFactoryResetter.java0000644000175000017500000000325211736333525022751 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.visitor.ClassVisitor; /** * This ClassVisitor resets a given name factory whenever it visits a class * file. * * @author Eric Lafortune */ public class NameFactoryResetter implements ClassVisitor { private final NameFactory nameFactory; /** * Creates a new NameFactoryResetter. * @param nameFactory the name factory to be reset. */ public NameFactoryResetter(NameFactory nameFactory) { this.nameFactory = nameFactory; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { nameFactory.reset(); } public void visitLibraryClass(LibraryClass libraryClass) { nameFactory.reset(); } } proguard4.8/src/proguard/obfuscate/NameMarker.java0000644000175000017500000001156011736333525021046 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util.SimplifiedVisitor; import proguard.classfile.constant.ClassConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.visitor.*; /** * This ClassVisitor and MemberVisitor * marks names of the classes and class members it visits. The marked names * will remain unchanged in the obfuscation step. * * @see ClassObfuscator * @see MemberObfuscator * * @author Eric Lafortune */ class NameMarker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, AttributeVisitor, InnerClassesInfoVisitor, ConstantVisitor { // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { keepClassName(programClass); // Make sure any outer class names are kept as well. programClass.attributesAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { keepClassName(libraryClass); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { keepFieldName(programClass, programField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { keepMethodName(programClass, programMethod); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { keepFieldName(libraryClass, libraryField); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { keepMethodName(libraryClass, libraryMethod); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Make sure the outer class names are kept as well. innerClassesAttribute.innerClassEntriesAccept(clazz, this); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { // Make sure the outer class name is kept as well. int innerClassIndex = innerClassesInfo.u2innerClassIndex; int outerClassIndex = innerClassesInfo.u2outerClassIndex; if (innerClassIndex != 0 && outerClassIndex != 0 && clazz.getClassName(innerClassIndex).equals(clazz.getName())) { clazz.constantPoolEntryAccept(outerClassIndex, this); } } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Make sure the outer class name is kept as well. classConstant.referencedClassAccept(this); } // Small utility method. /** * Ensures the name of the given class name will be kept. */ public void keepClassName(Clazz clazz) { ClassObfuscator.setNewClassName(clazz, clazz.getName()); } /** * Ensures the name of the given field name will be kept. */ private void keepFieldName(Clazz clazz, Field field) { MemberObfuscator.setFixedNewMemberName(field, field.getName(clazz)); } /** * Ensures the name of the given method name will be kept. */ private void keepMethodName(Clazz clazz, Method method) { String name = method.getName(clazz); if (!name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) && !name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { MemberObfuscator.setFixedNewMemberName(method, method.getName(clazz)); } } } proguard4.8/src/proguard/obfuscate/ParameterNameMarker.java0000664000175000017500000001123711736333525022712 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.AttributeVisitor; import proguard.classfile.util.*; /** * This AttributeVisitor trims and marks all local variable (type) table * attributes that it visits. It keeps parameter names and types and removes * the ordinary local variable names and types. * * @author Eric Lafortune */ public class ParameterNameMarker extends SimplifiedVisitor implements AttributeVisitor { private final AttributeVisitor attributeUsageMarker; /** * Constructs a new ParameterNameMarker. * @param attributeUsageMarker the marker that will be used to mark * attributes containing local variable info. */ public ParameterNameMarker(AttributeVisitor attributeUsageMarker) { this.attributeUsageMarker = attributeUsageMarker; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { if (!AttributeUsageMarker.isUsed(localVariableTableAttribute) && hasParameters(clazz, method)) { // Shift the entries that start at offset 0 to the front. int newIndex = 0; for (int index = 0; index < localVariableTableAttribute.u2localVariableTableLength; index++) { LocalVariableInfo localVariableInfo = localVariableTableAttribute.localVariableTable[index]; if (localVariableInfo.u2startPC == 0) { localVariableTableAttribute.localVariableTable[newIndex++] = localVariableInfo; } } // Trim the table. localVariableTableAttribute.u2localVariableTableLength = newIndex; // Mark the table if there are any entries. if (newIndex > 0) { attributeUsageMarker.visitLocalVariableTableAttribute(clazz, method, codeAttribute, localVariableTableAttribute); } } } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { if (!AttributeUsageMarker.isUsed(localVariableTypeTableAttribute) && hasParameters(clazz, method)) { // Shift the entries that start at offset 0 to the front. int newIndex = 0; for (int index = 0; index < localVariableTypeTableAttribute.u2localVariableTypeTableLength; index++) { LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeTableAttribute.localVariableTypeTable[index]; if (localVariableTypeInfo.u2startPC == 0) { localVariableTypeTableAttribute.localVariableTypeTable[newIndex++] = localVariableTypeInfo; } } // Trim the table. localVariableTypeTableAttribute.u2localVariableTypeTableLength = newIndex; // Mark the table if there are any entries. if (newIndex > 0) { attributeUsageMarker.visitLocalVariableTypeTableAttribute(clazz, method, codeAttribute, localVariableTypeTableAttribute); } } } // Small utility methods. private boolean hasParameters(Clazz clazz, Method method) { return method.getDescriptor(clazz).charAt(1) != ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE; } }proguard4.8/src/proguard/obfuscate/MemberObfuscator.java0000644000175000017500000001600711736333525022264 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util.*; import proguard.classfile.visitor.MemberVisitor; import java.util.*; /** * This MemberVisitor obfuscates all class members that it visits. * It uses names from the given name factory. At the same time, it avoids names * from the given descriptor map. *

* The class members must have been linked before applying this visitor. * * @see MethodLinker * * @author Eric Lafortune */ public class MemberObfuscator extends SimplifiedVisitor implements MemberVisitor { private final boolean allowAggressiveOverloading; private final NameFactory nameFactory; private final Map descriptorMap; /** * Creates a new MemberObfuscator. * @param allowAggressiveOverloading a flag that specifies whether class * members can be overloaded aggressively. * @param nameFactory the factory that can produce * obfuscated member names. * @param descriptorMap the map of descriptors to * [new name - old name] maps. */ public MemberObfuscator(boolean allowAggressiveOverloading, NameFactory nameFactory, Map descriptorMap) { this.allowAggressiveOverloading = allowAggressiveOverloading; this.nameFactory = nameFactory; this.descriptorMap = descriptorMap; } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) { // Special cases: and are always kept unchanged. // We can ignore them here. String name = member.getName(clazz); if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) || name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { return; } // Get the member's descriptor. String descriptor = member.getDescriptor(clazz); // Check whether we're allowed to do aggressive overloading if (!allowAggressiveOverloading) { // Trim the return argument from the descriptor if not. // Works for fields and methods alike. descriptor = descriptor.substring(0, descriptor.indexOf(')')+1); } // Get the name map, creating a new one if necessary. Map nameMap = retrieveNameMap(descriptorMap, descriptor); // Get the member's new name. String newName = newMemberName(member); // Assign a new one, if necessary. if (newName == null) { // Find an acceptable new name. nameFactory.reset(); do { newName = nameFactory.nextName(); } while (nameMap.containsKey(newName)); // Remember not to use the new name again in this name space. nameMap.put(newName, name); // Assign the new name. setNewMemberName(member, newName); } } // Small utility methods. /** * Gets the name map, based on the given map and a given descriptor. * A new empty map is created if necessary. * @param descriptorMap the map of descriptors to [new name - old name] maps. * @param descriptor the class member descriptor. * @return the corresponding name map. */ static Map retrieveNameMap(Map descriptorMap, String descriptor) { // See if we can find the nested map with this descriptor key. Map nameMap = (Map)descriptorMap.get(descriptor); // Create a new one if not. if (nameMap == null) { nameMap = new HashMap(); descriptorMap.put(descriptor, nameMap); } return nameMap; } /** * Assigns a fixed new name to the given class member. * @param member the class member. * @param name the new name. */ static void setFixedNewMemberName(Member member, String name) { VisitorAccepter lastVisitorAccepter = MethodLinker.lastVisitorAccepter(member); if (!(lastVisitorAccepter instanceof LibraryMember) && !(lastVisitorAccepter instanceof MyFixedName)) { lastVisitorAccepter.setVisitorInfo(new MyFixedName(name)); } else { lastVisitorAccepter.setVisitorInfo(name); } } /** * Assigns a new name to the given class member. * @param member the class member. * @param name the new name. */ static void setNewMemberName(Member member, String name) { MethodLinker.lastVisitorAccepter(member).setVisitorInfo(name); } /** * Returns whether the new name of the given class member is fixed. * @param member the class member. * @return whether its new name is fixed. */ static boolean hasFixedNewMemberName(Member member) { VisitorAccepter lastVisitorAccepter = MethodLinker.lastVisitorAccepter(member); return lastVisitorAccepter instanceof LibraryMember || lastVisitorAccepter instanceof MyFixedName; } /** * Retrieves the new name of the given class member. * @param member the class member. * @return the class member's new name, or null if it doesn't * have one yet. */ static String newMemberName(Member member) { return (String)MethodLinker.lastVisitorAccepter(member).getVisitorInfo(); } /** * This VisitorAccepter can be used to wrap a name string, to indicate that * the name is fixed. */ private static class MyFixedName implements VisitorAccepter { private String newName; public MyFixedName(String newName) { this.newName = newName; } // Implementations for VisitorAccepter. public Object getVisitorInfo() { return newName; } public void setVisitorInfo(Object visitorInfo) { newName = (String)visitorInfo; } } } proguard4.8/src/proguard/obfuscate/MemberNameConflictFixer.java0000644000175000017500000001506711736333525023522 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util.*; import proguard.classfile.visitor.MemberVisitor; import java.util.Map; /** * This MemberInfoVisitor solves obfuscation naming conflicts in all class * members that it visits. It avoids names from the given descriptor map, * delegating to the given obfuscator in order to get a new name if necessary. * * @author Eric Lafortune */ public class MemberNameConflictFixer implements MemberVisitor { private final boolean allowAggressiveOverloading; private final Map descriptorMap; private final WarningPrinter warningPrinter; private final MemberObfuscator memberObfuscator; /** * Creates a new MemberNameConflictFixer. * @param allowAggressiveOverloading a flag that specifies whether class * members can be overloaded aggressively. * @param descriptorMap the map of descriptors to * [new name - old name] maps. * @param warningPrinter an optional warning printer to which * warnings about conflicting name * mappings can be printed. * @param memberObfuscator the obfuscator that can assign new * names to members with conflicting * names. */ public MemberNameConflictFixer(boolean allowAggressiveOverloading, Map descriptorMap, WarningPrinter warningPrinter, MemberObfuscator memberObfuscator) { this.allowAggressiveOverloading = allowAggressiveOverloading; this.descriptorMap = descriptorMap; this.warningPrinter = warningPrinter; this.memberObfuscator = memberObfuscator; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { visitMember(programClass, programField, true); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Special cases: and are always kept unchanged. // We can ignore them here. String name = programMethod.getName(programClass); if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) || name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { return; } visitMember(programClass, programMethod, false); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) {} public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {} /** * Obfuscates the given class member. * @param clazz the class of the given member. * @param member the class member to be obfuscated. * @param isField specifies whether the class member is a field. */ private void visitMember(Clazz clazz, Member member, boolean isField) { // Get the member's name and descriptor. String name = member.getName(clazz); String descriptor = member.getDescriptor(clazz); // Check whether we're allowed to overload aggressively. if (!allowAggressiveOverloading) { // Trim the return argument from the descriptor if not. // Works for fields and methods alike. descriptor = descriptor.substring(0, descriptor.indexOf(')')+1); } // Get the name map. Map nameMap = MemberObfuscator.retrieveNameMap(descriptorMap, descriptor); // Get the member's new name. String newName = MemberObfuscator.newMemberName(member); // Get the expected old name for this new name. String previousName = (String)nameMap.get(newName); if (previousName != null && !name.equals(previousName)) { // There's a conflict! A member (with a given old name) in a // first namespace has received the same new name as this // member (with a different old name) in a second name space, // and now these two have to live together in this name space. if (MemberObfuscator.hasFixedNewMemberName(member) && warningPrinter != null) { descriptor = member.getDescriptor(clazz); warningPrinter.print(clazz.getName(), "Warning: " + ClassUtil.externalClassName(clazz.getName()) + (isField ? ": field '" + ClassUtil.externalFullFieldDescription(0, name, descriptor) : ": method '" + ClassUtil.externalFullMethodDescription(clazz.getName(), 0, name, descriptor)) + "' can't be mapped to '" + newName + "' because it would conflict with " + (isField ? "field '" : "method '" ) + previousName + "', which is already being mapped to '" + newName + "'"); } // Clear the conflicting name. MemberObfuscator.setNewMemberName(member, null); // Assign a new name. member.accept(clazz, memberObfuscator); } } } proguard4.8/src/proguard/obfuscate/MappingPrinter.java0000644000175000017500000001063111736333525021761 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util.*; import proguard.classfile.visitor.*; import java.io.PrintStream; /** * This ClassVisitor prints out the renamed classes and class members with * their old names and new names. * * @see ClassRenamer * * @author Eric Lafortune */ public class MappingPrinter extends SimplifiedVisitor implements ClassVisitor, MemberVisitor { private final PrintStream ps; /** * Creates a new MappingPrinter that prints to System.out. */ public MappingPrinter() { this(System.out); } /** * Creates a new MappingPrinter that prints to the given stream. * @param printStream the stream to which to print */ public MappingPrinter(PrintStream printStream) { this.ps = printStream; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { String name = programClass.getName(); String newName = ClassObfuscator.newClassName(programClass); ps.println(ClassUtil.externalClassName(name) + " -> " + ClassUtil.externalClassName(newName) + ":"); // Print out the class members. programClass.fieldsAccept(this); programClass.methodsAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { String newName = MemberObfuscator.newMemberName(programField); if (newName != null) { ps.println(" " + //lineNumberRange(programClass, programField) + ClassUtil.externalFullFieldDescription( 0, programField.getName(programClass), programField.getDescriptor(programClass)) + " -> " + newName); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Special cases: and are always kept unchanged. // We can ignore them here. String name = programMethod.getName(programClass); if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) || name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { return; } String newName = MemberObfuscator.newMemberName(programMethod); if (newName != null) { ps.println(" " + lineNumberRange(programClass, programMethod) + ClassUtil.externalFullMethodDescription( programClass.getName(), 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) + " -> " + newName); } } // Small utility methods. /** * Returns the line number range of the given class member, followed by a * colon, or just an empty String if no range is available. */ private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember) { String range = programMember.getLineNumberRange(programClass); return range != null ? (range + ":") : ""; } } proguard4.8/src/proguard/obfuscate/SimpleNameFactory.java0000644000175000017500000001054611736333525022411 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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 java.util.*; /** * This NameFactory generates unique short names, using mixed-case * characters or lower-case characters only. * * @author Eric Lafortune */ public class SimpleNameFactory implements NameFactory { private static final int CHARACTER_COUNT = 26; private static final List cachedMixedCaseNames = new ArrayList(); private static final List cachedLowerCaseNames = new ArrayList(); private final boolean generateMixedCaseNames; private int index = 0; /** * Creates a new SimpleNameFactory that generates mixed-case names. */ public SimpleNameFactory() { this(true); } /** * Creates a new SimpleNameFactory. * @param generateMixedCaseNames a flag to indicate whether the generated * names will be mixed-case, or lower-case only. */ public SimpleNameFactory(boolean generateMixedCaseNames) { this.generateMixedCaseNames = generateMixedCaseNames; } // Implementations for NameFactory. public void reset() { index = 0; } public String nextName() { return name(index++); } /** * Returns the name at the given index. */ private String name(int index) { // Which cache do we need? List cachedNames = generateMixedCaseNames ? cachedMixedCaseNames : cachedLowerCaseNames; // Do we have the name in the cache? if (index < cachedNames.size()) { return (String)cachedNames.get(index); } // Create a new name and cache it. String name = newName(index); cachedNames.add(index, name); return name; } /** * Creates and returns the name at the given index. */ private String newName(int index) { // If we're allowed to generate mixed-case names, we can use twice as // many characters. int totalCharacterCount = generateMixedCaseNames ? 2 * CHARACTER_COUNT : CHARACTER_COUNT; int baseIndex = index / totalCharacterCount; int offset = index % totalCharacterCount; char newChar = charAt(offset); String newName = baseIndex == 0 ? new String(new char[] { newChar }) : (name(baseIndex-1) + newChar); return newName; } /** * Returns the character with the given index, between 0 and the number of * acceptable characters. */ private char charAt(int index) { return (char)((index < CHARACTER_COUNT ? 'a' - 0 : 'A' - CHARACTER_COUNT) + index); } public static void main(String[] args) { System.out.println("Some mixed-case names:"); printNameSamples(new SimpleNameFactory(true), 60); System.out.println("Some lower-case names:"); printNameSamples(new SimpleNameFactory(false), 60); System.out.println("Some more mixed-case names:"); printNameSamples(new SimpleNameFactory(true), 80); System.out.println("Some more lower-case names:"); printNameSamples(new SimpleNameFactory(false), 80); } private static void printNameSamples(SimpleNameFactory factory, int count) { for (int counter = 0; counter < count; counter++) { System.out.println(" ["+factory.nextName()+"]"); } } } proguard4.8/src/proguard/obfuscate/MemberNameCollector.java0000644000175000017500000000746111736333525022710 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; import java.util.Map; /** * This MemberVisitor collects all new (obfuscation) names of the members * that it visits. * * @see MemberObfuscator * * @author Eric Lafortune */ public class MemberNameCollector extends SimplifiedVisitor implements MemberVisitor { private final boolean allowAggressiveOverloading; private final Map descriptorMap; /** * Creates a new MemberNameCollector. * @param allowAggressiveOverloading a flag that specifies whether class * members can be overloaded aggressively. * @param descriptorMap the map of descriptors to * [new name - old name] maps. */ public MemberNameCollector(boolean allowAggressiveOverloading, Map descriptorMap) { this.allowAggressiveOverloading = allowAggressiveOverloading; this.descriptorMap = descriptorMap; } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) { // Special cases: and are always kept unchanged. // We can ignore them here. String name = member.getName(clazz); if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) || name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { return; } // Get the member's new name. String newName = MemberObfuscator.newMemberName(member); // Remember it, if it has already been set. if (newName != null) { // Get the member's descriptor. String descriptor = member.getDescriptor(clazz); // Check whether we're allowed to do aggressive overloading if (!allowAggressiveOverloading) { // Trim the return argument from the descriptor if not. // Works for fields and methods alike. descriptor = descriptor.substring(0, descriptor.indexOf(')')+1); } // Put the [descriptor - new name] in the map, // creating a new [new name - old name] map if necessary. Map nameMap = MemberObfuscator.retrieveNameMap(descriptorMap, descriptor); // Isn't there another original name for this new name, or should // this original name get priority? String otherName = (String)nameMap.get(newName); if (otherName == null || MemberObfuscator.hasFixedNewMemberName(member) || name.compareTo(otherName) < 0) { // Remember not to use the new name again in this name space. nameMap.put(newName, name); } } } } proguard4.8/src/proguard/obfuscate/MappingReader.java0000644000175000017500000001560611736333525021547 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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 java.io.*; /** * This class can parse mapping files and invoke a processor for each of the * mapping entries. * * @author Eric Lafortune */ public class MappingReader { private final File mappingFile; public MappingReader(File mappingFile) { this.mappingFile = mappingFile; } /** * Reads the mapping file, presenting all of the encountered mapping entries * to the given processor. */ public void pump(MappingProcessor mappingProcessor) throws IOException { LineNumberReader reader = new LineNumberReader( new BufferedReader( new FileReader(mappingFile))); try { String className = null; // Read the subsequent class mappings and class member mappings. while (true) { String line = reader.readLine(); if (line == null) { break; } line = line.trim(); // The distinction between a class mapping and a class // member mapping is the initial whitespace. if (line.endsWith(":")) { // Process the class mapping and remember the class's // old name. className = processClassMapping(line, mappingProcessor); } else if (className != null) { // Process the class member mapping, in the context of the // current old class name. processClassMemberMapping(className, line, mappingProcessor); } } } catch (IOException ex) { throw new IOException("Can't process mapping file (" + ex.getMessage() + ")"); } finally { try { reader.close(); } catch (IOException ex) { // This shouldn't happen. } } } /** * Parses the given line with a class mapping and processes the * results with the given mapping processor. Returns the old class name, * or null if any subsequent class member lines can be ignored. */ private String processClassMapping(String line, MappingProcessor mappingProcessor) { // See if we can parse "___ -> ___:", containing the original // class name and the new class name. int arrowIndex = line.indexOf("->"); if (arrowIndex < 0) { return null; } int colonIndex = line.indexOf(':', arrowIndex + 2); if (colonIndex < 0) { return null; } // Extract the elements. String className = line.substring(0, arrowIndex).trim(); String newClassName = line.substring(arrowIndex + 2, colonIndex).trim(); // Process this class name mapping. boolean interested = mappingProcessor.processClassMapping(className, newClassName); return interested ? className : null; } /** * Parses the given line with a class member mapping and processes the * results with the given mapping processor. */ private void processClassMemberMapping(String className, String line, MappingProcessor mappingProcessor) { // See if we can parse "___:___:___ ___(___) -> ___", // containing the optional line numbers, the return type, the original // field/method name, optional arguments, and the new field/method name. int colonIndex1 = line.indexOf(':'); int colonIndex2 = colonIndex1 < 0 ? -1 : line.indexOf(':', colonIndex1 + 1); int spaceIndex = line.indexOf(' ', colonIndex2 + 2); int argumentIndex1 = line.indexOf('(', spaceIndex + 1); int argumentIndex2 = argumentIndex1 < 0 ? -1 : line.indexOf(')', argumentIndex1 + 1); int arrowIndex = line.indexOf("->", Math.max(spaceIndex, argumentIndex2) + 1); if (spaceIndex < 0 || arrowIndex < 0) { return; } // Extract the elements. String type = line.substring(colonIndex2 + 1, spaceIndex).trim(); String name = line.substring(spaceIndex + 1, argumentIndex1 >= 0 ? argumentIndex1 : arrowIndex).trim(); String newName = line.substring(arrowIndex + 2).trim(); // Process this class member mapping. if (type.length() > 0 && name.length() > 0 && newName.length() > 0) { // Is it a field or a method? if (argumentIndex2 < 0) { mappingProcessor.processFieldMapping(className, type, name, newName); } else { int firstLineNumber = 0; int lastLineNumber = 0; if (colonIndex2 > 0) { firstLineNumber = Integer.parseInt(line.substring(0, colonIndex1).trim()); lastLineNumber = Integer.parseInt(line.substring(colonIndex1 + 1, colonIndex2).trim()); } String arguments = line.substring(argumentIndex1 + 1, argumentIndex2).trim(); mappingProcessor.processMethodMapping(className, firstLineNumber, lastLineNumber, type, name, arguments, newName); } } } } proguard4.8/src/proguard/obfuscate/MultiMappingProcessor.java0000644000175000017500000000705011736333525023331 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; /** * This MappingKeeper delegates all method calls to each MappingProcessor * in a given list. * * @author Eric Lafortune */ public class MultiMappingProcessor implements MappingProcessor { private final MappingProcessor[] mappingProcessors; /** * Creates a new MultiMappingProcessor. * @param mappingProcessors the mapping processors to which method calls * will be delegated. */ public MultiMappingProcessor(MappingProcessor[] mappingProcessors) { this.mappingProcessors = mappingProcessors; } // Implementations for MappingProcessor. public boolean processClassMapping(String className, String newClassName) { boolean result = false; for (int index = 0; index < mappingProcessors.length; index++) { result |= mappingProcessors[index].processClassMapping(className, newClassName); } return result; } public void processFieldMapping(String className, String fieldType, String fieldName, String newFieldName) { for (int index = 0; index < mappingProcessors.length; index++) { mappingProcessors[index].processFieldMapping(className, fieldType, fieldName, newFieldName); } } public void processMethodMapping(String className, int firstLineNumber, int lastLineNumber, String methodReturnType, String methodName, String methodArguments, String newMethodName) { for (int index = 0; index < mappingProcessors.length; index++) { mappingProcessors[index].processMethodMapping(className, firstLineNumber, lastLineNumber, methodReturnType, methodName, methodArguments, newMethodName); } } } proguard4.8/src/proguard/obfuscate/NumericNameFactory.java0000644000175000017500000000247011736333525022557 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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 java.util.*; /** * This NameFactory generates unique numeric names, starting at * "1". * * @author Eric Lafortune */ public class NumericNameFactory implements NameFactory { private int index; // Implementations for NameFactory. public void reset() { index = 0; } public String nextName() { return Integer.toString(++index); } }proguard4.8/src/proguard/obfuscate/DictionaryNameFactory.java0000644000175000017500000001312411736333525023260 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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 java.io.*; import java.util.*; /** * This NameFactory generates names that are read from a * specified input file. * Comments (everything starting with '#' on a single line) are ignored. * * @author Eric Lafortune */ public class DictionaryNameFactory implements NameFactory { private static final char COMMENT_CHARACTER = '#'; private final List names; private final NameFactory nameFactory; private int index = 0; /** * Creates a new DictionaryNameFactory. * @param file the file from which the names can be read. * @param nameFactory the name factory from which names will be retrieved * if the list of read names has been exhausted. */ public DictionaryNameFactory(File file, NameFactory nameFactory) throws IOException { this.names = new ArrayList(); this.nameFactory = nameFactory; Reader reader = new FileReader(file); try { StringBuffer buffer = new StringBuffer(); while (true) { // Read the next character. int c = reader.read(); // Is it a valid identifier character? if (c != -1 && (buffer.length() == 0 ? Character.isJavaIdentifierStart((char)c) : Character.isJavaIdentifierPart((char)c))) { // Append it to the current identifier. buffer.append((char)c); } else { // Did we collect a new identifier? if (buffer.length() > 0) { // Add the completed name to the list of names, if it's // not in it yet. String name = buffer.toString(); if (!names.contains(name)) { names.add(name); } // Clear the buffer. buffer.setLength(0); } // Is this the beginning of a comment line? if (c == COMMENT_CHARACTER) { // Skip all characters till the end of the line. do { c = reader.read(); } while (c != -1 && c != '\n' && c != '\r'); } // Is this the end of the file? if (c == -1) { // Just return. return; } } } } finally { reader.close(); } } /** * Creates a new DictionaryNameFactory. * @param dictionaryNameFactory the dictionary name factory whose dictionary * will be used. * @param nameFactory the name factory from which names will be * retrieved if the list of read names has been * exhausted. */ public DictionaryNameFactory(DictionaryNameFactory dictionaryNameFactory, NameFactory nameFactory) { this.names = dictionaryNameFactory.names; this.nameFactory = nameFactory; } // Implementations for NameFactory. public void reset() { index = 0; nameFactory.reset(); } public String nextName() { String name; // Do we still have names? if (index < names.size()) { // Return the next name. name = (String)names.get(index++); } else { // Return the next different name from the other name factory. do { name = nameFactory.nextName(); } while (names.contains(name)); } return name; } public static void main(String[] args) { try { DictionaryNameFactory factory = new DictionaryNameFactory(new File(args[0]), new SimpleNameFactory()); for (int counter = 0; counter < 50; counter++) { System.out.println("["+factory.nextName()+"]"); } } catch (IOException ex) { ex.printStackTrace(); } } } proguard4.8/src/proguard/obfuscate/SpecialNameFactory.java0000644000175000017500000000430411736333525022533 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; /** * This NameFactory generates names that are special, by appending * a suffix. * * @author Eric Lafortune */ public class SpecialNameFactory implements NameFactory { private static final char SPECIAL_SUFFIX = '_'; private final NameFactory nameFactory; /** * Creates a new SpecialNameFactory. * @param nameFactory the name factory from which original names will be * retrieved. */ public SpecialNameFactory(NameFactory nameFactory) { this.nameFactory = nameFactory; } // Implementations for NameFactory. public void reset() { nameFactory.reset(); } public String nextName() { return nameFactory.nextName() + SPECIAL_SUFFIX; } // Small utility methods. /** * Returns whether the given name is special. */ static boolean isSpecialName(String name) { return name != null && name.charAt(name.length()-1) == SPECIAL_SUFFIX; } public static void main(String[] args) { SpecialNameFactory factory = new SpecialNameFactory(new SimpleNameFactory()); for (int counter = 0; counter < 50; counter++) { System.out.println("["+factory.nextName()+"]"); } } } proguard4.8/src/proguard/obfuscate/MemberNameFilter.java0000664000175000017500000000654411736333525022212 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.visitor.MemberVisitor; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when the visited member has a new name. * Constructors are judged based on the class name. * * @see ClassObfuscator * @see MemberObfuscator * * @author Eric Lafortune */ public class MemberNameFilter implements MemberVisitor { private final MemberVisitor memberVisitor; /** * Creates a new MemberSpecialNameFilter. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public MemberNameFilter(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (hasName(programField)) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (hasName(programClass, programMethod)) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (hasName(libraryField)) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (hasName(libraryClass, libraryMethod)) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } // Small utility methods. /** * Returns whether the given class has a new name. */ private boolean hasName(Clazz clazz) { return ClassObfuscator.newClassName(clazz) != null; } /** * Returns whether the given method has a new name. */ private boolean hasName(Clazz clazz, Method method) { return hasName(method) || (hasName(clazz) && method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)); } /** * Returns whether the given class member has a new name. */ private boolean hasName(Member member) { return MemberObfuscator.newMemberName(member) != null; } }proguard4.8/src/proguard/obfuscate/ClassRenamer.java0000644000175000017500000000672311736333525021410 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.constant.ClassConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.ConstantPoolEditor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor renames the class names and class member * names of the classes it visits, using names previously determined by the * obfuscator. * * @see ClassObfuscator * @see MemberObfuscator * * @author Eric Lafortune */ public class ClassRenamer extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, ConstantVisitor { // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Rename this class. programClass.thisClassConstantAccept(this); // Rename the class members. programClass.fieldsAccept(this); programClass.methodsAccept(this); } public void visitLibraryClass(LibraryClass libraryClass) { libraryClass.thisClassName = ClassObfuscator.newClassName(libraryClass); // Rename the class members. libraryClass.fieldsAccept(this); libraryClass.methodsAccept(this); } // Implementations for MemberVisitor. public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { // Has the class member name changed? String name = programMember.getName(programClass); String newName = MemberObfuscator.newMemberName(programMember); if (newName != null && !newName.equals(name)) { programMember.u2nameIndex = new ConstantPoolEditor(programClass).addUtf8Constant(newName); } } public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) { String newName = MemberObfuscator.newMemberName(libraryMember); if (newName != null) { libraryMember.name = newName; } } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Update the Class entry if required. String newName = ClassObfuscator.newClassName(clazz); if (newName != null) { // Refer to a new Utf8 entry. classConstant.u2nameIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newName); } } } proguard4.8/src/proguard/obfuscate/MemberSpecialNameFilter.java0000644000175000017500000000603111736333525023500 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.visitor.MemberVisitor; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when the visited member has a * special new name. A special name is a name that might have been produced by * a SpecialNameFactory. * * @see MemberObfuscator * @see SpecialNameFactory * * @author Eric Lafortune */ public class MemberSpecialNameFilter implements MemberVisitor { private final MemberVisitor memberVisitor; /** * Creates a new MemberSpecialNameFilter. * @param memberVisitor the MemberVisitor to which * visits will be delegated. */ public MemberSpecialNameFilter(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (hasSpecialName(programField)) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (hasSpecialName(programMethod)) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (hasSpecialName(libraryField)) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (hasSpecialName(libraryMethod)) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } // Small utility methods. /** * Returns whether the given class member has a special new name. * @param member the class member. */ private static boolean hasSpecialName(Member member) { return SpecialNameFactory.isSpecialName(MemberObfuscator.newMemberName(member)); } } proguard4.8/src/proguard/obfuscate/Obfuscator.java0000664000175000017500000004762411736333525021147 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.*; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.visitor.AllConstantVisitor; import proguard.classfile.editor.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.util.*; import java.io.*; import java.util.*; /** * This class can perform obfuscation of class pools according to a given * specification. * * @author Eric Lafortune */ public class Obfuscator { private final Configuration configuration; /** * Creates a new Obfuscator. */ public Obfuscator(Configuration configuration) { this.configuration = configuration; } /** * Performs obfuscation of the given program class pool. */ public void execute(ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { // Check if we have at least some keep commands. if (configuration.keep == null && configuration.applyMapping == null && configuration.printMapping == null) { throw new IOException("You have to specify '-keep' options for the obfuscation step."); } // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); libraryClassPool.classesAccept(new ClassCleaner()); // If the class member names have to correspond globally, // link all class members in all classes, otherwise // link all non-private methods in all class hierarchies. ClassVisitor memberInfoLinker = configuration.useUniqueClassMemberNames ? (ClassVisitor)new AllMemberVisitor(new MethodLinker()) : (ClassVisitor)new BottomClassFilter(new MethodLinker()); programClassPool.classesAccept(memberInfoLinker); libraryClassPool.classesAccept(memberInfoLinker); // Create a visitor for marking the seeds. NameMarker nameMarker = new NameMarker(); ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, nameMarker, nameMarker, false, false, true); // Mark the seeds. programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); // All library classes and library class members keep their names. libraryClassPool.classesAccept(nameMarker); libraryClassPool.classesAccept(new AllMemberVisitor(nameMarker)); // Mark attributes that have to be kept. AttributeVisitor attributeUsageMarker = new NonEmptyAttributeFilter( new AttributeUsageMarker()); AttributeVisitor optionalAttributeUsageMarker = configuration.keepAttributes == null ? null : new AttributeNameFilter(new ListParser(new NameParser()).parse(configuration.keepAttributes), attributeUsageMarker); programClassPool.classesAccept( new AllAttributeVisitor(true, new RequiredAttributeFilter(attributeUsageMarker, optionalAttributeUsageMarker))); // Keep parameter names and types if specified. if (configuration.keepParameterNames) { programClassPool.classesAccept( new AllMethodVisitor( new MemberNameFilter( new AllAttributeVisitor(true, new ParameterNameMarker(attributeUsageMarker))))); } // Remove the attributes that can be discarded. Note that the attributes // may only be discarded after the seeds have been marked, since the // configuration may rely on annotations. programClassPool.classesAccept(new AttributeShrinker()); // Apply the mapping, if one has been specified. The mapping can // override the names of library classes and of library class members. if (configuration.applyMapping != null) { WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); MappingReader reader = new MappingReader(configuration.applyMapping); MappingProcessor keeper = new MultiMappingProcessor(new MappingProcessor[] { new MappingKeeper(programClassPool, warningPrinter), new MappingKeeper(libraryClassPool, null), }); reader.pump(keeper); // Print out a summary of the warnings if necessary. int mappingWarningCount = warningPrinter.getWarningCount(); if (mappingWarningCount > 0) { System.err.println("Warning: there were " + mappingWarningCount + " kept classes and class members that were remapped anyway."); System.err.println(" You should adapt your configuration or edit the mapping file."); if (!configuration.ignoreWarnings) { System.err.println(" If you are sure this remapping won't hurt,"); System.err.println(" you could try your luck using the '-ignorewarnings' option."); throw new IOException("Please correct the above warnings first."); } } } // Come up with new names for all classes. DictionaryNameFactory classNameFactory = configuration.classObfuscationDictionary != null ? new DictionaryNameFactory(configuration.classObfuscationDictionary, null) : null; DictionaryNameFactory packageNameFactory = configuration.packageObfuscationDictionary != null ? new DictionaryNameFactory(configuration.packageObfuscationDictionary, null) : null; programClassPool.classesAccept( new ClassObfuscator(programClassPool, classNameFactory, packageNameFactory, configuration.useMixedCaseClassNames, configuration.keepPackageNames, configuration.flattenPackageHierarchy, configuration.repackageClasses, configuration.allowAccessModification)); // Come up with new names for all class members. NameFactory nameFactory = new SimpleNameFactory(); if (configuration.obfuscationDictionary != null) { nameFactory = new DictionaryNameFactory(configuration.obfuscationDictionary, nameFactory); } WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); // Maintain a map of names to avoid [descriptor - new name - old name]. Map descriptorMap = new HashMap(); // Do the class member names have to be globally unique? if (configuration.useUniqueClassMemberNames) { // Collect all member names in all classes. programClassPool.classesAccept( new AllMemberVisitor( new MemberNameCollector(configuration.overloadAggressively, descriptorMap))); // Assign new names to all members in all classes. programClassPool.classesAccept( new AllMemberVisitor( new MemberObfuscator(configuration.overloadAggressively, nameFactory, descriptorMap))); } else { // Come up with new names for all non-private class members. programClassPool.classesAccept( new MultiClassVisitor(new ClassVisitor[] { // Collect all private member names in this class and down // the hierarchy. new ClassHierarchyTraveler(true, false, false, true, new AllMemberVisitor( new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberNameCollector(configuration.overloadAggressively, descriptorMap)))), // Collect all non-private member names anywhere in the hierarchy. new ClassHierarchyTraveler(true, true, true, true, new AllMemberVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameCollector(configuration.overloadAggressively, descriptorMap)))), // Assign new names to all non-private members in this class. new AllMemberVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberObfuscator(configuration.overloadAggressively, nameFactory, descriptorMap))), // Clear the collected names. new MapCleaner(descriptorMap) })); // Come up with new names for all private class members. programClassPool.classesAccept( new MultiClassVisitor(new ClassVisitor[] { // Collect all member names in this class. new AllMemberVisitor( new MemberNameCollector(configuration.overloadAggressively, descriptorMap)), // Collect all non-private member names higher up the hierarchy. new ClassHierarchyTraveler(false, true, true, false, new AllMemberVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameCollector(configuration.overloadAggressively, descriptorMap)))), // Collect all member names from interfaces of abstract // classes down the hierarchy. // Due to an error in the JLS/JVMS, virtual invocations // may end up at a private method otherwise (Sun/Oracle // bugs #6691741 and #6684387, ProGuard bug #3471941, // and ProGuard test #1180). new ClassHierarchyTraveler(false, false, false, true, new ClassAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0, new ClassHierarchyTraveler(false, false, true, false, new AllMemberVisitor( new MemberNameCollector(configuration.overloadAggressively, descriptorMap))))), // Assign new names to all private members in this class. new AllMemberVisitor( new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberObfuscator(configuration.overloadAggressively, nameFactory, descriptorMap))), // Clear the collected names. new MapCleaner(descriptorMap) })); } // Some class members may have ended up with conflicting names. // Come up with new, globally unique names for them. NameFactory specialNameFactory = new SpecialNameFactory(new SimpleNameFactory()); // Collect a map of special names to avoid // [descriptor - new name - old name]. Map specialDescriptorMap = new HashMap(); programClassPool.classesAccept( new AllMemberVisitor( new MemberSpecialNameFilter( new MemberNameCollector(configuration.overloadAggressively, specialDescriptorMap)))); libraryClassPool.classesAccept( new AllMemberVisitor( new MemberSpecialNameFilter( new MemberNameCollector(configuration.overloadAggressively, specialDescriptorMap)))); // Replace conflicting non-private member names with special names. programClassPool.classesAccept( new MultiClassVisitor(new ClassVisitor[] { // Collect all private member names in this class and down // the hierarchy. new ClassHierarchyTraveler(true, false, false, true, new AllMemberVisitor( new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberNameCollector(configuration.overloadAggressively, descriptorMap)))), // Collect all non-private member names in this class and // higher up the hierarchy. new ClassHierarchyTraveler(true, true, true, false, new AllMemberVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameCollector(configuration.overloadAggressively, descriptorMap)))), // Assign new names to all conflicting non-private members // in this class and higher up the hierarchy. new ClassHierarchyTraveler(true, true, true, false, new AllMemberVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameConflictFixer(configuration.overloadAggressively, descriptorMap, warningPrinter, new MemberObfuscator(configuration.overloadAggressively, specialNameFactory, specialDescriptorMap))))), // Clear the collected names. new MapCleaner(descriptorMap) })); // Replace conflicting private member names with special names. // This is only possible if those names were kept or mapped. programClassPool.classesAccept( new MultiClassVisitor(new ClassVisitor[] { // Collect all member names in this class. new AllMemberVisitor( new MemberNameCollector(configuration.overloadAggressively, descriptorMap)), // Collect all non-private member names higher up the hierarchy. new ClassHierarchyTraveler(false, true, true, false, new AllMemberVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameCollector(configuration.overloadAggressively, descriptorMap)))), // Assign new names to all conflicting private members in this // class. new AllMemberVisitor( new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberNameConflictFixer(configuration.overloadAggressively, descriptorMap, warningPrinter, new MemberObfuscator(configuration.overloadAggressively, specialNameFactory, specialDescriptorMap)))), // Clear the collected names. new MapCleaner(descriptorMap) })); // Print out any warnings about member name conflicts. int warningCount = warningPrinter.getWarningCount(); if (warningCount > 0) { System.err.println("Warning: there were " + warningCount + " conflicting class member name mappings."); System.err.println(" Your configuration may be inconsistent."); if (!configuration.ignoreWarnings) { System.err.println(" If you are sure the conflicts are harmless,"); System.err.println(" you could try your luck using the '-ignorewarnings' option."); throw new IOException("Please correct the above warnings first."); } } // Print out the mapping, if requested. if (configuration.printMapping != null) { PrintStream ps = isFile(configuration.printMapping) ? new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printMapping))) : System.out; // Print out items that will be removed. programClassPool.classesAcceptAlphabetically(new MappingPrinter(ps)); if (ps != System.out) { ps.close(); } } // Actually apply the new names. programClassPool.classesAccept(new ClassRenamer()); libraryClassPool.classesAccept(new ClassRenamer()); // Update all references to these new names. programClassPool.classesAccept(new ClassReferenceFixer(false)); libraryClassPool.classesAccept(new ClassReferenceFixer(false)); programClassPool.classesAccept(new MemberReferenceFixer()); // Make package visible elements public or protected, if obfuscated // classes are being repackaged aggressively. if (configuration.repackageClasses != null && configuration.allowAccessModification) { programClassPool.classesAccept( new AllConstantVisitor( new AccessFixer())); // Fix the access flags of the inner classes information. programClassPool.classesAccept( new AllAttributeVisitor( new AllInnerClassesInfoVisitor( new InnerClassesAccessFixer()))); } // Fix the bridge method flags. programClassPool.classesAccept( new AllMethodVisitor( new BridgeMethodFixer())); // Rename the source file attributes, if requested. if (configuration.newSourceFileAttribute != null) { programClassPool.classesAccept(new SourceFileRenamer(configuration.newSourceFileAttribute)); } // Remove unused constants. programClassPool.classesAccept( new ConstantPoolShrinker()); } /** * Returns whether the given file is actually a file, or just a placeholder * for the standard output. */ private boolean isFile(File file) { return file.getPath().length() > 0; } } proguard4.8/src/proguard/DataEntryReaderFactory.java0000664000175000017500000001225311736333525021421 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.io.*; import proguard.util.*; import java.util.List; /** * This class can create DataEntryReader instances based on class path entries. * The readers will unwrap the input data entries from any jars, wars, ears, * and zips, before passing them to a given reader. * * @author Eric Lafortune */ public class DataEntryReaderFactory { /** * Creates a DataEntryReader that can read the given class path entry. * * @param messagePrefix a prefix for messages that are printed out. * @param classPathEntry the input class path entry. * @param reader a data entry reader to which the reading of actual * classes and resource files can be delegated. * @return a DataEntryReader for reading the given class path entry. */ public static DataEntryReader createDataEntryReader(String messagePrefix, ClassPathEntry classPathEntry, DataEntryReader reader) { boolean isJar = classPathEntry.isJar(); boolean isWar = classPathEntry.isWar(); boolean isEar = classPathEntry.isEar(); boolean isZip = classPathEntry.isZip(); List filter = classPathEntry.getFilter(); List jarFilter = classPathEntry.getJarFilter(); List warFilter = classPathEntry.getWarFilter(); List earFilter = classPathEntry.getEarFilter(); List zipFilter = classPathEntry.getZipFilter(); System.out.println(messagePrefix + (isJar ? "jar" : isWar ? "war" : isEar ? "ear" : isZip ? "zip" : "directory") + " [" + classPathEntry.getName() + "]" + (filter != null || jarFilter != null || warFilter != null || earFilter != null || zipFilter != null ? " (filtered)" : "")); // Add a filter, if specified. if (filter != null) { reader = new FilteredDataEntryReader( new DataEntryNameFilter( new ListParser(new FileNameParser()).parse(filter)), reader); } // Unzip any jars, if necessary. reader = wrapInJarReader(reader, isJar, jarFilter, ".jar"); if (!isJar) { // Unzip any wars, if necessary. reader = wrapInJarReader(reader, isWar, warFilter, ".war"); if (!isWar) { // Unzip any ears, if necessary. reader = wrapInJarReader(reader, isEar, earFilter, ".ear"); if (!isEar) { // Unzip any zips, if necessary. reader = wrapInJarReader(reader, isZip, zipFilter, ".zip"); } } } return reader; } /** * Wraps the given DataEntryReader in a JarReader, filtering it if necessary. */ private static DataEntryReader wrapInJarReader(DataEntryReader reader, boolean isJar, List jarFilter, String jarExtension) { // Unzip any jars, if necessary. DataEntryReader jarReader = new JarReader(reader); if (isJar) { // Always unzip. return jarReader; } else { // Add a filter, if specified. if (jarFilter != null) { jarReader = new FilteredDataEntryReader( new DataEntryNameFilter( new ListParser(new FileNameParser()).parse(jarFilter)), jarReader); } // Only unzip the right type of jars. return new FilteredDataEntryReader( new DataEntryNameFilter( new ExtensionMatcher(jarExtension)), jarReader, reader); } } } proguard4.8/src/proguard/WordReader.java0000664000175000017500000002601111740606455017106 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.io.*; /** * An abstract reader of words, with the possibility to include other readers. * Words are separated by spaces or broken off at delimiters. Words containing * spaces or delimiters can be quoted with single or double quotes. * Comments (everything starting with '#' on a single line) are ignored. * * @author Eric Lafortune * @noinspection TailRecursion */ public abstract class WordReader { private static final char COMMENT_CHARACTER = '#'; private File baseDir; private WordReader includeWordReader; private String currentLine; private int currentLineLength; private int currentIndex; private String currentWord; private String currentComments; /** * Creates a new WordReader with the given base directory. */ protected WordReader(File baseDir) { this.baseDir = baseDir; } /** * Sets the base directory of this reader. */ public void setBaseDir(File baseDir) { if (includeWordReader != null) { includeWordReader.setBaseDir(baseDir); } else { this.baseDir = baseDir; } } /** * Returns the base directory of this reader, if any. */ public File getBaseDir() { return includeWordReader != null ? includeWordReader.getBaseDir() : baseDir; } /** * Specifies to start reading words from the given WordReader. When it is * exhausted, this WordReader will continue to provide its own words. * * @param newIncludeWordReader the WordReader that will start reading words. */ public void includeWordReader(WordReader newIncludeWordReader) { if (includeWordReader == null) { includeWordReader = newIncludeWordReader; } else { includeWordReader.includeWordReader(newIncludeWordReader); } } /** * Reads a word from this WordReader, or from one of its active included * WordReader objects. * * @param isFileName return a complete line (or argument), if the word * isn't an option (it doesn't start with '-'). * @return the read word. */ public String nextWord(boolean isFileName) throws IOException { currentWord = null; // See if we have an included reader to produce a word. if (includeWordReader != null) { // Does the included word reader still produce a word? currentWord = includeWordReader.nextWord(isFileName); if (currentWord != null) { // Return it if so. return currentWord; } // Otherwise close and ditch the word reader. includeWordReader.close(); includeWordReader = null; } // Get a word from this reader. // Skip any whitespace and comments left on the current line. if (currentLine != null) { // Skip any leading whitespace. while (currentIndex < currentLineLength && Character.isWhitespace(currentLine.charAt(currentIndex))) { currentIndex++; } // Skip any comments. if (currentIndex < currentLineLength && isComment(currentLine.charAt(currentIndex))) { currentIndex = currentLineLength; } } // Make sure we have a non-blank line. while (currentLine == null || currentIndex == currentLineLength) { currentLine = nextLine(); if (currentLine == null) { return null; } currentLineLength = currentLine.length(); // Skip any leading whitespace. currentIndex = 0; while (currentIndex < currentLineLength && Character.isWhitespace(currentLine.charAt(currentIndex))) { currentIndex++; } // Remember any leading comments. if (currentIndex < currentLineLength && isComment(currentLine.charAt(currentIndex))) { // Remember the comments. String comment = currentLine.substring(currentIndex + 1); currentComments = currentComments == null ? comment : currentComments + '\n' + comment; // Skip the comments. currentIndex = currentLineLength; } } // Find the word starting at the current index. int startIndex = currentIndex; int endIndex; char startChar = currentLine.charAt(startIndex); if (isQuote(startChar)) { // The next word is starting with a quote character. // Skip the opening quote. startIndex++; // The next word is a quoted character string. // Find the closing quote. do { currentIndex++; if (currentIndex == currentLineLength) { currentWord = currentLine.substring(startIndex-1, currentIndex); throw new IOException("Missing closing quote for "+locationDescription()); } } while (currentLine.charAt(currentIndex) != startChar); endIndex = currentIndex++; } else if (isFileName && !isOption(startChar)) { // The next word is a (possibly optional) file name. // Find the end of the line, the first path separator, the first // option, or the first comment. while (currentIndex < currentLineLength) { char currentCharacter = currentLine.charAt(currentIndex); if (isFileDelimiter(currentCharacter) || ((isOption(currentCharacter) || isComment(currentCharacter)) && Character.isWhitespace(currentLine.charAt(currentIndex-1)))) { break; } currentIndex++; } endIndex = currentIndex; // Trim any trailing whitespace. while (endIndex > startIndex && Character.isWhitespace(currentLine.charAt(endIndex-1))) { endIndex--; } } else if (isDelimiter(startChar)) { // The next word is a single delimiting character. endIndex = ++currentIndex; } else { // The next word is a simple character string. // Find the end of the line, the first delimiter, or the first // white space. while (currentIndex < currentLineLength) { char currentCharacter = currentLine.charAt(currentIndex); if (isDelimiter(currentCharacter) || Character.isWhitespace(currentCharacter) || isComment(currentCharacter)) { break; } currentIndex++; } endIndex = currentIndex; } // Remember and return the parsed word. currentWord = currentLine.substring(startIndex, endIndex); return currentWord; } /** * Returns the comments collected before returning the last word. * Starts collecting new comments. * * @return the collected comments, or null if there weren't any. */ public String lastComments() throws IOException { if (includeWordReader == null) { String comments = currentComments; currentComments = null; return comments; } else { return includeWordReader.lastComments(); } } /** * Constructs a readable description of the current position in this * WordReader and its included WordReader objects. * * @return the description. */ public String locationDescription() { return (includeWordReader == null ? (currentWord == null ? "end of " : "'" + currentWord + "' in " ) : (includeWordReader.locationDescription() + ",\n" + " included from ")) + lineLocationDescription(); } /** * Reads a line from this WordReader, or from one of its active included * WordReader objects. * * @return the read line. */ protected abstract String nextLine() throws IOException; /** * Returns a readable description of the current WordReader position. * * @return the description. */ protected abstract String lineLocationDescription(); /** * Closes the FileWordReader. */ public void close() throws IOException { // Close and ditch the included word reader, if any. if (includeWordReader != null) { includeWordReader.close(); includeWordReader = null; } } // Small utility methods. private boolean isOption(char character) { return character == '-'; } private boolean isComment(char character) { return character == COMMENT_CHARACTER; } private boolean isDelimiter(char character) { return character == '@' || character == '{' || character == '}' || character == '(' || character == ')' || character == ',' || character == ';' || character == File.pathSeparatorChar; } private boolean isFileDelimiter(char character) { return character == '(' || character == ')' || character == ',' || character == ';' || character == File.pathSeparatorChar; } private boolean isQuote(char character) { return character == '\'' || character == '"'; } } proguard4.8/src/proguard/wtk/0000775000175000017500000000000011760503005014777 5ustar ericericproguard4.8/src/proguard/wtk/package.html0000644000175000017500000000012511736333525017267 0ustar ericeric This package contains the J2ME Wireless Toolkit plug-in for ProGuard. proguard4.8/src/proguard/wtk/ProGuardObfuscator.java0000664000175000017500000001123311752556325021433 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.wtk; import com.sun.kvem.environment.Obfuscator; import proguard.*; import java.io.*; /** * ProGuard plug-in for the J2ME Wireless Toolkit. *

* In order to integrate this plug-in in the toolkit, you'll have to put the * following lines in the file * {j2mewtk.dir}/wtklib/Linux/ktools.properties or * {j2mewtk.dir}\wtklib\Windows\ktools.properties (whichever is * applicable). *

*

 * obfuscator.runner.class.name: proguard.wtk.ProGuardObfuscator
 * obfuscator.runner.classpath: /usr/local/java/proguard1.6/lib/proguard.jar
 * 
* Please make sure the class path is set correctly for your system. * * @author Eric Lafortune */ public class ProGuardObfuscator implements Obfuscator { private static final String DEFAULT_CONFIGURATION = "default.pro"; // Implementations for Obfuscator. public void createScriptFile(File jadFile, File projectDir) { // We don't really need to create a script file; // we'll just fill out all options in the run method. } public void run(File obfuscatedJarFile, String wtkBinDir, String wtkLibDir, String jarFileName, String projectDirName, String classPath, String emptyAPI) throws IOException { // Create the ProGuard configuration. Configuration configuration = new Configuration(); // Parse the default configuration file. ConfigurationParser parser = new ConfigurationParser(this.getClass().getResource(DEFAULT_CONFIGURATION), System.getProperties()); try { parser.parse(configuration); // Fill out the library class path. configuration.libraryJars = classPath(classPath); // Fill out the program class path (input and output). configuration.programJars = new ClassPath(); configuration.programJars.add(new ClassPathEntry(new File(jarFileName), false)); configuration.programJars.add(new ClassPathEntry(obfuscatedJarFile, true)); // The preverify tool seems to unpack the resulting classes, // so we must not use mixed-case class names on Windows. configuration.useMixedCaseClassNames = !System.getProperty("os.name").regionMatches(true, 0, "windows", 0, 7); // Run ProGuard with these options. ProGuard proGuard = new ProGuard(configuration); proGuard.execute(); } catch (ParseException ex) { throw new IOException(ex.getMessage()); } finally { parser.close(); } } /** * Converts the given class path String into a ClassPath object. */ private ClassPath classPath(String classPathString) { ClassPath classPath = new ClassPath(); String separator = System.getProperty("path.separator"); int index = 0; while (index < classPathString.length()) { // Find the next separator, or the end of the String. int next_index = classPathString.indexOf(separator, index); if (next_index < 0) { next_index = classPathString.length(); } // Create and add the found class path entry. ClassPathEntry classPathEntry = new ClassPathEntry(new File(classPathString.substring(index, next_index)), false); classPath.add(classPathEntry); // Continue after the separator. index = next_index + 1; } return classPath; } } proguard4.8/src/proguard/wtk/default.pro0000644000175000017500000001146011163773611017156 0ustar ericeric-dontnote -microedition -mergeinterfacesaggressively -overloadaggressively -repackageclasses '' -allowaccessmodification # Keep all extensions of javax.microedition.midlet.MIDlet. -keep public class * extends javax.microedition.midlet.MIDlet # Keep all native class/method names. -keepclasseswithmembernames class * { native ; } # Remove all invocations of System methods without side effects # whose return values are not used. -assumenosideeffects public class java.lang.System { public static native long currentTimeMillis(); static java.lang.Class getCallerClass(); public static native int identityHashCode(java.lang.Object); public static java.lang.SecurityManager getSecurityManager(); public static java.util.Properties getProperties(); public static java.lang.String getProperty(java.lang.String); public static java.lang.String getenv(java.lang.String); public static native java.lang.String mapLibraryName(java.lang.String); public static java.lang.String getProperty(java.lang.String,java.lang.String); } # Remove all invocations of String methods without side effects # whose return values are not used. -assumenosideeffects public class java.lang.String { public java.lang.String(); public java.lang.String(byte[]); public java.lang.String(byte[],int); public java.lang.String(byte[],int,int); public java.lang.String(byte[],int,int,int); public java.lang.String(byte[],int,int,java.lang.String); public java.lang.String(byte[],java.lang.String); public java.lang.String(char[]); public java.lang.String(char[],int,int); public java.lang.String(java.lang.String); public java.lang.String(java.lang.StringBuffer); public static java.lang.String copyValueOf(char[]); public static java.lang.String copyValueOf(char[],int,int); public static java.lang.String valueOf(boolean); public static java.lang.String valueOf(char); public static java.lang.String valueOf(char[]); public static java.lang.String valueOf(char[],int,int); public static java.lang.String valueOf(double); public static java.lang.String valueOf(float); public static java.lang.String valueOf(int); public static java.lang.String valueOf(java.lang.Object); public static java.lang.String valueOf(long); public boolean contentEquals(java.lang.StringBuffer); public boolean endsWith(java.lang.String); public boolean equalsIgnoreCase(java.lang.String); public boolean equals(java.lang.Object); public boolean matches(java.lang.String); public boolean regionMatches(boolean,int,java.lang.String,int,int); public boolean regionMatches(int,java.lang.String,int,int); public boolean startsWith(java.lang.String); public boolean startsWith(java.lang.String,int); public byte[] getBytes(); public byte[] getBytes(java.lang.String); public char charAt(int); public char[] toCharArray(); public int compareToIgnoreCase(java.lang.String); public int compareTo(java.lang.Object); public int compareTo(java.lang.String); public int hashCode(); public int indexOf(int); public int indexOf(int,int); public int indexOf(java.lang.String); public int indexOf(java.lang.String,int); public int lastIndexOf(int); public int lastIndexOf(int,int); public int lastIndexOf(java.lang.String); public int lastIndexOf(java.lang.String,int); public int length(); public java.lang.CharSequence subSequence(int,int); public java.lang.String concat(java.lang.String); public java.lang.String replaceAll(java.lang.String,java.lang.String); public java.lang.String replace(char,char); public java.lang.String replaceFirst(java.lang.String,java.lang.String); public java.lang.String[] split(java.lang.String); public java.lang.String[] split(java.lang.String,int); public java.lang.String substring(int); public java.lang.String substring(int,int); public java.lang.String toLowerCase(); public java.lang.String toLowerCase(java.util.Locale); public java.lang.String toString(); public java.lang.String toUpperCase(); public java.lang.String toUpperCase(java.util.Locale); public java.lang.String trim(); } # Remove all invocations of StringBuffer methods without side effects # whose return values are not used. -assumenosideeffects public class java.lang.StringBuffer { public java.lang.StringBuffer(); public java.lang.StringBuffer(int); public java.lang.StringBuffer(java.lang.String); public java.lang.String toString(); public char charAt(int); public int capacity(); public int indexOf(java.lang.String,int); public int lastIndexOf(java.lang.String); public int lastIndexOf(java.lang.String,int); public int length(); public java.lang.String substring(int); public java.lang.String substring(int,int); } proguard4.8/src/proguard/Configuration.java0000644000175000017500000002577311736333525017673 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import java.io.File; import java.util.List; /** * The ProGuard configuration. * * @see ProGuard * * @author Eric Lafortune */ public class Configuration { /////////////////////////////////////////////////////////////////////////// // Input and output options. /////////////////////////////////////////////////////////////////////////// /** * A list of input and output entries (jars, wars, ears, zips, and directories). */ public ClassPath programJars; /** * A list of library entries (jars, wars, ears, zips, and directories). */ public ClassPath libraryJars; /** * Specifies whether to skip non-public library classes while reading * library jars. */ public boolean skipNonPublicLibraryClasses = false; /** * Specifies whether to skip non-public library class members while reading * library classes. */ public boolean skipNonPublicLibraryClassMembers = true; /** * A list of Strings specifying directories to be kept in * the output directories or the output jars. A null list * means no directories. An empty list means all directories. The directory * names may contain "**", "*", or "?" wildcards, and they may be preceded * by the "!" negator. */ public List keepDirectories; /** * Specifies the version number of the output classes, or 0 if the version * number can be left unchanged. */ public int targetClassVersion; /** * Specifies the last modification time of this configuration. This time * is necessary to check whether the input has to be processed. Setting it * to Long.MAX_VALUE forces processing, even if the modification times * of the output appear more recent than the modification times of the * input. */ public long lastModified = 0L; /////////////////////////////////////////////////////////////////////////// // Keep options. /////////////////////////////////////////////////////////////////////////// /** * A list of {@link KeepClassSpecification} instances, whose class names and * class member names are to be kept from shrinking, optimization, and/or * obfuscation. */ public List keep; /** * An optional output file for listing the kept seeds. * An empty file name means the standard output. */ public File printSeeds; /////////////////////////////////////////////////////////////////////////// // Shrinking options. /////////////////////////////////////////////////////////////////////////// /** * Specifies whether the code should be shrunk. */ public boolean shrink = true; /** * An optional output file for listing the unused classes and class * members. An empty file name means the standard output. */ public File printUsage; /** * A list of {@link ClassSpecification} instances, for which an explanation * is to be printed, why they are kept in the shrinking step. */ public List whyAreYouKeeping; /////////////////////////////////////////////////////////////////////////// // Optimization options. /////////////////////////////////////////////////////////////////////////// /** * Specifies whether the code should be optimized. */ public boolean optimize = true; /** * A list of Strings specifying the optimizations to be * performed. A null list means all optimizations. The * optimization names may contain "*" or "?" wildcards, and they may * be preceded by the "!" negator. */ public List optimizations; /** * Specifies the number of optimization passes. */ public int optimizationPasses = 1; /** * A list of {@link ClassSpecification} instances, whose methods are * assumed to have no side effects. */ public List assumeNoSideEffects; /** * Specifies whether the access of class members can be modified. */ public boolean allowAccessModification = false; /** * Specifies whether interfaces may be merged aggressively. */ public boolean mergeInterfacesAggressively = false; /////////////////////////////////////////////////////////////////////////// // Obfuscation options. /////////////////////////////////////////////////////////////////////////// /** * Specifies whether the code should be obfuscated. */ public boolean obfuscate = true; /** * An optional output file for listing the obfuscation mapping. * An empty file name means the standard output. */ public File printMapping; /** * An optional input file for reading an obfuscation mapping. */ public File applyMapping; /** * An optional name of a file containing obfuscated class member names. */ public File obfuscationDictionary; /** * An optional name of a file containing obfuscated class names. */ public File classObfuscationDictionary; /** * An optional name of a file containing obfuscated package names. */ public File packageObfuscationDictionary; /** * Specifies whether to apply aggressive name overloading on class members. */ public boolean overloadAggressively = false; /** * Specifies whether to generate globally unique class member names. */ public boolean useUniqueClassMemberNames = false; /** * Specifies whether obfuscated packages and classes can get mixed-case names. */ public boolean useMixedCaseClassNames = true; /** * A list of Strings specifying package names to be kept. * A null list means no names. An empty list means all * names. The package names may contain "**", "*", or "?" wildcards, and * they may be preceded by the "!" negator. */ public List keepPackageNames; /** * An optional base package if the obfuscated package hierarchy is to be * flattened, null otherwise. */ public String flattenPackageHierarchy; /** * An optional base package if the obfuscated classes are to be repackaged * into a single package, null otherwise. */ public String repackageClasses; /** * A list of Strings specifying optional attributes to be kept. * A null list means no attributes. An empty list means all * attributes. The attribute names may contain "*" or "?" wildcards, and * they may be preceded by the "!" negator. */ public List keepAttributes; /** * Specifies whether method parameter names and types should be kept for * methods that are not obfuscated. This is achieved by keeping partial * "LocalVariableTable" and "LocalVariableTypeTable" attributes. */ public boolean keepParameterNames = false; /** * An optional replacement for all SourceFile attributes. */ public String newSourceFileAttribute; /** * A list of Strings specifying a filter for classes whose * string constants are to be adapted, based on corresponding obfuscated * class names. */ public List adaptClassStrings; /** * A list of Strings specifying a filter for files whose * names are to be adapted, based on corresponding obfuscated class names. */ public List adaptResourceFileNames; /** * A list of Strings specifying a filter for files whose * contents are to be adapted, based on obfuscated class names. */ public List adaptResourceFileContents; /////////////////////////////////////////////////////////////////////////// // Preverification options. /////////////////////////////////////////////////////////////////////////// /** * Specifies whether the code should be preverified. */ public boolean preverify = true; /** * Specifies whether the code should be preverified for Java Micro Edition * (creating StackMap attributes) instead of for Java Standard Edition * (creating StackMapTable attributes). */ public boolean microEdition = false; /////////////////////////////////////////////////////////////////////////// // General options. /////////////////////////////////////////////////////////////////////////// /** * Specifies whether to print verbose messages. */ public boolean verbose = false; /** * A list of Strings specifying a filter for the classes for * which not to print notes, if there are noteworthy potential problems. * A null list means all classes. The class names may contain * "**", "*", or "?" wildcards, and they may be preceded by the "!" negator. */ public List note = null; /** * A list of Strings specifying a filter for the classes for * which not to print warnings, if there are any problems. * A null list means all classes. The class names may contain * "**", "*", or "?" wildcards, and they may be preceded by the "!" negator. */ public List warn = null; /** * Specifies whether to ignore any warnings. */ public boolean ignoreWarnings = false; /** * An optional output file for printing out the configuration that ProGuard * is using (with included files and replaced variables). * An empty file name means the standard output. */ public File printConfiguration; /** * An optional output file for printing out the processed code in a more * or less readable form. An empty file name means the standard output. */ public File dump; } proguard4.8/src/proguard/optimize/0000775000175000017500000000000011760503005016032 5ustar ericericproguard4.8/src/proguard/optimize/package.html0000644000175000017500000000014311736333525020322 0ustar ericeric This package contains visitors that assist with various optimizations of byte code. proguard4.8/src/proguard/optimize/evaluation/0000775000175000017500000000000011760503005020201 5ustar ericericproguard4.8/src/proguard/optimize/evaluation/package.html0000644000175000017500000000017111736333525022472 0ustar ericeric This package contains visitors that perform partial evaluation and subsequent optimizations on byte code. proguard4.8/src/proguard/optimize/evaluation/EvaluationShrinker.java0000664000175000017500000031616511736333525024710 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.evaluation; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.RefConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.info.*; import java.util.Arrays; /** * This AttributeVisitor simplifies the code attributes that it visits, based * on partial evaluation. * * @author Eric Lafortune */ public class EvaluationShrinker extends SimplifiedVisitor implements AttributeVisitor { //* private static final boolean DEBUG_RESULTS = false; private static final boolean DEBUG = false; /*/ private static boolean DEBUG_RESULTS = true; private static boolean DEBUG = true; //*/ private static final int UNSUPPORTED = -1; private static final int NOP = InstructionConstants.OP_NOP & 0xff; private static final int POP = InstructionConstants.OP_POP & 0xff; private static final int POP2 = InstructionConstants.OP_POP2 & 0xff; private static final int DUP = InstructionConstants.OP_DUP & 0xff; private static final int DUP_X1 = InstructionConstants.OP_DUP_X1 & 0xff; private static final int DUP_X2 = InstructionConstants.OP_DUP_X2 & 0xff; private static final int DUP2 = InstructionConstants.OP_DUP2 & 0xff; private static final int DUP2_X1 = InstructionConstants.OP_DUP2_X1 & 0xff; private static final int DUP2_X2 = InstructionConstants.OP_DUP2_X2 & 0xff; private static final int SWAP = InstructionConstants.OP_SWAP & 0xff; private static final int MOV_X2 = DUP_X2 | (POP << 8); private static final int MOV2_X1 = DUP2_X1 | (POP2 << 8); private static final int MOV2_X2 = DUP2_X2 | (POP2 << 8); private static final int POP_X1 = SWAP | (POP << 8); private static final int POP_X2 = DUP2_X1 | (POP2 << 8) | (POP << 16); private static final int POP_X3 = UNSUPPORTED; private static final int POP2_X1 = DUP_X2 | (POP << 8) | (POP2 << 16); private static final int POP2_X2 = DUP2_X2 | (POP2 << 8) | (POP2 << 16); private static final int POP3 = POP2 | (POP << 8); private static final int POP4 = POP2 | (POP2 << 8); private static final int POP_DUP = POP | (DUP << 8); private static final int POP_SWAP_POP = POP | (SWAP << 8) | (POP << 16); private static final int POP2_SWAP_POP = POP2 | (SWAP << 8) | (POP << 16); private static final int SWAP_DUP_X1 = SWAP | (DUP_X1 << 8); private static final int SWAP_DUP_X1_SWAP = SWAP | (DUP_X1 << 8) | (SWAP << 16); private static final int SWAP_POP_DUP = SWAP | (POP << 8) | (DUP << 16); private static final int SWAP_POP_DUP_X1 = SWAP | (POP << 8) | (DUP_X1 << 16); private static final int DUP_X2_POP2 = DUP_X2 | (POP2 << 8); private static final int DUP2_X1_POP3 = DUP2_X1 | (POP2 << 8) | (POP << 16); private static final int DUP2_X2_POP3 = DUP2_X2 | (POP2 << 8) | (POP << 16); private static final int DUP2_X2_SWAP_POP = DUP2_X2 | (SWAP << 8) | (POP << 16); private final InstructionVisitor extraDeletedInstructionVisitor; private final InstructionVisitor extraAddedInstructionVisitor; private final PartialEvaluator partialEvaluator; private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator(); private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true); private final MyUnusedParameterSimplifier unusedParameterSimplifier = new MyUnusedParameterSimplifier(); private final MyProducerMarker producerMarker = new MyProducerMarker(); private final MyVariableInitializationMarker variableInitializationMarker = new MyVariableInitializationMarker(); private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer(); private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); private boolean[][] variablesNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_VARIABLES_SIZE]; private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE]; private boolean[][] stacksSimplifiedBefore = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE]; private boolean[] instructionsNecessary = new boolean[ClassConstants.TYPICAL_CODE_LENGTH]; private int maxMarkedOffset; /** * Creates a new EvaluationShrinker. */ public EvaluationShrinker() { this(new PartialEvaluator(), null, null); } /** * Creates a new EvaluationShrinker. * @param partialEvaluator the partial evaluator that will * execute the code and provide * information about the results. * @param extraDeletedInstructionVisitor an optional extra visitor for all * deleted instructions. * @param extraAddedInstructionVisitor an optional extra visitor for all * added instructions. */ public EvaluationShrinker(PartialEvaluator partialEvaluator, InstructionVisitor extraDeletedInstructionVisitor, InstructionVisitor extraAddedInstructionVisitor) { this.partialEvaluator = partialEvaluator; this.extraDeletedInstructionVisitor = extraDeletedInstructionVisitor; this.extraAddedInstructionVisitor = extraAddedInstructionVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = DEBUG_RESULTS = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // TODO: Remove this when the evaluation shrinker has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while shrinking instructions after partial evaluation:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); System.err.println("Not optimizing this method"); if (DEBUG) { method.accept(clazz, new ClassPrinter()); throw ex; } } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (DEBUG_RESULTS) { System.out.println(); System.out.println("Class "+ClassUtil.externalClassName(clazz.getName())); System.out.println("Method "+ClassUtil.externalFullMethodDescription(clazz.getName(), 0, method.getName(clazz), method.getDescriptor(clazz))); } // Initialize the necessary array. initializeNecessary(codeAttribute); // Evaluate the method. partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); int codeLength = codeAttribute.u4codeLength; // Reset the code changes. codeAttributeEditor.reset(codeLength); // Mark any unused method parameters on the stack. if (DEBUG) System.out.println("Invocation simplification:"); for (int offset = 0; offset < codeLength; offset++) { if (partialEvaluator.isTraced(offset)) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); instruction.accept(clazz, method, codeAttribute, offset, unusedParameterSimplifier); } } // Mark all essential instructions that have been encountered as used. if (DEBUG) System.out.println("Usage initialization: "); maxMarkedOffset = -1; // The invocation of the "super" or "this" method inside a // constructor is always necessary. int superInitializationOffset = partialEvaluator.superInitializationOffset(); if (superInitializationOffset != PartialEvaluator.NONE) { if (DEBUG) System.out.print("(super.)"); markInstruction(superInitializationOffset); } // Also mark infinite loops and instructions that cause side effects. for (int offset = 0; offset < codeLength; offset++) { if (partialEvaluator.isTraced(offset)) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); // Mark that the instruction is necessary if it is an infinite loop. if (instruction.opcode == InstructionConstants.OP_GOTO && ((BranchInstruction)instruction).branchOffset == 0) { if (DEBUG) System.out.print("(infinite loop)"); markInstruction(offset); } // Mark that the instruction is necessary if it has side effects. else if (sideEffectInstructionChecker.hasSideEffects(clazz, method, codeAttribute, offset, instruction)) { markInstruction(offset); } } } if (DEBUG) System.out.println(); // Globally mark instructions and their produced variables and stack // entries on which necessary instructions depend. // Instead of doing this recursively, we loop across all instructions, // starting at the highest previously unmarked instruction that has // been been marked. if (DEBUG) System.out.println("Usage marking:"); while (maxMarkedOffset >= 0) { int offset = maxMarkedOffset; maxMarkedOffset = offset - 1; if (partialEvaluator.isTraced(offset)) { if (isInstructionNecessary(offset)) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); instruction.accept(clazz, method, codeAttribute, offset, producerMarker); } // Check if this instruction is a branch origin from a branch // that straddles some marked code. markStraddlingBranches(offset, partialEvaluator.branchTargets(offset), true); // Check if this instruction is a branch target from a branch // that straddles some marked code. markStraddlingBranches(offset, partialEvaluator.branchOrigins(offset), false); } if (DEBUG) { if (maxMarkedOffset > offset) { System.out.println(" -> "+maxMarkedOffset); } } } if (DEBUG) System.out.println(); // Mark variable initializations, even if they aren't strictly necessary. // The virtual machine's verification step is not smart enough to see // this, and may complain otherwise. if (DEBUG) System.out.println("Initialization marking: "); for (int offset = 0; offset < codeLength; offset++) { // Is it a variable initialization that hasn't been marked yet? if (partialEvaluator.isTraced(offset) && !isInstructionNecessary(offset)) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); instruction.accept(clazz, method, codeAttribute, offset, variableInitializationMarker); } } if (DEBUG) System.out.println(); // Locally fix instructions, in order to keep the stack consistent. if (DEBUG) System.out.println("Stack consistency fixing:"); maxMarkedOffset = codeLength - 1; while (maxMarkedOffset >= 0) { int offset = maxMarkedOffset; maxMarkedOffset = offset - 1; if (partialEvaluator.isTraced(offset)) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); instruction.accept(clazz, method, codeAttribute, offset, stackConsistencyFixer); // Check if this instruction is a branch origin from a branch // that straddles some marked code. markStraddlingBranches(offset, partialEvaluator.branchTargets(offset), true); // Check if this instruction is a branch target from a branch // that straddles some marked code. markStraddlingBranches(offset, partialEvaluator.branchOrigins(offset), false); } } if (DEBUG) System.out.println(); // Replace traced but unmarked backward branches by infinite loops. // The virtual machine's verification step is not smart enough to see // the code isn't reachable, and may complain otherwise. // Any clearly unreachable code will still be removed elsewhere. if (DEBUG) System.out.println("Infinite loop fixing:"); for (int offset = 0; offset < codeLength; offset++) { // Is it a traced but unmarked backward branch, without an unmarked // straddling forward branch? Note that this is still a heuristic. if (partialEvaluator.isTraced(offset) && !isInstructionNecessary(offset) && isAllSmallerThanOrEqual(partialEvaluator.branchTargets(offset), offset) && !isAnyUnnecessaryInstructionBranchingOver(lastNecessaryInstructionOffset(offset), offset)) { replaceByInfiniteLoop(clazz, offset); } } if (DEBUG) System.out.println(); // Insert infinite loops after jumps to subroutines that don't return. // The virtual machine's verification step is not smart enough to see // the code isn't reachable, and may complain otherwise. if (DEBUG) System.out.println("Non-returning subroutine fixing:"); for (int offset = 0; offset < codeLength; offset++) { // Is it a traced but unmarked backward branch, without an unmarked // straddling forward branch? Note that this is still a heuristic. if (isInstructionNecessary(offset) && partialEvaluator.isSubroutineInvocation(offset)) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); int nextOffset = offset + instruction.length(offset); if (!isInstructionNecessary(nextOffset)) { replaceByInfiniteLoop(clazz, nextOffset); } } } if (DEBUG) System.out.println(); // Delete all instructions that are not used. int offset = 0; do { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); if (!isInstructionNecessary(offset)) { codeAttributeEditor.deleteInstruction(offset); codeAttributeEditor.insertBeforeInstruction(offset, (Instruction)null); codeAttributeEditor.replaceInstruction(offset, (Instruction)null); codeAttributeEditor.insertAfterInstruction(offset, (Instruction)null); // Visit the instruction, if required. if (extraDeletedInstructionVisitor != null) { instruction.accept(clazz, method, codeAttribute, offset, extraDeletedInstructionVisitor); } } offset += instruction.length(offset); } while (offset < codeLength); if (DEBUG_RESULTS) { System.out.println("Simplification results:"); offset = 0; do { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); System.out.println((isInstructionNecessary(offset) ? " + " : " - ")+instruction.toString(offset)); if (partialEvaluator.isTraced(offset)) { int initializationOffset = partialEvaluator.initializationOffset(offset); if (initializationOffset != PartialEvaluator.NONE) { System.out.println(" is to be initialized at ["+initializationOffset+"]"); } InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset); if (branchTargets != null) { System.out.println(" has overall been branching to "+branchTargets); } boolean deleted = codeAttributeEditor.deleted[offset]; if (isInstructionNecessary(offset) && deleted) { System.out.println(" is deleted"); } Instruction preInsertion = codeAttributeEditor.preInsertions[offset]; if (preInsertion != null) { System.out.println(" is preceded by: "+preInsertion); } Instruction replacement = codeAttributeEditor.replacements[offset]; if (replacement != null) { System.out.println(" is replaced by: "+replacement); } Instruction postInsertion = codeAttributeEditor.postInsertions[offset]; if (postInsertion != null) { System.out.println(" is followed by: "+postInsertion); } } offset += instruction.length(offset); } while (offset < codeLength); } // Apply all accumulated changes to the code. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } /** * This MemberVisitor marks stack entries that aren't necessary because * parameters aren't used in the methods that are visited. */ private class MyUnusedParameterSimplifier extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, MemberVisitor { private int invocationOffset; private ConstantInstruction invocationInstruction; // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { switch (constantInstruction.opcode) { case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: this.invocationOffset = offset; this.invocationInstruction = constantInstruction; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); break; } } // Implementations for ConstantVisitor. public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { refConstant.referencedMemberAccept(this); } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) {} public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Get the total size of the parameters. int parameterSize = ParameterUsageMarker.getParameterSize(programMethod); // Make the method invocation static, if possible. if ((programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0 && !ParameterUsageMarker.isParameterUsed(programMethod, 0)) { replaceByStaticInvocation(programClass, invocationOffset, invocationInstruction); } // Remove unused parameters. for (int index = 0; index < parameterSize; index++) { if (!ParameterUsageMarker.isParameterUsed(programMethod, index)) { TracedStack stack = partialEvaluator.getStackBefore(invocationOffset); int stackIndex = stack.size() - parameterSize + index; if (DEBUG) { System.out.println(" ["+invocationOffset+"] Ignoring parameter #"+index+" of "+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] (stack entry #"+stackIndex+" ["+stack.getBottom(stackIndex)+"])"); System.out.println(" Full stack: "+stack); } markStackSimplificationBefore(invocationOffset, stackIndex); } } } } /** * This InstructionVisitor marks the producing instructions and produced * variables and stack entries of the instructions that it visits. * Simplified method arguments are ignored. */ private class MyProducerMarker extends SimplifiedVisitor implements InstructionVisitor { // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { markStackProducers(clazz, offset, instruction); } public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { switch (simpleInstruction.opcode) { case InstructionConstants.OP_DUP: conditionallyMarkStackEntryProducers(offset, 0, 0); conditionallyMarkStackEntryProducers(offset, 1, 0); break; case InstructionConstants.OP_DUP_X1: conditionallyMarkStackEntryProducers(offset, 0, 0); conditionallyMarkStackEntryProducers(offset, 1, 1); conditionallyMarkStackEntryProducers(offset, 2, 0); break; case InstructionConstants.OP_DUP_X2: conditionallyMarkStackEntryProducers(offset, 0, 0); conditionallyMarkStackEntryProducers(offset, 1, 1); conditionallyMarkStackEntryProducers(offset, 2, 2); conditionallyMarkStackEntryProducers(offset, 3, 0); break; case InstructionConstants.OP_DUP2: conditionallyMarkStackEntryProducers(offset, 0, 0); conditionallyMarkStackEntryProducers(offset, 1, 1); conditionallyMarkStackEntryProducers(offset, 2, 0); conditionallyMarkStackEntryProducers(offset, 3, 1); break; case InstructionConstants.OP_DUP2_X1: conditionallyMarkStackEntryProducers(offset, 0, 0); conditionallyMarkStackEntryProducers(offset, 1, 1); conditionallyMarkStackEntryProducers(offset, 2, 2); conditionallyMarkStackEntryProducers(offset, 3, 0); conditionallyMarkStackEntryProducers(offset, 4, 1); break; case InstructionConstants.OP_DUP2_X2: conditionallyMarkStackEntryProducers(offset, 0, 0); conditionallyMarkStackEntryProducers(offset, 1, 1); conditionallyMarkStackEntryProducers(offset, 2, 2); conditionallyMarkStackEntryProducers(offset, 3, 3); conditionallyMarkStackEntryProducers(offset, 4, 0); conditionallyMarkStackEntryProducers(offset, 5, 1); break; case InstructionConstants.OP_SWAP: conditionallyMarkStackEntryProducers(offset, 0, 1); conditionallyMarkStackEntryProducers(offset, 1, 0); break; default: markStackProducers(clazz, offset, simpleInstruction); break; } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Is the variable being loaded (or incremented)? if (variableInstruction.opcode < InstructionConstants.OP_ISTORE) { markVariableProducers(offset, variableInstruction.variableIndex); } else { markStackProducers(clazz, offset, variableInstruction); } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Mark the initializer invocation, if this is a 'new' instruction. if (constantInstruction.opcode == InstructionConstants.OP_NEW) { markInitialization(offset); } markStackProducers(clazz, offset, constantInstruction); } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Explicitly mark the produced stack entry of a 'jsr' instruction, // because the consuming 'astore' instruction of the subroutine is // cleared every time it is traced. if (branchInstruction.opcode == InstructionConstants.OP_JSR || branchInstruction.opcode == InstructionConstants.OP_JSR_W) { markStackEntryAfter(offset, 0); } else { markStackProducers(clazz, offset, branchInstruction); } } } /** * This InstructionVisitor marks variable initializations that are * necessary to appease the JVM. */ private class MyVariableInitializationMarker extends SimplifiedVisitor implements InstructionVisitor { // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { if (!variableInstruction.isLoad()) { int variableIndex = variableInstruction.variableIndex; if (isVariableInitialization(offset, variableIndex) && isVariableInitializationNecessary(clazz, method, codeAttribute, offset, variableIndex)) { markInstruction(offset); } } } } /** * This InstructionVisitor fixes instructions locally, popping any unused * produced stack entries after marked instructions, and popping produced * stack entries and pushing missing stack entries instead of unmarked * instructions. */ private class MyStackConsistencyFixer extends SimplifiedVisitor implements InstructionVisitor { // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { // Has the instruction been marked? if (isInstructionNecessary(offset)) { // Check all stack entries that are popped. // Typical case: a freshly marked variable initialization that // requires some value on the stack. int popCount = instruction.stackPopCount(clazz); if (popCount > 0) { TracedStack tracedStack = partialEvaluator.getStackBefore(offset); int stackSize = tracedStack.size(); int requiredPushCount = 0; for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++) { if (!isStackSimplifiedBefore(offset, stackIndex)) { // Is this stack entry pushed by any producer // (because it is required by other consumers)? if (isStackEntryPresentBefore(offset, stackIndex)) { // Mark all produced stack entries. markStackEntryProducers(offset, stackIndex); } else { // Remember to push it. requiredPushCount++; } } } // Push some necessary stack entries. if (requiredPushCount > 0) { if (DEBUG) System.out.println(" Inserting before marked consumer "+instruction.toString(offset)); if (requiredPushCount > (instruction.isCategory2() ? 2 : 1)) { throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"]"); } insertPushInstructions(offset, false, tracedStack.getTop(0).computationalType()); } } // Check all other stack entries, if this is a return // instruction. // Typical case: the code returns, but there are still other // entries left on the stack. These have to be consistent. InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset); if (branchTargets != null && branchTargets.instructionOffsetCount() == 0) { TracedStack tracedStack = partialEvaluator.getStackBefore(offset); int unpoppedStackSize = tracedStack.size() - popCount; for (int stackIndex = 0; stackIndex < unpoppedStackSize; stackIndex++) { // Is this stack entry pushed by any producer // (because it is required by other consumers)? if (isStackEntryPresentBefore(offset, stackIndex)) { // Mark all produced stack entries. markStackEntryProducers(offset, stackIndex); } } } // Check all stack entries that are pushed. // Typical case: a return value that wasn't really required and // that should be popped. int pushCount = instruction.stackPushCount(clazz); if (pushCount > 0) { TracedStack tracedStack = partialEvaluator.getStackAfter(offset); int stackSize = tracedStack.size(); int requiredPopCount = 0; for (int stackIndex = stackSize - pushCount; stackIndex < stackSize; stackIndex++) { // Is the stack entry required by consumers? if (!isStackEntryNecessaryAfter(offset, stackIndex)) { // Remember to pop it. requiredPopCount++; } } // Pop the unnecessary stack entries. if (requiredPopCount > 0) { if (DEBUG) System.out.println(" Inserting after marked producer "+instruction.toString(offset)); insertPopInstructions(offset, false, requiredPopCount); } } } else { // Check all stack entries that would be popped. // Typical case: a stack value that is required elsewhere and // that still has to be popped. int popCount = instruction.stackPopCount(clazz); if (popCount > 0) { TracedStack tracedStack = partialEvaluator.getStackBefore(offset); int stackSize = tracedStack.size(); int expectedPopCount = 0; for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++) { // Is this stack entry pushed by any producer // (because it is required by other consumers)? if (isStackEntryPresentBefore(offset, stackIndex)) { // Mark all produced stack entries. markStackEntryProducers(offset, stackIndex); // Remember to pop it. expectedPopCount++; } } // Pop the unnecessary stack entries. if (expectedPopCount > 0) { if (DEBUG) System.out.println(" Replacing unmarked consumer "+instruction.toString(offset)); insertPopInstructions(offset, true, expectedPopCount); } } // Check all stack entries that would be pushed. // Typical case: never. int pushCount = instruction.stackPushCount(clazz); if (pushCount > 0) { TracedStack tracedStack = partialEvaluator.getStackAfter(offset); int stackSize = tracedStack.size(); int expectedPushCount = 0; for (int stackIndex = stackSize - pushCount; stackIndex < stackSize; stackIndex++) { // Is the stack entry required by consumers? if (isStackEntryNecessaryAfter(offset, stackIndex)) { // Remember to push it. expectedPushCount++; } } // Push some necessary stack entries. if (expectedPushCount > 0) { if (DEBUG) System.out.println(" Replacing unmarked producer "+instruction.toString(offset)); insertPushInstructions(offset, true, tracedStack.getTop(0).computationalType()); } } } } public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { if (isInstructionNecessary(offset) && isDupOrSwap(simpleInstruction)) { int stackSizeBefore = partialEvaluator.getStackBefore(offset).size(); // Check all stack entries that are popped. // Typical case: a freshly marked variable initialization that // requires some value on the stack. int popCount = simpleInstruction.stackPopCount(clazz); if (popCount > 0) { for (int stackIndex = stackSizeBefore - popCount; stackIndex < stackSizeBefore; stackIndex++) { // Is this stack entry pushed by any producer // (because it is required by other consumers)? if (isStackEntryPresentBefore(offset, stackIndex)) { // Mark all produced stack entries. markStackEntryProducers(offset, stackIndex); } } } int topBefore = stackSizeBefore - 1; int topAfter = partialEvaluator.getStackAfter(offset).size() - 1; byte oldOpcode = simpleInstruction.opcode; // Simplify the dup/swap instruction if possible. int newOpcodes = fixDupSwap(offset, oldOpcode, topBefore, topAfter); // Did we find a suitabe (extended) opcode? if (newOpcodes == UNSUPPORTED) { // We can't easily emulate some constructs. throw new UnsupportedOperationException("Can't handle "+simpleInstruction.toString()+" instruction at ["+offset +"]"); } // Is there a single replacement opcode? if ((newOpcodes & ~0xff) == 0) { byte newOpcode = (byte)newOpcodes; if (newOpcode == InstructionConstants.OP_NOP) { // Delete the instruction. codeAttributeEditor.deleteInstruction(offset); if (extraDeletedInstructionVisitor != null) { extraDeletedInstructionVisitor.visitSimpleInstruction(null, null, null, offset, null); } if (DEBUG) System.out.println(" Deleting marked instruction "+simpleInstruction.toString(offset)); } else if (newOpcode == oldOpcode) { // Leave the instruction unchanged. codeAttributeEditor.undeleteInstruction(offset); if (DEBUG) System.out.println(" Marking unchanged instruction "+simpleInstruction.toString(offset)); } else { // Replace the instruction. Instruction replacementInstruction = new SimpleInstruction(newOpcode); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); if (DEBUG) System.out.println(" Replacing instruction "+simpleInstruction.toString(offset)+" by "+replacementInstruction.toString()); } } else { // Collect the replacement instructions. Instruction[] replacementInstructions = new Instruction[4]; if (DEBUG) System.out.println(" Replacing instruction "+simpleInstruction.toString(offset)+" by"); int count = 0; while (newOpcodes != 0) { SimpleInstruction replacementInstruction = new SimpleInstruction((byte)newOpcodes); replacementInstructions[count++] = replacementInstruction; if (DEBUG) System.out.println(" "+replacementInstruction.toString()); newOpcodes >>>= 8; } // Create a properly sized array. if (count < 4) { Instruction[] newInstructions = new Instruction[count]; System.arraycopy(replacementInstructions, 0, newInstructions, 0, count); replacementInstructions = newInstructions; } codeAttributeEditor.replaceInstruction(offset, replacementInstructions); } } else { visitAnyInstruction(clazz, method, codeAttribute, offset, simpleInstruction); } } /** * Returns a dup/swap opcode that is corrected for the stack entries * that are present before the instruction and necessary after the * instruction. The returned integer opcode may contain multiple byte * opcodes (least significant byte first). * @param instructionOffset the offset of the dup/swap instruction. * @param dupSwapOpcode the original dup/swap opcode. * @param topBefore the index of the top stack entry before * the instruction (counting from the bottom). * @param topAfter the index of the top stack entry after * the instruction (counting from the bottom). * @return the corrected opcode. */ private int fixDupSwap(int instructionOffset, byte dupSwapOpcode, int topBefore, int topAfter) { switch (dupSwapOpcode) { case InstructionConstants.OP_DUP: return fixedDup (instructionOffset, topBefore, topAfter); case InstructionConstants.OP_DUP_X1: return fixedDup_x1 (instructionOffset, topBefore, topAfter); case InstructionConstants.OP_DUP_X2: return fixedDup_x2 (instructionOffset, topBefore, topAfter); case InstructionConstants.OP_DUP2: return fixedDup2 (instructionOffset, topBefore, topAfter); case InstructionConstants.OP_DUP2_X1: return fixedDup2_x1(instructionOffset, topBefore, topAfter); case InstructionConstants.OP_DUP2_X2: return fixedDup2_x2(instructionOffset, topBefore, topAfter); case InstructionConstants.OP_SWAP: return fixedSwap (instructionOffset, topBefore, topAfter); default: throw new IllegalArgumentException("Not a dup/swap opcode ["+dupSwapOpcode+"]"); } } private int fixedDup(int instructionOffset, int topBefore, int topAfter) { boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0); boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0); boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1); // Figure out which stack entries should be moved, // copied, or removed. return stackEntryNecessary0 ? stackEntryNecessary1 ? DUP : // ...O -> ...OO NOP : // ...O -> ...O stackEntryNecessary1 ? NOP : // ...O -> ...O stackEntryPresent0 ? POP : // ...O -> ... NOP; // ... -> ... } private int fixedDup_x1(int instructionOffset, int topBefore, int topAfter) { boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0); boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1); boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0); boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1); boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2); // Figure out which stack entries should be moved, // copied, or removed. return stackEntryNecessary1 ? stackEntryNecessary2 ? stackEntryNecessary0 ? DUP_X1 : // ...XO -> ...OXO SWAP : // ...XO -> ...OX // !stackEntryNecessary2 stackEntryNecessary0 ? NOP : // ...XO -> ...XO stackEntryPresent0 ? POP : // ...XO -> ...X NOP : // ...X -> ...X stackEntryPresent1 ? stackEntryNecessary2 ? stackEntryNecessary0 ? SWAP_POP_DUP : // ...XO -> ...OO POP_X1 : // ...XO -> ...O // !stackEntryNecessary2 stackEntryNecessary0 ? POP_X1 : // ...XO -> ...O stackEntryPresent0 ? POP2 : // ...XO -> ... POP : // ...X -> ... // !stackEntryPresent1 stackEntryNecessary2 ? stackEntryNecessary0 ? DUP : // ...O -> ...OO NOP : // ...O -> ...O // !stackEntryNecessary2 stackEntryNecessary0 ? NOP : // ...O -> ...O stackEntryPresent0 ? POP : // ...O -> ... NOP; // ... -> ... } private int fixedDup_x2(int instructionOffset, int topBefore, int topAfter) { boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0); boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1); boolean stackEntryPresent2 = isStackEntryPresentBefore(instructionOffset, topBefore - 2); boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0); boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1); boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2); boolean stackEntryNecessary3 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 3); // Figure out which stack entries should be moved, // copied, or removed. return stackEntryNecessary1 ? stackEntryNecessary2 ? stackEntryNecessary3 ? stackEntryNecessary0 ? DUP_X2 : // ...XYO -> ...OXYO MOV_X2 : // ...XYO -> ...OXY // !stackEntryNecessary3 stackEntryNecessary0 ? NOP : // ...XYO -> ...XYO stackEntryPresent0 ? POP : // ...XYO -> ...XY NOP : // ...XY -> ...XY stackEntryPresent2 ? stackEntryNecessary3 ? // stackEntryNecessary0 ? UNSUPPORTED : // ...XYO -> ...OYO UNSUPPORTED : // ...XYO -> ...OY // !stackEntryNecessary3 stackEntryNecessary0 ? POP_X2 : // ...XYO -> ...YO stackEntryPresent0 ? POP_SWAP_POP : // ...XYO -> ...Y POP_X1 : // ...XY -> ...Y // !stackEntryPresent2 stackEntryNecessary3 ? stackEntryNecessary0 ? DUP_X1 : // ...YO -> ...OYO SWAP : // ...YO -> ...OY // !stackEntryNecessary3 stackEntryNecessary0 ? NOP : // ...YO -> ...YO stackEntryPresent0 ? POP : // ...YO -> ...Y NOP : // ...Y -> ...Y stackEntryPresent1 ? stackEntryNecessary2 ? stackEntryNecessary3 ? stackEntryNecessary0 ? SWAP_POP_DUP_X1 : // ...XYO -> ...OXO DUP_X2_POP2 : // ...XYO -> ...OX // !stackEntryNecessary3 stackEntryNecessary0 ? POP_X1 : // ...XYO -> ...XO stackEntryPresent0 ? POP2 : // ...XYO -> ...X POP : // ...XY -> ...X stackEntryPresent2 ? stackEntryNecessary3 ? stackEntryNecessary0 ? UNSUPPORTED : // ...XYO -> ...OO POP2_X1 : // ...XYO -> ...O // !stackEntryNecessary3 stackEntryNecessary0 ? POP2_X1 : // ...XYO -> ...O stackEntryPresent0 ? POP3 : // ...XYO -> ... POP2 : // ...XY -> ... // !stackEntryPresent2 stackEntryNecessary3 ? stackEntryNecessary0 ? SWAP_POP_DUP : // ...YO -> ...OO POP_X1 : // ...YO -> ...O // !stackEntryNecessary3 stackEntryNecessary0 ? POP_X1 : // ...YO -> ...O stackEntryPresent0 ? POP2 : // ...YO -> ... POP : // ...Y -> ... // !stackEntryPresent1 stackEntryNecessary2 ? stackEntryNecessary3 ? stackEntryNecessary0 ? DUP_X1 : // ...XO -> ...OXO SWAP : // ...XO -> ...OX // !stackEntryNecessary3 stackEntryNecessary0 ? NOP : // ...XO -> ...XO stackEntryPresent0 ? POP : // ...XO -> ...X NOP : // ...X -> ...X stackEntryPresent2 ? stackEntryNecessary3 ? stackEntryNecessary0 ? SWAP_POP_DUP : // ...XO -> ...OO POP_X1 : // ...XO -> ...O // !stackEntryNecessary3 stackEntryNecessary0 ? POP_X1 : // ...XO -> ...O stackEntryPresent0 ? POP2 : // ...XO -> ... POP : // ...X -> ... // !stackEntryPresent2 stackEntryNecessary3 ? stackEntryNecessary0 ? DUP : // ...O -> ...OO NOP : // ...O -> ...O // !stackEntryNecessary3 stackEntryNecessary0 ? NOP : // ...O -> ...O stackEntryPresent0 ? POP : // ...O -> ... NOP; // ... -> ... } private int fixedDup2(int instructionOffset, int topBefore, int topAfter) { boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0); boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1); boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0); boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1); boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2); boolean stackEntryNecessary3 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 3); return stackEntryNecessary3 ? stackEntryNecessary2 ? stackEntryNecessary1 ? stackEntryNecessary0 ? DUP2 : // ...AB -> ...ABAB SWAP_DUP_X1 : // ...AB -> ...ABA // !stackEntryNecessary1 stackEntryNecessary0 ? DUP : // ...AB -> ...ABB NOP : // ...AB -> ...AB // !stackEntryNecessary2 stackEntryNecessary1 ? stackEntryNecessary0 ? SWAP_DUP_X1_SWAP : // ...AB -> ...AAB stackEntryPresent0 ? POP_DUP : // ...AB -> ...AA DUP : // ...A -> ...AA // !stackEntryNecessary1 stackEntryNecessary0 ? NOP : // ...AB -> ...AB stackEntryPresent0 ? POP : // ...AB -> ...A NOP : // ...A -> ...A // !stackEntryNecessary3 stackEntryNecessary2 ? stackEntryNecessary1 ? stackEntryNecessary0 ? DUP_X1 : // ...AB -> ...BAB SWAP : // ...AB -> ...BA stackEntryPresent1 ? stackEntryNecessary0 ? SWAP_POP_DUP : // ...AB -> ...BB POP_X1 : // ...AB -> ...B // !stackEntryPresent1 stackEntryNecessary0 ? POP : // ...B -> ...BB NOP : // ...B -> ...B // !stackEntryNecessary2 stackEntryNecessary1 ? stackEntryNecessary0 ? NOP : // ...AB -> ...AB stackEntryPresent0 ? POP : // ...AB -> ...A NOP : // ...A -> ...A stackEntryPresent1 ? stackEntryNecessary0 ? POP_X1 : // ...AB -> ...B stackEntryPresent0 ? POP2 : // ...AB -> ... POP : // ...A -> ... // !stackEntryPresent1 stackEntryNecessary0 ? NOP : // ...B -> ...B stackEntryPresent0 ? POP : // ...B -> ... NOP; // ... -> ... } private int fixedDup2_x1(int instructionOffset, int topBefore, int topAfter) { // We're currently assuming the value to be duplicated // is a long or a double, taking up two slots, or at // least consistent. boolean stackEntriesPresent01 = isStackEntriesPresentBefore(instructionOffset, topBefore - 0, topBefore - 1); boolean stackEntryPresent2 = isStackEntryPresentBefore( instructionOffset, topBefore - 2); boolean stackEntriesNecessary01 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 0, topAfter - 1); boolean stackEntryNecessary2 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 2); boolean stackEntriesNecessary34 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 3, topAfter - 4); // Figure out which stack entries should be moved, // copied, or removed. return stackEntryNecessary2 ? stackEntriesNecessary34 ? stackEntriesNecessary01 ? DUP2_X1 : // ...XAB -> ...ABXAB MOV2_X1 : // ...XAB -> ...ABX // !stackEntriesNecessary34 stackEntriesNecessary01 ? NOP : // ...XAB -> ...XAB stackEntriesPresent01 ? POP2 : // ...XAB -> ...X NOP : // ...X -> ...X stackEntryPresent2 ? stackEntriesNecessary34 ? stackEntriesNecessary01 ? UNSUPPORTED : // ...XAB -> ...ABAB POP_X2 : // ...XAB -> ...AB // !stackEntriesNecessary34 stackEntriesNecessary01 ? DUP2_X1_POP3 : // ...XAB -> ...AB stackEntriesPresent01 ? POP3 : // ...XAB -> ... POP : // ...X -> ... // !stackEntryPresent2 stackEntriesNecessary34 ? stackEntriesNecessary01 ? DUP2 : // ...AB -> ...ABAB NOP : // ...AB -> ...AB // !stackEntriesNecessary34 stackEntriesNecessary01 ? NOP : // ...AB -> ...AB stackEntriesPresent01 ? POP2 : // ...AB -> ... NOP; // ... -> ... } private int fixedDup2_x2(int instructionOffset, int topBefore, int topAfter) { // We're currently assuming the value to be duplicated // is a long or a double, taking up two slots, or at // least consistent. boolean stackEntriesPresent01 = isStackEntriesPresentBefore(instructionOffset, topBefore - 0, topBefore - 1); boolean stackEntryPresent2 = isStackEntryPresentBefore( instructionOffset, topBefore - 2); boolean stackEntryPresent3 = isStackEntryPresentBefore( instructionOffset, topBefore - 3); boolean stackEntriesNecessary01 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 0, topAfter - 1); boolean stackEntryNecessary2 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 2); boolean stackEntryNecessary3 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 3); boolean stackEntriesNecessary45 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 4, topAfter - 5); // Figure out which stack entries should be moved, // copied, or removed. return stackEntryNecessary2 ? stackEntryNecessary3 ? stackEntriesNecessary45 ? stackEntriesNecessary01 ? DUP2_X2 : // ...XYAB -> ...ABXYAB MOV2_X2 : // ...XYAB -> ...ABXY // !stackEntriesNecessary45 stackEntriesNecessary01 ? NOP : // ...XYAB -> ...XYAB stackEntriesPresent01 ? POP2 : // ...XYAB -> ...XY NOP : // ...XY -> ...XY stackEntryPresent3 ? stackEntriesNecessary45 ? stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABYAB DUP2_X2_SWAP_POP : // ...XYAB -> ...ABY // !stackEntriesNecessary45 stackEntriesNecessary01 ? POP_X3 : // ...XYAB -> ...YAB stackEntriesPresent01 ? POP2_SWAP_POP : // ...XYAB -> ...Y POP_X1 : // ...XY -> ...Y // !stackEntryPresent3 stackEntriesNecessary45 ? stackEntriesNecessary01 ? DUP2_X1 : // ...YAB -> ...ABYAB MOV2_X1 : // ...YAB -> ...ABY // !stackEntriesNecessary45 stackEntriesNecessary01 ? NOP : // ...YAB -> ...YAB stackEntriesPresent01 ? POP2 : // ...YAB -> ...Y NOP : // ...Y -> ...Y stackEntryPresent2 ? stackEntryNecessary3 ? stackEntriesNecessary45 ? stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABXAB DUP2_X2_POP3 : // ...XYAB -> ...ABX // !stackEntriesNecessary45 stackEntriesNecessary01 ? POP_X2 : // ...XYAB -> ...XAB stackEntriesPresent01 ? POP3 : // ...XYAB -> ...X POP : // ...XY -> ...X stackEntryPresent3 ? stackEntriesNecessary45 ? stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABAB POP2_X2 : // ...XYAB -> ...AB // !stackEntriesNecessary45 stackEntriesNecessary01 ? POP2_X2 : // ...XYAB -> ...AB stackEntriesPresent01 ? POP4 : // ...XYAB -> ... POP2 : // ...XY -> ... // !stackEntryPresent3 stackEntriesNecessary45 ? stackEntriesNecessary01 ? UNSUPPORTED : // ...YAB -> ...ABAB POP_X2 : // ...YAB -> ...AB // !stackEntriesNecessary45 stackEntriesNecessary01 ? POP_X2 : // ...YAB -> ...AB stackEntriesPresent01 ? POP3 : // ...YAB -> ... POP : // ...Y -> ... // !stackEntryPresent2 stackEntryNecessary3 ? stackEntriesNecessary45 ? stackEntriesNecessary01 ? DUP2_X1 : // ...XAB -> ...ABXAB MOV2_X1 : // ...XAB -> ...ABX // !stackEntriesNecessary45 stackEntriesNecessary01 ? NOP : // ...XAB -> ...XAB stackEntriesPresent01 ? POP2 : // ...XAB -> ...X NOP : // ...X -> ...X stackEntryPresent3 ? stackEntriesNecessary45 ? stackEntriesNecessary01 ? UNSUPPORTED : // ...XAB -> ...ABAB POP_X2 : // ...XAB -> ...AB // !stackEntriesNecessary45 stackEntriesNecessary01 ? POP_X2 : // ...XAB -> ...AB stackEntriesPresent01 ? POP3 : // ...XAB -> ... POP : // ...X -> ... // !stackEntryPresent3 stackEntriesNecessary45 ? stackEntriesNecessary01 ? DUP2 : // ...AB -> ...ABAB NOP : // ...AB -> ...AB // !stackEntriesNecessary45 stackEntriesNecessary01 ? NOP : // ...AB -> ...AB stackEntriesPresent01 ? POP2 : // ...AB -> ... NOP; // ... -> ... } private int fixedSwap(int instructionOffset, int topBefore, int topAfter) { boolean stackEntryPresent0 = isStackEntryPresentBefore(instructionOffset, topBefore - 0); boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1); boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0); boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1); // Figure out which stack entries should be moved // or removed. return stackEntryNecessary0 ? stackEntryNecessary1 ? SWAP : // ...AB -> ...BA stackEntryPresent0 ? POP : // ...AB -> ...A NOP : // ...A -> ...A stackEntryPresent1 ? POP_X1 : // ...AB -> ...B NOP; // ...B -> ...B } } // Small utility methods. /** * Marks the variable and the corresponding producing instructions * of the consumer at the given offset. * @param consumerOffset the offset of the consumer. * @param variableIndex the index of the variable to be marked. */ private void markVariableProducers(int consumerOffset, int variableIndex) { TracedVariables tracedVariables = partialEvaluator.getVariablesBefore(consumerOffset); // Mark the producer of the loaded value. markVariableProducers(tracedVariables.getProducerValue(variableIndex).instructionOffsetValue(), variableIndex); } /** * Marks the variable and its producing instructions at the given offsets. * @param producerOffsets the offsets of the producers to be marked. * @param variableIndex the index of the variable to be marked. */ private void markVariableProducers(InstructionOffsetValue producerOffsets, int variableIndex) { if (producerOffsets != null) { int offsetCount = producerOffsets.instructionOffsetCount(); for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++) { // Make sure the variable and the instruction are marked // at the producing offset. int offset = producerOffsets.instructionOffset(offsetIndex); markVariableAfter(offset, variableIndex); markInstruction(offset); } } } /** * Marks the stack entries and their producing instructions of the * consumer at the given offset. * @param clazz the containing class. * @param consumerOffset the offset of the consumer. * @param consumer the consumer of the stack entries. */ private void markStackProducers(Clazz clazz, int consumerOffset, Instruction consumer) { TracedStack tracedStack = partialEvaluator.getStackBefore(consumerOffset); int stackSize = tracedStack.size(); // Mark the producers of the popped values. int popCount = consumer.stackPopCount(clazz); for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++) { markStackEntryProducers(consumerOffset, stackIndex); } } /** * Marks the stack entry and the corresponding producing instructions * of the consumer at the given offset, if the stack entry of the * consumer is marked. * @param consumerOffset the offset of the consumer. * @param consumerTopStackIndex the index of the stack entry to be checked * (counting from the top). * @param producerTopStackIndex the index of the stack entry to be marked * (counting from the top). */ private void conditionallyMarkStackEntryProducers(int consumerOffset, int consumerTopStackIndex, int producerTopStackIndex) { int consumerBottomStackIndex = partialEvaluator.getStackAfter(consumerOffset).size() - consumerTopStackIndex - 1; if (isStackEntryNecessaryAfter(consumerOffset, consumerBottomStackIndex)) { int producerBottomStackIndex = partialEvaluator.getStackBefore(consumerOffset).size() - producerTopStackIndex - 1; markStackEntryProducers(consumerOffset, producerBottomStackIndex); } } /** * Marks the stack entry and the corresponding producing instructions * of the consumer at the given offset. * @param consumerOffset the offset of the consumer. * @param stackIndex the index of the stack entry to be marked * (counting from the bottom). */ private void markStackEntryProducers(int consumerOffset, int stackIndex) { if (!isStackSimplifiedBefore(consumerOffset, stackIndex)) { markStackEntryProducers(partialEvaluator.getStackBefore(consumerOffset).getBottomProducerValue(stackIndex).instructionOffsetValue(), stackIndex); } } /** * Marks the stack entry and its producing instructions at the given * offsets. * @param producerOffsets the offsets of the producers to be marked. * @param stackIndex the index of the stack entry to be marked * (counting from the bottom). */ private void markStackEntryProducers(InstructionOffsetValue producerOffsets, int stackIndex) { if (producerOffsets != null) { int offsetCount = producerOffsets.instructionOffsetCount(); for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++) { // Make sure the stack entry and the instruction are marked // at the producing offset. int offset = producerOffsets.instructionOffset(offsetIndex); markStackEntryAfter(offset, stackIndex); markInstruction(offset); } } } /** * Marks the stack entry and its initializing instruction * ('invokespecial *.') for the given 'new' instruction offset. * @param newInstructionOffset the offset of the 'new' instruction. */ private void markInitialization(int newInstructionOffset) { int initializationOffset = partialEvaluator.initializationOffset(newInstructionOffset); TracedStack tracedStack = partialEvaluator.getStackAfter(newInstructionOffset); markStackEntryAfter(initializationOffset, tracedStack.size() - 1); markInstruction(initializationOffset); } /** * Marks the branch instructions of straddling branches, if they straddle * some code that has been marked. * @param instructionOffset the offset of the branch origin or branch target. * @param branchOffsets the offsets of the straddling branch targets * or branch origins. * @param isPointingToTargets true if the above offsets are * branch targets, false if they * are branch origins. */ private void markStraddlingBranches(int instructionOffset, InstructionOffsetValue branchOffsets, boolean isPointingToTargets) { if (branchOffsets != null) { // Loop over all branch offsets. int branchCount = branchOffsets.instructionOffsetCount(); for (int branchIndex = 0; branchIndex < branchCount; branchIndex++) { // Is the branch straddling forward any necessary instructions? int branchOffset = branchOffsets.instructionOffset(branchIndex); // Is the offset pointing to a branch origin or to a branch target? if (isPointingToTargets) { markStraddlingBranch(instructionOffset, branchOffset, instructionOffset, branchOffset); } else { markStraddlingBranch(instructionOffset, branchOffset, branchOffset, instructionOffset); } } } } private void markStraddlingBranch(int instructionOffsetStart, int instructionOffsetEnd, int branchOrigin, int branchTarget) { if (!isInstructionNecessary(branchOrigin) && isAnyInstructionNecessary(instructionOffsetStart, instructionOffsetEnd)) { if (DEBUG) System.out.print("["+branchOrigin+"->"+branchTarget+"]"); // Mark the branch instruction. markInstruction(branchOrigin); } } /** * Pushes a specified type of stack entry before or at the given offset. * The instruction is marked as necessary. */ private void insertPushInstructions(int offset, boolean replace, int computationalType) { // Mark this instruction. markInstruction(offset); // Create a simple push instrucion. Instruction replacementInstruction = new SimpleInstruction(pushOpcode(computationalType)); if (DEBUG) System.out.println(": "+replacementInstruction.toString(offset)); // Replace or insert the push instruction. if (replace) { // Replace the push instruction. codeAttributeEditor.replaceInstruction(offset, replacementInstruction); } else { // Insert the push instruction. codeAttributeEditor.insertBeforeInstruction(offset, replacementInstruction); if (extraAddedInstructionVisitor != null) { replacementInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor); } } } /** * Returns the opcode of a push instruction corresponding to the given * computational type. * @param computationalType the computational type to be pushed on the stack. */ private byte pushOpcode(int computationalType) { switch (computationalType) { case Value.TYPE_INTEGER: return InstructionConstants.OP_ICONST_0; case Value.TYPE_LONG: return InstructionConstants.OP_LCONST_0; case Value.TYPE_FLOAT: return InstructionConstants.OP_FCONST_0; case Value.TYPE_DOUBLE: return InstructionConstants.OP_DCONST_0; case Value.TYPE_REFERENCE: case Value.TYPE_INSTRUCTION_OFFSET: return InstructionConstants.OP_ACONST_NULL; } throw new IllegalArgumentException("No push opcode for computational type ["+computationalType+"]"); } /** * Pops the given number of stack entries at or after the given offset. * The instructions are marked as necessary. */ private void insertPopInstructions(int offset, boolean replace, int popCount) { // Mark this instruction. markInstruction(offset); switch (popCount) { case 1: { // Replace or insert a single pop instruction. Instruction popInstruction = new SimpleInstruction(InstructionConstants.OP_POP); if (replace) { codeAttributeEditor.replaceInstruction(offset, popInstruction); } else { codeAttributeEditor.insertAfterInstruction(offset, popInstruction); if (extraAddedInstructionVisitor != null) { popInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor); } } break; } case 2: { // Replace or insert a single pop2 instruction. Instruction popInstruction = new SimpleInstruction(InstructionConstants.OP_POP2); if (replace) { codeAttributeEditor.replaceInstruction(offset, popInstruction); } else { codeAttributeEditor.insertAfterInstruction(offset, popInstruction); if (extraAddedInstructionVisitor != null) { popInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor); } } break; } default: { // Replace or insert the specified number of pop instructions. Instruction[] popInstructions = new Instruction[popCount / 2 + popCount % 2]; Instruction popInstruction = new SimpleInstruction(InstructionConstants.OP_POP2); for (int index = 0; index < popCount / 2; index++) { popInstructions[index] = popInstruction; } if (popCount % 2 == 1) { popInstruction = new SimpleInstruction(InstructionConstants.OP_POP); popInstructions[popCount / 2] = popInstruction; } if (replace) { codeAttributeEditor.replaceInstruction(offset, popInstructions); for (int index = 1; index < popInstructions.length; index++) { if (extraAddedInstructionVisitor != null) { popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor); } } } else { codeAttributeEditor.insertAfterInstruction(offset, popInstructions); for (int index = 0; index < popInstructions.length; index++) { if (extraAddedInstructionVisitor != null) { popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor); } } } break; } } } /** * Replaces the instruction at a given offset by a static invocation. */ private void replaceByStaticInvocation(Clazz clazz, int offset, ConstantInstruction constantInstruction) { // Remember the replacement instruction. Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, constantInstruction.constantIndex).shrink(); if (DEBUG) System.out.println(" Replacing by static invocation "+constantInstruction.toString(offset)+" -> "+replacementInstruction.toString()); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); } /** * Replaces the given instruction by an infinite loop. */ private void replaceByInfiniteLoop(Clazz clazz, int offset) { if (DEBUG) System.out.println(" Inserting infinite loop at ["+offset+"]"); // Mark the instruction. markInstruction(offset); // Replace the instruction by an infinite loop. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO, 0); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); } // Small utility methods. /** * Returns whether the given instruction is a dup or swap instruction * (dup, dup_x1, dup_x2, dup2, dup2_x1, dup2_x2, swap). */ private boolean isDupOrSwap(Instruction instruction) { return instruction.opcode >= InstructionConstants.OP_DUP && instruction.opcode <= InstructionConstants.OP_SWAP; } /** * Returns whether the given instruction is a pop instruction * (pop, pop2). */ private boolean isPop(Instruction instruction) { return instruction.opcode == InstructionConstants.OP_POP || instruction.opcode == InstructionConstants.OP_POP2; } /** * Returns whether any traced but unnecessary instruction between the two * given offsets is branching over the second given offset. */ private boolean isAnyUnnecessaryInstructionBranchingOver(int instructionOffset1, int instructionOffset2) { for (int offset = instructionOffset1; offset < instructionOffset2; offset++) { // Is it a traced but unmarked straddling branch? if (partialEvaluator.isTraced(offset) && !isInstructionNecessary(offset) && isAnyLargerThan(partialEvaluator.branchTargets(offset), instructionOffset2)) { return true; } } return false; } /** * Returns whether all of the given instruction offsets (at least one) * are smaller than or equal to the given offset. */ private boolean isAllSmallerThanOrEqual(InstructionOffsetValue instructionOffsets, int instructionOffset) { if (instructionOffsets != null) { // Loop over all instruction offsets. int branchCount = instructionOffsets.instructionOffsetCount(); if (branchCount > 0) { for (int branchIndex = 0; branchIndex < branchCount; branchIndex++) { // Is the offset larger than the reference offset? if (instructionOffsets.instructionOffset(branchIndex) > instructionOffset) { return false; } } return true; } } return false; } /** * Returns whether any of the given instruction offsets (at least one) * is larger than the given offset. */ private boolean isAnyLargerThan(InstructionOffsetValue instructionOffsets, int instructionOffset) { if (instructionOffsets != null) { // Loop over all instruction offsets. int branchCount = instructionOffsets.instructionOffsetCount(); if (branchCount > 0) { for (int branchIndex = 0; branchIndex < branchCount; branchIndex++) { // Is the offset larger than the reference offset? if (instructionOffsets.instructionOffset(branchIndex) > instructionOffset) { return true; } } } } return false; } /** * Initializes the necessary data structure. */ private void initializeNecessary(CodeAttribute codeAttribute) { int codeLength = codeAttribute.u4codeLength; int maxLocals = codeAttribute.u2maxLocals; int maxStack = codeAttribute.u2maxStack; // Create new arrays for storing information at each instruction offset. if (variablesNecessaryAfter.length < codeLength || variablesNecessaryAfter[0].length < maxLocals) { variablesNecessaryAfter = new boolean[codeLength][maxLocals]; } else { for (int offset = 0; offset < codeLength; offset++) { Arrays.fill(variablesNecessaryAfter[offset], 0, maxLocals, false); } } if (stacksNecessaryAfter.length < codeLength || stacksNecessaryAfter[0].length < maxStack) { stacksNecessaryAfter = new boolean[codeLength][maxStack]; } else { for (int offset = 0; offset < codeLength; offset++) { Arrays.fill(stacksNecessaryAfter[offset], 0, maxStack, false); } } if (stacksSimplifiedBefore.length < codeLength || stacksSimplifiedBefore[0].length < maxStack) { stacksSimplifiedBefore = new boolean[codeLength][maxStack]; } else { for (int offset = 0; offset < codeLength; offset++) { Arrays.fill(stacksSimplifiedBefore[offset], 0, maxStack, false); } } if (instructionsNecessary.length < codeLength) { instructionsNecessary = new boolean[codeLength]; } else { Arrays.fill(instructionsNecessary, 0, codeLength, false); } } /** * Returns whether the specified variable is initialized at the specified * offset. */ private boolean isVariableInitialization(int instructionOffset, int variableIndex) { // Wasn't the variable set yet? Value valueBefore = partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex); if (valueBefore == null) { return true; } // Is the computational type different now? Value valueAfter = partialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex); if (valueAfter.computationalType() != valueBefore.computationalType()) { return true; } // Was the producer an argument (which may be removed)? Value producersBefore = partialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex); return producersBefore.instructionOffsetValue().instructionOffsetCount() == 1 && producersBefore.instructionOffsetValue().instructionOffset(0) == PartialEvaluator.AT_METHOD_ENTRY; } /** * Returns whether the specified variable must be initialized at the * specified offset, according to the verifier of the JVM. */ private boolean isVariableInitializationNecessary(Clazz clazz, Method method, CodeAttribute codeAttribute, int initializationOffset, int variableIndex) { int codeLength = codeAttribute.u4codeLength; // Is the variable necessary anywhere at all? if (isVariableNecessaryAfterAny(0, codeLength, variableIndex)) { if (DEBUG) System.out.println("Simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]"); // Lazily perform simple partial evaluation, the way the JVM // verifier would do it. simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); if (DEBUG) System.out.println("End of simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]"); // Check if the variable is necessary elsewhere. for (int offset = 0; offset < codeLength; offset++) { if (partialEvaluator.isTraced(offset)) { Value producer = partialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex); if (producer != null) { Value simpleProducer = simplePartialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex); if (simpleProducer != null) { InstructionOffsetValue producerOffsets = producer.instructionOffsetValue(); InstructionOffsetValue simpleProducerOffsets = simpleProducer.instructionOffsetValue(); if (DEBUG) { System.out.println(" ["+offset+"] producers ["+producerOffsets+"], simple producers ["+simpleProducerOffsets+"]"); } // Is the variable being used without all of its // immediate simple producers being marked? if (isVariableNecessaryAfterAny(producerOffsets, variableIndex) && !isVariableNecessaryAfterAll(simpleProducerOffsets, variableIndex)) { if (DEBUG) { System.out.println(" => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] necessary"); } // Then the initialization may be necessary. return true; } } } } } } if (DEBUG) { System.out.println(" => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] not necessary"); } return false; } private void markVariableAfter(int instructionOffset, int variableIndex) { if (!isVariableNecessaryAfter(instructionOffset, variableIndex)) { if (DEBUG) System.out.print("["+instructionOffset+".v"+variableIndex+"],"); variablesNecessaryAfter[instructionOffset][variableIndex] = true; if (maxMarkedOffset < instructionOffset) { maxMarkedOffset = instructionOffset; } } } /** * Returns whether the specified variable is ever necessary after any * instructions in the specified block. */ private boolean isVariableNecessaryAfterAny(int startOffset, int endOffset, int variableIndex) { for (int offset = startOffset; offset < endOffset; offset++) { if (isVariableNecessaryAfter(offset, variableIndex)) { return true; } } return false; } /** * Returns whether the specified variable is ever necessary after any * instructions in the specified set of instructions offsets. */ private boolean isVariableNecessaryAfterAny(InstructionOffsetValue instructionOffsetValue, int variableIndex) { int count = instructionOffsetValue.instructionOffsetCount(); for (int index = 0; index < count; index++) { if (isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index), variableIndex)) { return true; } } return false; } /** * Returns whether the specified variable is ever necessary after all * instructions in the specified set of instructions offsets. */ private boolean isVariableNecessaryAfterAll(InstructionOffsetValue instructionOffsetValue, int variableIndex) { int count = instructionOffsetValue.instructionOffsetCount(); for (int index = 0; index < count; index++) { if (!isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index), variableIndex)) { return false; } } return true; } private boolean isVariableNecessaryAfter(int instructionOffset, int variableIndex) { return instructionOffset == PartialEvaluator.AT_METHOD_ENTRY || variablesNecessaryAfter[instructionOffset][variableIndex]; } /** * Marks the stack entry after the given offset. * @param instructionOffset the offset of the stack entry to be marked. * @param stackIndex the index of the stack entry to be marked * (counting from the bottom). */ private void markStackEntryAfter(int instructionOffset, int stackIndex) { if (!isStackEntryNecessaryAfter(instructionOffset, stackIndex)) { if (DEBUG) System.out.print("["+instructionOffset+".s"+stackIndex+"],"); stacksNecessaryAfter[instructionOffset][stackIndex] = true; if (maxMarkedOffset < instructionOffset) { maxMarkedOffset = instructionOffset; } } } /** * Returns whether the stack specified entries before the given offset are * present. */ private boolean isStackEntriesPresentBefore(int instructionOffset, int stackIndex1, int stackIndex2) { boolean present1 = isStackEntryPresentBefore(instructionOffset, stackIndex1); boolean present2 = isStackEntryPresentBefore(instructionOffset, stackIndex2); // if (present1 ^ present2) // { // throw new UnsupportedOperationException("Can't handle partial use of dup2 instructions"); // } return present1 || present2; } /** * Returns whether the specified stack entry before the given offset is * present. * @param instructionOffset the offset of the stack entry to be checked. * @param stackIndex the index of the stack entry to be checked * (counting from the bottom). */ private boolean isStackEntryPresentBefore(int instructionOffset, int stackIndex) { TracedStack tracedStack = partialEvaluator.getStackBefore(instructionOffset); InstructionOffsetValue producerOffsets = tracedStack.getBottomProducerValue(stackIndex).instructionOffsetValue(); return isAnyStackEntryNecessaryAfter(producerOffsets, stackIndex); } /** * Returns whether the stack specified entries after the given offset are * necessary. */ private boolean isStackEntriesNecessaryAfter(int instructionOffset, int stackIndex1, int stackIndex2) { boolean present1 = isStackEntryNecessaryAfter(instructionOffset, stackIndex1); boolean present2 = isStackEntryNecessaryAfter(instructionOffset, stackIndex2); // if (present1 ^ present2) // { // throw new UnsupportedOperationException("Can't handle partial use of dup2 instructions"); // } return present1 || present2; } /** * Returns whether any of the stack entries after the given offsets are * necessary. * @param instructionOffsets the offsets of the stack entries to be checked. * @param stackIndex the index of the stack entries to be checked * (counting from the bottom). */ private boolean isAnyStackEntryNecessaryAfter(InstructionOffsetValue instructionOffsets, int stackIndex) { int offsetCount = instructionOffsets.instructionOffsetCount(); for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++) { if (isStackEntryNecessaryAfter(instructionOffsets.instructionOffset(offsetIndex), stackIndex)) { return true; } } return false; } /** * Returns whether the specified stack entry after the given offset is * necessary. * @param instructionOffset the offset of the stack entry to be checked. * @param stackIndex the index of the stack entry to be checked * (counting from the bottom). */ private boolean isStackEntryNecessaryAfter(int instructionOffset, int stackIndex) { return instructionOffset == PartialEvaluator.AT_CATCH_ENTRY || stacksNecessaryAfter[instructionOffset][stackIndex]; } private void markStackSimplificationBefore(int instructionOffset, int stackIndex) { stacksSimplifiedBefore[instructionOffset][stackIndex] = true; } private boolean isStackSimplifiedBefore(int instructionOffset, int stackIndex) { return stacksSimplifiedBefore[instructionOffset][stackIndex]; } private void markInstruction(int instructionOffset) { if (!isInstructionNecessary(instructionOffset)) { if (DEBUG) System.out.print(instructionOffset+","); instructionsNecessary[instructionOffset] = true; if (maxMarkedOffset < instructionOffset) { maxMarkedOffset = instructionOffset; } } } private boolean isAnyInstructionNecessary(int instructionOffset1, int instructionOffset2) { for (int instructionOffset = instructionOffset1; instructionOffset < instructionOffset2; instructionOffset++) { if (isInstructionNecessary(instructionOffset)) { return true; } } return false; } /** * Returns the highest offset of an instruction that has been marked as * necessary, before the given offset. */ private int lastNecessaryInstructionOffset(int instructionOffset) { for (int offset = instructionOffset-1; offset >= 0; offset--) { if (isInstructionNecessary(instructionOffset)) { return offset; } } return 0; } private boolean isInstructionNecessary(int instructionOffset) { return instructionOffset == PartialEvaluator.AT_METHOD_ENTRY || instructionsNecessary[instructionOffset]; } }proguard4.8/src/proguard/optimize/evaluation/TracedBranchUnit.java0000644000175000017500000000400611736333525024235 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.evaluation; import proguard.classfile.Clazz; import proguard.classfile.attribute.CodeAttribute; import proguard.evaluation.BasicBranchUnit; import proguard.evaluation.value.Value; /** * This BranchUnit remembers the branch unit commands that are invoked on it. * * @author Eric Lafortune */ class TracedBranchUnit extends BasicBranchUnit { // Implementations for BranchUnit. public void branchConditionally(Clazz clazz, CodeAttribute codeAttribute, int offset, int branchTarget, int conditional) { if (conditional == Value.ALWAYS) { // Always branch. super.branch(clazz, codeAttribute, offset, branchTarget); } else if (conditional != Value.NEVER) { // Maybe branch. super.branchConditionally(clazz, codeAttribute, offset, branchTarget, conditional); } else { super.setCalled(); } } } proguard4.8/src/proguard/optimize/evaluation/LivenessAnalyzer.java0000664000175000017500000004256511736333525024371 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.evaluation; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.evaluation.value.*; /** * This AttributeVisitor analyzes the liveness of the variables in the code * attributes that it visits, based on partial evaluation. * * @author Eric Lafortune */ public class LivenessAnalyzer extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private static final int MAX_VARIABLES_SIZE = 64; private final PartialEvaluator partialEvaluator; private long[] isAliveBefore = new long[ClassConstants.TYPICAL_CODE_LENGTH]; private long[] isAliveAfter = new long[ClassConstants.TYPICAL_CODE_LENGTH]; private long[] isCategory2 = new long[ClassConstants.TYPICAL_CODE_LENGTH]; // Fields acting as global temporary variables. private boolean checkAgain; private long alive; /** * Creates a new LivenessAnalyzer. */ public LivenessAnalyzer() { this(new PartialEvaluator()); } /** * Creates a new LivenessAnalyzer that will use the given partial evaluator. * It will run this evaluator on every code attribute that it visits. */ public LivenessAnalyzer(PartialEvaluator partialEvaluator) { this.partialEvaluator = partialEvaluator; } /** * Returns whether the instruction at the given offset has ever been * executed during the partial evaluation. */ public boolean isTraced(int instructionOffset) { return partialEvaluator.isTraced(instructionOffset); } /** * Returns whether the specified variable is alive before the instruction * at the given offset. */ public boolean isAliveBefore(int instructionOffset, int variableIndex) { return variableIndex >= MAX_VARIABLES_SIZE || (isAliveBefore[instructionOffset] & (1L << variableIndex)) != 0; } /** * Sets whether the specified variable is alive before the instruction * at the given offset. */ public void setAliveBefore(int instructionOffset, int variableIndex, boolean alive) { if (variableIndex < MAX_VARIABLES_SIZE) { if (alive) { isAliveBefore[instructionOffset] |= 1L << variableIndex; } else { isAliveBefore[instructionOffset] &= ~(1L << variableIndex); } } } /** * Returns whether the specified variable is alive after the instruction * at the given offset. */ public boolean isAliveAfter(int instructionOffset, int variableIndex) { return variableIndex >= MAX_VARIABLES_SIZE || (isAliveAfter[instructionOffset] & (1L << variableIndex)) != 0; } /** * Sets whether the specified variable is alive after the instruction * at the given offset. */ public void setAliveAfter(int instructionOffset, int variableIndex, boolean alive) { if (variableIndex < MAX_VARIABLES_SIZE) { if (alive) { isAliveAfter[instructionOffset] |= 1L << variableIndex; } else { isAliveAfter[instructionOffset] &= ~(1L << variableIndex); } } } /** * Returns whether the specified variable takes up two entries after the * instruction at the given offset. */ public boolean isCategory2(int instructionOffset, int variableIndex) { return variableIndex < MAX_VARIABLES_SIZE && (isCategory2[instructionOffset] & (1L << variableIndex)) != 0; } /** * Sets whether the specified variable takes up two entries after the * instruction at the given offset. */ public void setCategory2(int instructionOffset, int variableIndex, boolean category2) { if (variableIndex < MAX_VARIABLES_SIZE) { if (category2) { isCategory2[instructionOffset] |= 1L << variableIndex; } else { isCategory2[instructionOffset] &= ~(1L << variableIndex); } } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); if (DEBUG) { System.out.println(); System.out.println("Liveness analysis: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); } // Initialize the global arrays. initializeArrays(codeAttribute); // Evaluate the method. partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); int codeLength = codeAttribute.u4codeLength; int variablesSize = codeAttribute.u2maxLocals; // We'll only really analyze the first 64 variables. if (variablesSize > MAX_VARIABLES_SIZE) { variablesSize = MAX_VARIABLES_SIZE; } // Mark liveness blocks, as many times as necessary. do { checkAgain = false; alive = 0L; // Loop over all traced instructions, backward. for (int offset = codeLength - 1; offset >= 0; offset--) { if (partialEvaluator.isTraced(offset)) { // Update the liveness based on the branch targets. InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset); if (branchTargets != null) { // Update the liveness right after the branch instruction. alive = combinedLiveness(branchTargets); } // Merge the current liveness. alive |= isAliveAfter[offset]; // Update the liveness after the instruction. isAliveAfter[offset] = alive; // Update the current liveness based on the instruction. codeAttribute.instructionAccept(clazz, method, offset, this); // Merge the current liveness. alive |= isAliveBefore[offset]; // Update the liveness before the instruction. if ((~isAliveBefore[offset] & alive) != 0L) { isAliveBefore[offset] = alive; // Do we have to check again after this loop? checkAgain |= offset < maxOffset(partialEvaluator.branchOrigins(offset)); } } } // Account for the liveness at the start of the exception handlers. codeAttribute.exceptionsAccept(clazz, method, this); } while (checkAgain); // Loop over all instructions, to mark variables that take up two entries. for (int offset = 0; offset < codeLength; offset++) { if (partialEvaluator.isTraced(offset)) { // Loop over all variables. for (int variableIndex = 0; variableIndex < variablesSize; variableIndex++) { // Is the variable alive and a category 2 type? if (isAliveBefore(offset, variableIndex)) { Value value = partialEvaluator.getVariablesBefore(offset).getValue(variableIndex); if (value != null && value.isCategory2()) { // Mark it as such. setCategory2(offset, variableIndex, true); // Mark the next variable as well. setAliveBefore(offset, variableIndex + 1, true); setCategory2( offset, variableIndex + 1, true); } } // Is the variable alive and a category 2 type? if (isAliveAfter(offset, variableIndex)) { Value value = partialEvaluator.getVariablesAfter(offset).getValue(variableIndex); if (value != null && value.isCategory2()) { // Mark it as such. setCategory2(offset, variableIndex, true); // Mark the next variable as well. setAliveAfter(offset, variableIndex + 1, true); setCategory2( offset, variableIndex + 1, true); } } } } } if (DEBUG) { // Loop over all instructions. for (int offset = 0; offset < codeLength; offset++) { if (partialEvaluator.isTraced(offset)) { long aliveBefore = isAliveBefore[offset]; long aliveAfter = isAliveAfter[offset]; long category2 = isCategory2[offset]; // Print out the liveness of all variables before the instruction. for (int variableIndex = 0; variableIndex < variablesSize; variableIndex++) { long variableMask = (1L << variableIndex); System.out.print((aliveBefore & variableMask) == 0L ? '.' : (category2 & variableMask) == 0L ? 'x' : '*'); } // Print out the instruction itself. System.out.println(" "+ InstructionFactory.create(codeAttribute.code, offset).toString(offset)); // Print out the liveness of all variables after the instruction. for (int variableIndex = 0; variableIndex < variablesSize; variableIndex++) { long variableMask = (1L << variableIndex); System.out.print((aliveAfter & variableMask) == 0L ? '.' : (category2 & variableMask) == 0L ? 'x' : '='); } System.out.println(); } } } } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { int variableIndex = variableInstruction.variableIndex; if (variableIndex < MAX_VARIABLES_SIZE) { long livenessMask = 1L << variableIndex; // Is it a load instruction or a store instruction? if (variableInstruction.isLoad()) { // Start marking the variable before the load instruction. alive |= livenessMask; } else { // Stop marking the variable before the store instruction. alive &= ~livenessMask; // But do mark the variable right after the store instruction. isAliveAfter[offset] |= livenessMask; } } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Special case: variable 0 ('this') in an initializer has to be alive // as long as it hasn't been initialized. if (offset == partialEvaluator.superInitializationOffset()) { alive |= 1L; } } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { // Are any variables alive at the start of the handler? long alive = isAliveBefore[exceptionInfo.u2handlerPC]; if (alive != 0L) { // Set the same liveness flags for the entire try block. int startOffset = exceptionInfo.u2startPC; int endOffset = exceptionInfo.u2endPC; for (int offset = startOffset; offset < endOffset; offset++) { if (partialEvaluator.isTraced(offset)) { if ((~(isAliveBefore[offset] & isAliveAfter[offset]) & alive) != 0L) { isAliveBefore[offset] |= alive; isAliveAfter[offset] |= alive; // Check again after having marked this try block. checkAgain = true; } } } } } // Small utility methods. /** * Initializes the global arrays. */ private void initializeArrays(CodeAttribute codeAttribute) { int codeLength = codeAttribute.u4codeLength; // Create new arrays for storing information at each instruction offset. if (isAliveBefore.length < codeLength) { isAliveBefore = new long[codeLength]; isAliveAfter = new long[codeLength]; isCategory2 = new long[codeLength]; } else { for (int index = 0; index < codeLength; index++) { isAliveBefore[index] = 0L; isAliveAfter[index] = 0L; isCategory2[index] = 0L; } } } /** * Returns the combined liveness mask of the variables right before the * specified instruction offsets. */ private long combinedLiveness(InstructionOffsetValue instructionOffsetValue) { long alive = 0L; int count = instructionOffsetValue.instructionOffsetCount(); for (int index = 0; index < count; index++) { alive |= isAliveBefore[instructionOffsetValue.instructionOffset(index)]; } return alive; } /** * Returns the minimum offset from the given instruction offsets. */ private int minOffset(Value instructionOffsets) { return minOffset(instructionOffsets, Integer.MAX_VALUE); } /** * Returns the minimum offset from the given instruction offsets. */ private int minOffset(Value instructionOffsets, int minOffset) { if (instructionOffsets != null) { InstructionOffsetValue instructionOffsetValue = instructionOffsets.instructionOffsetValue(); int count = instructionOffsetValue.instructionOffsetCount(); for (int index = 0; index < count; index++) { int offset = instructionOffsetValue.instructionOffset(index); if (minOffset > offset) { minOffset = offset; } } } return minOffset; } /** * Returns the maximum offset from the given instruction offsets. */ private int maxOffset(Value instructionOffsets) { return maxOffset(instructionOffsets, Integer.MIN_VALUE); } /** * Returns the maximum offset from the given instruction offsets. */ private int maxOffset(Value instructionOffsets, int maxOffset) { if (instructionOffsets != null) { InstructionOffsetValue instructionOffsetValue = instructionOffsets.instructionOffsetValue(); int count = instructionOffsetValue.instructionOffsetCount(); for (int index = 0; index < count; index++) { int offset = instructionOffsetValue.instructionOffset(index); if (maxOffset < offset) { maxOffset = offset; } } } return maxOffset; } } proguard4.8/src/proguard/optimize/evaluation/LoadingInvocationUnit.java0000644000175000017500000001521111736333525025324 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.evaluation; import proguard.classfile.*; import proguard.classfile.constant.RefConstant; import proguard.evaluation.BasicInvocationUnit; import proguard.evaluation.value.*; /** * This InvocationUbit loads parameter values and return values that were * previously stored with the methods that are invoked. * * @see StoringInvocationUnit * @author Eric Lafortune */ public class LoadingInvocationUnit extends BasicInvocationUnit { private final boolean loadFieldValues; private final boolean loadMethodParameterValues; private final boolean loadMethodReturnValues; /** * Creates a new LoadingInvocationUnit with the given value factory. */ public LoadingInvocationUnit(ValueFactory valueFactory) { this(valueFactory, false, false, false); } /** * Creates a new LoadingInvocationUnit with the given value factory, for * loading the specified values. */ public LoadingInvocationUnit(ValueFactory valueFactory, boolean loadFieldValues, boolean loadMethodParameterValues, boolean loadMethodReturnValues) { super(valueFactory); this.loadFieldValues = loadFieldValues; this.loadMethodParameterValues = loadMethodParameterValues; this.loadMethodReturnValues = loadMethodReturnValues; } // Implementations for BasicInvocationUnit. protected Value getFieldClassValue(Clazz clazz, RefConstant refConstant, String type) { if (loadFieldValues) { // Do we know this field? Member referencedMember = refConstant.referencedMember; if (referencedMember != null) { // Retrieve the stored field class value. ReferenceValue value = StoringInvocationUnit.getFieldClassValue((Field)referencedMember); if (value != null && value.isParticular()) { return value; } } } return super.getFieldClassValue(clazz, refConstant, type); } protected Value getFieldValue(Clazz clazz, RefConstant refConstant, String type) { if (loadFieldValues) { // Do we know this field? Member referencedMember = refConstant.referencedMember; if (referencedMember != null) { // Retrieve the stored field value. Value value = StoringInvocationUnit.getFieldValue((Field)referencedMember); if (value != null && value.isParticular()) { return value; } } } return super.getFieldValue(clazz, refConstant, type); } protected Value getMethodParameterValue(Clazz clazz, Method method, int parameterIndex, String type, Clazz referencedClass) { if (loadMethodParameterValues) { // Retrieve the stored method parameter value. Value value = StoringInvocationUnit.getMethodParameterValue(method, parameterIndex); if (value != null && value.isParticular()) { return value; } } return super.getMethodParameterValue(clazz, method, parameterIndex, type, referencedClass); } protected Value getMethodReturnValue(Clazz clazz, RefConstant refConstant, String type) { if (loadMethodReturnValues) { // Do we know this method? Member referencedMember = refConstant.referencedMember; if (referencedMember != null) { // Retrieve the stored method return value. Value value = StoringInvocationUnit.getMethodReturnValue((Method)referencedMember); if (value != null && value.isParticular()) { return value; } } } return super.getMethodReturnValue(clazz, refConstant, type); } // // Small utility methods. // // private Value refresh(Value value) // { // if (value.isParticular()) // { // return value; // } // // switch (value.computationalType()) // { // case Value.TYPE_INTEGER: return valueFactory.createIntegerValue(); // case Value.TYPE_LONG: return valueFactory.createLongValue(); // case Value.TYPE_FLOAT: return valueFactory.createFloatValue(); // case Value.TYPE_DOUBLE: return valueFactory.createDoubleValue(); // default: // { // ReferenceValue referenceValue = value.referenceValue(); // // return valueFactory.createReferenceValue(referenceValue.getType(), // referenceValue.getReferencedClass(), // referenceValue.isNull() != Value.NEVER); // } // } // } } proguard4.8/src/proguard/optimize/evaluation/StoringInvocationUnit.java0000644000175000017500000001452411736333525025402 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.evaluation; import proguard.classfile.*; import proguard.classfile.constant.RefConstant; import proguard.evaluation.BasicInvocationUnit; import proguard.evaluation.value.*; import proguard.optimize.info.*; /** * This InvocationUbit stores parameter values and return values with the * methods that are invoked. * * @see LoadingInvocationUnit * @author Eric Lafortune */ public class StoringInvocationUnit extends BasicInvocationUnit { private boolean storeFieldValues; private boolean storeMethodParameterValues; private boolean storeMethodReturnValues; /** * Creates a new StoringInvocationUnit with the given value factory. */ public StoringInvocationUnit(ValueFactory valueFactory) { this(valueFactory, true, true, true); } /** * Creates a new StoringInvocationUnit with the given value factory, for * storing the specified values. */ public StoringInvocationUnit(ValueFactory valueFactory, boolean storeFieldValues, boolean storeMethodParameterValues, boolean storeMethodReturnValues) { super(valueFactory); this.storeFieldValues = storeFieldValues; this.storeMethodParameterValues = storeMethodParameterValues; this.storeMethodReturnValues = storeMethodReturnValues; } // Implementations for BasicInvocationUnit. protected void setFieldClassValue(Clazz clazz, RefConstant refConstant, ReferenceValue value) { if (storeFieldValues) { Member referencedMember = refConstant.referencedMember; if (referencedMember != null) { generalizeFieldClassValue((Field)referencedMember, value); } } } protected void setFieldValue(Clazz clazz, RefConstant refConstant, Value value) { if (storeFieldValues) { Member referencedMember = refConstant.referencedMember; if (referencedMember != null) { generalizeFieldValue((Field)referencedMember, value); } } } protected void setMethodParameterValue(Clazz clazz, RefConstant refConstant, int parameterIndex, Value value) { if (storeMethodParameterValues) { Member referencedMember = refConstant.referencedMember; if (referencedMember != null) { generalizeMethodParameterValue((Method)referencedMember, parameterIndex, value); } } } protected void setMethodReturnValue(Clazz clazz, Method method, Value value) { if (storeMethodReturnValues) { generalizeMethodReturnValue(method, value); } } // Small utility methods. private static void generalizeFieldClassValue(Field field, ReferenceValue value) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); if (info != null) { info.generalizeReferencedClass(value); } } public static ReferenceValue getFieldClassValue(Field field) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); return info != null ? info.getReferencedClass() : null; } private static void generalizeFieldValue(Field field, Value value) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); if (info != null) { info.generalizeValue(value); } } public static Value getFieldValue(Field field) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); return info != null ? info.getValue() : null; } private static void generalizeMethodParameterValue(Method method, int parameterIndex, Value value) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.generalizeParameter(parameterIndex, value); } } public static Value getMethodParameterValue(Method method, int parameterIndex) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info != null ? info.getParameter(parameterIndex) : null; } private static void generalizeMethodReturnValue(Method method, Value value) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.generalizeReturnValue(value); } } public static Value getMethodReturnValue(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info != null ? info.getReturnValue() : null; } } proguard4.8/src/proguard/optimize/evaluation/EvaluationSimplifier.java0000664000175000017500000011602711736333525025221 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.evaluation; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.editor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.info.*; /** * This AttributeVisitor simplifies the code attributes that it visits, based * on partial evaluation. * * @author Eric Lafortune */ public class EvaluationSimplifier extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor { private static final int POS_ZERO_FLOAT_BITS = Float.floatToIntBits(0.0f); private static final long POS_ZERO_DOUBLE_BITS = Double.doubleToLongBits(0.0); //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final InstructionVisitor extraInstructionVisitor; private final PartialEvaluator partialEvaluator; private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true); private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); /** * Creates a new EvaluationSimplifier. */ public EvaluationSimplifier() { this(new PartialEvaluator(), null); } /** * Creates a new EvaluationSimplifier. * @param partialEvaluator the partial evaluator that will * execute the code and provide * information about the results. * @param extraInstructionVisitor an optional extra visitor for all * simplified instructions. */ public EvaluationSimplifier(PartialEvaluator partialEvaluator, InstructionVisitor extraInstructionVisitor) { this.partialEvaluator = partialEvaluator; this.extraInstructionVisitor = extraInstructionVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // TODO: Remove this when the evaluation simplifier has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while simplifying instructions after partial evaluation:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); System.err.println("Not optimizing this method"); if (DEBUG) { method.accept(clazz, new ClassPrinter()); throw ex; } } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (DEBUG) { System.out.println(); System.out.println("Class "+ClassUtil.externalClassName(clazz.getName())); System.out.println("Method "+ClassUtil.externalFullMethodDescription(clazz.getName(), 0, method.getName(clazz), method.getDescriptor(clazz))); } // Evaluate the method. partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); int codeLength = codeAttribute.u4codeLength; // Reset the code changes. codeAttributeEditor.reset(codeLength); // Replace any instructions that can be simplified. for (int offset = 0; offset < codeLength; offset++) { if (partialEvaluator.isTraced(offset)) { Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); instruction.accept(clazz, method, codeAttribute, offset, this); } } // Apply all accumulated changes to the code. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { switch (simpleInstruction.opcode) { case InstructionConstants.OP_IALOAD: case InstructionConstants.OP_BALOAD: case InstructionConstants.OP_CALOAD: case InstructionConstants.OP_SALOAD: case InstructionConstants.OP_IADD: case InstructionConstants.OP_ISUB: case InstructionConstants.OP_IMUL: case InstructionConstants.OP_IDIV: case InstructionConstants.OP_IREM: case InstructionConstants.OP_INEG: case InstructionConstants.OP_ISHL: case InstructionConstants.OP_ISHR: case InstructionConstants.OP_IUSHR: case InstructionConstants.OP_IAND: case InstructionConstants.OP_IOR: case InstructionConstants.OP_IXOR: case InstructionConstants.OP_L2I: case InstructionConstants.OP_F2I: case InstructionConstants.OP_D2I: case InstructionConstants.OP_I2B: case InstructionConstants.OP_I2C: case InstructionConstants.OP_I2S: replaceIntegerPushInstruction(clazz, offset, simpleInstruction); break; case InstructionConstants.OP_LALOAD: case InstructionConstants.OP_LADD: case InstructionConstants.OP_LSUB: case InstructionConstants.OP_LMUL: case InstructionConstants.OP_LDIV: case InstructionConstants.OP_LREM: case InstructionConstants.OP_LNEG: case InstructionConstants.OP_LSHL: case InstructionConstants.OP_LSHR: case InstructionConstants.OP_LUSHR: case InstructionConstants.OP_LAND: case InstructionConstants.OP_LOR: case InstructionConstants.OP_LXOR: case InstructionConstants.OP_I2L: case InstructionConstants.OP_F2L: case InstructionConstants.OP_D2L: replaceLongPushInstruction(clazz, offset, simpleInstruction); break; case InstructionConstants.OP_FALOAD: case InstructionConstants.OP_FADD: case InstructionConstants.OP_FSUB: case InstructionConstants.OP_FMUL: case InstructionConstants.OP_FDIV: case InstructionConstants.OP_FREM: case InstructionConstants.OP_FNEG: case InstructionConstants.OP_I2F: case InstructionConstants.OP_L2F: case InstructionConstants.OP_D2F: replaceFloatPushInstruction(clazz, offset, simpleInstruction); break; case InstructionConstants.OP_DALOAD: case InstructionConstants.OP_DADD: case InstructionConstants.OP_DSUB: case InstructionConstants.OP_DMUL: case InstructionConstants.OP_DDIV: case InstructionConstants.OP_DREM: case InstructionConstants.OP_DNEG: case InstructionConstants.OP_I2D: case InstructionConstants.OP_L2D: case InstructionConstants.OP_F2D: replaceDoublePushInstruction(clazz, offset, simpleInstruction); break; case InstructionConstants.OP_AALOAD: replaceReferencePushInstruction(clazz, offset, simpleInstruction); break; } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { int variableIndex = variableInstruction.variableIndex; switch (variableInstruction.opcode) { case InstructionConstants.OP_ILOAD: case InstructionConstants.OP_ILOAD_0: case InstructionConstants.OP_ILOAD_1: case InstructionConstants.OP_ILOAD_2: case InstructionConstants.OP_ILOAD_3: replaceIntegerPushInstruction(clazz, offset, variableInstruction, variableIndex); break; case InstructionConstants.OP_LLOAD: case InstructionConstants.OP_LLOAD_0: case InstructionConstants.OP_LLOAD_1: case InstructionConstants.OP_LLOAD_2: case InstructionConstants.OP_LLOAD_3: replaceLongPushInstruction(clazz, offset, variableInstruction, variableIndex); break; case InstructionConstants.OP_FLOAD: case InstructionConstants.OP_FLOAD_0: case InstructionConstants.OP_FLOAD_1: case InstructionConstants.OP_FLOAD_2: case InstructionConstants.OP_FLOAD_3: replaceFloatPushInstruction(clazz, offset, variableInstruction, variableIndex); break; case InstructionConstants.OP_DLOAD: case InstructionConstants.OP_DLOAD_0: case InstructionConstants.OP_DLOAD_1: case InstructionConstants.OP_DLOAD_2: case InstructionConstants.OP_DLOAD_3: replaceDoublePushInstruction(clazz, offset, variableInstruction, variableIndex); break; case InstructionConstants.OP_ALOAD: case InstructionConstants.OP_ALOAD_0: case InstructionConstants.OP_ALOAD_1: case InstructionConstants.OP_ALOAD_2: case InstructionConstants.OP_ALOAD_3: replaceReferencePushInstruction(clazz, offset, variableInstruction); break; case InstructionConstants.OP_ASTORE: case InstructionConstants.OP_ASTORE_0: case InstructionConstants.OP_ASTORE_1: case InstructionConstants.OP_ASTORE_2: case InstructionConstants.OP_ASTORE_3: deleteReferencePopInstruction(clazz, offset, variableInstruction); break; case InstructionConstants.OP_RET: replaceBranchInstruction(clazz, offset, variableInstruction); break; } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { switch (constantInstruction.opcode) { case InstructionConstants.OP_GETSTATIC: case InstructionConstants.OP_GETFIELD: replaceAnyPushInstruction(clazz, offset, constantInstruction); break; case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: if (constantInstruction.stackPushCount(clazz) > 0 && !sideEffectInstructionChecker.hasSideEffects(clazz, method, codeAttribute, offset, constantInstruction)) { replaceAnyPushInstruction(clazz, offset, constantInstruction); } break; case InstructionConstants.OP_CHECKCAST: replaceReferencePushInstruction(clazz, offset, constantInstruction); break; } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { switch (branchInstruction.opcode) { case InstructionConstants.OP_GOTO: case InstructionConstants.OP_GOTO_W: // Don't replace unconditional branches. break; case InstructionConstants.OP_JSR: case InstructionConstants.OP_JSR_W: replaceJsrInstruction(clazz, offset, branchInstruction); break; default: replaceBranchInstruction(clazz, offset, branchInstruction); break; } } public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) { // First try to simplify it to a simple branch. replaceBranchInstruction(clazz, offset, switchInstruction); // Otherwise make sure all branch targets are valid. if (!codeAttributeEditor.isModified(offset)) { replaceSwitchInstruction(clazz, offset, switchInstruction); } } // Small utility methods. /** * Replaces the push instruction at the given offset by a simpler push * instruction, if possible. */ private void replaceAnyPushInstruction(Clazz clazz, int offset, Instruction instruction) { Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { switch (pushedValue.computationalType()) { case Value.TYPE_INTEGER: replaceIntegerPushInstruction(clazz, offset, instruction); break; case Value.TYPE_LONG: replaceLongPushInstruction(clazz, offset, instruction); break; case Value.TYPE_FLOAT: replaceFloatPushInstruction(clazz, offset, instruction); break; case Value.TYPE_DOUBLE: replaceDoublePushInstruction(clazz, offset, instruction); break; case Value.TYPE_REFERENCE: replaceReferencePushInstruction(clazz, offset, instruction); break; } } } /** * Replaces the integer pushing instruction at the given offset by a simpler * push instruction, if possible. */ private void replaceIntegerPushInstruction(Clazz clazz, int offset, Instruction instruction) { replaceIntegerPushInstruction(clazz, offset, instruction, partialEvaluator.getVariablesBefore(offset).size()); } /** * Replaces the integer pushing instruction at the given offset by a simpler * push instruction, if possible. */ private void replaceIntegerPushInstruction(Clazz clazz, int offset, Instruction instruction, int maxVariableIndex) { Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { // Push a constant instead. int value = pushedValue.integerValue().value(); if (value << 16 >> 16 == value) { replaceConstantPushInstruction(clazz, offset, instruction, InstructionConstants.OP_SIPUSH, value); } else { ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor((ProgramClass)clazz); Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_LDC, constantPoolEditor.addIntegerConstant(value)).shrink(); replaceInstruction(clazz, offset, instruction, replacementInstruction); } } else if (pushedValue.isSpecific()) { // Load an equivalent lower-numbered variable instead, if any. TracedVariables variables = partialEvaluator.getVariablesBefore(offset); for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++) { if (pushedValue.equals(variables.load(variableIndex))) { replaceVariablePushInstruction(clazz, offset, instruction, InstructionConstants.OP_ILOAD, variableIndex); break; } } } } /** * Replaces the long pushing instruction at the given offset by a simpler * push instruction, if possible. */ private void replaceLongPushInstruction(Clazz clazz, int offset, Instruction instruction) { replaceLongPushInstruction(clazz, offset, instruction, partialEvaluator.getVariablesBefore(offset).size()); } /** * Replaces the long pushing instruction at the given offset by a simpler * push instruction, if possible. */ private void replaceLongPushInstruction(Clazz clazz, int offset, Instruction instruction, int maxVariableIndex) { Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { // Push a constant instead. long value = pushedValue.longValue().value(); if (value == 0L || value == 1L) { replaceConstantPushInstruction(clazz, offset, instruction, InstructionConstants.OP_LCONST_0, (int)value); } else { ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor((ProgramClass)clazz); Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_LDC2_W, constantPoolEditor.addLongConstant(value)).shrink(); replaceInstruction(clazz, offset, instruction, replacementInstruction); } } else if (pushedValue.isSpecific()) { // Load an equivalent lower-numbered variable instead, if any. TracedVariables variables = partialEvaluator.getVariablesBefore(offset); for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++) { // Note that we have to check the second part as well. if (pushedValue.equals(variables.load(variableIndex)) && variables.load(variableIndex + 1) != null && variables.load(variableIndex + 1).computationalType() == Value.TYPE_TOP) { replaceVariablePushInstruction(clazz, offset, instruction, InstructionConstants.OP_LLOAD, variableIndex); } } } } /** * Replaces the float pushing instruction at the given offset by a simpler * push instruction, if possible. */ private void replaceFloatPushInstruction(Clazz clazz, int offset, Instruction instruction) { replaceFloatPushInstruction(clazz, offset, instruction, partialEvaluator.getVariablesBefore(offset).size()); } /** * Replaces the float pushing instruction at the given offset by a simpler * push instruction, if possible. */ private void replaceFloatPushInstruction(Clazz clazz, int offset, Instruction instruction, int maxVariableIndex) { Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { // Push a constant instead. // Make sure to distinguish between +0.0 and -0.0. float value = pushedValue.floatValue().value(); if (value == 0.0f && Float.floatToIntBits(value) == POS_ZERO_FLOAT_BITS || value == 1.0f || value == 2.0f) { replaceConstantPushInstruction(clazz, offset, instruction, InstructionConstants.OP_FCONST_0, (int)value); } else { ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor((ProgramClass)clazz); Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_LDC, constantPoolEditor.addFloatConstant(value)).shrink(); replaceInstruction(clazz, offset, instruction, replacementInstruction); } } else if (pushedValue.isSpecific()) { // Load an equivalent lower-numbered variable instead, if any. TracedVariables variables = partialEvaluator.getVariablesBefore(offset); for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++) { if (pushedValue.equals(variables.load(variableIndex))) { replaceVariablePushInstruction(clazz, offset, instruction, InstructionConstants.OP_FLOAD, variableIndex); } } } } /** * Replaces the double pushing instruction at the given offset by a simpler * push instruction, if possible. */ private void replaceDoublePushInstruction(Clazz clazz, int offset, Instruction instruction) { replaceDoublePushInstruction(clazz, offset, instruction, partialEvaluator.getVariablesBefore(offset).size()); } /** * Replaces the double pushing instruction at the given offset by a simpler * push instruction, if possible. */ private void replaceDoublePushInstruction(Clazz clazz, int offset, Instruction instruction, int maxVariableIndex) { Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { // Push a constant instead. // Make sure to distinguish between +0.0 and -0.0. double value = pushedValue.doubleValue().value(); if (value == 0.0 && Double.doubleToLongBits(value) == POS_ZERO_DOUBLE_BITS || value == 1.0) { replaceConstantPushInstruction(clazz, offset, instruction, InstructionConstants.OP_DCONST_0, (int)value); } else { ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor((ProgramClass)clazz); Instruction replacementInstruction = new ConstantInstruction(InstructionConstants.OP_LDC2_W, constantPoolEditor.addDoubleConstant(value)).shrink(); replaceInstruction(clazz, offset, instruction, replacementInstruction); } } else if (pushedValue.isSpecific()) { // Load an equivalent lower-numbered variable instead, if any. TracedVariables variables = partialEvaluator.getVariablesBefore(offset); for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++) { // Note that we have to check the second part as well. if (pushedValue.equals(variables.load(variableIndex)) && variables.load(variableIndex + 1) != null && variables.load(variableIndex + 1).computationalType() == Value.TYPE_TOP) { replaceVariablePushInstruction(clazz, offset, instruction, InstructionConstants.OP_DLOAD, variableIndex); } } } } /** * Replaces the reference pushing instruction at the given offset by a * simpler push instruction, if possible. */ private void replaceReferencePushInstruction(Clazz clazz, int offset, Instruction instruction) { Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { // A reference value can only be specific if it is null. replaceConstantPushInstruction(clazz, offset, instruction, InstructionConstants.OP_ACONST_NULL, 0); } } /** * Replaces the instruction at a given offset by a given push instruction * of a constant. */ private void replaceConstantPushInstruction(Clazz clazz, int offset, Instruction instruction, byte replacementOpcode, int value) { Instruction replacementInstruction = new SimpleInstruction(replacementOpcode, value).shrink(); replaceInstruction(clazz, offset, instruction, replacementInstruction); } /** * Replaces the instruction at a given offset by a given push instruction * of a variable. */ private void replaceVariablePushInstruction(Clazz clazz, int offset, Instruction instruction, byte replacementOpcode, int variableIndex) { Instruction replacementInstruction = new VariableInstruction(replacementOpcode, variableIndex).shrink(); replaceInstruction(clazz, offset, instruction, replacementInstruction); } /** * Replaces the given 'jsr' instruction by a simpler branch instruction, * if it jumps to a subroutine that doesn't return or a subroutine that * is only called from one place. */ private void replaceJsrInstruction(Clazz clazz, int offset, BranchInstruction branchInstruction) { // Is the subroutine ever returning? int subroutineStart = offset + branchInstruction.branchOffset; if (!partialEvaluator.isSubroutineReturning(subroutineStart) || partialEvaluator.branchOrigins(subroutineStart).instructionOffsetCount() == 1) { // All 'jsr' instructions to this subroutine can be replaced // by unconditional branch instructions. replaceBranchInstruction(clazz, offset, branchInstruction); } else if (!partialEvaluator.isTraced(offset + branchInstruction.length(offset))) { // We have to make sure the instruction after this 'jsr' // instruction is valid, even if it is never reached. replaceByInfiniteLoop(clazz, offset + branchInstruction.length(offset), branchInstruction); } } /** * Deletes the reference popping instruction at the given offset, if * it is at the start of a subroutine that doesn't return or a subroutine * that is only called from one place. */ private void deleteReferencePopInstruction(Clazz clazz, int offset, Instruction instruction) { if (partialEvaluator.isSubroutineStart(offset) && (!partialEvaluator.isSubroutineReturning(offset) || partialEvaluator.branchOrigins(offset).instructionOffsetCount() == 1)) { if (DEBUG) System.out.println(" Deleting store of subroutine return address "+instruction.toString(offset)); // A reference value can only be specific if it is null. codeAttributeEditor.deleteInstruction(offset); } } /** * Deletes the given branch instruction, or replaces it by a simpler branch * instruction, if possible. */ private void replaceBranchInstruction(Clazz clazz, int offset, Instruction instruction) { InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset); // Is there exactly one branch target (not from a goto or jsr)? if (branchTargets != null && branchTargets.instructionOffsetCount() == 1) { // Is it branching to the next instruction? int branchOffset = branchTargets.instructionOffset(0) - offset; if (branchOffset == instruction.length(offset)) { if (DEBUG) System.out.println(" Ignoring zero branch instruction at ["+offset+"]"); } else { // Replace the branch instruction by a simple branch instruction. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO_W, branchOffset).shrink(); replaceInstruction(clazz, offset, instruction, replacementInstruction); } } } /** * Makes sure all branch targets of the given switch instruction are valid. */ private void replaceSwitchInstruction(Clazz clazz, int offset, SwitchInstruction switchInstruction) { // Get the actual branch targets. InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset); // Get an offset that can serve as a valid default offset. int defaultOffset = branchTargets.instructionOffset(branchTargets.instructionOffsetCount()-1) - offset; Instruction replacementInstruction = null; // Check the jump offsets. int[] jumpOffsets = switchInstruction.jumpOffsets; for (int index = 0; index < jumpOffsets.length; index++) { if (!branchTargets.contains(offset + jumpOffsets[index])) { // Replace the unused offset. jumpOffsets[index] = defaultOffset; // Remember to replace the instruction. replacementInstruction = switchInstruction; } } // Check the default offset. if (!branchTargets.contains(offset + switchInstruction.defaultOffset)) { // Replace the unused offset. switchInstruction.defaultOffset = defaultOffset; // Remember to replace the instruction. replacementInstruction = switchInstruction; } if (replacementInstruction != null) { replaceInstruction(clazz, offset, switchInstruction, replacementInstruction); } } /** * Replaces the given instruction by an infinite loop. */ private void replaceByInfiniteLoop(Clazz clazz, int offset, Instruction instruction) { // Replace the instruction by an infinite loop. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO, 0); if (DEBUG) System.out.println(" Replacing unreachable instruction by infinite loop "+replacementInstruction.toString(offset)); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); // Visit the instruction, if required. if (extraInstructionVisitor != null) { // Note: we're not passing the right arguments for now, knowing that // they aren't used anyway. instruction.accept(clazz, null, null, offset, extraInstructionVisitor); } } /** * Replaces the instruction at a given offset by a given push instruction. */ private void replaceInstruction(Clazz clazz, int offset, Instruction instruction, Instruction replacementInstruction) { // Pop unneeded stack entries if necessary. int popCount = instruction.stackPopCount(clazz) - replacementInstruction.stackPopCount(clazz); insertPopInstructions(offset, popCount); if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(offset)+" -> "+replacementInstruction.toString()+(popCount == 0 ? "" : " ("+popCount+" pops)")); codeAttributeEditor.replaceInstruction(offset, replacementInstruction); // Visit the instruction, if required. if (extraInstructionVisitor != null) { // Note: we're not passing the right arguments for now, knowing that // they aren't used anyway. instruction.accept(clazz, null, null, offset, extraInstructionVisitor); } } /** * Pops the given number of stack entries before the instruction at the * given offset. */ private void insertPopInstructions(int offset, int popCount) { switch (popCount) { case 0: { break; } case 1: { // Insert a single pop instruction. Instruction popInstruction = new SimpleInstruction(InstructionConstants.OP_POP); codeAttributeEditor.insertBeforeInstruction(offset, popInstruction); break; } case 2: { // Insert a single pop2 instruction. Instruction popInstruction = new SimpleInstruction(InstructionConstants.OP_POP2); codeAttributeEditor.insertBeforeInstruction(offset, popInstruction); break; } default: { // Insert the specified number of pop instructions. Instruction[] popInstructions = new Instruction[popCount / 2 + popCount % 2]; Instruction popInstruction = new SimpleInstruction(InstructionConstants.OP_POP2); for (int index = 0; index < popCount / 2; index++) { popInstructions[index] = popInstruction; } if (popCount % 2 == 1) { popInstruction = new SimpleInstruction(InstructionConstants.OP_POP); popInstructions[popCount / 2] = popInstruction; } codeAttributeEditor.insertBeforeInstruction(offset, popInstructions); break; } } } } proguard4.8/src/proguard/optimize/evaluation/PartialEvaluator.java0000664000175000017500000014335211736333525024346 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.evaluation; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.ClassConstant; import proguard.classfile.instruction.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.peephole.BranchTargetFinder; import java.util.Arrays; /** * This AttributeVisitor performs partial evaluation on the code attributes * that it visits. * * @author Eric Lafortune */ public class PartialEvaluator extends SimplifiedVisitor implements AttributeVisitor, ExceptionInfoVisitor { //* private static final boolean DEBUG = false; private static final boolean DEBUG_RESULTS = false; /*/ private static boolean DEBUG = true; private static boolean DEBUG_RESULTS = true; //*/ private static final int MAXIMUM_EVALUATION_COUNT = 5; public static final int NONE = -2; public static final int AT_METHOD_ENTRY = -1; public static final int AT_CATCH_ENTRY = -1; private final ValueFactory valueFactory; private final InvocationUnit invocationUnit; private final boolean evaluateAllCode; private InstructionOffsetValue[] branchOriginValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH]; private InstructionOffsetValue[] branchTargetValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH]; private TracedVariables[] variablesBefore = new TracedVariables[ClassConstants.TYPICAL_CODE_LENGTH]; private TracedStack[] stacksBefore = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH]; private TracedVariables[] variablesAfter = new TracedVariables[ClassConstants.TYPICAL_CODE_LENGTH]; private TracedStack[] stacksAfter = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean[] generalizedContexts = new boolean[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] evaluationCounts = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean evaluateExceptions; private final BasicBranchUnit branchUnit; private final BranchTargetFinder branchTargetFinder; private final java.util.Stack callingInstructionBlockStack; private final java.util.Stack instructionBlockStack = new java.util.Stack(); /** * Creates a simple PartialEvaluator. */ public PartialEvaluator() { this(new ValueFactory(), new BasicInvocationUnit(new ValueFactory()), true); } /** * Creates a new PartialEvaluator. * @param valueFactory the value factory that will create all values * during evaluation. * @param invocationUnit the invocation unit that will handle all * communication with other fields and methods. * @param evaluateAllCode a flag that specifies whether all branch targets * and exception handlers should be evaluated, * even if they are unreachable. */ public PartialEvaluator(ValueFactory valueFactory, InvocationUnit invocationUnit, boolean evaluateAllCode) { this(valueFactory, invocationUnit, evaluateAllCode, evaluateAllCode ? new BasicBranchUnit() : new TracedBranchUnit(), new BranchTargetFinder(), null); } /** * Creates a new PartialEvaluator, based on an existing one. * @param partialEvaluator the subroutine calling partial evaluator. */ private PartialEvaluator(PartialEvaluator partialEvaluator) { this(partialEvaluator.valueFactory, partialEvaluator.invocationUnit, partialEvaluator.evaluateAllCode, partialEvaluator.branchUnit, partialEvaluator.branchTargetFinder, partialEvaluator.instructionBlockStack); } /** * Creates a new PartialEvaluator. * @param valueFactory the value factory that will create all * values during evaluation. * @param invocationUnit the invocation unit that will handle all * communication with other fields and methods. * @param evaluateAllCode a flag that specifies whether all branch * targets and exception handlers should be * evaluated, even if they are unreachable. * @param branchUnit the branch unit that will handle all * branches. * @param branchTargetFinder the utility class that will find all * branches. */ private PartialEvaluator(ValueFactory valueFactory, InvocationUnit invocationUnit, boolean evaluateAllCode, BasicBranchUnit branchUnit, BranchTargetFinder branchTargetFinder, java.util.Stack callingInstructionBlockStack) { this.valueFactory = valueFactory; this.invocationUnit = invocationUnit; this.evaluateAllCode = evaluateAllCode; this.branchUnit = branchUnit; this.branchTargetFinder = branchTargetFinder; this.callingInstructionBlockStack = callingInstructionBlockStack == null ? this.instructionBlockStack : callingInstructionBlockStack; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = DEBUG_RESULTS = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // TODO: Remove this when the partial evaluator has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while performing partial evaluation:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); if (DEBUG) { method.accept(clazz, new ClassPrinter()); System.out.println("Evaluation results:"); int offset = 0; do { if (isBranchOrExceptionTarget(offset)) { System.out.println("Branch target from ["+branchOriginValues[offset]+"]:"); if (isTraced(offset)) { System.out.println(" Vars: "+variablesBefore[offset]); System.out.println(" Stack: "+stacksBefore[offset]); } } Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); System.out.println(instruction.toString(offset)); if (isTraced(offset)) { int initializationOffset = branchTargetFinder.initializationOffset(offset); if (initializationOffset != NONE) { System.out.println(" is to be initialized at ["+initializationOffset+"]"); } InstructionOffsetValue branchTargets = branchTargets(offset); if (branchTargets != null) { System.out.println(" has overall been branching to "+branchTargets); } System.out.println(" Vars: "+variablesAfter[offset]); System.out.println(" Stack: "+stacksAfter[offset]); } offset += instruction.length(offset); } while (offset < codeAttribute.u4codeLength); } throw ex; } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Evaluate the instructions, starting at the entry point. if (DEBUG) { System.out.println(); System.out.println("Partial evaluation: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); System.out.println(" Max locals = "+codeAttribute.u2maxLocals); System.out.println(" Max stack = "+codeAttribute.u2maxStack); } // Reuse the existing variables and stack objects, ensuring the right size. TracedVariables variables = new TracedVariables(codeAttribute.u2maxLocals); TracedStack stack = new TracedStack(codeAttribute.u2maxStack); // Initialize the reusable arrays and variables. initializeArrays(codeAttribute); initializeParameters(clazz, method, codeAttribute, variables); // Find all instruction offsets,... codeAttribute.accept(clazz, method, branchTargetFinder); // Start executing the first instruction block. evaluateInstructionBlockAndExceptionHandlers(clazz, method, codeAttribute, variables, stack, 0, codeAttribute.u4codeLength); if (DEBUG_RESULTS) { System.out.println("Evaluation results:"); int offset = 0; do { if (isBranchOrExceptionTarget(offset)) { System.out.println("Branch target from ["+branchOriginValues[offset]+"]:"); if (isTraced(offset)) { System.out.println(" Vars: "+variablesBefore[offset]); System.out.println(" Stack: "+stacksBefore[offset]); } } Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); System.out.println(instruction.toString(offset)); if (isTraced(offset)) { int initializationOffset = branchTargetFinder.initializationOffset(offset); if (initializationOffset != NONE) { System.out.println(" is to be initialized at ["+initializationOffset+"]"); } InstructionOffsetValue branchTargets = branchTargets(offset); if (branchTargets != null) { System.out.println(" has overall been branching to "+branchTargets); } System.out.println(" Vars: "+variablesAfter[offset]); System.out.println(" Stack: "+stacksAfter[offset]); } offset += instruction.length(offset); } while (offset < codeAttribute.u4codeLength); } } /** * Returns whether a block of instructions is ever used. */ public boolean isTraced(int startOffset, int endOffset) { for (int index = startOffset; index < endOffset; index++) { if (isTraced(index)) { return true; } } return false; } /** * Returns whether the instruction at the given offset has ever been * executed during the partial evaluation. */ public boolean isTraced(int instructionOffset) { return evaluationCounts[instructionOffset] > 0; } /** * Returns whether there is an instruction at the given offset. */ public boolean isInstruction(int instructionOffset) { return branchTargetFinder.isInstruction(instructionOffset); } /** * Returns whether the instruction at the given offset is the target of a * branch instruction or an exception. */ public boolean isBranchOrExceptionTarget(int instructionOffset) { return branchTargetFinder.isBranchTarget(instructionOffset) || branchTargetFinder.isExceptionHandler(instructionOffset); } /** * Returns whether the instruction at the given offset is the start of a * subroutine. */ public boolean isSubroutineStart(int instructionOffset) { return branchTargetFinder.isSubroutineStart(instructionOffset); } /** * Returns whether the instruction at the given offset is a subroutine * invocation. */ public boolean isSubroutineInvocation(int instructionOffset) { return branchTargetFinder.isSubroutineInvocation(instructionOffset); } /** * Returns whether the instruction at the given offset is part of a * subroutine. */ public boolean isSubroutine(int instructionOffset) { return branchTargetFinder.isSubroutine(instructionOffset); } /** * Returns whether the subroutine at the given offset is ever returning * by means of a regular 'ret' instruction. */ public boolean isSubroutineReturning(int instructionOffset) { return branchTargetFinder.isSubroutineReturning(instructionOffset); } /** * Returns the offset after the subroutine that starts at the given * offset. */ public int subroutineEnd(int instructionOffset) { return branchTargetFinder.subroutineEnd(instructionOffset); } /** * Returns the instruction offset at which the object instance that is * created at the given 'new' instruction offset is initialized, or * NONE if it is not being created. */ public int initializationOffset(int instructionOffset) { return branchTargetFinder.initializationOffset(instructionOffset); } /** * Returns whether the method is an instance initializer. */ public boolean isInitializer() { return branchTargetFinder.isInitializer(); } /** * Returns the instruction offset at which this initializer is calling * the "super" or "this" initializer method, or NONE if it is * not an initializer. */ public int superInitializationOffset() { return branchTargetFinder.superInitializationOffset(); } /** * Returns the offset of the 'new' instruction that corresponds to the * invocation of the instance initializer at the given offset, or * AT_METHOD_ENTRY if the invocation is calling the "super" or * "this" initializer method, , or NONE if it is not a 'new' * instruction. */ public int creationOffset(int offset) { return branchTargetFinder.creationOffset(offset); } /** * Returns the variables before execution of the instruction at the given * offset. */ public TracedVariables getVariablesBefore(int instructionOffset) { return variablesBefore[instructionOffset]; } /** * Returns the variables after execution of the instruction at the given * offset. */ public TracedVariables getVariablesAfter(int instructionOffset) { return variablesAfter[instructionOffset]; } /** * Returns the stack before execution of the instruction at the given * offset. */ public TracedStack getStackBefore(int instructionOffset) { return stacksBefore[instructionOffset]; } /** * Returns the stack after execution of the instruction at the given * offset. */ public TracedStack getStackAfter(int instructionOffset) { return stacksAfter[instructionOffset]; } /** * Returns the instruction offsets that branch to the given instruction * offset. */ public InstructionOffsetValue branchOrigins(int instructionOffset) { return branchOriginValues[instructionOffset]; } /** * Returns the instruction offsets to which the given instruction offset * branches. */ public InstructionOffsetValue branchTargets(int instructionOffset) { return branchTargetValues[instructionOffset]; } // Utility methods to evaluate instruction blocks. /** * Pushes block of instructions to be executed in the calling partial * evaluator. */ private void pushCallingInstructionBlock(TracedVariables variables, TracedStack stack, int startOffset) { callingInstructionBlockStack.push(new MyInstructionBlock(variables, stack, startOffset)); } /** * Pushes block of instructions to be executed in this partial evaluator. */ private void pushInstructionBlock(TracedVariables variables, TracedStack stack, int startOffset) { instructionBlockStack.push(new MyInstructionBlock(variables, stack, startOffset)); } /** * Evaluates the instruction block and the exception handlers covering the * given instruction range in the given code. */ private void evaluateInstructionBlockAndExceptionHandlers(Clazz clazz, Method method, CodeAttribute codeAttribute, TracedVariables variables, TracedStack stack, int startOffset, int endOffset) { evaluateInstructionBlock(clazz, method, codeAttribute, variables, stack, startOffset); evaluateExceptionHandlers(clazz, method, codeAttribute, startOffset, endOffset); } /** * Evaluates a block of instructions, starting at the given offset and ending * at a branch instruction, a return instruction, or a throw instruction. */ private void evaluateInstructionBlock(Clazz clazz, Method method, CodeAttribute codeAttribute, TracedVariables variables, TracedStack stack, int startOffset) { // Execute the initial instruction block. evaluateSingleInstructionBlock(clazz, method, codeAttribute, variables, stack, startOffset); // Execute all resulting instruction blocks on the execution stack. while (!instructionBlockStack.empty()) { if (DEBUG) System.out.println("Popping alternative branch out of "+instructionBlockStack.size()+" blocks"); MyInstructionBlock instructionBlock = (MyInstructionBlock)instructionBlockStack.pop(); evaluateSingleInstructionBlock(clazz, method, codeAttribute, instructionBlock.variables, instructionBlock.stack, instructionBlock.startOffset); } } /** * Evaluates a block of instructions, starting at the given offset and ending * at a branch instruction, a return instruction, or a throw instruction. * Instruction blocks that are to be evaluated as a result are pushed on * the given stack. */ private void evaluateSingleInstructionBlock(Clazz clazz, Method method, CodeAttribute codeAttribute, TracedVariables variables, TracedStack stack, int startOffset) { byte[] code = codeAttribute.code; if (DEBUG) { System.out.println("Instruction block starting at ["+startOffset+"] in "+ ClassUtil.externalFullMethodDescription(clazz.getName(), 0, method.getName(clazz), method.getDescriptor(clazz))); System.out.println("Init vars: "+variables); System.out.println("Init stack: "+stack); } Processor processor = new Processor(variables, stack, valueFactory, branchUnit, invocationUnit); int instructionOffset = startOffset; int maxOffset = startOffset; // Evaluate the subsequent instructions. while (true) { if (maxOffset < instructionOffset) { maxOffset = instructionOffset; } // Maintain a generalized local variable frame and stack at this // instruction offset, before execution. int evaluationCount = evaluationCounts[instructionOffset]; if (evaluationCount == 0) { // First time we're passing by this instruction. if (variablesBefore[instructionOffset] == null) { // There's not even a context at this index yet. variablesBefore[instructionOffset] = new TracedVariables(variables); stacksBefore[instructionOffset] = new TracedStack(stack); } else { // Reuse the context objects at this index. variablesBefore[instructionOffset].initialize(variables); stacksBefore[instructionOffset].copy(stack); } // We'll execute in the generalized context, because it is // the same as the current context. generalizedContexts[instructionOffset] = true; } else { // Merge in the current context. boolean variablesChanged = variablesBefore[instructionOffset].generalize(variables, true); boolean stackChanged = stacksBefore[instructionOffset].generalize(stack); //System.out.println("GVars: "+variablesBefore[instructionOffset]); //System.out.println("GStack: "+stacksBefore[instructionOffset]); // Bail out if the current context is the same as last time. if (!variablesChanged && !stackChanged && generalizedContexts[instructionOffset]) { if (DEBUG) System.out.println("Repeated variables, stack, and branch targets"); break; } // See if this instruction has been evaluated an excessive number // of times. if (evaluationCount >= MAXIMUM_EVALUATION_COUNT) { if (DEBUG) System.out.println("Generalizing current context after "+evaluationCount+" evaluations"); // Continue, but generalize the current context. // Note that the most recent variable values have to remain // last in the generalizations, for the sake of the ret // instruction. variables.generalize(variablesBefore[instructionOffset], false); stack.generalize(stacksBefore[instructionOffset]); // We'll execute in the generalized context. generalizedContexts[instructionOffset] = true; } else { // We'll execute in the current context. generalizedContexts[instructionOffset] = false; } } // We'll evaluate this instruction. evaluationCounts[instructionOffset]++; // Remember this instruction's offset with any stored value. Value storeValue = new InstructionOffsetValue(instructionOffset); variables.setProducerValue(storeValue); stack.setProducerValue(storeValue); // Reset the trace value. InstructionOffsetValue traceValue = InstructionOffsetValue.EMPTY_VALUE; // Note that the instruction is only volatile. Instruction instruction = InstructionFactory.create(code, instructionOffset); // By default, the next instruction will be the one after this // instruction. int nextInstructionOffset = instructionOffset + instruction.length(instructionOffset); InstructionOffsetValue nextInstructionOffsetValue = new InstructionOffsetValue(nextInstructionOffset); branchUnit.resetCalled(); branchUnit.setTraceBranchTargets(nextInstructionOffsetValue); if (DEBUG) { System.out.println(instruction.toString(instructionOffset)); } try { // Process the instruction. The processor may modify the // variables and the stack, and it may call the branch unit // and the invocation unit. instruction.accept(clazz, method, codeAttribute, instructionOffset, processor); } catch (RuntimeException ex) { System.err.println("Unexpected error while evaluating instruction:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Instruction = "+instruction.toString(instructionOffset)); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); throw ex; } // Collect the branch targets from the branch unit. InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets(); int branchTargetCount = branchTargets.instructionOffsetCount(); // Stop tracing. branchUnit.setTraceBranchTargets(traceValue); if (DEBUG) { if (branchUnit.wasCalled()) { System.out.println(" is branching to "+branchTargets); } if (branchTargetValues[instructionOffset] != null) { System.out.println(" has up till now been branching to "+branchTargetValues[instructionOffset]); } System.out.println(" Vars: "+variables); System.out.println(" Stack: "+stack); } // Maintain a generalized local variable frame and stack at this // instruction offset, after execution. if (evaluationCount == 0) { // First time we're passing by this instruction. if (variablesAfter[instructionOffset] == null) { // There's not even a context at this index yet. variablesAfter[instructionOffset] = new TracedVariables(variables); stacksAfter[instructionOffset] = new TracedStack(stack); } else { // Reuse the context objects at this index. variablesAfter[instructionOffset].initialize(variables); stacksAfter[instructionOffset].copy(stack); } } else { // Merge in the current context. variablesAfter[instructionOffset].generalize(variables, true); stacksAfter[instructionOffset].generalize(stack); } // Did the branch unit get called? if (branchUnit.wasCalled()) { // Accumulate the branch targets at this offset. branchTargetValues[instructionOffset] = branchTargetValues[instructionOffset] == null ? branchTargets : branchTargetValues[instructionOffset].generalize(branchTargets).instructionOffsetValue(); // Are there no branch targets at all? if (branchTargetCount == 0) { // Exit from this code block. break; } // Accumulate the branch origins at the branch target offsets. InstructionOffsetValue instructionOffsetValue = new InstructionOffsetValue(instructionOffset); for (int index = 0; index < branchTargetCount; index++) { int branchTarget = branchTargets.instructionOffset(index); branchOriginValues[branchTarget] = branchOriginValues[branchTarget] == null ? instructionOffsetValue: branchOriginValues[branchTarget].generalize(instructionOffsetValue).instructionOffsetValue(); } // Are there multiple branch targets? if (branchTargetCount > 1) { // Push them on the execution stack and exit from this block. for (int index = 0; index < branchTargetCount; index++) { if (DEBUG) System.out.println("Pushing alternative branch #"+index+" out of "+branchTargetCount+", from ["+instructionOffset+"] to ["+branchTargets.instructionOffset(index)+"]"); pushInstructionBlock(new TracedVariables(variables), new TracedStack(stack), branchTargets.instructionOffset(index)); } break; } if (DEBUG) System.out.println("Definite branch from ["+instructionOffset+"] to ["+branchTargets.instructionOffset(0)+"]"); } // Just continue with the next instruction. instructionOffset = branchTargets.instructionOffset(0); // Is this a subroutine invocation? if (instruction.opcode == InstructionConstants.OP_JSR || instruction.opcode == InstructionConstants.OP_JSR_W) { // Evaluate the subroutine in another partial evaluator. evaluateSubroutine(clazz, method, codeAttribute, variables, stack, instructionOffset, instructionBlockStack); break; } else if (instruction.opcode == InstructionConstants.OP_RET) { // Let the partial evaluator that has called the subroutine // handle the evaluation after the return. pushCallingInstructionBlock(new TracedVariables(variables), new TracedStack(stack), instructionOffset); break; } } if (DEBUG) System.out.println("Ending processing of instruction block starting at ["+startOffset+"]"); } /** * Evaluates a subroutine and its exception handlers, starting at the given * offset and ending at a subroutine return instruction. */ private void evaluateSubroutine(Clazz clazz, Method method, CodeAttribute codeAttribute, TracedVariables variables, TracedStack stack, int subroutineStart, java.util.Stack instructionBlockStack) { int subroutineEnd = branchTargetFinder.subroutineEnd(subroutineStart); if (DEBUG) System.out.println("Evaluating subroutine from "+subroutineStart+" to "+subroutineEnd); // Create a temporary partial evaluator, so there are no conflicts // with variables that are alive across subroutine invocations, between // different invocations. PartialEvaluator subroutinePartialEvaluator = new PartialEvaluator(this); subroutinePartialEvaluator.initializeArrays(codeAttribute); // Evaluate the subroutine. subroutinePartialEvaluator.evaluateInstructionBlockAndExceptionHandlers(clazz, method, codeAttribute, variables, stack, subroutineStart, subroutineEnd); // Merge back the temporary partial evaluator. This way, we'll get // the lowest common denominator of stacks and variables. generalize(subroutinePartialEvaluator, 0, codeAttribute.u4codeLength); if (DEBUG) System.out.println("Ending subroutine from "+subroutineStart+" to "+subroutineEnd); } /** * Generalizes the results of this partial evaluator with those of another * given partial evaluator, over a given range of instructions. */ private void generalize(PartialEvaluator other, int codeStart, int codeEnd) { if (DEBUG) System.out.println("Generalizing with temporary partial evaluation"); for (int offset = codeStart; offset < codeEnd; offset++) { if (other.branchOriginValues[offset] != null) { branchOriginValues[offset] = branchOriginValues[offset] == null ? other.branchOriginValues[offset] : branchOriginValues[offset].generalize(other.branchOriginValues[offset]).instructionOffsetValue(); } if (other.isTraced(offset)) { if (other.branchTargetValues[offset] != null) { branchTargetValues[offset] = branchTargetValues[offset] == null ? other.branchTargetValues[offset] : branchTargetValues[offset].generalize(other.branchTargetValues[offset]).instructionOffsetValue(); } if (evaluationCounts[offset] == 0) { variablesBefore[offset] = other.variablesBefore[offset]; stacksBefore[offset] = other.stacksBefore[offset]; variablesAfter[offset] = other.variablesAfter[offset]; stacksAfter[offset] = other.stacksAfter[offset]; generalizedContexts[offset] = other.generalizedContexts[offset]; evaluationCounts[offset] = other.evaluationCounts[offset]; } else { variablesBefore[offset].generalize(other.variablesBefore[offset], false); stacksBefore[offset] .generalize(other.stacksBefore[offset]); variablesAfter[offset] .generalize(other.variablesAfter[offset], false); stacksAfter[offset] .generalize(other.stacksAfter[offset]); //generalizedContexts[offset] evaluationCounts[offset] += other.evaluationCounts[offset]; } } } } /** * Evaluates the exception handlers covering and targeting the given * instruction range in the given code. */ private void evaluateExceptionHandlers(Clazz clazz, Method method, CodeAttribute codeAttribute, int startOffset, int endOffset) { if (DEBUG) System.out.println("Evaluating exceptions covering ["+startOffset+" -> "+endOffset+"]:"); ExceptionHandlerFilter exceptionEvaluator = new ExceptionHandlerFilter(startOffset, endOffset, this); // Evaluate the exception catch blocks, until their entry variables // have stabilized. do { // Reset the flag to stop evaluating. evaluateExceptions = false; // Evaluate all relevant exception catch blocks once. codeAttribute.exceptionsAccept(clazz, method, startOffset, endOffset, exceptionEvaluator); } while (evaluateExceptions); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { int startPC = exceptionInfo.u2startPC; int endPC = exceptionInfo.u2endPC; // Do we have to evaluate this exception catch block? if (isTraced(startPC, endPC)) { int handlerPC = exceptionInfo.u2handlerPC; int catchType = exceptionInfo.u2catchType; if (DEBUG) System.out.println("Evaluating exception ["+startPC +" -> "+endPC +": "+handlerPC+"]:"); // Reuse the existing variables and stack objects, ensuring the // right size. TracedVariables variables = new TracedVariables(codeAttribute.u2maxLocals); TracedStack stack = new TracedStack(codeAttribute.u2maxStack); // Initialize the trace values. Value storeValue = new InstructionOffsetValue(AT_CATCH_ENTRY); variables.setProducerValue(storeValue); stack.setProducerValue(storeValue); // Initialize the variables by generalizing the variables of the // try block. Make sure to include the results of the last // instruction for preverification. generalizeVariables(startPC, endPC, evaluateAllCode, variables); // Initialize the the stack. //stack.push(valueFactory.createReference((ClassConstant)((ProgramClass)clazz).getConstant(exceptionInfo.u2catchType), false)); String catchClassName = catchType != 0 ? clazz.getClassName(catchType) : ClassConstants.INTERNAL_NAME_JAVA_LANG_THROWABLE; Clazz catchClass = catchType != 0 ? ((ClassConstant)((ProgramClass)clazz).getConstant(catchType)).referencedClass : null; stack.push(valueFactory.createReferenceValue(catchClassName, catchClass, false)); int evaluationCount = evaluationCounts[handlerPC]; // Evaluate the instructions, starting at the entry point. evaluateInstructionBlock(clazz, method, codeAttribute, variables, stack, handlerPC); // Remember to evaluate all exception handlers once more. if (!evaluateExceptions) { evaluateExceptions = evaluationCount < evaluationCounts[handlerPC]; } } // else if (evaluateAllCode) // { // if (DEBUG) System.out.println("No information for partial evaluation of exception ["+startPC +" -> "+endPC +": "+exceptionInfo.u2handlerPC+"] yet"); // // // We don't have any information on the try block yet, but we do // // have to evaluate the exception handler. // // Remember to evaluate all exception handlers once more. // evaluateExceptions = true; // } else { if (DEBUG) System.out.println("No information for partial evaluation of exception ["+startPC +" -> "+endPC +": "+exceptionInfo.u2handlerPC+"]"); } } // Small utility methods. /** * Initializes the data structures for the variables, stack, etc. */ private void initializeArrays(CodeAttribute codeAttribute) { int codeLength = codeAttribute.u4codeLength; // Create new arrays for storing information at each instruction offset. if (variablesAfter.length < codeLength) { // Create new arrays. branchOriginValues = new InstructionOffsetValue[codeLength]; branchTargetValues = new InstructionOffsetValue[codeLength]; variablesBefore = new TracedVariables[codeLength]; stacksBefore = new TracedStack[codeLength]; variablesAfter = new TracedVariables[codeLength]; stacksAfter = new TracedStack[codeLength]; generalizedContexts = new boolean[codeLength]; evaluationCounts = new int[codeLength]; } else { // Reset the arrays. Arrays.fill(branchOriginValues, null); Arrays.fill(branchTargetValues, null); Arrays.fill(generalizedContexts, false); Arrays.fill(evaluationCounts, 0); for (int index = 0; index < codeLength; index++) { if (variablesBefore[index] != null) { variablesBefore[index].reset(codeAttribute.u2maxLocals); } if (stacksBefore[index] != null) { stacksBefore[index].reset(codeAttribute.u2maxStack); } if (variablesAfter[index] != null) { variablesAfter[index].reset(codeAttribute.u2maxLocals); } if (stacksAfter[index] != null) { stacksAfter[index].reset(codeAttribute.u2maxStack); } } } } /** * Initializes the data structures for the variables, stack, etc. */ private void initializeParameters(Clazz clazz, Method method, CodeAttribute codeAttribute, TracedVariables variables) { // Create the method parameters. TracedVariables parameters = new TracedVariables(codeAttribute.u2maxLocals); // Remember this instruction's offset with any stored value. Value storeValue = new InstructionOffsetValue(AT_METHOD_ENTRY); parameters.setProducerValue(storeValue); // Initialize the method parameters. invocationUnit.enterMethod(clazz, method, parameters); if (DEBUG) { System.out.println(" Params: "+parameters); } // Initialize the variables with the parameters. variables.initialize(parameters); // Set the store value of each parameter variable. InstructionOffsetValue atMethodEntry = new InstructionOffsetValue(AT_METHOD_ENTRY); for (int index = 0; index < parameters.size(); index++) { variables.setProducerValue(index, atMethodEntry); } } /** * Generalize the local variable frames of a block of instructions. */ private void generalizeVariables(int startOffset, int endOffset, boolean includeAfterLastInstruction, TracedVariables generalizedVariables) { boolean first = true; int lastIndex = -1; // Generalize the variables before each of the instructions in the block. for (int index = startOffset; index < endOffset; index++) { if (isTraced(index)) { TracedVariables tracedVariables = variablesBefore[index]; if (first) { // Initialize the variables with the first traced local // variable frame. generalizedVariables.initialize(tracedVariables); first = false; } else { // Generalize the variables with the traced local variable // frame. We can't use the return value, because local // generalization can be different a couple of times, // with the global generalization being the same. generalizedVariables.generalize(tracedVariables, false); } lastIndex = index; } } // Generalize the variables after the last instruction in the block, // if required. if (includeAfterLastInstruction && lastIndex >= 0) { TracedVariables tracedVariables = variablesAfter[lastIndex]; if (first) { // Initialize the variables with the local variable frame. generalizedVariables.initialize(tracedVariables); } else { // Generalize the variables with the local variable frame. generalizedVariables.generalize(tracedVariables, false); } } // Just clear the variables if there aren't any traced instructions // in the block. if (first) { generalizedVariables.reset(generalizedVariables.size()); } } private static class MyInstructionBlock { private TracedVariables variables; private TracedStack stack; private int startOffset; private MyInstructionBlock(TracedVariables variables, TracedStack stack, int startOffset) { this.variables = variables; this.stack = stack; this.startOffset = startOffset; } } } proguard4.8/src/proguard/optimize/evaluation/VariableOptimizer.java0000664000175000017500000003016211736333525024511 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.evaluation; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.editor.*; import proguard.classfile.visitor.MemberVisitor; import proguard.classfile.attribute.*; import proguard.classfile.util.*; /** * This AttributeVisitor optimizes variable allocation based on their the liveness, * in the code attributes that it visits. * * @author Eric Lafortune */ public class VariableOptimizer extends SimplifiedVisitor implements AttributeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private static final int MAX_VARIABLES_SIZE = 64; private final boolean reuseThis; private final MemberVisitor extraVariableMemberVisitor; private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(); private final VariableRemapper variableRemapper = new VariableRemapper(); private VariableCleaner variableCleaner = new VariableCleaner(); private int[] variableMap = new int[ClassConstants.TYPICAL_VARIABLES_SIZE]; /** * Creates a new VariableOptimizer. * @param reuseThis specifies whether the 'this' variable can be reused. * Many JVMs for JME and IBM's JVMs for JSE can't handle * such reuse. */ public VariableOptimizer(boolean reuseThis) { this(reuseThis, null); } /** * Creates a new VariableOptimizer with an extra visitor. * @param reuseThis specifies whether the 'this' variable * can be reused. Many JVMs for JME and * IBM's JVMs for JSE can't handle such * reuse. * @param extraVariableMemberVisitor an optional extra visitor for all * removed variables. */ public VariableOptimizer(boolean reuseThis, MemberVisitor extraVariableMemberVisitor) { this.reuseThis = reuseThis; this.extraVariableMemberVisitor = extraVariableMemberVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // Initialize the global arrays. initializeArrays(codeAttribute); // Analyze the liveness of the variables in the code. livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); // Trim the variables in the local variable tables, because even // clipping the tables individually may leave some inconsistencies // between them. codeAttribute.attributesAccept(clazz, method, this); int startIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 || reuseThis ? 0 : 1; int parameterSize = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), method.getAccessFlags()); int variableSize = codeAttribute.u2maxLocals; int codeLength = codeAttribute.u4codeLength; boolean remapping = false; // Loop over all variables. for (int oldIndex = 0; oldIndex < variableSize; oldIndex++) { // By default, the variable will be mapped onto itself. variableMap[oldIndex] = oldIndex; // Only try remapping the variable if it's not a parameter. if (oldIndex >= parameterSize && oldIndex < MAX_VARIABLES_SIZE) { // Try to remap the variable to a variable with a smaller index. for (int newIndex = startIndex; newIndex < oldIndex; newIndex++) { if (areNonOverlapping(oldIndex, newIndex, codeLength)) { variableMap[oldIndex] = newIndex; updateLiveness(oldIndex, newIndex, codeLength); remapping = true; // This variable has been remapped. Go to the next one. break; } } } } // Have we been able to remap any variables? if (remapping) { if (DEBUG) { System.out.println("VariableOptimizer: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); for (int index= 0; index < variableSize; index++) { System.out.println(" v"+index+" -> "+variableMap[index]); } } // Remap the variables. variableRemapper.setVariableMap(variableMap); variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); // Visit the method, if required. if (extraVariableMemberVisitor != null) { method.accept(clazz, extraVariableMemberVisitor); } } else { // Just clean up any empty variables. variableCleaner.visitCodeAttribute(clazz, method, codeAttribute); } } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Trim the variables in the local variable table. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Trim the variables in the local variable type table. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Trim the local variable to the instructions at which it is alive. int variable = localVariableInfo.u2index; int startPC = localVariableInfo.u2startPC; int endPC = startPC + localVariableInfo.u2length; startPC = firstLiveness(startPC, endPC, variable); endPC = lastLiveness(startPC, endPC, variable); // Leave the start address of unused variables unchanged. int length = endPC - startPC; if (length > 0) { localVariableInfo.u2startPC = startPC; } localVariableInfo.u2length = length; } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { // Trim the local variable type to the instructions at which it is alive. int variable = localVariableTypeInfo.u2index; int startPC = localVariableTypeInfo.u2startPC; int endPC = startPC + localVariableTypeInfo.u2length; startPC = firstLiveness(startPC, endPC, variable); endPC = lastLiveness(startPC, endPC, variable); // Leave the start address of unused variables unchanged. int length = endPC - startPC; if (length > 0) { localVariableTypeInfo.u2startPC = startPC; } localVariableTypeInfo.u2length = length; } // Small utility methods. /** * Initializes the global arrays. */ private void initializeArrays(CodeAttribute codeAttribute) { int codeLength = codeAttribute.u4codeLength; // Create new arrays for storing information at each instruction offset. if (variableMap.length < codeLength) { variableMap = new int[codeLength]; } } /** * Returns whether the given variables are never alive at the same time. */ private boolean areNonOverlapping(int variableIndex1, int variableIndex2, int codeLength) { // Loop over all instructions. for (int offset = 0; offset < codeLength; offset++) { if ((livenessAnalyzer.isAliveBefore(offset, variableIndex1) && livenessAnalyzer.isAliveBefore(offset, variableIndex2)) || (livenessAnalyzer.isAliveAfter(offset, variableIndex1) && livenessAnalyzer.isAliveAfter(offset, variableIndex2)) || // For now, exclude Category 2 variables. livenessAnalyzer.isCategory2(offset, variableIndex1)) { return false; } } return true; } /** * Updates the liveness resulting from mapping the given old variable on * the given new variable. */ private void updateLiveness(int oldVariableIndex, int newVariableIndex, int codeLength) { // Loop over all instructions. for (int offset = 0; offset < codeLength; offset++) { // Update the liveness before the instruction. if (livenessAnalyzer.isAliveBefore(offset, oldVariableIndex)) { livenessAnalyzer.setAliveBefore(offset, oldVariableIndex, false); livenessAnalyzer.setAliveBefore(offset, newVariableIndex, true); } // Update the liveness after the instruction. if (livenessAnalyzer.isAliveAfter(offset, oldVariableIndex)) { livenessAnalyzer.setAliveAfter(offset, oldVariableIndex, false); livenessAnalyzer.setAliveAfter(offset, newVariableIndex, true); } } } /** * Returns the first instruction offset between the given offsets at which * the given variable goes alive. */ private int firstLiveness(int startOffset, int endOffset, int variableIndex) { for (int offset = startOffset; offset < endOffset; offset++) { if (livenessAnalyzer.isTraced(offset) && livenessAnalyzer.isAliveBefore(offset, variableIndex)) { return offset; } } return endOffset; } /** * Returns the last instruction offset between the given offsets before * which the given variable is still alive. */ private int lastLiveness(int startOffset, int endOffset, int variableIndex) { int previousOffset = endOffset; for (int offset = endOffset-1; offset >= startOffset; offset--) { if (livenessAnalyzer.isTraced(offset)) { if (livenessAnalyzer.isAliveBefore(offset, variableIndex)) { return previousOffset; } previousOffset = offset; } } return endOffset; } } proguard4.8/src/proguard/optimize/MethodStaticizer.java0000644000175000017500000000552111736333525022173 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.editor.MethodInvocationFixer; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.info.ParameterUsageMarker; import proguard.optimize.peephole.VariableShrinker; /** * This MemberVisitor makes all methods that it visits static, if their 'this' * parameters are unused. * * @see ParameterUsageMarker * @see MethodInvocationFixer * @see VariableShrinker * @author Eric Lafortune */ public class MethodStaticizer extends SimplifiedVisitor implements MemberVisitor, AttributeVisitor { private final MemberVisitor extraStaticMemberVisitor; /** * Creates a new MethodStaticizer. */ public MethodStaticizer() { this(null); } /** * Creates a new MethodStaticizer with an extra visitor. * @param extraStaticMemberVisitor an optional extra visitor for all * methods that have been made static. */ public MethodStaticizer(MemberVisitor extraStaticMemberVisitor) { this.extraStaticMemberVisitor = extraStaticMemberVisitor; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Is the 'this' parameter being used? if (!ParameterUsageMarker.isParameterUsed(programMethod, 0)) { // Make the method static. programMethod.u2accessFlags = (programMethod.getAccessFlags() & ~ClassConstants.INTERNAL_ACC_FINAL) | ClassConstants.INTERNAL_ACC_STATIC; // Visit the method, if required. if (extraStaticMemberVisitor != null) { extraStaticMemberVisitor.visitProgramMethod(programClass, programMethod); } } } } proguard4.8/src/proguard/optimize/peephole/0000775000175000017500000000000011760503005017633 5ustar ericericproguard4.8/src/proguard/optimize/peephole/TargetClassChanger.java0000644000175000017500000003775111736333525024230 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.editor.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** * This ClassVisitor replaces references to classes and class members if the * classes have targets that are intended to replace them. * * @see VerticalClassMerger * @see ClassReferenceFixer * @see MemberReferenceFixer * @author Eric Lafortune */ public class TargetClassChanger extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, MemberVisitor, AttributeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { private static final boolean DEBUG = false; // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Change the references of the constant pool. programClass.constantPoolEntriesAccept(this); // Change the references of the class members. programClass.fieldsAccept(this); programClass.methodsAccept(this); // Change the references of the attributes. programClass.attributesAccept(this); // Is the class itself being retargeted? Clazz targetClass = ClassMerger.getTargetClass(programClass); if (targetClass != null) { // Restore the class name. We have to add a new class entry // to avoid an existing entry with the same name being reused. The // names have to be fixed later, based on their referenced classes. programClass.u2thisClass = addNewClassConstant(programClass, programClass.getName(), programClass); // This class will loose all its interfaces. programClass.u2interfacesCount = 0; // This class will loose all its subclasses. programClass.subClasses = null; } else { // Remove interface classes that are pointing to this class. int newInterfacesCount = 0; for (int index = 0; index < programClass.u2interfacesCount; index++) { Clazz interfaceClass = programClass.getInterface(index); if (!programClass.equals(interfaceClass)) { programClass.u2interfaces[newInterfacesCount++] = programClass.u2interfaces[index]; } } programClass.u2interfacesCount = newInterfacesCount; // Update the subclasses of the superclass and interfaces of the // target class. ConstantVisitor subclassAdder = new ReferencedClassVisitor( new SubclassFilter(programClass, new SubclassAdder(programClass))); programClass.superClassConstantAccept(subclassAdder); programClass.interfaceConstantsAccept(subclassAdder); // TODO: Maybe restore private method references. } } public void visitLibraryClass(LibraryClass libraryClass) { // Change the references of the class members. libraryClass.fieldsAccept(this); libraryClass.methodsAccept(this); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Change the referenced class. programField.referencedClass = updateReferencedClass(programField.referencedClass); // Change the references of the attributes. programField.attributesAccept(programClass, this); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Change the referenced classes. updateReferencedClasses(programMethod.referencedClasses); // Change the references of the attributes. programMethod.attributesAccept(programClass, this); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { // Change the referenced class. libraryField.referencedClass = updateReferencedClass(libraryField.referencedClass); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { // Change the referenced classes. updateReferencedClasses(libraryMethod.referencedClasses); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Does the string refer to a class, due to a Class.forName construct? Clazz referencedClass = stringConstant.referencedClass; Clazz newReferencedClass = updateReferencedClass(referencedClass); if (referencedClass != newReferencedClass) { // Change the referenced class. stringConstant.referencedClass = newReferencedClass; // Change the referenced class member, if applicable. stringConstant.referencedMember = updateReferencedMember(stringConstant.referencedMember, stringConstant.getString(clazz), null, newReferencedClass); } } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { Clazz referencedClass = refConstant.referencedClass; Clazz newReferencedClass = updateReferencedClass(referencedClass); if (referencedClass != newReferencedClass) { if (DEBUG) { System.out.println("TargetClassChanger:"); System.out.println(" ["+clazz.getName()+"] changing reference from ["+refConstant.referencedClass+"."+refConstant.referencedMember.getName(refConstant.referencedClass)+refConstant.referencedMember.getDescriptor(refConstant.referencedClass)+"]"); } // Change the referenced class. refConstant.referencedClass = newReferencedClass; // Change the referenced class member. refConstant.referencedMember = updateReferencedMember(refConstant.referencedMember, refConstant.getName(clazz), refConstant.getType(clazz), newReferencedClass); if (DEBUG) { System.out.println(" ["+clazz.getName()+"] to ["+refConstant.referencedClass+"."+refConstant.referencedMember.getName(refConstant.referencedClass)+refConstant.referencedMember.getDescriptor(refConstant.referencedClass)+"]"); } } } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Change the referenced class. classConstant.referencedClass = updateReferencedClass(classConstant.referencedClass); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Change the references of the attributes. codeAttribute.attributesAccept(clazz, method, this); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Change the references of the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Change the references of the local variables. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { // Change the referenced classes. updateReferencedClasses(signatureAttribute.referencedClasses); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Change the references of the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Change the references of the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Change the references of the annotation. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Change the referenced class. localVariableInfo.referencedClass = updateReferencedClass(localVariableInfo.referencedClass); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { // Change the referenced classes. updateReferencedClasses(localVariableTypeInfo.referencedClasses); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { // Change the referenced classes. updateReferencedClasses(annotation.referencedClasses); // Change the references of the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) { Clazz referencedClass = elementValue.referencedClass; Clazz newReferencedClass = updateReferencedClass(referencedClass); if (referencedClass != newReferencedClass) { // Change the referenced annotation class. elementValue.referencedClass = newReferencedClass; // Change the referenced method. elementValue.referencedMethod = (Method)updateReferencedMember(elementValue.referencedMethod, elementValue.getMethodName(clazz), null, newReferencedClass); } } public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { // Change the referenced annotation class and method. visitAnyElementValue(clazz, annotation, constantElementValue); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { // Change the referenced annotation class and method. visitAnyElementValue(clazz, annotation, enumConstantElementValue); // Change the referenced classes. updateReferencedClasses(enumConstantElementValue.referencedClasses); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { // Change the referenced annotation class and method. visitAnyElementValue(clazz, annotation, classElementValue); // Change the referenced classes. updateReferencedClasses(classElementValue.referencedClasses); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { // Change the referenced annotation class and method. visitAnyElementValue(clazz, annotation, annotationElementValue); // Change the references of the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { // Change the referenced annotation class and method. visitAnyElementValue(clazz, annotation, arrayElementValue); // Change the references of the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } // Small utility methods. /** * Updates the retargeted classes in the given array of classes. */ private void updateReferencedClasses(Clazz[] referencedClasses) { if (referencedClasses == null) { return; } for (int index = 0; index < referencedClasses.length; index++) { referencedClasses[index] = updateReferencedClass(referencedClasses[index]); } } /** * Returns the retargeted class of the given class. */ private Clazz updateReferencedClass(Clazz referencedClass) { if (referencedClass == null) { return null; } Clazz targetClazz = ClassMerger.getTargetClass(referencedClass); return targetClazz != null ? targetClazz : referencedClass; } /** * Returns the retargeted class member of the given class member. */ private Member updateReferencedMember(Member referencedMember, String name, String type, Clazz newReferencedClass) { if (referencedMember == null) { return null; } return referencedMember instanceof Field ? (Member)newReferencedClass.findField(name, type) : (Member)newReferencedClass.findMethod(name, type); } /** * Explicitly adds a new class constant for the given class in the given * program class. */ private int addNewClassConstant(ProgramClass programClass, String className, Clazz referencedClass) { ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor(programClass); int nameIndex = constantPoolEditor.addUtf8Constant(className); int classConstantIndex = constantPoolEditor.addConstant(new ClassConstant(nameIndex, referencedClass)); return classConstantIndex; } }proguard4.8/src/proguard/optimize/peephole/package.html0000644000175000017500000000013311736333525022122 0ustar ericeric This package contains visitors that perform various peephole optimizations. proguard4.8/src/proguard/optimize/peephole/UnreachableCodeRemover.java0000644000175000017500000001132311736333525025053 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.Instruction; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor deletes blocks of code that can never be reached by * regular calls or branches. * * @author Eric Lafortune */ public class UnreachableCodeRemover extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final InstructionVisitor extraInstructionVisitor; private final ReachableCodeMarker reachableCodeMarker = new ReachableCodeMarker(); private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); /** * Creates a new UnreachableCodeRemover. */ public UnreachableCodeRemover() { this(null); } /** * Creates a new UnreachableCodeRemover. * @param extraInstructionVisitor an optional extra visitor for all * deleted instructions. */ public UnreachableCodeRemover(InstructionVisitor extraInstructionVisitor) { this.extraInstructionVisitor = extraInstructionVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // TODO: Remove this when the code has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while removing unreachable code:"); System.err.println(" Class = ["+clazz.getName()+"]"); System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); throw ex; } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (DEBUG) { System.out.println("UnreachableCodeRemover: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); } reachableCodeMarker.visitCodeAttribute(clazz, method, codeAttribute); codeAttributeEditor.reset(codeAttribute.u4codeLength); codeAttribute.instructionsAccept(clazz, method, this); codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { if (DEBUG) { System.out.println(" "+(reachableCodeMarker.isReachable(offset) ? "+" : "-")+" "+instruction.toString(offset)); } // Is this instruction unreachable? if (!reachableCodeMarker.isReachable(offset)) { // Then delete it. codeAttributeEditor.deleteInstruction(offset); // Visit the instruction, if required. if (extraInstructionVisitor != null) { instruction.accept(clazz, method, codeAttribute, offset, extraInstructionVisitor); } } } } proguard4.8/src/proguard/optimize/peephole/VerticalClassMerger.java0000644000175000017500000000700611736333525024413 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.ProgramClass; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor inlines the direct subclasses into the program classes * that it visits, whenever possible. * * @see ClassMerger * @author Eric Lafortune */ public class VerticalClassMerger extends SimplifiedVisitor implements ClassVisitor { private final boolean allowAccessModification; private final boolean mergeInterfacesAggressively; private final ClassVisitor extraClassVisitor; /** * Creates a new VerticalClassMerger. * @param allowAccessModification specifies whether the access modifiers * of classes can be changed in order to * merge them. * @param mergeInterfacesAggressively specifies whether interfaces may * be merged aggressively. */ public VerticalClassMerger(boolean allowAccessModification, boolean mergeInterfacesAggressively) { this(allowAccessModification, mergeInterfacesAggressively, null); } /** * Creates a new VerticalClassMerger. * @param allowAccessModification specifies whether the access modifiers * of classes can be changed in order to * merge them. * @param mergeInterfacesAggressively specifies whether interfaces may * be merged aggressively. * @param extraClassVisitor an optional extra visitor for all * merged classes. */ public VerticalClassMerger(boolean allowAccessModification, boolean mergeInterfacesAggressively, ClassVisitor extraClassVisitor) { this.allowAccessModification = allowAccessModification; this.mergeInterfacesAggressively = mergeInterfacesAggressively; this.extraClassVisitor = extraClassVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.subclassesAccept(new ClassMerger(programClass, allowAccessModification, mergeInterfacesAggressively, extraClassVisitor)); } }proguard4.8/src/proguard/optimize/peephole/InstructionSequencesReplacer.java0000644000175000017500000001572311736333525026372 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.constant.Constant; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.Instruction; import proguard.classfile.instruction.visitor.*; /** * This InstructionVisitor replaces multiple instruction sequences at once. * * @see InstructionSequenceReplacer * @author Eric Lafortune */ public class InstructionSequencesReplacer extends MultiInstructionVisitor implements InstructionVisitor { private static final int PATTERN_INDEX = 0; private static final int REPLACEMENT_INDEX = 1; /** * Creates a new InstructionSequencesReplacer. * @param patternConstants any constants referenced by the pattern * instruction. * @param instructionSequences the instruction sequences to be replaced, * with subsequently the sequence pair index, * the patten/replacement index (0 or 1), * and the instruction index in the sequence. * @param branchTargetFinder a branch target finder that has been * initialized to indicate branch targets * in the visited code. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. */ public InstructionSequencesReplacer(Constant[] patternConstants, Instruction[][][] instructionSequences, BranchTargetFinder branchTargetFinder, CodeAttributeEditor codeAttributeEditor) { this(patternConstants, instructionSequences, branchTargetFinder, codeAttributeEditor, null); } /** * Creates a new InstructionSequenceReplacer. * @param patternConstants any constants referenced by the pattern * instruction. * @param instructionSequences the instruction sequences to be replaced, * with subsequently the sequence pair index, * the patten/replacement index (0 or 1), * and the instruction index in the sequence. * @param branchTargetFinder a branch target finder that has been * initialized to indicate branch targets * in the visited code. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. * @param extraInstructionVisitor an optional extra visitor for all deleted * load instructions. */ public InstructionSequencesReplacer(Constant[] patternConstants, Instruction[][][] instructionSequences, BranchTargetFinder branchTargetFinder, CodeAttributeEditor codeAttributeEditor, InstructionVisitor extraInstructionVisitor) { super(createInstructionSequenceReplacers(patternConstants, instructionSequences, branchTargetFinder, codeAttributeEditor, extraInstructionVisitor)); } /** * Creates an array of InstructionSequenceReplacer instances. * @param patternConstants any constants referenced by the pattern * instruction. * @param instructionSequences the instruction sequences to be replaced, * with subsequently the sequence pair index, * the from/to index (0 or 1), and the * instruction index in the sequence. * @param branchTargetFinder a branch target finder that has been * initialized to indicate branch targets * in the visited code. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. * @param extraInstructionVisitor an optional extra visitor for all deleted * load instructions. */ private static InstructionVisitor[] createInstructionSequenceReplacers(Constant[] patternConstants, Instruction[][][] instructionSequences, BranchTargetFinder branchTargetFinder, CodeAttributeEditor codeAttributeEditor, InstructionVisitor extraInstructionVisitor) { InstructionVisitor[] instructionSequenceReplacers = new InstructionSequenceReplacer[instructionSequences.length]; for (int index = 0; index < instructionSequenceReplacers.length; index++) { Instruction[][] instructionSequencePair = instructionSequences[index]; instructionSequenceReplacers[index] = new InstructionSequenceReplacer(patternConstants, instructionSequencePair[PATTERN_INDEX], instructionSequencePair[REPLACEMENT_INDEX], branchTargetFinder, codeAttributeEditor, extraInstructionVisitor); } return instructionSequenceReplacers; } } proguard4.8/src/proguard/optimize/peephole/MethodInliner.java0000664000175000017500000006101411736333525023254 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.optimize.info.*; import java.util.*; /** * This AttributeVisitor inlines short methods or methods that are only invoked * once, in the code attributes that it visits. * * @author Eric Lafortune */ public class MethodInliner extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ConstantVisitor, MemberVisitor { private static final int MAXIMUM_INLINED_CODE_LENGTH = Integer.parseInt(System.getProperty("maximum.inlined.code.length", "8")); private static final int MAXIMUM_RESULTING_CODE_LENGTH_JSE = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "7000")); private static final int MAXIMUM_RESULTING_CODE_LENGTH_JME = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "2000")); //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final boolean microEdition; private final boolean allowAccessModification; private final boolean inlineSingleInvocations; private final InstructionVisitor extraInlinedInvocationVisitor; private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(); private final AccessMethodMarker accessMethodMarker = new AccessMethodMarker(); private final CatchExceptionMarker catchExceptionMarker = new CatchExceptionMarker(); private final StackSizeComputer stackSizeComputer = new StackSizeComputer(); private ProgramClass targetClass; private ProgramMethod targetMethod; private ConstantAdder constantAdder; private ExceptionInfoAdder exceptionInfoAdder; private int estimatedResultingCodeLength; private boolean inlining; private Stack inliningMethods = new Stack(); private boolean emptyInvokingStack; private int uninitializedObjectCount; private int variableOffset; private boolean inlined; private boolean inlinedAny; /** * Creates a new MethodInliner. * @param microEdition indicates whether the resulting code is * targeted at Java Micro Edition. * @param allowAccessModification indicates whether the access modifiers of * classes and class members can be changed * in order to inline methods. * @param inlineSingleInvocations indicates whether the single invocations * should be inlined, or, alternatively, * short methods. */ public MethodInliner(boolean microEdition, boolean allowAccessModification, boolean inlineSingleInvocations) { this(microEdition, allowAccessModification, inlineSingleInvocations, null); } /** * Creates a new MethodInliner. * @param microEdition indicates whether the resulting code is * targeted at Java Micro Edition. * @param allowAccessModification indicates whether the access modifiers of * classes and class members can be changed * in order to inline methods. * @param inlineSingleInvocations indicates whether the single invocations * should be inlined, or, alternatively, * short methods. * @param extraInlinedInvocationVisitor an optional extra visitor for all * inlined invocation instructions. */ public MethodInliner(boolean microEdition, boolean allowAccessModification, boolean inlineSingleInvocations, InstructionVisitor extraInlinedInvocationVisitor) { this.microEdition = microEdition; this.allowAccessModification = allowAccessModification; this.inlineSingleInvocations = inlineSingleInvocations; this.extraInlinedInvocationVisitor = extraInlinedInvocationVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // TODO: Remove this when the method inliner has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { // Process the code. visitCodeAttribute0(clazz, method, codeAttribute); } catch (RuntimeException ex) { System.err.println("Unexpected error while inlining method:"); System.err.println(" Target class = ["+targetClass.getName()+"]"); System.err.println(" Target method = ["+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]"); if (inlining) { System.err.println(" Inlined class = ["+clazz.getName()+"]"); System.err.println(" Inlined method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); } System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); System.err.println("Not inlining this method"); if (DEBUG) { targetMethod.accept(targetClass, new ClassPrinter()); if (inlining) { method.accept(clazz, new ClassPrinter()); } throw ex; } } } public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (!inlining) { // codeAttributeComposer.DEBUG = DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); targetClass = (ProgramClass)clazz; targetMethod = (ProgramMethod)method; constantAdder = new ConstantAdder(targetClass); exceptionInfoAdder = new ExceptionInfoAdder(targetClass, codeAttributeComposer); estimatedResultingCodeLength = codeAttribute.u4codeLength; inliningMethods.clear(); uninitializedObjectCount = method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ? 1 : 0; inlinedAny = false; codeAttributeComposer.reset(); stackSizeComputer.visitCodeAttribute(clazz, method, codeAttribute); // Append the body of the code. copyCode(clazz, method, codeAttribute); targetClass = null; targetMethod = null; constantAdder = null; // Update the code attribute if any code has been inlined. if (inlinedAny) { codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute); // Update the accessing flags. codeAttribute.instructionsAccept(clazz, method, accessMethodMarker); // Update the exception catching flags. catchExceptionMarker.visitCodeAttribute(clazz, method, codeAttribute); } } // Only inline the method if it is invoked once or if it is short. else if ((inlineSingleInvocations ? MethodInvocationMarker.getInvocationCount(method) == 1 : codeAttribute.u4codeLength <= MAXIMUM_INLINED_CODE_LENGTH) && estimatedResultingCodeLength + codeAttribute.u4codeLength < (microEdition ? MAXIMUM_RESULTING_CODE_LENGTH_JME : MAXIMUM_RESULTING_CODE_LENGTH_JSE)) { if (DEBUG) { System.out.println("MethodInliner: inlining ["+ clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] in ["+ targetClass.getName()+"."+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]"); } // Ignore the removal of the original method invocation, // the addition of the parameter setup, and // the modification of a few inlined instructions. estimatedResultingCodeLength += codeAttribute.u4codeLength; // Append instructions to store the parameters. storeParameters(clazz, method); // Inline the body of the code. copyCode(clazz, method, codeAttribute); inlined = true; inlinedAny = true; } } /** * Appends instructions to pop the parameters for the given method, storing * them in new local variables. */ private void storeParameters(Clazz clazz, Method method) { String descriptor = method.getDescriptor(clazz); boolean isStatic = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0; // Count the number of parameters, taking into account their categories. int parameterCount = ClassUtil.internalMethodParameterCount(descriptor); int parameterSize = ClassUtil.internalMethodParameterSize(descriptor); int parameterOffset = isStatic ? 0 : 1; // Store the parameter types. String[] parameterTypes = new String[parameterSize]; InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); for (int parameterIndex = 0; parameterIndex < parameterSize; parameterIndex++) { String parameterType = internalTypeEnumeration.nextType(); parameterTypes[parameterIndex] = parameterType; if (ClassUtil.internalTypeSize(parameterType) == 2) { parameterIndex++; } } codeAttributeComposer.beginCodeFragment(parameterSize+1); // Go over the parameter types backward, storing the stack entries // in their corresponding variables. for (int parameterIndex = parameterSize-1; parameterIndex >= 0; parameterIndex--) { String parameterType = parameterTypes[parameterIndex]; if (parameterType != null) { byte opcode; switch (parameterType.charAt(0)) { case ClassConstants.INTERNAL_TYPE_BOOLEAN: case ClassConstants.INTERNAL_TYPE_BYTE: case ClassConstants.INTERNAL_TYPE_CHAR: case ClassConstants.INTERNAL_TYPE_SHORT: case ClassConstants.INTERNAL_TYPE_INT: opcode = InstructionConstants.OP_ISTORE; break; case ClassConstants.INTERNAL_TYPE_LONG: opcode = InstructionConstants.OP_LSTORE; break; case ClassConstants.INTERNAL_TYPE_FLOAT: opcode = InstructionConstants.OP_FSTORE; break; case ClassConstants.INTERNAL_TYPE_DOUBLE: opcode = InstructionConstants.OP_DSTORE; break; default: opcode = InstructionConstants.OP_ASTORE; break; } codeAttributeComposer.appendInstruction(parameterSize-parameterIndex-1, new VariableInstruction(opcode, variableOffset + parameterOffset + parameterIndex).shrink()); } } // Put the 'this' reference in variable 0 (plus offset). if (!isStatic) { codeAttributeComposer.appendInstruction(parameterSize, new VariableInstruction(InstructionConstants.OP_ASTORE, variableOffset).shrink()); } codeAttributeComposer.endCodeFragment(); } /** * Appends the code of the given code attribute. */ private void copyCode(Clazz clazz, Method method, CodeAttribute codeAttribute) { // The code may expand, due to expanding constant and variable // instructions. codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); // Copy the instructions. codeAttribute.instructionsAccept(clazz, method, this); // Append a label just after the code. codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); // Copy the exceptions. codeAttribute.exceptionsAccept(clazz, method, exceptionInfoAdder); codeAttributeComposer.endCodeFragment(); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { codeAttributeComposer.appendInstruction(offset, instruction.shrink()); } public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Are we inlining this instruction? if (inlining) { // Replace any return instructions by branches to the end of the code. switch (simpleInstruction.opcode) { case InstructionConstants.OP_IRETURN: case InstructionConstants.OP_LRETURN: case InstructionConstants.OP_FRETURN: case InstructionConstants.OP_DRETURN: case InstructionConstants.OP_ARETURN: case InstructionConstants.OP_RETURN: // Are we not at the last instruction? if (offset < codeAttribute.u4codeLength-1) { // Replace the return instruction by a branch instruction. Instruction branchInstruction = new BranchInstruction(InstructionConstants.OP_GOTO_W, codeAttribute.u4codeLength - offset); codeAttributeComposer.appendInstruction(offset, branchInstruction.shrink()); } else { // Just leave out the instruction, but put in a label, // for the sake of any other branch instructions. codeAttributeComposer.appendLabel(offset); } return; } } codeAttributeComposer.appendInstruction(offset, simpleInstruction.shrink()); } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Are we inlining this instruction? if (inlining) { // Update the variable index. variableInstruction.variableIndex += variableOffset; } codeAttributeComposer.appendInstruction(offset, variableInstruction.shrink()); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Is it a method invocation? switch (constantInstruction.opcode) { case InstructionConstants.OP_NEW: uninitializedObjectCount++; break; case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: // See if we can inline it. inlined = false; // Append a label, in case the invocation will be inlined. codeAttributeComposer.appendLabel(offset); emptyInvokingStack = !inlining && stackSizeComputer.isReachable(offset) && stackSizeComputer.getStackSize(offset) == 0; variableOffset += codeAttribute.u2maxLocals; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); variableOffset -= codeAttribute.u2maxLocals; // Was the method inlined? if (inlined) { if (extraInlinedInvocationVisitor != null) { extraInlinedInvocationVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, constantInstruction); } // The invocation itself is no longer necessary. return; } break; } // Are we inlining this instruction? if (inlining) { // Make sure the constant is present in the constant pool of the // target class. constantInstruction.constantIndex = constantAdder.addConstant(clazz, constantInstruction.constantIndex); } codeAttributeComposer.appendInstruction(offset, constantInstruction.shrink()); } // Implementations for ConstantVisitor. public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) {} public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { methodrefConstant.referencedMemberAccept(this); } // Implementations for MemberVisitor. public void visitAnyMember(Clazz Clazz, Member member) {} public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { int accessFlags = programMethod.getAccessFlags(); if (// Only inline the method if it is private, static, or final. (accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_FINAL)) != 0 && // Only inline the method if it is not synchronized, etc. (accessFlags & (ClassConstants.INTERNAL_ACC_SYNCHRONIZED | ClassConstants.INTERNAL_ACC_NATIVE | ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 && // Don't inline an method, except in an method in the // same class. // (!programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) || // (programClass.equals(targetClass) && // targetMethod.getName(targetClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))) && !programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) && // Don't inline a method into itself. (!programMethod.equals(targetMethod) || !programClass.equals(targetClass)) && // Only inline the method if it isn't recursing. !inliningMethods.contains(programMethod) && // Only inline the method if its target class has at least the // same version number as the source class, in order to avoid // introducing incompatible constructs. targetClass.u4version >= programClass.u4version && // Only inline the method if it doesn't invoke a super method, or if // it is in the same class. (!SuperInvocationMarker.invokesSuperMethods(programMethod) || programClass.equals(targetClass)) && // Only inline the method if it doesn't branch backward while there // are uninitialized objects. (!BackwardBranchMarker.branchesBackward(programMethod) || uninitializedObjectCount == 0) && // Only inline if the code access of the inlined method allows it. (allowAccessModification || ((!AccessMethodMarker.accessesPrivateCode(programMethod) || programClass.equals(targetClass)) && (!AccessMethodMarker.accessesPackageCode(programMethod) || ClassUtil.internalPackageName(programClass.getName()).equals( ClassUtil.internalPackageName(targetClass.getName()))))) && // (!AccessMethodMarker.accessesProtectedCode(programMethod) || // targetClass.extends_(programClass) || // targetClass.implements_(programClass)) || (!AccessMethodMarker.accessesProtectedCode(programMethod) || programClass.equals(targetClass)) && // Only inline the method if it doesn't catch exceptions, or if it // is invoked with an empty stack. (!CatchExceptionMarker.catchesExceptions(programMethod) || emptyInvokingStack) && // Only inline the method if it comes from the a class with at most // a subset of the initialized superclasses. (programClass.equals(targetClass) || initializedSuperClasses(targetClass).containsAll(initializedSuperClasses(programClass)))) { boolean oldInlining = inlining; inlining = true; inliningMethods.push(programMethod); // Inline the method body. programMethod.attributesAccept(programClass, this); // Update the optimization information of the target method. MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(targetMethod); if (info != null) { info.merge(MethodOptimizationInfo.getMethodOptimizationInfo(programMethod)); } inlining = oldInlining; inliningMethods.pop(); } else if (programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { uninitializedObjectCount--; } } /** * Returns the set of superclasses and interfaces that are initialized. */ private Set initializedSuperClasses(Clazz clazz) { Set set = new HashSet(); // Visit all superclasses and interfaces, collecting the ones that have // static initializers. clazz.hierarchyAccept(true, true, true, false, new StaticInitializerContainingClassFilter( new ClassCollector(set))); return set; } } proguard4.8/src/proguard/optimize/peephole/GotoGotoReplacer.java0000644000175000017500000001106611736333525023732 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor simplifies unconditional branches to other * unconditional branches. * * @author Eric Lafortune */ public class GotoGotoReplacer extends SimplifiedVisitor implements InstructionVisitor { private final CodeAttributeEditor codeAttributeEditor; private final InstructionVisitor extraInstructionVisitor; /** * Creates a new GotoGotoReplacer. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. */ public GotoGotoReplacer(CodeAttributeEditor codeAttributeEditor) { this(codeAttributeEditor, null); } /** * Creates a new GotoGotoReplacer. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. * @param extraInstructionVisitor an optional extra visitor for all replaced * goto instructions. */ public GotoGotoReplacer(CodeAttributeEditor codeAttributeEditor, InstructionVisitor extraInstructionVisitor) { this.codeAttributeEditor = codeAttributeEditor; this.extraInstructionVisitor = extraInstructionVisitor; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Check if the instruction is an unconditional goto instruction. byte opcode = branchInstruction.opcode; if (opcode == InstructionConstants.OP_GOTO || opcode == InstructionConstants.OP_GOTO_W) { // Check if the goto instruction points to another simple goto // instruction. int branchOffset = branchInstruction.branchOffset; int targetOffset = offset + branchOffset; if (branchOffset != 0 && branchOffset != branchInstruction.length(offset) && !codeAttributeEditor.isModified(offset) && !codeAttributeEditor.isModified(targetOffset)) { Instruction targetInstruction = InstructionFactory.create(codeAttribute.code, targetOffset); if (targetInstruction.opcode == InstructionConstants.OP_GOTO) { // Simplify the goto instruction. int targetBranchOffset = ((BranchInstruction)targetInstruction).branchOffset; Instruction newBranchInstruction = new BranchInstruction(opcode, (branchOffset + targetBranchOffset)); codeAttributeEditor.replaceInstruction(offset, newBranchInstruction); // Visit the instruction, if required. if (extraInstructionVisitor != null) { extraInstructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction); } } } } } } proguard4.8/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java0000664000175000017500000001306711740561642030012 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; 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.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; import java.util.Arrays; /** * This ClassVisitor removes InnerClasses and EnclosingMethod attributes in * classes that are retargeted or that refer to classes that are retargeted. * * @see ClassMerger * @author Eric Lafortune */ public class RetargetedInnerClassAttributeRemover extends SimplifiedVisitor implements ClassVisitor, AttributeVisitor, InnerClassesInfoVisitor, ConstantVisitor { private boolean retargeted; // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { int attributesCount = programClass.u2attributesCount; Attribute[] attributes = programClass.attributes; int newAtributesCount = 0; // Copy over all non-retargeted attributes. for (int index = 0; index < attributesCount; index++) { Attribute attribute = attributes[index]; // Check if it's an InnerClasses or EnclosingMethod attribute in // a retargeted class or referring to a retargeted class. retargeted = false; attribute.accept(programClass, this); if (!retargeted) { attributes[newAtributesCount++] = attribute; } } // Clean up any remaining array elements. Arrays.fill(attributes, newAtributesCount, attributesCount, null); // Update the number of attributes. programClass.u2attributesCount = newAtributesCount; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Check whether the class itself is retargeted. checkTarget(clazz); if (!retargeted) { // Check whether the referenced classes are retargeted. innerClassesAttribute.innerClassEntriesAccept(clazz, this); int classesCount = innerClassesAttribute.u2classesCount; InnerClassesInfo[] classes = innerClassesAttribute.classes; int newClassesCount = 0; // Copy over all non-retargeted attributes. for (int index = 0; index < classesCount; index++) { InnerClassesInfo classInfo = classes[index]; // Check if the outer class or inner class is a retargeted class. retargeted = false; classInfo.outerClassConstantAccept(clazz, this); classInfo.innerClassConstantAccept(clazz, this); if (!retargeted) { classes[newClassesCount++] = classInfo; } } // Clean up any remaining array elements. Arrays.fill(classes, newClassesCount, classesCount, null); // Update the number of classes. innerClassesAttribute.u2classesCount = newClassesCount; // Remove the attribute altogether if it's empty. retargeted = newClassesCount == 0; } } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { // Check whether the class itself is retargeted. checkTarget(clazz); // Check whether the referenced class is retargeted. checkTarget(enclosingMethodAttribute.referencedClass); } // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) { // Check whether the inner class or the outer class are retargeted. innerClassesInfo.innerClassConstantAccept(clazz, this); innerClassesInfo.outerClassConstantAccept(clazz, this); } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Check whether the referenced class is retargeted. checkTarget(classConstant.referencedClass); } // Small utility methods. /** * Sets the global return value to true if the given class is retargeted. */ private void checkTarget(Clazz clazz) { if (clazz != null && ClassMerger.getTargetClass(clazz) != null) { retargeted = true; } } }proguard4.8/src/proguard/optimize/peephole/MethodFinalizer.java0000644000175000017500000000632011736333525023574 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.optimize.KeepMarker; /** * This MemberVisitor makes the program methods that it visits * final, if possible. * * @author Eric Lafortune */ public class MethodFinalizer extends SimplifiedVisitor implements MemberVisitor { private final MemberVisitor extraMemberVisitor; private final MemberFinder memberFinder = new MemberFinder(); /** * Creates a new ClassFinalizer. */ public MethodFinalizer() { this(null); } /** * Creates a new ClassFinalizer. * @param extraMemberVisitor an optional extra visitor for all finalized * methods. */ public MethodFinalizer(MemberVisitor extraMemberVisitor) { this.extraMemberVisitor = extraMemberVisitor; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { String name = programMethod.getName(programClass); // If the method is not already private/static/final/abstract, // and it is not a constructor, // and its class is final, // or it is not being kept and it is not overridden, // then make it final. if ((programMethod.u2accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_FINAL | ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 && !name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) && ((programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0 || (!KeepMarker.isKept(programMethod) && (programClass.subClasses == null || !memberFinder.isOverriden(programClass, programMethod))))) { programMethod.u2accessFlags |= ClassConstants.INTERNAL_ACC_FINAL; // Visit the method, if required. if (extraMemberVisitor != null) { extraMemberVisitor.visitProgramMethod(programClass, programMethod); } } } }proguard4.8/src/proguard/optimize/peephole/HorizontalClassMerger.java0000644000175000017500000000725211736333525024776 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor inlines siblings in the program classes that it visits, * whenever possible. * * @see ClassMerger * @author Eric Lafortune */ public class HorizontalClassMerger extends SimplifiedVisitor implements ClassVisitor { private final boolean allowAccessModification; private final boolean mergeInterfacesAggressively; private final ClassVisitor extraClassVisitor; /** * Creates a new HorizontalClassMerger. * @param allowAccessModification specifies whether the access modifiers * of classes can be changed in order to * merge them. * @param mergeInterfacesAggressively specifies whether interfaces may * be merged aggressively. */ public HorizontalClassMerger(boolean allowAccessModification, boolean mergeInterfacesAggressively) { this(allowAccessModification, mergeInterfacesAggressively, null); } /** * Creates a new VerticalClassMerger. * @param allowAccessModification specifies whether the access modifiers * of classes can be changed in order to * merge them. * @param mergeInterfacesAggressively specifies whether interfaces may * be merged aggressively. * @param extraClassVisitor an optional extra visitor for all * merged classes. */ public HorizontalClassMerger(boolean allowAccessModification, boolean mergeInterfacesAggressively, ClassVisitor extraClassVisitor) { this.allowAccessModification = allowAccessModification; this.mergeInterfacesAggressively = mergeInterfacesAggressively; this.extraClassVisitor = extraClassVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { programClass.superClassConstantAccept(new ReferencedClassVisitor( new SubclassTraveler( new ProgramClassFilter( new ClassMerger(programClass, allowAccessModification, mergeInterfacesAggressively, extraClassVisitor))))); } }proguard4.8/src/proguard/optimize/peephole/ReachableCodeMarker.java0000644000175000017500000002003311736333525024310 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import java.util.Arrays; /** * This AttributeVisitor finds all instruction offsets, branch targets, and * exception targets in the CodeAttribute objects that it visits. * * @author Eric Lafortune */ public class ReachableCodeMarker extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor { private boolean[] isReachable = new boolean[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean next; private boolean evaluateExceptions; /** * Returns whether the instruction at the given offset is reachable in * the CodeAttribute that was visited most recently. */ public boolean isReachable(int offset) { return isReachable[offset]; } /** * Returns whether any of the instructions at the given offsets are * reachable in the CodeAttribute that was visited most recently. */ public boolean isReachable(int startOffset, int endOffset) { // Check if any of the instructions is reachable. for (int offset = startOffset; offset < endOffset; offset++) { if (isReachable[offset]) { return true; } } return false; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Make sure there is a sufficiently large array. int codeLength = codeAttribute.u4codeLength; if (isReachable.length < codeLength) { // Create a new array. isReachable = new boolean[codeLength]; } else { // Reset the array. Arrays.fill(isReachable, 0, codeLength, false); } // Mark the code, starting at the entry point. markCode(clazz, method, codeAttribute, 0); // Mark the exception handlers, iterating as long as necessary. do { evaluateExceptions = false; codeAttribute.exceptionsAccept(clazz, method, this); } while (evaluateExceptions); } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { byte opcode = simpleInstruction.opcode; if (opcode == InstructionConstants.OP_IRETURN || opcode == InstructionConstants.OP_LRETURN || opcode == InstructionConstants.OP_FRETURN || opcode == InstructionConstants.OP_DRETURN || opcode == InstructionConstants.OP_ARETURN || opcode == InstructionConstants.OP_RETURN || opcode == InstructionConstants.OP_ATHROW) { next = false; } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { if (variableInstruction.opcode == InstructionConstants.OP_RET) { next = false; } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Mark the branch target. markBranchTarget(clazz, method, codeAttribute, offset + branchInstruction.branchOffset); byte opcode = branchInstruction.opcode; if (opcode == InstructionConstants.OP_GOTO || opcode == InstructionConstants.OP_GOTO_W) { next = false; } } public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) { // Mark the branch targets of the default jump offset. markBranchTarget(clazz, method, codeAttribute, offset + switchInstruction.defaultOffset); // Mark the branch targets of the jump offsets. markBranchTargets(clazz, method, codeAttribute, offset, switchInstruction.jumpOffsets); next = false; } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { // Mark the exception handler if it's relevant. if (!isReachable(exceptionInfo.u2handlerPC) && isReachable(exceptionInfo.u2startPC, exceptionInfo.u2endPC)) { markCode(clazz, method, codeAttribute, exceptionInfo.u2handlerPC); evaluateExceptions = true; } } // Small utility methods. /** * Marks the branch targets of the given jump offsets for the instruction * at the given offset. */ private void markBranchTargets(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int[] jumpOffsets) { for (int index = 0; index < jumpOffsets.length; index++) { markCode(clazz, method, codeAttribute, offset + jumpOffsets[index]); } } /** * Marks the branch target at the given offset. */ private void markBranchTarget(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset) { boolean oldNext = next; markCode(clazz, method, codeAttribute, offset); next = oldNext; } /** * Marks the code starting at the given offset. */ private void markCode(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset) { boolean oldNext = next; byte[] code = codeAttribute.code; // Continue with the current instruction as long as we haven't marked it // yet. while (!isReachable[offset]) { // Get the current instruction. Instruction instruction = InstructionFactory.create(code, offset); // Mark it as reachable. isReachable[offset] = true; // By default, we'll assume we can continue with the next // instruction in a moment. next = true; // Mark the branch targets, if any. instruction.accept(clazz, method, codeAttribute, offset, this); // Can we really continue with the next instruction? if (!next) { break; } // Go to the next instruction. offset += instruction.length(offset); } next = oldNext; } } proguard4.8/src/proguard/optimize/peephole/GotoReturnReplacer.java0000644000175000017500000001125311736333525024277 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor replaces unconditional branches to return instructions * by these same return instructions. * * @author Eric Lafortune */ public class GotoReturnReplacer extends SimplifiedVisitor implements InstructionVisitor { private final CodeAttributeEditor codeAttributeEditor; private final InstructionVisitor extraInstructionVisitor; /** * Creates a new GotoReturnReplacer. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. */ public GotoReturnReplacer(CodeAttributeEditor codeAttributeEditor) { this(codeAttributeEditor, null); } /** * Creates a new GotoReturnReplacer. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. * @param extraInstructionVisitor an optional extra visitor for all replaced * goto instructions. */ public GotoReturnReplacer(CodeAttributeEditor codeAttributeEditor, InstructionVisitor extraInstructionVisitor) { this.codeAttributeEditor = codeAttributeEditor; this.extraInstructionVisitor = extraInstructionVisitor; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Check if the instruction is an unconditional goto instruction. byte opcode = branchInstruction.opcode; if (opcode == InstructionConstants.OP_GOTO || opcode == InstructionConstants.OP_GOTO_W) { // Check if the goto instruction points to a return instruction. int targetOffset = offset + branchInstruction.branchOffset; if (!codeAttributeEditor.isModified(offset) && !codeAttributeEditor.isModified(targetOffset)) { Instruction targetInstruction = InstructionFactory.create(codeAttribute.code, targetOffset); switch (targetInstruction.opcode) { case InstructionConstants.OP_IRETURN: case InstructionConstants.OP_LRETURN: case InstructionConstants.OP_FRETURN: case InstructionConstants.OP_DRETURN: case InstructionConstants.OP_ARETURN: case InstructionConstants.OP_RETURN: // Replace the goto instruction by the return instruction. Instruction returnInstruction = new SimpleInstruction(targetInstruction.opcode); codeAttributeEditor.replaceInstruction(offset, returnInstruction); // Visit the instruction, if required. if (extraInstructionVisitor != null) { extraInstructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction); } break; } } } } } proguard4.8/src/proguard/optimize/peephole/InstructionSequenceConstants.java0000664000175000017500000071604411736333525026434 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.instruction.*; import proguard.classfile.visitor.ClassPrinter; /** * This class contains a set of instruction sequences and their suggested * replacements. * * @see InstructionSequencesReplacer * @see InstructionSequenceReplacer * @author Eric Lafortune */ public class InstructionSequenceConstants { private static final int X = InstructionSequenceReplacer.X; private static final int Y = InstructionSequenceReplacer.Y; private static final int Z = InstructionSequenceReplacer.Z; private static final int A = InstructionSequenceReplacer.A; private static final int B = InstructionSequenceReplacer.B; private static final int C = InstructionSequenceReplacer.C; private static final int D = InstructionSequenceReplacer.D; private static final int STRING_A_LENGTH = InstructionSequenceReplacer.STRING_A_LENGTH; private static final int BOOLEAN_A_STRING = InstructionSequenceReplacer.BOOLEAN_A_STRING; private static final int CHAR_A_STRING = InstructionSequenceReplacer.CHAR_A_STRING; private static final int INT_A_STRING = InstructionSequenceReplacer.INT_A_STRING; private static final int LONG_A_STRING = InstructionSequenceReplacer.LONG_A_STRING; private static final int FLOAT_A_STRING = InstructionSequenceReplacer.FLOAT_A_STRING; private static final int DOUBLE_A_STRING = InstructionSequenceReplacer.DOUBLE_A_STRING; private static final int STRING_A_STRING = InstructionSequenceReplacer.STRING_A_STRING; private static final int BOOLEAN_B_STRING = InstructionSequenceReplacer.BOOLEAN_B_STRING; private static final int CHAR_B_STRING = InstructionSequenceReplacer.CHAR_B_STRING; private static final int INT_B_STRING = InstructionSequenceReplacer.INT_B_STRING; private static final int LONG_B_STRING = InstructionSequenceReplacer.LONG_B_STRING; private static final int FLOAT_B_STRING = InstructionSequenceReplacer.FLOAT_B_STRING; private static final int DOUBLE_B_STRING = InstructionSequenceReplacer.DOUBLE_B_STRING; private static final int STRING_B_STRING = InstructionSequenceReplacer.STRING_B_STRING; private static final int I_32768 = 0; private static final int I_65536 = 1; private static final int I_16777216 = 2; // private static final int I_0x000000ff private static final int I_0x0000ff00 = 3; private static final int I_0x00ff0000 = 4; private static final int I_0xff000000 = 5; private static final int I_0x0000ffff = 6; private static final int I_0xffff0000 = 7; private static final int L_M1 = 8; private static final int L_2 = 9; private static final int L_4 = 10; private static final int L_8 = 11; private static final int L_16 = 12; private static final int L_32 = 13; private static final int L_64 = 14; private static final int L_128 = 15; private static final int L_256 = 16; private static final int L_512 = 17; private static final int L_1024 = 18; private static final int L_2048 = 19; private static final int L_4096 = 20; private static final int L_8192 = 21; private static final int L_16384 = 22; private static final int L_32768 = 23; private static final int L_65536 = 24; private static final int L_16777216 = 25; private static final int L_4294967296 = 26; private static final int L_0x00000000ffffffff = 27; private static final int L_0xffffffff00000000 = 28; private static final int F_M1 = 29; private static final int D_M1 = 30; private static final int STRING_EMPTY = 31; private static final int FIELD_I = 32; // Implicitly uses X and Y. private static final int FIELD_L = 33; // Implicitly uses X and Y. private static final int FIELD_F = 34; // Implicitly uses X and Y. private static final int FIELD_D = 35; // Implicitly uses X and Y. private static final int METHOD_STRING_EQUALS = 36; private static final int METHOD_STRING_LENGTH = 37; private static final int METHOD_STRING_VALUEOF_Z = 38; private static final int METHOD_STRING_VALUEOF_C = 39; private static final int METHOD_STRING_VALUEOF_I = 40; private static final int METHOD_STRING_VALUEOF_J = 41; private static final int METHOD_STRING_VALUEOF_F = 42; private static final int METHOD_STRING_VALUEOF_D = 43; private static final int METHOD_STRING_VALUEOF_OBJECT = 44; private static final int METHOD_STRINGBUFFER_INIT = 45; private static final int METHOD_STRINGBUFFER_INIT_STRING = 46; private static final int METHOD_STRINGBUFFER_APPEND_Z = 47; private static final int METHOD_STRINGBUFFER_APPEND_C = 48; private static final int METHOD_STRINGBUFFER_APPEND_I = 49; private static final int METHOD_STRINGBUFFER_APPEND_J = 50; private static final int METHOD_STRINGBUFFER_APPEND_F = 51; private static final int METHOD_STRINGBUFFER_APPEND_D = 52; private static final int METHOD_STRINGBUFFER_APPEND_STRING = 53; private static final int METHOD_STRINGBUFFER_APPEND_OBJECT = 54; private static final int METHOD_STRINGBUFFER_LENGTH = 55; private static final int METHOD_STRINGBUFFER_TOSTRING = 56; private static final int METHOD_STRINGBUILDER_INIT = 57; private static final int METHOD_STRINGBUILDER_INIT_STRING = 58; private static final int METHOD_STRINGBUILDER_APPEND_Z = 59; private static final int METHOD_STRINGBUILDER_APPEND_C = 60; private static final int METHOD_STRINGBUILDER_APPEND_I = 61; private static final int METHOD_STRINGBUILDER_APPEND_J = 62; private static final int METHOD_STRINGBUILDER_APPEND_F = 63; private static final int METHOD_STRINGBUILDER_APPEND_D = 64; private static final int METHOD_STRINGBUILDER_APPEND_STRING = 65; private static final int METHOD_STRINGBUILDER_APPEND_OBJECT = 66; private static final int METHOD_STRINGBUILDER_LENGTH = 67; private static final int METHOD_STRINGBUILDER_TOSTRING = 68; private static final int CLASS_STRING = 69; private static final int CLASS_STRINGBUFFER = 70; private static final int CLASS_STRINGBUILDER = 71; private static final int NAME_AND_TYPE_I = 72; // Implicitly uses Y. private static final int NAME_AND_TYPE_L = 73; // Implicitly uses Y. private static final int NAME_AND_TYPE_F = 74; // Implicitly uses Y. private static final int NAME_AND_TYPE_D = 75; // Implicitly uses Y. private static final int NAME_AND_TYPE_EQUALS = 76; private static final int NAME_AND_TYPE_LENGTH = 77; private static final int NAME_AND_TYPE_VALUEOF_Z = 78; private static final int NAME_AND_TYPE_VALUEOF_C = 79; private static final int NAME_AND_TYPE_VALUEOF_I = 80; private static final int NAME_AND_TYPE_VALUEOF_J = 81; private static final int NAME_AND_TYPE_VALUEOF_F = 82; private static final int NAME_AND_TYPE_VALUEOF_D = 83; private static final int NAME_AND_TYPE_VALUEOF_OBJECT = 84; private static final int NAME_AND_TYPE_INIT = 85; private static final int NAME_AND_TYPE_INIT_STRING = 86; private static final int NAME_AND_TYPE_APPEND_Z_STRINGBUFFER = 87; private static final int NAME_AND_TYPE_APPEND_C_STRINGBUFFER = 88; private static final int NAME_AND_TYPE_APPEND_I_STRINGBUFFER = 89; private static final int NAME_AND_TYPE_APPEND_J_STRINGBUFFER = 90; private static final int NAME_AND_TYPE_APPEND_F_STRINGBUFFER = 91; private static final int NAME_AND_TYPE_APPEND_D_STRINGBUFFER = 92; private static final int NAME_AND_TYPE_APPEND_STRING_STRINGBUFFER = 93; private static final int NAME_AND_TYPE_APPEND_OBJECT_STRINGBUFFER = 94; private static final int NAME_AND_TYPE_APPEND_Z_STRINGBUILDER = 95; private static final int NAME_AND_TYPE_APPEND_C_STRINGBUILDER = 96; private static final int NAME_AND_TYPE_APPEND_I_STRINGBUILDER = 97; private static final int NAME_AND_TYPE_APPEND_J_STRINGBUILDER = 98; private static final int NAME_AND_TYPE_APPEND_F_STRINGBUILDER = 99; private static final int NAME_AND_TYPE_APPEND_D_STRINGBUILDER = 100; private static final int NAME_AND_TYPE_APPEND_STRING_STRINGBUILDER = 101; private static final int NAME_AND_TYPE_APPEND_OBJECT_STRINGBUILDER = 102; private static final int NAME_AND_TYPE_TOSTRING = 103; private static final int UTF8_EMPTY = 104; private static final int UTF8_I = 105; private static final int UTF8_L = 106; private static final int UTF8_F = 107; private static final int UTF8_D = 108; private static final int UTF8_STRING = 109; private static final int UTF8_STRINGBUFFER = 110; private static final int UTF8_STRINGBUILDER = 111; private static final int UTF8_EQUALS = 112; private static final int UTF8_OBJECT_Z = 113; private static final int UTF8_LENGTH = 114; private static final int UTF8__I = 115; private static final int UTF8_VALUEOF = 116; private static final int UTF8_Z_STRING = 117; private static final int UTF8_C_STRING = 118; private static final int UTF8_I_STRING = 119; private static final int UTF8_J_STRING = 120; private static final int UTF8_F_STRING = 121; private static final int UTF8_D_STRING = 122; private static final int UTF8_OBJECT_STRING = 123; private static final int UTF8_INIT = 124; private static final int UTF8__VOID = 125; private static final int UTF8_STRING_VOID = 126; private static final int UTF8_TOSTRING = 127; private static final int UTF8__STRING = 128; private static final int UTF8_APPEND = 129; private static final int UTF8_Z_STRINGBUFFER = 130; private static final int UTF8_C_STRINGBUFFER = 131; private static final int UTF8_I_STRINGBUFFER = 132; private static final int UTF8_J_STRINGBUFFER = 133; private static final int UTF8_F_STRINGBUFFER = 134; private static final int UTF8_D_STRINGBUFFER = 135; private static final int UTF8_STRING_STRINGBUFFER = 136; private static final int UTF8_OBJECT_STRINGBUFFER = 137; private static final int UTF8_Z_STRINGBUILDER = 138; private static final int UTF8_C_STRINGBUILDER = 139; private static final int UTF8_I_STRINGBUILDER = 140; private static final int UTF8_J_STRINGBUILDER = 141; private static final int UTF8_F_STRINGBUILDER = 142; private static final int UTF8_D_STRINGBUILDER = 143; private static final int UTF8_STRING_STRINGBUILDER = 144; private static final int UTF8_OBJECT_STRINGBUILDER = 145; private static final int SENTINEL = 146; public static final Constant[] CONSTANTS = new Constant[] { new IntegerConstant(32768), new IntegerConstant(65536), new IntegerConstant(16777216), new IntegerConstant(0x0000ff00), new IntegerConstant(0x00ff0000), new IntegerConstant(0xff000000), new IntegerConstant(0x0000ffff), new IntegerConstant(0xffff0000), new LongConstant(-1L), new LongConstant(2L), new LongConstant(4L), new LongConstant(8L), new LongConstant(16L), new LongConstant(32L), new LongConstant(64L), new LongConstant(128L), new LongConstant(256L), new LongConstant(512L), new LongConstant(1024L), new LongConstant(2048L), new LongConstant(4096L), new LongConstant(8192L), new LongConstant(16384L), new LongConstant(32768L), new LongConstant(65536L), new LongConstant(16777216L), new LongConstant(4294967296L), new LongConstant(0x00000000ffffffffL), new LongConstant(0xffffffff00000000L), new FloatConstant(-1f), new DoubleConstant(-1d), new StringConstant(UTF8_EMPTY, null, null), new FieldrefConstant(X, NAME_AND_TYPE_I, null, null), new FieldrefConstant(X, NAME_AND_TYPE_L, null, null), new FieldrefConstant(X, NAME_AND_TYPE_F, null, null), new FieldrefConstant(X, NAME_AND_TYPE_D, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_EQUALS, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_LENGTH, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_Z, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_C, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_I, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_J, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_F, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_D, null, null), new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_OBJECT, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_INIT, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_INIT_STRING, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_Z_STRINGBUFFER, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_C_STRINGBUFFER, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_I_STRINGBUFFER, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_J_STRINGBUFFER, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_F_STRINGBUFFER, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_D_STRINGBUFFER, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_STRING_STRINGBUFFER, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_OBJECT_STRINGBUFFER, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_LENGTH, null, null), new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_TOSTRING, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_INIT, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_INIT_STRING, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_Z_STRINGBUILDER, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_C_STRINGBUILDER, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_I_STRINGBUILDER, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_J_STRINGBUILDER, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_F_STRINGBUILDER, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_D_STRINGBUILDER, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_STRING_STRINGBUILDER, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_OBJECT_STRINGBUILDER, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_LENGTH, null, null), new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_TOSTRING, null, null), new ClassConstant(UTF8_STRING, null), new ClassConstant(UTF8_STRINGBUFFER, null), new ClassConstant(UTF8_STRINGBUILDER, null), new NameAndTypeConstant(Y, UTF8_I), new NameAndTypeConstant(Y, UTF8_L), new NameAndTypeConstant(Y, UTF8_F), new NameAndTypeConstant(Y, UTF8_D), new NameAndTypeConstant(UTF8_EQUALS, UTF8_OBJECT_Z), new NameAndTypeConstant(UTF8_LENGTH, UTF8__I), new NameAndTypeConstant(UTF8_VALUEOF, UTF8_Z_STRING), new NameAndTypeConstant(UTF8_VALUEOF, UTF8_C_STRING), new NameAndTypeConstant(UTF8_VALUEOF, UTF8_I_STRING), new NameAndTypeConstant(UTF8_VALUEOF, UTF8_J_STRING), new NameAndTypeConstant(UTF8_VALUEOF, UTF8_F_STRING), new NameAndTypeConstant(UTF8_VALUEOF, UTF8_D_STRING), new NameAndTypeConstant(UTF8_VALUEOF, UTF8_OBJECT_STRING), new NameAndTypeConstant(UTF8_INIT, UTF8__VOID), new NameAndTypeConstant(UTF8_INIT, UTF8_STRING_VOID), new NameAndTypeConstant(UTF8_APPEND, UTF8_Z_STRINGBUFFER), new NameAndTypeConstant(UTF8_APPEND, UTF8_C_STRINGBUFFER), new NameAndTypeConstant(UTF8_APPEND, UTF8_I_STRINGBUFFER), new NameAndTypeConstant(UTF8_APPEND, UTF8_J_STRINGBUFFER), new NameAndTypeConstant(UTF8_APPEND, UTF8_F_STRINGBUFFER), new NameAndTypeConstant(UTF8_APPEND, UTF8_D_STRINGBUFFER), new NameAndTypeConstant(UTF8_APPEND, UTF8_STRING_STRINGBUFFER), new NameAndTypeConstant(UTF8_APPEND, UTF8_OBJECT_STRINGBUFFER), new NameAndTypeConstant(UTF8_APPEND, UTF8_Z_STRINGBUILDER), new NameAndTypeConstant(UTF8_APPEND, UTF8_C_STRINGBUILDER), new NameAndTypeConstant(UTF8_APPEND, UTF8_I_STRINGBUILDER), new NameAndTypeConstant(UTF8_APPEND, UTF8_J_STRINGBUILDER), new NameAndTypeConstant(UTF8_APPEND, UTF8_F_STRINGBUILDER), new NameAndTypeConstant(UTF8_APPEND, UTF8_D_STRINGBUILDER), new NameAndTypeConstant(UTF8_APPEND, UTF8_STRING_STRINGBUILDER), new NameAndTypeConstant(UTF8_APPEND, UTF8_OBJECT_STRINGBUILDER), new NameAndTypeConstant(UTF8_TOSTRING, UTF8__STRING), new Utf8Constant(""), new Utf8Constant("I"), new Utf8Constant("J"), new Utf8Constant("F"), new Utf8Constant("D"), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING_BUILDER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_EQUALS), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_EQUALS), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_LENGTH), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LENGTH), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_VALUEOF), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_BOOLEAN), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_CHAR), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_INT), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_LONG), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_FLOAT), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_DOUBLE), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_OBJECT), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_INIT), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INIT), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_VOID), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_TOSTRING), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_TOSTRING), new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_APPEND), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CHAR_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INT_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LONG_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_FLOAT_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_OBJECT_STRING_BUFFER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUILDER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CHAR_STRING_BUILDER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INT_STRING_BUILDER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LONG_STRING_BUILDER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_FLOAT_STRING_BUILDER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUILDER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_STRING_BUILDER), new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_OBJECT_STRING_BUILDER), }; public static final Instruction[][][] VARIABLE = new Instruction[][][] { { // nop = nothing { new SimpleInstruction(InstructionConstants.OP_NOP), },{ // Nothing. }, }, { // iload/pop = nothing { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_POP), },{ // Nothing. }, }, { // lload/pop2 = nothing { new VariableInstruction(InstructionConstants.OP_LLOAD, X), new SimpleInstruction(InstructionConstants.OP_POP2), },{ // Nothing. }, }, { // fload/pop = nothing { new VariableInstruction(InstructionConstants.OP_FLOAD, X), new SimpleInstruction(InstructionConstants.OP_POP), },{ // Nothing. }, }, { // dload/pop2 = nothing { new VariableInstruction(InstructionConstants.OP_DLOAD, X), new SimpleInstruction(InstructionConstants.OP_POP2), },{ // Nothing. }, }, { // aload/pop = nothing { new VariableInstruction(InstructionConstants.OP_ALOAD, X), new SimpleInstruction(InstructionConstants.OP_POP), },{ // Nothing. }, }, { // i = i = nothing { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ // Nothing. }, }, { // l = l = nothing { new VariableInstruction(InstructionConstants.OP_LLOAD, X), new VariableInstruction(InstructionConstants.OP_LSTORE, X), },{ // Nothing. }, }, { // f = f = nothing { new VariableInstruction(InstructionConstants.OP_FLOAD, X), new VariableInstruction(InstructionConstants.OP_FSTORE, X), },{ // Nothing. }, }, { // d = d = nothing { new VariableInstruction(InstructionConstants.OP_DLOAD, X), new VariableInstruction(InstructionConstants.OP_DSTORE, X), },{ // Nothing. }, }, { // a = a = nothing { new VariableInstruction(InstructionConstants.OP_ALOAD, X), new VariableInstruction(InstructionConstants.OP_ASTORE, X), },{ // Nothing. }, }, { // istore/istore = pop/istore { new VariableInstruction(InstructionConstants.OP_ISTORE, X), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new SimpleInstruction(InstructionConstants.OP_POP), new VariableInstruction(InstructionConstants.OP_ISTORE, X), }, }, { // lstore/lstore = pop2/lstore { new VariableInstruction(InstructionConstants.OP_LSTORE, X), new VariableInstruction(InstructionConstants.OP_LSTORE, X), },{ new SimpleInstruction(InstructionConstants.OP_POP2), new VariableInstruction(InstructionConstants.OP_LSTORE, X), }, }, { // fstore/fstore = pop/fstore { new VariableInstruction(InstructionConstants.OP_FSTORE, X), new VariableInstruction(InstructionConstants.OP_FSTORE, X), },{ new SimpleInstruction(InstructionConstants.OP_POP), new VariableInstruction(InstructionConstants.OP_FSTORE, X), }, }, { // dstore/dstore = pop2/dstore { new VariableInstruction(InstructionConstants.OP_DSTORE, X), new VariableInstruction(InstructionConstants.OP_DSTORE, X), },{ new SimpleInstruction(InstructionConstants.OP_POP2), new VariableInstruction(InstructionConstants.OP_DSTORE, X), }, }, { // astore/astore = pop/astore { new VariableInstruction(InstructionConstants.OP_ASTORE, X), new VariableInstruction(InstructionConstants.OP_ASTORE, X), },{ new SimpleInstruction(InstructionConstants.OP_POP), new VariableInstruction(InstructionConstants.OP_ASTORE, X), }, }, { // istore/iload = dup/istore { new VariableInstruction(InstructionConstants.OP_ISTORE, X), new VariableInstruction(InstructionConstants.OP_ILOAD, X), },{ new SimpleInstruction(InstructionConstants.OP_DUP), new VariableInstruction(InstructionConstants.OP_ISTORE, X), }, }, { // lstore/lload = dup2/lstore { new VariableInstruction(InstructionConstants.OP_LSTORE, X), new VariableInstruction(InstructionConstants.OP_LLOAD, X), },{ new SimpleInstruction(InstructionConstants.OP_DUP2), new VariableInstruction(InstructionConstants.OP_LSTORE, X), }, }, { // fstore/fload = dup/fstore { new VariableInstruction(InstructionConstants.OP_FSTORE, X), new VariableInstruction(InstructionConstants.OP_FLOAD, X), },{ new SimpleInstruction(InstructionConstants.OP_DUP), new VariableInstruction(InstructionConstants.OP_FSTORE, X), }, }, { // dstore/dload = dup2/dstore { new VariableInstruction(InstructionConstants.OP_DSTORE, X), new VariableInstruction(InstructionConstants.OP_DLOAD, X), },{ new SimpleInstruction(InstructionConstants.OP_DUP2), new VariableInstruction(InstructionConstants.OP_DSTORE, X), }, }, { // astore/aload = dup/astore { new VariableInstruction(InstructionConstants.OP_ASTORE, X), new VariableInstruction(InstructionConstants.OP_ALOAD, X), },{ new SimpleInstruction(InstructionConstants.OP_DUP), new VariableInstruction(InstructionConstants.OP_ASTORE, X), }, }, }; public static final Instruction[][][] ARITHMETIC = new Instruction[][][] { { // c + i = i + c { new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IADD), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new SimpleInstruction(InstructionConstants.OP_IADD), }, }, { // b + i = i + b { new SimpleInstruction(InstructionConstants.OP_BIPUSH, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IADD), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_BIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IADD), }, }, { // s + i = i + s { new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IADD), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IADD), }, }, { // c + i = i + c { new ConstantInstruction(InstructionConstants.OP_LDC, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IADD), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), new ConstantInstruction(InstructionConstants.OP_LDC, A), new SimpleInstruction(InstructionConstants.OP_IADD), }, }, { // c * i = i * c { new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IMUL), }, }, { // b * i = i * b { new SimpleInstruction(InstructionConstants.OP_BIPUSH, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_BIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IMUL), }, }, { // s * i = i * s { new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IMUL), }, }, { // c * i = i * c { new ConstantInstruction(InstructionConstants.OP_LDC, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), new ConstantInstruction(InstructionConstants.OP_LDC, A), new SimpleInstruction(InstructionConstants.OP_IMUL), }, }, { // c + l = l + c { new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), new VariableInstruction(InstructionConstants.OP_LLOAD, X), new SimpleInstruction(InstructionConstants.OP_LADD), },{ new VariableInstruction(InstructionConstants.OP_LLOAD, X), new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), new SimpleInstruction(InstructionConstants.OP_LADD), }, }, { // c + l = l + c { new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new VariableInstruction(InstructionConstants.OP_LLOAD, X), new SimpleInstruction(InstructionConstants.OP_LADD), },{ new VariableInstruction(InstructionConstants.OP_LLOAD, X), new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new SimpleInstruction(InstructionConstants.OP_LADD), }, }, { // c * l = l * c { new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), new VariableInstruction(InstructionConstants.OP_LLOAD, X), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new VariableInstruction(InstructionConstants.OP_LLOAD, X), new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), new SimpleInstruction(InstructionConstants.OP_LMUL), }, }, { // c + f = f + c { new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), new VariableInstruction(InstructionConstants.OP_FLOAD, X), new SimpleInstruction(InstructionConstants.OP_FADD), },{ new VariableInstruction(InstructionConstants.OP_FLOAD, X), new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), new SimpleInstruction(InstructionConstants.OP_FADD), }, }, { // c + f = f + c { new ConstantInstruction(InstructionConstants.OP_LDC, A), new VariableInstruction(InstructionConstants.OP_FLOAD, X), new SimpleInstruction(InstructionConstants.OP_FADD), },{ new VariableInstruction(InstructionConstants.OP_FLOAD, X), new ConstantInstruction(InstructionConstants.OP_LDC, A), new SimpleInstruction(InstructionConstants.OP_FADD), }, }, { // c * f = f * c { new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), new VariableInstruction(InstructionConstants.OP_FLOAD, X), new SimpleInstruction(InstructionConstants.OP_FMUL), },{ new VariableInstruction(InstructionConstants.OP_FLOAD, X), new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), new SimpleInstruction(InstructionConstants.OP_FMUL), }, }, { // c * f = f * c { new ConstantInstruction(InstructionConstants.OP_LDC, A), new VariableInstruction(InstructionConstants.OP_FLOAD, X), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new VariableInstruction(InstructionConstants.OP_FLOAD, X), new ConstantInstruction(InstructionConstants.OP_LDC, A), new SimpleInstruction(InstructionConstants.OP_LMUL), }, }, { // c + d = d + c { new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), new VariableInstruction(InstructionConstants.OP_DLOAD, X), new SimpleInstruction(InstructionConstants.OP_DADD), },{ new VariableInstruction(InstructionConstants.OP_DLOAD, X), new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), new SimpleInstruction(InstructionConstants.OP_DADD), }, }, { // c + d = d + c { new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new VariableInstruction(InstructionConstants.OP_DLOAD, X), new SimpleInstruction(InstructionConstants.OP_DADD), },{ new VariableInstruction(InstructionConstants.OP_DLOAD, X), new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new SimpleInstruction(InstructionConstants.OP_DADD), }, }, { // c * d = d * c { new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), new VariableInstruction(InstructionConstants.OP_DLOAD, X), new SimpleInstruction(InstructionConstants.OP_DMUL), },{ new VariableInstruction(InstructionConstants.OP_DLOAD, X), new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), new SimpleInstruction(InstructionConstants.OP_DMUL), }, }, { // c * d = d * c { new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new VariableInstruction(InstructionConstants.OP_DLOAD, X), new SimpleInstruction(InstructionConstants.OP_DMUL), },{ new VariableInstruction(InstructionConstants.OP_DLOAD, X), new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new SimpleInstruction(InstructionConstants.OP_DMUL), }, }, { // i = i + c = i += c { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IADD), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, A), }, }, { // i = i + b = i += b { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_BIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IADD), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, A), }, }, { // i = i + s = i += s { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IADD), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, A), }, }, { // i = i - -1 = i++ { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new SimpleInstruction(InstructionConstants.OP_ISUB), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, 1), }, }, { // i = i - 1 = i-- { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_ICONST_1), new SimpleInstruction(InstructionConstants.OP_ISUB), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, -1), }, }, { // i = i - 2 = i -= 2 { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_ICONST_2), new SimpleInstruction(InstructionConstants.OP_ISUB), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, -2), }, }, { // i = i - 3 = i -= 3 { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_ICONST_3), new SimpleInstruction(InstructionConstants.OP_ISUB), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, -3), }, }, { // i = i - 4 = i -= 4 { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_ICONST_4), new SimpleInstruction(InstructionConstants.OP_ISUB), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, -4), }, }, { // i = i - 5 = i -= 5 { new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_ICONST_5), new SimpleInstruction(InstructionConstants.OP_ISUB), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ new VariableInstruction(InstructionConstants.OP_IINC, X, -5), }, }, { // ... + 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_IADD), },{ // Nothing. }, }, { // ... + 0L = ... { new SimpleInstruction(InstructionConstants.OP_LCONST_0), new SimpleInstruction(InstructionConstants.OP_LADD), },{ // Nothing. }, }, // Not valid for -0.0. // { // ... + 0f = ... // { // new SimpleInstruction(InstructionConstants.OP_FCONST_0), // new SimpleInstruction(InstructionConstants.OP_FADD), // },{ // // Nothing. // }, // }, // { // ... + 0d = ... // { // new SimpleInstruction(InstructionConstants.OP_DCONST_0), // new SimpleInstruction(InstructionConstants.OP_DADD), // },{ // // Nothing. // }, // }, { // ... - 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_ISUB), },{ // Nothing. }, }, { // ... - 0L = ... { new SimpleInstruction(InstructionConstants.OP_LCONST_0), new SimpleInstruction(InstructionConstants.OP_LSUB), },{ // Nothing. }, }, { // ... - 0f = ... { new SimpleInstruction(InstructionConstants.OP_FCONST_0), new SimpleInstruction(InstructionConstants.OP_FSUB), },{ // Nothing. }, }, { // ... - 0d = ... { new SimpleInstruction(InstructionConstants.OP_DCONST_0), new SimpleInstruction(InstructionConstants.OP_DSUB), },{ // Nothing. }, }, { // ... * -1 = -... { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_INEG), }, }, { // ... * 0 = 0 { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_POP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), }, }, { // ... * 1 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ // Nothing. }, }, { // ... * 2 = ... << 1 { new SimpleInstruction(InstructionConstants.OP_ICONST_2), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_ICONST_1), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 4 = ... << 2 { new SimpleInstruction(InstructionConstants.OP_ICONST_4), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_ICONST_2), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 8 = ... << 3 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_ICONST_3), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 16 = ... << 4 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 4), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 32 = ... << 5 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 5), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 64 = ... << 6 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 64), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 6), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 128 = ... << 7 { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 128), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 7), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 256 = ... << 8 { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 256), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 512 = ... << 9 { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 512), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 9), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 1024 = ... << 10 { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 1024), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 10), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 2048 = ... << 11 { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 2048), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 11), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 4096 = ... << 12 { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 4096), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 12), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 8192 = ... << 13 { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 8192), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 13), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 16384 = ... << 14 { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 16384), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 14), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 32768 = ... << 15 { new ConstantInstruction(InstructionConstants.OP_LDC, I_32768), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 15), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 65536 = ... << 16 { new ConstantInstruction(InstructionConstants.OP_LDC, I_65536), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * 16777216 = ... << 24 { new ConstantInstruction(InstructionConstants.OP_LDC, I_16777216), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHL), }, }, { // ... * -1L = -... { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_M1), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_LNEG), }, }, { // ... * 0L = 0L { new SimpleInstruction(InstructionConstants.OP_LCONST_0), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_POP2), new SimpleInstruction(InstructionConstants.OP_LCONST_0), }, }, { // ... * 1L = ... { new SimpleInstruction(InstructionConstants.OP_LCONST_1), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ // Nothing. }, }, { // ... * 2L = ... << 1 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_2), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_ICONST_1), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 4L = ... << 2 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_4), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_ICONST_2), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 8L = ... << 3 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_8), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_ICONST_3), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 16L = ... << 4 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_16), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 4), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 32L = ... << 5 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_32), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 5), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 64L = ... << 6 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_64), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 6), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 128L = ... << 7 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_128), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 7), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 256L = ... << 8 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_256), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 512L = ... << 9 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_512), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 9), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 1024L = ... << 10 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_1024), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 10), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 2048L = ... << 11 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_2048), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 11), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 4096L = ... << 12 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_4096), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 12), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 8192L = ... << 13 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_8192), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 13), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 16384L = ... << 14 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_16384), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 14), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 32768L = ... << 15 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_32768), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 15), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 65536LL = ... << 16 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_65536), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 16777216L = ... << 24 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_16777216), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * 4294967296L = ... << 32 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_4294967296), new SimpleInstruction(InstructionConstants.OP_LMUL), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), new SimpleInstruction(InstructionConstants.OP_LSHL), }, }, { // ... * -1f = -... { new ConstantInstruction(InstructionConstants.OP_LDC, F_M1), new SimpleInstruction(InstructionConstants.OP_FMUL), },{ new SimpleInstruction(InstructionConstants.OP_FNEG), }, }, // Not valid for -0.0 and for NaN. // { // ... * 0f = 0f // { // new SimpleInstruction(InstructionConstants.OP_FCONST_0), // new SimpleInstruction(InstructionConstants.OP_FMUL), // },{ // new SimpleInstruction(InstructionConstants.OP_POP), // new SimpleInstruction(InstructionConstants.OP_FCONST_0), // }, // }, { // ... * 1f = ... { new SimpleInstruction(InstructionConstants.OP_FCONST_1), new SimpleInstruction(InstructionConstants.OP_FMUL), },{ // Nothing. }, }, { // ... * -1d = -... { new ConstantInstruction(InstructionConstants.OP_LDC2_W, D_M1), new SimpleInstruction(InstructionConstants.OP_DMUL), },{ new SimpleInstruction(InstructionConstants.OP_DNEG), }, }, // Not valid for -0.0 and for NaN. // { // ... * 0d = 0d // { // new SimpleInstruction(InstructionConstants.OP_DCONST_0), // new SimpleInstruction(InstructionConstants.OP_DMUL), // },{ // new SimpleInstruction(InstructionConstants.OP_POP2), // new SimpleInstruction(InstructionConstants.OP_DCONST_0), // }, // }, { // ... * 1d = ... { new SimpleInstruction(InstructionConstants.OP_DCONST_1), new SimpleInstruction(InstructionConstants.OP_DMUL), },{ // Nothing. }, }, { // ... / -1 = -... { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new SimpleInstruction(InstructionConstants.OP_IDIV), },{ new SimpleInstruction(InstructionConstants.OP_INEG), }, }, { // ... / 1 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new SimpleInstruction(InstructionConstants.OP_IDIV), },{ // Nothing. }, }, // Not valid for negative values. // { // ... / 2 = ... >> 1 // { // new SimpleInstruction(InstructionConstants.OP_ICONST_2), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_ICONST_1), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 4 = ... >> 2 // { // new SimpleInstruction(InstructionConstants.OP_ICONST_4), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_ICONST_2), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 8 = ... >> 3 // { // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_ICONST_3), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 16 = ... >> 4 // { // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 4), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 32 = ... >> 5 // { // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 5), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 64 = ... >> 6 // { // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 64), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 6), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 128 = ... >> 7 // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 128), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 7), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 256 = ... >> 8 // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 256), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 512 = ... >> 9 // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 512), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 9), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 1024 = ... >> 10 // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 1024), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 10), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 2048 = ... >> 11 // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 2048), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 11), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 4096 = ... >> 12 // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 4096), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 12), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 8192 = ... >> 13 // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 8192), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 13), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 16384 = ... >> 14 // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 16384), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 14), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 32768 = ... >> 15 // { // new ConstantInstruction(InstructionConstants.OP_LDC, I_32768), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 15), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 65536 = ... >> 16 // { // new ConstantInstruction(InstructionConstants.OP_LDC, I_65536), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, // { // ... / 16777216 = ... >> 24 // { // new ConstantInstruction(InstructionConstants.OP_LDC, I_16777216), // new SimpleInstruction(InstructionConstants.OP_IDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), // new SimpleInstruction(InstructionConstants.OP_ISHR), // }, // }, { // ... / -1L = -... { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_M1), new SimpleInstruction(InstructionConstants.OP_LDIV), },{ new SimpleInstruction(InstructionConstants.OP_LNEG), }, }, { // ... / 1L = ... { new SimpleInstruction(InstructionConstants.OP_LCONST_1), new SimpleInstruction(InstructionConstants.OP_LDIV), },{ // Nothing. }, }, // Not valid for negative values. // { // ... / 2L = ... >> 1 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_2), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_ICONST_1), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 4L = ... >> 2 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_4), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_ICONST_2), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 8L = ... >> 3 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_8), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_ICONST_3), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 16L = ... >> 4 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_16), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 4), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 32L = ... >> 5 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_32), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 5), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 64L = ... >> 6 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_64), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 6), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 128L = ... >> 7 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_128), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 7), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 256L = ... >> 8 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_256), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 512L = ... >> 9 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_512), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 9), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 1024L = ... >> 10 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_1024), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 10), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 2048L = ... >> 11 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_2048), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 11), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 4096L = ... >> 12 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_4096), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 12), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 8192L = ... >> 13 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_8192), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 13), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 16384L = ... >> 14 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_16384), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 14), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 32768L = ... >> 15 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_32768), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 15), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 65536LL = ... >> 16 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_65536), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 16777216L = ... >> 24 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_16777216), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, // { // ... / 4294967296L = ... >> 32 // { // new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_4294967296), // new SimpleInstruction(InstructionConstants.OP_LDIV), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), // new SimpleInstruction(InstructionConstants.OP_LSHR), // }, // }, { // ... / -1f = -... { new ConstantInstruction(InstructionConstants.OP_LDC, F_M1), new SimpleInstruction(InstructionConstants.OP_FDIV), },{ new SimpleInstruction(InstructionConstants.OP_FNEG), }, }, { // ... / 1f = ... { new SimpleInstruction(InstructionConstants.OP_FCONST_1), new SimpleInstruction(InstructionConstants.OP_FDIV), },{ // Nothing. }, }, { // ... / -1d = -... { new ConstantInstruction(InstructionConstants.OP_LDC2_W, D_M1), new SimpleInstruction(InstructionConstants.OP_DDIV), },{ new SimpleInstruction(InstructionConstants.OP_DNEG), }, }, { // ... / 1d = ... { new SimpleInstruction(InstructionConstants.OP_DCONST_1), new SimpleInstruction(InstructionConstants.OP_DDIV), },{ // Nothing. }, }, { // ... % 1 = 0 { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new SimpleInstruction(InstructionConstants.OP_IREM), },{ new SimpleInstruction(InstructionConstants.OP_POP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), }, }, // Not valid for negative values. // { // ... % 2 = ... & 0x1 // { // new SimpleInstruction(InstructionConstants.OP_ICONST_2), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_ICONST_1), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 4 = ... & 0x3 // { // new SimpleInstruction(InstructionConstants.OP_ICONST_4), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_ICONST_3), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 8 = ... & 0x07 // { // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 0x07), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 16 = ... & 0x0f // { // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 0x0f), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 32 = ... & 0x1f // { // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 0x1f), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 64 = ... & 0x3f // { // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 64), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 0x3f), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 128 = ... & 0x7f // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 128), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_BIPUSH, 0x7f), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 256 = ... & 0x00ff // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 256), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0x00ff), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 512 = ... & 0x01ff // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 512), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0x01ff), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 1024 = ... & 0x03ff // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 1024), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0x03ff), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 2048 = ... & 0x07ff // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 2048), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0x07ff), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 4096 = ... & 0x0fff // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 4096), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0x0fff), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 8192 = ... & 0x1fff // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 8192), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0x1fff), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, // { // ... % 16384 = ... & 0x3fff // { // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 16384), // new SimpleInstruction(InstructionConstants.OP_IREM), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0x3fff), // new SimpleInstruction(InstructionConstants.OP_IAND), // }, // }, { // ... % 1L = 0L { new SimpleInstruction(InstructionConstants.OP_LCONST_1), new SimpleInstruction(InstructionConstants.OP_LREM), },{ new SimpleInstruction(InstructionConstants.OP_POP2), new SimpleInstruction(InstructionConstants.OP_LCONST_0), }, }, // { // ... % 1f = 0f // { // new SimpleInstruction(InstructionConstants.OP_FCONST_1), // new SimpleInstruction(InstructionConstants.OP_FREM), // },{ // new SimpleInstruction(InstructionConstants.OP_POP), // new SimpleInstruction(InstructionConstants.OP_FCONST_0), // }, // }, // { // ... % 1d = 0d // { // new SimpleInstruction(InstructionConstants.OP_DCONST_1), // new SimpleInstruction(InstructionConstants.OP_DREM), // },{ // new SimpleInstruction(InstructionConstants.OP_POP2), // new SimpleInstruction(InstructionConstants.OP_DCONST_0), // }, // }, { // -(-...) = ... { new SimpleInstruction(InstructionConstants.OP_INEG), new SimpleInstruction(InstructionConstants.OP_INEG), },{ // Nothing. }, }, { // -(-...) = ... { new SimpleInstruction(InstructionConstants.OP_LNEG), new SimpleInstruction(InstructionConstants.OP_LNEG), },{ // Nothing. }, }, { // -(-...) = ... { new SimpleInstruction(InstructionConstants.OP_FNEG), new SimpleInstruction(InstructionConstants.OP_FNEG), },{ // Nothing. }, }, { // -(-...) = ... { new SimpleInstruction(InstructionConstants.OP_DNEG), new SimpleInstruction(InstructionConstants.OP_DNEG), },{ // Nothing. }, }, { // +(-...) = -... { new SimpleInstruction(InstructionConstants.OP_INEG), new SimpleInstruction(InstructionConstants.OP_IADD), },{ new SimpleInstruction(InstructionConstants.OP_ISUB), }, }, { // +(-...) = -... { new SimpleInstruction(InstructionConstants.OP_LNEG), new SimpleInstruction(InstructionConstants.OP_LADD), },{ new SimpleInstruction(InstructionConstants.OP_LSUB), }, }, { // +(-...) = -... { new SimpleInstruction(InstructionConstants.OP_FNEG), new SimpleInstruction(InstructionConstants.OP_FADD), },{ new SimpleInstruction(InstructionConstants.OP_FSUB), }, }, { // +(-...) = -... { new SimpleInstruction(InstructionConstants.OP_DNEG), new SimpleInstruction(InstructionConstants.OP_DADD), },{ new SimpleInstruction(InstructionConstants.OP_DSUB), }, }, { // ... << 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_ISHL), },{ // Nothing. }, }, { // ... << 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_LSHL), },{ // Nothing. }, }, { // ... >> 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_ISHR), },{ // Nothing. }, }, { // ... >> 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_LSHR), },{ // Nothing. }, }, { // ... >>> 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_IUSHR), },{ // Nothing. }, }, { // ... >>> 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_LUSHR), },{ // Nothing. }, }, { // ... & -1 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new SimpleInstruction(InstructionConstants.OP_IAND), },{ // Nothing. }, }, { // ... & 0 = 0 { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_IAND), },{ new SimpleInstruction(InstructionConstants.OP_POP), new SimpleInstruction(InstructionConstants.OP_ICONST_0), }, }, { // ... & -1L = ... { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_M1), new SimpleInstruction(InstructionConstants.OP_LAND), },{ // Nothing. }, }, { // ... & 0L = 0L { new SimpleInstruction(InstructionConstants.OP_LCONST_0), new SimpleInstruction(InstructionConstants.OP_LAND), },{ new SimpleInstruction(InstructionConstants.OP_POP2), new SimpleInstruction(InstructionConstants.OP_LCONST_0), }, }, { // ... | -1 = -1 { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new SimpleInstruction(InstructionConstants.OP_IOR), },{ new SimpleInstruction(InstructionConstants.OP_POP), new SimpleInstruction(InstructionConstants.OP_ICONST_M1), }, }, { // ... | 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_IOR), },{ // Nothing. }, }, { // ... | -1L = -1L { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_M1), new SimpleInstruction(InstructionConstants.OP_LAND), },{ new SimpleInstruction(InstructionConstants.OP_POP2), new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_M1), }, }, { // ... | 0L = ... { new SimpleInstruction(InstructionConstants.OP_LCONST_0), new SimpleInstruction(InstructionConstants.OP_LOR), },{ // Nothing. }, }, { // ... ^ 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new SimpleInstruction(InstructionConstants.OP_IXOR), },{ // Nothing. }, }, { // ... ^ 0L = ... { new SimpleInstruction(InstructionConstants.OP_LCONST_0), new SimpleInstruction(InstructionConstants.OP_LXOR), },{ // Nothing. }, }, { // (... & 0x0000ff00) >> 8 = (... >> 8) & 0xff { new ConstantInstruction(InstructionConstants.OP_LDC, I_0x0000ff00), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), new SimpleInstruction(InstructionConstants.OP_ISHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), new SimpleInstruction(InstructionConstants.OP_ISHR), new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0xff), new SimpleInstruction(InstructionConstants.OP_IAND), }, }, { // (... & 0x0000ff00) >>> 8 = (... >>> 8) & 0xff { new ConstantInstruction(InstructionConstants.OP_LDC, I_0x0000ff00), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), new SimpleInstruction(InstructionConstants.OP_IUSHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 8), new SimpleInstruction(InstructionConstants.OP_IUSHR), new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0xff), new SimpleInstruction(InstructionConstants.OP_IAND), }, }, { // (... & 0x00ff0000) >> 16 = (... >> 16) & 0xff { new ConstantInstruction(InstructionConstants.OP_LDC, I_0x00ff0000), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0xff), new SimpleInstruction(InstructionConstants.OP_IAND), }, }, { // (... & 0x00ff0000) >>> 16 = (... >>> 16) & 0xff { new ConstantInstruction(InstructionConstants.OP_LDC, I_0x00ff0000), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0xff), new SimpleInstruction(InstructionConstants.OP_IAND), }, }, { // (... & 0xff000000) >> 24 = ... >> 24 { new ConstantInstruction(InstructionConstants.OP_LDC, I_0xff000000), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHR), }, }, { // (... & 0xffff0000) >> 16 = ... >> 16 { new ConstantInstruction(InstructionConstants.OP_LDC, I_0xffff0000), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), }, }, { // (... & 0xffff0000) >>> 16 = ... >>> 16 { new ConstantInstruction(InstructionConstants.OP_LDC, I_0xffff0000), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), }, }, { // (... >> 24) & 0xff = ... >>> 24 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHR), new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0xff), new SimpleInstruction(InstructionConstants.OP_IAND), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_IUSHR), }, }, { // (... >>> 24) & 0xff = ... >>> 24 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_IUSHR), new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0xff), new SimpleInstruction(InstructionConstants.OP_IAND), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_IUSHR), }, }, { // (byte)(... & 0x000000ff) = (byte)... { new SimpleInstruction(InstructionConstants.OP_SIPUSH, 0xff), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_I2B), },{ new SimpleInstruction(InstructionConstants.OP_I2B), }, }, { // (char)(... & 0x0000ffff) = (char)... { new ConstantInstruction(InstructionConstants.OP_LDC, I_0x0000ffff), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_I2C), },{ new SimpleInstruction(InstructionConstants.OP_I2C), }, }, { // (short)(... & 0x0000ffff) = (short)... { new ConstantInstruction(InstructionConstants.OP_LDC, I_0x0000ffff), new SimpleInstruction(InstructionConstants.OP_IAND), new SimpleInstruction(InstructionConstants.OP_I2S), },{ new SimpleInstruction(InstructionConstants.OP_I2S), }, }, { // (byte)(... >> 24) = ... >> 24 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHR), new SimpleInstruction(InstructionConstants.OP_I2B), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHR), }, }, { // (byte)(... >>> 24) = ... >> 24 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_IUSHR), new SimpleInstruction(InstructionConstants.OP_I2B), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHR), }, }, { // (char)(... >> 16) = ... >>> 16 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), new SimpleInstruction(InstructionConstants.OP_I2C), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), }, }, { // (char)(... >>> 16) = ... >>> 16 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), new SimpleInstruction(InstructionConstants.OP_I2C), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), }, }, { // (short)(... >> 16) = ... >> 16 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), new SimpleInstruction(InstructionConstants.OP_I2S), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), }, }, { // (short)(... >>> 16) = ... >> 16 { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), new SimpleInstruction(InstructionConstants.OP_I2S), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), }, }, { // ... << 24 >> 24 = (byte)... { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHL), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 24), new SimpleInstruction(InstructionConstants.OP_ISHR), },{ new SimpleInstruction(InstructionConstants.OP_I2B), }, }, { // ... << 16 >>> 16 = (char)... { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHL), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_IUSHR), },{ new SimpleInstruction(InstructionConstants.OP_I2C), }, }, { // ... << 16 >> 16 = (short)... { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHL), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 16), new SimpleInstruction(InstructionConstants.OP_ISHR), },{ new SimpleInstruction(InstructionConstants.OP_I2S), }, }, { // ... << 32 >> 32 = (long)(int)... { new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), new SimpleInstruction(InstructionConstants.OP_LSHL), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), new SimpleInstruction(InstructionConstants.OP_LSHR), },{ new SimpleInstruction(InstructionConstants.OP_L2I), new SimpleInstruction(InstructionConstants.OP_I2L), }, }, { // (int)(... & 0x00000000ffffffffL) = (int)... { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_0x00000000ffffffff), new SimpleInstruction(InstructionConstants.OP_LAND), new SimpleInstruction(InstructionConstants.OP_L2I), },{ new SimpleInstruction(InstructionConstants.OP_L2I), }, }, { // (... & 0xffffffff00000000L) >> 32 = ... >> 32 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_0xffffffff00000000), new SimpleInstruction(InstructionConstants.OP_LAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), new SimpleInstruction(InstructionConstants.OP_LSHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), new SimpleInstruction(InstructionConstants.OP_LSHR), }, }, { // (... & 0xffffffff00000000L) >>> 32 = ... >>> 32 { new ConstantInstruction(InstructionConstants.OP_LDC2_W, L_0xffffffff00000000), new SimpleInstruction(InstructionConstants.OP_LAND), new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), new SimpleInstruction(InstructionConstants.OP_LUSHR), },{ new SimpleInstruction(InstructionConstants.OP_BIPUSH, 32), new SimpleInstruction(InstructionConstants.OP_LUSHR), }, }, { // ... += 0 = nothing { new VariableInstruction(InstructionConstants.OP_IINC, X, 0), },{ // Nothing. }, }, }; public static final Instruction[][][] FIELD = new Instruction[][][] { { // getfield/putfield = nothing { new VariableInstruction(InstructionConstants.OP_ALOAD, X), new VariableInstruction(InstructionConstants.OP_ALOAD, X), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Y), new ConstantInstruction(InstructionConstants.OP_PUTFIELD, Y), },{ // Nothing. }, }, // { // putfield_L/putfield_L = pop2_x1/putfield // { // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_L), // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_L), // },{ // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new SimpleInstruction(InstructionConstants.OP_POP2), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_L), // }, // }, // { // putfield_D/putfield_D = pop2_x1/putfield // { // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_D), // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_D), // },{ // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new SimpleInstruction(InstructionConstants.OP_POP2), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_D), // }, // }, // { // putfield/putfield = pop_x1/putfield // { // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, Y), // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, Y), // },{ // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new SimpleInstruction(InstructionConstants.OP_POP), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, Y), // }, // }, // { // putfield_L/getfield_L = dup2_x1/putfield // { // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_L), // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // new ConstantInstruction(InstructionConstants.OP_GETFIELD, FIELD_L), // },{ // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new SimpleInstruction(InstructionConstants.OP_DUP2_X1), // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_L), // }, // }, // { // putfield_D/getfield_D = dup2_x1/putfield // { // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_D), // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // new ConstantInstruction(InstructionConstants.OP_GETFIELD, FIELD_D), // },{ // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new SimpleInstruction(InstructionConstants.OP_DUP2_X1), // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, FIELD_D), // }, // }, // { // putfield/getfield = dup_x1/putfield // { // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, Y), // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // new ConstantInstruction(InstructionConstants.OP_GETFIELD, Y), // },{ // new VariableInstruction(InstructionConstants.OP_ALOAD, X), // // ... // new SimpleInstruction(InstructionConstants.OP_DUP_X1), // new ConstantInstruction(InstructionConstants.OP_PUTFIELD, Y), // }, // }, { // getstatic/putstatic = nothing { new ConstantInstruction(InstructionConstants.OP_GETSTATIC, X), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, X), },{ // Nothing. }, }, { // putstatic_L/putstatic_L = pop2/putstatic { new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_L), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_L), },{ new SimpleInstruction(InstructionConstants.OP_POP2), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_L), }, }, { // putstatic_D/putstatic_D = pop2/putstatic { new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_D), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_D), },{ new SimpleInstruction(InstructionConstants.OP_POP2), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_D), }, }, { // putstatic/putstatic = pop/putstatic { new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, X), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, X), },{ new SimpleInstruction(InstructionConstants.OP_POP), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, X), }, }, { // putstatic_L/getstatic_L = dup2/putstatic { new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_L), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, FIELD_L), },{ new SimpleInstruction(InstructionConstants.OP_DUP2), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_L), }, }, { // putstatic_D/getstatic_D = dup2/putstatic { new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_D), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, FIELD_D), },{ new SimpleInstruction(InstructionConstants.OP_DUP2), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, FIELD_D), }, }, { // putstatic/getstatic = dup/putstatic { new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, X), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, X), },{ new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, X), }, }, }; public static final Instruction[][][] CAST = new Instruction[][][] { { // (byte)(byte)... = (byte)... { new SimpleInstruction(InstructionConstants.OP_I2B), new SimpleInstruction(InstructionConstants.OP_I2B), },{ new SimpleInstruction(InstructionConstants.OP_I2B), }, }, { // (byte)(char)... = (byte)... { new SimpleInstruction(InstructionConstants.OP_I2C), new SimpleInstruction(InstructionConstants.OP_I2B), },{ new SimpleInstruction(InstructionConstants.OP_I2B), }, }, { // (byte)(short)... = (byte)... { new SimpleInstruction(InstructionConstants.OP_I2S), new SimpleInstruction(InstructionConstants.OP_I2B), },{ new SimpleInstruction(InstructionConstants.OP_I2B), }, }, { // (char)(char)... = (char)... { new SimpleInstruction(InstructionConstants.OP_I2C), new SimpleInstruction(InstructionConstants.OP_I2C), },{ new SimpleInstruction(InstructionConstants.OP_I2C), }, }, { // (char)(short)... = (char)... { new SimpleInstruction(InstructionConstants.OP_I2S), new SimpleInstruction(InstructionConstants.OP_I2C), },{ new SimpleInstruction(InstructionConstants.OP_I2C), }, }, { // (short)(byte)... = (byte)... { new SimpleInstruction(InstructionConstants.OP_I2B), new SimpleInstruction(InstructionConstants.OP_I2S), },{ new SimpleInstruction(InstructionConstants.OP_I2B), }, }, { // (short)(char)... = (short)... { new SimpleInstruction(InstructionConstants.OP_I2C), new SimpleInstruction(InstructionConstants.OP_I2S), },{ new SimpleInstruction(InstructionConstants.OP_I2S), }, }, { // (short)(short)... = (short)... { new SimpleInstruction(InstructionConstants.OP_I2S), new SimpleInstruction(InstructionConstants.OP_I2S), },{ new SimpleInstruction(InstructionConstants.OP_I2S), }, }, { // (int)(long)... = ... { new SimpleInstruction(InstructionConstants.OP_I2L), new SimpleInstruction(InstructionConstants.OP_L2I), },{ // Nothing. }, }, { // (X)(X)... = (X)... { new ConstantInstruction(InstructionConstants.OP_CHECKCAST, X), new ConstantInstruction(InstructionConstants.OP_CHECKCAST, X), },{ new ConstantInstruction(InstructionConstants.OP_CHECKCAST, X), }, }, // Not handled correctly in all cases by VMs prior to Java 6... // { // (byte)bytes[...] = bytes[...] // { // new SimpleInstruction(InstructionConstants.OP_BALOAD), // new SimpleInstruction(InstructionConstants.OP_I2B), // },{ // new SimpleInstruction(InstructionConstants.OP_BALOAD), // }, // }, // { // (short)bytes[...] = bytes[...] // { // new SimpleInstruction(InstructionConstants.OP_BALOAD), // new SimpleInstruction(InstructionConstants.OP_I2S), // },{ // new SimpleInstruction(InstructionConstants.OP_BALOAD), // }, // }, // { // (char)chars[...] = chars[...] // { // new SimpleInstruction(InstructionConstants.OP_CALOAD), // new SimpleInstruction(InstructionConstants.OP_I2C), // },{ // new SimpleInstruction(InstructionConstants.OP_CALOAD), // }, // }, // { // (short)shorts[...] = shorts[...] // { // new SimpleInstruction(InstructionConstants.OP_SALOAD), // new SimpleInstruction(InstructionConstants.OP_I2S), // },{ // new SimpleInstruction(InstructionConstants.OP_SALOAD), // }, // }, // { // bytes[...] = (byte)... = bytes[...] = ... // { // new SimpleInstruction(InstructionConstants.OP_I2B), // new SimpleInstruction(InstructionConstants.OP_BASTORE), // },{ // new SimpleInstruction(InstructionConstants.OP_BASTORE), // }, // }, // { // chars[...] = (char)... = chars[...] = ... // { // new SimpleInstruction(InstructionConstants.OP_I2C), // new SimpleInstruction(InstructionConstants.OP_CASTORE), // },{ // new SimpleInstruction(InstructionConstants.OP_CASTORE), // }, // }, // { // shorts[...] = (short)... = shorts[...] = ... // { // new SimpleInstruction(InstructionConstants.OP_I2S), // new SimpleInstruction(InstructionConstants.OP_SASTORE), // },{ // new SimpleInstruction(InstructionConstants.OP_SASTORE), // }, // }, }; public static final Instruction[][][] BRANCH = new Instruction[][][] { { // goto +3 = nothing { new BranchInstruction(InstructionConstants.OP_GOTO, 3), },{ // Nothing. }, }, { // ifeq +3 = pop { new BranchInstruction(InstructionConstants.OP_IFEQ, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP), }, }, { // ifne +3 = pop { new BranchInstruction(InstructionConstants.OP_IFNE, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP), }, }, { // iflt +3 = pop { new BranchInstruction(InstructionConstants.OP_IFLT, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP), }, }, { // ifge +3 = pop { new BranchInstruction(InstructionConstants.OP_IFGE, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP), }, }, { // ifgt +3 = pop { new BranchInstruction(InstructionConstants.OP_IFGT, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP), }, }, { // ifle +3 = pop { new BranchInstruction(InstructionConstants.OP_IFLE, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP), }, }, { // ificmpeq +3 = pop2 { new BranchInstruction(InstructionConstants.OP_IFICMPEQ, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP2), }, }, { // ificmpne +3 = pop2 { new BranchInstruction(InstructionConstants.OP_IFICMPNE, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP2), }, }, { // ificmplt +3 = pop2 { new BranchInstruction(InstructionConstants.OP_IFICMPLT, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP2), }, }, { // ificmpge +3 = pop2 { new BranchInstruction(InstructionConstants.OP_IFICMPGE, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP2), }, }, { // ificmpgt +3 = pop2 { new BranchInstruction(InstructionConstants.OP_IFICMPGT, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP2), }, }, { // ificmple +3 = pop2 { new BranchInstruction(InstructionConstants.OP_IFICMPLE, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP2), }, }, { // ifacmpeq +3 = pop2 { new BranchInstruction(InstructionConstants.OP_IFACMPEQ, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP2), }, }, { // ifacmpne +3 = pop2 { new BranchInstruction(InstructionConstants.OP_IFACMPNE, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP2), }, }, { // ifnull +3 = pop { new BranchInstruction(InstructionConstants.OP_IFNULL, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP), }, }, { // ifnonnull +3 = pop { new BranchInstruction(InstructionConstants.OP_IFNONNULL, 3), },{ new SimpleInstruction(InstructionConstants.OP_POP), }, }, { // if (... == 0) = ifeq { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFICMPEQ, X), },{ new BranchInstruction(InstructionConstants.OP_IFEQ, X), }, }, { // if (0 == i) = iload/ifeq { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPEQ, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFEQ, X), }, }, { // if (0 == i) = getstatic/ifeq { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPEQ, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFEQ, X), }, }, { // if (0 == i) = getfield/ifeq { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPEQ, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFEQ, X), }, }, { // if (... != 0) = ifne { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFICMPNE, X), },{ new BranchInstruction(InstructionConstants.OP_IFNE, X), }, }, { // if (0 != i) = iload/ifeq { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPNE, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFNE, X), }, }, { // if (0 != i) = getstatic/ifeq { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPNE, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFNE, X), }, }, { // if (0 != i) = getfield/ifeq { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPNE, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFNE, X), }, }, { // if (... < 0) = iflt { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), },{ new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // if (... < 1) = ifle { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), },{ new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // if (0 > i) = iload/iflt { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // if (1 > i) = iload/ifle { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // if (0 > i) = getstatic/iflt { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // if (1 > i) = getstatic/ifle { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // if (0 > i) = getfield/iflt { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // if (1 > i) = getfield/ifle { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // if (... >= 0) = ifge { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), },{ new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // if (... >= 1) = ifgt { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), },{ new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // if (0 <= i) = iload/ifge { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // if (1 <= i) = iload/ifgt { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // if (0 <= i) = getstatic/ifge { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // if (1 <= i) = getstatic/ifgt { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // if (0 <= i) = getfield/ifge { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // if (1 <= i) = getfield/ifgt { new SimpleInstruction(InstructionConstants.OP_ICONST_1), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // if (... > 0) = ifgt { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), },{ new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // if (... > -1) = ifge { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), },{ new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // if (0 < i) = iload/ifgt { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // if (-1 < i) = iload/ifge { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // if (0 < i) = getstatic/ifgt { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // if (-1 < i) = getstatic/ifge { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // if (0 < i) = getfield/ifgt { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // if (-1 < i) = getfield/ifge { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // if (... <= 0) = ifle { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), },{ new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // if (... <= -1) = iflt { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), },{ new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // if (0 >= i) = iload/ifle { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // if (-1 >= i) = iload/iflt { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, Y), new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // if (0 >= i) = getstatic/ifle { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // if (-1 >= i) = getstatic/iflt { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // if (0 >= i) = getfield/ifle { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // if (-1 >= i) = getfield/iflt { new SimpleInstruction(InstructionConstants.OP_ICONST_M1), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // if (... == null) = ifnull { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new BranchInstruction(InstructionConstants.OP_IFACMPEQ, X), },{ new BranchInstruction(InstructionConstants.OP_IFNULL, X), }, }, { // if (null == a) = aload/ifnull { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new BranchInstruction(InstructionConstants.OP_IFACMPEQ, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new BranchInstruction(InstructionConstants.OP_IFNULL, X), }, }, { // if (null == a) = getstatic/ifnull { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFACMPEQ, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFNULL, X), }, }, { // if (null == a) = getfield/ifnull { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFACMPEQ, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFNULL, X), }, }, { // if (... != null) = ifnonnull { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new BranchInstruction(InstructionConstants.OP_IFACMPNE, X), },{ new BranchInstruction(InstructionConstants.OP_IFNONNULL, X), }, }, { // if (null != a) = aload/ifnonnull { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new BranchInstruction(InstructionConstants.OP_IFACMPNE, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new BranchInstruction(InstructionConstants.OP_IFNONNULL, X), }, }, { // if (null != a) = getstatic/ifnonnull { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFACMPNE, X), },{ new ConstantInstruction(InstructionConstants.OP_GETSTATIC, Y), new BranchInstruction(InstructionConstants.OP_IFNONNULL, X), }, }, { // if (null != a) = getfield/ifnonnull { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFACMPNE, X), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, Y), new ConstantInstruction(InstructionConstants.OP_GETFIELD, Z), new BranchInstruction(InstructionConstants.OP_IFNONNULL, X), }, }, { // iconst_0/ifeq = goto { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFEQ, X), },{ new BranchInstruction(InstructionConstants.OP_GOTO, X), }, }, { // iconst/ifeq = nothing { new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new BranchInstruction(InstructionConstants.OP_IFEQ, X), },{ // Nothing. }, }, { // bipush/ifeq = nothing { new SimpleInstruction(InstructionConstants.OP_BIPUSH, A), new BranchInstruction(InstructionConstants.OP_IFEQ, X), },{ // Nothing. }, }, { // sipush/ifeq = nothing { new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new BranchInstruction(InstructionConstants.OP_IFEQ, X), },{ // Nothing. }, }, { // iconst_0/ifne = nothing { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFNE, X), },{ // Nothing. }, }, { // iconst/ifne = goto { new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new BranchInstruction(InstructionConstants.OP_IFNE, X), },{ new BranchInstruction(InstructionConstants.OP_GOTO, X), }, }, { // bipush/ifne = goto { new SimpleInstruction(InstructionConstants.OP_BIPUSH, A), new BranchInstruction(InstructionConstants.OP_IFNE, X), },{ new BranchInstruction(InstructionConstants.OP_GOTO, X), }, }, { // sipush/ifne = goto { new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new BranchInstruction(InstructionConstants.OP_IFNE, X), },{ new BranchInstruction(InstructionConstants.OP_GOTO, X), }, }, { // iconst_0/iflt = nothing { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFLT, X), },{ // Nothing. }, }, { // iconst_0/ifge = goto { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFGE, X), },{ new BranchInstruction(InstructionConstants.OP_GOTO, X), }, }, { // iconst_0/ifgt = nothing { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFGT, X), },{ // Nothing. }, }, { // iconst_0/ifle = goto { new SimpleInstruction(InstructionConstants.OP_ICONST_0), new BranchInstruction(InstructionConstants.OP_IFLE, X), },{ new BranchInstruction(InstructionConstants.OP_GOTO, X), }, }, { // aconst_null/ifnull = goto { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new BranchInstruction(InstructionConstants.OP_IFNULL, X), },{ new BranchInstruction(InstructionConstants.OP_GOTO, X), }, }, { // aconst_null/ifnonnul = nothing { new SimpleInstruction(InstructionConstants.OP_ACONST_NULL), new BranchInstruction(InstructionConstants.OP_IFNONNULL, X), },{ // Nothing. }, }, { // ifeq/goto = ifne { new BranchInstruction(InstructionConstants.OP_IFEQ, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFNE, X), }, }, { // ifne/goto = ifeq { new BranchInstruction(InstructionConstants.OP_IFNE, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFEQ, X), }, }, { // iflt/goto = ifge { new BranchInstruction(InstructionConstants.OP_IFLT, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFGE, X), }, }, { // ifge/goto = iflt { new BranchInstruction(InstructionConstants.OP_IFGE, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFLT, X), }, }, { // ifgt/goto = ifle { new BranchInstruction(InstructionConstants.OP_IFGT, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFLE, X), }, }, { // ifle/goto = ifgt { new BranchInstruction(InstructionConstants.OP_IFLE, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFGT, X), }, }, { // ificmpeq/goto = ificmpne { new BranchInstruction(InstructionConstants.OP_IFICMPEQ, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFICMPNE, X), }, }, { // ificmpne/goto = ificmpeq { new BranchInstruction(InstructionConstants.OP_IFICMPNE, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFICMPEQ, X), }, }, { // ificmplt/goto = ificmpge { new BranchInstruction(InstructionConstants.OP_IFICMPLT, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFICMPGE, X), }, }, { // ificmpge/goto = ificmplt { new BranchInstruction(InstructionConstants.OP_IFICMPGE, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFICMPLT, X), }, }, { // ificmpgt/goto = ificmple { new BranchInstruction(InstructionConstants.OP_IFICMPGT, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFICMPLE, X), }, }, { // ificmple/goto = ificmpgt { new BranchInstruction(InstructionConstants.OP_IFICMPLE, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFICMPGT, X), }, }, { // ifacmpeq/goto = ifacmpne { new BranchInstruction(InstructionConstants.OP_IFACMPEQ, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFACMPNE, X), }, }, { // ifacmpne/goto = ifacmpeq { new BranchInstruction(InstructionConstants.OP_IFACMPNE, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFACMPEQ, X), }, }, { // ifnull/goto = ifnonnull { new BranchInstruction(InstructionConstants.OP_IFNULL, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFNONNULL, X), }, }, { // ifnonnull/goto = ifnull { new BranchInstruction(InstructionConstants.OP_IFNONNULL, 6), new BranchInstruction(InstructionConstants.OP_GOTO, X), },{ new BranchInstruction(InstructionConstants.OP_IFNULL, X), }, }, // { // switch (...) { default: ... } = pop/goto ... // { // new TableSwitchInstruction(InstructionConstants.OP_TABLESWITCH, A, X, Y, 0, new int[0]), // },{ // new SimpleInstruction(InstructionConstants.OP_POP), // new BranchInstruction(InstructionConstants.OP_GOTO, A), // }, // }, // { // switch (...) { default: ... } = pop/goto ... // { // new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, A, 0, new int[0], new int[0]), // },{ // new SimpleInstruction(InstructionConstants.OP_POP), // new BranchInstruction(InstructionConstants.OP_GOTO, A), // }, // }, { // switch (...) { case/case/default: ... } = switch (...) { case/default: ... } { new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, A, new int[] { X, Y }, new int[] { A, B }), },{ new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, A, new int[] { Y }, new int[] { B }), }, }, { // switch (...) { case/case/default: ... } = switch (...) { case/default: ... } { new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, B, new int[] { X, Y }, new int[] { A, B }), },{ new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, B, new int[] { X }, new int[] { A }), }, }, { // switch (...) { case/case/case/default: ... } = switch (...) { case/case/default: ... } { new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, A, new int[] { X, Y, Z }, new int[] { A, B, C }), },{ new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, A, new int[] { Y, Z }, new int[] { B, C }), }, }, { // switch (...) { case/case/case/default: ... } = switch (...) { case/case/default: ... } { new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, B, new int[] { X, Y, Z }, new int[] { A, B, C }), },{ new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, B, new int[] { X, Z }, new int[] { A, C }), }, }, { // switch (...) { case/case/case/default: ... } = switch (...) { case/case/default: ... } { new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, C, new int[] { X, Y, Z }, new int[] { A, B, C }), },{ new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, C, new int[] { X, Y }, new int[] { A, B }), }, }, // { // switch (...) { case ...: ... default: ... } // // = if (... == ...) ... else ... // { // new TableSwitchInstruction(InstructionConstants.OP_TABLESWITCH, A, X, Y, 1, new int[] { B }), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, X), // new BranchInstruction(InstructionConstants.OP_IFICMPNE, A), // new BranchInstruction(InstructionConstants.OP_GOTO, B), // }, // }, // { // switch (...) { case ...: ... default: ... } // // = if (... == ...) ... else ... // { // new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH, A, 1, new int[] { X }, new int[] { B }), // },{ // new SimpleInstruction(InstructionConstants.OP_SIPUSH, X), // new BranchInstruction(InstructionConstants.OP_IFICMPNE, A), // new BranchInstruction(InstructionConstants.OP_GOTO, B), // }, // } }; public static final Instruction[][][] STRING = new Instruction[][][] { { // "...".equals("...") = true { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRING_EQUALS), },{ new SimpleInstruction(InstructionConstants.OP_ICONST_1), }, }, { // "...".length() = ... { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRING_LENGTH), },{ new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH), }, }, { // String.valueOf(Z) = ".... { new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z), },{ new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING), }, }, { // String.valueOf(C) = "...." { new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), }, }, { // String.valueOf(Cc) = "...." { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), }, }, { // String.valueOf(I) = "...." { new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), }, }, { // String.valueOf(Ic) = "...." { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), }, }, { // String.valueOf(J) = "...." { new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), }, }, { // String.valueOf(Jc) = "...." { new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), }, }, { // String.valueOf(F) = "...." { new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), }, }, { // String.valueOf(Fc) = "...." { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), }, }, { // String.valueOf(D) = "...." { new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), }, }, { // String.valueOf(Dc) = "...." { new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), }, }, { // new StringBuffer("...").toString() = "..." (ignoring identity) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new ConstantInstruction(InstructionConstants.OP_LDC, A), }, }, { // new StringBuffer(string).toString() = string (ignoring identity) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new VariableInstruction(InstructionConstants.OP_ALOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, A), }, }, { // new StringBuffer("...").length() = length { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_LENGTH), },{ new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH), }, }, { // StringBuffer#append("") = nothing { new ConstantInstruction(InstructionConstants.OP_LDC, STRING_EMPTY), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), },{ // Nothing. }, }, { // new StringBuffer().append(Z) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), },{ new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(C) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(Cc) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(I) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(Ic) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(J) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(Jc) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(F) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(Fc) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(D) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append(Dc) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer().append("...") = new StringBuffer("...") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), },{ new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(Z) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(C) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(Cc) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(I) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(Ic) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(J) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_LCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(Jc) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(F) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_FCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(Fc) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(D) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_DCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append(Dc) = new StringBuffer("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // new StringBuffer("...").append("...") = new StringBuffer("......") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), }, }, { // StringBuffer#append("...").append(Z) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(C) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(Cc) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(I) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(Ic) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(J) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_LCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(Jc) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(F) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_FCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(Fc) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(D) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_DCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append(Dc) = StringBuffer#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // StringBuffer#append("...").append("...") = StringBuffer#append("......") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), }, }, { // new StringBuffer().append(z).toString() = String.valueOf(z) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z), }, }, { // new StringBuffer().append(c).toString() = String.valueOf(c) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C), }, }, { // new StringBuffer().append(i).toString() = String.valueOf(i) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I), }, }, { // new StringBuffer().append(j).toString() = String.valueOf(j) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new VariableInstruction(InstructionConstants.OP_LLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_LLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J), }, }, { // new StringBuffer().append(f).toString() = String.valueOf(f) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new VariableInstruction(InstructionConstants.OP_FLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_FLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F), }, }, { // new StringBuffer().append(d).toString() = String.valueOf(d) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new VariableInstruction(InstructionConstants.OP_DLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_DLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D), }, }, { // new StringBuffer().append(string).toString() = string { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new VariableInstruction(InstructionConstants.OP_ALOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, A), }, }, { // new StringBuffer().append(object).toString() = String.valueOf(object) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), new VariableInstruction(InstructionConstants.OP_ALOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_OBJECT), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_OBJECT), }, }, { // new StringBuilder("...").toString() = "..." (ignoring identity) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new ConstantInstruction(InstructionConstants.OP_LDC, A), }, }, { // new StringBuilder(string).toString() = string (ignoring identity) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new VariableInstruction(InstructionConstants.OP_ALOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, A), }, }, { // new StringBuilder("...").length() = length { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_LENGTH), },{ new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH), }, }, { // StringBuilder#append("") = nothing { new ConstantInstruction(InstructionConstants.OP_LDC, STRING_EMPTY), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), },{ // Nothing. }, }, { // new StringBuilder().append(Z) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), },{ new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(C) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(Cc) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(I) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(Ic) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(J) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(Jc) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(F) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(Fc) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(D) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append(Dc) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder().append("...") = new StringBuilder("...") { new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), },{ new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(Z) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(C) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(Cc) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(I) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(Ic) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(J) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_LCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(Jc) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(F) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_FCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(Fc) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(D) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new SimpleInstruction(InstructionConstants.OP_DCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append(Dc) = new StringBuilder("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // new StringBuilder("...").append("...") = new StringBuilder("......") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), }, }, { // StringBuilder#append("...").append(Z) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(C) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(Cc) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(I) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(Ic) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(J) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_LCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(Jc) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(F) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_FCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(Fc) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(D) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new SimpleInstruction(InstructionConstants.OP_DCONST_0, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append(Dc) = StringBuilder#append("....") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // StringBuilder#append("...").append("...") = StringBuilder#append("......") { new ConstantInstruction(InstructionConstants.OP_LDC, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_LDC, B), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), },{ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), }, }, { // new StringBuilder().append(z).toString() = String.valueOf(z) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z), }, }, { // new StringBuilder().append(c).toString() = String.valueOf(c) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C), }, }, { // new StringBuilder().append(i).toString() = String.valueOf(i) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I), }, }, { // new StringBuilder().append(j).toString() = String.valueOf(j) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new VariableInstruction(InstructionConstants.OP_LLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_LLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J), }, }, { // new StringBuilder().append(f).toString() = String.valueOf(f) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new VariableInstruction(InstructionConstants.OP_FLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_FLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F), }, }, { // new StringBuilder().append(d).toString() = String.valueOf(d) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new VariableInstruction(InstructionConstants.OP_DLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_DLOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D), }, }, { // new StringBuilder().append(string).toString() = string { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new VariableInstruction(InstructionConstants.OP_ALOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, A), }, }, { // new StringBuilder().append(object).toString() = String.valueOf(object) { new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), new SimpleInstruction(InstructionConstants.OP_DUP), new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), new VariableInstruction(InstructionConstants.OP_ALOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_OBJECT), new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), },{ new VariableInstruction(InstructionConstants.OP_ALOAD, A), new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_OBJECT), }, }, }; /** * Prints out the constants and the instruction sequences. */ public static void main(String[] args) { ProgramClass clazz = new ProgramClass(); clazz.constantPool = CONSTANTS; ClassPrinter printer = new ClassPrinter(); for (int index = 0; index < CONSTANTS.length; index++) { System.out.print("["+index+"] "); try { CONSTANTS[index].accept(clazz, printer); } catch (Exception e) { System.out.println("("+e.getClass().getName()+")"); } } if (CONSTANTS.length != SENTINEL) { throw new IllegalStateException("Constants length ["+CONSTANTS.length+"] different from number of constant names ["+SENTINEL+"]"); } Instruction[][][] sequences = STRING; for (int sequence = 0; sequence < sequences.length; sequence++) { System.out.println(); Instruction[] instructions = sequences[sequence][0]; for (int index = 0; index < instructions.length; index++) { Instruction instruction = instructions[index]; try { instruction.accept(clazz, null, null, index, new ClassPrinter()); } catch (Exception e) {} } System.out.println("=>"); instructions = sequences[sequence][1]; for (int index = 0; index < instructions.length; index++) { Instruction instruction = instructions[index]; try { instruction.accept(clazz, null, null, index, new ClassPrinter()); } catch (Exception e) {} } } } } proguard4.8/src/proguard/optimize/peephole/ClassFinalizer.java0000644000175000017500000000523711736333525023427 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.optimize.KeepMarker; /** * This ClassVisitor makes the program classes that it visits * final, if possible. * * @author Eric Lafortune */ public class ClassFinalizer extends SimplifiedVisitor implements ClassVisitor { private final ClassVisitor extraClassVisitor; /** * Creates a new ClassFinalizer. */ public ClassFinalizer() { this(null); } /** * Creates a new ClassFinalizer. * @param extraClassVisitor an optional extra visitor for all finalized * classes. */ public ClassFinalizer(ClassVisitor extraClassVisitor) { this.extraClassVisitor = extraClassVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // If the class is not final/interface/abstract, // and it is not being kept, // and it doesn't have any subclasses, // then make it final. if ((programClass.u2accessFlags & (ClassConstants.INTERNAL_ACC_FINAL | ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 && !KeepMarker.isKept(programClass) && programClass.subClasses == null) { programClass.u2accessFlags |= ClassConstants.INTERNAL_ACC_FINAL; // Visit the class, if required. if (extraClassVisitor != null) { extraClassVisitor.visitProgramClass(programClass); } } } } proguard4.8/src/proguard/optimize/peephole/InstructionSequenceReplacer.java0000664000175000017500000004640411736333525026211 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; /** * This InstructionVisitor replaces a given pattern instruction sequence by * another given replacement instruction sequence. The arguments of the * instruction sequences can be wildcards that are matched and replaced. * * @see InstructionSequenceMatcher * @author Eric Lafortune */ public class InstructionSequenceReplacer extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor { /* public static boolean DEBUG = true; /*/ private static final boolean DEBUG = false; //*/ public static final int X = InstructionSequenceMatcher.X; public static final int Y = InstructionSequenceMatcher.Y; public static final int Z = InstructionSequenceMatcher.Z; public static final int A = InstructionSequenceMatcher.A; public static final int B = InstructionSequenceMatcher.B; public static final int C = InstructionSequenceMatcher.C; public static final int D = InstructionSequenceMatcher.D; private static final int BOOLEAN_STRING = 0x1; private static final int CHAR_STRING = 0x2; private static final int INT_STRING = 0x3; private static final int LONG_STRING = 0x4; private static final int FLOAT_STRING = 0x5; private static final int DOUBLE_STRING = 0x6; private static final int STRING_STRING = 0x7; public static final int STRING_A_LENGTH = 0x20000000; public static final int BOOLEAN_A_STRING = 0x20000001; public static final int CHAR_A_STRING = 0x20000002; public static final int INT_A_STRING = 0x20000003; public static final int LONG_A_STRING = 0x20000004; public static final int FLOAT_A_STRING = 0x20000005; public static final int DOUBLE_A_STRING = 0x20000006; public static final int STRING_A_STRING = 0x20000007; public static final int BOOLEAN_B_STRING = 0x20000010; public static final int CHAR_B_STRING = 0x20000020; public static final int INT_B_STRING = 0x20000030; public static final int LONG_B_STRING = 0x20000040; public static final int FLOAT_B_STRING = 0x20000050; public static final int DOUBLE_B_STRING = 0x20000060; public static final int STRING_B_STRING = 0x20000070; private final InstructionSequenceMatcher instructionSequenceMatcher; private final Constant[] patternConstants; private final Instruction[] replacementInstructions; private final BranchTargetFinder branchTargetFinder; private final CodeAttributeEditor codeAttributeEditor; private final InstructionVisitor extraInstructionVisitor; private final MyReplacementInstructionFactory replacementInstructionFactory = new MyReplacementInstructionFactory(); /** * Creates a new InstructionSequenceReplacer. * @param patternConstants any constants referenced by the pattern * instruction. * @param patternInstructions the pattern instruction sequence. * @param replacementInstructions the replacement instruction sequence. * @param branchTargetFinder a branch target finder that has been * initialized to indicate branch targets * in the visited code. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. */ public InstructionSequenceReplacer(Constant[] patternConstants, Instruction[] patternInstructions, Instruction[] replacementInstructions, BranchTargetFinder branchTargetFinder, CodeAttributeEditor codeAttributeEditor) { this(patternConstants, patternInstructions, replacementInstructions, branchTargetFinder, codeAttributeEditor, null); } /** * Creates a new InstructionSequenceReplacer. * @param patternConstants any constants referenced by the pattern * instruction. * @param branchTargetFinder a branch target finder that has been * initialized to indicate branch targets * in the visited code. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. * @param extraInstructionVisitor an optional extra visitor for all deleted * load instructions. */ public InstructionSequenceReplacer(Constant[] patternConstants, Instruction[] patternInstructions, Instruction[] replacementInstructions, BranchTargetFinder branchTargetFinder, CodeAttributeEditor codeAttributeEditor, InstructionVisitor extraInstructionVisitor) { this.instructionSequenceMatcher = new InstructionSequenceMatcher(patternConstants, patternInstructions); this.patternConstants = patternConstants; this.replacementInstructions = replacementInstructions; this.branchTargetFinder = branchTargetFinder; this.codeAttributeEditor = codeAttributeEditor; this.extraInstructionVisitor = extraInstructionVisitor; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { // Reset the instruction sequence matcher if the instruction is a branch // target or if it has already been modified. if (branchTargetFinder.isTarget(offset) || codeAttributeEditor.isModified(offset)) { instructionSequenceMatcher.reset(); } // Try to match the instruction. instruction.accept(clazz, method, codeAttribute, offset, instructionSequenceMatcher); // Did the instruction sequence match and is it still unmodified? if (instructionSequenceMatcher.isMatching() && matchedInstructionsUnmodified()) { if (DEBUG) { System.out.println("InstructionSequenceReplacer: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); System.out.println(" Matched:"); for (int index = 0; index < instructionSequenceMatcher.instructionCount(); index++) { int matchedOffset = instructionSequenceMatcher.matchedInstructionOffset(index); System.out.println(" "+InstructionFactory.create(codeAttribute.code, matchedOffset).toString(matchedOffset)); } System.out.println(" Replacement:"); for (int index = 0; index < replacementInstructions.length; index++) { int matchedOffset = instructionSequenceMatcher.matchedInstructionOffset(index); System.out.println(" "+replacementInstructionFactory.create(clazz, index).shrink().toString(matchedOffset)); } } // Replace the instruction sequence. for (int index = 0; index < replacementInstructions.length; index++) { codeAttributeEditor.replaceInstruction(instructionSequenceMatcher.matchedInstructionOffset(index), replacementInstructionFactory.create(clazz, index).shrink()); } // Delete any remaining instructions in the from sequence. for (int index = replacementInstructions.length; index < instructionSequenceMatcher.instructionCount(); index++) { codeAttributeEditor.deleteInstruction(instructionSequenceMatcher.matchedInstructionOffset(index)); } // Visit the instruction, if required. if (extraInstructionVisitor != null) { instruction.accept(clazz, method, codeAttribute, offset, extraInstructionVisitor); } } } // Small utility methods. /** * Returns whether the matched pattern instructions haven't been modified * before. */ private boolean matchedInstructionsUnmodified() { for (int index = 0; index < instructionSequenceMatcher.instructionCount(); index++) { if (codeAttributeEditor.isModified(instructionSequenceMatcher.matchedInstructionOffset(index))) { return false; } } return true; } /** * This class creates replacement instructions for matched sequences, with * any matched arguments filled out. */ private class MyReplacementInstructionFactory implements InstructionVisitor { private Instruction replacementInstruction; /** * Creates the replacement instruction for the given index in the * instruction sequence. */ public Instruction create(Clazz clazz, int index) { // Create the instruction. replacementInstructions[index].accept(clazz, null, null, instructionSequenceMatcher.matchedInstructionOffset(index), this); // Return it. return replacementInstruction.shrink(); } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { replacementInstruction = new SimpleInstruction(simpleInstruction.opcode, matchedArgument(clazz, simpleInstruction.constant)); } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { replacementInstruction = new VariableInstruction(variableInstruction.opcode, instructionSequenceMatcher.matchedArgument(variableInstruction.variableIndex), instructionSequenceMatcher.matchedArgument(variableInstruction.constant)); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { replacementInstruction = new ConstantInstruction(constantInstruction.opcode, matchedConstantIndex((ProgramClass)clazz, constantInstruction.constantIndex), instructionSequenceMatcher.matchedArgument(constantInstruction.constant)); } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { replacementInstruction = new BranchInstruction(branchInstruction.opcode, instructionSequenceMatcher.matchedBranchOffset(offset, branchInstruction.branchOffset)); } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { replacementInstruction = new TableSwitchInstruction(tableSwitchInstruction.opcode, instructionSequenceMatcher.matchedBranchOffset(offset, tableSwitchInstruction.defaultOffset), instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.lowCase), instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.highCase), instructionSequenceMatcher.matchedJumpOffsets(offset, tableSwitchInstruction.jumpOffsets)); } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { replacementInstruction = new LookUpSwitchInstruction(lookUpSwitchInstruction.opcode, instructionSequenceMatcher.matchedBranchOffset(offset, lookUpSwitchInstruction.defaultOffset), instructionSequenceMatcher.matchedArguments(lookUpSwitchInstruction.cases), instructionSequenceMatcher.matchedJumpOffsets(offset, lookUpSwitchInstruction.jumpOffsets)); } /** * Returns the matched argument for the given pattern argument. */ private int matchedArgument(Clazz clazz, int argument) { // Special case: do we have to compute the string length? if (argument == STRING_A_LENGTH) { // Return the string length. return clazz.getStringString(instructionSequenceMatcher.matchedArgument(A)).length(); } // Otherwise, just return the matched argument. return instructionSequenceMatcher.matchedArgument(argument); } /** * Returns the matched or newly created constant index for the given * pattern constant index. */ private int matchedConstantIndex(ProgramClass programClass, int constantIndex) { // Special case: do we have to create a concatenated string? if (constantIndex >= BOOLEAN_A_STRING && constantIndex <= (STRING_A_STRING | STRING_B_STRING)) { // Create a new string constant and return its index. return new ConstantPoolEditor(programClass).addStringConstant( argumentAsString(programClass, constantIndex & 0xf, A) + argumentAsString(programClass, (constantIndex >>> 4) & 0xf, B), null, null); } int matchedConstantIndex = instructionSequenceMatcher.matchedConstantIndex(constantIndex); // Do we have a matched constant index? if (matchedConstantIndex > 0) { // Return its index. return matchedConstantIndex; } // Otherwise, we still have to create a new constant. // This currently only works for constants without any wildcards. ProgramClass dummyClass = new ProgramClass(); dummyClass.constantPool = patternConstants; return new ConstantAdder(programClass).addConstant(dummyClass, constantIndex); } private String argumentAsString(ProgramClass programClass, int valueType, int argument) { switch (valueType) { case BOOLEAN_STRING: return Boolean.toString((instructionSequenceMatcher.wasConstant(argument) ? ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : instructionSequenceMatcher.matchedArgument(argument)) != 0); case CHAR_STRING: return Character.toString((char)(instructionSequenceMatcher.wasConstant(argument) ? ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : instructionSequenceMatcher.matchedArgument(argument))); case INT_STRING: return Integer.toString(instructionSequenceMatcher.wasConstant(argument) ? ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : instructionSequenceMatcher.matchedArgument(argument)); case LONG_STRING: return Long.toString(instructionSequenceMatcher.wasConstant(argument) ? ((LongConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : instructionSequenceMatcher.matchedArgument(argument)); case FLOAT_STRING: return Float.toString(instructionSequenceMatcher.wasConstant(argument) ? ((FloatConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : instructionSequenceMatcher.matchedArgument(argument)); case DOUBLE_STRING: return Double.toString(instructionSequenceMatcher.wasConstant(argument) ? ((DoubleConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : instructionSequenceMatcher.matchedArgument(argument)); case STRING_STRING: return programClass.getStringString(instructionSequenceMatcher.matchedConstantIndex(argument)); default: return ""; } } } } proguard4.8/src/proguard/optimize/peephole/BranchTargetFinder.java0000644000175000017500000005604411736333525024214 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import java.util.Arrays; /** * This AttributeVisitor finds all instruction offsets, branch targets, and * exception targets in the CodeAttribute objects that it visits. * * @author Eric Lafortune */ public class BranchTargetFinder extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor, ConstantVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ public static final int NONE = -2; public static final int AT_METHOD_ENTRY = -1; private static final short INSTRUCTION = 1 << 0; private static final short BRANCH_ORIGIN = 1 << 1; private static final short BRANCH_TARGET = 1 << 2; private static final short AFTER_BRANCH = 1 << 3; private static final short EXCEPTION_START = 1 << 4; private static final short EXCEPTION_END = 1 << 5; private static final short EXCEPTION_HANDLER = 1 << 6; private static final short SUBROUTINE_INVOCATION = 1 << 7; private static final short SUBROUTINE_RETURNING = 1 << 8; private static final int MAXIMUM_CREATION_OFFSETS = 32; private short[] instructionMarks = new short[ClassConstants.TYPICAL_CODE_LENGTH + 1]; private int[] subroutineStarts = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] subroutineEnds = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] creationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] initializationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private int superInitializationOffset; private int currentSubroutineStart; private int currentSubroutineEnd; private int[] recentCreationOffsets = new int[MAXIMUM_CREATION_OFFSETS]; private int recentCreationOffsetIndex; private boolean isInitializer; /** * Returns whether there is an instruction at the given offset in the * CodeAttribute that was visited most recently. */ public boolean isInstruction(int offset) { return (instructionMarks[offset] & INSTRUCTION) != 0; } /** * Returns whether the instruction at the given offset is the target of * any kind in the CodeAttribute that was visited most recently. */ public boolean isTarget(int offset) { return offset == 0 || (instructionMarks[offset] & (BRANCH_TARGET | EXCEPTION_START | EXCEPTION_END | EXCEPTION_HANDLER)) != 0; } /** * Returns whether the instruction at the given offset is the origin of a * branch instruction in the CodeAttribute that was visited most recently. */ public boolean isBranchOrigin(int offset) { return (instructionMarks[offset] & BRANCH_ORIGIN) != 0; } /** * Returns whether the instruction at the given offset is the target of a * branch instruction in the CodeAttribute that was visited most recently. */ public boolean isBranchTarget(int offset) { return (instructionMarks[offset] & BRANCH_TARGET) != 0; } /** * Returns whether the instruction at the given offset comes right after a * definite branch instruction in the CodeAttribute that was visited most * recently. */ public boolean isAfterBranch(int offset) { return (instructionMarks[offset] & AFTER_BRANCH) != 0; } /** * Returns whether the instruction at the given offset is the start of an * exception try block in the CodeAttribute that was visited most recently. */ public boolean isExceptionStart(int offset) { return (instructionMarks[offset] & EXCEPTION_START) != 0; } /** * Returns whether the instruction at the given offset is the end of an * exception try block in the CodeAttribute that was visited most recently. */ public boolean isExceptionEnd(int offset) { return (instructionMarks[offset] & EXCEPTION_END) != 0; } /** * Returns whether the instruction at the given offset is the start of an * exception catch block in the CodeAttribute that was visited most recently. */ public boolean isExceptionHandler(int offset) { return (instructionMarks[offset] & EXCEPTION_HANDLER) != 0; } /** * Returns whether the instruction at the given offset is a subroutine * invocation in the CodeAttribute that was visited most recently. */ public boolean isSubroutineInvocation(int offset) { return (instructionMarks[offset] & SUBROUTINE_INVOCATION) != 0; } /** * Returns whether the instruction at the given offset is the start of a * subroutine in the CodeAttribute that was visited most recently. */ public boolean isSubroutineStart(int offset) { return subroutineStarts[offset] == offset; } /** * Returns whether the instruction at the given offset is part of a * subroutine in the CodeAttribute that was visited most recently. */ public boolean isSubroutine(int offset) { return subroutineStarts[offset] != NONE; } /** * Returns whether the subroutine at the given offset is ever returning * by means of a regular 'ret' instruction. */ public boolean isSubroutineReturning(int offset) { return (instructionMarks[offset] & SUBROUTINE_RETURNING) != 0; } /** * Returns the start offset of the subroutine at the given offset, in the * CodeAttribute that was visited most recently. */ public int subroutineStart(int offset) { return subroutineStarts[offset]; } /** * Returns the offset after the subroutine at the given offset, in the * CodeAttribute that was visited most recently. */ public int subroutineEnd(int offset) { return subroutineEnds[offset]; } /** * Returns whether the instruction at the given offset is a 'new' * instruction, in the CodeAttribute that was visited most recently. */ public boolean isNew(int offset) { return initializationOffsets[offset] != NONE; } /** * Returns the instruction offset at which the object instance that is * created at the given 'new' instruction offset is initialized, or * NONE if it is not being created. */ public int initializationOffset(int offset) { return initializationOffsets[offset]; } /** * Returns whether the method is an instance initializer, in the * CodeAttribute that was visited most recently. */ public boolean isInitializer() { return superInitializationOffset != NONE; } /** * Returns the instruction offset at which this initializer is calling * the "super" or "this" initializer method, or NONE if it is * not an initializer. */ public int superInitializationOffset() { return superInitializationOffset; } /** * Returns whether the instruction at the given offset is the special * invocation of an instance initializer, in the CodeAttribute that was * visited most recently. */ public boolean isInitializer(int offset) { return creationOffsets[offset] != NONE; } /** * Returns the offset of the 'new' instruction that corresponds to the * invocation of the instance initializer at the given offset, or * AT_METHOD_ENTRY if the invocation is calling the "super" or * "this" initializer method, , or NONE if it is not a 'new' * instruction. */ public int creationOffset(int offset) { return creationOffsets[offset]; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // Make sure there are sufficiently large arrays. int codeLength = codeAttribute.u4codeLength; if (subroutineStarts.length < codeLength) { // Create new arrays. instructionMarks = new short[codeLength + 1]; subroutineStarts = new int[codeLength]; subroutineEnds = new int[codeLength]; creationOffsets = new int[codeLength]; initializationOffsets = new int[codeLength]; // Reset the arrays. Arrays.fill(subroutineStarts, 0, codeLength, NONE); Arrays.fill(subroutineEnds, 0, codeLength, NONE); Arrays.fill(creationOffsets, 0, codeLength, NONE); Arrays.fill(initializationOffsets, 0, codeLength, NONE); } else { // Reset the arrays. Arrays.fill(instructionMarks, 0, codeLength, (short)0); Arrays.fill(subroutineStarts, 0, codeLength, NONE); Arrays.fill(subroutineEnds, 0, codeLength, NONE); Arrays.fill(creationOffsets, 0, codeLength, NONE); Arrays.fill(initializationOffsets, 0, codeLength, NONE); instructionMarks[codeLength] = 0; } superInitializationOffset = NONE; // We're assuming all subroutines are contiguous blocks of code. // We're not starting in a subroutine. currentSubroutineStart = NONE; currentSubroutineEnd = NONE; recentCreationOffsetIndex = 0; // Initialize the stack of 'new' instruction offsets if this method is // an instance initializer. if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { recentCreationOffsets[recentCreationOffsetIndex++] = AT_METHOD_ENTRY; } // The end of the code is a branch target sentinel. instructionMarks[codeLength] = BRANCH_TARGET; // Mark branch targets by going over all instructions. codeAttribute.instructionsAccept(clazz, method, this); // Mark branch targets in the exception table. codeAttribute.exceptionsAccept(clazz, method, this); // Fill out any gaps in the subroutine starts and the subroutine ends // and subroutine returning flags, working backward. // We're not starting in a subroutine. int subroutineStart = NONE; int subroutineEnd = codeLength; boolean subroutineReturning = false; for (int index = codeLength - 1; index >= 0; index--) { if (isInstruction(index)) { // Are we inside a previously marked subroutine? if (subroutineStarts[index] != NONE) { // Update the current subroutine start. subroutineStart = subroutineStarts[index]; } else if (subroutineStart != NONE) { // Mark the subroutine start. subroutineStarts[index] = subroutineStart; } // Did we reach the start of the subroutine. if (isSubroutineStart(index)) { // Stop marking it. subroutineStart = NONE; } // Are we inside a subroutine? if (isSubroutine(index)) { // Mark the subroutine end. subroutineEnds[index] = subroutineEnd; // Update or mark the subroutine returning flag. if (isSubroutineReturning(index)) { subroutineReturning = true; } else if (subroutineReturning) { instructionMarks[index] |= SUBROUTINE_RETURNING; } } else { // Update the subroutine end and returning flag. subroutineEnd = index; subroutineReturning = false; } } } if (DEBUG) { System.out.println(); System.out.println("Branch targets: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); for (int index = 0; index < codeLength; index++) { if (isInstruction(index)) { System.out.println("" + (isBranchOrigin(index) ? 'B' : '-') + (isAfterBranch(index) ? 'b' : '-') + (isBranchTarget(index) ? 'T' : '-') + (isExceptionStart(index) ? 'E' : '-') + (isExceptionEnd(index) ? 'e' : '-') + (isExceptionHandler(index) ? 'H' : '-') + (isSubroutineInvocation(index) ? 'J' : '-') + (isSubroutineStart(index) ? 'S' : '-') + (isSubroutineReturning(index) ? 'r' : '-') + (isSubroutine(index) ? " ["+subroutineStart(index)+" -> "+subroutineEnd(index)+"]" : "") + (isNew(index) ? " ["+initializationOffset(index)+"] " : " ---- ") + InstructionFactory.create(codeAttribute.code, index).toString(index)); } } } } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; // Check if this is the first instruction of a subroutine. checkSubroutine(offset); byte opcode = simpleInstruction.opcode; if (opcode == InstructionConstants.OP_IRETURN || opcode == InstructionConstants.OP_LRETURN || opcode == InstructionConstants.OP_FRETURN || opcode == InstructionConstants.OP_DRETURN || opcode == InstructionConstants.OP_ARETURN || opcode == InstructionConstants.OP_ATHROW) { // Mark the branch origin. markBranchOrigin(offset); // Mark the next instruction. markAfterBranchOrigin(offset + simpleInstruction.length(offset)); } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; // Check if this is the first instruction of a subroutine. checkSubroutine(offset); // Check if the instruction is a 'new' instruction. if (constantInstruction.opcode == InstructionConstants.OP_NEW) { // Push the 'new' instruction offset on the stack. recentCreationOffsets[recentCreationOffsetIndex++] = offset; } else { // Check if the instruction is an initializer invocation. isInitializer = false; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); if (isInitializer) { // Pop the 'new' instruction offset from the stack. int recentCreationOffset = recentCreationOffsets[--recentCreationOffsetIndex]; // Fill it out in the creation offsets. creationOffsets[offset] = recentCreationOffset; // Fill out the initialization offsets. if (recentCreationOffset == AT_METHOD_ENTRY) { superInitializationOffset = offset; } else { initializationOffsets[recentCreationOffset] = offset; } } } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; // Check if this is the first instruction of a subroutine. checkSubroutine(offset); if (variableInstruction.opcode == InstructionConstants.OP_RET) { // Mark the branch origin. markBranchOrigin(offset); // Mark the regular subroutine return. instructionMarks[offset] |= SUBROUTINE_RETURNING; // Mark the next instruction. markAfterBranchOrigin(offset + variableInstruction.length(offset)); } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Mark the branch origin. markBranchOrigin(offset); // Check if this is the first instruction of a subroutine. checkSubroutine(offset); // Mark the branch target. markBranchTarget(offset, branchInstruction.branchOffset); byte opcode = branchInstruction.opcode; if (opcode == InstructionConstants.OP_JSR || opcode == InstructionConstants.OP_JSR_W) { // Mark the subroutine invocation. instructionMarks[offset] |= SUBROUTINE_INVOCATION; // Mark the subroutine start. int targetOffset = offset + branchInstruction.branchOffset; subroutineStarts[targetOffset] = targetOffset; } else if (opcode == InstructionConstants.OP_GOTO || opcode == InstructionConstants.OP_GOTO_W) { // Mark the next instruction. markAfterBranchOrigin(offset + branchInstruction.length(offset)); } } public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) { // Mark the branch origin. markBranchOrigin(offset); // Check if this is the first instruction of a subroutine. checkSubroutine(offset); // Mark the branch targets of the default jump offset. markBranchTarget(offset, switchInstruction.defaultOffset); // Mark the branch targets of the jump offsets. markBranchTargets(offset, switchInstruction.jumpOffsets); // Mark the next instruction. markAfterBranchOrigin(offset + switchInstruction.length(offset)); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { isInitializer = methodrefConstant.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { // Mark the exception offsets. instructionMarks[exceptionInfo.u2startPC] |= EXCEPTION_START; instructionMarks[exceptionInfo.u2endPC] |= EXCEPTION_END; instructionMarks[exceptionInfo.u2handlerPC] |= EXCEPTION_HANDLER; } // Small utility methods. /** * Marks the branch targets of the given jump offsets for the instruction * at the given offset. */ private void markBranchTargets(int offset, int[] jumpOffsets) { for (int index = 0; index < jumpOffsets.length; index++) { markBranchTarget(offset, jumpOffsets[index]); } } /** * Marks the branch origin at the given offset. */ private void markBranchOrigin(int offset) { instructionMarks[offset] |= INSTRUCTION | BRANCH_ORIGIN; } /** * Marks the branch target at the given offset. */ private void markBranchTarget(int offset, int jumpOffset) { int targetOffset = offset + jumpOffset; instructionMarks[targetOffset] |= BRANCH_TARGET; // Are we inside a previously marked subroutine? if (isSubroutine(offset)) { // Mark the subroutine start of the target. subroutineStarts[targetOffset] = currentSubroutineStart; // Update the current subroutine end. if (currentSubroutineEnd < targetOffset) { currentSubroutineEnd = targetOffset; } } } /** * Marks the instruction at the given offset, after a branch. */ private void markAfterBranchOrigin(int nextOffset) { instructionMarks[nextOffset] |= AFTER_BRANCH; // Are we at the end of the current subroutine? if (currentSubroutineEnd <= nextOffset) { // Reset the subroutine start. currentSubroutineStart = NONE; } } /** * Checks if the specified instruction is inside a subroutine. */ private void checkSubroutine(int offset) { // Are we inside a previously marked subroutine? if (isSubroutine(offset)) { // Update the current subroutine start. currentSubroutineStart = subroutineStarts[offset]; } else { // Mark the subroutine start (or NONE). subroutineStarts[offset] = currentSubroutineStart; } } } proguard4.8/src/proguard/optimize/peephole/PeepholeOptimizer.java0000644000175000017500000000775011736333525024164 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor sets up and applies the peephole optimizations of its * instruction visitor. The instruction visitor should be using the same * (optional) branch target finder and code attribute editor. * * @author Eric Lafortune */ public class PeepholeOptimizer extends SimplifiedVisitor implements AttributeVisitor { private final BranchTargetFinder branchTargetFinder; private final CodeAttributeEditor codeAttributeEditor; private final InstructionVisitor instructionVisitor; /** * Creates a new PeepholeOptimizer. * @param codeAttributeEditor the code attribute editor that will be reset * and then executed. * @param instructionVisitor the instruction visitor that performs * peephole optimizations using the above code * attribute editor. */ public PeepholeOptimizer(CodeAttributeEditor codeAttributeEditor, InstructionVisitor instructionVisitor) { this(null, codeAttributeEditor, instructionVisitor); } /** * Creates a new PeepholeOptimizer. * @param branchTargetFinder branch target finder that will be initialized * to indicate branch targets in the visited code. * @param codeAttributeEditor the code attribute editor that will be reset * and then executed. * @param instructionVisitor the instruction visitor that performs * peephole optimizations using the above code * attribute editor. */ public PeepholeOptimizer(BranchTargetFinder branchTargetFinder, CodeAttributeEditor codeAttributeEditor, InstructionVisitor instructionVisitor) { this.branchTargetFinder = branchTargetFinder; this.codeAttributeEditor = codeAttributeEditor; this.instructionVisitor = instructionVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (branchTargetFinder != null) { // Set up the branch target finder. branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute); } // Set up the code attribute editor. codeAttributeEditor.reset(codeAttribute.u4codeLength); // Find the peephole optimizations. codeAttribute.instructionsAccept(clazz, method, instructionVisitor); // Apply the peephole optimizations. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } } proguard4.8/src/proguard/optimize/peephole/VariableShrinker.java0000644000175000017500000001075311736333525023750 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.editor.VariableEditor; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.*; import proguard.optimize.info.*; /** * This MemberVisitor removes unused local variables from the code of the methods * that it visits. * * @see ParameterUsageMarker * @see MethodStaticizer * @see MethodDescriptorShrinker * @author Eric Lafortune */ public class VariableShrinker extends SimplifiedVisitor implements AttributeVisitor { private static final boolean DEBUG = false; private final MemberVisitor extraVariableMemberVisitor; private final VariableUsageMarker variableUsageMarker = new VariableUsageMarker(); private final VariableEditor variableEditor = new VariableEditor(); /** * Creates a new VariableShrinker. */ public VariableShrinker() { this(null); } /** * Creates a new VariableShrinker with an extra visitor. * @param extraVariableMemberVisitor an optional extra visitor for all * removed variables. */ public VariableShrinker(MemberVisitor extraVariableMemberVisitor) { this.extraVariableMemberVisitor = extraVariableMemberVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT) == 0) { // Compute the parameter size. int parameterSize = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), method.getAccessFlags()); // Get the total size of the local variable frame. int maxLocals = codeAttribute.u2maxLocals; if (DEBUG) { System.out.println("VariableShrinker: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); System.out.println(" Parameter size = " + parameterSize); System.out.println(" Max locals = " + maxLocals); } // Figure out the local variables that are used by the code. variableUsageMarker.visitCodeAttribute(clazz, method, codeAttribute); // Delete unused local variables from the local variable frame. variableEditor.reset(maxLocals); for (int variableIndex = parameterSize; variableIndex < maxLocals; variableIndex++) { // Is the variable not required? if (!variableUsageMarker.isVariableUsed(variableIndex)) { if (DEBUG) { System.out.println(" Deleting local variable #"+variableIndex); } // Delete the unused variable. variableEditor.deleteVariable(variableIndex); // Visit the method, if required. if (extraVariableMemberVisitor != null) { method.accept(clazz, extraVariableMemberVisitor); } } } // Shift all remaining parameters and variables in the byte code. variableEditor.visitCodeAttribute(clazz, method, codeAttribute); } } } proguard4.8/src/proguard/optimize/peephole/NopRemover.java0000644000175000017500000000635511736333525022614 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor removes all nop instructions that it encounters. * * @author Eric Lafortune */ public class NopRemover extends SimplifiedVisitor implements InstructionVisitor { private final CodeAttributeEditor codeAttributeEditor; private final InstructionVisitor extraInstructionVisitor; /** * Creates a new NopRemover. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. */ public NopRemover(CodeAttributeEditor codeAttributeEditor) { this(codeAttributeEditor, null); } /** * Creates a new NopRemover. * @param codeAttributeEditor a code editor that can be used for * accumulating changes to the code. * @param extraInstructionVisitor an optional extra visitor for all removed * nop instructions. */ public NopRemover(CodeAttributeEditor codeAttributeEditor, InstructionVisitor extraInstructionVisitor) { this.codeAttributeEditor = codeAttributeEditor; this.extraInstructionVisitor = extraInstructionVisitor; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Check if the instruction is a nop instruction. if (simpleInstruction.opcode == InstructionConstants.OP_NOP && !codeAttributeEditor.isModified(offset)) { codeAttributeEditor.deleteInstruction(offset); // Visit the instruction, if required. if (extraInstructionVisitor != null) { extraInstructionVisitor.visitSimpleInstruction(clazz, method, codeAttribute, offset, simpleInstruction); } } } } proguard4.8/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java0000644000175000017500000002325511736333525025050 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor redirects unconditional branches so any common code * is shared, and the code preceding the branch can be removed, in the code * attributes that it visits. * * @author Eric Lafortune */ public class GotoCommonCodeReplacer extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final InstructionVisitor extraInstructionVisitor; private final BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); /** * Creates a new GotoCommonCodeReplacer. * @param extraInstructionVisitor an optional extra visitor for all replaced * goto instructions. */ public GotoCommonCodeReplacer(InstructionVisitor extraInstructionVisitor) { this.extraInstructionVisitor = extraInstructionVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); // Mark all branch targets. branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute); // Reset the code attribute editor. codeAttributeEditor.reset(codeAttribute.u4codeLength); // Remap the variables of the instructions. codeAttribute.instructionsAccept(clazz, method, this); // Apply the code atribute editor. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Check if the instruction is an unconditional goto instruction that // isn't the target of a branch itself. byte opcode = branchInstruction.opcode; if ((opcode == InstructionConstants.OP_GOTO || opcode == InstructionConstants.OP_GOTO_W) && !branchTargetFinder.isBranchTarget(offset)) { int branchOffset = branchInstruction.branchOffset; int targetOffset = offset + branchOffset; // Get the number of common bytes. int commonCount = commonByteCodeCount(codeAttribute, offset, targetOffset); if (commonCount > 0 && !exceptionBoundary(codeAttribute, offset, targetOffset)) { if (DEBUG) { System.out.println("GotoCommonCodeReplacer: "+clazz.getName()+"."+method.getName(clazz)+" (["+(offset-commonCount)+"] - "+branchInstruction.toString(offset)+" -> "+targetOffset+")"); } // Delete the common instructions. for (int delta = 0; delta <= commonCount; delta++) { int deleteOffset = offset - delta; if (branchTargetFinder.isInstruction(deleteOffset)) { codeAttributeEditor.replaceInstruction( deleteOffset, (Instruction)null); codeAttributeEditor.insertBeforeInstruction(deleteOffset, (Instruction)null); codeAttributeEditor.insertAfterInstruction( deleteOffset, (Instruction)null); codeAttributeEditor.deleteInstruction(deleteOffset); } } // Redirect the goto instruction, if it is still necessary. int newBranchOffset = branchOffset - commonCount; if (newBranchOffset != branchInstruction.length(offset)) { Instruction newGotoInstruction = new BranchInstruction(opcode, newBranchOffset); codeAttributeEditor.replaceInstruction(offset, newGotoInstruction); } // Visit the instruction, if required. if (extraInstructionVisitor != null) { extraInstructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction); } } } } // Small utility methods. /** * Returns the number of common bytes preceding the given offsets, * avoiding branches and exception blocks. */ private int commonByteCodeCount(CodeAttribute codeAttribute, int offset1, int offset2) { // Find the block of common instructions preceding it. byte[] code = codeAttribute.code; int successfulDelta = 0; for (int delta = 1; delta <= offset1 && delta <= offset2 && offset2 - delta != offset1; delta++) { int newOffset1 = offset1 - delta; int newOffset2 = offset2 - delta; // Is the code identical at both offsets? if (code[newOffset1] != code[newOffset2]) { break; } // Are there instructions at either offset but not both? if (branchTargetFinder.isInstruction(newOffset1) ^ branchTargetFinder.isInstruction(newOffset2)) { break; } // Are there instructions at both offsets? if (branchTargetFinder.isInstruction(newOffset1) && branchTargetFinder.isInstruction(newOffset2)) { // Are the offsets involved in some branches? // Note that the preverifier doesn't like initializer // invocations to be moved around. // Also note that the preverifier doesn't like pop instructions // that work on different operands. if (branchTargetFinder.isBranchOrigin(newOffset1) || branchTargetFinder.isBranchTarget(newOffset1) || branchTargetFinder.isExceptionStart(newOffset1) || branchTargetFinder.isExceptionEnd(newOffset1) || branchTargetFinder.isInitializer(newOffset1) || branchTargetFinder.isExceptionStart(newOffset2) || branchTargetFinder.isExceptionEnd(newOffset2) || isPop(code[newOffset1])) { break; } // Make sure the new branch target was a branch target before, // in order not to introduce new entries in the stack map table. if (branchTargetFinder.isBranchTarget(newOffset2)) { successfulDelta = delta; } if (branchTargetFinder.isBranchTarget(newOffset1)) { break; } } } return successfulDelta; } /** * Returns whether the given opcode represents a pop instruction that must * get a consistent type (pop, pop2, arraylength). */ private boolean isPop(byte opcode) { return opcode == InstructionConstants.OP_POP || opcode == InstructionConstants.OP_POP2 || opcode == InstructionConstants.OP_ARRAYLENGTH; } /** * Returns the whether there is a boundary of an exception block between * the given offsets (including both). */ private boolean exceptionBoundary(CodeAttribute codeAttribute, int offset1, int offset2) { // Swap the offsets if the second one is smaller than the first one. if (offset2 < offset1) { int offset = offset1; offset1 = offset2; offset2 = offset; } // Check if there is a boundary of an exception block. for (int offset = offset1; offset <= offset2; offset++) { if (branchTargetFinder.isExceptionStart(offset) || branchTargetFinder.isExceptionEnd(offset)) { return true; } } return false; } } proguard4.8/src/proguard/optimize/peephole/ClassMerger.java0000664000175000017500000005701111740565346022727 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeNameFilter; import proguard.classfile.constant.ClassConstant; import proguard.classfile.constant.visitor.*; import proguard.classfile.editor.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.optimize.KeepMarker; import proguard.optimize.info.*; import proguard.util.*; import java.util.*; /** * This ClassVisitor inlines the classes that it visits in a given target class, * whenever possible. * * @see RetargetedInnerClassAttributeRemover * @see TargetClassChanger * @see ClassReferenceFixer * @see MemberReferenceFixer * @see AccessFixer * @author Eric Lafortune */ public class ClassMerger extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final ProgramClass targetClass; private final boolean allowAccessModification; private final boolean mergeInterfacesAggressively; private final ClassVisitor extraClassVisitor; private final MemberVisitor fieldOptimizationInfoCopier = new FieldOptimizationInfoCopier(); /** * Creates a new ClassMerger that will merge classes into the given target * class. * @param targetClass the class into which all visited * classes will be merged. * @param allowAccessModification specifies whether the access modifiers * of classes can be changed in order to * merge them. * @param mergeInterfacesAggressively specifies whether interfaces may * be merged aggressively. */ public ClassMerger(ProgramClass targetClass, boolean allowAccessModification, boolean mergeInterfacesAggressively) { this(targetClass, allowAccessModification, mergeInterfacesAggressively, null); } /** * Creates a new ClassMerger that will merge classes into the given target * class. * @param targetClass the class into which all visited * classes will be merged. * @param allowAccessModification specifies whether the access modifiers * of classes can be changed in order to * merge them. * @param mergeInterfacesAggressively specifies whether interfaces may * be merged aggressively. * @param extraClassVisitor an optional extra visitor for all * merged classes. */ public ClassMerger(ProgramClass targetClass, boolean allowAccessModification, boolean mergeInterfacesAggressively, ClassVisitor extraClassVisitor) { this.targetClass = targetClass; this.allowAccessModification = allowAccessModification; this.mergeInterfacesAggressively = mergeInterfacesAggressively; this.extraClassVisitor = extraClassVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { //final String CLASS_NAME = "abc/Def"; //DEBUG = programClass.getName().equals(CLASS_NAME) || // targetClass.getName().equals(CLASS_NAME); // TODO: Remove this when the class merger has stabilized. // Catch any unexpected exceptions from the actual visiting method. try { visitProgramClass0(programClass); } catch (RuntimeException ex) { System.err.println("Unexpected error while merging classes:"); System.err.println(" Class = ["+programClass.getName()+"]"); System.err.println(" Target class = ["+targetClass.getName()+"]"); System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); if (DEBUG) { programClass.accept(new ClassPrinter()); targetClass.accept(new ClassPrinter()); } throw ex; } } public void visitProgramClass0(ProgramClass programClass) { if (!programClass.equals(targetClass) && // Don't merge classes that must be preserved. !KeepMarker.isKept(programClass) && !KeepMarker.isKept(targetClass) && // Only merge classes that haven't been retargeted yet. getTargetClass(programClass) == null && getTargetClass(targetClass) == null && // Don't merge annotation classes, with all their introspection and // infinite recursion. (programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_ANNOTATTION) == 0 && // Only merge classes if we can change the access permissions, or // if they are in the same package, or // if they are public and don't contain or invoke package visible // class members. (allowAccessModification || ((programClass.getAccessFlags() & targetClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_PUBLIC) != 0 && !PackageVisibleMemberContainingClassMarker.containsPackageVisibleMembers(programClass) && !PackageVisibleMemberInvokingClassMarker.invokesPackageVisibleMembers(programClass)) || ClassUtil.internalPackageName(programClass.getName()).equals( ClassUtil.internalPackageName(targetClass.getName()))) && // Only merge two classes or two interfaces or two abstract classes, // or a class into an interface with a single implementation. ((programClass.getAccessFlags() & (ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) == (targetClass.getAccessFlags() & (ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) || (isOnlySubClass(programClass, targetClass) && (programClass.getSuperClass().equals(targetClass) || programClass.getSuperClass().equals(targetClass.getSuperClass())))) && // One class must not implement the other class indirectly. !indirectlyImplementedInterfaces(programClass).contains(targetClass) && !targetClass.extendsOrImplements(programClass) && // The two classes must have the same superclasses and interfaces // with static initializers. initializedSuperClasses(programClass).equals(initializedSuperClasses(targetClass)) && // The two classes must have the same superclasses and interfaces // that are tested with 'instanceof'. instanceofedSuperClasses(programClass).equals(instanceofedSuperClasses(targetClass)) && // The two classes must have the same superclasses that are caught // as exceptions. caughtSuperClasses(programClass).equals(caughtSuperClasses(targetClass)) && // The two classes must not both be part of a .class construct. !(DotClassMarker.isDotClassed(programClass) && DotClassMarker.isDotClassed(targetClass)) && // The two classes must not introduce any unwanted fields. !introducesUnwantedFields(programClass, targetClass) && !introducesUnwantedFields(targetClass, programClass) && // The classes must not have clashing constructors. !haveAnyIdenticalInitializers(programClass, targetClass) && // The classes must not introduce abstract methods, unless // explicitly allowed. (mergeInterfacesAggressively || (!introducesUnwantedAbstractMethods(programClass, targetClass) && !introducesUnwantedAbstractMethods(targetClass, programClass))) && // The classes must not override each others concrete methods. !overridesAnyMethods(programClass, targetClass) && !overridesAnyMethods(targetClass, programClass) && // The classes must not shadow each others non-private methods. !shadowsAnyMethods(programClass, targetClass) && !shadowsAnyMethods(targetClass, programClass)) { if (DEBUG) { System.out.println("ClassMerger ["+programClass.getName()+"] -> ["+targetClass.getName()+"]"); System.out.println(" Source interface? ["+((programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE)!=0)+"]"); System.out.println(" Target interface? ["+((targetClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE)!=0)+"]"); System.out.println(" Source subclasses ["+programClass.subClasses+"]"); System.out.println(" Target subclasses ["+targetClass.subClasses+"]"); System.out.println(" Source superclass ["+programClass.getSuperClass().getName()+"]"); System.out.println(" Target superclass ["+targetClass.getSuperClass().getName()+"]"); } // Combine the access flags. int targetAccessFlags = targetClass.getAccessFlags(); int sourceAccessFlags = programClass.getAccessFlags(); targetClass.u2accessFlags = ((targetAccessFlags & sourceAccessFlags) & (ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) | ((targetAccessFlags | sourceAccessFlags) & (ClassConstants.INTERNAL_ACC_PUBLIC | ClassConstants.INTERNAL_ACC_SUPER | ClassConstants.INTERNAL_ACC_ANNOTATTION | ClassConstants.INTERNAL_ACC_ENUM)); // Copy over the superclass, unless it's the target class itself. //if (!targetClass.getName().equals(programClass.getSuperName())) //{ // targetClass.u2superClass = // new ConstantAdder(targetClass).addConstant(programClass, programClass.u2superClass); //} // Copy over the interfaces that aren't present yet and that // wouldn't cause loops in the class hierarchy. programClass.interfaceConstantsAccept( new ExceptClassConstantFilter(targetClass.getName(), new ImplementedClassConstantFilter(targetClass, new ImplementingClassConstantFilter(targetClass, new InterfaceAdder(targetClass))))); // Copy over the class members. MemberAdder memberAdder = new MemberAdder(targetClass, fieldOptimizationInfoCopier); programClass.fieldsAccept(memberAdder); programClass.methodsAccept(memberAdder); // Copy over the other attributes. programClass.attributesAccept( new AttributeNameFilter(new NotMatcher(new OrMatcher(new OrMatcher( new FixedStringMatcher(ClassConstants.ATTR_SourceFile), new FixedStringMatcher(ClassConstants.ATTR_InnerClasses)), new FixedStringMatcher(ClassConstants.ATTR_EnclosingMethod))), new AttributeAdder(targetClass, true))); // Update the optimization information of the target class. ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(targetClass); if (info != null) { info.merge(ClassOptimizationInfo.getClassOptimizationInfo(programClass)); } // Remember to replace the inlined class by the target class. setTargetClass(programClass, targetClass); // Visit the merged class, if required. if (extraClassVisitor != null) { extraClassVisitor.visitProgramClass(programClass); } } } // Small utility methods. /** * Returns whether a given class is the only subclass of another given class. */ private boolean isOnlySubClass(Clazz subClass, ProgramClass clazz) { // TODO: The list of subclasses is not up to date. return clazz.subClasses != null && clazz.subClasses.length == 1 && clazz.subClasses[0].equals(subClass); } /** * Returns the set of indirectly implemented interfaces. */ private Set indirectlyImplementedInterfaces(Clazz clazz) { Set set = new HashSet(); ReferencedClassVisitor referencedInterfaceCollector = new ReferencedClassVisitor( new ClassHierarchyTraveler(false, false, true, false, new ClassCollector(set))); // Visit all superclasses and collect their interfaces. clazz.superClassConstantAccept(referencedInterfaceCollector); // Visit all interfaces and collect their interfaces. clazz.interfaceConstantsAccept(referencedInterfaceCollector); return set; } /** * Returns the set of superclasses and interfaces that are initialized. */ private Set initializedSuperClasses(Clazz clazz) { Set set = new HashSet(); // Visit all superclasses and interfaces, collecting the ones that have // static initializers. clazz.hierarchyAccept(true, true, true, false, new StaticInitializerContainingClassFilter( new ClassCollector(set))); return set; } /** * Returns the set of superclasses and interfaces that are used in * 'instanceof' tests. */ private Set instanceofedSuperClasses(Clazz clazz) { Set set = new HashSet(); // Visit all superclasses and interfaces, collecting the ones that are // used in an 'instanceof' test. clazz.hierarchyAccept(true, true, true, false, new InstanceofClassFilter( new ClassCollector(set))); return set; } /** * Returns the set of superclasses that are caught as exceptions. */ private Set caughtSuperClasses(Clazz clazz) { // Don't bother if this isn't an exception at all. if (!clazz.extends_(ClassConstants.INTERNAL_NAME_JAVA_LANG_THROWABLE)) { return Collections.EMPTY_SET; } // Visit all superclasses, collecting the ones that are caught // (plus java.lang.Object, in the current implementation). Set set = new HashSet(); clazz.hierarchyAccept(true, true, false, false, new CaughtClassFilter( new ClassCollector(set))); return set; } /** * Returns whether the given class would introduce any unwanted fields * in the target class. */ private boolean introducesUnwantedFields(ProgramClass programClass, ProgramClass targetClass) { // The class must not have any fields, or it must not be instantiated, // without any other subclasses. return programClass.u2fieldsCount != 0 && (InstantiationClassMarker.isInstantiated(targetClass) || (targetClass.subClasses != null && !isOnlySubClass(programClass, targetClass))); } /** * Returns whether the two given classes have initializers with the same * descriptors. */ private boolean haveAnyIdenticalInitializers(Clazz clazz, Clazz targetClass) { MemberCounter counter = new MemberCounter(); // TODO: Currently checking shared methods, not just initializers. // TODO: Allow identical methods. // Visit all methods, counting the ones that are also present in the // target class. clazz.methodsAccept(//new MemberNameFilter(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT), new SimilarMemberVisitor(targetClass, true, false, false, false, new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT, counter))); return counter.getCount() > 0; } /** * Returns whether the given class would introduce any abstract methods * in the target class. */ private boolean introducesUnwantedAbstractMethods(Clazz clazz, ProgramClass targetClass) { // It's ok if the target class is already abstract and it has at most // the class as a subclass. if ((targetClass.getAccessFlags() & (ClassConstants.INTERNAL_ACC_ABSTRACT | ClassConstants.INTERNAL_ACC_INTERFACE)) != 0 && (targetClass.subClasses == null || isOnlySubClass(clazz, targetClass))) { return false; } MemberCounter counter = new MemberCounter(); Set targetSet = new HashSet(); // Collect all abstract methods, and similar abstract methods in the // class hierarchy of the target class. clazz.methodsAccept(new MemberAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0, new MultiMemberVisitor(new MemberVisitor[] { counter, new SimilarMemberVisitor(targetClass, true, true, true, false, new MemberAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0, new MemberCollector(targetSet))) }))); return targetSet.size() < counter.getCount(); } /** * Returns whether the given class overrides any methods in the given * target class. */ private boolean overridesAnyMethods(Clazz clazz, Clazz targetClass) { MemberCounter counter = new MemberCounter(); // Visit all non-private non-static methods, counting the ones that are // being overridden in the class hierarchy of the target class. clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT, new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)), new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT)), new SimilarMemberVisitor(targetClass, true, true, false, false, new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT, counter)))))); return counter.getCount() > 0; } /** * Returns whether the given class or its subclasses shadow any methods in * the given target class. */ private boolean shadowsAnyMethods(Clazz clazz, Clazz targetClass) { MemberCounter counter = new MemberCounter(); // Visit all private methods, counting the ones that are shadowing // non-private methods in the class hierarchy of the target class. clazz.hierarchyAccept(true, false, false, true, new AllMethodVisitor( new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT)), new SimilarMemberVisitor(targetClass, true, true, true, false, new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, counter)))))); // Visit all static methods, counting the ones that are shadowing // non-private methods in the class hierarchy of the target class. clazz.hierarchyAccept(true, false, false, true, new AllMethodVisitor( new MemberAccessFilter(ClassConstants.INTERNAL_ACC_STATIC, 0, new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)), new SimilarMemberVisitor(targetClass, true, true, true, false, new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, counter)))))); return counter.getCount() > 0; } public static void setTargetClass(Clazz clazz, Clazz targetClass) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info != null) { info.setTargetClass(targetClass); } } public static Clazz getTargetClass(Clazz clazz) { Clazz targetClass = null; // Return the last target class, if any. while (true) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info == null) { return targetClass; } clazz = info.getTargetClass(); if (clazz == null) { return targetClass; } targetClass = clazz; } } /** * This MemberVisitor copies field optimization info from copied fields. */ private static class FieldOptimizationInfoCopier extends SimplifiedVisitor implements MemberVisitor { public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Copy the optimization info from the field that was just copied. ProgramField copiedField = (ProgramField)programField.getVisitorInfo(); Object info = copiedField.getVisitorInfo(); programField.setVisitorInfo(info instanceof FieldOptimizationInfo ? new FieldOptimizationInfo((FieldOptimizationInfo)info) : info); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Linked methods share their optimization info. } } }proguard4.8/src/proguard/optimize/peephole/UnreachableExceptionRemover.java0000644000175000017500000001256611736333525026151 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.optimize.info.ExceptionInstructionChecker; /** * This AttributeVisitor removes exception handlers that are unreachable in the * code attributes that it visits. * * @author Eric Lafortune */ public class UnreachableExceptionRemover extends SimplifiedVisitor implements AttributeVisitor, ExceptionInfoVisitor { private final ExceptionInfoVisitor extraExceptionInfoVisitor; private final ExceptionInstructionChecker exceptionInstructionChecker = new ExceptionInstructionChecker(); /** * Creates a new UnreachableExceptionRemover. */ public UnreachableExceptionRemover() { this(null); } /** * Creates a new UnreachableExceptionRemover. * @param extraExceptionInfoVisitor an optional extra visitor for all * removed exceptions. */ public UnreachableExceptionRemover(ExceptionInfoVisitor extraExceptionInfoVisitor) { this.extraExceptionInfoVisitor = extraExceptionInfoVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Go over the exception table. codeAttribute.exceptionsAccept(clazz, method, this); // Remove exceptions with empty code blocks. codeAttribute.u2exceptionTableLength = removeEmptyExceptions(codeAttribute.exceptionTable, codeAttribute.u2exceptionTableLength); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { if (!mayThrowExceptions(clazz, method, codeAttribute, exceptionInfo.u2startPC, exceptionInfo.u2endPC)) { // Make the code block empty. exceptionInfo.u2endPC = exceptionInfo.u2startPC; if (extraExceptionInfoVisitor != null) { extraExceptionInfoVisitor.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo); } } } // Small utility methods. /** * Returns whether the specified block of code may throw exceptions. */ private boolean mayThrowExceptions(Clazz clazz, Method method, CodeAttribute codeAttribute, int startOffset, int endOffset) { byte[] code = codeAttribute.code; // Go over all instructions. int offset = startOffset; while (offset < endOffset) { // Get the current instruction. Instruction instruction = InstructionFactory.create(code, offset); // Check if it may be throwing exceptions. if (exceptionInstructionChecker.mayThrowExceptions(clazz, method, codeAttribute, offset, instruction)) { return true; } // Go to the next instruction. offset += instruction.length(offset); } return false; } /** * Returns the given list of exceptions, without the ones that have empty * code blocks. */ private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos, int exceptionInfoCount) { // Overwrite all empty exceptions. int newIndex = 0; for (int index = 0; index < exceptionInfoCount; index++) { ExceptionInfo exceptionInfo = exceptionInfos[index]; if (exceptionInfo.u2startPC < exceptionInfo.u2endPC) { exceptionInfos[newIndex++] = exceptionInfo; } } return newIndex; } } proguard4.8/src/proguard/optimize/peephole/MemberPrivatizer.java0000644000175000017500000000651311736333525024003 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.peephole; import proguard.classfile.*; import proguard.classfile.editor.MethodInvocationFixer; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.info.NonPrivateMemberMarker; /** * This MemberVisitor makes all class members that it visits private, unless * they have been marked by a NonPrivateMemberMarker. The invocations of * privatized methods still have to be fixed. * * @see NonPrivateMemberMarker * @see MethodInvocationFixer * @author Eric Lafortune */ public class MemberPrivatizer extends SimplifiedVisitor implements MemberVisitor { private final MemberVisitor extraMemberVisitor; /** * Creates a new MemberPrivatizer. */ public MemberPrivatizer() { this(null); } /** * Creates a new MemberPrivatizer. * @param extraMemberVisitor an optional extra visitor for all privatized * class members. */ public MemberPrivatizer(MemberVisitor extraMemberVisitor) { this.extraMemberVisitor = extraMemberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Is the field unmarked? if (NonPrivateMemberMarker.canBeMadePrivate(programField)) { // Make the field private. programField.u2accessFlags = AccessUtil.replaceAccessFlags(programField.u2accessFlags, ClassConstants.INTERNAL_ACC_PRIVATE); // Visit the field, if required. if (extraMemberVisitor != null) { extraMemberVisitor.visitProgramField(programClass, programField); } } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Is the method unmarked? if (NonPrivateMemberMarker.canBeMadePrivate(programMethod)) { // Make the method private. programMethod.u2accessFlags = AccessUtil.replaceAccessFlags(programMethod.u2accessFlags, ClassConstants.INTERNAL_ACC_PRIVATE); // Visit the method, if required. if (extraMemberVisitor != null) { extraMemberVisitor.visitProgramMethod(programClass, programMethod); } } } } proguard4.8/src/proguard/optimize/TailRecursionSimplifier.java0000644000175000017500000003211711736333525023521 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.MethodrefConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.CodeAttributeComposer; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; /** * This MemberVisitor simplifies tail recursion calls in all methods that it * visits. * * @author Eric Lafortune */ public class TailRecursionSimplifier extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ConstantVisitor, ExceptionInfoVisitor { //* private static final boolean DEBUG = false; /*/ private static boolean DEBUG = true; //*/ private final InstructionVisitor extraTailRecursionVisitor; private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(); private final MyRecursionChecker recursionChecker = new MyRecursionChecker(); private Method targetMethod; private boolean inlinedAny; /** * Creates a new TailRecursionSimplifier. */ public TailRecursionSimplifier() { this(null); } /** * Creates a new TailRecursionSimplifier with an extra visitor. * @param extraTailRecursionVisitor an optional extra visitor for all * simplified tail recursions. */ public TailRecursionSimplifier(InstructionVisitor extraTailRecursionVisitor) { this.extraTailRecursionVisitor = extraTailRecursionVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { int accessFlags = method.getAccessFlags(); if (// Only check the method if it is private, static, or final. (accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_FINAL)) != 0 && // Only check the method if it is not synchronized, etc. (accessFlags & (ClassConstants.INTERNAL_ACC_SYNCHRONIZED | ClassConstants.INTERNAL_ACC_NATIVE | ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0) { // codeAttributeComposer.DEBUG = DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); targetMethod = method; inlinedAny = false; codeAttributeComposer.reset(); // The code may expand, due to expanding constant and variable // instructions. codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); // Copy the instructions. codeAttribute.instructionsAccept(clazz, method, this); // Update the code attribute if any code has been inlined. if (inlinedAny) { // Copy the exceptions. codeAttribute.exceptionsAccept(clazz, method, this); // Append a label just after the code. codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); codeAttributeComposer.endCodeFragment(); codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute); } } } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { // Copy the instruction. codeAttributeComposer.appendInstruction(offset, instruction.shrink()); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Is it a method invocation? switch (constantInstruction.opcode) { case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: { // Is it a recursive call? clazz.constantPoolEntryAccept(constantInstruction.constantIndex, recursionChecker); if (recursionChecker.isRecursive()) { // Is the next instruction a return? int nextOffset = offset + constantInstruction.length(offset); Instruction nextInstruction = InstructionFactory.create(codeAttribute.code, nextOffset); switch (nextInstruction.opcode) { case InstructionConstants.OP_IRETURN: case InstructionConstants.OP_LRETURN: case InstructionConstants.OP_FRETURN: case InstructionConstants.OP_DRETURN: case InstructionConstants.OP_ARETURN: case InstructionConstants.OP_RETURN: { // Isn't the recursive call inside a try/catch block? codeAttribute.exceptionsAccept(clazz, method, offset, recursionChecker); if (recursionChecker.isRecursive()) { if (DEBUG) { System.out.println("TailRecursionSimplifier: ["+ clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"], inlining "+constantInstruction.toString(offset)); } // Append a label. codeAttributeComposer.appendLabel(offset); storeParameters(clazz, method); // Branch back to the start of the method. int gotoOffset = offset + 1; codeAttributeComposer.appendInstruction(gotoOffset, new BranchInstruction(InstructionConstants.OP_GOTO, -gotoOffset)); // The original return instruction will be // removed elsewhere, if possible. // Remember that the code has changed. inlinedAny = true; if (extraTailRecursionVisitor != null) { extraTailRecursionVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, constantInstruction); } // The invocation itself is no longer necessary. return; } } } } break; } } // Copy the instruction. codeAttributeComposer.appendInstruction(offset, constantInstruction.shrink()); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { codeAttributeComposer.appendException(new ExceptionInfo(exceptionInfo.u2startPC, exceptionInfo.u2endPC, exceptionInfo.u2handlerPC, exceptionInfo.u2catchType)); } /** * This ConstantVisitor and ExceptionInfoVisitor returns whether a method * invocation can be treated as tail-recursive. */ private class MyRecursionChecker extends SimplifiedVisitor implements ConstantVisitor, ExceptionInfoVisitor { private boolean recursive; /** * Returns whether the method invocation can be treated as * tail-recursive. */ public boolean isRecursive() { return recursive; } // Implementations for ConstantVisitor. public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { recursive = targetMethod.equals(methodrefConstant.referencedMember); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { recursive = false; } } // Small utility methods. /** * Appends instructions to pop the parameters for the given method, storing * them in new local variables. */ private void storeParameters(Clazz clazz, Method method) { String descriptor = method.getDescriptor(clazz); boolean isStatic = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0; // Count the number of parameters, taking into account their categories. int parameterSize = ClassUtil.internalMethodParameterSize(descriptor); int parameterOffset = isStatic ? 0 : 1; // Store the parameter types. String[] parameterTypes = new String[parameterSize]; InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); for (int parameterIndex = 0; parameterIndex < parameterSize; parameterIndex++) { String parameterType = internalTypeEnumeration.nextType(); parameterTypes[parameterIndex] = parameterType; if (ClassUtil.internalTypeSize(parameterType) == 2) { parameterIndex++; } } codeAttributeComposer.beginCodeFragment(parameterSize + 1); // Go over the parameter types backward, storing the stack entries // in their corresponding variables. for (int parameterIndex = parameterSize-1; parameterIndex >= 0; parameterIndex--) { String parameterType = parameterTypes[parameterIndex]; if (parameterType != null) { byte opcode; switch (parameterType.charAt(0)) { case ClassConstants.INTERNAL_TYPE_BOOLEAN: case ClassConstants.INTERNAL_TYPE_BYTE: case ClassConstants.INTERNAL_TYPE_CHAR: case ClassConstants.INTERNAL_TYPE_SHORT: case ClassConstants.INTERNAL_TYPE_INT: opcode = InstructionConstants.OP_ISTORE; break; case ClassConstants.INTERNAL_TYPE_LONG: opcode = InstructionConstants.OP_LSTORE; break; case ClassConstants.INTERNAL_TYPE_FLOAT: opcode = InstructionConstants.OP_FSTORE; break; case ClassConstants.INTERNAL_TYPE_DOUBLE: opcode = InstructionConstants.OP_DSTORE; break; default: opcode = InstructionConstants.OP_ASTORE; break; } codeAttributeComposer.appendInstruction(parameterSize-parameterIndex-1, new VariableInstruction(opcode, parameterOffset + parameterIndex).shrink()); } } // Put the 'this' reference in variable 0. if (!isStatic) { codeAttributeComposer.appendInstruction(parameterSize, new VariableInstruction(InstructionConstants.OP_ASTORE, 0).shrink()); } codeAttributeComposer.endCodeFragment(); } }proguard4.8/src/proguard/optimize/KeptMemberFilter.java0000644000175000017500000000506111736333525022111 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.visitor.MemberVisitor; /** * This MemberVisitor delegates all its method calls to another MemberVisitor, * but only for Member objects that are marked as kept. * * @see KeepMarker * * @author Eric Lafortune */ public class KeptMemberFilter implements MemberVisitor { private final MemberVisitor memberVisitor; /** * Creates a new KeptMemberFilter. * @param memberVisitor the member visitor to which the visiting will be * delegated. */ public KeptMemberFilter(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (KeepMarker.isKept(programField)) { memberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (KeepMarker.isKept(programMethod)) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { if (KeepMarker.isKept(libraryField)) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { if (KeepMarker.isKept(libraryMethod)) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } }proguard4.8/src/proguard/optimize/MemberDescriptorSpecializer.java0000644000175000017500000001222111736333525024345 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.editor.ClassReferenceFixer; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.evaluation.value.Value; import proguard.optimize.evaluation.StoringInvocationUnit; /** * This MemberVisitor specializes parameters in the descriptors of the * methods that it visits. * * @see StoringInvocationUnit * @see ClassReferenceFixer * @author Eric Lafortune */ public class MemberDescriptorSpecializer extends SimplifiedVisitor implements MemberVisitor { private static final boolean DEBUG = false; private final MemberVisitor extraParameterMemberVisitor; /** * Creates a new MethodDescriptorShrinker. */ public MemberDescriptorSpecializer() { this(null); } /** * Creates a new MethodDescriptorShrinker with an extra visitor. * @param extraParameterMemberVisitor an optional extra visitor for all * class members whose parameters have * been specialized. */ public MemberDescriptorSpecializer(MemberVisitor extraParameterMemberVisitor) { this.extraParameterMemberVisitor = extraParameterMemberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { Value parameterValue = StoringInvocationUnit.getFieldValue(programField); if (parameterValue.computationalType() == Value.TYPE_REFERENCE) { Clazz referencedClass = parameterValue.referenceValue().getReferencedClass(); if (programField.referencedClass != referencedClass) { if (DEBUG) { System.out.println("MemberDescriptorSpecializer: "+programClass.getName()+"."+programField.getName(programClass)+" "+programField.getDescriptor(programClass)); System.out.println(" "+programField.referencedClass.getName()+" -> "+referencedClass.getName()); } programField.referencedClass = referencedClass; // Visit the field, if required. if (extraParameterMemberVisitor != null) { extraParameterMemberVisitor.visitProgramField(programClass, programField); } } } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // All parameters of non-static methods are shifted by one in the local // variable frame. int firstParameterIndex = (programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 0 : 1; int parameterCount = ClassUtil.internalMethodParameterCount(programMethod.getDescriptor(programClass)); int classIndex = 0; // Go over the parameters. for (int parameterIndex = firstParameterIndex; parameterIndex < parameterCount; parameterIndex++) { Value parameterValue = StoringInvocationUnit.getMethodParameterValue(programMethod, parameterIndex); if (parameterValue.computationalType() == Value.TYPE_REFERENCE) { Clazz referencedClass = parameterValue.referenceValue().getReferencedClass(); if (programMethod.referencedClasses[classIndex] != referencedClass) { if (DEBUG) { System.out.println("MemberDescriptorSpecializer: "+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)); System.out.println(" "+programMethod.referencedClasses[classIndex].getName()+" -> "+referencedClass.getName()); } programMethod.referencedClasses[classIndex] = referencedClass; // Visit the method, if required. if (extraParameterMemberVisitor != null) { extraParameterMemberVisitor.visitProgramMethod(programClass, programMethod); } } classIndex++; } } } } proguard4.8/src/proguard/optimize/WriteOnlyFieldFilter.java0000644000175000017500000000430511736333525022756 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.info.ReadWriteFieldMarker; /** * This MemberVisitor delegates its visits to program fields to * other given MemberVisitor instances, but only when the visited * field has been marked as write-only. * * @see ReadWriteFieldMarker * @author Eric Lafortune */ public class WriteOnlyFieldFilter extends SimplifiedVisitor implements MemberVisitor { private final MemberVisitor writeOnlyFieldVisitor; /** * Creates a new WriteOnlyFieldFilter. * @param writeOnlyFieldVisitor the MemberVisitor to which * visits to write-only fields will be delegated. */ public WriteOnlyFieldFilter(MemberVisitor writeOnlyFieldVisitor) { this.writeOnlyFieldVisitor = writeOnlyFieldVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (ReadWriteFieldMarker.isWritten(programField) && !ReadWriteFieldMarker.isRead(programField)) { writeOnlyFieldVisitor.visitProgramField(programClass, programField); } } } proguard4.8/src/proguard/optimize/OptimizationInfoMemberFilter.java0000644000175000017500000000604211736333525024510 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.info.*; /** * This MemberVisitor delegates its visits to another given * MemberVisitor, but only when the visited member has optimization * info. * * @see FieldOptimizationInfo * @see MethodOptimizationInfo * @author Eric Lafortune */ public class OptimizationInfoMemberFilter implements MemberVisitor { private final MemberVisitor memberVisitor; /** * Creates a new OptimizationInfoMemberFilter. * @param memberVisitor the MemberVisitor to which visits will * be delegated. */ public OptimizationInfoMemberFilter(MemberVisitor memberVisitor) { this.memberVisitor = memberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Does the field have optimization info? if (FieldOptimizationInfo.getFieldOptimizationInfo(programField) != null) { memberVisitor.visitProgramField(programClass, programField); } } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { // Does the field have optimization info? if (FieldOptimizationInfo.getFieldOptimizationInfo(libraryField) != null) { memberVisitor.visitLibraryField(libraryClass, libraryField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Does the method have optimization info? if (MethodOptimizationInfo.getMethodOptimizationInfo(programMethod) != null) { memberVisitor.visitProgramMethod(programClass, programMethod); } } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { // Does the method have optimization info? if (MethodOptimizationInfo.getMethodOptimizationInfo(libraryMethod) != null) { memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); } } } proguard4.8/src/proguard/optimize/KeepMarker.java0000664000175000017500000000575711736333526020755 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.util.MethodLinker; import proguard.classfile.visitor.*; import proguard.optimize.info.NoSideEffectMethodMarker; /** * This ClassVisitor and MemberVisitor * marks classes and class members it visits. The marked elements * will remain unchanged as necessary in the optimization step. * * @see NoSideEffectMethodMarker * @author Eric Lafortune */ public class KeepMarker implements ClassVisitor, MemberVisitor { // A visitor info flag to indicate the visitor accepter is being kept. private static final Object KEPT = new Object(); // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { markAsKept(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { markAsKept(libraryClass); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { markAsKept(programField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { markAsKept(MethodLinker.lastMember(programMethod)); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { markAsKept(libraryField); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { markAsKept(MethodLinker.lastMember(libraryMethod)); } // Small utility methods. private static void markAsKept(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(KEPT); } public static boolean isKept(VisitorAccepter visitorAccepter) { // We're also checking for the constant in NoSideEffectMethodMarker, // to keep things simple. Object visitorInfo = MethodLinker.lastVisitorAccepter(visitorAccepter).getVisitorInfo(); return visitorInfo == KEPT || visitorInfo == NoSideEffectMethodMarker.KEPT_BUT_NO_SIDE_EFFECTS; } } proguard4.8/src/proguard/optimize/ConstantMemberFilter.java0000644000175000017500000000515511736333526023004 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; import proguard.evaluation.value.Value; import proguard.optimize.evaluation.StoringInvocationUnit; /** * This MemberVisitor delegates its visits to program class members * to another given MemberVisitor, but only when the visited * class member has been marked as a constant. * * @see StoringInvocationUnit * @author Eric Lafortune */ public class ConstantMemberFilter extends SimplifiedVisitor implements MemberVisitor { private final MemberVisitor constantMemberVisitor; /** * Creates a new ConstantMemberFilter. * @param constantMemberVisitor the MemberVisitor to which * visits to constant members will be delegated. */ public ConstantMemberFilter(MemberVisitor constantMemberVisitor) { this.constantMemberVisitor = constantMemberVisitor; } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { Value value = StoringInvocationUnit.getFieldValue(programField); if (value != null && value.isParticular()) { constantMemberVisitor.visitProgramField(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { Value value = StoringInvocationUnit.getMethodReturnValue(programMethod); if (value != null && value.isParticular()) { constantMemberVisitor.visitProgramMethod(programClass, programMethod); } } } proguard4.8/src/proguard/optimize/MethodDescriptorShrinker.java0000644000175000017500000002645611736333526023711 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.editor.ConstantPoolEditor; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.info.*; import proguard.optimize.peephole.VariableShrinker; /** * This MemberVisitor removes unused parameters in the descriptors of the * methods that it visits. * * @see ParameterUsageMarker * @see VariableUsageMarker * @see VariableShrinker * @author Eric Lafortune */ public class MethodDescriptorShrinker extends SimplifiedVisitor implements MemberVisitor, AttributeVisitor { private static final boolean DEBUG = false; private final MemberVisitor extraMemberVisitor; /** * Creates a new MethodDescriptorShrinker. */ public MethodDescriptorShrinker() { this(null); } /** * Creates a new MethodDescriptorShrinker with an extra visitor. * @param extraMemberVisitor an optional extra visitor for all methods whose * parameters have been simplified. */ public MethodDescriptorShrinker(MemberVisitor extraMemberVisitor) { this.extraMemberVisitor = extraMemberVisitor; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Update the descriptor if it has any unused parameters. String descriptor = programMethod.getDescriptor(programClass); String newDescriptor = shrinkDescriptor(programMethod, descriptor); if (!descriptor.equals(newDescriptor)) { // Shrink the signature and parameter annotations. programMethod.attributesAccept(programClass, this); String name = programMethod.getName(programClass); String newName = name; // Append a code, if the method isn't a class instance initializer. if (!name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { newName += ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode())); } if (DEBUG) { System.out.println("MethodDescriptorShrinker:"); System.out.println(" ["+programClass.getName()+"."+ name+descriptor+"] -> ["+ newName+newDescriptor+"]"); } ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor(programClass); // Update the name, if necessary. if (!newName.equals(name)) { programMethod.u2nameIndex = constantPoolEditor.addUtf8Constant(newName); } // Update the referenced classes. programMethod.referencedClasses = shrinkReferencedClasses(programMethod, descriptor, programMethod.referencedClasses); // Finally, update the descriptor itself. programMethod.u2descriptorIndex = constantPoolEditor.addUtf8Constant(newDescriptor); // Visit the method, if required. if (extraMemberVisitor != null) { extraMemberVisitor.visitProgramMethod(programClass, programMethod); } } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute) { // Compute the new signature. String signature = clazz.getString(signatureAttribute.u2signatureIndex); String newSignature = shrinkDescriptor(method, signature); // Update the signature. signatureAttribute.u2signatureIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature); // Update the referenced classes. signatureAttribute.referencedClasses = shrinkReferencedClasses(method, signature, signatureAttribute.referencedClasses); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { int[] annotationsCounts = parameterAnnotationsAttribute.u2parameterAnnotationsCount; Annotation[][] annotations = parameterAnnotationsAttribute.parameterAnnotations; // All parameters of non-static methods are shifted by one in the local // variable frame. int parameterIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 0 : 1; int annotationIndex = 0; int newAnnotationIndex = 0; // Go over the parameters. String descriptor = method.getDescriptor(clazz); InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); while (internalTypeEnumeration.hasMoreTypes()) { String type = internalTypeEnumeration.nextType(); if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) { annotationsCounts[newAnnotationIndex] = annotationsCounts[annotationIndex]; annotations[newAnnotationIndex++] = annotations[annotationIndex]; } annotationIndex++; parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; } // Update the number of parameters. parameterAnnotationsAttribute.u2parametersCount = newAnnotationIndex; // Clear the unused entries. while (newAnnotationIndex < annotationIndex) { annotationsCounts[newAnnotationIndex] = 0; annotations[newAnnotationIndex++] = null; } } // Small utility methods. /** * Returns a shrunk descriptor or signature of the given method. */ private String shrinkDescriptor(Method method, String descriptor) { // All parameters of non-static methods are shifted by one in the local // variable frame. int parameterIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 0 : 1; // Go over the parameters. InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); StringBuffer newDescriptorBuffer = new StringBuffer(); newDescriptorBuffer.append(internalTypeEnumeration.formalTypeParameters()); newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN); while (internalTypeEnumeration.hasMoreTypes()) { String type = internalTypeEnumeration.nextType(); if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) { newDescriptorBuffer.append(type); } else if (DEBUG) { System.out.println(" Deleting parameter #"+parameterIndex+" ["+type+"]"); } parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; } newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); newDescriptorBuffer.append(internalTypeEnumeration.returnType()); return newDescriptorBuffer.toString(); } /** * Shrinks the array of referenced classes of the given method. */ private Clazz[] shrinkReferencedClasses(Method method, String descriptor, Clazz[] referencedClasses) { if (referencedClasses != null) { // All parameters of non-static methods are shifted by one in the local // variable frame. int parameterIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 0 : 1; int referencedClassIndex = 0; int newReferencedClassIndex = 0; // Go over the parameters. InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration(descriptor); // Also look at the formal type parameters. String type = internalTypeEnumeration.formalTypeParameters(); int count = new DescriptorClassEnumeration(type).classCount(); for (int counter = 0; counter < count; counter++) { referencedClasses[newReferencedClassIndex++] = referencedClasses[referencedClassIndex++]; } while (internalTypeEnumeration.hasMoreTypes()) { // Consider the classes referenced by this parameter type. type = internalTypeEnumeration.nextType(); count = new DescriptorClassEnumeration(type).classCount(); if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) { // Copy the referenced classes. for (int counter = 0; counter < count; counter++) { referencedClasses[newReferencedClassIndex++] = referencedClasses[referencedClassIndex++]; } } else { // Skip the referenced classes. referencedClassIndex += count; } parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; } // Also look at the return value. type = internalTypeEnumeration.returnType(); count = new DescriptorClassEnumeration(type).classCount(); for (int counter = 0; counter < count; counter++) { referencedClasses[newReferencedClassIndex++] = referencedClasses[referencedClassIndex++]; } // Clear the unused entries. while (newReferencedClassIndex < referencedClassIndex) { referencedClasses[newReferencedClassIndex++] = null; } } return referencedClasses; } } proguard4.8/src/proguard/optimize/Optimizer.java0000664000175000017500000013527511740563716020711 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.*; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.Constant; import proguard.classfile.constant.visitor.*; import proguard.classfile.editor.*; import proguard.classfile.instruction.visitor.*; import proguard.classfile.util.MethodLinker; import proguard.classfile.visitor.*; import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.evaluation.*; import proguard.optimize.info.*; import proguard.optimize.peephole.*; import proguard.util.*; import java.io.IOException; import java.util.*; /** * This class optimizes class pools according to a given configuration. * * @author Eric Lafortune */ public class Optimizer { private static final String CLASS_MARKING_FINAL = "class/marking/final"; private static final String CLASS_MERGING_VERTICAL = "class/merging/vertical"; private static final String CLASS_MERGING_HORIZONTAL = "class/merging/horizontal"; private static final String FIELD_REMOVAL_WRITEONLY = "field/removal/writeonly"; private static final String FIELD_MARKING_PRIVATE = "field/marking/private"; private static final String FIELD_PROPAGATION_VALUE = "field/propagation/value"; private static final String METHOD_MARKING_PRIVATE = "method/marking/private"; private static final String METHOD_MARKING_STATIC = "method/marking/static"; private static final String METHOD_MARKING_FINAL = "method/marking/final"; private static final String METHOD_REMOVAL_PARAMETER = "method/removal/parameter"; private static final String METHOD_PROPAGATION_PARAMETER = "method/propagation/parameter"; private static final String METHOD_PROPAGATION_RETURNVALUE = "method/propagation/returnvalue"; private static final String METHOD_INLINING_SHORT = "method/inlining/short"; private static final String METHOD_INLINING_UNIQUE = "method/inlining/unique"; private static final String METHOD_INLINING_TAILRECURSION = "method/inlining/tailrecursion"; private static final String CODE_MERGING = "code/merging"; private static final String CODE_SIMPLIFICATION_VARIABLE = "code/simplification/variable"; private static final String CODE_SIMPLIFICATION_ARITHMETIC = "code/simplification/arithmetic"; private static final String CODE_SIMPLIFICATION_CAST = "code/simplification/cast"; private static final String CODE_SIMPLIFICATION_FIELD = "code/simplification/field"; private static final String CODE_SIMPLIFICATION_BRANCH = "code/simplification/branch"; private static final String CODE_SIMPLIFICATION_STRING = "code/simplification/string"; private static final String CODE_SIMPLIFICATION_ADVANCED = "code/simplification/advanced"; private static final String CODE_REMOVAL_ADVANCED = "code/removal/advanced"; private static final String CODE_REMOVAL_SIMPLE = "code/removal/simple"; private static final String CODE_REMOVAL_VARIABLE = "code/removal/variable"; private static final String CODE_REMOVAL_EXCEPTION = "code/removal/exception"; private static final String CODE_ALLOCATION_VARIABLE = "code/allocation/variable"; public static final String[] OPTIMIZATION_NAMES = new String[] { CLASS_MARKING_FINAL, CLASS_MERGING_VERTICAL, CLASS_MERGING_HORIZONTAL, FIELD_REMOVAL_WRITEONLY, FIELD_MARKING_PRIVATE, FIELD_PROPAGATION_VALUE, METHOD_MARKING_PRIVATE, METHOD_MARKING_STATIC, METHOD_MARKING_FINAL, METHOD_REMOVAL_PARAMETER, METHOD_PROPAGATION_PARAMETER, METHOD_PROPAGATION_RETURNVALUE, METHOD_INLINING_SHORT, METHOD_INLINING_UNIQUE, METHOD_INLINING_TAILRECURSION, CODE_MERGING, CODE_SIMPLIFICATION_VARIABLE, CODE_SIMPLIFICATION_ARITHMETIC, CODE_SIMPLIFICATION_CAST, CODE_SIMPLIFICATION_FIELD, CODE_SIMPLIFICATION_BRANCH, CODE_SIMPLIFICATION_STRING, CODE_SIMPLIFICATION_ADVANCED, CODE_REMOVAL_ADVANCED, CODE_REMOVAL_SIMPLE, CODE_REMOVAL_VARIABLE, CODE_REMOVAL_EXCEPTION, CODE_ALLOCATION_VARIABLE, }; private final Configuration configuration; /** * Creates a new Optimizer. */ public Optimizer(Configuration configuration) { this.configuration = configuration; } /** * Performs optimization of the given program class pool. */ public boolean execute(ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { // Check if we have at least some keep commands. if (configuration.keep == null && configuration.applyMapping == null && configuration.printMapping == null) { throw new IOException("You have to specify '-keep' options for the optimization step."); } // Create a matcher for filtering optimizations. StringMatcher filter = configuration.optimizations != null ? new ListParser(new NameParser()).parse(configuration.optimizations) : new ConstantMatcher(true); boolean classMarkingFinal = filter.matches(CLASS_MARKING_FINAL); boolean classMergingVertical = filter.matches(CLASS_MERGING_VERTICAL); boolean classMergingHorizontal = filter.matches(CLASS_MERGING_HORIZONTAL); boolean fieldRemovalWriteonly = filter.matches(FIELD_REMOVAL_WRITEONLY); boolean fieldMarkingPrivate = filter.matches(FIELD_MARKING_PRIVATE); boolean fieldPropagationValue = filter.matches(FIELD_PROPAGATION_VALUE); boolean methodMarkingPrivate = filter.matches(METHOD_MARKING_PRIVATE); boolean methodMarkingStatic = filter.matches(METHOD_MARKING_STATIC); boolean methodMarkingFinal = filter.matches(METHOD_MARKING_FINAL); boolean methodRemovalParameter = filter.matches(METHOD_REMOVAL_PARAMETER); boolean methodPropagationParameter = filter.matches(METHOD_PROPAGATION_PARAMETER); boolean methodPropagationReturnvalue = filter.matches(METHOD_PROPAGATION_RETURNVALUE); boolean methodInliningShort = filter.matches(METHOD_INLINING_SHORT); boolean methodInliningUnique = filter.matches(METHOD_INLINING_UNIQUE); boolean methodInliningTailrecursion = filter.matches(METHOD_INLINING_TAILRECURSION); boolean codeMerging = filter.matches(CODE_MERGING); boolean codeSimplificationVariable = filter.matches(CODE_SIMPLIFICATION_VARIABLE); boolean codeSimplificationArithmetic = filter.matches(CODE_SIMPLIFICATION_ARITHMETIC); boolean codeSimplificationCast = filter.matches(CODE_SIMPLIFICATION_CAST); boolean codeSimplificationField = filter.matches(CODE_SIMPLIFICATION_FIELD); boolean codeSimplificationBranch = filter.matches(CODE_SIMPLIFICATION_BRANCH); boolean codeSimplificationString = filter.matches(CODE_SIMPLIFICATION_STRING); boolean codeSimplificationAdvanced = filter.matches(CODE_SIMPLIFICATION_ADVANCED); boolean codeRemovalAdvanced = filter.matches(CODE_REMOVAL_ADVANCED); boolean codeRemovalSimple = filter.matches(CODE_REMOVAL_SIMPLE); boolean codeRemovalVariable = filter.matches(CODE_REMOVAL_VARIABLE); boolean codeRemovalException = filter.matches(CODE_REMOVAL_EXCEPTION); boolean codeAllocationVariable = filter.matches(CODE_ALLOCATION_VARIABLE); // Create counters to count the numbers of optimizations. ClassCounter classMarkingFinalCounter = new ClassCounter(); ClassCounter classMergingVerticalCounter = new ClassCounter(); ClassCounter classMergingHorizontalCounter = new ClassCounter(); MemberCounter fieldRemovalWriteonlyCounter = new MemberCounter(); MemberCounter fieldMarkingPrivateCounter = new MemberCounter(); MemberCounter fieldPropagationValueCounter = new MemberCounter(); MemberCounter methodMarkingPrivateCounter = new MemberCounter(); MemberCounter methodMarkingStaticCounter = new MemberCounter(); MemberCounter methodMarkingFinalCounter = new MemberCounter(); MemberCounter methodRemovalParameterCounter = new MemberCounter(); MemberCounter methodPropagationParameterCounter = new MemberCounter(); MemberCounter methodPropagationReturnvalueCounter = new MemberCounter(); InstructionCounter methodInliningShortCounter = new InstructionCounter(); InstructionCounter methodInliningUniqueCounter = new InstructionCounter(); InstructionCounter methodInliningTailrecursionCounter = new InstructionCounter(); InstructionCounter codeMergingCounter = new InstructionCounter(); InstructionCounter codeSimplificationVariableCounter = new InstructionCounter(); InstructionCounter codeSimplificationArithmeticCounter = new InstructionCounter(); InstructionCounter codeSimplificationCastCounter = new InstructionCounter(); InstructionCounter codeSimplificationFieldCounter = new InstructionCounter(); InstructionCounter codeSimplificationBranchCounter = new InstructionCounter(); InstructionCounter codeSimplificationStringCounter = new InstructionCounter(); InstructionCounter codeSimplificationAdvancedCounter = new InstructionCounter(); InstructionCounter deletedCounter = new InstructionCounter(); InstructionCounter addedCounter = new InstructionCounter(); MemberCounter codeRemovalVariableCounter = new MemberCounter(); ExceptionCounter codeRemovalExceptionCounter = new ExceptionCounter(); MemberCounter codeAllocationVariableCounter = new MemberCounter(); MemberCounter initializerFixCounter1 = new MemberCounter(); MemberCounter initializerFixCounter2 = new MemberCounter(); // Some optimizations are required by other optimizations. codeSimplificationAdvanced = codeSimplificationAdvanced || fieldPropagationValue || methodPropagationParameter || methodPropagationReturnvalue; codeRemovalAdvanced = codeRemovalAdvanced || fieldRemovalWriteonly || methodMarkingStatic || methodRemovalParameter; codeRemovalSimple = codeRemovalSimple || codeSimplificationBranch; codeRemovalException = codeRemovalException || codeRemovalAdvanced || codeRemovalSimple; // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); libraryClassPool.classesAccept(new ClassCleaner()); // Link all methods that should get the same optimization info. programClassPool.classesAccept(new BottomClassFilter( new MethodLinker())); libraryClassPool.classesAccept(new BottomClassFilter( new MethodLinker())); // Create a visitor for marking the seeds. KeepMarker keepMarker = new KeepMarker(); ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, keepMarker, keepMarker, false, true, false); // Mark the seeds. programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); // All library classes and library class members remain unchanged. libraryClassPool.classesAccept(keepMarker); libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker)); // We also keep all classes that are involved in .class constructs. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new AllInstructionVisitor( new DotClassClassVisitor(keepMarker))))); // We also keep all classes that are accessed dynamically. programClassPool.classesAccept( new AllConstantVisitor( new ConstantTagFilter(ClassConstants.CONSTANT_String, new ReferencedClassVisitor(keepMarker)))); // We also keep all class members that are accessed dynamically. programClassPool.classesAccept( new AllConstantVisitor( new ConstantTagFilter(ClassConstants.CONSTANT_String, new ReferencedMemberVisitor(keepMarker)))); // We also keep all bootstrap method signatures. programClassPool.classesAccept( new ClassVersionFilter(ClassConstants.INTERNAL_CLASS_VERSION_1_7, new AllAttributeVisitor( new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods, new AllBootstrapMethodInfoVisitor( new BootstrapMethodHandleTraveler( new MethodrefTraveler( new ReferencedMemberVisitor(keepMarker)))))))); // Attach some optimization info to all classes and class members, so // it can be filled out later. programClassPool.classesAccept(new ClassOptimizationInfoSetter()); programClassPool.classesAccept(new AllMemberVisitor( new MemberOptimizationInfoSetter())); if (configuration.assumeNoSideEffects != null) { // Create a visitor for marking methods that don't have any side effects. NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker(); ClassPoolVisitor noClassPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects, null, noSideEffectMethodMarker); // Mark the seeds. programClassPool.accept(noClassPoolvisitor); libraryClassPool.accept(noClassPoolvisitor); } if (classMarkingFinal) { // Make classes final, whereever possible. programClassPool.classesAccept( new ClassFinalizer(classMarkingFinalCounter)); } if (methodMarkingFinal) { // Make methods final, whereever possible. programClassPool.classesAccept( new AllMethodVisitor( new MethodFinalizer(methodMarkingFinalCounter))); } if (fieldRemovalWriteonly) { // Mark all fields that are write-only. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new AllInstructionVisitor( new ReadWriteFieldMarker())))); // Count the write-only fields. programClassPool.classesAccept( new AllFieldVisitor( new WriteOnlyFieldFilter(fieldRemovalWriteonlyCounter))); } else { // Mark all fields as read/write. programClassPool.classesAccept( new AllFieldVisitor( new ReadWriteFieldMarker())); } // Mark all used parameters, including the 'this' parameters. programClassPool.classesAccept( new AllMethodVisitor( new OptimizationInfoMemberFilter( new ParameterUsageMarker(!methodMarkingStatic, !methodRemovalParameter)))); // Mark all classes that have static initializers. programClassPool.classesAccept(new StaticInitializerContainingClassMarker()); // Mark all methods that have side effects. programClassPool.accept(new SideEffectMethodMarker()); // System.out.println("Optimizer.execute: before evaluation simplification"); // programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter())); // Perform partial evaluation for filling out fields, method parameters, // and method return values. ValueFactory valueFactory = new IdentifiedValueFactory(); if (fieldPropagationValue || methodPropagationParameter || methodPropagationReturnvalue) { // Fill out fields, method parameters, and return values, so they // can be propagated. InvocationUnit storingInvocationUnit = new StoringInvocationUnit(valueFactory, fieldPropagationValue, methodPropagationParameter, methodPropagationReturnvalue); programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new PartialEvaluator(valueFactory, storingInvocationUnit, false)))); if (fieldPropagationValue) { // Count the constant fields. programClassPool.classesAccept( new AllFieldVisitor( new ConstantMemberFilter(fieldPropagationValueCounter))); } if (methodPropagationParameter) { // Count the constant method parameters. programClassPool.classesAccept( new AllMethodVisitor( new ConstantParameterFilter(methodPropagationParameterCounter))); } if (methodPropagationReturnvalue) { // Count the constant method return values. programClassPool.classesAccept( new AllMethodVisitor( new ConstantMemberFilter(methodPropagationReturnvalueCounter))); } } InvocationUnit loadingInvocationUnit = new LoadingInvocationUnit(valueFactory, fieldPropagationValue, methodPropagationParameter, methodPropagationReturnvalue); if (codeSimplificationAdvanced) { // Simplify based on partial evaluation, propagating constant // field values, method parameter values, and return values. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new EvaluationSimplifier( new PartialEvaluator(valueFactory, loadingInvocationUnit, false), codeSimplificationAdvancedCounter)))); } if (codeRemovalAdvanced) { // Remove code based on partial evaluation, also removing unused // parameters from method invocations, and making methods static // if possible. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new EvaluationShrinker( new PartialEvaluator(valueFactory, loadingInvocationUnit, !codeSimplificationAdvanced), deletedCounter, addedCounter)))); } if (methodRemovalParameter) { // Shrink the parameters in the method descriptors. programClassPool.classesAccept( new AllMethodVisitor( new OptimizationInfoMemberFilter( new MethodDescriptorShrinker()))); } if (methodMarkingStatic) { // Make all non-static methods that don't require the 'this' // parameter static. programClassPool.classesAccept( new AllMethodVisitor( new OptimizationInfoMemberFilter( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC, new MethodStaticizer(methodMarkingStaticCounter))))); } if (methodRemovalParameter) { // Fix all references to class members. // This operation also updates the stack sizes. programClassPool.classesAccept( new MemberReferenceFixer()); // Remove unused bootstrap method arguments. programClassPool.classesAccept( new AllAttributeVisitor( new AllBootstrapMethodInfoVisitor( new BootstrapMethodArgumentShrinker()))); } if (methodRemovalParameter || methodMarkingPrivate || methodMarkingStatic) { // Remove all unused parameters from the byte code, shifting all // remaining variables. // This operation also updates the local variable frame sizes. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new ParameterShrinker(methodRemovalParameterCounter)))); } else if (codeRemovalAdvanced) { // Just update the local variable frame sizes. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new StackSizeUpdater()))); } if (methodRemovalParameter && methodRemovalParameterCounter.getCount() > 0) { // Tweak the descriptors of duplicate initializers, due to removed // method parameters. programClassPool.classesAccept( new AllMethodVisitor( new DuplicateInitializerFixer(initializerFixCounter1))); if (initializerFixCounter1.getCount() > 0) { // Fix all invocations of tweaked initializers. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new DuplicateInitializerInvocationFixer(addedCounter)))); // Fix all references to tweaked initializers. programClassPool.classesAccept(new MemberReferenceFixer()); } } //// Specializing the class member descriptors seems to increase the //// class file size, on average. //// Specialize all class member descriptors. //programClassPool.classesAccept(new AllMemberVisitor( // new OptimizationInfoMemberFilter( // new MemberDescriptorSpecializer()))); // //// Fix all references to classes, for MemberDescriptorSpecializer. //programClassPool.classesAccept(new AllMemberVisitor( // new OptimizationInfoMemberFilter( // new ClassReferenceFixer(true)))); // Mark all classes with package visible members. // Mark all exception catches of methods. // Count all method invocations. // Mark super invocations and other access of methods. programClassPool.classesAccept( new MultiClassVisitor( new ClassVisitor[] { new PackageVisibleMemberContainingClassMarker(), new AllConstantVisitor( new PackageVisibleMemberInvokingClassMarker()), new AllMethodVisitor( new MultiMemberVisitor( new MemberVisitor[] { new AllAttributeVisitor( new MultiAttributeVisitor( new AttributeVisitor[] { new CatchExceptionMarker(), new AllInstructionVisitor( new MultiInstructionVisitor( new InstructionVisitor[] { new InstantiationClassMarker(), new InstanceofClassMarker(), new DotClassMarker(), new MethodInvocationMarker(), new SuperInvocationMarker(), new BackwardBranchMarker(), new AccessMethodMarker(), })), new AllExceptionInfoVisitor( new ExceptionHandlerConstantVisitor( new ReferencedClassVisitor( new CaughtClassMarker()))), })), })), })); if (classMergingVertical) { // Merge classes into their superclasses or interfaces. programClassPool.classesAccept( new VerticalClassMerger(configuration.allowAccessModification, configuration.mergeInterfacesAggressively, classMergingVerticalCounter)); } if (classMergingHorizontal) { // Merge classes into their sibling classes. programClassPool.classesAccept( new HorizontalClassMerger(configuration.allowAccessModification, configuration.mergeInterfacesAggressively, classMergingHorizontalCounter)); } if (classMergingVerticalCounter .getCount() > 0 || classMergingHorizontalCounter.getCount() > 0) { // Clean up inner class attributes to avoid loops. programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover()); // Update references to merged classes. programClassPool.classesAccept(new TargetClassChanger()); programClassPool.classesAccept(new ClassReferenceFixer(true)); programClassPool.classesAccept(new MemberReferenceFixer()); if (configuration.allowAccessModification) { // Fix the access flags of referenced merged classes and their // class members. programClassPool.classesAccept( new AllConstantVisitor( new AccessFixer())); } // Fix the access flags of the inner classes information. programClassPool.classesAccept( new AllAttributeVisitor( new AllInnerClassesInfoVisitor( new InnerClassesAccessFixer()))); // Tweak the descriptors of duplicate initializers, due to merged // parameter classes. programClassPool.classesAccept( new AllMethodVisitor( new DuplicateInitializerFixer(initializerFixCounter2))); if (initializerFixCounter2.getCount() > 0) { // Fix all invocations of tweaked initializers. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new DuplicateInitializerInvocationFixer(addedCounter)))); // Fix all references to tweaked initializers. programClassPool.classesAccept(new MemberReferenceFixer()); } } if (methodInliningUnique) { // Inline methods that are only invoked once. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new MethodInliner(configuration.microEdition, configuration.allowAccessModification, true, methodInliningUniqueCounter)))); } if (methodInliningShort) { // Inline short methods. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new MethodInliner(configuration.microEdition, configuration.allowAccessModification, false, methodInliningShortCounter)))); } if (methodInliningTailrecursion) { // Simplify tail recursion calls. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new TailRecursionSimplifier(methodInliningTailrecursionCounter)))); } if (fieldMarkingPrivate || methodMarkingPrivate) { // Mark all class members that can not be made private. programClassPool.classesAccept( new NonPrivateMemberMarker()); } if (fieldMarkingPrivate) { // Make all non-private fields private, whereever possible. programClassPool.classesAccept( new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE, new AllFieldVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberPrivatizer(fieldMarkingPrivateCounter))))); } if (methodMarkingPrivate) { // Make all non-private methods private, whereever possible. programClassPool.classesAccept( new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE, new AllMethodVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberPrivatizer(methodMarkingPrivateCounter))))); } if ((methodInliningUniqueCounter .getCount() > 0 || methodInliningShortCounter .getCount() > 0 || methodInliningTailrecursionCounter.getCount() > 0) && configuration.allowAccessModification) { // Fix the access flags of referenced classes and class members, // for MethodInliner. programClassPool.classesAccept( new AllConstantVisitor( new AccessFixer())); } if (methodRemovalParameterCounter .getCount() > 0 || classMergingVerticalCounter .getCount() > 0 || classMergingHorizontalCounter .getCount() > 0 || methodMarkingPrivateCounter .getCount() > 0 ) { // Fix invocations of interface methods, of methods that have become // non-abstract or private, and of methods that have moved to a // different package. programClassPool.classesAccept( new AllMemberVisitor( new AllAttributeVisitor( new MethodInvocationFixer()))); } if (codeMerging) { // Share common blocks of code at branches. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new GotoCommonCodeReplacer(codeMergingCounter)))); } // Create a branch target marker and a code attribute editor that can // be reused for all code attributes. BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); List peepholeOptimizations = new ArrayList(); if (codeSimplificationVariable) { // Peephole optimizations involving local variables. peepholeOptimizations.add( new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.VARIABLE, branchTargetFinder, codeAttributeEditor, codeSimplificationVariableCounter)); } if (codeSimplificationArithmetic) { // Peephole optimizations involving arithmetic operations. peepholeOptimizations.add( new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.ARITHMETIC, branchTargetFinder, codeAttributeEditor, codeSimplificationArithmeticCounter)); } if (codeSimplificationCast) { // Peephole optimizations involving cast operations. peepholeOptimizations.add( new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.CAST, branchTargetFinder, codeAttributeEditor, codeSimplificationCastCounter)); } if (codeSimplificationField) { // Peephole optimizations involving fields. peepholeOptimizations.add( new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.FIELD, branchTargetFinder, codeAttributeEditor, codeSimplificationFieldCounter)); } if (codeSimplificationBranch) { // Peephole optimizations involving branches. peepholeOptimizations.add( new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.BRANCH, branchTargetFinder, codeAttributeEditor, codeSimplificationBranchCounter)); // Include optimization of branches to branches and returns. peepholeOptimizations.add( new GotoGotoReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); peepholeOptimizations.add( new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); } if (codeSimplificationString) { // Peephole optimizations involving branches. peepholeOptimizations.add( new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.STRING, branchTargetFinder, codeAttributeEditor, codeSimplificationStringCounter)); } if (!peepholeOptimizations.isEmpty()) { // Convert the list into an array. InstructionVisitor[] peepholeOptimizationsArray = new InstructionVisitor[peepholeOptimizations.size()]; peepholeOptimizations.toArray(peepholeOptimizationsArray); // Perform the peephole optimisations. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor, new MultiInstructionVisitor( peepholeOptimizationsArray))))); } if (codeRemovalException) { // Remove unnecessary exception handlers. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new UnreachableExceptionRemover(codeRemovalExceptionCounter)))); } if (codeRemovalSimple) { // Remove unreachable code. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new UnreachableCodeRemover(deletedCounter)))); } if (codeRemovalVariable) { // Remove all unused local variables. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new VariableShrinker(codeRemovalVariableCounter)))); } if (codeAllocationVariable) { // Optimize the variables. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new VariableOptimizer(false, codeAllocationVariableCounter)))); } // Remove unused constants. programClassPool.classesAccept( new ConstantPoolShrinker()); int classMarkingFinalCount = classMarkingFinalCounter .getCount(); int classMergingVerticalCount = classMergingVerticalCounter .getCount(); int classMergingHorizontalCount = classMergingHorizontalCounter .getCount(); int fieldRemovalWriteonlyCount = fieldRemovalWriteonlyCounter .getCount(); int fieldMarkingPrivateCount = fieldMarkingPrivateCounter .getCount(); int fieldPropagationValueCount = fieldPropagationValueCounter .getCount(); int methodMarkingPrivateCount = methodMarkingPrivateCounter .getCount(); int methodMarkingStaticCount = methodMarkingStaticCounter .getCount(); int methodMarkingFinalCount = methodMarkingFinalCounter .getCount(); int methodRemovalParameterCount = methodRemovalParameterCounter .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter1.getCount() - initializerFixCounter2.getCount(); int methodPropagationParameterCount = methodPropagationParameterCounter .getCount(); int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount(); int methodInliningShortCount = methodInliningShortCounter .getCount(); int methodInliningUniqueCount = methodInliningUniqueCounter .getCount(); int methodInliningTailrecursionCount = methodInliningTailrecursionCounter .getCount(); int codeMergingCount = codeMergingCounter .getCount(); int codeSimplificationVariableCount = codeSimplificationVariableCounter .getCount(); int codeSimplificationArithmeticCount = codeSimplificationArithmeticCounter.getCount(); int codeSimplificationCastCount = codeSimplificationCastCounter .getCount(); int codeSimplificationFieldCount = codeSimplificationFieldCounter .getCount(); int codeSimplificationBranchCount = codeSimplificationBranchCounter .getCount(); int codeSimplificationStringCount = codeSimplificationStringCounter .getCount(); int codeSimplificationAdvancedCount = codeSimplificationAdvancedCounter .getCount(); int codeRemovalCount = deletedCounter .getCount() - addedCounter.getCount(); int codeRemovalVariableCount = codeRemovalVariableCounter .getCount(); int codeRemovalExceptionCount = codeRemovalExceptionCounter .getCount(); int codeAllocationVariableCount = codeAllocationVariableCounter .getCount(); // Forget about constant fields, parameters, and return values, if they // didn't lead to any useful optimizations. We want to avoid fruitless // additional optimization passes. if (codeSimplificationAdvancedCount == 0) { fieldPropagationValueCount = 0; methodPropagationParameterCount = 0; methodPropagationReturnvalueCount = 0; } if (configuration.verbose) { System.out.println(" Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal)); System.out.println(" Number of vertically merged classes: " + classMergingVerticalCount + disabled(classMergingVertical)); System.out.println(" Number of horizontally merged classes: " + classMergingHorizontalCount + disabled(classMergingHorizontal)); System.out.println(" Number of removed write-only fields: " + fieldRemovalWriteonlyCount + disabled(fieldRemovalWriteonly)); System.out.println(" Number of privatized fields: " + fieldMarkingPrivateCount + disabled(fieldMarkingPrivate)); System.out.println(" Number of inlined constant fields: " + fieldPropagationValueCount + disabled(fieldPropagationValue)); System.out.println(" Number of privatized methods: " + methodMarkingPrivateCount + disabled(methodMarkingPrivate)); System.out.println(" Number of staticized methods: " + methodMarkingStaticCount + disabled(methodMarkingStatic)); System.out.println(" Number of finalized methods: " + methodMarkingFinalCount + disabled(methodMarkingFinal)); System.out.println(" Number of removed method parameters: " + methodRemovalParameterCount + disabled(methodRemovalParameter)); System.out.println(" Number of inlined constant parameters: " + methodPropagationParameterCount + disabled(methodPropagationParameter)); System.out.println(" Number of inlined constant return values: " + methodPropagationReturnvalueCount + disabled(methodPropagationReturnvalue)); System.out.println(" Number of inlined short method calls: " + methodInliningShortCount + disabled(methodInliningShort)); System.out.println(" Number of inlined unique method calls: " + methodInliningUniqueCount + disabled(methodInliningUnique)); System.out.println(" Number of inlined tail recursion calls: " + methodInliningTailrecursionCount + disabled(methodInliningTailrecursion)); System.out.println(" Number of merged code blocks: " + codeMergingCount + disabled(codeMerging)); System.out.println(" Number of variable peephole optimizations: " + codeSimplificationVariableCount + disabled(codeSimplificationVariable)); System.out.println(" Number of arithmetic peephole optimizations: " + codeSimplificationArithmeticCount + disabled(codeSimplificationArithmetic)); System.out.println(" Number of cast peephole optimizations: " + codeSimplificationCastCount + disabled(codeSimplificationCast)); System.out.println(" Number of field peephole optimizations: " + codeSimplificationFieldCount + disabled(codeSimplificationField)); System.out.println(" Number of branch peephole optimizations: " + codeSimplificationBranchCount + disabled(codeSimplificationBranch)); System.out.println(" Number of string peephole optimizations: " + codeSimplificationStringCount + disabled(codeSimplificationString)); System.out.println(" Number of simplified instructions: " + codeSimplificationAdvancedCount + disabled(codeSimplificationAdvanced)); System.out.println(" Number of removed instructions: " + codeRemovalCount + disabled(codeRemovalAdvanced)); System.out.println(" Number of removed local variables: " + codeRemovalVariableCount + disabled(codeRemovalVariable)); System.out.println(" Number of removed exception blocks: " + codeRemovalExceptionCount + disabled(codeRemovalException)); System.out.println(" Number of optimized local variable frames: " + codeAllocationVariableCount + disabled(codeAllocationVariable)); } return classMarkingFinalCount > 0 || classMergingVerticalCount > 0 || classMergingHorizontalCount > 0 || fieldRemovalWriteonlyCount > 0 || fieldMarkingPrivateCount > 0 || methodMarkingPrivateCount > 0 || methodMarkingStaticCount > 0 || methodMarkingFinalCount > 0 || fieldPropagationValueCount > 0 || methodRemovalParameterCount > 0 || methodPropagationParameterCount > 0 || methodPropagationReturnvalueCount > 0 || methodInliningShortCount > 0 || methodInliningUniqueCount > 0 || methodInliningTailrecursionCount > 0 || codeMergingCount > 0 || codeSimplificationVariableCount > 0 || codeSimplificationArithmeticCount > 0 || codeSimplificationCastCount > 0 || codeSimplificationFieldCount > 0 || codeSimplificationBranchCount > 0 || codeSimplificationStringCount > 0 || codeSimplificationAdvancedCount > 0 || codeRemovalCount > 0 || codeRemovalVariableCount > 0 || codeRemovalExceptionCount > 0 || codeAllocationVariableCount > 0; } /** * Returns a String indicating whether the given flag is enabled or * disabled. */ private String disabled(boolean flag) { return flag ? "" : " (disabled)"; } /** * Returns a String indicating whether the given flags are enabled or * disabled. */ private String disabled(boolean flag1, boolean flag2) { return flag1 && flag2 ? "" : flag1 || flag2 ? " (partially disabled)" : " (disabled)"; } } proguard4.8/src/proguard/optimize/BootstrapMethodArgumentShrinker.java0000644000175000017500000000676611736333526025255 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.ConstantPoolEditor; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.info.*; import proguard.optimize.peephole.VariableShrinker; /** * This BootstrapMethodInfoVisitor removes unused constant arguments from * bootstrap method entries that it visits. * * @see ParameterUsageMarker * @see VariableUsageMarker * @see VariableShrinker * @author Eric Lafortune */ public class BootstrapMethodArgumentShrinker extends SimplifiedVisitor implements BootstrapMethodInfoVisitor, ConstantVisitor, MemberVisitor { private long usedParameters; // Implementations for BootstrapMethodInfoVisitor. public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) { // Check which method parameters are used. usedParameters = -1L; clazz.constantPoolEntryAccept(bootstrapMethodInfo.u2methodHandleIndex, this); // Remove the unused arguments. int methodArgumentCount = bootstrapMethodInfo.u2methodArgumentCount; int[] methodArguments = bootstrapMethodInfo.u2methodArguments; int newArgumentIndex = 0; for (int argumentIndex = 0; argumentIndex < methodArgumentCount; argumentIndex++) { if (argumentIndex >= 64 || (usedParameters & (1L << argumentIndex)) != 0L) { methodArguments[newArgumentIndex++] = methodArguments[argumentIndex]; } } // Update the number of arguments. bootstrapMethodInfo.u2methodArgumentCount = newArgumentIndex; } // Implementations for ConstantVisitor. public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { // Check the referenced bootstrap method. clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { // Check the referenced class member itself. refConstant.referencedMemberAccept(this); } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { usedParameters = ParameterUsageMarker.getUsedParameters(programMethod); } } proguard4.8/src/proguard/optimize/ParameterShrinker.java0000644000175000017500000001221311736333526022334 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.editor.VariableRemapper; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.info.ParameterUsageMarker; /** * This MemberVisitor removes unused parameters from the code of the methods * that it visits. * * @see ParameterUsageMarker * @see MethodStaticizer * @see MethodDescriptorShrinker * @author Eric Lafortune */ public class ParameterShrinker extends SimplifiedVisitor implements AttributeVisitor { private static final boolean DEBUG = false; private final MemberVisitor extraVariableMemberVisitor; private final VariableRemapper variableRemapper = new VariableRemapper(); /** * Creates a new ParameterShrinker. */ public ParameterShrinker() { this(null); } /** * Creates a new ParameterShrinker with an extra visitor. * @param extraVariableMemberVisitor an optional extra visitor for all * removed parameters. */ public ParameterShrinker(MemberVisitor extraVariableMemberVisitor) { this.extraVariableMemberVisitor = extraVariableMemberVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Get the original parameter size that was saved. int oldParameterSize = ParameterUsageMarker.getParameterSize(method); // Compute the new parameter size from the shrunk descriptor. int newParameterSize = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), method.getAccessFlags()); if (oldParameterSize > newParameterSize) { // Get the total size of the local variable frame. int maxLocals = codeAttribute.u2maxLocals; if (DEBUG) { System.out.println("ParameterShrinker: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); System.out.println(" Old parameter size = " + oldParameterSize); System.out.println(" New parameter size = " + newParameterSize); System.out.println(" Max locals = " + maxLocals); } // Create a variable map. int[] variableMap = new int[maxLocals]; // Move unused parameters right after the parameter block. int usedParameterIndex = 0; int unusedParameterIndex = newParameterSize; for (int parameterIndex = 0; parameterIndex < oldParameterSize; parameterIndex++) { // Is the variable required as a parameter? if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) { // Keep the variable as a parameter. variableMap[parameterIndex] = usedParameterIndex++; } else { if (DEBUG) { System.out.println(" Deleting parameter #"+parameterIndex); } // Shift the variable to the unused parameter block, // in case it is still used as a variable. variableMap[parameterIndex] = unusedParameterIndex++; // Visit the method, if required. if (extraVariableMemberVisitor != null) { method.accept(clazz, extraVariableMemberVisitor); } } } // Fill out the remainder of the map. for (int variableIndex = oldParameterSize; variableIndex < maxLocals; variableIndex++) { variableMap[variableIndex] = variableIndex; } // Set the map. variableRemapper.setVariableMap(variableMap); // Remap the variables. variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); } } } proguard4.8/src/proguard/optimize/ConstantParameterFilter.java0000644000175000017500000000546711736333526023523 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.evaluation.value.Value; import proguard.optimize.evaluation.StoringInvocationUnit; import proguard.optimize.info.ParameterUsageMarker; /** * This MemberVisitor delegates its visits to program methods * to another given MemberVisitor, for each method parameter * that has been marked as constant. * * @see StoringInvocationUnit * @author Eric Lafortune */ public class ConstantParameterFilter extends SimplifiedVisitor implements MemberVisitor { private final MemberVisitor constantParameterVisitor; /** * Creates a new ConstantParameterFilter. * @param constantParameterVisitor the MemberVisitor to which * visits will be delegated. */ public ConstantParameterFilter(MemberVisitor constantParameterVisitor) { this.constantParameterVisitor = constantParameterVisitor; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // All parameters of non-static methods are shifted by one in the local // variable frame. int firstParameterIndex = (programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 0 : 1; int parameterCount = ClassUtil.internalMethodParameterCount(programMethod.getDescriptor(programClass)); for (int index = firstParameterIndex; index < parameterCount; index++) { Value value = StoringInvocationUnit.getMethodParameterValue(programMethod, index); if (value != null && value.isParticular()) { constantParameterVisitor.visitProgramMethod(programClass, programMethod); } } } }proguard4.8/src/proguard/optimize/KeptClassFilter.java0000644000175000017500000000373611736333526021757 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor delegates all its method calls to another ClassVisitor, * but only for Clazz objects that are marked as kept. * * @see KeepMarker * * @author Eric Lafortune */ public class KeptClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; /** * Creates a new KeptClassFilter. * @param classVisitor the class visitor to which the visiting will be * delegated. */ public KeptClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (KeepMarker.isKept(programClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (KeepMarker.isKept(libraryClass)) { classVisitor.visitLibraryClass(libraryClass); } } }proguard4.8/src/proguard/optimize/ChangedCodePrinter.java0000644000175000017500000002602711736333526022406 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.ClassUtil; /** * This AttributeVisitor delegates its call to another AttributeVisitor, and * prints out the code if the other visitor has changed it. * * @author Eric Lafortune */ public class ChangedCodePrinter implements AttributeVisitor { private final AttributeVisitor attributeVisitor; public ChangedCodePrinter(AttributeVisitor attributeVisitor) { this.attributeVisitor = attributeVisitor; } // Implementations for AttributeVisitor. public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) { attributeVisitor.visitUnknownAttribute(clazz, unknownAttribute); } public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) { attributeVisitor.visitBootstrapMethodsAttribute(clazz, bootstrapMethodsAttribute); } public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { attributeVisitor.visitSourceFileAttribute(clazz, sourceFileAttribute); } public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) { attributeVisitor.visitSourceDirAttribute(clazz, sourceDirAttribute); } public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { attributeVisitor.visitInnerClassesAttribute(clazz, innerClassesAttribute); } public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { attributeVisitor.visitEnclosingMethodAttribute(clazz, enclosingMethodAttribute); } public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) { attributeVisitor.visitDeprecatedAttribute(clazz, deprecatedAttribute); } public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) { attributeVisitor.visitSyntheticAttribute(clazz, syntheticAttribute); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute syntheticAttribute) { attributeVisitor.visitSignatureAttribute(clazz, syntheticAttribute); } public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute) { attributeVisitor.visitDeprecatedAttribute(clazz, field, deprecatedAttribute); } public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute) { attributeVisitor.visitSyntheticAttribute(clazz, field, syntheticAttribute); } public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute syntheticAttribute) { attributeVisitor.visitSignatureAttribute(clazz, field, syntheticAttribute); } public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute) { attributeVisitor.visitDeprecatedAttribute(clazz, method, deprecatedAttribute); } public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute) { attributeVisitor.visitSyntheticAttribute(clazz, method, syntheticAttribute); } public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute syntheticAttribute) { attributeVisitor.visitSignatureAttribute(clazz, method, syntheticAttribute); } public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { attributeVisitor.visitConstantValueAttribute(clazz, field, constantValueAttribute); } public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) { attributeVisitor.visitExceptionsAttribute(clazz, method, exceptionsAttribute); } public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) { attributeVisitor.visitStackMapAttribute(clazz, method, codeAttribute, stackMapAttribute); } public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) { attributeVisitor.visitStackMapTableAttribute(clazz, method, codeAttribute, stackMapTableAttribute); } public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { attributeVisitor.visitLineNumberTableAttribute(clazz, method, codeAttribute, lineNumberTableAttribute); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { attributeVisitor.visitLocalVariableTableAttribute(clazz, method, codeAttribute, localVariableTableAttribute); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { attributeVisitor.visitLocalVariableTypeTableAttribute(clazz, method, codeAttribute, localVariableTypeTableAttribute); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, runtimeVisibleAnnotationsAttribute); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, runtimeInvisibleAnnotationsAttribute); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, field, runtimeVisibleAnnotationsAttribute); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, field, runtimeInvisibleAnnotationsAttribute); } public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute) { attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, method, runtimeVisibleAnnotationsAttribute); } public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute) { attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, method, runtimeInvisibleAnnotationsAttribute); } public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute) { attributeVisitor.visitRuntimeVisibleParameterAnnotationsAttribute(clazz, method, runtimeVisibleParameterAnnotationsAttribute); } public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute) { attributeVisitor.visitRuntimeInvisibleParameterAnnotationsAttribute(clazz, method, runtimeInvisibleParameterAnnotationsAttribute); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { attributeVisitor.visitAnnotationDefaultAttribute(clazz, method, annotationDefaultAttribute); } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { byte[] code = codeAttribute.code; byte[] oldCode = new byte[code.length]; // Copy the current code. System.arraycopy(code, 0, oldCode, 0, codeAttribute.u4codeLength); // Delegate to the real visitor. attributeVisitor.visitCodeAttribute(clazz, method, codeAttribute); // Check if the code has changed. if (codeHasChanged(codeAttribute, oldCode)) { printChangedCode(clazz, method, codeAttribute, oldCode); } } // Small utility methods. private boolean codeHasChanged(CodeAttribute codeAttribute, byte[] oldCode) { if (oldCode.length != codeAttribute.u4codeLength) { return true; } for (int index = 0; index < codeAttribute.u4codeLength; index++) { if (oldCode[index] != codeAttribute.code[index]) { return true; } } return false; } private void printChangedCode(Clazz clazz, Method method, CodeAttribute codeAttribute, byte[] oldCode) { System.out.println("Class "+ClassUtil.externalClassName(clazz.getName())); System.out.println("Method "+ClassUtil.externalFullMethodDescription(clazz.getName(), 0, method.getName(clazz), method.getDescriptor(clazz))); for (int index = 0; index < codeAttribute.u4codeLength; index++) { System.out.println( (oldCode[index] == codeAttribute.code[index]? " -- ":" => ")+ index+": "+ Integer.toHexString(0x100|oldCode[index] &0xff).substring(1)+" "+ Integer.toHexString(0x100|codeAttribute.code[index]&0xff).substring(1)); } } } proguard4.8/src/proguard/optimize/info/0000775000175000017500000000000011760503005016765 5ustar ericericproguard4.8/src/proguard/optimize/info/ReadWriteFieldMarker.java0000644000175000017500000001176511736333526023650 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; /** * This InstructionVisitor marks all fields that are write-only. * * @author Eric Lafortune */ public class ReadWriteFieldMarker extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, MemberVisitor { // Parameters for the visitor methods. private boolean reading = true; private boolean writing = true; // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { byte opcode = constantInstruction.opcode; // Check for instructions that involve fields. switch (opcode) { case InstructionConstants.OP_LDC: case InstructionConstants.OP_LDC_W: // Mark the field, if any, as being read from and written to. reading = true; writing = true; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); break; case InstructionConstants.OP_GETSTATIC: case InstructionConstants.OP_GETFIELD: // Mark the field as being read from. reading = true; writing = false; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); break; case InstructionConstants.OP_PUTSTATIC: case InstructionConstants.OP_PUTFIELD: // Mark the field as being written to. reading = false; writing = true; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); break; } } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Mark the referenced field, if any. stringConstant.referencedMemberAccept(this); } public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { // Mark the referenced field. fieldrefConstant.referencedMemberAccept(this); } // Implementations for MemberVisitor. public void visitAnyMember(Clazz Clazz, Member member) {} public void visitProgramField(ProgramClass programClass, ProgramField programField) { // Mark the field if it is being read from. if (reading) { markAsRead(programField); } // Mark the field if it is being written to. if (writing) { markAsWritten(programField); } } // Small utility methods. private static void markAsRead(Field field) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); if (info != null) { info.setRead(); } } public static boolean isRead(Field field) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); return info == null || info.isRead(); } private static void markAsWritten(Field field) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); if (info != null) { info.setWritten(); } } public static boolean isWritten(Field field) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); return info == null || info.isWritten(); } } proguard4.8/src/proguard/optimize/info/package.html0000644000175000017500000000023111736333526021254 0ustar ericeric This package contains classes to collect additional information about classes and class members, which can then be used for optimization. proguard4.8/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java0000644000175000017500000000734611736333526027512 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.constant.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ConstantVisitor marks all classes that refer to package visible classes * or class members. * * @author Eric Lafortune */ public class PackageVisibleMemberInvokingClassMarker extends SimplifiedVisitor implements ConstantVisitor, ClassVisitor, MemberVisitor { private Clazz referencingClass; // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Check the referenced class and class member, if any. if (stringConstant.referencedClass != clazz) { referencingClass = clazz; stringConstant.referencedClassAccept(this); stringConstant.referencedMemberAccept(this); } } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { // Check the referenced class and class member. if (refConstant.referencedClass != clazz) { referencingClass = clazz; refConstant.referencedClassAccept(this); refConstant.referencedMemberAccept(this); } } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Check the referenced class. if (classConstant.referencedClass != clazz) { referencingClass = clazz; classConstant.referencedClassAccept(this); } } // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { if ((clazz.getAccessFlags() & ClassConstants.INTERNAL_ACC_PUBLIC) == 0) { setInvokesPackageVisibleMembers(referencingClass); } } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) { if ((member.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PUBLIC | ClassConstants.INTERNAL_ACC_PRIVATE)) == 0) { setInvokesPackageVisibleMembers(referencingClass); } } // Small utility methods. private static void setInvokesPackageVisibleMembers(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info != null) { info.setInvokesPackageVisibleMembers(); } } public static boolean invokesPackageVisibleMembers(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); return info == null || info.invokesPackageVisibleMembers(); } }proguard4.8/src/proguard/optimize/info/DotClassMarker.java0000644000175000017500000000615411736333526022526 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This InstructionVisitor marks all classes that are used in a .class * construct by any of the instructions that it visits. * * @author Eric Lafortune */ public class DotClassMarker extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, ClassVisitor { // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { if (constantInstruction.opcode == InstructionConstants.OP_LDC || constantInstruction.opcode == InstructionConstants.OP_LDC_W) { clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); } } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.referencedClassAccept(this); } // Implementations for ClassVisitor. public void visitLibraryClass(LibraryClass libraryClass) {} public void visitProgramClass(ProgramClass programClass) { setDotClassed(programClass); } // Small utility methods. private static void setDotClassed(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info != null) { info.setDotClassed(); } } public static boolean isDotClassed(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); return info == null || info.isDotClassed(); } }proguard4.8/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java0000644000175000017500000000407611736333526027446 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor marks all classes that contain static initializers. * * @author Eric Lafortune */ public class StaticInitializerContainingClassMarker extends SimplifiedVisitor implements ClassVisitor { // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { if (clazz.findMethod(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, ClassConstants.INTERNAL_METHOD_TYPE_CLINIT) != null) { setStaticInitializer(clazz); } } // Small utility methods. private static void setStaticInitializer(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info != null) { info.setContainsStaticInitializer(); } } public static boolean containsStaticInitializer(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); return info == null || info.containsStaticInitializer(); } }proguard4.8/src/proguard/optimize/info/NonPrivateMemberMarker.java0000644000175000017500000001246011736333526024224 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor marks all class members that can not be made private in the * classes that it visits, and in the classes to which they refer. * * @author Eric Lafortune */ public class NonPrivateMemberMarker extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, MemberVisitor { private final MethodImplementationFilter filteredMethodMarker = new MethodImplementationFilter(this); // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Mark all referenced class members in different classes. programClass.constantPoolEntriesAccept(this); // Explicitly mark the method. programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, ClassConstants.INTERNAL_METHOD_TYPE_CLINIT, this); // Explicitly mark the parameterless method. programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT, ClassConstants.INTERNAL_METHOD_TYPE_INIT, this); // Mark all methods that may have implementations. programClass.methodsAccept(filteredMethodMarker); } public void visitLibraryClass(LibraryClass libraryClass) { // Go over all methods. libraryClass.methodsAccept(this); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // The referenced class member, if any, can never be made private, // even if it's in the same class. stringConstant.referencedMemberAccept(this); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { Clazz referencedClass = refConstant.referencedClass; // Is it referring to a class member in another class? // The class member might be in another class, or // it may be referenced through another class. if (referencedClass != null && !referencedClass.equals(clazz) || !refConstant.getClassName(clazz).equals(clazz.getName())) { // The referenced class member can never be made private. refConstant.referencedMemberAccept(this); } } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { markCanNotBeMadePrivate(programField); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { markCanNotBeMadePrivate(libraryField); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { markCanNotBeMadePrivate(programMethod); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { markCanNotBeMadePrivate(libraryMethod); } // Small utility methods. private static void markCanNotBeMadePrivate(Field field) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); if (info != null) { info.setCanNotBeMadePrivate(); } } /** * Returns whether the given field can be made private. */ public static boolean canBeMadePrivate(Field field) { FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); return info != null && info.canBeMadePrivate(); } private static void markCanNotBeMadePrivate(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setCanNotBeMadePrivate(); } } /** * Returns whether the given method can be made private. */ public static boolean canBeMadePrivate(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info != null && info.canBeMadePrivate(); } } proguard4.8/src/proguard/optimize/info/MethodInvocationMarker.java0000644000175000017500000000666211736333526024270 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; /** * This InstructionVisitor counts the number of times methods are invoked from * the instructions that are visited. * * @author Eric Lafortune */ public class MethodInvocationMarker extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, MemberVisitor { // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Mark the referenced method, if any. stringConstant.referencedMemberAccept(this); } public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) { // Mark the referenced method. refConstant.referencedMemberAccept(this); } // Implementations for MemberVisitor. public void visitAnyMember(Clazz Clazz, Member member) {} public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { incrementInvocationCount(programMethod); } // Small utility methods. private static void incrementInvocationCount(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.incrementInvocationCount(); } } /** * Returns the number of times the given method was invoked by the * instructions that were visited. */ public static int getInvocationCount(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info != null ? info.getInvocationCount() : Integer.MAX_VALUE; } } proguard4.8/src/proguard/optimize/info/CatchExceptionMarker.java0000644000175000017500000000420311736333526023704 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This AttributeVisitor marks all methods that catch exceptions. * * @author Eric Lafortune */ public class CatchExceptionMarker extends SimplifiedVisitor implements AttributeVisitor { // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { if (codeAttribute.u2exceptionTableLength > 0) { markCatchException(method); } } // Small utility methods. private static void markCatchException(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setCatchesExceptions(); } } public static boolean catchesExceptions(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info == null || info.catchesExceptions(); } } proguard4.8/src/proguard/optimize/info/AccessMethodMarker.java0000644000175000017500000001420011736333526023343 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This InstructionVisitor marks the types of class accesses and class member * accesses of the methods whose instructions it visits. * * @author Eric Lafortune */ public class AccessMethodMarker extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, ClassVisitor, MemberVisitor { private Method invokingMethod; // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { invokingMethod = method; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Check the referenced class or class member, if any. stringConstant.referencedClassAccept(this); stringConstant.referencedMemberAccept(this); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { // Check the bootstrap method. invokeDynamicConstant.bootstrapMethodHandleAccept(clazz, this); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { // Check the method reference. clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { // Check the referenced class. clazz.constantPoolEntryAccept(refConstant.u2classIndex, this); // Check the referenced class member itself. refConstant.referencedClassAccept(this); refConstant.referencedMemberAccept(this); } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Check the referenced class. classConstant.referencedClassAccept(this); } // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { int accessFlags = clazz.getAccessFlags(); if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) == 0) { setAccessesPackageCode(invokingMethod); } } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) { int accessFlags = member.getAccessFlags(); if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0) { setAccessesPrivateCode(invokingMethod); } else if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0) { setAccessesProtectedCode(invokingMethod); } else if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) == 0) { setAccessesPackageCode(invokingMethod); } } // Small utility methods. private static void setAccessesPrivateCode(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setAccessesPrivateCode(); } } /** * Returns whether the given method accesses private class members. */ public static boolean accessesPrivateCode(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info == null || info.accessesPrivateCode(); } private static void setAccessesPackageCode(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setAccessesPackageCode(); } } /** * Returns whether the given method accesses package visible classes or class * members. */ public static boolean accessesPackageCode(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info == null || info.accessesPackageCode(); } private static void setAccessesProtectedCode(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setAccessesProtectedCode(); } } /** * Returns whether the given method accesses protected class members. */ public static boolean accessesProtectedCode(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info == null || info.accessesProtectedCode(); } } proguard4.8/src/proguard/optimize/info/InstantiationClassMarker.java0000644000175000017500000000575611736333526024633 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.ClassConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This InstructionVisitor marks all classes that are instantiated by any of * the instructions that it visits. * * @author Eric Lafortune */ public class InstantiationClassMarker extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, ClassVisitor { // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { if (constantInstruction.opcode == InstructionConstants.OP_NEW) { clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); } } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.referencedClassAccept(this); } // Implementations for ClassVisitor. public void visitLibraryClass(LibraryClass libraryClass) {} public void visitProgramClass(ProgramClass programClass) { setInstantiated(programClass); } // Small utility methods. private static void setInstantiated(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info != null) { info.setInstantiated(); } } public static boolean isInstantiated(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); return info == null || info.isInstantiated(); } }proguard4.8/src/proguard/optimize/info/SuperInvocationMarker.java0000644000175000017500000000612211736333526024135 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.RefConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor marks all methods that invoke super methods (other * than initializers) from the instructions that it visits. * * @author Eric Lafortune */ public class SuperInvocationMarker extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor { private boolean invokesSuperMethods; // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { if (constantInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL) { invokesSuperMethods = false; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); if (invokesSuperMethods) { setInvokesSuperMethods(method); } } } // Implementations for ConstantVisitor. public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) { invokesSuperMethods = !clazz.equals(refConstant.referencedClass) && !refConstant.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT); } // Small utility methods. private static void setInvokesSuperMethods(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setInvokesSuperMethods(); } } public static boolean invokesSuperMethods(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info == null || info.invokesSuperMethods(); } } proguard4.8/src/proguard/optimize/info/ClassOptimizationInfoSetter.java0000644000175000017500000000311311736333526025317 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; import proguard.optimize.KeepMarker; /** * This ClassVisitor attaches a ClassOptimizationInfo instance to every class * that is not being kept that it visits. * * @author Eric Lafortune */ public class ClassOptimizationInfoSetter extends SimplifiedVisitor implements ClassVisitor { // Implementations for MemberVisitor. public void visitProgramClass(ProgramClass programClass) { if (!KeepMarker.isKept(programClass)) { ClassOptimizationInfo.setClassOptimizationInfo(programClass); } } }proguard4.8/src/proguard/optimize/info/BackwardBranchMarker.java0000644000175000017500000000570311736333526023645 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; /** * This InstructionVisitor marks all methods that branch backward in any of the * instructions that it visits. * * @author Eric Lafortune */ public class BackwardBranchMarker extends SimplifiedVisitor implements InstructionVisitor { // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { markBackwardBranch(method, branchInstruction.branchOffset); } public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) { markBackwardBranch(method, switchInstruction.defaultOffset); for (int index = 0; index < switchInstruction.jumpOffsets.length; index++) { markBackwardBranch(method, switchInstruction.jumpOffsets[index]); } } // Small utility methods. /** * Marks the given method if the given branch offset is negative. */ private void markBackwardBranch(Method method, int branchOffset) { if (branchOffset < 0) { setBranchesBackward(method); } } private static void setBranchesBackward(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setBranchesBackward(); } } public static boolean branchesBackward(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info == null || info.branchesBackward(); } } proguard4.8/src/proguard/optimize/info/SideEffectInstructionChecker.java0000644000175000017500000002154211736333526025376 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; import java.util.*; /** * This class can tell whether an instruction has any side effects. Return * instructions can be included or not. * * @see ReadWriteFieldMarker * @see StaticInitializerContainingClassMarker * @see NoSideEffectMethodMarker * @see SideEffectMethodMarker * @author Eric Lafortune */ public class SideEffectInstructionChecker extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, MemberVisitor { private final boolean includeReturnInstructions; // A return value for the visitor methods. private Clazz referencingClass; private boolean hasSideEffects; public SideEffectInstructionChecker(boolean includeReturnInstructions) { this.includeReturnInstructions = includeReturnInstructions; } public boolean hasSideEffects(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { hasSideEffects = false; instruction.accept(clazz, method, codeAttribute, offset, this); return hasSideEffects; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { byte opcode = simpleInstruction.opcode; // Check for instructions that might cause side effects. if (opcode == InstructionConstants.OP_IASTORE || opcode == InstructionConstants.OP_LASTORE || opcode == InstructionConstants.OP_FASTORE || opcode == InstructionConstants.OP_DASTORE || opcode == InstructionConstants.OP_AASTORE || opcode == InstructionConstants.OP_BASTORE || opcode == InstructionConstants.OP_CASTORE || opcode == InstructionConstants.OP_SASTORE || opcode == InstructionConstants.OP_ATHROW || opcode == InstructionConstants.OP_MONITORENTER || opcode == InstructionConstants.OP_MONITOREXIT || (includeReturnInstructions && (opcode == InstructionConstants.OP_IRETURN || opcode == InstructionConstants.OP_LRETURN || opcode == InstructionConstants.OP_FRETURN || opcode == InstructionConstants.OP_DRETURN || opcode == InstructionConstants.OP_ARETURN || opcode == InstructionConstants.OP_RETURN))) { // These instructions always cause a side effect. hasSideEffects = true; } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { byte opcode = variableInstruction.opcode; // Check for instructions that might cause side effects. if (includeReturnInstructions && opcode == InstructionConstants.OP_RET) { hasSideEffects = true; } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { byte opcode = constantInstruction.opcode; // Check for instructions that might cause side effects. if (opcode == InstructionConstants.OP_GETSTATIC || opcode == InstructionConstants.OP_PUTSTATIC || opcode == InstructionConstants.OP_GETFIELD || opcode == InstructionConstants.OP_PUTFIELD || opcode == InstructionConstants.OP_INVOKEVIRTUAL || opcode == InstructionConstants.OP_INVOKESPECIAL || opcode == InstructionConstants.OP_INVOKESTATIC || opcode == InstructionConstants.OP_INVOKEINTERFACE || opcode == InstructionConstants.OP_INVOKEDYNAMIC) { // Check if the field is write-only or volatile, or if the invoked // method is causing any side effects. clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { byte opcode = branchInstruction.opcode; // Check for instructions that might cause side effects. if (includeReturnInstructions && (opcode == InstructionConstants.OP_JSR || opcode == InstructionConstants.OP_JSR_W)) { hasSideEffects = true; } } // Implementations for ConstantVisitor. public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { // We'll have to assume invoking an unknown method has side effects. hasSideEffects = true; } public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { // Pass the referencing class. referencingClass = clazz; // We'll have to assume accessing an unknown field has side effects. hasSideEffects = true; // Check the referenced field, if known. fieldrefConstant.referencedMemberAccept(this); } public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) { // Pass the referencing class. referencingClass = clazz; // We'll have to assume invoking an unknown method has side effects. hasSideEffects = true; // Check the referenced method, if known. refConstant.referencedMemberAccept(this); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { hasSideEffects = (ReadWriteFieldMarker.isRead(programField) && ReadWriteFieldMarker.isWritten(programField)) || ((programField.getAccessFlags() & ClassConstants.INTERNAL_ACC_VOLATILE) != 0) || (!programClass.equals(referencingClass) && !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(programClass))); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Note that side effects already include synchronization of some // implementation of the method. hasSideEffects = !NoSideEffectMethodMarker.hasNoSideEffects(programMethod) && (SideEffectMethodMarker.hasSideEffects(programMethod) || (!programClass.equals(referencingClass) && !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(programClass)))); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { hasSideEffects = true; } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { hasSideEffects = !NoSideEffectMethodMarker.hasNoSideEffects(libraryMethod); } /** * Returns the set of superclasses and interfaces that are initialized. */ private Set initializedSuperClasses(Clazz clazz) { Set set = new HashSet(); // Visit all superclasses and interfaces, collecting the ones that have // static initializers. clazz.hierarchyAccept(true, true, true, false, new StaticInitializerContainingClassFilter( new ClassCollector(set))); return set; } } proguard4.8/src/proguard/optimize/info/InstanceofClassFilter.java0000644000175000017500000000360411736333526024072 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor delegates all its method calls to another ClassVisitor, * but only for Clazz objects that are used in an 'instanceof' test. * * @see InstanceofClassMarker * @author Eric Lafortune */ public class InstanceofClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; public InstanceofClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (InstanceofClassMarker.isInstanceofed(programClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (InstanceofClassMarker.isInstanceofed(libraryClass)) { classVisitor.visitLibraryClass(libraryClass); } } }proguard4.8/src/proguard/optimize/info/FieldOptimizationInfo.java0000644000175000017500000001336511736333526024120 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.attribute.*; import proguard.classfile.util.*; import proguard.evaluation.value.*; import proguard.evaluation.ConstantValueFactory; /** * This class stores some optimization information that can be attached to * a field. * * @author Eric Lafortune */ public class FieldOptimizationInfo extends SimplifiedVisitor implements AttributeVisitor { private static final SpecificValueFactory VALUE_FACTORY = new SpecificValueFactory(); private static final ConstantValueFactory CONSTANT_VALUE_FACTORY = new ConstantValueFactory(VALUE_FACTORY); private boolean isWritten; private boolean isRead; private boolean canBeMadePrivate = true; private ReferenceValue referencedClass; private Value value; public FieldOptimizationInfo(Clazz clazz, Field field) { int accessFlags = field.getAccessFlags(); isWritten = isRead = (accessFlags & ClassConstants.INTERNAL_ACC_VOLATILE) != 0; if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0) { // See if we can initialize the static field with a constant value. field.accept(clazz, new AllAttributeVisitor(this)); } if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 && value == null) { // Otherwise initialize the non-final field with the default value. value = initialValue(field.getDescriptor(clazz)); } } public FieldOptimizationInfo(FieldOptimizationInfo FieldOptimizationInfo) { this.isWritten = FieldOptimizationInfo.isWritten; this.isRead = FieldOptimizationInfo.isRead; this.canBeMadePrivate = FieldOptimizationInfo.canBeMadePrivate; this.referencedClass = FieldOptimizationInfo.referencedClass; this.value = FieldOptimizationInfo.value; } public void setWritten() { isWritten = true; } public boolean isWritten() { return isWritten; } public void setRead() { isRead = true; } public boolean isRead() { return isRead; } public void setCanNotBeMadePrivate() { canBeMadePrivate = false; } public boolean canBeMadePrivate() { return canBeMadePrivate; } public void generalizeReferencedClass(ReferenceValue referencedClass) { this.referencedClass = this.referencedClass != null ? this.referencedClass.generalize(referencedClass) : referencedClass; } public ReferenceValue getReferencedClass() { return referencedClass; } public void generalizeValue(Value value) { this.value = this.value != null ? this.value.generalize(value) : value; } public Value getValue() { return value; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) { // Retrieve the initial static field value. value = CONSTANT_VALUE_FACTORY.constantValue(clazz, constantValueAttribute.u2constantValueIndex); } // Small utility methods. private Value initialValue(String type) { switch (type.charAt(0)) { case ClassConstants.INTERNAL_TYPE_BOOLEAN: case ClassConstants.INTERNAL_TYPE_BYTE: case ClassConstants.INTERNAL_TYPE_CHAR: case ClassConstants.INTERNAL_TYPE_SHORT: case ClassConstants.INTERNAL_TYPE_INT: return VALUE_FACTORY.createIntegerValue(0); case ClassConstants.INTERNAL_TYPE_LONG: return VALUE_FACTORY.createLongValue(0L); case ClassConstants.INTERNAL_TYPE_FLOAT: return VALUE_FACTORY.createFloatValue(0.0f); case ClassConstants.INTERNAL_TYPE_DOUBLE: return VALUE_FACTORY.createDoubleValue(0.0); case ClassConstants.INTERNAL_TYPE_CLASS_START: case ClassConstants.INTERNAL_TYPE_ARRAY: return VALUE_FACTORY.createReferenceValueNull(); default: throw new IllegalArgumentException("Invalid type ["+type+"]"); } } public static void setFieldOptimizationInfo(Clazz clazz, Field field) { field.setVisitorInfo(new FieldOptimizationInfo(clazz, field)); } public static FieldOptimizationInfo getFieldOptimizationInfo(Field field) { Object visitorInfo = field.getVisitorInfo(); return visitorInfo instanceof FieldOptimizationInfo ? (FieldOptimizationInfo)visitorInfo : null; } } proguard4.8/src/proguard/optimize/info/MemberOptimizationInfoSetter.java0000644000175000017500000000406111736333526025464 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.KeepMarker; /** * This MemberVisitor attaches a FieldOptimizationInfo instance to every field * and a MethodOptimizationInfo instance to every method that is not being kept * that it visits. * * @author Eric Lafortune */ public class MemberOptimizationInfoSetter extends SimplifiedVisitor implements MemberVisitor { // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { if (!KeepMarker.isKept(programField)) { FieldOptimizationInfo.setFieldOptimizationInfo(programClass, programField); } } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (!KeepMarker.isKept(programMethod)) { MethodOptimizationInfo.setMethodOptimizationInfo(programClass, programMethod); } } } proguard4.8/src/proguard/optimize/info/MethodOptimizationInfo.java0000644000175000017500000001611311736333526024307 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.evaluation.value.Value; /** * This class stores some optimization information that can be attached to * a method. * * @author Eric Lafortune */ public class MethodOptimizationInfo { private boolean hasNoSideEffects = false; private boolean hasSideEffects = false; private boolean canBeMadePrivate = true; private boolean catchesExceptions = false; private boolean branchesBackward = false; private boolean invokesSuperMethods = false; private boolean accessesPrivateCode = false; private boolean accessesPackageCode = false; private boolean accessesProtectedCode = false; private int invocationCount = 0; private int parameterSize = 0; private long usedParameters = 0L; private Value[] parameters; private Value returnValue; /** * Creates a new MethodOptimizationInfo for the given method. */ public MethodOptimizationInfo(Clazz clazz, Method method) { // Set up an array of the right size for storing information about the // passed parameters. int parameterCount = ClassUtil.internalMethodParameterCount(method.getDescriptor(clazz)); if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0) { parameterCount++; } if (parameterCount > 0) { parameters = new Value[parameterCount]; } } public void setNoSideEffects() { hasNoSideEffects = true; } public boolean hasNoSideEffects() { return hasNoSideEffects; } public void setSideEffects() { hasSideEffects = true; } public boolean hasSideEffects() { return hasSideEffects; } public void setCanNotBeMadePrivate() { canBeMadePrivate = false; } public boolean canBeMadePrivate() { return canBeMadePrivate; } public void setCatchesExceptions() { catchesExceptions = true; } public boolean catchesExceptions() { return catchesExceptions; } public void setBranchesBackward() { branchesBackward = true; } public boolean branchesBackward() { return branchesBackward; } public void setInvokesSuperMethods() { invokesSuperMethods = true; } public boolean invokesSuperMethods() { return invokesSuperMethods; } public void setAccessesPrivateCode() { accessesPrivateCode = true; } public boolean accessesPrivateCode() { return accessesPrivateCode; } public void setAccessesPackageCode() { accessesPackageCode = true; } public boolean accessesPackageCode() { return accessesPackageCode; } public void setAccessesProtectedCode() { accessesProtectedCode = true; } public boolean accessesProtectedCode() { return accessesProtectedCode; } public void incrementInvocationCount() { invocationCount++; } public int getInvocationCount() { return invocationCount; } public void setParameterSize(int parameterSize) { this.parameterSize = parameterSize; } public int getParameterSize() { return parameterSize; } public void setParameterUsed(int parameterIndex) { usedParameters |= 1L << parameterIndex; } public void setUsedParameters(long usedParameters) { this.usedParameters = usedParameters; } public boolean isParameterUsed(int parameterIndex) { return parameterIndex >= 64 || (usedParameters & (1L << parameterIndex)) != 0; } public long getUsedParameters() { return usedParameters; } public void generalizeParameter(int parameterIndex, Value parameter) { parameters[parameterIndex] = parameters[parameterIndex] != null ? parameters[parameterIndex].generalize(parameter) : parameter; } public Value getParameter(int parameterIndex) { return parameters != null ? parameters[parameterIndex] : null; } public void generalizeReturnValue(Value returnValue) { this.returnValue = this.returnValue != null ? this.returnValue.generalize(returnValue) : returnValue; } public Value getReturnValue() { return returnValue; } public void merge(MethodOptimizationInfo other) { if (other != null) { this.hasNoSideEffects &= other.hasNoSideEffects; this.hasSideEffects |= other.hasSideEffects; //this.canBeMadePrivate &= other.canBeMadePrivate; this.catchesExceptions |= other.catchesExceptions; this.branchesBackward |= other.branchesBackward; this.invokesSuperMethods |= other.invokesSuperMethods; this.accessesPrivateCode |= other.accessesPrivateCode; this.accessesPackageCode |= other.accessesPackageCode; this.accessesProtectedCode |= other.accessesProtectedCode; } else { this.hasNoSideEffects = false; this.hasSideEffects = true; //this.canBeMadePrivate = false; this.catchesExceptions = true; this.branchesBackward = true; this.invokesSuperMethods = true; this.accessesPrivateCode = true; this.accessesPackageCode = true; this.accessesProtectedCode = true; } } public static void setMethodOptimizationInfo(Clazz clazz, Method method) { MethodLinker.lastMember(method).setVisitorInfo(new MethodOptimizationInfo(clazz, method)); } public static MethodOptimizationInfo getMethodOptimizationInfo(Method method) { Object visitorInfo = MethodLinker.lastMember(method).getVisitorInfo(); return visitorInfo instanceof MethodOptimizationInfo ? (MethodOptimizationInfo)visitorInfo : null; } } proguard4.8/src/proguard/optimize/info/NoSideEffectMethodMarker.java0000664000175000017500000000542011736333526024446 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; /** * This MemberVisitor marks all methods that it visits as not having any side * effects. It will make the SideEffectMethodMarker consider them as such * without further analysis. * * @see SideEffectMethodMarker * @author Eric Lafortune */ public class NoSideEffectMethodMarker extends SimplifiedVisitor implements MemberVisitor { // A visitor info flag to indicate the visitor accepter is being kept, // but that it doesn't have any side effects. public static final Object KEPT_BUT_NO_SIDE_EFFECTS = new Object(); // Implementations for MemberVisitor. public void visitAnyMember(Clazz Clazz, Member member) { // Ignore any attempts to mark fields. } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { markNoSideEffects(programMethod); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { markNoSideEffects(libraryMethod); } // Small utility methods. private static void markNoSideEffects(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setNoSideEffects(); } else { MethodLinker.lastMember(method).setVisitorInfo(KEPT_BUT_NO_SIDE_EFFECTS); } } public static boolean hasNoSideEffects(Method method) { if (MethodLinker.lastVisitorAccepter(method).getVisitorInfo() == KEPT_BUT_NO_SIDE_EFFECTS) { return true; } MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info != null && info.hasNoSideEffects(); } } proguard4.8/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java0000644000175000017500000000504611736333526030012 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassVisitor marks all classes that contain package visible members. * * @author Eric Lafortune */ public class PackageVisibleMemberContainingClassMarker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor { // Implementations for ClassVisitor. public void visitAnyClass(Clazz clazz) { // Check the class itself. if ((clazz.getAccessFlags() & ClassConstants.INTERNAL_ACC_PUBLIC) == 0) { setPackageVisibleMembers(clazz); } else { // Check the members. clazz.fieldsAccept(this); clazz.methodsAccept(this); } } // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) { if ((member.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_PUBLIC)) == 0) { setPackageVisibleMembers(clazz); } } // Small utility methods. private static void setPackageVisibleMembers(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info != null) { info.setContainsPackageVisibleMembers(); } } public static boolean containsPackageVisibleMembers(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); return info == null || info.containsPackageVisibleMembers(); } }proguard4.8/src/proguard/optimize/info/ParameterUsageMarker.java0000644000175000017500000002332011736333526023711 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.evaluation.value.Value; import proguard.optimize.evaluation.PartialEvaluator; /** * This MemberVisitor counts the parameters and marks the used parameters * of the methods that it visits. It also marks the 'this' parameters of * methods that have hierarchies. * * @author Eric Lafortune */ public class ParameterUsageMarker extends SimplifiedVisitor implements MemberVisitor, AttributeVisitor, InstructionVisitor { private static final boolean DEBUG = false; private final boolean markThisParameter; private final boolean markAllParameters; private final PartialEvaluator partialEvaluator = new PartialEvaluator(); /** * Creates a new ParameterUsageMarker. */ public ParameterUsageMarker() { this(false, false); } /** * Creates a new ParameterUsageMarker that optionally marks all parameters. * @param markThisParameter specifies whether all 'this' parameters should * be marked as being used. * @param markAllParameters specifies whether all other parameters should * be marked as being used. */ public ParameterUsageMarker(boolean markThisParameter, boolean markAllParameters) { this.markThisParameter = markThisParameter; this.markAllParameters = markAllParameters; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { int parameterSize = ClassUtil.internalMethodParameterSize(programMethod.getDescriptor(programClass), programMethod.getAccessFlags()); if (parameterSize > 0) { int accessFlags = programMethod.getAccessFlags(); // Must we mark the 'this' parameter? if (markThisParameter && (accessFlags & ClassConstants.INTERNAL_ACC_STATIC) == 0) { // Mark the 'this' parameter. markParameterUsed(programMethod, 0); } // Must we mark all other parameters? if (markAllParameters) { // Mark all parameters, without the 'this' parameter. markUsedParameters(programMethod, (accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? -1L : -2L); } // Is it a native method? if ((accessFlags & ClassConstants.INTERNAL_ACC_NATIVE) != 0) { // Mark all parameters. markUsedParameters(programMethod, -1L); } // Is it an abstract method? else if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) { // Mark the 'this' parameter. markParameterUsed(programMethod, 0); } // Is it a non-native, concrete method? else { // Is the method not static, but synchronized, or can it have // other implementations, or is it a class instance initializer? if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) == 0 && ((accessFlags & ClassConstants.INTERNAL_ACC_SYNCHRONIZED) != 0 || programClass.mayHaveImplementations(programMethod) || programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))) { // Mark the 'this' parameter. markParameterUsed(programMethod, 0); } // Mark the parameters that are used by the code. programMethod.attributesAccept(programClass, this); } if (DEBUG) { System.out.print("ParameterUsageMarker: ["+programClass.getName() +"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"]: "); for (int index = 0; index < parameterSize; index++) { System.out.print(isParameterUsed(programMethod, index) ? '+' : '-'); } System.out.println(); } } // Set the parameter size. setParameterSize(programMethod, parameterSize); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { // Can the method have other implementations? if (libraryClass.mayHaveImplementations(libraryMethod)) { // All implementations must keep all parameters of this method, // including the 'this' parameter. markUsedParameters(libraryMethod, -1L); } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Evaluate the code. partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); // Mark the parameters that are used by the code. codeAttribute.instructionsAccept(clazz, method, this); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { if (partialEvaluator.isTraced(offset) && variableInstruction.isLoad()) { int parameterIndex = variableInstruction.variableIndex; if (parameterIndex < codeAttribute.u2maxLocals) { Value producer = partialEvaluator.getVariablesBefore(offset).getProducerValue(parameterIndex); if (producer != null && producer.instructionOffsetValue().contains(PartialEvaluator.AT_METHOD_ENTRY)) { // Mark the variable. markParameterUsed(method, parameterIndex); // Account for Category 2 instructions, which take up two entries. if (variableInstruction.isCategory2()) { markParameterUsed(method, parameterIndex + 1); } } } } } // Small utility methods. /** * Sets the total size of the parameters. */ private static void setParameterSize(Method method, int parameterSize) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setParameterSize(parameterSize); } } /** * Returns the total size of the parameters. */ public static int getParameterSize(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info != null ? info.getParameterSize() : 0; } /** * Marks the given parameter as being used. */ public static void markParameterUsed(Method method, int variableIndex) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setParameterUsed(variableIndex); } } /** * Marks the given parameters as being used. */ public static void markUsedParameters(Method method, long usedParameters) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setUsedParameters(info.getUsedParameters() | usedParameters); } } /** * Returns whether the given parameter is being used. */ public static boolean isParameterUsed(Method method, int variableIndex) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info == null || info.isParameterUsed(variableIndex); } /** * Returns which parameters are being used. */ public static long getUsedParameters(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info != null ? info.getUsedParameters() : -1L; } } proguard4.8/src/proguard/optimize/info/SideEffectMethodMarker.java0000644000175000017500000001266311736333526024156 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.instruction.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; /** * This ClassPoolVisitor marks all methods that have side effects. * * @see ReadWriteFieldMarker * @see NoSideEffectMethodMarker * @author Eric Lafortune */ public class SideEffectMethodMarker extends SimplifiedVisitor implements ClassPoolVisitor, ClassVisitor, MemberVisitor, AttributeVisitor { // A reusable object for checking whether instructions have side effects. private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(false); // Parameters and values for visitor methods. private int newSideEffectCount; private boolean hasSideEffects; // Implementations for ClassPoolVisitor. public void visitClassPool(ClassPool classPool) { // Go over all classes and their methods, marking if they have side // effects, until no new cases can be found. do { newSideEffectCount = 0; // Go over all classes and their methods once. classPool.classesAccept(this); } while (newSideEffectCount > 0); } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Go over all methods. programClass.methodsAccept(this); } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { if (!hasSideEffects(programMethod) && !NoSideEffectMethodMarker.hasNoSideEffects(programMethod)) { // Initialize the return value. hasSideEffects = (programMethod.getAccessFlags() & (ClassConstants.INTERNAL_ACC_NATIVE | ClassConstants.INTERNAL_ACC_SYNCHRONIZED)) != 0; // Look further if the method hasn't been marked yet. if (!hasSideEffects) { // Investigate the actual code. programMethod.attributesAccept(programClass, this); } // Mark the method depending on the return value. if (hasSideEffects) { markSideEffects(programMethod); newSideEffectCount++; } } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Remember whether the code has any side effects. hasSideEffects = hasSideEffects(clazz, method, codeAttribute); } // Small utility methods. /** * Returns whether the given code has any side effects. */ private boolean hasSideEffects(Clazz clazz, Method method, CodeAttribute codeAttribute) { byte[] code = codeAttribute.code; int length = codeAttribute.u4codeLength; // Go over all instructions. int offset = 0; do { // Get the current instruction. Instruction instruction = InstructionFactory.create(code, offset); // Check if it may be throwing exceptions. if (sideEffectInstructionChecker.hasSideEffects(clazz, method, codeAttribute, offset, instruction)) { return true; } // Go to the next instruction. offset += instruction.length(offset); } while (offset < length); return false; } private static void markSideEffects(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); if (info != null) { info.setSideEffects(); } } public static boolean hasSideEffects(Method method) { MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); return info == null || info.hasSideEffects(); } } proguard4.8/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java0000644000175000017500000000366011736333526027450 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor delegates all its method calls to another ClassVisitor, * but only for Clazz objects that are instantiated. * * @author Eric Lafortune */ public class StaticInitializerContainingClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; public StaticInitializerContainingClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (StaticInitializerContainingClassMarker.containsStaticInitializer(programClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (StaticInitializerContainingClassMarker.containsStaticInitializer(libraryClass)) { classVisitor.visitLibraryClass(libraryClass); } } }proguard4.8/src/proguard/optimize/info/CaughtClassMarker.java0000644000175000017500000000371511736333526023213 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor marks all program classes that it visits as caught. * This means that these classes are exception classes that occur in exception * handlers. * * @author Eric Lafortune */ public class CaughtClassMarker implements ClassVisitor { // Implementations for ClassVisitor. public void visitLibraryClass(LibraryClass libraryClass) {} public void visitProgramClass(ProgramClass programClass) { setCaught(programClass); } // Small utility methods. private static void setCaught(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info != null) { info.setCaught(); } } public static boolean isCaught(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); return info == null || info.isCaught(); } }proguard4.8/src/proguard/optimize/info/VariableUsageMarker.java0000644000175000017500000000607011736333526023521 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import java.util.Arrays; /** * This AttributeVisitor marks the local variables that are used in the code * attributes that it visits. * * @author Eric Lafortune */ public class VariableUsageMarker extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor { private boolean[] variableUsed = new boolean[ClassConstants.TYPICAL_VARIABLES_SIZE]; /** * Returns whether the given variable has been marked as being used. */ public boolean isVariableUsed(int variableIndex) { return variableUsed[variableIndex]; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { int maxLocals = codeAttribute.u2maxLocals; // Try to reuse the previous array. if (variableUsed.length < maxLocals) { // Create a new array. variableUsed = new boolean[maxLocals]; } else { // Reset the array. Arrays.fill(variableUsed, 0, maxLocals, false); } codeAttribute.instructionsAccept(clazz, method, this); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Mark the variable. variableUsed[variableInstruction.variableIndex] = true; // Account for Category 2 instructions, which take up two entries. if (variableInstruction.isCategory2()) { variableUsed[variableInstruction.variableIndex + 1] = true; } } } proguard4.8/src/proguard/optimize/info/ClassOptimizationInfo.java0000644000175000017500000000762711736333526024146 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.Clazz; /** * This class stores some optimization information that can be attached to * a class. * * @author Eric Lafortune */ public class ClassOptimizationInfo { private boolean isInstantiated = false; private boolean isInstanceofed = false; private boolean isDotClassed = false; private boolean isCaught = false; private boolean containsStaticInitializer = false; private boolean containsPackageVisibleMembers = false; private boolean invokesPackageVisibleMembers = false; private Clazz targetClass; public void setInstantiated() { isInstantiated = true; } public boolean isInstantiated() { return isInstantiated; } public void setInstanceofed() { isInstanceofed = true; } public boolean isInstanceofed() { return isInstanceofed; } public void setDotClassed() { isDotClassed = true; } public boolean isDotClassed() { return isDotClassed; } public void setCaught() { isCaught = true; } public boolean isCaught() { return isCaught; } public void setContainsStaticInitializer() { containsStaticInitializer = true; } public boolean containsStaticInitializer() { return containsStaticInitializer; } public void setContainsPackageVisibleMembers() { containsPackageVisibleMembers = true; } public boolean containsPackageVisibleMembers() { return containsPackageVisibleMembers; } public void setInvokesPackageVisibleMembers() { invokesPackageVisibleMembers = true; } public boolean invokesPackageVisibleMembers() { return invokesPackageVisibleMembers; } public void setTargetClass(Clazz targetClass) { this.targetClass = targetClass; } public Clazz getTargetClass() { return targetClass; } public void merge(ClassOptimizationInfo other) { this.isInstantiated |= other.isInstantiated; this.isInstanceofed |= other.isInstanceofed; this.isDotClassed |= other.isDotClassed; this.isCaught |= other.isCaught; this.containsStaticInitializer |= other.containsStaticInitializer; this.containsPackageVisibleMembers |= other.containsPackageVisibleMembers; this.invokesPackageVisibleMembers |= other.invokesPackageVisibleMembers; } public static void setClassOptimizationInfo(Clazz clazz) { clazz.setVisitorInfo(new ClassOptimizationInfo()); } public static ClassOptimizationInfo getClassOptimizationInfo(Clazz clazz) { Object visitorInfo = clazz.getVisitorInfo(); return visitorInfo instanceof ClassOptimizationInfo ? (ClassOptimizationInfo)visitorInfo : null; } } proguard4.8/src/proguard/optimize/info/InstanceofClassMarker.java0000644000175000017500000000600211736333526024061 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.ClassConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** * This InstructionVisitor marks all classes that are used in an 'instanceof' * test by any of the instructions that it visits. * * @author Eric Lafortune */ public class InstanceofClassMarker extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor, ClassVisitor { // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { if (constantInstruction.opcode == InstructionConstants.OP_INSTANCEOF) { clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); } } // Implementations for ConstantVisitor. public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { classConstant.referencedClassAccept(this); } // Implementations for ClassVisitor. public void visitLibraryClass(LibraryClass libraryClass) {} public void visitProgramClass(ProgramClass programClass) { setInstanceofed(programClass); } // Small utility methods. private static void setInstanceofed(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); if (info != null) { info.setInstanceofed(); } } public static boolean isInstanceofed(Clazz clazz) { ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); return info == null || info.isInstanceofed(); } }proguard4.8/src/proguard/optimize/info/InstantiationClassFilter.java0000644000175000017500000000354211736333526024626 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor delegates all its method calls to another ClassVisitor, * but only for Clazz objects that are instantiated. * * @author Eric Lafortune */ public class InstantiationClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; public InstantiationClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (InstantiationClassMarker.isInstantiated(programClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (InstantiationClassMarker.isInstantiated(libraryClass)) { classVisitor.visitLibraryClass(libraryClass); } } }proguard4.8/src/proguard/optimize/info/CaughtClassFilter.java0000644000175000017500000000353411736333526023216 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor delegates all its method calls to another ClassVisitor, * but only for Clazz objects that are caught as exceptions. * * @see CaughtClassMarker * @author Eric Lafortune */ public class CaughtClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; public CaughtClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (CaughtClassMarker.isCaught(programClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (CaughtClassMarker.isCaught(libraryClass)) { classVisitor.visitLibraryClass(libraryClass); } } }proguard4.8/src/proguard/optimize/info/DotClassFilter.java0000644000175000017500000000353311736333526022530 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.visitor.ClassVisitor; /** * This ClassVisitor delegates all its method calls to another ClassVisitor, * but only for Clazz objects that are used in a .class construct. * * @see DotClassMarker * @author Eric Lafortune */ public class DotClassFilter implements ClassVisitor { private final ClassVisitor classVisitor; public DotClassFilter(ClassVisitor classVisitor) { this.classVisitor = classVisitor; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { if (DotClassMarker.isDotClassed(programClass)) { classVisitor.visitProgramClass(programClass); } } public void visitLibraryClass(LibraryClass libraryClass) { if (DotClassMarker.isDotClassed(libraryClass)) { classVisitor.visitLibraryClass(libraryClass); } } }proguard4.8/src/proguard/optimize/info/ExceptionInstructionChecker.java0000644000175000017500000001721411736333526025334 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize.info; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; import proguard.classfile.constant.RefConstant; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; /** * This class can tell whether an instruction might throw exceptions. * * @author Eric Lafortune */ public class ExceptionInstructionChecker extends SimplifiedVisitor implements InstructionVisitor // ConstantVisitor, // MemberVisitor { // A return value for the visitor methods. private boolean mayThrowExceptions; /** * Returns whether the given instruction may throw exceptions. */ public boolean mayThrowExceptions(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { mayThrowExceptions = false; instruction.accept(clazz, method, codeAttribute, offset, this); return mayThrowExceptions; } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { byte opcode = simpleInstruction.opcode; // Check for instructions that may throw exceptions. // Note that monitorexit can not sensibly throw exceptions, except the // broken and deprecated asynchronous ThreadDeath. Removing the // artificial infinite looping exception blocks that recent compilers // add does not strictly follow the JVM specs, but it does have the // additional benefit of avoiding a bug in the JVM in JDK 1.1. switch (opcode) { case InstructionConstants.OP_IDIV: case InstructionConstants.OP_LDIV: case InstructionConstants.OP_IREM: case InstructionConstants.OP_LREM: case InstructionConstants.OP_IALOAD: case InstructionConstants.OP_LALOAD: case InstructionConstants.OP_FALOAD: case InstructionConstants.OP_DALOAD: case InstructionConstants.OP_AALOAD: case InstructionConstants.OP_BALOAD: case InstructionConstants.OP_CALOAD: case InstructionConstants.OP_SALOAD: case InstructionConstants.OP_IASTORE: case InstructionConstants.OP_LASTORE: case InstructionConstants.OP_FASTORE: case InstructionConstants.OP_DASTORE: case InstructionConstants.OP_AASTORE: case InstructionConstants.OP_BASTORE: case InstructionConstants.OP_CASTORE: case InstructionConstants.OP_SASTORE: case InstructionConstants.OP_NEWARRAY: case InstructionConstants.OP_ARRAYLENGTH: case InstructionConstants.OP_ATHROW: case InstructionConstants.OP_MONITORENTER: // These instructions may throw exceptions. mayThrowExceptions = true; } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { byte opcode = constantInstruction.opcode; // Check for instructions that may throw exceptions. switch (opcode) { case InstructionConstants.OP_GETSTATIC: case InstructionConstants.OP_PUTSTATIC: case InstructionConstants.OP_GETFIELD: case InstructionConstants.OP_PUTFIELD: case InstructionConstants.OP_INVOKEVIRTUAL: case InstructionConstants.OP_INVOKESPECIAL: case InstructionConstants.OP_INVOKESTATIC: case InstructionConstants.OP_INVOKEINTERFACE: case InstructionConstants.OP_INVOKEDYNAMIC: case InstructionConstants.OP_NEW: case InstructionConstants.OP_ANEWARRAY: case InstructionConstants.OP_CHECKCAST: case InstructionConstants.OP_INSTANCEOF: case InstructionConstants.OP_MULTIANEWARRAY: // These instructions may throw exceptions. mayThrowExceptions = true; } // case InstructionConstants.OP_INVOKEVIRTUAL: // case InstructionConstants.OP_INVOKESPECIAL: // case InstructionConstants.OP_INVOKESTATIC: // case InstructionConstants.OP_INVOKEINTERFACE: // // Check if the invoking the method may throw an exception. // clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); } // // Implementations for ConstantVisitor. // // public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) // { // Member referencedMember = refConstant.referencedMember; // // // Do we have a reference to the method? // if (referencedMember == null) // { // // We'll have to assume invoking the unknown method may throw an // // an exception. // mayThrowExceptions = true; // } // else // { // // First check the referenced method itself. // refConstant.referencedMemberAccept(this); // // // If the result isn't conclusive, check down the hierarchy. // if (!mayThrowExceptions) // { // Clazz referencedClass = refConstant.referencedClass; // Method referencedMethod = (Method)referencedMember; // // // Check all other implementations of the method in the class // // hierarchy. // referencedClass.methodImplementationsAccept(referencedMethod, // false, // false, // true, // true, // this); // } // } // } // // // // Implementations for MemberVisitor. // // public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) // { // mayThrowExceptions = mayThrowExceptions || // ExceptionMethodMarker.mayThrowExceptions(programMethod); // } // // // public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) // { // mayThrowExceptions = mayThrowExceptions || // !NoExceptionMethodMarker.doesntThrowExceptions(libraryMethod); // } } proguard4.8/src/proguard/optimize/DuplicateInitializerInvocationFixer.java0000644000175000017500000001336711736333526026067 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; /** * This AttributeVisitor adds an additional integer parameter to the tweaked * initialization method invocations that it visits. */ public class DuplicateInitializerInvocationFixer extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, ConstantVisitor, MemberVisitor { private static final boolean DEBUG = false; private final InstructionVisitor extraAddedInstructionVisitor; private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); private String descriptor; private int descriptorLengthDelta; /** * Creates a new DuplicateInitializerInvocationFixer. */ public DuplicateInitializerInvocationFixer() { this(null); } /** * Creates a new DuplicateInitializerInvocationFixer. * @param extraAddedInstructionVisitor an optional extra visitor for all * added instructions. */ public DuplicateInitializerInvocationFixer(InstructionVisitor extraAddedInstructionVisitor) { this.extraAddedInstructionVisitor = extraAddedInstructionVisitor; } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Reset the code changes. codeAttributeEditor.reset(codeAttribute.u4codeLength); // Fix any duplicate constructor invocations. codeAttribute.instructionsAccept(clazz, method, this); // Apply all accumulated changes to the code. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } // Implementations for InstructionVisitor. public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { if (constantInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL) { descriptorLengthDelta = 0; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); if (descriptorLengthDelta > 0) { Instruction extraInstruction = new SimpleInstruction(descriptorLengthDelta == 1 ? InstructionConstants.OP_ICONST_0 : InstructionConstants.OP_ACONST_NULL); codeAttributeEditor.insertBeforeInstruction(offset, extraInstruction); if (DEBUG) { System.out.println(" ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] Inserting "+extraInstruction.toString()+" before "+constantInstruction.toString(offset)); } if (extraAddedInstructionVisitor != null) { extraInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor); } } } } // Implementations for ConstantVisitor. public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { // Check the referenced constructor descriptor. descriptor = methodrefConstant.getType(clazz); methodrefConstant.referencedMemberAccept(this); } // Implementations for MemberVisitor. public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {} public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { descriptorLengthDelta = programMethod.getDescriptor(programClass).length() - descriptor.length(); if (DEBUG) { if (descriptorLengthDelta > 0) { System.out.println("DuplicateInitializerInvocationFixer:"); System.out.println(" ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") referenced by:"); } } } } proguard4.8/src/proguard/optimize/DuplicateInitializerFixer.java0000644000175000017500000002075711736333526024036 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.optimize; import proguard.classfile.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.editor.ConstantPoolEditor; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; /** * This MemberVisitor adds an additional parameter to the duplicate * initialization methods that it visits. */ public class DuplicateInitializerFixer extends SimplifiedVisitor implements MemberVisitor, AttributeVisitor { private static final boolean DEBUG = false; private static final char[] TYPES = new char[] { ClassConstants.INTERNAL_TYPE_BYTE, ClassConstants.INTERNAL_TYPE_CHAR, ClassConstants.INTERNAL_TYPE_SHORT, ClassConstants.INTERNAL_TYPE_INT, ClassConstants.INTERNAL_TYPE_BOOLEAN }; private final MemberVisitor extraFixedInitializerVisitor; /** * Creates a new DuplicateInitializerFixer. */ public DuplicateInitializerFixer() { this(null); } /** * Creates a new DuplicateInitializerFixer with an extra visitor. * @param extraFixedInitializerVisitor an optional extra visitor for all * initializers that have been fixed. */ public DuplicateInitializerFixer(MemberVisitor extraFixedInitializerVisitor) { this.extraFixedInitializerVisitor = extraFixedInitializerVisitor; } // Implementations for MemberVisitor. public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { // Is it a class instance initializer? String name = programMethod.getName(programClass); if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) { // Is there already another initializer with the same descriptor? String descriptor = programMethod.getDescriptor(programClass); Method similarMethod = programClass.findMethod(name, descriptor); if (!programMethod.equals(similarMethod)) { // Should this initializer be preserved? if (KeepMarker.isKept(programMethod)) { // Fix the other initializer. programMethod = (ProgramMethod)similarMethod; } int index = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); // Try to find a new, unique descriptor. int typeCounter = 0; while (true) { // Construct the new descriptor by inserting a new type // as an additional last argument. StringBuffer newDescriptorBuffer = new StringBuffer(descriptor.substring(0, index)); for (int arrayDimension = 0; arrayDimension < typeCounter / TYPES.length; arrayDimension++) { newDescriptorBuffer.append(ClassConstants.INTERNAL_TYPE_ARRAY); } newDescriptorBuffer.append(TYPES[typeCounter % TYPES.length]); newDescriptorBuffer.append(descriptor.substring(index)); String newDescriptor = newDescriptorBuffer.toString(); // Is the new initializer descriptor unique? if (programClass.findMethod(name, newDescriptor) == null) { if (DEBUG) { System.out.println("DuplicateInitializerFixer:"); System.out.println(" ["+programClass.getName()+"."+name+descriptor+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") -> ["+newDescriptor+"]"); } // Update the descriptor. programMethod.u2descriptorIndex = new ConstantPoolEditor(programClass).addUtf8Constant(newDescriptor); // Fix the local variable frame size, the method // signature, and the parameter annotations, if // necessary. programMethod.attributesAccept(programClass, this); // Visit the initializer, if required. if (extraFixedInitializerVisitor != null) { extraFixedInitializerVisitor.visitProgramMethod(programClass, programMethod); } // We're done with this constructor. return; } typeCounter++; } } } } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // The minimum variable size is determined by the arguments. int maxLocals = ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), method.getAccessFlags()); if (codeAttribute.u2maxLocals < maxLocals) { codeAttribute.u2maxLocals = maxLocals; } } public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute) { String descriptor = method.getDescriptor(clazz); int descriptorIndex = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); String signature = clazz.getString(signatureAttribute.u2signatureIndex); int signatureIndex = signature.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); String newSignature = signature.substring(0, signatureIndex) + descriptor.charAt(descriptorIndex - 1) + signature.substring(signatureIndex); // Update the signature. signatureAttribute.u2signatureIndex = new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Update the number of parameters. int oldParametersCount = parameterAnnotationsAttribute.u2parametersCount++; if (parameterAnnotationsAttribute.u2parameterAnnotationsCount == null || parameterAnnotationsAttribute.u2parameterAnnotationsCount.length < parameterAnnotationsAttribute.u2parametersCount) { int[] annotationsCounts = new int[parameterAnnotationsAttribute.u2parametersCount]; Annotation[][] annotations = new Annotation[parameterAnnotationsAttribute.u2parametersCount][]; System.arraycopy(parameterAnnotationsAttribute.u2parameterAnnotationsCount, 0, annotationsCounts, 0, oldParametersCount); System.arraycopy(parameterAnnotationsAttribute.parameterAnnotations, 0, annotations, 0, oldParametersCount); parameterAnnotationsAttribute.u2parameterAnnotationsCount = annotationsCounts; parameterAnnotationsAttribute.parameterAnnotations = annotations; } } }proguard4.8/src/proguard/retrace/0000775000175000017500000000000011760503005015617 5ustar ericericproguard4.8/src/proguard/retrace/package.html0000644000175000017500000000020111736333526020103 0ustar ericeric This package contains the main ReTrace application. ReTrace can de-obfuscate stack traces of obfuscated programs. proguard4.8/src/proguard/retrace/MANIFEST.MF0000644000175000017500000000012411163773611017255 0ustar ericericManifest-Version: 1.0 Main-Class: proguard.retrace.ReTrace Class-Path: proguard.jar proguard4.8/src/proguard/retrace/ReTrace.java0000664000175000017500000006354311754047310020027 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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.retrace; import proguard.classfile.util.ClassUtil; import proguard.obfuscate.*; import java.io.*; import java.util.*; import java.util.regex.*; /** * Tool for de-obfuscating stack traces of applications that were obfuscated * with ProGuard. * * @author Eric Lafortune */ public class ReTrace implements MappingProcessor { private static final String REGEX_OPTION = "-regex"; private static final String VERBOSE_OPTION = "-verbose"; public static final String STACK_TRACE_EXPRESSION = "(?:.*?\\bat\\s+%c.%m\\s*\\(.*?(?::%l)?\\)\\s*)|(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)"; private static final String REGEX_CLASS = "\\b(?:[A-Za-z0-9_$]+\\.)*[A-Za-z0-9_$]+\\b"; private static final String REGEX_CLASS_SLASH = "\\b(?:[A-Za-z0-9_$]+/)*[A-Za-z0-9_$]+\\b"; private static final String REGEX_LINE_NUMBER = "\\b[0-9]+\\b"; private static final String REGEX_TYPE = REGEX_CLASS + "(?:\\[\\])*"; private static final String REGEX_MEMBER = "?"; private static final String REGEX_ARGUMENTS = "(?:" + REGEX_TYPE + "(?:\\s*,\\s*" + REGEX_TYPE + ")*)?"; // The class settings. private final String regularExpression; private final boolean verbose; private final File mappingFile; private final File stackTraceFile; private Map classMap = new HashMap(); private Map classFieldMap = new HashMap(); private Map classMethodMap = new HashMap(); /** * Creates a new ReTrace object to process stack traces on the standard * input, based on the given mapping file name. * @param regularExpression the regular expression for parsing the lines in * the stack trace. * @param verbose specifies whether the de-obfuscated stack trace * should be verbose. * @param mappingFile the mapping file that was written out by * ProGuard. */ public ReTrace(String regularExpression, boolean verbose, File mappingFile) { this(regularExpression, verbose, mappingFile, null); } /** * Creates a new ReTrace object to process a stack trace from the given file, * based on the given mapping file name. * @param regularExpression the regular expression for parsing the lines in * the stack trace. * @param verbose specifies whether the de-obfuscated stack trace * should be verbose. * @param mappingFile the mapping file that was written out by * ProGuard. * @param stackTraceFile the optional name of the file that contains the * stack trace. */ public ReTrace(String regularExpression, boolean verbose, File mappingFile, File stackTraceFile) { this.regularExpression = regularExpression; this.verbose = verbose; this.mappingFile = mappingFile; this.stackTraceFile = stackTraceFile; } /** * Performs the subsequent ReTrace operations. */ public void execute() throws IOException { // Read the mapping file. MappingReader mappingReader = new MappingReader(mappingFile); mappingReader.pump(this); StringBuffer expressionBuffer = new StringBuffer(regularExpression.length() + 32); char[] expressionTypes = new char[32]; int expressionTypeCount = 0; int index = 0; while (true) { int nextIndex = regularExpression.indexOf('%', index); if (nextIndex < 0 || nextIndex == regularExpression.length()-1 || expressionTypeCount == expressionTypes.length) { break; } expressionBuffer.append(regularExpression.substring(index, nextIndex)); expressionBuffer.append('('); char expressionType = regularExpression.charAt(nextIndex + 1); switch(expressionType) { case 'c': expressionBuffer.append(REGEX_CLASS); break; case 'C': expressionBuffer.append(REGEX_CLASS_SLASH); break; case 'l': expressionBuffer.append(REGEX_LINE_NUMBER); break; case 't': expressionBuffer.append(REGEX_TYPE); break; case 'f': expressionBuffer.append(REGEX_MEMBER); break; case 'm': expressionBuffer.append(REGEX_MEMBER); break; case 'a': expressionBuffer.append(REGEX_ARGUMENTS); break; } expressionBuffer.append(')'); expressionTypes[expressionTypeCount++] = expressionType; index = nextIndex + 2; } expressionBuffer.append(regularExpression.substring(index)); Pattern pattern = Pattern.compile(expressionBuffer.toString()); // Read the stack trace file. LineNumberReader reader = new LineNumberReader(stackTraceFile == null ? (Reader)new InputStreamReader(System.in) : (Reader)new BufferedReader(new FileReader(stackTraceFile))); try { StringBuffer outLine = new StringBuffer(256); List extraOutLines = new ArrayList(); String className = null; // Read the line in the stack trace. while (true) { String line = reader.readLine(); if (line == null) { break; } Matcher matcher = pattern.matcher(line); if (matcher.matches()) { int lineNumber = 0; String type = null; String arguments = null; // Figure out a class name, line number, type, and // arguments beforehand. for (int expressionTypeIndex = 0; expressionTypeIndex < expressionTypeCount; expressionTypeIndex++) { int startIndex = matcher.start(expressionTypeIndex + 1); if (startIndex >= 0) { String match = matcher.group(expressionTypeIndex + 1); char expressionType = expressionTypes[expressionTypeIndex]; switch (expressionType) { case 'c': className = originalClassName(match); break; case 'C': className = originalClassName(ClassUtil.externalClassName(match)); break; case 'l': lineNumber = Integer.parseInt(match); break; case 't': type = originalType(match); break; case 'a': arguments = originalArguments(match); break; } } } // Actually construct the output line. int lineIndex = 0; outLine.setLength(0); extraOutLines.clear(); for (int expressionTypeIndex = 0; expressionTypeIndex < expressionTypeCount; expressionTypeIndex++) { int startIndex = matcher.start(expressionTypeIndex + 1); if (startIndex >= 0) { int endIndex = matcher.end(expressionTypeIndex + 1); String match = matcher.group(expressionTypeIndex + 1); // Copy a literal piece of input line. outLine.append(line.substring(lineIndex, startIndex)); char expressionType = expressionTypes[expressionTypeIndex]; switch (expressionType) { case 'c': className = originalClassName(match); outLine.append(className); break; case 'C': className = originalClassName(ClassUtil.externalClassName(match)); outLine.append(ClassUtil.internalClassName(className)); break; case 'l': lineNumber = Integer.parseInt(match); outLine.append(match); break; case 't': type = originalType(match); outLine.append(type); break; case 'f': originalFieldName(className, match, type, outLine, extraOutLines); break; case 'm': originalMethodName(className, match, lineNumber, type, arguments, outLine, extraOutLines); break; case 'a': arguments = originalArguments(match); outLine.append(arguments); break; } // Skip the original element whose processed version // has just been appended. lineIndex = endIndex; } } // Copy the last literal piece of input line. outLine.append(line.substring(lineIndex)); // Print out the main line. System.out.println(outLine); // Print out any additional lines. for (int extraLineIndex = 0; extraLineIndex < extraOutLines.size(); extraLineIndex++) { System.out.println(extraOutLines.get(extraLineIndex)); } } else { // Print out the original line. System.out.println(line); } } } catch (IOException ex) { throw new IOException("Can't read stack trace (" + ex.getMessage() + ")"); } finally { if (stackTraceFile != null) { try { reader.close(); } catch (IOException ex) { // This shouldn't happen. } } } } /** * Finds the original field name(s), appending the first one to the out * line, and any additional alternatives to the extra lines. */ private void originalFieldName(String className, String obfuscatedFieldName, String type, StringBuffer outLine, List extraOutLines) { int extraIndent = -1; // Class name -> obfuscated field names. Map fieldMap = (Map)classFieldMap.get(className); if (fieldMap != null) { // Obfuscated field names -> fields. Set fieldSet = (Set)fieldMap.get(obfuscatedFieldName); if (fieldSet != null) { // Find all matching fields. Iterator fieldInfoIterator = fieldSet.iterator(); while (fieldInfoIterator.hasNext()) { FieldInfo fieldInfo = (FieldInfo)fieldInfoIterator.next(); if (fieldInfo.matches(type)) { // Is this the first matching field? if (extraIndent < 0) { extraIndent = outLine.length(); // Append the first original name. if (verbose) { outLine.append(fieldInfo.type).append(' '); } outLine.append(fieldInfo.originalName); } else { // Create an additional line with the proper // indentation. StringBuffer extraBuffer = new StringBuffer(); for (int counter = 0; counter < extraIndent; counter++) { extraBuffer.append(' '); } // Append the alternative name. if (verbose) { extraBuffer.append(fieldInfo.type).append(' '); } extraBuffer.append(fieldInfo.originalName); // Store the additional line. extraOutLines.add(extraBuffer); } } } } } // Just append the obfuscated name if we haven't found any matching // fields. if (extraIndent < 0) { outLine.append(obfuscatedFieldName); } } /** * Finds the original method name(s), appending the first one to the out * line, and any additional alternatives to the extra lines. */ private void originalMethodName(String className, String obfuscatedMethodName, int lineNumber, String type, String arguments, StringBuffer outLine, List extraOutLines) { int extraIndent = -1; // Class name -> obfuscated method names. Map methodMap = (Map)classMethodMap.get(className); if (methodMap != null) { // Obfuscated method names -> methods. Set methodSet = (Set)methodMap.get(obfuscatedMethodName); if (methodSet != null) { // Find all matching methods. Iterator methodInfoIterator = methodSet.iterator(); while (methodInfoIterator.hasNext()) { MethodInfo methodInfo = (MethodInfo)methodInfoIterator.next(); if (methodInfo.matches(lineNumber, type, arguments)) { // Is this the first matching method? if (extraIndent < 0) { extraIndent = outLine.length(); // Append the first original name. if (verbose) { outLine.append(methodInfo.type).append(' '); } outLine.append(methodInfo.originalName); if (verbose) { outLine.append('(').append(methodInfo.arguments).append(')'); } } else { // Create an additional line with the proper // indentation. StringBuffer extraBuffer = new StringBuffer(); for (int counter = 0; counter < extraIndent; counter++) { extraBuffer.append(' '); } // Append the alternative name. if (verbose) { extraBuffer.append(methodInfo.type).append(' '); } extraBuffer.append(methodInfo.originalName); if (verbose) { extraBuffer.append('(').append(methodInfo.arguments).append(')'); } // Store the additional line. extraOutLines.add(extraBuffer); } } } } } // Just append the obfuscated name if we haven't found any matching // methods. if (extraIndent < 0) { outLine.append(obfuscatedMethodName); } } /** * Returns the original argument types. */ private String originalArguments(String obfuscatedArguments) { StringBuffer originalArguments = new StringBuffer(); int startIndex = 0; while (true) { int endIndex = obfuscatedArguments.indexOf(',', startIndex); if (endIndex < 0) { break; } originalArguments.append(originalType(obfuscatedArguments.substring(startIndex, endIndex).trim())).append(','); startIndex = endIndex + 1; } originalArguments.append(originalType(obfuscatedArguments.substring(startIndex).trim())); return originalArguments.toString(); } /** * Returns the original type. */ private String originalType(String obfuscatedType) { int index = obfuscatedType.indexOf('['); return index >= 0 ? originalClassName(obfuscatedType.substring(0, index)) + obfuscatedType.substring(index) : originalClassName(obfuscatedType); } /** * Returns the original class name. */ private String originalClassName(String obfuscatedClassName) { String originalClassName = (String)classMap.get(obfuscatedClassName); return originalClassName != null ? originalClassName : obfuscatedClassName; } // Implementations for MappingProcessor. public boolean processClassMapping(String className, String newClassName) { // Obfuscated class name -> original class name. classMap.put(newClassName, className); return true; } public void processFieldMapping(String className, String fieldType, String fieldName, String newFieldName) { // Original class name -> obfuscated field names. Map fieldMap = (Map)classFieldMap.get(className); if (fieldMap == null) { fieldMap = new HashMap(); classFieldMap.put(className, fieldMap); } // Obfuscated field name -> fields. Set fieldSet = (Set)fieldMap.get(newFieldName); if (fieldSet == null) { fieldSet = new LinkedHashSet(); fieldMap.put(newFieldName, fieldSet); } // Add the field information. fieldSet.add(new FieldInfo(fieldType, fieldName)); } public void processMethodMapping(String className, int firstLineNumber, int lastLineNumber, String methodReturnType, String methodName, String methodArguments, String newMethodName) { // Original class name -> obfuscated method names. Map methodMap = (Map)classMethodMap.get(className); if (methodMap == null) { methodMap = new HashMap(); classMethodMap.put(className, methodMap); } // Obfuscated method name -> methods. Set methodSet = (Set)methodMap.get(newMethodName); if (methodSet == null) { methodSet = new LinkedHashSet(); methodMap.put(newMethodName, methodSet); } // Add the method information. methodSet.add(new MethodInfo(firstLineNumber, lastLineNumber, methodReturnType, methodArguments, methodName)); } /** * A field record. */ private static class FieldInfo { private String type; private String originalName; private FieldInfo(String type, String originalName) { this.type = type; this.originalName = originalName; } private boolean matches(String type) { return type == null || type.equals(this.type); } } /** * A method record. */ private static class MethodInfo { private int firstLineNumber; private int lastLineNumber; private String type; private String arguments; private String originalName; private MethodInfo(int firstLineNumber, int lastLineNumber, String type, String arguments, String originalName) { this.firstLineNumber = firstLineNumber; this.lastLineNumber = lastLineNumber; this.type = type; this.arguments = arguments; this.originalName = originalName; } private boolean matches(int lineNumber, String type, String arguments) { return (lineNumber == 0 || (firstLineNumber <= lineNumber && lineNumber <= lastLineNumber) || lastLineNumber == 0) && (type == null || type.equals(this.type)) && (arguments == null || arguments.equals(this.arguments)); } } /** * The main program for ReTrace. */ public static void main(String[] args) { if (args.length < 1) { System.err.println("Usage: java proguard.ReTrace [-verbose] []"); System.exit(-1); } String regularExpresssion = STACK_TRACE_EXPRESSION; boolean verbose = false; int argumentIndex = 0; while (argumentIndex < args.length) { String arg = args[argumentIndex]; if (arg.equals(REGEX_OPTION)) { regularExpresssion = args[++argumentIndex]; } else if (arg.equals(VERBOSE_OPTION)) { verbose = true; } else { break; } argumentIndex++; } if (argumentIndex >= args.length) { System.err.println("Usage: java proguard.ReTrace [-regex ] [-verbose] []"); System.exit(-1); } File mappingFile = new File(args[argumentIndex++]); File stackTraceFile = argumentIndex < args.length ? new File(args[argumentIndex]) : null; ReTrace reTrace = new ReTrace(regularExpresssion, verbose, mappingFile, stackTraceFile); try { // Execute ReTrace with its given settings. reTrace.execute(); } catch (IOException ex) { if (verbose) { // Print a verbose stack trace. ex.printStackTrace(); } else { // Print just the stack trace message. System.err.println("Error: "+ex.getMessage()); } System.exit(1); } System.exit(0); } } proguard4.8/src/proguard/ProGuard.java0000664000175000017500000003136011757712477016610 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.ClassPool; import proguard.classfile.editor.ClassElementSorter; import proguard.classfile.visitor.*; import proguard.obfuscate.Obfuscator; import proguard.optimize.*; import proguard.preverify.*; import proguard.shrink.Shrinker; import java.io.*; import java.util.Properties; /** * Tool for shrinking, optimizing, obfuscating, and preverifying Java classes. * * @author Eric Lafortune */ public class ProGuard { public static final String VERSION = "ProGuard, version 4.8"; private final Configuration configuration; private ClassPool programClassPool = new ClassPool(); private final ClassPool libraryClassPool = new ClassPool(); /** * Creates a new ProGuard object to process jars as specified by the given * configuration. */ public ProGuard(Configuration configuration) { this.configuration = configuration; } /** * Performs all subsequent ProGuard operations. */ public void execute() throws IOException { System.out.println(VERSION); GPL.check(); if (configuration.printConfiguration != null) { printConfiguration(); } if (configuration.programJars != null && configuration.programJars.hasOutput() && new UpToDateChecker(configuration).check()) { return; } readInput(); if (configuration.printSeeds != null || configuration.shrink || configuration.optimize || configuration.obfuscate || configuration.preverify) { initialize(); } if (configuration.targetClassVersion != 0) { target(); } if (configuration.printSeeds != null) { printSeeds(); } if (configuration.shrink) { shrink(); } if (configuration.preverify) { inlineSubroutines(); } if (configuration.optimize) { for (int optimizationPass = 0; optimizationPass < configuration.optimizationPasses; optimizationPass++) { if (!optimize()) { // Stop optimizing if the code doesn't improve any further. break; } // Shrink again, if we may. if (configuration.shrink) { // Don't print any usage this time around. configuration.printUsage = null; configuration.whyAreYouKeeping = null; shrink(); } } } if (configuration.obfuscate) { obfuscate(); } if (configuration.preverify) { preverify(); } if (configuration.shrink || configuration.optimize || configuration.obfuscate || configuration.preverify) { sortClassElements(); } if (configuration.programJars.hasOutput()) { writeOutput(); } if (configuration.dump != null) { dump(); } } /** * Prints out the configuration that ProGuard is using. */ private void printConfiguration() throws IOException { if (configuration.verbose) { System.out.println("Printing configuration to [" + fileName(configuration.printConfiguration) + "]..."); } PrintStream ps = createPrintStream(configuration.printConfiguration); try { new ConfigurationWriter(ps).write(configuration); } finally { closePrintStream(ps); } } /** * Reads the input class files. */ private void readInput() throws IOException { if (configuration.verbose) { System.out.println("Reading input..."); } // Fill the program class pool and the library class pool. new InputReader(configuration).execute(programClassPool, libraryClassPool); } /** * Initializes the cross-references between all classes, performs some * basic checks, and shrinks the library class pool. */ private void initialize() throws IOException { if (configuration.verbose) { System.out.println("Initializing..."); } new Initializer(configuration).execute(programClassPool, libraryClassPool); } /** * Sets that target versions of the program classes. */ private void target() throws IOException { if (configuration.verbose) { System.out.println("Setting target versions..."); } new Targeter(configuration).execute(programClassPool); } /** * Prints out classes and class members that are used as seeds in the * shrinking and obfuscation steps. */ private void printSeeds() throws IOException { if (configuration.verbose) { System.out.println("Printing kept classes, fields, and methods..."); } PrintStream ps = createPrintStream(configuration.printSeeds); try { new SeedPrinter(ps).write(configuration, programClassPool, libraryClassPool); } finally { closePrintStream(ps); } } /** * Performs the shrinking step. */ private void shrink() throws IOException { if (configuration.verbose) { System.out.println("Shrinking..."); // We'll print out some explanation, if requested. if (configuration.whyAreYouKeeping != null) { System.out.println("Explaining why classes and class members are being kept..."); } // We'll print out the usage, if requested. if (configuration.printUsage != null) { System.out.println("Printing usage to [" + fileName(configuration.printUsage) + "]..."); } } // Perform the actual shrinking. programClassPool = new Shrinker(configuration).execute(programClassPool, libraryClassPool); } /** * Performs the subroutine inlining step. */ private void inlineSubroutines() { if (configuration.verbose) { System.out.println("Inlining subroutines..."); } // Perform the actual inlining. new SubroutineInliner(configuration).execute(programClassPool); } /** * Performs the optimization step. */ private boolean optimize() throws IOException { if (configuration.verbose) { System.out.println("Optimizing..."); } // Perform the actual optimization. return new Optimizer(configuration).execute(programClassPool, libraryClassPool); } /** * Performs the obfuscation step. */ private void obfuscate() throws IOException { if (configuration.verbose) { System.out.println("Obfuscating..."); // We'll apply a mapping, if requested. if (configuration.applyMapping != null) { System.out.println("Applying mapping [" + fileName(configuration.applyMapping) + "]"); } // We'll print out the mapping, if requested. if (configuration.printMapping != null) { System.out.println("Printing mapping to [" + fileName(configuration.printMapping) + "]..."); } } // Perform the actual obfuscation. new Obfuscator(configuration).execute(programClassPool, libraryClassPool); } /** * Performs the preverification step. */ private void preverify() { if (configuration.verbose) { System.out.println("Preverifying..."); } // Perform the actual preverification. new Preverifier(configuration).execute(programClassPool); } /** * Sorts the elements of all program classes. */ private void sortClassElements() { programClassPool.classesAccept(new ClassElementSorter()); } /** * Writes the output class files. */ private void writeOutput() throws IOException { if (configuration.verbose) { System.out.println("Writing output..."); } // Write out the program class pool. new OutputWriter(configuration).execute(programClassPool); } /** * Prints out the contents of the program classes. */ private void dump() throws IOException { if (configuration.verbose) { System.out.println("Printing classes to [" + fileName(configuration.dump) + "]..."); } PrintStream ps = createPrintStream(configuration.dump); try { programClassPool.classesAccept(new ClassPrinter(ps)); } finally { closePrintStream(ps); } } /** * Returns a print stream for the given file, or the standard output if * the file name is empty. */ private PrintStream createPrintStream(File file) throws FileNotFoundException { return isFile(file) ? new PrintStream(new BufferedOutputStream(new FileOutputStream(file))) : System.out; } /** * Closes the given print stream, or closes it if is the standard output. * @param printStream */ private void closePrintStream(PrintStream printStream) { if (printStream == System.out) { printStream.flush(); } else { printStream.close(); } } /** * Returns the canonical file name for the given file, or "standard output" * if the file name is empty. */ private String fileName(File file) { if (isFile(file)) { try { return file.getCanonicalPath(); } catch (IOException ex) { return file.getPath(); } } else { return "standard output"; } } /** * Returns whether the given file is actually a file, or just a placeholder * for the standard output. */ private boolean isFile(File file) { return file.getPath().length() > 0; } /** * The main method for ProGuard. */ public static void main(String[] args) { if (args.length == 0) { System.out.println(VERSION); System.out.println("Usage: java proguard.ProGuard [options ...]"); System.exit(1); } // Create the default options. Configuration configuration = new Configuration(); try { // Parse the options specified in the command line arguments. ConfigurationParser parser = new ConfigurationParser(args, System.getProperties()); try { parser.parse(configuration); } finally { parser.close(); } // Execute ProGuard with these options. new ProGuard(configuration).execute(); } catch (Exception ex) { if (configuration.verbose) { // Print a verbose stack trace. ex.printStackTrace(); } else { // Print just the stack trace message. System.err.println("Error: "+ex.getMessage()); } System.exit(1); } System.exit(0); } } proguard4.8/src/proguard/Initializer.java0000644000175000017500000004560611753221101017325 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.ClassPool; import proguard.classfile.attribute.visitor.AllAttributeVisitor; import proguard.classfile.constant.visitor.*; import proguard.classfile.instruction.visitor.AllInstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.util.*; import java.io.IOException; import java.util.*; /** * This class initializes class pools. * * @author Eric Lafortune */ public class Initializer { private final Configuration configuration; /** * Creates a new Initializer to initialize classes according to the given * configuration. */ public Initializer(Configuration configuration) { this.configuration = configuration; } /** * Initializes the classes in the given program class pool and library class * pool, performs some basic checks, and shrinks the library class pool. */ public void execute(ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { int originalLibraryClassPoolSize = libraryClassPool.size(); // Perform a basic check on the keep options in the configuration. WarningPrinter keepClassMemberNotePrinter = new WarningPrinter(System.out, configuration.note); new KeepClassMemberChecker(keepClassMemberNotePrinter).checkClassSpecifications(configuration.keep); // Construct a reduced library class pool with only those library // classes whose hierarchies are referenced by the program classes. // We can't do this if we later have to come up with the obfuscated // class member names that are globally unique. ClassPool reducedLibraryClassPool = configuration.useUniqueClassMemberNames ? null : new ClassPool(); WarningPrinter classReferenceWarningPrinter = new WarningPrinter(System.err, configuration.warn); WarningPrinter dependencyWarningPrinter = new WarningPrinter(System.err, configuration.warn); // Initialize the superclass hierarchies for program classes. programClassPool.classesAccept( new ClassSuperHierarchyInitializer(programClassPool, libraryClassPool, classReferenceWarningPrinter, null)); // Initialize the superclass hierarchy of all library classes, without // warnings. libraryClassPool.classesAccept( new ClassSuperHierarchyInitializer(programClassPool, libraryClassPool, null, dependencyWarningPrinter)); // Initialize the class references of program class members and // attributes. Note that all superclass hierarchies have to be // initialized for this purpose. WarningPrinter memberReferenceWarningPrinter = new WarningPrinter(System.err, configuration.warn); programClassPool.classesAccept( new ClassReferenceInitializer(programClassPool, libraryClassPool, classReferenceWarningPrinter, memberReferenceWarningPrinter, null)); if (reducedLibraryClassPool != null) { // Collect the library classes that are directly referenced by // program classes, without introspection. programClassPool.classesAccept( new ReferencedClassVisitor( new LibraryClassFilter( new ClassPoolFiller(reducedLibraryClassPool)))); // Reinitialize the superclass hierarchies of referenced library // classes, this time with warnings. reducedLibraryClassPool.classesAccept( new ClassSuperHierarchyInitializer(programClassPool, libraryClassPool, classReferenceWarningPrinter, null)); } // Initialize the Class.forName references. WarningPrinter dynamicClassReferenceNotePrinter = new WarningPrinter(System.out, configuration.note); WarningPrinter classForNameNotePrinter = new WarningPrinter(System.out, configuration.note); programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new AllInstructionVisitor( new DynamicClassReferenceInitializer(programClassPool, libraryClassPool, dynamicClassReferenceNotePrinter, null, classForNameNotePrinter, createClassNoteExceptionMatcher(configuration.keep)))))); // Initialize the Class.get[Declared]{Field,Method} references. WarningPrinter getMemberNotePrinter = new WarningPrinter(System.out, configuration.note); programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new AllInstructionVisitor( new DynamicMemberReferenceInitializer(programClassPool, libraryClassPool, getMemberNotePrinter, createClassMemberNoteExceptionMatcher(configuration.keep, true), createClassMemberNoteExceptionMatcher(configuration.keep, false)))))); // Initialize other string constant references, if requested. if (configuration.adaptClassStrings != null) { programClassPool.classesAccept( new ClassNameFilter(configuration.adaptClassStrings, new AllConstantVisitor( new StringReferenceInitializer(programClassPool, libraryClassPool)))); } // Print various notes, if specified. WarningPrinter fullyQualifiedClassNameNotePrinter = new WarningPrinter(System.out, configuration.note); WarningPrinter descriptorKeepNotePrinter = new WarningPrinter(System.out, configuration.note); new FullyQualifiedClassNameChecker(programClassPool, libraryClassPool, fullyQualifiedClassNameNotePrinter).checkClassSpecifications(configuration.keep); new DescriptorKeepChecker(programClassPool, libraryClassPool, descriptorKeepNotePrinter).checkClassSpecifications(configuration.keep); // Initialize the class references of library class members. if (reducedLibraryClassPool != null) { // Collect the library classes that are referenced by program // classes, directly or indirectly, with or without introspection. programClassPool.classesAccept( new ReferencedClassVisitor( new LibraryClassFilter( new ClassHierarchyTraveler(true, true, true, false, new LibraryClassFilter( new ClassPoolFiller(reducedLibraryClassPool)))))); // Initialize the class references of referenced library // classes, without warnings. reducedLibraryClassPool.classesAccept( new ClassReferenceInitializer(programClassPool, libraryClassPool, null, null, dependencyWarningPrinter)); // Reset the library class pool. libraryClassPool.clear(); // Copy the library classes that are referenced directly by program // classes and the library classes that are referenced by referenced // library classes. reducedLibraryClassPool.classesAccept( new MultiClassVisitor(new ClassVisitor[] { new ClassHierarchyTraveler(true, true, true, false, new LibraryClassFilter( new ClassPoolFiller(libraryClassPool))), new ReferencedClassVisitor( new LibraryClassFilter( new ClassHierarchyTraveler(true, true, true, false, new LibraryClassFilter( new ClassPoolFiller(libraryClassPool))))) })); } else { // Initialize the class references of all library class members. libraryClassPool.classesAccept( new ClassReferenceInitializer(programClassPool, libraryClassPool, null, null, dependencyWarningPrinter)); } // Initialize the subclass hierarchies. programClassPool.classesAccept(new ClassSubHierarchyInitializer()); libraryClassPool.classesAccept(new ClassSubHierarchyInitializer()); // Share strings between the classes, to reduce heap memory usage. programClassPool.classesAccept(new StringSharer()); libraryClassPool.classesAccept(new StringSharer()); // Print out a summary of the notes, if necessary. int fullyQualifiedNoteCount = fullyQualifiedClassNameNotePrinter.getWarningCount(); if (fullyQualifiedNoteCount > 0) { System.out.println("Note: there were " + fullyQualifiedNoteCount + " references to unknown classes."); System.out.println(" You should check your configuration for typos."); } int descriptorNoteCount = descriptorKeepNotePrinter.getWarningCount(); if (descriptorNoteCount > 0) { System.out.println("Note: there were " + descriptorNoteCount + " unkept descriptor classes in kept class members."); System.out.println(" You should consider explicitly keeping the mentioned classes"); System.out.println(" (using '-keep')."); } int dynamicClassReferenceNoteCount = dynamicClassReferenceNotePrinter.getWarningCount(); if (dynamicClassReferenceNoteCount > 0) { System.out.println("Note: there were " + dynamicClassReferenceNoteCount + " unresolved dynamic references to classes or interfaces."); System.out.println(" You should check if you need to specify additional program jars."); } int classForNameNoteCount = classForNameNotePrinter.getWarningCount(); if (classForNameNoteCount > 0) { System.out.println("Note: there were " + classForNameNoteCount + " class casts of dynamically created class instances."); System.out.println(" You might consider explicitly keeping the mentioned classes and/or"); System.out.println(" their implementations (using '-keep')."); } int getmemberNoteCount = getMemberNotePrinter.getWarningCount(); if (getmemberNoteCount > 0) { System.out.println("Note: there were " + getmemberNoteCount + " accesses to class members by means of introspection."); System.out.println(" You should consider explicitly keeping the mentioned class members"); System.out.println(" (using '-keep' or '-keepclassmembers')."); } // Print out a summary of the warnings, if necessary. int classReferenceWarningCount = classReferenceWarningPrinter.getWarningCount(); if (classReferenceWarningCount > 0) { System.err.println("Warning: there were " + classReferenceWarningCount + " unresolved references to classes or interfaces."); System.err.println(" You may need to specify additional library jars (using '-libraryjars')."); if (configuration.skipNonPublicLibraryClasses) { System.err.println(" You may also have to remove the option '-skipnonpubliclibraryclasses'."); } } int dependencyWarningCount = dependencyWarningPrinter.getWarningCount(); if (dependencyWarningCount > 0) { System.err.println("Warning: there were " + dependencyWarningCount + " instances of library classes depending on program classes."); System.err.println(" You must avoid such dependencies, since the program classes will"); System.err.println(" be processed, while the library classes will remain unchanged."); } int memberReferenceWarningCount = memberReferenceWarningPrinter.getWarningCount(); if (memberReferenceWarningCount > 0) { System.err.println("Warning: there were " + memberReferenceWarningCount + " unresolved references to program class members."); System.err.println(" Your input classes appear to be inconsistent."); System.err.println(" You may need to recompile them and try again."); System.err.println(" Alternatively, you may have to specify the option "); System.err.println(" '-dontskipnonpubliclibraryclassmembers'."); if (configuration.skipNonPublicLibraryClasses) { System.err.println(" You may also have to remove the option '-skipnonpubliclibraryclasses'."); } } if ((classReferenceWarningCount > 0 || dependencyWarningCount > 0 || memberReferenceWarningCount > 0) && !configuration.ignoreWarnings) { throw new IOException("Please correct the above warnings first."); } if ((configuration.note == null || !configuration.note.isEmpty()) && (configuration.warn != null && configuration.warn.isEmpty() || configuration.ignoreWarnings)) { System.out.println("Note: You're ignoring all warnings!"); } // Discard unused library classes. if (configuration.verbose) { System.out.println("Ignoring unused library classes..."); System.out.println(" Original number of library classes: " + originalLibraryClassPoolSize); System.out.println(" Final number of library classes: " + libraryClassPool.size()); } } /** * Extracts a list of exceptions of classes for which not to print notes, * from the keep configuration. */ private StringMatcher createClassNoteExceptionMatcher(List noteExceptions) { if (noteExceptions != null) { List noteExceptionNames = new ArrayList(noteExceptions.size()); for (int index = 0; index < noteExceptions.size(); index++) { KeepClassSpecification keepClassSpecification = (KeepClassSpecification)noteExceptions.get(index); if (keepClassSpecification.markClasses) { // If the class itself is being kept, it's ok. String className = keepClassSpecification.className; if (className != null) { noteExceptionNames.add(className); } // If all of its extensions are being kept, it's ok too. String extendsClassName = keepClassSpecification.extendsClassName; if (extendsClassName != null) { noteExceptionNames.add(extendsClassName); } } } if (noteExceptionNames.size() > 0) { return new ListParser(new ClassNameParser()).parse(noteExceptionNames); } } return null; } /** * Extracts a list of exceptions of field or method names for which not to * print notes, from the keep configuration. */ private StringMatcher createClassMemberNoteExceptionMatcher(List noteExceptions, boolean isField) { if (noteExceptions != null) { List noteExceptionNames = new ArrayList(); for (int index = 0; index < noteExceptions.size(); index++) { KeepClassSpecification keepClassSpecification = (KeepClassSpecification)noteExceptions.get(index); List memberSpecifications = isField ? keepClassSpecification.fieldSpecifications : keepClassSpecification.methodSpecifications; if (memberSpecifications != null) { for (int index2 = 0; index2 < memberSpecifications.size(); index2++) { MemberSpecification memberSpecification = (MemberSpecification)memberSpecifications.get(index2); String memberName = memberSpecification.name; if (memberName != null) { noteExceptionNames.add(memberName); } } } } if (noteExceptionNames.size() > 0) { return new ListParser(new ClassNameParser()).parse(noteExceptionNames); } } return null; } } proguard4.8/src/proguard/KeepClassSpecification.java0000644000175000017500000001256311736333526021431 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; /** * This class represents a keep option with class specification. * * @author Eric Lafortune */ public class KeepClassSpecification extends ClassSpecification { public final boolean markClasses; public final boolean markConditionally; public final boolean allowShrinking; public final boolean allowOptimization; public final boolean allowObfuscation; /** * Creates a new KeepClassSpecification for all possible classes. * @param markClasses specifies whether to mark the classes. * If false, only class members are marked. * If true, the classes are marked as well. * @param markConditionally specifies whether to mark the classes and * class members conditionally. If true, classes * and class members are marked, on the condition * that all specified class members are present. * @param allowShrinking specifies whether shrinking is allowed. * @param allowOptimization specifies whether optimization is allowed. * @param allowObfuscation specifies whether obfuscation is allowed. */ public KeepClassSpecification(boolean markClasses, boolean markConditionally, boolean allowShrinking, boolean allowOptimization, boolean allowObfuscation) { this.markClasses = markClasses; this.markConditionally = markConditionally; this.allowShrinking = allowShrinking; this.allowOptimization = allowOptimization; this.allowObfuscation = allowObfuscation; } /** * Creates a new KeepClassSpecification. * @param markClasses specifies whether to mark the classes. * If false, only class members are marked. * If true, the classes are marked as well. * @param markConditionally specifies whether to mark the classes and * class members conditionally. If true, classes * and class members are marked, on the condition * that all specified class members are present. * @param allowShrinking specifies whether shrinking is allowed. * @param allowOptimization specifies whether optimization is allowed. * @param allowObfuscation specifies whether obfuscation is allowed. * @param classSpecification the specification of classes and class members. */ public KeepClassSpecification(boolean markClasses, boolean markConditionally, boolean allowShrinking, boolean allowOptimization, boolean allowObfuscation, ClassSpecification classSpecification) { super(classSpecification); this.markClasses = markClasses; this.markConditionally = markConditionally; this.allowShrinking = allowShrinking; this.allowOptimization = allowOptimization; this.allowObfuscation = allowObfuscation; } // Implementations for Object. public boolean equals(Object object) { if (object == null || this.getClass() != object.getClass()) { return false; } KeepClassSpecification other = (KeepClassSpecification)object; return this.markClasses == other.markClasses && this.markConditionally == other.markConditionally && this.allowShrinking == other.allowShrinking && this.allowOptimization == other.allowOptimization && this.allowObfuscation == other.allowObfuscation && super.equals(other); } public int hashCode() { return (markClasses ? 0 : 1) ^ (markConditionally ? 0 : 2) ^ (allowShrinking ? 0 : 4) ^ (allowOptimization ? 0 : 8) ^ (allowObfuscation ? 0 : 16) ^ super.hashCode(); } public Object clone() { // try // { return super.clone(); // } // catch (CloneNotSupportedException e) // { // return null; // } } } proguard4.8/src/proguard/ClassPathEntry.java0000664000175000017500000001547111736333526017765 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.util.ListUtil; import java.io.*; import java.util.List; /** * This class represents an entry from a class path: a jar, a war, a zip, an * ear, or a directory, with a name and a flag to indicates whether the entry is * an input entry or an output entry. Optional filters can be specified for the * names of the contained resource/classes, jars, wars, ears, and zips. * * @author Eric Lafortune */ public class ClassPathEntry { private File file; private boolean output; private List filter; private List jarFilter; private List warFilter; private List earFilter; private List zipFilter; /** * Creates a new ClassPathEntry with the given file and output flag. */ public ClassPathEntry(File file, boolean isOutput) { this.file = file; this.output = isOutput; } /** * Returns the path name of the entry. */ public String getName() { try { return file.getCanonicalPath(); } catch (IOException ex) { return file.getPath(); } } /** * Returns the file. */ public File getFile() { return file; } /** * Sets the file. */ public void setFile(File file) { this.file = file; } /** * Returns whether this data entry is an output entry. */ public boolean isOutput() { return output; } /** * Specifies whether this data entry is an output entry. */ public void setOutput(boolean output) { this.output = output; } /** * Returns whether this data entry is a jar file. */ public boolean isJar() { return hasExtension(".jar"); } /** * Returns whether this data entry is a war file. */ public boolean isWar() { return hasExtension(".war"); } /** * Returns whether this data entry is a ear file. */ public boolean isEar() { return hasExtension(".ear"); } /** * Returns whether this data entry is a zip file. */ public boolean isZip() { return hasExtension(".zip"); } /** * Returns whether this data entry has the given extension. */ private boolean hasExtension(String extension) { return endsWithIgnoreCase(file.getPath(), extension); } /** * Returns whether the given string ends with the given suffix, ignoring * its case. */ private static boolean endsWithIgnoreCase(String string, String suffix) { int stringLength = string.length(); int suffixLength = suffix.length(); return string.regionMatches(true, stringLength - suffixLength, suffix, 0, suffixLength); } /** * Returns the name filter that is applied to bottom-level files in this entry. */ public List getFilter() { return filter; } /** * Sets the name filter that is applied to bottom-level files in this entry. */ public void setFilter(List filter) { this.filter = filter == null || filter.size() == 0 ? null : filter; } /** * Returns the name filter that is applied to jar files in this entry, if any. */ public List getJarFilter() { return jarFilter; } /** * Sets the name filter that is applied to jar files in this entry, if any. */ public void setJarFilter(List filter) { this.jarFilter = filter == null || filter.size() == 0 ? null : filter; } /** * Returns the name filter that is applied to war files in this entry, if any. */ public List getWarFilter() { return warFilter; } /** * Sets the name filter that is applied to war files in this entry, if any. */ public void setWarFilter(List filter) { this.warFilter = filter == null || filter.size() == 0 ? null : filter; } /** * Returns the name filter that is applied to ear files in this entry, if any. */ public List getEarFilter() { return earFilter; } /** * Sets the name filter that is applied to ear files in this entry, if any. */ public void setEarFilter(List filter) { this.earFilter = filter == null || filter.size() == 0 ? null : filter; } /** * Returns the name filter that is applied to zip files in this entry, if any. */ public List getZipFilter() { return zipFilter; } /** * Sets the name filter that is applied to zip files in this entry, if any. */ public void setZipFilter(List filter) { this.zipFilter = filter == null || filter.size() == 0 ? null : filter; } // Implementations for Object. public String toString() { String string = getName(); if (filter != null || jarFilter != null || warFilter != null || earFilter != null || zipFilter != null) { string += ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD + (zipFilter != null ? ListUtil.commaSeparatedString(zipFilter, true) : "") + ConfigurationConstants.SEPARATOR_KEYWORD + (earFilter != null ? ListUtil.commaSeparatedString(earFilter, true) : "") + ConfigurationConstants.SEPARATOR_KEYWORD + (warFilter != null ? ListUtil.commaSeparatedString(warFilter, true) : "") + ConfigurationConstants.SEPARATOR_KEYWORD + (jarFilter != null ? ListUtil.commaSeparatedString(jarFilter, true) : "") + ConfigurationConstants.SEPARATOR_KEYWORD + (filter != null ? ListUtil.commaSeparatedString(filter, true) : "") + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD; } return string; } } proguard4.8/src/proguard/SeedPrinter.java0000644000175000017500000000720111736333526017273 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2012 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; import proguard.classfile.ClassPool; import proguard.classfile.attribute.visitor.AllAttributeVisitor; import proguard.classfile.constant.visitor.AllConstantVisitor; import proguard.classfile.instruction.visitor.AllInstructionVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; import proguard.optimize.*; import proguard.util.*; import java.io.*; import java.util.*; /** * This class prints out the seeds specified by keep options. * * @author Eric Lafortune */ public class SeedPrinter { private final PrintStream ps; /** * Creates a new ConfigurationWriter for the given PrintStream. */ public SeedPrinter(PrintStream ps) throws IOException { this.ps = ps; } /** * Prints out the seeds for the classes in the given program class pool. * @param configuration the configuration containing the keep options. * @throws IOException if an IO error occurs while writing the configuration. */ public void write(Configuration configuration, ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { // Check if we have at least some keep commands. if (configuration.keep == null) { throw new IOException("You have to specify '-keep' options for the shrinking step."); } // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); libraryClassPool.classesAccept(new ClassCleaner()); // Create a visitor for printing out the seeds. We're printing out // the program elements that are preserved against shrinking, // optimization, or obfuscation. KeepMarker keepMarker = new KeepMarker(); ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, keepMarker, keepMarker, true, true, true); // Mark the seeds. programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); // Print out the seeds. SimpleClassPrinter printer = new SimpleClassPrinter(false, ps); programClassPool.classesAcceptAlphabetically(new MultiClassVisitor( new ClassVisitor[] { new KeptClassFilter(printer), new AllMemberVisitor(new KeptMemberFilter(printer)) })); } }proguard4.8/build/0000775000175000017500000000000011760503005012657 5ustar ericericproguard4.8/build/build.xml0000644000175000017500000001235511171705717014516 0ustar ericeric proguard4.8/build/build.sh0000755000175000017500000000400311223213303014301 0ustar ericeric#!/bin/bash # # GNU/Linux build script for ProGuard. # # Configuration. # ANT_HOME=${ANT_HOME:-/usr/local/java/ant} WTK_HOME=${WTK_HOME:-/usr/local/java/wtk} if [ -z $PROGUARD_HOME ]; then PROGUARD_HOME=$(which "$0") PROGUARD_HOME=$(dirname "$0")/.. fi cd "$PROGUARD_HOME" SRC=src CLASSES=classes LIB=lib PROGUARD=proguard/ProGuard PROGUARD_GUI=proguard/gui/ProGuardGUI RETRACE=proguard/retrace/ReTrace ANT_TASK=proguard/ant/ProGuardTask WTK_PLUGIN=proguard/wtk/ProGuardObfuscator ANT_JAR=$ANT_HOME/lib/ant.jar WTK_JAR=$WTK_HOME/wtklib/kenv.zip PROGUARD_JAR=$LIB/proguard.jar PROGUARD_GUI_JAR=$LIB/proguardgui.jar RETRACE_JAR=$LIB/retrace.jar # # Function definitions. # function compile { # Compile java source files. echo "Compiling ${1//\//.} ..." javac -nowarn -Xlint:none -sourcepath "$SRC" -d "$CLASSES" \ "$SRC/$1.java" 2>&1 \ | sed -e 's|^| |' # Copy resource files. (cd "$SRC"; find $(dirname $1) -maxdepth 1 \ \( -name \*.properties -o -name \*.png -o -name \*.gif -o -name \*.pro \) \ -exec cp --parents {} "../$CLASSES" \; ) } function createjar { echo "Creating $2..." jar -cfm "$2" "$SRC/$(dirname $1)/MANIFEST.MF" -C "$CLASSES" $(dirname $1) } function updatejar { echo "Updating $PROGUARD_JAR..." jar -uf "$PROGUARD_JAR" -C "$CLASSES" $(dirname $1) } # # Main script body. # mkdir -p "$CLASSES" compile $PROGUARD createjar $PROGUARD "$PROGUARD_JAR" compile $PROGUARD_GUI createjar $PROGUARD_GUI "$PROGUARD_GUI_JAR" compile $RETRACE createjar $RETRACE "$RETRACE_JAR" if [ -f "$ANT_JAR" ]; then export CLASSPATH=$ANT_JAR compile $ANT_TASK updatejar $ANT_TASK else echo "Please make sure the environment variable ANT_HOME is set correctly," echo "if you want to compile the optional ProGuard Ant task." fi if [ -f "$WTK_JAR" ]; then export CLASSPATH=$WTK_JAR compile $WTK_PLUGIN updatejar $WTK_PLUGIN else echo "Please make sure the environment variable WTK_HOME is set correctly," echo "if you want to compile the optional ProGuard WTK plugin." fi proguard4.8/build/makefile0000644000175000017500000000445611171706013014366 0ustar ericeric# GNU/Linux makefile for ProGuard. ANT_HOME = /usr/local/java/ant WTK_HOME = /usr/local/java/wtk PROGUARD_HOME := $(subst ./..,..,$(subst /build/..,/,$(dir $(MAKEFILE_LIST))..)) SRC = $(PROGUARD_HOME)/src CLASSES = $(PROGUARD_HOME)/classes LIB = $(PROGUARD_HOME)/lib ANT_JAR = $(ANT_HOME)/lib/ant.jar WTK_JAR = $(WTK_HOME)/wtklib/kenv.zip CLASSPATH = $(ANT_JAR):$(WTK_JAR) PROGUARD = proguard/ProGuard PROGUARD_GUI = proguard/gui/ProGuardGUI RETRACE = proguard/retrace/ReTrace ANT_TASK = proguard/ant/ProGuardTask WTK_PLUGIN = proguard/wtk/ProGuardObfuscator TARGETS = $(PROGUARD) $(PROGUARD_GUI) $(RETRACE) $(ANT_TASK) $(WTK_PLUGIN) JAVAC_OPTIONS = -nowarn -Xlint:none -classpath $(CLASSPATH) -sourcepath $(SRC) -d $(CLASSES) # Command sequence definitions for creating jars. define createjar jar -cfm $(LIB)/$@.jar $(SRC)/$(dir $<)MANIFEST.MF \ -C $(CLASSES) $(dir $<) endef define updatejar jar -uf $(LIB)/proguard.jar \ -C $(CLASSES) $(dir $<) endef # The various targets. all: basic options basic: proguard proguardgui retrace options: anttask wtkplugin proguard: $(PROGUARD) $(createjar) proguardgui: proguard proguardgui: $(PROGUARD_GUI) $(createjar) retrace: $(RETRACE) $(createjar) anttask: $(ANT_JAR) anttask: $(PROGUARD) anttask: $(ANT_TASK) $(updatejar) wtkplugin: $(WTK_JAR) wtkplugin: $(PROGUARD) wtkplugin: $(WTK_PLUGIN) $(updatejar) clean: -rm -fr $(CLASSES) $(LIB) define RESOURCES $(shell find $(SRC)/$(dir $(1)) -maxdepth 1 \( -name \*.properties -o -name \*.png -o -name \*.gif -o -name \*.pro \) -printf $(CLASSES)/$(dir $(1))%P\\n) endef define TARGETRULE $(1): $(CLASSES) $(CLASSES)/$(1).class $(call RESOURCES,$(1)) $(LIB) endef $(foreach TARGET,$(TARGETS),$(eval $(call TARGETRULE,$(TARGET)))) $(CLASSES) $(LIB): -mkdir -p $@ $(CLASSES)/%.class: $(SRC)/%.java javac $(JAVAC_OPTIONS) $^ $(CLASSES)/%.properties $(CLASSES)/%.png $(CLASSES)/%.gif $(CLASSES)/%.pro: cp $(subst $(CLASSES),$(SRC),$@) $@ %.jar %.zip: echo "Please make sure the path to $@ is set" echo "correctly in this $(strip $(MAKEFILE_LIST))." echo "Alternatively, if you don't need the corresponding option," echo "you can run `make' with the option -k." find $@ .PHONY: all basic options proguard proguardgui retrace anttask wtkplugin clean $(TARGETS) $(OPTIONAL_TARGETS) proguard4.8/build/README0000644000175000017500000000222611760502511013540 0ustar ericericProGuard, Java class file shrinker, optimizer, obfuscator, and preverifier ========================================================================== This directory contains a number of alternative ways to build ProGuard: - build.sh : a shell script for GNU/Linux - makefile : a makefile for GNU/Linux - build.xml : an Ant build file for all platforms - As a final alternative, you can also easily compile the code from the command line: mkdir classes javac -sourcepath src -d classes src/proguard/ProGuard.java javac -sourcepath src -d classes src/proguard/gui/ProGuardGUI.java javac -sourcepath src -d classes src/proguard/retrace/ReTrace.java For the ProGuard Ant task: javac -sourcepath src -d classes -classpath lib/ant.jar \ src/proguard/ant/ProGuardTask.java For the Java Micro Edition Wireless Tool Kit (JME WTK) obfuscator plug-in: javac -sourcepath src -d classes -classpath wtklib/kenv.zip \ src/proguard/wtk/ProGuardObfuscator.java Note that you'll have to install Ant and the JME WTK yourself. Enjoy! http://proguard.sourceforge.net/ Copyright (c) 2002-2012 Eric Lafortune (eric@graphics.cornell.edu) proguard4.8/examples/0000775000175000017500000000000011760503005013376 5ustar ericericproguard4.8/examples/proguard.pro0000644000175000017500000000317311476667044015767 0ustar ericeric# # This ProGuard configuration file illustrates how to process ProGuard itself. # Configuration files for typical applications will be very similar. # Usage: # java -jar proguard.jar @proguard.pro # # Specify the input jars, output jars, and library jars. # We'll filter out the Ant and WTK classes, keeping everything else. -injars ../lib/proguard.jar(!proguard/ant/**,!proguard/wtk/**) -outjars proguard_out.jar -libraryjars /lib/rt.jar # Write out an obfuscation mapping file, for de-obfuscating any stack traces # later on, or for incremental obfuscation of extensions. -printmapping proguard.map # Allow methods with the same signature, except for the return type, # to get the same obfuscation name. -overloadaggressively # Put all obfuscated classes into the nameless root package. -repackageclasses '' # Allow classes and class members to be made public. -allowaccessmodification # The entry point: ProGuard and its main method. -keep public class proguard.ProGuard { public static void main(java.lang.String[]); } # If you want to preserve the Ant task as well, you'll have to specify the # main ant.jar. #-libraryjars /usr/local/java/ant/lib/ant.jar #-adaptresourcefilecontents proguard/ant/task.properties # #-keep,allowobfuscation class proguard.ant.* #-keepclassmembers public class proguard.ant.* { # (org.apache.tools.ant.Project); # public void set*(***); # public void add*(***); #} # If you want to preserve the WTK obfuscation plug-in, you'll have to specify # the kenv.zip file. #-libraryjars /usr/local/java/wtk2.5.2/wtklib/kenv.zip #-keep public class proguard.wtk.ProGuardObfuscator proguard4.8/examples/proguardgui.pro0000644000175000017500000000312211476550562016462 0ustar ericeric# # This ProGuard configuration file illustrates how to process the ProGuard GUI. # Configuration files for typical applications will be very similar. # Usage: # java -jar proguard.jar @proguardgui.pro # # Specify the input jars, output jars, and library jars. # The input jars will be merged in a single output jar. # We'll filter out the Ant and WTK classes. -injars ../lib/proguardgui.jar -injars ../lib/proguard.jar(!META-INF/**,!proguard/ant/**,!proguard/wtk/**) -injars ../lib/retrace.jar (!META-INF/**) -outjars proguardgui_out.jar -libraryjars /lib/rt.jar # If we wanted to reuse the previously obfuscated proguard_out.jar, we could # perform incremental obfuscation based on its mapping file, and only keep the # additional GUI files instead of all files. #-applymapping proguard.map #-injars ../lib/proguardgui.jar #-outjars proguardgui_out.jar #-libraryjars ../lib/proguard.jar(!proguard/ant/**,!proguard/wtk/**) #-libraryjars ../lib/retrace.jar #-libraryjars /lib/rt.jar # Allow methods with the same signature, except for the return type, # to get the same obfuscation name. -overloadaggressively # Put all obfuscated classes into the nameless root package. -repackageclasses '' # Adapt the names of resource files, based on the corresponding obfuscated # class names. Notably, in this case, the GUI resource properties file will # have to be renamed. -adaptresourcefilenames **.properties,**.gif,**.jpg # The entry point: ProGuardGUI and its main method. -keep public class proguard.gui.ProGuardGUI { public static void main(java.lang.String[]); } proguard4.8/examples/proguardall.pro0000644000175000017500000000333311476667044016456 0ustar ericeric# # This ProGuard configuration file illustrates how to process ProGuard # (including its main application, its GUI, its Ant task, and its WTK plugin), # and the ReTrace tool, all in one go. # Configuration files for typical applications will be very similar. # Usage: # java -jar proguard.jar @proguardall.pro # # Specify the input jars, output jars, and library jars. # We'll read all jars from the lib directory, process them, and write the # processed jars to a new out directory. -injars ../lib -outjars out # You may have to adapt the paths below. -libraryjars /lib/rt.jar -libraryjars /usr/local/java/ant/lib/ant.jar -libraryjars /usr/local/java/wtk2.5.2/wtklib/kenv.zip # Allow methods with the same signature, except for the return type, # to get the same obfuscation name. -overloadaggressively # Put all obfuscated classes into the nameless root package. -repackageclasses '' # Adapt the names and contents of the resource files. -adaptresourcefilenames **.properties,**.gif,**.jpg -adaptresourcefilecontents proguard/ant/task.properties # The main entry points. -keep public class proguard.ProGuard { public static void main(java.lang.String[]); } -keep public class proguard.gui.ProGuardGUI { public static void main(java.lang.String[]); } -keep public class proguard.retrace.ReTrace { public static void main(java.lang.String[]); } # If we have ant.jar, we can properly process the Ant task. -keep,allowobfuscation class proguard.ant.* -keepclassmembers public class proguard.ant.* { (org.apache.tools.ant.Project); public void set*(***); public void add*(***); } # If we have kenv.zip, we can process the J2ME WTK plugin. -keep public class proguard.wtk.ProGuardObfuscator proguard4.8/examples/applets.pro0000644000175000017500000000420011476550562015600 0ustar ericeric# # This ProGuard configuration file illustrates how to process applets. # Usage: # java -jar proguard.jar @applets.pro # # Specify the input jars, output jars, and library jars. -injars in.jar -outjars out.jar -libraryjars /lib/rt.jar # Save the obfuscation mapping to a file, so you can de-obfuscate any stack # traces later on. Keep a fixed source file attribute and all line number # tables to get line numbers in the stack traces. # You can comment this out if you're not interested in stack traces. -printmapping out.map -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable # Preserve all annotations. -keepattributes *Annotation* # You can print out the seeds that are matching the keep options below. #-printseeds out.seeds # Preserve all public applets. -keep public class * extends java.applet.Applet # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native ; } # Preserve the special static methods that are required in all enumeration # classes. -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. # You can comment this out if your library doesn't use serialization. # If your code contains serializable classes that have to be backward # compatible, please refer to the manual. -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Your application may contain more items that need to be preserved; # typically classes that are dynamically created using Class.forName: # -keep public class mypackage.MyClass # -keep public interface mypackage.MyInterface # -keep public class * implements mypackage.MyInterface proguard4.8/examples/android.pro0000644000175000017500000001207511754154206015553 0ustar ericeric# # This ProGuard configuration file illustrates how to process Android # applications. # Usage: # java -jar proguard.jar @android.pro # # If you're using the Android SDK (version 2.3 or higher), the android tool # already creates a file like this in your project, called proguard.cfg. # It should contain the settings of this file, minus the input and output paths # (-injars, -outjars, -libraryjars, -printmapping, and -printseeds). # The generated Ant build file automatically sets these paths. # Specify the input jars, output jars, and library jars. # Note that ProGuard works with Java bytecode (.class), # before the dex compiler converts it into Dalvik code (.dex). -injars bin/classes -injars libs -outjars bin/classes-processed.jar -libraryjars /usr/local/android-sdk/platforms/android-9/android.jar #-libraryjars /usr/local/android-sdk/add-ons/google_apis-7_r01/libs/maps.jar # ... # Save the obfuscation mapping to a file, so you can de-obfuscate any stack # traces later on. -printmapping bin/classes-processed.map # You can print out the seeds that are matching the keep options below. #-printseeds bin/classes-processed.seeds # Preverification is irrelevant for the dex compiler and the Dalvik VM. -dontpreverify # Reduce the size of the output some more. -repackageclasses '' -allowaccessmodification # Switch off some optimizations that trip older versions of the Dalvik VM. -optimizations !code/simplification/arithmetic # Keep a fixed source file attribute and all line number tables to get line # numbers in the stack traces. # You can comment this out if you're not interested in stack traces. -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable # RemoteViews might need annotations. -keepattributes *Annotation* # Preserve all fundamental application classes. -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider # Preserve all View implementations, their special context constructors, and # their setters. -keep public class * extends android.view.View { public (android.content.Context); public (android.content.Context, android.util.AttributeSet); public (android.content.Context, android.util.AttributeSet, int); public void set*(...); } # Preserve all classes that have special context constructors, and the # constructors themselves. -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet); } # Preserve all classes that have special context constructors, and the # constructors themselves. -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet, int); } # Preserve all possible onClick handlers. -keepclassmembers class * extends android.content.Context { public void *(android.view.View); public void *(android.view.MenuItem); } # Preserve the special fields of all Parcelable implementations. -keepclassmembers class * implements android.os.Parcelable { static android.os.Parcelable$Creator CREATOR; } # Preserve static fields of inner classes of R classes that might be accessed # through introspection. -keepclassmembers class **.R$* { public static ; } # Preserve the required interface from the License Verification Library # (but don't nag the developer if the library is not used at all). -keep public interface com.android.vending.licensing.ILicensingService -dontnote com.android.vending.licensing.ILicensingService # The Android Compatibility library references some classes that may not be # present in all versions of the API, but we know that's ok. -dontwarn android.support.** # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native ; } # Preserve the special static methods that are required in all enumeration # classes. -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. # You can comment this out if your application doesn't use serialization. # If your code contains serializable classes that have to be backward # compatible, please refer to the manual. -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Your application may contain more items that need to be preserved; # typically classes that are dynamically created using Class.forName: # -keep public class mypackage.MyClass # -keep public interface mypackage.MyInterface # -keep public class * implements mypackage.MyInterface proguard4.8/examples/retrace.pro0000644000175000017500000000242011476550562015557 0ustar ericeric# # This ProGuard configuration file illustrates how to process the ReTrace tool. # Configuration files for typical applications will be very similar. # Usage: # java -jar proguard.jar @retrace.pro # # Specify the input jars, output jars, and library jars. # The input jars will be merged in a single output jar. # We'll filter out the Ant and WTK classes. -injars ../lib/retrace.jar -injars ../lib/proguard.jar(!META-INF/MANIFEST.MF, !proguard/ant/**,!proguard/wtk/**) -outjars retrace_out.jar -libraryjars /lib/rt.jar # If we wanted to reuse the previously obfuscated proguard_out.jar, we could # perform incremental obfuscation based on its mapping file, and only keep the # additional ReTrace files instead of all files. #-applymapping proguard.map #-outjars retrace_out.jar(proguard/retrace/**) # Allow methods with the same signature, except for the return type, # to get the same obfuscation name. -overloadaggressively # Put all obfuscated classes into the nameless root package. -repackageclasses '' # Allow classes and class members to be made public. -allowaccessmodification # The entry point: ReTrace and its main method. -keep public class proguard.retrace.ReTrace { public static void main(java.lang.String[]); } proguard4.8/examples/servlets.pro0000644000175000017500000000427211476550562016010 0ustar ericeric# # This ProGuard configuration file illustrates how to process servlets. # Usage: # java -jar proguard.jar @servlets.pro # # Specify the input jars, output jars, and library jars. -injars in.jar -outjars out.jar -libraryjars /lib/rt.jar -libraryjars /usr/local/java/servlet/servlet.jar # Save the obfuscation mapping to a file, so you can de-obfuscate any stack # traces later on. Keep a fixed source file attribute and all line number # tables to get line numbers in the stack traces. # You can comment this out if you're not interested in stack traces. -printmapping out.map -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable # Preserve all annotations. -keepattributes *Annotation* # You can print out the seeds that are matching the keep options below. #-printseeds out.seeds # Preserve all public servlets. -keep public class * implements javax.servlet.Servlet # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native ; } # Preserve the special static methods that are required in all enumeration # classes. -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. # You can comment this out if your library doesn't use serialization. # If your code contains serializable classes that have to be backward # compatible, please refer to the manual. -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Your application may contain more items that need to be preserved; # typically classes that are dynamically created using Class.forName: # -keep public class mypackage.MyClass # -keep public interface mypackage.MyInterface # -keep public class * implements mypackage.MyInterface proguard4.8/examples/applications.pro0000644000175000017500000000442311476550562016625 0ustar ericeric# # This ProGuard configuration file illustrates how to process applications. # Usage: # java -jar proguard.jar @applications.pro # # Specify the input jars, output jars, and library jars. -injars in.jar -outjars out.jar -libraryjars /lib/rt.jar #-libraryjars junit.jar #-libraryjars servlet.jar #-libraryjars jai_core.jar #... # Save the obfuscation mapping to a file, so you can de-obfuscate any stack # traces later on. Keep a fixed source file attribute and all line number # tables to get line numbers in the stack traces. # You can comment this out if you're not interested in stack traces. -printmapping out.map -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable # Preserve all annotations. -keepattributes *Annotation* # You can print out the seeds that are matching the keep options below. #-printseeds out.seeds # Preserve all public applications. -keepclasseswithmembers public class * { public static void main(java.lang.String[]); } # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native ; } # Preserve the special static methods that are required in all enumeration # classes. -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. # You can comment this out if your application doesn't use serialization. # If your code contains serializable classes that have to be backward # compatible, please refer to the manual. -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Your application may contain more items that need to be preserved; # typically classes that are dynamically created using Class.forName: # -keep public class mypackage.MyClass # -keep public interface mypackage.MyInterface # -keep public class * implements mypackage.MyInterface proguard4.8/examples/ant/0000775000175000017500000000000011760503005014160 5ustar ericericproguard4.8/examples/ant/servlets.xml0000644000175000017500000000565311476672223016575 0ustar ericeric proguard4.8/examples/ant/library.xml0000644000175000017500000000667311163773610016370 0ustar ericeric proguard4.8/examples/ant/android-8.xml0000644000175000017500000001554211476670211016504 0ustar ericeric Converting optimized files into ${intermediate.dex.file}... Optimizing compiled files and libraries into ${out.proguard.absolute.jar}... -dontpreverify -repackageclasses '' -allowaccessmodification -optimizations !code/simplification/arithmetic -keepattributes *Annotation* -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.view.View { public <init>(android.content.Context); public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); public void set*(...); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers class * implements android.os.Parcelable { static android.os.Parcelable$Creator CREATOR; } -keepclassmembers class **.R$* { public static <fields>; } -keep public interface com.android.vending.licensing.ILicensingService -dontnote com.android.vending.licensing.ILicensingService -keepclasseswithmembernames class * { native <methods>; } -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } proguard4.8/examples/ant/applications2.xml0000644000175000017500000000457511476672663017510 0ustar ericeric -injars in.jar -outjars out.jar -libraryjars ${java.home}/lib/rt.jar -printmapping out.map -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable -keepattributes *Annotation* -keepclasseswithmembers public class * { public static void main(java.lang.String[]); } -keepclasseswithmembernames class * { native <methods>; } -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } proguard4.8/examples/ant/proguard.xml0000644000175000017500000000542611476672004016544 0ustar ericeric proguard4.8/examples/ant/applets.xml0000644000175000017500000000564011476671026016372 0ustar ericeric proguard4.8/examples/ant/applications3.xml0000644000175000017500000000651411476673754017506 0ustar ericeric proguard4.8/examples/ant/midlets.xml0000644000175000017500000000317611476673154016371 0ustar ericeric proguard4.8/examples/ant/applications1.xml0000644000175000017500000000065711476672331017474 0ustar ericeric proguard4.8/examples/library.pro0000644000175000017500000000474511476550562015612 0ustar ericeric# # This ProGuard configuration file illustrates how to process a program # library, such that it remains usable as a library. # Usage: # java -jar proguard.jar @library.pro # # Specify the input jars, output jars, and library jars. # In this case, the input jar is the program library that we want to process. -injars in.jar -outjars out.jar -libraryjars /lib/rt.jar # Save the obfuscation mapping to a file, so we can de-obfuscate any stack # traces later on. Keep a fixed source file attribute and all line number # tables to get line numbers in the stack traces. # You can comment this out if you're not interested in stack traces. -printmapping out.map -keepparameternames -renamesourcefileattribute SourceFile -keepattributes Exceptions,InnerClasses,Signature,Deprecated, SourceFile,LineNumberTable,EnclosingMethod # Preserve all annotations. -keepattributes *Annotation* # Preserve all public classes, and their public and protected fields and # methods. -keep public class * { public protected *; } # Preserve all .class method names. -keepclassmembernames class * { java.lang.Class class$(java.lang.String); java.lang.Class class$(java.lang.String, boolean); } # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native ; } # Preserve the special static methods that are required in all enumeration # classes. -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. # You can comment this out if your library doesn't use serialization. # If your code contains serializable classes that have to be backward # compatible, please refer to the manual. -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Your library may contain more items that need to be preserved; # typically classes that are dynamically created using Class.forName: # -keep public class mypackage.MyClass # -keep public interface mypackage.MyInterface # -keep public class * implements mypackage.MyInterface proguard4.8/examples/annotations/0000775000175000017500000000000011760503015015734 5ustar ericericproguard4.8/examples/annotations/src/0000775000175000017500000000000011760503005016522 5ustar ericericproguard4.8/examples/annotations/src/proguard/0000775000175000017500000000000011760503005020345 5ustar ericericproguard4.8/examples/annotations/src/proguard/annotation/0000775000175000017500000000000011760503005022517 5ustar ericericproguard4.8/examples/annotations/src/proguard/annotation/KeepClassMemberNames.java0000644000175000017500000000077311163773610027365 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all class members of the annotated class * from being optimized or obfuscated as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepClassMemberNames {} proguard4.8/examples/annotations/src/proguard/annotation/KeepPublicClassMemberNames.java0000644000175000017500000000101011163773610030505 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all public class members of the annotated * class from being optimized or obfuscated as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepPublicClassMemberNames {} proguard4.8/examples/annotations/src/proguard/annotation/KeepGettersSetters.java0000644000175000017500000000101011163773610027154 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all getters and setters of the annotated * class from being shrunk, optimized, or obfuscated as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepGettersSetters {} proguard4.8/examples/annotations/src/proguard/annotation/KeepPublicProtectedClassMemberNames.java0000644000175000017500000000103611163773610032367 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all public or protected class members of * the annotated class from being optimized or obfuscated as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepPublicProtectedClassMemberNames {} proguard4.8/examples/annotations/src/proguard/annotation/KeepClassMembers.java0000644000175000017500000000100011163773610026544 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all class members of the annotated class * from being shrunk, optimized, or obfuscated as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepClassMembers {} proguard4.8/examples/annotations/src/proguard/annotation/KeepApplication.java0000644000175000017500000000074111163773610026442 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep the annotated class as an application, * together with its a main method. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepApplication {} proguard4.8/examples/annotations/src/proguard/annotation/KeepPublicGettersSetters.java0000644000175000017500000000102511163773610030321 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all public getters and setters of the * annotated class from being shrunk, optimized, or obfuscated as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepPublicGettersSetters {} proguard4.8/examples/annotations/src/proguard/annotation/KeepImplementations.java0000644000175000017500000000074711163773610027355 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all implementations or extensions of the * annotated class as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepImplementations {} proguard4.8/examples/annotations/src/proguard/annotation/Keep.java0000644000175000017500000000103211163773610024250 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies not to optimize or obfuscate the annotated class or * class member as an entry point. */ @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR }) @Retention(RetentionPolicy.CLASS) @Documented public @interface Keep {} proguard4.8/examples/annotations/src/proguard/annotation/KeepPublicImplementations.java0000644000175000017500000000076411163773610030513 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all public implementations or extensions * of the annotated class as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepPublicImplementations {} proguard4.8/examples/annotations/src/proguard/annotation/KeepPublicClassMembers.java0000644000175000017500000000101511163773610027711 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all public class members of the annotated * class from being shrunk, optimized, or obfuscated as entry points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepPublicClassMembers {} proguard4.8/examples/annotations/src/proguard/annotation/KeepPublicProtectedClassMembers.java0000644000175000017500000000104611163773610031567 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies to keep all public or protected class members of * the annotated class from being shrunk, optimized, or obfuscated as entry * points. */ @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepPublicProtectedClassMembers {} proguard4.8/examples/annotations/src/proguard/annotation/KeepName.java0000644000175000017500000000103611163773610025055 0ustar ericeric/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) */ package proguard.annotation; import java.lang.annotation.*; /** * This annotation specifies not to optimize or obfuscate the annotated class or * class member as an entry point. */ @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR }) @Retention(RetentionPolicy.CLASS) @Documented public @interface KeepName {} proguard4.8/examples/annotations/examples/0000775000175000017500000000000011760503005017551 5ustar ericericproguard4.8/examples/annotations/examples/Applet.java0000644000175000017500000000100211175074657021650 0ustar ericericimport proguard.annotation.*; /** * This applet illustrates the use of annotations for configuring ProGuard. * * You can compile it with: * javac -classpath ../lib/annotations.jar Applet.java * You can then process it with: * java -jar ../../../lib/proguard.jar @ ../examples.pro * * The annotation will preserve the class and its essential methods. */ @Keep public class Applet extends java.applet.Applet { // Implementations for Applet. public void init() { // ... } } proguard4.8/examples/annotations/examples/NativeCallBack.java0000644000175000017500000000217211175074766023240 0ustar ericericimport proguard.annotation.*; /** * This application illustrates the use of annotations for configuring ProGuard. * * You can compile it with: * javac -classpath ../lib/annotations.jar NativeCallBack.java * You can then process it with: * java -jar ../../../lib/proguard.jar @ ../examples.pro * * The annotation will preserve the class and its main method. */ @KeepApplication public class NativeCallBack { /** * Suppose this is a native method that computes an answer. * * The -keep option regular ProGuard configuration will make sure it is * not renamed when processing this code. */ public native int computeAnswer(); /** * Suppose this method is called back from the above native method. * * ProGuard would remove it, because it is not referenced from java. * The annotation will make sure it is preserved anyhow. */ @Keep public int getAnswer() { return 42; } public static void main(String[] args) { int answer = new NativeCallBack().computeAnswer(); System.out.println("The answer is " + answer); } } proguard4.8/examples/annotations/examples/Bean.java0000644000175000017500000000213511175074722021271 0ustar ericericimport proguard.annotation.*; /** * This bean illustrates the use of annotations for configuring ProGuard. * * You can compile it with: * javac -classpath ../lib/annotations.jar Bean.java * You can then process it with: * java -jar ../../../lib/proguard.jar @ ../examples.pro * * The annotations will preserve the class and its public getters and setters. */ @Keep @KeepPublicGettersSetters public class Bean { public boolean booleanProperty; public int intProperty; public String stringProperty; public boolean isBooleanProperty() { return booleanProperty; } public void setBooleanProperty(boolean booleanProperty) { this.booleanProperty = booleanProperty; } public int getIntProperty() { return intProperty; } public void setIntProperty(int intProperty) { this.intProperty = intProperty; } public String getStringProperty() { return stringProperty; } public void setStringProperty(String stringProperty) { this.stringProperty = stringProperty; } } proguard4.8/examples/annotations/examples/Application.java0000644000175000017500000000103211175074575022670 0ustar ericericimport proguard.annotation.KeepApplication; /** * This application illustrates the use of annotations for configuring ProGuard. * * You can compile it with: * javac -classpath ../lib/annotations.jar Application.java * You can then process it with: * java -jar ../../../lib/proguard.jar @ ../examples.pro * * The annotation will preserve the class and its main method. */ @KeepApplication public class Application { public static void main(String[] args) { System.out.println("The answer is 42"); } } proguard4.8/examples/annotations/examples.pro0000644000175000017500000000336711415710272020305 0ustar ericeric# # This ProGuard configuration file illustrates how to use annotations for # specifying which classes and class members should be kept. # Usage: # java -jar proguard.jar @examples.pro # # Specify the input, output, and library jars. # This is assuming the code has been compiled in the examples directory. -injars examples(*.class) -outjars out -libraryjars /lib/rt.jar # Some important configuration is based on the annotations in the code. # We have to specify what the annotations mean to ProGuard. -include lib/annotations.pro # # We can then still add any other options that might be useful. # # Print out a list of what we're preserving. -printseeds # Preserve all annotations themselves. -keepattributes *Annotation* # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native ; } # Preserve the special static methods that are required in all enumeration # classes. -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. # You can comment this out if your application doesn't use serialization. # If your code contains serializable classes that have to be backward # compatible, please refer to the manual. -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } proguard4.8/examples/annotations/lib/0000775000175000017500000000000011760503015016502 5ustar ericericproguard4.8/examples/annotations/lib/annotations.pro0000644000175000017500000000720211163773610021567 0ustar ericeric# # This ProGuard configuration file specifies how annotations can be used # to configure the processing of other code. # Usage: # java -jar proguard.jar @annotations.pro -libraryjars annotations.jar ... # # Note that the other input/output options still have to be specified. # If you specify them in a separate file, you can simply include this file: # -include annotations.pro # # You can add any other options that are required. For instance, if you are # processing a library, you can still include the options from library.pro. # The annotations are defined in the accompanying jar. For now, we'll start # with these. You can always define your own annotations, if necessary. -libraryjars annotations.jar # The following annotations can be specified with classes and with class # members. # @Keep specifies not to shrink, optimize, or obfuscate the annotated class # or class member as an entry point. -keep @proguard.annotation.Keep class * -keepclassmembers class * { @proguard.annotation.Keep *; } # @KeepName specifies not to optimize or obfuscate the annotated class or # class member as an entry point. -keepnames @proguard.annotation.KeepName class * -keepclassmembernames class * { @proguard.annotation.KeepName *; } # The following annotations can only be specified with classes. # @KeepImplementations and @KeepPublicImplementations specify to keep all, # resp. all public, implementations or extensions of the annotated class as # entry points. Note the extension of the java-like syntax, adding annotations # before the (wild-carded) interface name. -keep class * implements @proguard.annotation.KeepImplementations * -keep public class * implements @proguard.annotation.KeepPublicImplementations * # @KeepApplication specifies to keep the annotated class as an application, # together with its main method. -keepclasseswithmembers @proguard.annotation.KeepApplication public class * { public static void main(java.lang.String[]); } # @KeepClassMembers, @KeepPublicClassMembers, and # @KeepPublicProtectedClassMembers specify to keep all, all public, resp. # all public or protected, class members of the annotated class from being # shrunk, optimized, or obfuscated as entry points. -keepclassmembers @proguard.annotation.KeepClassMembers class * { *; } -keepclassmembers @proguard.annotation.KeepPublicClassMembers class * { public *; } -keepclassmembers @proguard.annotation.KeepPublicProtectedClassMembers class * { public protected *; } # @KeepClassMemberNames, @KeepPublicClassMemberNames, and # @KeepPublicProtectedClassMemberNames specify to keep all, all public, resp. # all public or protected, class members of the annotated class from being # optimized or obfuscated as entry points. -keepclassmembernames @proguard.annotation.KeepClassMemberNames class * { *; } -keepclassmembernames @proguard.annotation.KeepPublicClassMemberNames class * { public *; } -keepclassmembernames @proguard.annotation.KeepPublicProtectedClassMemberNames class * { public protected *; } # @KeepGettersSetters and @KeepPublicGettersSetters specify to keep all, resp. # all public, getters and setters of the annotated class from being shrunk, # optimized, or obfuscated as entry points. -keepclassmembers @proguard.annotation.KeepGettersSetters class * { void set*(***); void set*(int, ***); boolean is*(); boolean is*(int); *** get*(); *** get*(int); } -keepclassmembers @proguard.annotation.KeepPublicGettersSetters class * { public void set*(***); public void set*(int, ***); public boolean is*(); public boolean is*(int); public *** get*(); public *** get*(int); } proguard4.8/examples/annotations/lib/annotations.jar0000664000175000017500000001375311760503015021546 0ustar ericericPK@ META-INF/PKPK@META-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu )h)f&W+x%irrPKLэJDDPK@)proguard/annotation/KeepApplication.classMK1ߩR?GϞ^,X ɲ<QlVddOI=8%cW)asѩٻZ)Ť^/E/pd}IULhB#*2JRo깁[szv^PY ;ú8p]Ҳzτ &=OzB{ۧАA5hnv%w4m GՎq#PKh PK@proguard/annotation/Keep.classKK@Դ]E ]4E1DA\MK2MB:)E9s~~CG6:Q^ $Q1g8 LJfYyd8 Hm81/SR λ^/Yv:Λ{A&dNdEw.\ثeJD^Md'l5 ZrP[ ľTv@]tWg}PK7ͽPK@*proguard/annotation/KeepClassMembers.classMK@ߩU*ңsO֋KIeB?Jx"fw>}gϷw8 pЍ+S Xz<ᲺY ͝2gYDHkcFWḯJ,?0evH謄r^(Yx]lBhfl==OAfFt]OGQDlpgRW ^ɜ(;!6JOɒSK7o5 Z޶Pwlk; .ث#>p|PKAWPK@,proguard/annotation/KeepGettersSetters.classJ1ƿ_"GϞ,X ɲj|J(X2͗0onp(B'1Wf< [e|X i+,+9UXa|X ZKWm*e< \Գ7OAFl޿pY?po2> Z&w&nh=MYBV~g h~}j{; . c8PK1PK@-proguard/annotation/KeepImplementations.classJ1ƿ_z7= ,EOvXRɲM }5>%&*ÂM78pN2 }Q*.X[aыX i+ ~ 9U<Q`b%tF*g'B9/Q ǥ=LCY=;aQddlVah$&s+(/*&-( nAomށ5 ]-]i/PK(xPK@4proguard/annotation/KeepPublicClassMemberNames.classN0?@WPc#f- &BBLNz\9vؕj <0P ,}|Y2;IO|U6ֲH|Uå\K7N*jctʚJbV3&O!Ld謥rM5d\Y% \6sr?Hd;Z<űU|-J{Y.~#۾.)sfֲ@B{`cOBAqc PK[PK@0proguard/annotation/KeepPublicClassMembers.classN0ƿ+-! R 19)rQbW1<a dgw' qUR1쑹\d6QHob%s,E2U; } # Your midlet may contain more items that need to be preserved; # typically classes that are dynamically created using Class.forName: # -keep public class mypackage.MyClass # -keep public interface mypackage.MyInterface # -keep public class * implements mypackage.MyInterface proguard4.8/examples/scala.pro0000644000175000017500000000767111663670514015230 0ustar ericeric# # This ProGuard configuration file illustrates how to process Scala # applications, including the Scala runtime. # Usage: # java -jar proguard.jar @scala.pro # # Specify the input jars, output jars, and library jars. -injars in.jar -injars /usr/local/java/scala-2.9.1/lib/scala-library.jar #-injars /usr/local/java/scala-2.9.1/lib/scala-compiler.jar(!META-INF/MANIFEST.MF) #-injars /usr/local/java/scala-2.9.1/lib/jline.jar(!META-INF/MANIFEST.MF) -outjars out.jar -libraryjars /lib/rt.jar #-libraryjars /usr/local/java/ant/lib/ant.jar #... # Ignore some compiler artefacts. -dontwarn scala.** # Save the obfuscation mapping to a file, so you can de-obfuscate any stack # traces later on. Keep a fixed source file attribute and all line number # tables to get line numbers in the stack traces. # You can comment this out if you're not interested in stack traces. -printmapping out.map -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable # Preserve all annotations. -keepattributes *Annotation* # You can print out the seeds that are matching the keep options below. #-printseeds out.seeds # Preserve all public applications. -keepclasseswithmembers public class * { public static void main(java.lang.String[]); } # Preserve some classes and class members that are accessed by means of # introspection. -keep class * implements org.xml.sax.EntityResolver -keepclassmembers class * { ** MODULE$; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool { long eventCount; int workerCounts; int runControl; scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack; scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread { int base; int sp; int runState; } -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask { int status; } -keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue { scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head; scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail; scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe; } # Preserve some classes and class members that are accessed by means of # introspection in the Scala compiler library, if it is processed as well. #-keep class * implements jline.Completor #-keep class * implements jline.Terminal #-keep class scala.tools.nsc.Global #-keepclasseswithmembers class * { # (scala.tools.nsc.Global); #} #-keepclassmembers class * { # *** scala_repl_value(); # *** scala_repl_result(); #} # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native ; } # Preserve the special static methods that are required in all enumeration # classes. -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. # You can comment this out if your application doesn't use serialization. # If your code contains serializable classes that have to be backward # compatible, please refer to the manual. -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Your application may contain more items that need to be preserved; # typically classes that are dynamically created using Class.forName: # -keep public class mypackage.MyClass # -keep public interface mypackage.MyInterface # -keep public class * implements mypackage.MyInterface proguard4.8/examples/dictionaries/0000775000175000017500000000000011760503005016053 5ustar ericericproguard4.8/examples/dictionaries/keywords.txt0000644000175000017500000000137611163773610020500 0ustar ericeric# # This obfuscation dictionary contains reserved Java keywords. They can't # be used in Java source files, but they can be used in compiled class files. # Note that this hardly improves the obfuscation. Decent decompilers can # automatically replace reserved keywords, and the effect can fairly simply be # undone by obfuscating again with simpler names. # Usage: # java -jar proguard.jar ..... -obfuscationdictionary keywords.txt # do if for int new try byte case char else goto long this void break catch class const final float short super throw while double import native public return static switch throws boolean default extends finally package private abstract continue strictfp volatile interface protected transient implements instanceof synchronized proguard4.8/examples/dictionaries/windows.txt0000644000175000017500000000267711163773610020330 0ustar ericeric# # This obfuscation dictionary contains names that are not allowed as file names # in Windows, not even with extensions like .class or .java. They can however # be used without problems in jar archives, which just begs to apply them as # obfuscated class names. Trying to unpack the obfuscated archives in Windows # will probably generate some sparks. # Usage: # java -jar proguard.jar ..... -classobfuscationdictionary windows.txt # -packageobfuscationdictionary windows.txt # aux Aux aUx AUx auX AuX aUX AUX AUX con Con cOn COn coN CoN cON CON CON nul Nul nUl NUl nuL NuL nUL NUL NUL prn Prn pRn PRn prN PrN pRN PRN PRN com1 Com1 cOm1 COm1 coM1 CoM1 cOM1 COM1 COM1 com2 Com2 cOm2 COm2 coM2 CoM2 cOM2 COM2 COM2 com3 Com3 cOm3 COm3 coM3 CoM3 cOM3 COM3 COM3 com4 Com4 cOm4 COm4 coM4 CoM4 cOM4 COM4 COM4 com5 Com5 cOm5 COm5 coM5 CoM5 cOM5 COM5 COM5 com6 Com6 cOm6 COm6 coM6 CoM6 cOM6 COM6 COM6 com7 Com7 cOm7 COm7 coM7 CoM7 cOM7 COM7 COM7 com8 Com8 cOm8 COm8 coM8 CoM8 cOM8 COM8 COM8 com9 Com9 cOm9 COm9 coM9 CoM9 cOM9 COM9 COM9 lpt1 Lpt1 lPt1 LPt1 lpT1 LpT1 lPT1 LPT1 LPT1 lpt2 Lpt2 lPt2 LPt2 lpT2 LpT2 lPT2 LPT2 LPT2 lpt3 Lpt3 lPt3 LPt3 lpT3 LpT3 lPT3 LPT3 LPT3 lpt4 Lpt4 lPt4 LPt4 lpT4 LpT4 lPT4 LPT4 LPT4 lpt5 Lpt5 lPt5 LPt5 lpT5 LpT5 lPT5 LPT5 LPT5 lpt6 Lpt6 lPt6 LPt6 lpT6 LpT6 lPT6 LPT6 LPT6 lpt7 Lpt7 lPt7 LPt7 lpT7 LpT7 lPT7 LPT7 LPT7 lpt8 Lpt8 lPt8 LPt8 lpT8 LpT8 lPT8 LPT8 LPT8 lpt9 Lpt9 lPt9 LPt9 lpT9 LpT9 lPT9 LPT9 LPT9 proguard4.8/examples/dictionaries/compact.txt0000644000175000017500000000050111163773610020244 0ustar ericeric# # This obfuscation dictionary contains strings that are already present # in many class files. Since these strings can be shared, the resulting # obfuscated class files will generally be a little bit more compact. # Usage: # java -jar proguard.jar ..... -obfuscationdictionary compact.txt # Code V I Z B C S F D L proguard4.8/examples/dictionaries/shakespeare.txt0000644000175000017500000000105011163773610021111 0ustar ericeric# # This obfuscation dictionary contains quotes from plays by Shakespeare. # It illustrates that any text can be used, for whatever flippant reasons # one may have. # Usage: # java -jar proguard.jar ..... -obfuscationdictionary shakespeare.txt # "This thing of darkness I acknowledge mine." --From The Tempest (V, i, 275-276) "Though this be madness, yet there is method in 't." --From Hamlet (II, ii, 206) "What's in a name? That which we call a rose By any other word would smell as sweet." --From Romeo and Juliet (II, ii, 1-2) proguard4.8/docs/0000775000175000017500000000000011760503005012510 5ustar ericericproguard4.8/docs/title.gif0000644000175000017500000000506511163773610014334 0ustar ericericGIF89a%%/ %*9CGQejo四yyeeoVV`>>G~~ >CL%%* jjt   ttt%*/LQV /49ty **949>CGG ootCGL%GL[**/y~~GLQ99>otyȖ %* *~~[`e`ej``ejot tt~jttꛠ*QQVGGLeej //9**4  %`eeQQ[ */4yy~ooy%joy99C>>LLQ[ *ejty~[`jjjoۈ//4V[`~>CGty~GLV % %%V[e>GQy~QVeV[j9CL``jLLVtty%/4LLQ̃ VV[ejj[[`QV[~[ej`eo49Cjjjȑ449~GGQQV`%%%44>CLL*/9//>! , H*\xS4ŋ b` 9@:f\Y8=@H!AN˟@5 &&P @A jpN> Z BA%0§ַ+'tpH1daL܌>8 dT0`E\~a ,*x<<'0XAg6x? -.M\&Da` kzz6i%袹-@/yC8'.Z 6F4}y@gT  ᐃC8@pAHp%BR dB#(-B a8 B0rH1k)H#Bt8ŵD be;?ˊR^ .S `e–-Zc@0?؉{D~H ͑Eh"B3Hv (:X Vt[[Fy d-@LjVn x AKYgI ho*Bɬ@f*?hV r9իy0Nh--,ox Yཅ!iAXA "`@cA" !DZ cHp( A0GcIrIK )hWV= @dH-P1pa<-<Z$P PDlF%a\ & @ FT KEh0C@(` Y p(: ;(Zaƪ9PÒ‚VXdhvRGadZPA*ދ "86~cCxJm?8Ҳ1{A ׌,h0BQ xP?;proguard4.8/docs/screenshots.html0000644000175000017500000000516511736333522015753 0ustar ericeric ProGuard Screenshots

Screenshots

GUI screenshot ProGuard Input/Output Shrinking Optimization Obfuscation Information Process ReTrace The graphical user interface to ProGuard works like a wizard. It allows you to browse through the presented tabs and fill them out.

You can click on the small tab buttons to see the full-size versions of the tabs.

Console screenshot Of course, real developers don't need all this point-and-click fluff. They write short configuration files using their favorite text editors and invoke ProGuard from the command-line.

You can click on the image to see the full-size version.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/screenshot_gui1.gif0000644000175000017500000012340311163773610016312 0ustar ericericGIF87a333LLLVVVbbbfffpppzθνҾ,O HS*\ȰÇ#JHŋ3jȱǏ CIɓ(S\2!K._ʜI͛8sɳϟ@ѣH&MӧPJJիXjʵׯ`ÊKٳhӪ]˶۷^f-Pt)x˷߿ LZb+0]Đ#KL˘3k@MӨS^ͺװc˞M۸sͻ Nȓ>ṡFo8]سkνgV_9sRGU=˟OC-ZSNؔh& FR~Wa6N Z_(\-bv^U3QVCh(#sF=_eTyM9'%Hf{BHG#Fh~Il9Kp0Z"cX.T柀!ihRf蘄2裐ss(KUJ#{Z:*jW*Ya*+X걇ޓ|r {Tv*c:"5d&*F+퀶+sr%WN+nDzz*조.uk-:PUYo{.ˮ:(p+I :j_&*gtb e(+/$,4*c(7qh~,D}P6#J FG-TkƲʹUw`u!٭͚ʵp-tmx޸n'7'Wngw砇.褗n騧ꬷ.n,#;/o'7G/Wogˇ/䗟<ܧ/{O H_hǿ:'H Z̠@A |7H(L A0WH8! [x3ԡH"PHE(*X.z`A21|f -pH1~lD^ը<~Ѝt IAxTFёٻ4,&7NLXHRx]"M9Kѓ,gYBP:Вe*K]^$-Ib~X 9I_Bҙ%0ExjZؼ-_t4YlL綹FW%)9V̧>YMv'$Hoҏ}0І:4̢DЇZd27ю3 HoQTyJW0`KgJӚ1)RjӞuJTHMjpZԜTPT+ԦSͪV}ZU[ 2 4'yp+JE~j^^MP `vsqAL`)XoAX Ճ^,ٱZ$A< 5m"ZԖE/m8 6 "a!fǝԛfl|z AK5;8~/?i?s^_rlq(:gnu}цr"@}tGv3sa_?ǀxweG{`Xg9y%Xta+}}X}ꆀqi]e]f ;;BǑW˧lI@<~YF~I`fIyiiٙiSd)okY wPi9mY)}qV4t{ٖ|shc {IHiG~7}tYyYFdɝ9⹝0iFyᙞ 9 I FpgƟ:Go YhQ_ ̙siنɹ YY$C*,ڢ.ʢe2061z:yŕwoX],fAJtCf\Ϲ1Y #IEu|Wڛj\Z%ڥG x#IF 'ipr:t*eTx|Zwڧ =:Wq\k:KzoѨ"XI%%l ǵyu"*?|<#ʪ:\\;|cʽX}e ]Tlw{0`ʗK}zh)9ȄXC%d]f}h-[{ ;o61-3=ק0 qJl|ԂBXm|6|Cٓcٕb|ٞ=(ؾ8Ԛڇ_M9| 9%M4]۶}۸]k]ǜM]v]l| ׽Ӎ ;};T&ј/ځحIؐڥ=ْ-}bڍ&e mݬKb]͗v>n`}} ýÈlˋ.73؜CCj{I _ ne)>'Ud- h]6nxe.0n*/!.FyJL>vG >-|mz(7U]:{S}DMذFRC>锾j tb K忝M9Xiק,sz::EU#F]Nc,D=CU^^Nj>r!ԾˮZ.짷埾Dw`-;^DѮTm.IgFathftٮ]]N.dMPIcNncGyJ~y_?5F .NFbjK:|DMETV ~W~7w~~HJ~D/?}YbW98]e+5h?MíKԉęcУcI PB >QD-^ĘQ)  8#LDRʕ\|))fL`ڬyfN3qdTIET҆")DV*0dĐ] 0VGɖe쁋k5=¸QZM87^}u(ǐtXbƍ?v8ɓ)r͜;WlhҋFZRm67v&~K.۷WO-1xݭ8L?`I.ž]vݵEɗ~|zݯ2w_?`&Kn#Sm9Oـ{nЩ"lC$v8DOD1EQ/]*CdcFei\1H!OC#C (620kB(˫0Cz I-7RA$D iAބ3N9N;3O<]ҳO:L3P#/L2Lm!) D02PR44/S+5ԊSOE5UUWeUW_cU@E9B̴˪ ΄Q,?J[_T}h5[mI57\q%\sE7]ueqo6޾v-,!) 6cu4+g-XZ4Y6^^!@m 7c?9dG&dO^W6kj08,x^K_>f5ᄯa_fi0>l3j:kkj&h{aKب2`g~7 fz5 MnhϞK}R&/ gqx]s wua_`n~4WW85.X?[ |G?}g}߇?_B׳d롮P{@nG`%8A VЂ`5AvpcvE <73q! d,7CЇ?b8D"шGDqO*DІ0 fHÆUo_d8F2ьgL"DQqyP+ \P_t9HBҐDd"HF6ґ4F/Ϗ[d/9G]e1-P1ġ-JVҕe,e9KZҖĥ+AJAQ;%&Gt1#A~L+&/@MTӚf6Mnvӛg8ʼn]J`&غgB3<+{`{سa-TwuӜGz6UmW8wT^6 7AO͓&JuV+l!ޱ7 phv/{׷X{38#oF M;^;h>=pfs\-vlGr}G=GW|ӞFӇn>wcCs oo7&}[Ǻ;!D-z;qHr2\#(G>r;G8rjھNN}LA'<'w=y/s69οsqø_̤Gk{qsūs|3[ŏ]ZY[)І@bo38]?~v 7np\=P m!`Zy{)B4D49P6т9KƋ@)廍~A@5!> @QAd1g?ۀfJcЍf2IQ (a1|Ar1$24CA@A%$#,;tzC;9t cD:+AI>ayBZaA0FFJljklQFIڿSTUC[Bf+;!(ƮE^$HņxFdDey\g FiDK$ bȆtȇHʡ Ax1G",>#E4~C{UݫLZ`gL"\FD,&=?]K0jFN]=]ƕjoVNeоDڐݝc_='k~u~iQ(Aj~xgt\LxGqjUNuʝ=\HoSi&z6Wqz]uwnmFc`{sW^zy{fGtů^.V{z[H>ȗ׷?XO{DhgIo|j/]?|f?pmrWy^/=)^%NSxbPWg @Oz_'~sx4]w)aL=/p7_i[ǶP|bS8"ƌ7r#S@F( p$vi%̘2gҬi&Μ:a"IŒ!"8qA  Y1ңL%"hqiGP>QQWNbY*$[pϵ[}ҭl]@HPaSOׯXsZ],WD#g{pUx ˙& Y#ğmUزgEY$ɕ_v7‡/n8r=}Vuۡ;r>*k!R)ʧǟiӏmBqu(D_F Fnp]a~ Q_ a*!~Dn ބ$6b}1H$TcJ+a#=#A 9$Ey$>.vŢzMFuʇeRUeA57`EXx6#X &T6vBI }(aw'`1AXi8&JPz***:kKgf^)e_v}ebj_PE9ʒY!>Z|~jg~څmނ.C:hZGonWk-1zm+0K<1[|1k1:.Zb*eƠ}$bפd_JUeCe%zIvf }4I+4M;4Եو[; p5Yk5]{5a=6[ (zA% ,4j¦Ug[&s^ܩi5;8K>9 SRٙk9睗=ۤQu^BRH'ɗ`T#f)f>`Jb̔<+{` .); 03_,9&>1S.~1MaӸ68>1,!F>rg|%3 ,)SV2-s^,19SCҬ5n~3,9ӹvfsˬ=h -A:'y3h39~4#-zі4+#V3&Ӟ4C}JgԦ&8iUծO-Yx5s]o,ִ5;N>قezӹA6-m1ֶ8ms޵-ns>7ӭz~w~]һ7nx B7"07=8b^R p N#Wbs ZϴB)*򑓼ty֤@d$se?9Ѓ.tS< @Leo#k"MAІKS^:îLϓ:.dIbT33~;Ytd9r7};Og[;(>[2]hwv]<9xt:Vy۽yILՠ yZ،E ,vX8'JQ-.ˁ<&*N]$&2#ۺq\]#]\[q4jP""$Dr~)#6-R9 th%&<;E`)J>:,2@c2ңН1!Aԣف>RE2"#C^@?c.Xi$K*VdVhaa_gUedKJuaRDF#P6P.FE#SډT^^TvUZicA\a{E·w^͌ IS]]CPcYK\!]6Y%R#,aloVp5k)&c"nI&bVr$F]1v%X2utP>GveldE&gP^f( &ff8)@&*Uwi|iNU)z*\Fʏb&r im2*y")^)"fsji**a~~+vV_Vd:$k) q6f+ F֫2+.kbԉZf++nhB,ӝ],fnl+iJS|^=ҟҫ #v|As_w7row~7xxwc瘪z7{v7|+}׷}w|wat.q,8tZ/8ӄ~8X%.WǃGw8 8Io8G/0ʈ-8_L8V"38/..Q9'/97?9Gy`Wy!ȴoeyOb)A9ǹ99:A$/:7zx9GzTg;zй[:O:z:G:7ǺzߺOKېB{9k/;7{k:g_o;w$;'{;{9kz9c{;;㺹;cy;û{߹z;ú:dg<twƇ|||?{o>?''?AG~SCX?CF`_]ԌplKx7{xۿgG|W<@4Q2@$|IC FHT&1fԸcGA E&9ʐ*]tYeK5qHI1u:hQG&UiSO2@SRRLuć .26KYYU{,oݎ;n]wvѻo-2pa-&. ϛ3yZd䘑wb4y#͕%kgțCkΌ2OԦR>=Z瑱ֽwo߿HիSS k ϡGDHE[{w $Jy囤W׭DǗp'+ٶm3?ĭHcAp о 9A qC#PD ,xQ-0hFaQ /1 2,RH W D\'+O*)*# [1,@"t˰OKn+ 7S9;S=? TA -TNdDLg?!+R IP.MRѾTU.І0L񪙤ZO^H*KV)P[STG4K'RZY5Ul5a--YVWe-[,c Xюv͚TYrcWeYf^8SϞ6ojښjcHU6XŅXno].Ts)')3!$ySU ҊZiy^$Xw۵}Uݘw9t|Ah`*&.~!CfpE$[{Mt^ݨWWP&Ս,a8~jG5"Hy$='Yd!2Qn>Rbx%Z90a|L"]&aLMژ<.g.ˍܲ/$/e"6^LKi\4o-" K; R/BЉt5k6/6,_LufvԵubD*ZFUc-'ioqO`d7\ߚɲDj)6GEۨf4nqڊ>2LOװeêT=n}#ʊ*FrSv;ݓŴ(s8-k?=s sD= 70N G:$TGiH@=Tt7殀&Dza`Xt`Ea M6t>F-DuLtB !BȎHBCrpImMGs#AҞSXGM~ ΃SbFCCLJJ8)TBMǃL9%ENKhOSԣt5Mlۋjqz"^'_Ќ_g,̣ I )PuSOJMqm>a'_h_ 0(TR#GSSe5<* KG04LUqF-OSSguYV.'-K"RJ5rB(H:[YM*E,,FE HW/ZzΔ\5ĵW$`&zgv`6 ` vy4H/[ub+_e_u,I4A9v,RqyZEc 'eY^)ebd ̊Rҵ->([˃ZNH*:X\fŒv)⥆3XdO/fnKwdqtB`˖vl Ζq^l_ gG$kZUW_UbɶnJfTsIFu_(W ҈_JuXyln6*R&GjDW)r-W.mA;B5 t%o)=Q)N>PtOwu)V7)v51_Bd5S(My_K`^ $'w&tb%*w8uj8) S: 6m |CETH{ehsE֯.ApP&~~/Z5sd17C<wU2Y 05T-ao01zoρk{q3.Cwja8g z@TdwG0dر 2i?2.Ï31$s?Ӑ%x&8(818UHvUXh& 4j Wˠ1$[ˆI7k75q?R.C1ceq. gq-z,=25Q'}2SSMX>*>/SzZ4n \`f`[DΐXK 2%X #Y=+u,/8/_2Xtm2G7R1[7y$tnv=BhTT.5 H`SЌאyy r9y XQy$xU ڹ--y;&Qڥ3(Fb:eGfJ}:zz@&!R*klm>Zg٤$%zY7%[ZC7+e:٤?7㱢Ÿa:gWf(xTGD* { [X8օ`6+cU+yAG~]Z8!ڴmp,wC~Y9kȏ/y;z)'̊Í£,h;{8hDn Ǖ/9{(MFUGblZZBƿ)ؠry,9(l ػw;j1ᬾf'j {.`N`U7i n@Kw)л{qa<^|Jo7$@xdp̂ !,,bIb|iPcsEEa8``4'(P2ѮxY]{jE-4r`XG.-< *7eO?эV`y @ @a9}k2I! h 8!-t@J I !/WeBuB4MmE.ͫ6` :(a۹}۹- B)A`2"!8lTwyq2z%f zor1IF͖eLI e2.!2AZ[=D Ɲ<=>!h8 @ A&lq RFw}OA>t;w&,SF(g2/>58٥ՅٟPM.`.`T`2@ ȀH R`` 2`,srEArrQ%w5;y! =S?9cP(x&8uxS;(g8AvIН86}b,T/b ^`ɠ,@:!씅X@@ c="̏7u"SL<Р@ 24СÈ!6xƍ^ThƆCN,3LdF cv)cL"Iٓ̚*1t(Q#_"%ӝ *̭\5رd˖=$mЪpܹ]ڵ+&޽|p*ӘY aI.Afdɐ+Š'k:w:4-C߽Wv} ;쯲ڼmPq:2N9#qO/h<.w\zp&gYRK>TS{bt7ս9ӐJ&K8[Z@Ֆk]La^AaJa\EU|& DbxСRXbi615W>BVU^sTwdN]RKMuR*9zYoVnJ]2vFst_y_[vezji^D ֟ ցl)Z,h][p xldUPd\Ge:aqVD*LJZh9h_g|u{^jEUp&$EK߰K٤s8eԙїg=}kwmEҙ-X6˦~g^ •Z+lp+H %)p=H`aAa[Jrɹozdq%z@;@ҷi=/ @|޸bxU}kV˭ K > 27CezЁ\;SvFpm;H h$*qLlŮ 1byFQ\"0qAh"k#4:bPo)? qc8HeQxWHJr%+9KĊ[\# 1 ,egg` V H8aTRA L00 Kj 3]$dAuɆd2Ԭ5ln$߮/zSZ1 8 \S *L$610-HdF՜6 шJts%YSTQH *pЂlSP#h 2d'"uRӢf2^LmSBTJb4Q]K(Ĭz!idư W37ExqLiJ~h](hFRw v٫$ *GTEdu@IVz=+pxH8D(6Aҫm\cdO~K^[R,stng'&w5(\uD,ߺOTv0/v"N!` JPdGʽ N$eS@e3Vw%&ueU~a`@, @ _#H>#Ћ~}g} K5Zm9A'܀4h#Ԙu~Yg;~9鏏y'}d8DňOe̘(ԃA@k>$B8sC)0`Cy IO `!sp3::(xʸ) 9p1{cc>0hv&RK (Ei%`- S{w`5}&DUiu֒wN{FF_Fh$k$E!ip91t *rNCL0;ERyzYy{ɗyQbs(W0LHmWtM)6Fkb}3F2)!0cs$P A:S (UmUxwz+$ G? :uAP:uAx WWm*IR~ *;(\p(SN!s]Qu}וy<[ d dig>]D+uE|M2u}ؐlL !vkE #Jٵ-Xx۽աwA&|,9F /0d fXҊqxt!_#_M/X'/AIxގч,7P@ 0c04ףzNOM M&!b`#bl | u(U0dM nqq?u>8'&W#`Wp#k(*K@(&} N_7o(|y`:-*Ae0Pe2 0s+ {/5T|J<24A iw~گZLP w/ N"@[?4, - 0D@$sӣ5nTQ!Av!YҤI 2dK1eΤY)6g`SOA9tP/eڔ)ХNJJuҧV֌ZTWaŎ%gYdOa[mSz|xe)OlǍRD '>a%#^@uݘ2ggBi^53S׭v 5ϤH{^]4oڷc[q㎽á9uӕ~:zs7]~lב&޾9{]}Т[/%4:.+cAAbGD24#4+H@! l3.+0#S1&.ӆ oc ޒqs GGfr5+2I%CJ+>TmIG1ZqM6UlM7пHDsO>EJЂ@ DI2%L3@3zT\ͦP;H54OJ4**!T7OsTU9m3auG,eUOZY5c+bcJ]մtYfC˩|ιK v[nUo. )$N8$" z^&w_~+>Lr]W0o*fLM=t95CacԊ_8a%&HrXZYf2k٬goL:/K^I$CEBЌ.|%j$^~_ ,xd˖ym\V;6K0>[\&Vn9マ <հwܥgjOzR̺-\;\shoA=lɿ*ݖID<WCmXnSYv׾x]p[ uo~={(NII輼6}2r7CPֹY‰sЛOKܝ @X(;7Q}#`ޓ10VvN@ nT q ƿ ~+X9M{fT s%A* .h^wĠ:qD(EYQbD+zg7bؗi@bA.AAQg:(ъxGȧT3(ljS+t#MS>`?%jQ&UK}Gi4,UiUzU^y4GSδ c%+ < S keZ4Dok]z׻NJLYҬV%lKB|phc~_D1dv hf=ٰTT¦VaYOmmV ($}+E n C\ -BrKuŴTt-k{]EV!iyͺґha*YFvB@)Lwn_ם1 Bnl|i\#m/E4 _KY]X#^O6n +fLhDal|c?\"2qF4-b7ߋf֦~hbGYSIJ룡 52<"(q Bp x'&JxߥslKV<7۵2g@_π ֗u.2 LtdB4+ F"<(y6]Q:jt]j@{][TT suyM \QyCk@֛EYyƯ(kXg[Ŷh-r9.(s;aȈAdFgM}o2rwok;&x ;pF[\KA 3.l@ v@yq\#nry|7x]R V˫oae0ۨ'iH>b /:pIG]ʄ 3 4(e"V=W70y#79hB%`~k|W`~$*G,xSO{+u&YBZI0VtŻ==2F5?:Ǚ9iR\EC 9\4],K |Yi<Ɋ C;'<듾x~{[GQD44GVLWHrlPVY|ZߩǃSx)182,)*;"OJEL< j5呠!Cvԛ\mFJ;LɌD; ?>3Hڨ,p"ER؄P">ќqkѠt4KT,KqyuXl PE $4 MǴ\{$"a.-ڤ짧,2FPQ@мCl\Ml\ɍ ăK {113JMNDF͒鄌XiM|OF&K;ӣ/۬1+ıKK K=rlPT#Ѓ/G4I#Pi7bOo=Q e^|97`6< PDA}MQ! <0O)'KЬڼa¢Dm)M8R1S S I--Q)Z%A2B C4]pI151Ĝ U2?$MRM2T0ӄԧj5.I@R2 + @ԯ`CQ\a?I(8i <I/M֤R¹;xVhg5ѩj)/jUFRtAZ-I sXUvUQJ T/:k,"U,JJ=4L0'QlC[\ܔn\?JiWT@&. [­h2ďcDF47-.aښjSPj1q4W$.t=Y+4>1X1C h'[#ƙbҋ"V.\- =EEqXԚZYe _m !D{(4{u,.;7*-֕=uJȎCY4>}زmܦ8h9R /z;: ˵&2( Н(:Jaƿ)r_C=⩚4>a2Bp՟@K\(m({CscS7kҖ,+~N0N^)"dGz+ xx+bEcd}L>4 g#J cJh882mј&zt2}`ZE[ep.]H6p(1 E/)&, E)*_abpNhVA Y^Z(\8PƺW;,F75|S[.Chi=i^ϐS44ЀCDL#17&4FxiG`+; EM]]1e+6hwik=ݖ>1 #6 mJ(D@꼊Vd:vMk>)ޙ< Y+ Ѐ+XM bE&l؎N׌ L2 m*J%tQ‹Wl8ؾf90HdޒJ@H z&x'*G5(¯Un2^A H'Lh0QoJx5ȵ/C@gꛂ"no_6?>) 2K2jqmRK9 FSCJJq& Ղ%{) &6>`M+&0Px&-`G`*YbNIp-&01n!OrJ4N:.ϲ(?HS岏2\'9_'sMV:t|e&?rHA2s0p/0pޖKתMnn%C喾rl6(( :ӭW~IYujL : rI/?WiΩVcC Ȃ'dDu7jw0uN t!B +h@qH xu ؍viwmyՆwW!z IyyǺ * :ݒEr{yoʡ <˘ P-G̸TY [-"BTXW;yGk \d  6P@_ ,)X4 nҰWzy= ). B> *qHzxw?}|7߈* /8>m>))zLxjmЧ'}GwW1  p4@(dcBh ZCws:~j$D0x ;0 8B=س&܉)ޙ#qD9/bfc:?ʡpj!ɒ&OLr%˖.Op)s&͚6o̩s'Ϟ> *t(ѢF"= 3)ә@-PӨ"`*f+׭jq5F6Xf-7۶"w*vaPXH(6a „ N ƌ9j@Ru]@ڵ/S!:1be qtI<1xt|L%NcϮ}L޿w"~jZuÏ/>WYOnQ"BE@hD 68!baFt=$'$&V؀F/z7☣;#RؒvyGbw'"P\CBŁYW*` %$dB۱9FW]odw[6٧L9BCf)1DƘ ",a0PB N(]UHA 4+HAWɧUt`d2D'W'RX2ltj91pY %t# 4C %lP@S\:0 `BD'xXPAH0d Fl'<ҦvZw?OAC&K3m6(dQ]uaYvF ]vY3B g =)'xHwVFtgԯiw`BR.[A%xBHWu͒, #=ꫳgyUTu\o ŧG$cϏoCc5ާ" 4sVq`oa؅qP"(e7PP@-0H;ő/fi;Tk  2APonBahH0: {4gCc6fD!XJSO_ Rd2x.rAx32)7*P %2Hzx,c6! a`bGUU!^Ԩp z$'I1Q;WS.I<\ !?!!QLxDKNz%W.Ov2\&hzȣ B ёP"шn>&0M,[';;b6pŌh\jcL=9'?sOAF~q!hD8)JhȐb@ 9CS'IKjRΌL)PR'+ԬϦ@TEI%<(1RJ]2 iA\ѭ IJ6۪2zF h&sTj]+'z *wJd\SF;ѵt:3"nDOFIUX&)\EWjd# &6j R-o+*m*h-SYN@ rz'B⪡b(xL Pî6[kW2w<ER`"t@U >= 0AI[1 N B`й9 Klbkzl=)"`DP7&,P QE2x%]cƈ=1%tUdAlejJ 3i 7gEU=cV(;9r.*Iܝ+`I3 +VC73s4QCb4VHr4d 0/`kJNn~uJ:IEW;Uv )`aC,}<-+\5%iYC;Ey5|2 NF8B8i6 \a]Mل{m:*ue9]-nD䬄CF! ` !iGz4nM{><Ә(G0sUvLt׮<ʐ8vڙ=){iǣ)7=U2b|tZe>|^!ؙZCіGHhC_i`iwZ%UX0_ <ǟu@R±}Ի\ztRh|5VҮXd!AdV@<@ ՠMxezaj`h`*Ъ@*qUle,\Vz^~a U6Sԅd[Ye d@ \ d\J<h \!`%XaԕV ! *j*zFMAE @t˷h hl@`$x(>a)G"+Rc?f"  ^ @d@9 oL:j ԀXid'-bvE#Mc52]f`yV|@֔x8 yM Ā  'dO!^an=_>cHnR?!8 J]l&B%!y#G HOI!djAw1K , R((!Ԯ)OzOeW>P&E6^ H  e (% 2`l)Wz^jX!_IA$ew =A=* ^e_dgVHaxG%C` \eQihh&fڦ Y&$ ] 1X$l(&m؞K&mb5&]!,!7¸T#L%dB'x. FJFȑͦngv'&]U'!0CEBaB&,(&4OLYMI&ܧ~j('QP h% 8S#۹OQlhQJϋP `@l@٨˓H)[L^Vhdj)tHiLʨ@bߛi.dAquni::2WPʈd haǘj^]h3eb*n&д駂  p)`<)U\j⪒u)l ͈(P0JAXPX|۵[]FriZiP|迴۱ @؀y!@OAd][Rk\N8*ƹHxL%  A_ϖ4GrX+*j,fGzv,a "4! @C 5lO !хaN H 8V@|Wb-u+"r TEPDXAXA@ 8Tr8k,N+f޺bc׶8lhHhք  fIL 8\|NNF\,6-ߒm*gԏ Gh X.j9.<FAI*zՁ?n:5Px@rLf\1 tY, C8qks(\>o*!2.]ho!Ɓ‰운/2s~6+dI ̜\۷oQ_N,tĶv  P$0w Q =V~GўoRq.VNq]f\n]\J /q13(nZ"3rЋC]ԊqqXq{1dۅ\)HA&p5\+r+?,Cf[I%%crkvyt al.hO3C34+̀-L- .n/{3mb}Ƨۅ@8zl@.OI]7/N~G۱\؀Sp6+h?o@$A(d`  2rlvG?/H,RSl 5H'\wH2&^ެOk 5u^NB 4j5YAZIVsV5v(5}W l ȀpX4!}YQ 1&uchOkHS tXnjx @D_tBcc;vj,dk0 &x\/dZ0L8 Ҁ0kKv3.iӵj+@6Ϻ6jI@€x@ L" t,s$ .ɲrkks/MprB(HslG,A X|þUX"HC.$FlI˖"\$<΁ <0,b=[L/-~[n`Q?%BZt ?&w49~]rWl沗8ODHD ouNw|'Gbnn'+Y#H$NX$@ Z `Ɛz2Y(ZQ lJ҂@ Q~Tlѣ@) XRԥ )YӒ3 l@C#J PsM-Sy*2ŴbqK A-VL T i@UY: TaU޵^=ՑNM F0Igj QYW>$([Y\լ8E)T&yTIh 8jY li[[ny[Jp[\EQrՉ⤐xd[ϕSk_][!@x[^Uz^Ep[_w?9j]`vv$$`_@|U] )\a _9a!q~a&qO\oX5Έϡ7@5Y׃0hIVd'?Q\e+_+ɑe/KY_) 7h=2iiSqsyPg;rkYB']hCщVhG?ґ%f ҙִü_- t1Y_H9ptHޟ]k!`yk_]lcǶt&plg?{؝Li#d+mMR:ysvLSVa$]ڏFk[;E(ż]o{ox-vY'&IW OP Ra5!)H^r)WYr1e^p/_xo^J f:3\d> 3Et -Qԩ^u_Yֹuɾ6$8oő^3 $(2遟rn$?|Q~x/,|qn#䘧Α;mȿ[qIk*UMbAi%# wuoo~߿ { ?{r%q 4>dik@o~ZGG￿?ǟ/ ҏ HgD:(.*}T/chb6jW4? g0-aqO{ipssP[7 kp0 wP  4Foo4BE/.F R Â˼,5al00 Q qP:- e$~f=.*Pݪj@8^jf P*-q$sq|Q1qQS NQq: GfIL@:ѪJcȫ%1 q1 Q Q r !r!!Ϋ"" "/2"#pFPWbt$ @4=&&k&o'nr'u2hr'{2({&''R)R(')R*r)*r(2'& +ò&*y2+R,#lBGQG.d>2&bm&^2&) S00 3/3100O0!s223-2-3'2A23=1Os4 S5 V5+0541534_S5RL*7S`o `&"HR /)::;S;;;;S<Ǔ< =;ubGG>s Q9J9#%9:s( @ @ATAAtAA#TB'B*C3AK(D@&r`D/m/S&@_t@FgFkFoGsTGwG{GHH NHH{CBԃEIW%<#9aKKKLTLǔLLMTMTM MN4I+Dqm' E?DJPQUQQQR#UR'R+R/R S7S'uNͰO?2JIBrIqiP UVcUVgVkVoWsUWwW{WW XXwST>+BD 9Jk $VE[/ U[[[\U\Ǖ\\]ϵҕ]ە\UX>gڊVZ/`V`` `aVaaaa b'bvN2UU=t!2*.]_dӸRVeWe[eck^Vf{N4J&t$dJdiz6cGgKEq||JZkcql(kklVlǖllml6k6k}Vnnmo}bboopWpp pqWqqqr#Wrr/rs7s;s?tCWtGtKtOuSWuWu[u_vcWvgvkvowsWwww{u5t.xywxyWyy׌yzWzzKxMWxx{{|W|Ǘ||7uzb}W~~~WX ؀X؁#X8~'7,3X7;؃?CXGK؄O~7 ;proguard4.8/docs/screenshot_gui2.gif0000644000175000017500000011002711163773610016311 0ustar ericericGIF87a333fffz̴θνҾ,S HT*\ȰÇ#JHŋ3jȱǏ CIɓ(S\2!K._ʜI͛8sɳϟ@蒇ѣH&MӧPJJիXjʵׯ`ÊKٳhӪ]˶۷^fPtn*x˷߿ LZb+0]Đ#KL˘3k<MӨS^ͺװc˞M۸sͻ Nȓ>ṡFo8]سkνgV_9sRGU=˟OC-ZSNؔh& FR~Wa6N Z_(\-bv^U3ȃQVCh(#sF=_eTyM9'%Hf{BHG#Fh~Il9K p0Z"cX.T柀!ihRf蘄2裐ss(KUJ#{Z:*jW*Ya*+X걇ޓ|r{Tv*c:"5d&*F+퀶+sr%WN+nDzz*조.uk-:PUYo{.ˮ:(p+I :j_&*gtb e(+/$,4*c(7qh~,D}P6#J FG-TkƲʹUw`u!٭͚ʵp-tmx޸ 0n'7'~Wngw砇.褗n騧ꬷ.n,7/o'7G/Wog/o觯>p/og7HL:_&H Z̠7wGH(L W gH8!<(@ H"HLD!Ɛsb7E"檨uъ` X=hL6pH:bG}rHB3 PF:򑐌$'IJZ#9=^b ''PR(WESbLe+U9JT d.iyOr+e,EQvRD% Lfzҕ,e- [̦6ICEg'3=a3-Oh,@YOn:ݟ"5IъZ$' ˁ Ԝ}GP"S$%A=zY擥H Ѕڴ HzӜ  PJԢbSR.UL}cjǍ>W'O}SthJKXR-])5eY̘c=fA*ҹvܩ>I9 `KMb:d'KZ5l*j9E6?bhDцE4-jhU֓v=W9NgHo65uPu2k]uJRFЍn8[9E!bv rRvK8wy6seva+{kSζ#|)Mr;F7խC;놷nx;螷r[{n_BH;Qdx.JW< J,<G(OgpE0gN8Ϲws|@Ї==܃җ;PԧN[M9ѷ{=s-G:@hOpٵ'V;5OOx:G񐏼'O[ϼ7{Gyˑ|um` gOϽwF O_$HE;ЏO[Ͼ'g|OO7?O_8Xx }wpG8Xx؁87$X&x'|˧ ,؂.0284X6x8:؂xa{B8DXFxHJL؄NE((8TXVx*H9 \؅^`b8dXfxhj؅=e?aCr8tXvxxz|؇~HRh0Qd 4H WȈq8XH؉((3؋8Xx؆zIet78aH ъ!݈(X(Ȋ؈(3q ъظ؎RĈX؈Yx p ِ9YyِxtAGH*4I/Y4ُ:ɉ-6ɉ1+Y;FI'I(i'ɔȓWIYRٔZi\ٓ89)ec?)-ؖjyh*9/I 9|3YyCZhDuixNY)O)9dytyW@٘ٚ9CXiIchٚy09x)銸Ɋۈɒ ٛ E )YIzCٞ <8ٛ)Ĺ؉)BIi):i17izyәy"JɠȸE袼,J2:6Z ;٣>3٠IWyZ陝(E9|:FPSJ[:qD]gy8XC8ek\E^XJ]_}ʧZ|9H@:BZfjbʤJ:JPʙUzڟXjʪN9izd !:E:I٪KzgZZ{ʂ QԂ*:.RDڬ:ݺ zZjj* ʛjt|ȥ9 vѯjN:Jꦣ9%ZYʧ رE' %&$&('2 㺣8:<۳>@B誘؍ie2Ihڥ(Kɴ[YYyVS˯i9[YZ[Y{WZEjUai;nzt aW ME۸Ч˸븐[ Wa)lؑ}۷ X8ysK 7щ{Im mlV̆;ۼ˹@+ *C^ (+ M+ޮzu:m{~^{9b>d^d ָap䮊 TNmI|΍-荎\=^~@1p~䌙jJzX~t뫱mJ,ΠI~򫐏뒮^&O*^ vc=]ӎyi?.z*z+:?zʎA<%Y. >r~']..{i "( ,? #R |<5*ЋCGOEH%T_V>R _~cbo]fPVrתxʭ~j5h8san* 11-0K/ Hr6_?A58|;oG{}b?ȟ˼l˼;ПlOk^o_{I꿿 l LoZ1J@ DPB Qb/ HQF=~RH%MDRJ-]SL5męS$FTP pѤ@6ETϧS.ꔩU[6(ĉ-^JC0)uśW^}.Y{DXbƍ?Yd0yJGfΝ=ZhҚF:5af ev\TmƝ[n޽}\8n c\r͝?]]vݽ^<͟?mξ1]ǟ_~) @D0AdA0B Tϵ`s6چC?ֻ@OD1EWd1.#FgFo1GwG³P6,ɮJ&zҮ(ү-ĨE-K/ L3D3M5dM7߄3N9>(>OPC>0eQG=QL(&RK/4SM7SO?5TJdO#UWeUW_e5)WeUUZ=VW[wu^ Vc}5Q eYgV11Zk6[m[o7\q%N ue]weWvMJ]y1zw]~ ހ`UֺhfaH&b/8c7c?9 и"DuWfe_nRIl9uyY9hh_NDfiS|j:kkjD9#op$mfmݖ*nvo㾻'|:qg{7G}?~7~y!qJFsL.@`@6p]I`R(AP /b-@P_ UB/a /@|CuCЇ?b8D!&G! YD&6Q.a(Cd7E.vы_c8F2+eD#D6э&8UqeC G>яd 9HBҐDFF6ґΉ#%9IQzX<4INvғe(E9JRҔ"JVRZ )9Ej,gIʀ7C09LbӘDf2Lf6әT+9Mj$,-mj\b-ӜDg:չNvӝgq{SIT06r-W%*7O͏}.Wc^rk7?ېG&!AtP3¢_D!t`.۝H{>vWG{G^Gr^]>wv?{~ϵ3լHYzLdx7ސy{}-iO w}EoJK􏤼*Xٞ9{ofO{7>yo=7Wb;{G~xg7|/1}w߷?JD֣yi??'gd%BTd@?῝C q3ĉl 4("+AْARAAF !$ByDBhA% b()4#L+%dBsB0/0cB,4E-T.G,_Pl4D TTDQtE R|S [X3(1 EAV|`XED #3CK@C@agL`jdb,Fʉ/L4P4]JôQs$QӴa4jw lFE(`_#}|\5} 6]GbsGxDǐy03Bl6ojHn6HȌLȐ|m䷷}cɖ|\Iy7z{|KIII8աۡ8l<ʦ䝠PɩTL$+- l>9˙3K{9#˓˰Ğʸ|d.d? JsH>;#!s*:۠d: ꊤ l: !\ T lD<t=$c4<*" 4Mʴ, l$<+IMTMNp+٬K*ίEctT$ Fͬ>ˢL%Gܭ Jl?Oh2OOTOTξ`EUPztБ%M ЌjP P K>5Eї̅Q ч< e=}QۤE!}+#&Q:*A"u'#E)= },-ٲ03"c25S<"T5eSZQ1EHD<9SG*jT AitGU0DM`\TA_LM3ITWTUQ2)DԓO:W%]R9 UR[ENUCLlT12EM5`T]:$FFh,GuFH=dM3\VӼ0rW^uq oGR#TkV,V!qR9*~HǁaBvm$\"@>lX+‹nHȌoBM\X«4Od$IٚYّeEΓߪMJ8J-JUڌ3Ueх]YMNzN{eRZt9K,[c)˴E۱Zد˟dL:̥\l\ܾu [nJ\Fۖ ͯC;}([ITe]ҥ%ׅRA%QݽIZuUE^S^5^w鍼B %^_&u_BE;9__5 R(U`f&] vv`˄.ֲ 4mF`8a^a&7:Z4aaF68g"6i a I!_%'6kRb4?f%Z.VEbmEZuu6VU* ccxWLdK*E/I6+fؕ}ފX؇ڥ(.[td(c@2A6ٯ$>eE&|eZ[Y_w{!X5|fx1`2A.m[+N- LhH6slfɕcϔ%Z{~MY@Zـz۷Iy蝕yNaUӥŪSJڋvhcsK5i4[5!>i鐆^dܛ6;:<ܞ6龍i/~;ZݤV֡&j2jGK֥ꪶ=p8hf_ݰkj>-޵fk-k>6S޻}k-NDZ&k,625v =l9jvȖRlE_A fmVXʮ,>ֶ |m&Yٞ&毶Xxf^..n21,Fe=36f~k/nn2rcv5ZfΧ{.,mzgpD|6F_"/o;)BqJ$'WnWW&N 8VZq]q Gn _rq#ww<]qVUs5ozmd(^L]\ap*r-oAn~Ͽos Q6i-D7pAs9GGSFNknW^ev\FwFJ a&{G~XS/OP0sn6dH6xnuWo#X'>*GٹAhN}Y]ve'v~u_*HߛhVڌ.ށՙ8vi>j:pEv۳Ş&i˖fwrg!`0U\L~g{w#SfxFDjO"OsAWwDIWy y/y::m뚷ky/y9yzyy)+wz+zO)Zz{z_z7{zO${L{wo{yйo,q矽_@WgwLJȗɧo|'6||wÇP!W|}}3p/Ȃٷڟޟ}. 72Pg'ׇ~3ҟ3}ߥ;370}}'X &$$, „ hsG5}P'wV !>;ӿޡ#\WӸƷ_J:ia;[=b+;9oCӚ.4'  f?}/$–%RAް_ B{ޘzRW꧿ ryBhJ&< R +Kf9a֨yrqO^d]l`G䖷ֽv|[kt6_}i"Yq)nTK:E.|K-nwVcڨȼqDxmGN{ɷv˪5|tעUƁEaB&>qN",aWg;AV0qJ)1,䗨xQi nN^p&@Lғ!s˸3af~Rbf(r e/ӹΩ(263pTقXre{/ev~4Au'M E. q+?s21l =jܖuUtϷIGM™WeiwY}3x-{~RTᜩZڣ)vl-o֪ӢOtGzд6mPylHomieĻN0-{fil1;qxg ߃w4Y#t-9g_Wm>sotېw&nSݘBRԚZIxlLO20VԫO^H#^mNk4k}V6b<:riBBa ש Uxz_mV &T; X)/W\Wї[>>G<.f{j~\rҳ;tp^9=^߹`\Q1Wj]v` `iE@!ȱč z eYO׫ `A]u Z!}ߑ^ 6JDa maWІaQzE rGe*XN"։Y9zs!Wkd`dI+aJ#.dʯTE""5/=J2K׎ @9 .V#;*L]Tu㚨,>>RD^;䩼cƵ65tJ9 u}G_$$F5b#  ,-}T-ђ>?a@)fLNAG"1bE!$G:$RIM[+ 4i T␰eQ&%WZR^L=4UGBNd`e,ЅdW%d|){=l(dZr@6%bN]GZG6E86PavE&gfbRZ< !YEэ|k&kR jŰ,ꨎQJgvf~pҒ$dd#"LhDtN'uVu^'vfvn'wvw~'xx'yy'zz'{{'|gvn$G6-BD7Dd7f}/clYn6uԧE9eTQ P -#ԂB(2}Z,[GÑVF(樎 [WOJ$O9[J4D[Y^)^)M9=~)))))Ʃ)֩)橞))iٟW'`'Ql҅r>P!^*fB ~Y^pFmBFfGDzl*v~53ȣD8).+6ITzAaS#f.v+€?be(볶+~@48ve@"+&.l+'ART%`tc"B% 'Öɞ,~H'*p ֬,ڬ$@$@-(R@RvHJEN&mf,-ٖٞ-ڦm6&Pj~JRXmE֊2-ւF.wA@ <.FN.VnX&$Ж.a->&-Қ..bmުn^-..ڮ.P ./.Vm6oF(/n/ÂAF \ _Xl$H\nll.^گ2/*.2m0 /nCR/B//30;/gp~0{u]X%_""`^:$X|[[mnV0://p*poO3?q0kS;œZLNU)l@i"0Bg^(W]Vˀo0q PĮ#oG1V;r *!WĠf&o2'w'2(r(7%9$kO,B$^%KNc.###/cq2"/7q/0s3?r4GWr3_s.so’`ꮘ0ԀM]Ȳ:FH.+.C /s143322cs?34W0'#rg;sV1A47W†X-*8l,#,II 4J"B 0!l&<]<zQYB q>n>'!'q5[K3CuQs/_u'psVpTK6[4Z!qi|!p'PB$5^5Ā\B(XB^v$0l%,B#&_E&Y#dgpv5 oZhVjWpEJZ|%%N6N`_B'm7Av $Bl|V3fo5xvghwkh7xG0 H P%APA$' 8`^p"mPwxx~Ghhgo>w>臾>闾gIis\*`A(Wgo?w??g_6,DlS~o\@P4@4X ‡WVQ($(ȅbEV0f2E'A..TKRŔ93L7qҔfN6ygѝCoM4)Q<6eӘS"5jOXn]jUlYgѦUm[oF}*ٱpͺ&LJPB{].F#˽LP4k@􋪪0 /NA QI,QLQ=l*,d,N;#j.H"k8C:٤,"bV#Lh b1Ҋk視bk,7kM> O; >>/3P;<) /)K1&pos1/Bb\A%DK#R>!۹+.U4>`w_M-?|. /Rzܷ/NTz,_ oB+@.~ky8W|K#A n@A4Hv0Bp$IHkN q4f=V< \ ;\ݢwyzJ,='V/?MgExEmt^h=󍑌eL^(rS~BVIuG=} &xb@򏄬 HE.p`y$3]BY 1KZ:@: <2rHd <'HۢZL#DͽDPf;4fmk=/b̍+-MUfTFmnSag鵶.M_{RJt;Oy3 ;Y|?u>2FY*sKbQ-G:JC!h]UDBۯkqkof\x91a oyRCE&M-0v]݃<q%LB@j,e:e)OUr-o]/<Ѳ|f2ymg02$͸-_8  D7x3׼ƅv]5O1iMoӝvKjQԥ6QjUխvEMHUfiݲd]7Q `4 "],$ץa(,=.OOնZ?;lnq6ѝnnڠGceM &Ha 0ȸKBtIp/|Ac!qO1qo89Kf4*D"M4BڅƬ`E gρt~b0ёt/MwӡuOGg$9euՈfh{x@+pBd_>wcyx7x/qTp#! 1}4 __=$HwϞ_X{|7uO[_1-%ȠN! QB؀? sȳ{ۯw?[Wϟp(:Kgnߜ j  LD`mF0B/Ep߯~Q0UpY]a0epiS0\ ݴ#|JI ʠ n0VުKd„'H nq` ɰ 0 p ٰ 0 *jo," b@fT^qad``)1`99 3:+ P?Kr:rNG@Gt$힦,b ЫB-B+ \7(Lw>ID/?4%W%Z4EmQ@[@ P5.0 V/6 !6AHHtP  ɐWfsFDJESEU 4FoQF0'@IL C* A8a=;N4O;`O! R ʬtQ@tE%?Ls+=fnX#4s8.rV``v`p`ViVi5Vw@qlJWU?KXRS SS't|0 ~D;iF@d( !5ٚ$8T3'ZÂ( qW]ʆ5:#RUKŴYit\@S'Sb .Vqua6'y~a/eY8P;]ߵc='Ru^^RqF .e#? .@ (!@H17@fuGB]?fQwI>viV:IKuR^-5_Lw%ZCF @vlMɀ P!)6n営9jMK?L6fzF+ ttDMqD d@ BA`Xp.4ucsA7SdIWV'fpXLGzdK#b&?b hW&-5zi6txftK7ycYYkk5r#̇BSX !X>{hus|BVy%O:S[ZOp<`);Wv@z`>1dt|7}xyUywģuɾÓD"N"ǀL"҃6 {KT8<w6exc!UTQVcsq~ w.s  @ЪX6 jרp]wh(l!}:BgmM ,d@q$Ar8w;x g}xQ%3FCcgz 6@!A7#aZscbUiP]a9eyu~Sfp.Z#`A e$#Ryc[yy߰$:ȇ970DقD"ӹ__헜Ey5Yyy'w#X~w>bؙ@㙐%xK7iu{EE{73"WYp,|$y]D+ڢO}1DПL ` @H 4\4åE5_3ezdY|eP{s4:!2x> 8A:!:oF5NYc;/ cz3K4zã7J ,v"`( : X@ ( cVom:4a[/[kKBYz##v*Gxb@ fGҳIƇncriXm[yK-4!4H(`K<$4wչ[i{aZv6]t [;QCUR ZG*@@<>䘹I;J\ֱQ9{ĩ[SdU"i%Ds @4` &T<2`` @ @5o #ږI|dEj pk,@"aE $rg#@T%SvGGəGMR\uqRQt,Ļ,9,@\`^D  / cpM<Wo}}S7:5B 1Q g (`Q`(7O=i/U|] | \zWC>`@%6FQXvKYo]a^q5`+-4bD@ wKě6al:D<?[O@K<>aV |zC>НO>|^Fke:  b0>>hD}A?ox4<ަ, >!,l_\L^SrQLߔcXV"T7aJ*sl)3i~aA' 48%… ,h%Ĉ NC-ԦEHJ, $%'["Y3L/ټKR 4СD=4ҥL:} 5ԩTZ5֭\z=s'd˚=6ڵlۺ}v,NdS+@ϻ<92a .l&Ō>8MƉX9,;g|ٳh5ҵլ[~ ;ٴkۦ\{ K9ūx߿ W|ᓙg,)0@ déރ=(J.ɤg]h^]aمmƢMDcffjigrΙ֐ id ts)VJJJ=)-(aB"DJO6!al~ jJ*ln҉jfqy*W*Rgu%C`'P]Ӱ>阞l> Jm֊ŠHMvea nꮋnP0hPvKovm pM{mj]"H)Vq7AqGqg, r`DE*,gW\EV:s>/EBVEn k}rN?2RK-ƅP5PubFf38srMwAwe k5Ԃ?DᆓkD7Ce4H_yg 6ZݢNz0ޭwx6[L{M= O$|:d}OB/*x!4>翿CA0AOeQo,bG?o^XG{ձ]dEljD(CrpeJN; , Kp44] ? sq@auy+<(Ԍ<-E0HBqZT_5,LrY }6Qa vD k[4%TVC$.AD*2@KP" %.&/peC4r=:юw\*{xG#nh}I➘73!Ϗ@Old :HbXD$:A J 3591&g7)SZ+=a+xN;ќlj-" i P #/ R0'~C'E(5?-lZ6Mpjt8"s$ؽXiB[E_J7t2-(a :ԡ_j!`Bayͤ^OeG ըjrHR2{(gR`d͘ƜTaBK'װln_WJu-lR!aͲo^eӸ/uMv`]-^ %jao"ցSW!U+Nܫq0` 5Vfә XxO ~I3ͭwv™l*|iU y0H@K]a( R-[~kneJb$5Đu2XAΡЏM|1]x$O\'F01Ax\tB0!#4.ޅxD&Qd 8`hdW ZMdp @'ʵ~34In D5e XHde ƃ3yьی73LVHHd63Vm x9([ؼ605@N XMBoLs+@~-vk({ʆw`DdBƜ_ղD\{VЮPv+^Xj`'~f <'\Rd䳠t.We3'8A6KϙL𐋼='x ')e3X^/*l  QD G })Njr P84Uam!:AL8ڗπX ώvMz"Y|t[ x`C". Qd1+B=o|TvũhH:t. \0$" zIX"D$ AB,dQoɣ7Mr~{ ^ /")!F:jK<);xJ/3OqꓟSKL[hovMBqӖW6St4~m! Htw`@bDK0Kdv@ A2n&6A!Y!mN5hNCTNfX@P\S6]'B~t<2dp$GuJ Ua(YHY?xKB.~SX@SczO6jAV{ٗQZHDžJJDYXC#q)bGh6'865艟؉4%8X__gwjfdȃk &O//qK0M5y6'1ƶZlges,TȨ`Xc(D[%KtإB/<)\R44%Xvg(YFJUa5)S&; 2P]KÐ15[79=hx^jnL6e]\R3s.`+O P1JuM3,~)4i] Ut<ك>}@9!"( +<TMIp.I#2" X@gy7uwQ:^D:* %Wq@Ie``@ %`<& DСQKP8ʳyQ1TxjmK6pb9B,A PK(k/Kd`VS $[;ki%!-@ ~ :y뼒q.@ y5~m E s!K7Y%H#!08H" cSX88c{ q !"0PP(X &ƣ2]_3sxB5l#NK96J;<IU<꣭S /2exV5%FA[B61g{;C7HNGfXUHaФ[I,/hzqgB1Vi8Ņ/aF`NYl_8Rm<Ʊaq! f@)˺Se U@)zƏ]lȭ (Ǝ5hÉy @FSp(vBO9PZ/qlvlƎ\R[舯3j+@Uepb;311VyjY(,,ˏXqtULyZ9/ &`~zzF"E'pt5VQP +ͼJNY<ƴ|ޜ˪w|@u1q!''@Y+ RE('A[]=.ݻ'%"N@`X`%A-Q@s*Ձ}#oչf Pğ: GM`2` 08ZՂmmՅ}R틖ҁm_d|z_p_')( p'_|]b(m\P_\mMs]w M"6A7:S)ߣH Xݳԍ_B+g Pd68W` C` -Ts,Œl#w,ܹԁ1B An{)j(p$-Z1N" pN 1 z1-i1p&HpNG^Y2?-`Bk#!`-%~PE%B @(85O]l6/o+>~I#) g @:E| 7W0/܋Ŏέォa-n#'_DQ /$#0p׽N;t p3h M'Gu~!+)X2TJ `RXdQ/)ǼmߖWiS.PW1Wg ~6Non@3T}>2\;ET'IPw,?m %v>xxxcBEJ;Nxi}Y|p  pB/ذ/-ӳdMJr?e] 9ZΦ@ W~VVr1I? $XРA.dCL`*HQTaDRdI+)Ue'ODR4htABO=mhӧP%iSQ̜)+WfիW-Yiծe[qΥ[]y_&\mY#^JB<`ʖ/+/Q>#ȣ8pTb lj%.ХI$0CI$EaK,$Fs1 {$j*Ú2HKsI(rJ*JoAD@DȱϿ4|h%)MB@ݲӮ6HH $FJ$I0zpQH# ␪;j$)I,CuTRK5TTҒT@2KOM3ims@0{55lM#:?Je7b-Ί2'Y?hC݄b 4ONOSw\r5\tZ7ϼL2L6|V/UM6BY"j m2RfxR{8l e/KtCydK69utxgޗ]3MM5_)=qhG)OFݐ ,0v+HZY*ƬA^H$f19DQRYPDUNN fLt#fXbF76l^*cSܺ"NxSg=yO|StfƧp+:RIDp 8| S-P%/99hXhGC*fT?S),Vڐ@˅zֳʠ`0|S ҆Q&UHs2na5; TB0DڢD `/UssFnKk_ʞBUN-iҪZժX)@ВlX"bP\"B`%Q miIԦk^g׿VL`{evBP/[`Z P`P|.?`4 nwkymy{`en:XX@dKϹ!Vv(ACKp`X>hm W6m{a$-pb8@H.!,deX!bZ՚ִkxջDRX;1 jV5ū1M`K8 d *I],WaUqNYTu'0+`D_^%o#B<AsH_&t;1'zAe-mrd6ӝ UB{klІ&uhE!Ͼ酕T:m"0A}ؖ5T,1HDD0n:Zv U샰| 8%Ugpх%2R{i.gTslx;zΆv!w]7CyP @^8a0ʪYiF-ogd7 GS3&3I\ ` J jVD,PLAmiaK'zDfy %P p-x`xB0b>D;lcwLF{S+zKiWOH >@G@wspWb`&L,ߒov|硄y}tJ8Կ:"q_n} Z !8 ~%i&H~mܯy'_J=Go`z8cQPҐ $^Q_~Wkvd}Ax_Gf0'>;Xc8K?L@X?c/þL 'xp4 3BR Q*T@LA`-?r'>$KP7!&;KYJb#B4DUD>DLDz]8D,@A@AiKEKHiѲAB*BtZEezGRr*},IJL 0k#II=IIijR0zG|H#XR03?I3K첲4 j IKjt<G;'HMx=L,NjHD(H$0̠||M[L44ݸȬ2At X'خ$\t7ׄM\6ٜM r N"@NHi&4@tlNꮸGÜNN z)G+= BHڔB1Ot˔$JܤPOJ:lJ'@Κ4BO+{ȅ~ЌJF  %3|/ ̆Q$%7XR&]:B%,(2HRX(~4M˔P0P֬P-S  `t|S 08"`:?5XBLQDȊ\iTG}4SIM'4Mq?2ʔSLѼٝ `) xKT]!h&YUYK[KHIUPTK% ƻ?Q\Te]: 0;D #p٣=lVH!B)LU_=W:`ۓX0.s+,6pэDW(u]UFtI0,MmD mD0>,+Mr,ִЁ Yc*Xm'*~W+ @ W<FY Il sYe -مXS"]Jz]$=ԅK3@'X2Y-ZdD3t Ԅ(80FyFӺ,8mP5ثOZhLӽudGZ]H)L\\-,ETĝ[˽{{Ԯj*IZ-]u L؄2+؍]]4BIp'N]\͔ͭȡ%FDRD- .Q`2̚^^C8P.MRDA] ߍ;}ԁ 9T u˦,G%D@}(T@_`t޻G,ƞ,ǴM6؆ ciQ4e@b/ Y,"`H)5xT9jnR䑚u&ioe!AohAQ:әP#8p07bAGpWD˗GmTP0x|H'30?P}-75^@Md_PqƬMLǃM$`$0ЀHXssF`^:q&m'7KǓODIGH| H0_R^QDTI 6o~tBZC UIpF=3LR0J`^7hl%qMwzHtD _H^KXd pr+#Li-@u]j^GLLgLb1Nm4 pu]+V'nowƓ(7=-XR9+sqc#&wxWtB@=:qsw/pH0 vcQ+ˁH [\ci"xy|&D.PUzzYBp. FzW ?A))zŋ 8zQ>{_<_/ 蠏-:.JGg٣/|MN{&tLJCk@I%-?IqB-K%}7 oA^x0E"@_ZM@o(A<8?y txXg Rp x"p@$$𠑆iQ /Zt1Ȓ;N )2&O|˖4 ͚6o̩s'Ϟ> *t(ѢF"Mt)ӦNB*u*՞3cbͪu+׮^ +v,Y/VjyP92dv̋2VD>+] Feq2 )^,y+W g*l9*ҦONz5֮_Vz,ڶo},ִk ^5y03{2u.-&};d7f<χ;4ѱÏ/>9[7[LZ*uq ^9F"Pbb]4ф!&Q'G+Dg/>ހɔ7☣;#TC&KoHJfuWs҉%beVVQEbc9gfjsYw&${٧h! *@1%@B`U$pabariiQfڪڟfjp8aX"IgR.Da)E DjH[[[.Y5бiW]˕Py]gB] gS\s z +D@2,@'3 yte7L (% W3X+2 дOCSS]Wc[sݵ_c]gkvHw&y#$bҚ 7vE߆tBIC*z&4s޹Bz-S\]GW!Es1_7ݢ#3߼CӃoE/J0:٘}?>s;Rg"]N_㟿~{Nd&S;! \ 0B0*h !ܠ8ā"t>g0*\S0/M08,&7o3cH@2@P"jiD"gF-$ 84]vEÃg\ڋL_>mKʴ#83>?d@ @dAA"dB*d@B:CBdA#(}%Eb$Aě\dy.Qޫ##?I JdKKdLLdMdKMNdLNd*d/ օ]9Ifd$A$JJTUbeVjVreWzWeXeVXYeWdSb[f": 62Re^ _f` `faa"fbf)fc:cO^02GUgmfr]ehf ifjjfkkflffmmZrf٥4"[^q"gSAr2gs:sBgtJtRguZgsujvrgt=E] kO}ęDerI@|g}}g~~ggg wS"h`\;v/{R3ԅ~ JaXݼ qpfRRHd@06qVh3.g/~afh (6 "Z-f&Rii\Qj)IizەPQii阪隲iiAŜ)Eiij j"j*2j:BjJRjZbjjj)ڠvꦊꨒjꩢjꪲjjjp*jjk j**_*0BkJRkZbkjrkz뷂k븒k빢k뺲k뻲kkkkl lrk@;proguard4.8/docs/steel.gif0000644000175000017500000000530711163773610014326 0ustar ericericGIF87axx,xx@p(,F"l2/(t@Hثzm3,&Dښ"H2Lۏ>ghOYkUtn}qKE]w`p_h_F{GHzp~b_S|voBMµĠƻ؉YI^{ힵ͚J]ԩM5mZ8dX CCG5~__r%WF։ dzB Z ha'!vF6]_ē:YxuX}bNOk⋜T@JℋuX6n.^st4I]{v;w\P!/g.fڕhQ% iffyeP&)gSvS`9XŁr堫A&V''PrFRW¥^jߦ-TS# AUt0HV"DW+cM,{xt2`.v!d0[F+6@Q-Ɉ!YDZgn>H\4tO"8'ֺ.=#^bK&,VEe\G\WL1KrK]sJu PoZoGhhbx( Y̊Qm>9`!p&"k8 «6+f[NƵ'6{^L(ٹ}vAI{sԌyfO_,SWG N4= ڠxnkOh<ޛj%h\i 1W1ie剎}]R;*`5X۾it'ۡY Z꩕whe?d5r~*x\ te`^6] J!ԇMidPT(:+a_]QCbbDLCu%@Ueb]ݱFE@CI yDqYad" ahaN+~p ڱ,',S>V ⯜<فC½KvM[)fk*ƤE!g:GTTu5;vuCqǿL}@'<VBs^ǧ"pkLGʍ(cOLal|"9ÒmpgW\J`>1Tѹqz=|+y-LURṡFo8]سkνgV_9sRGU=˟OC-ZSNؔh& FR~Wa6N Z_(\-bv^U3QVCh(#sF=_eTyM9'%Hf{BHG#Fh~Il9K p0Z"cX.T柀!ihRf蘄2裐ss(KUJ#{Z:*jW*Ya*+X걇ޓ|r{Tv*c:"5d&*F+퀶+sr%WN+nDzz*조.uk-:PUYo{.ˮ:(p+I :j_&*gtb e(+/$,4*c(7qh~,D}P6#J FG-TkƲʹUw`u!٭͚ʵp-tmx޸ 0n'7'Wngw砇.褗n騧ꬷ.n,6/o'7G/Wog/o觯>p/og6HL:_&H Z̠7wGH(L W\f͐8̡wl"HL&:PݰW\.z` U'D޹hL6pHG5Vqs[ He5c 1L"Y2$'IJZ̤&7NNZ 9@є$%SV򕰌%" syJ^D-IbL2!9ғЌ4IMNf.}nrb6IrL:v~ @JrƢsdzF@`dg(:^r(`R HGJRԙXT̰/bL]%δP(FY Ξҧ fOKJԢHIR!aT@ R4TKծfuUWB]e)S` 5p\ȥVΑ̫gx} _j@as[d'KʊԮs6>v6gG[>^´iUZr}[-K=) p;CMn|\.׹utK 7ͮv]VM AMozgx^׽ @y^:~ L`}בH;3dp< /pi g 0L;NWb2"!fL8 mc?{l952s&-<ǘwȲ.{`L2PZR+]L:xγ>πsLBoYm@F;ѐ'MJ[Ҙδ!=C{Ӡfd5ԨNWVհgNָεGޑMbNlaZЎEoζn{Mnm?{NWm Mzη~.vt O;'N/<͎#7qBGN(OW򖻜߄gNM8y?.@!cnHҗ҆\duNǕַ#B P~3VOڹu-pZZZxxU]Ջ勿\%(]H]x_Uee_u޸_ݸ_8Ռxx:gb%ab(bb 6 6b6aƎf9dMcdFcHFd4$d:I֐Kvd)BF Yyc9 gfg3Y,)f+/"Yx3s:m'B:"ډ3,jiל-ڢ 8^(uDwdZfzc&lZEoɠנIuJ$hyՇ~~_:#wǂ0TIqzZzD8U'|GZʡ&^෪ڪ5EwPXzvk=*ʫm)+1ź MZTEʬ9jN I8QLߊF݊%v&z9W.]S :Dʬ*yxrVE~XWsUH%ů Kz%Xň"[HA[tsjZ%Ȋ:˳xPգsFK?/;3DwD834VK\ɈEY;]WbY@vd7+S[Ht^8{w+_xطYu `dyVyKvj{xuzt Ѷy9pع aȏb﨏;b 9z;ZzꞴ;n9ZY@ {d˛Dfzڧ:TʜzʙQaWNKtۮ'껾e1پ_f۞@Ĩ6Y- [əXN<Lu;죌W\^ֲfkAh+;lO;8Q{ֶpr<&eL?w ;g\1{tlg<Ȅ\&ƶN \ԩɒ< G$9|ō̱n|ɠʢ s\[85*EBWʵʲ˺-`"%"] PJ: &]!chS26=ԋH۰vbYeq8 3縏GK^m?xzX)X8֌E@XX֯wՃ/E_}YZ@;[>}׃׋Lv}0:ْؐ=ٔm:7d^fr_jT nPKk>&ep~络txnzb,h.wi^{^<8~;Q)3GҘ馮`Kyy=yL<:|;i:9Uꧾ|0[I{ޡB}:,NxJ~阎.\סY QyKVgPF^>wYy?.s;4jW,{{~;;G_|?Sm볱3$8dA0㏱ ; 780DG$D: E_COFo1ǢRt a2 eԱH#D2IyTG2J TJ+2䘤?)C$L3DS(.-L7ߔ4N;\s6M9M+P$PC/d?K`I't4SM7KQ/5TQG%TSOEu1ZUW_]=.Zե\u ]eW\{HغڎSeөR6ZiVUS *mJYM[byw&cUBv\ʵ\[Սݗe^{KsF Z@Y8`Yv\p^]ZN$ub8oa#~\ލWd/F;7eWfʷKvg:h&hFG9YOu[c?aa8l&k˶j쵯msrߖf+g<x'xG>yg!駧Nbv:]M>8>{=]=i.kǟ&mH`8@ЀD`@Yd~`%臩otPDP:T6թJ}Qy4ԪW$Uvի_*A*VIe XӊVugZVʕ`k^ZUկܟ;Xdrubb+YVc YmҖִEi B.umX+ؖmmu򖶩np׸6۟!\6׹%rkNWYuf;v]rEr{\WSD|;_׾o~_׿]{<:Fp`7p%pۏ\Etkt "mEk(#}G{ζj-oeB@yUr/ye>s|~^ΛЋ4g~KAA#hW&Vֵuq_/d,N6?=3qVqTz5j.=|A/H-J~ЙloIfL|Hn]z=K/ҿLdL\q7rMkgIsסGN|7Ͽ-o#7Fi}wą}G|gU&~^?eʿ@pl"4! d@C?|* >: T% _T#4D@itA?K vb'4Bs('(|BR)#B>cC2l)/t,64僾qB:d*R*"*=CPq@5ҫB4į:++*R+HAD ,O,rPE2PUD#CW)?;>YĠ)=?[v,-aD-ؚ-­d4-c\:Fbat3W oc0b2@]m<^KBtt."/2/w/vTzL/K4FPy=v=8X#>SPX#Es󽦓+Ȍ)r1ȏɐh6Gu !!mP2k47+;<7ʡ$ʢXTȱ#E J jsI\[s:pI0#˲4˳DùK(zK{Þ{;ԼQțKPz7X A|E)Td2: ʥpâK+zIO!JdIp<,L26ctׄ4#[jT5lH^<좦tţ2 uSJNI$| 9Kދ[sZ 6TOY+ȞLH|:0`{d6雾D:)EU?Oe99 Йc Ьr %QEeM+(8-!.T#E$U!%&$()e&u+ݛ-.e 0%25S3R1US Qa7SL5L@<=:zA8%B &KDI @ek69SrhHESWY (HD͜PJ>MqFG%'/ L'tZVGM+Nql _] [F\Fbk1`fvgf1>~ dkVRvmf1PoVh[en6g'PtVs>g pwvg&yg${|Fu~gvh'XHITE~RfXe+phV抶Fe5hpc*i0 6VTW_t S G=Q%eTSh2)eNgn&祦veei(jgv73$e2N;R5Uy9NbEk3fkd-9~\~hvj]gzjg{gx>fdžnɞlNրvmuJ9JKx8m5VW |λU]`5kR~TMhfl[hVe&+PVn.^,Viا9Iʞ+^L߸3YzMWJm6XgnVfnvnj~nVT݃2ܪnԝt5M}p@;vo.nVa[+r #LѭS^ ʾEr+CCO5)j['sF&+q~q+h]\>E*M*o<%]L[rжե)h^i.fJ'f4L4tN_eev9ǖ8V^veLx-׷n޷fnt(hIW`&id7s0ȃfwg> חp ZZWnYTYWMG6gmx*F"Ȏtl%OwHO`Q턷R6?j1?we'ic[gk k~yz''"z>lloV{Xxqi6p2_&z/V巏 o'>{?!`ŗlGǙGefn_se3wnw}'Snfb_ecge΁'⯁ozGn_Fps^Og>Wf~Ofg65ʷx|\k~vg^sjc1 |:yƙf4tj *B F[5W]!LvmM'%^wݴ"-"18#5x#9TO6VM7sG0\I*$odqGܒKY"VPTY6&i*x&i&m&qcgBB@n5&IW$ P("z$zĈNژ .hj)z)IZ`Yʺ*[++ "V⣐]iixdNY{-lj{Ú{.骻.gkgںAŪ`Y//DBJ:iu嶻0 ;0Y,ZjYjA/iqʖ7,15|36Ml`,zl1WhЂ2I# 0<;Sjg\3˨5E\5a=K;7 Ҫv[( }.6 ]u2D->3}ww^^x/߆xC.[N6{fr]|jJɲ6RE}qw5}_3:K?=hh8f{܊OAO-kUmuU>9{\珿wb(< 23Wo 1_0; W $>qG9r'|`X<Ѱ6!s>sՉb;"G%dz3f 1kc$bH<&O9aP1zf<#ӈ!>RT&.EJv#sHHQOBcT,bM Wn^\Gj$&396Fč[(Q(Yz(M"$ [hHEPc4'ͥЋb/5)af|ꖖ V aY,,3nQ)8P]FWq:*5:L*ZӪVIu3:X5Ֆ,NtXW.DQK1upR6 8Emp0C,b*go{OXUcmeQO`6171i-7=*bgU3e'W!)Sy;6!)2j#]ۗ%a|fytZ瘤ಓc,]Jc\a7k4wDqgɡ53mVy+)Ϻ] #+B-Qϱ,nI~^D!]RV֪b^=D7؞k2K31[Z AUƭhʮY9?OCd6 SװKsϺΓ$7fE2k~PH]l{lw2)Ed9Eöh숉S #x?YZ,ugNp^r9 cL[PēBȷ.HV36:?}xgɿ㩐e9%qxI7o 0zd>m!4Wvh~K{IF H'7ki{17u[&Ճ'N2bCKKWmURMp!C/8ܽyr?ocj= &R 2RVoϻG/0BYOכyҍB\gOKZڟβK&:ٗJ0 ǣi+X ?JɉJ~NA\ ɋr t}`x`TAEIM)ѐih 䝅xijE^zEX`Ȧq^ .!>}UTVXJv~!L!H)aKL!rIuatIUFr"! VMUXID^QšXWu^!f&ٲ!( ( uᆀH6&"-H'b޲iy^D/ZaJdeV%"36cbi,daoI 5F^J :#8#`HL $#䩆"vHrJŃT/ʢ8>ōlHb6]G"A(m"FC>Jܢ]%a`EXLccrGCjXFlBJcӂ\HM$MN$NƊLzd1vBe2QrJ&&$%k T~+>͘ /zdHfeRtDYU8 SSR!Tʲ̇hEbH`Z$l$r`a˞E񛙩%Zˉ[%eJ?*\Zc/!gAo헞 Jq$!Z2$fb]/ey)lZ!n$ [өee'B76Iu&N$9uR/i')%xp@#\<ccW`dQM^&bXZ'}Eɒbb'v'\lY;9ms^(f(Q=Vј}lU_Q_f5f(x=aɽ$|$Jd0jeHdI7gih\u]d֞1V-ʨgeETnP*U"gUtW{ ܥ~i}Fʩ^ᑨZeΊnfg&@V§%E eegoJRe矶jM9E^AU!`q̀ `|@ _ RjJFebiIDHf%s^h@#AOf]X$ʳJ+'*ebX$Q1g|#(BHVL`vc.,=!jip \,fn,vlZ@4X%pW]<),î,1Uv@֬,l"&hVyYeA).\4 D ^-fn-b-p&B#Ņr(َ2ʗ6} \@ <6Jad%XBdhCY܎ҮZm$@Յ-#<4'_Řϩn.q,Tn@|V#@U4TS>l..}m \!N! #TPشi../axIҀ$/~!EI(/Z*j&FG6l@A <$</䊅د#  @"B(l\h9;U9h"(`B% 0@Tt)h p%@pa B'SQ%5k8I8(U H `&AXP@A%B) |o 4hU<ऀeXN(GM&rHjD9Y@ކ~(@@ B)(br@$A4A TK(ZYd"bn&H2,3G/A`@ $&VT@PGU/@A|0]j݅a-t1 tm u]z)tU3(`zU8@&|"_2dk(sFH@EuA)iO'%Et\A\A lV!&`XO^jEDAtPl$ga܀."^ ^'u'-Xk!sN@F FY4@tIAFo 5wۇ[۵5h5Y.]_]W^3UGxeq&Ll#A#<V^\X`A#P2`EQE\f{^uyOGwxu7O)j6bjXHPr \ @ BX$WT@UDB$WW=i)T7QvoBAlh VWaZ!`H xa hfQO@&rwf󍥢E4v).x^_a*n$AXVrHA@ԤdMҤlCn5W,+Hi ȼbHhhA \A| l4 @P_ t&Lq'f^d[JZL,wA~ | TH>@4(@x `HUD'PVcYqTW{N ؉"XF@ XFh@UA'"8hHJP1a@Hs ĤGB"B(s.D; 9FѶSK @o@)TXfX1ǃ<۠ȟMP WF DiLjHU|q[ZE#>xg}ϪHDA Y'Hpۭ^]>k KQ)ѾܟE|ztk$#ek\UO>Ψ!u I`؁`| T')| t~;S98n  *BR"ϻ(t~VBigX>VLd8#D #&`%B"+: pQZk?#jm g\1@ . &LxaCWd8Q-:Ѹ#:H"TRI/aƔ9fM7qԹgO?:hQG&UiS0IVxkW/^&ZlYgCL` J;wCջoψJ-s&Ǐ!ore˗1gּsgϟAdVR=1_a=, @@!.Zk2p&ǑGysHD>^ s*2@C?'{.ߗ޼NE׿ 2L2 5?)KP¿|* ^xA F"ʫIQQ'Eز+pq=yC?R%l'RʛI6˳b(PT$jKB9;q]? Ľ"44QdG GU)IMOA UQIʐ Xh,լ*hJN 0H.9:|n;cBeEYgDϓkPM-H6>MMTJ-wWy:TS*0(KbKO 9+E0 ThhY|0{5iG@YdG5pS2\t9ms3mܔET]zqYy^|Wn#裑NZi]XJ* EP@4jm 6CN[CJvtG1fpUYH;\~R,cq.$b iD(^J*V/s%?Xou?m^wf_=^/c wXdγԼA+$,@wƜfe ?wGe~n{GW? 4 W_؊ MA3! K`|aYu\} a/vf$ʬ;tX#E4E,pydz b #a)X F1` p@ @W5pp9ΑsT0: -HAJdOHE.R"UM莕$0I6ll0+NPތ\6)GXE-m,fEYJx/H# K٥He.#(蒚4'Qp[4 FhNu (@0yL}T$4'MVQ<0AP %NCEmL`–BpMgriI˧?QRtg]UJUmW8|p^&2a0.bWNR.MeKWj|px 0'=TrYpg XRmVRWΕ&WE^#DTQ,]x"2Le!\`(Jue1Yuy9gkZю5P QaӫP G!TGƖTVoYFȒ5B8@յukι\'+53`lENC l D(,:}: P6- v!a O1a oAb%6QbG!yc'; T @(d!E>\ЁuDmB_" #U򕱜e-o]f1e6ќf5mvg9ϙug6#OeMGh;N (t t: 0iMg:h')ԥ6J_IL"rK( `nH=-s\#ةle1k`k,f. NStӝ6`)rY* OnܱoyphQ_dOhD:"5V0Q`h<҆Є at4rO^: 1qR#{9q,!v@G^r'Nh2RGqϜOx,ZsM;{VSD_A@(jDwM5ձ/ab> 5(vc|Hd܂$}9 >ws|,*m=Y! x \o˫~)x~& wW~(G x. [}Zsv(@<A]{uL SSW9uP7CMQߏވ)GoTa?{;yzg# 6B:ph%- P `t4OȢ,wXv/gG?0OEOwȯ~|M/JHP+JMpgn,n @`vcZi %``~JDM*ppwv0pUd`~0&|k|`pq  11\'Lt^Ή@L  .dH+)4+θ0Roo dvb/o~/}g[S1q,bAO,, 6`L. \ HA|d oQpg nPݐuc0!SQ$!,L WANq *p#<O0 2q [!yGfpiRf!c\/"rIQip꘥)p#)#"$ Ħ)*%zi'rZ,iR/-g-2(S R-OP/2 0c"Pr1[c/pf#@+}HjE,N%U0A34I ׋W0&A(&Oq.(ڭAb21;bDs7yH3J7A.`X" aҠ 4a"A " N$½^sO1z<31L:Cfc+&0a>4aVD| A0,a*5ӧ4"B` 2,tKKOUpғ6kyZCDmEB ,B,B (`EƒB}4PEuTqA, 0",@@$ .v* SQ8xׁx8xmt6_@4A.T  AUL1!PE& 8x8UBX.8ѧ,`J!.@`W;/KAQI,{{;]1(a[};G vwE.;;X!|j(-1<3<0<(=9G5Qm;i:8SY{'K#ǁ<3Vȍȑ<ɕ|əɝɡWq(K{6{, @"M2J,}\<|Đ<|<|#An6->@ }(@eqs"N<v-1}Ð 8=A=E}IMOS.ʫ%$ [)0   j;ӍؑGx ٝ١=ڥ}کڭگ] }_S9/4`6XM2I~J ǂu=}=}>^#\d6݃c20  p-Ӎjҕ=`IMQ>U~Y] ~'Oʣ'.$B!)Wd8~A>>~ꩾ>>:, f.iľӊtpp}9̗~\~[ӵ|zy:^}t*D (!FHFKJ9>~)0?59=A?EIAvM`k^X`«D?t;0i{" ** 0zێx? _ٿٵy B{>E*NR V4K;BQzTi&&+ZXƍxъȑ$I>)XTv+̙4kڼ3Ν<{ 4СD=4ҥL:} 5T0]p5֭\z 6,֫+[b#1p҉ܹSڭk^(U F(4$ R'^;n &2(;̟@v" sѣј>m:t蒬G%̩k۾;ݼ{ wUd?<v`dΝCG"AT_~ G2WYf4[p .`>aNp)1\nsιZlueE{b+c0pt2DYbP|A]$l,o< eQ/QeZne^~`afr衕)')gQYEM4Db#FXЄeIXtC&C> =LJ<\iRYl`~ jJj I晪aA7"t'U׎dAib`g^c\,y;gXk"V&hj~ n~*Zncɥҕ{m~q~҂q"/ n p/cmsێqoqHU^Hf!sˎo2W펴b4C_]4H_3;\\]^qN? uԡ|%UXWU :/\|\ qjY 0AA۽NzR xN'L\$/5W^6JbD3YF1` @IV$x#Xߞ{N{,V3xY=f䲶~UA?}; @0B{!P`{J֎~_{&;qVӍM+ku10p;E0t=h 7A?0~\tG~_[XK*.*  ~FjT#>aސ#Qbami!E\& ysX3 8a#E:]F#8n C'DZ.kFHeq,!m0w"ծ xLhC&ns X -/((Я]Koq-4EAr%`l$UdEUXe҄ `?3 FJTS?ّ\r,߀)tz-Ur?p4B/yAP':sZQ${DjulC-ts#cHIF@(? R,_C0(*>ozI Nt\I&FтG*hApoK] x.p[¾1i$P;čUvhtd03<$.1Di[֘bَR+_(H^0S=^8ō[G64fX~\I f/G d.3;'yl⒙\5'lNs&oyK̑a;ޱh! .jn7wngLZ.RQ:LTPs̤@Ѭnh.6Z OiݩHPƍC/T{4|nXOr֖܉&FgaZ 3tA{'i]Kq|ݱhKLriLpPВV0`A ( ?ȩ3dF{-8cԛ * @.ABQ8 >A! `{ڽn[|Dϥg,Xr-)AiT:՗Ԅ $  D>`d `lg;iTȏ 'e.JzxwIWW##ɜ87ӟ<t  !,(60` `&3,"sgEDA׊D ܟ*#ː#HQ~W$)6=^@ѵ }+& M?`z(ұ76]$39g!AwSߣPq/~?Y0uIX2)+0)v Su 1gh<[p`!Mr:j}uPG+ȂIa"x`HxxsTPEe  [}nMc\ťz0ZQ-RK'wKFE-_肼7I.4H|58Ӗ|-TmsKhxt&@|u 9+b4z<+23}1'M~a4brs`(h/8fxgbĉ7Tlq6msm&n P aF2-`SeW,HhixB3ExLb}eP,5w D'hSX؂ǨtÔ/nu-A^>.%n+Xd7ƭ 7 PIPX]ۑ$e0p,X+3IwZBhl;S8HBuE `N*PaMTk[+^)aaf RgeFu+%>k|x|fIVz3}Ifh@J+!+Ѻ` p UC'gwI\;IH?H%yP$Ak l=Ē.İZ#h(|%L{VzKwW10IJ0!=4 #I4[Gy 8g' u;di;}ap5*@4%0Ь avÒlzlO&Ǚt‡­-Ljv<q` ,p(M! `MX fxpJ||1| xrh'1~|?1`%.v,@ ``= 0$PA  H_c"H#p.V5!-#]929"_'v @= @r-0 P7v!|gF۪QBA`-3A*0'(ca L1v7GsM*Mۗn١/;8JS0 ERP%ٓm&: 41A1HR #nP Ci:(jjwAM!v=xm }"-I/@ hx @kE)h -BVcxfjdi=`EXࡗBD) 0a0Ƣpˤ}at TޢLk]˔BQYhjQi nGz 0h"CK.Cn]]c9*bVR` 0  n~ }?. V: /6{Ca0~`` UYnu}Qo~DI>^M- yCUV, qUd 0XRK˽+a%ܚseSr=";[sb.ZTf> .DˠjҞӞ)\2+yZ>~t"m2dz]ͅ7.NK+Nrt2v.W,.PRf*m^ƾȾPb*!Pv?w/' "]1oEԲf'1@7#g, y M0 S'i2A+N}bEyͅ8) p>?'V(;]_x6qxv|8#4p% Qpz'E{TǞC43ػ\Msު|/M)rp2A&>ͫ_9/ª ;? HBE MJNiDIcBB&(RU5U&ZuU6D3VZh=sW^{W`p5XdO  Xpi{ꠁCSJB.Ç C4]x㕗 voXSX~_d 6`oV -Xښ*h 74QHܰb7ZX! > D*RV9T63Wfufsyg"asمinhډ#p FEdwȀ3Q$W_]uUx{6lVןv.,CyѝDHh51(@*O#s0SKMH+r3m;w蓎汧gvM#b=!"!awww}vZ5_&|yw8|A3ESӓ235"ʘ""ʉE^~~_Xb+P$`EgebM}8ԘI72@t/ YkW N&?MP+dD=Y K ҐF|QC 4Bj$&@@(JH愹jaxE,1"fhuLkO ]BLW4A0L=712NP.$d! -vQ-$M%LT@L! 08 d)aP*)BdF1jRe-mD.RjU:?f6 Hp @ XD)A*R:8 $ʉr{DyKtS.y^ Pvxϧ&@] 4|`PT 0c:Ec",yQf`|gGEO=aҪS xR:KY: 0$!*ljS ANxl^Qg<6YTKejSQFP  I+I 3p& (%ިk;S=SzWVR*HJ4+(]Ja"JQAx O^ԼfV^Q>af&`MXSZ״DB؉eCR. mo}~֝[`nM pd!G$MWn]7%q\&W&Me:PJ-RR"e oWEnrZ6U V0(AiZ-|!()Z9YM|bX\$0*2A(@&:!Qc7)[2XC(1Cx0l1$^*XHC!HHI&1]n e8ǹR<Ҭhe+뚫篁ˁP ш?a^^Uh(^ BE0Yӛܹ;Dat]T:8`Ja4l}k\ lu}k6 |3}y2,#ՠӆ} @%Aw}nt{wbق,/"[󶜲-P'^s] Y% 2܅0qv}o'#w=qq@#PBa0Fr/x9ݵk_Uyviپ|ioH;:eN5J"]*tF [J4\l>'{{u,:ɀ1&>Q@ 8TЄw1|ZoŮ<'^sB{ړfӢ]Pa؍l 4/0?z??VKzq2uiшS݄/yσG»G_͙=qt\:! 2KЀD)WG5tmk-T<`:\?,88@<;`$,03(XT:c>d7*?A| =HkU9&0!؁Xh&X(Y{?#5`c7XB&l&t=B), <>ɷXqS p X(H 6Z5\؀ 8>&:C:9C?) D)B+*'X?KBGd11 Ц h10DO +1:HۯÃ>AlV$BԎ|:3i.BG#rSs&=301<+WLWԿXd?㚏1=-HLia[4U64BF J@T#p$4B Ҳ\LDL|+*[-d>7F H0[T x!>a3x4YlzMv̷QؾTFɕ &qpq (R:tN-l'2w:NJSvcj OF|JTb(|OլES99 &HALd&# <}T !'s|P- c8,p@EG0 h=ҥzQ+N?5&`HCh$Gx/0R$uR{Gat XB!C ȀDO(2S2S[2{LP FG+[KW{$:҆C#+S@ BT#H ܣX(&0a:S̯ĵL a:PUa"R<5^+ ؀&hy#`w)06a^E /[EVsMRf$ʃQ @)0@ՋL (((]5 M\qRJ p 2@FAE@@{*X]ޜ{I2%`B(T;@qc/H"FlA-^uY_e>0'd9H`N`uS0_ӵ&)4(@Oa4:ڮw!^.a~O3՟HNZՃP:$7$XJxG@GVI q"a>bi\5d`=#FK@\5s @~yQ{T3%LYZ=!10b$~cnvmmZ1@ _r"bqq9&Hnl*9KQa p ׫F˘ʡ!^~*VM5 pogdHh 1`c uFȔr"/).h9T]f 'pZkB(U2r07rH0JHH|r)p*+Fd"N(J,_`R8JO4'?t%`6/7b^̂:Є#b@:̄(I[e0E_ntЊs ^&ȔOS qҴ+ @F;pR7Fwz]f90ت^+V a+8=OTITNY wqwr/ws?wtOwu_wvowwwxwywzw{w|w}w~wwxOwq#u #hJi(2T|xE_ DIay0ǽq.ЃDajc:֯c^f޿{'J*ϣO_Y)N;*>qϯ? X" 2  砄R =Rt&Fz96SYբeSX7}أ?~\RG"K2٤OByWbeL(biXfkYFz-֦sX`w {٧:Z"2ڨABZ&*i']n(oQFjTL>bc⚫z; 2۬B*)AR6)z |jE^i^aP@/;{ /UW" 3@S\cKlm's#W-+粜E``0hODո?W5\G#0ݴOCSS]W;XsݵQ_ { lx o]7QVQ#Y8']#,3޸CS^k}sywW,uks5DO<Na>;!ß4L#3߼C}ZK_39t)ǒk^j&ߣ߯DO78q`WvN{ W,fl񛹲@:N ;Ay(5iG/*\a5x! k60M!tXCzIt@cc'|L2z 'B1NԊ#A,"H, bcR12qi՘F7 cĴFG2ьlc0qCdkfT# N=?#uŲqHDtaKb2=?O(CIO<%+Cei함d%)[JUʒPgE'lMcH1<0!$w8 OL$5iP SڟBu'89Ns36 vn';WNxJ.'t N)15a`'L(ER,IHhFKHiHAZR-VяԣU)JW-~jx Q iHF+%PҁCeAiъB5RH*4 U nZXVZUkVjWjuu򸗫z-*@A(")N5],B6u"[Y^l0Yz}f'kj%f?[ZviX+\1G_=8f0kgX26ʭB7M[ru?nٝ.ynu]~7奭c_UW$MH V3.7 C80+l c8֚;S IOMٙ8*;5݊8 z9B2l##ZK2!X lq=Uފn"L׸&71B<9j^379rF;9n2_^Nm+Bͤѕ ?3C:@*mKc:Ӛ4;OZ 5KmMBk{ꖝ)|9WhI:׆z_;6mc#ZK6a2* >ZxbگkdZ[a̺74-;^7w;򞷺F{;NoA{bWnU=r#<_|C<8+n;\k8;.q~GTWY\=ߓ}"n<jn<:9{Z :ыn^T -2[ ^pKoQ Z=CBp= _=[>=koև=!rz?>#?|C?ҟ>oc?>??v%WK??o??` `"`*2`:Bm_b`jr`z`` _ ` ` ` NaS,a"a*2a:BaJRaZbajrazaa!aaaa>!;proguard4.8/docs/alternatives.html0000644000175000017500000007570411757554560016134 0ustar ericeric ProGuard Alternatives

Alternatives

There are quite a few Java class file shrinkers, optimizers, obfuscators, and preverifiers out there. Users of ProGuard tell me it easily compares with the best of them. However, you may want to check that out yourself.

This is a list of the programs of which I'm aware. Obviously, I've never personally tested all of them. Many programs, even commercial ones, have been abandoned. Please drop me a note if you know of any other shrinkers, optimizers, obfuscators, or preverifiers, or if some information provided below is incorrect.

Author/Company Program Shrink. Optim. Obfusc. Preverif. License
Eric Lafortune ProGuard x x x x Free (GPL)
Jochen Hoenicke Jode x x x
Free (GPL)
Nate Nystrom Bloat x x

Free
Hidetoshi Ohuchi Jarg x
x
Free (BSD)
yWorks yGuard x
x
Free (no source)
Mojo Minijar x


Free (Apache)
RiggsHill Software GenJar x


Free (Apache)
Apache Ant Classfileset x


Free (Apache)
Carsten Elton Sørensen Treeshaker x


Free (Apache)
Jörg Spieler UCDetector x


Free (EPL)
Romain Guy Harvester x


Free (BSD)
Emeric Vernat DCD x


Free (LGPL)
Cristiano Sadun Pack x


Free (LGPL)
Sable Soot
x

Free (LGPL)
Konstantin Knizhnik JavaGO
x

Free
Sable JBCO

x
Free (LGPL)
Jeffrey Wheaton ClassEncrypt

x
Free (GPL)
Thorsten Heit JavaGuard

x
Free (LGPL)
Patrick Mueller Mwobfu

x
Free (GPL)
BebboSoft Bb_mug

x
Free (no source)
Vít Šesták Preverifier


x Free (EPL)
Saikoa DexGuard x x x
Commercial
PreEmptive DashOPro x x x
Commercial
Zelix KlassMaster x x x
Commercial
Sophia Cradle SophiaCompress x x x
Commercial
Eastridge Technology Jshrink x
x
Commercial
LeeSoftware Smokescreen Obfuscator x
x
Commercial
Innaworks mBooster x x
x Commercial
Sergey Sverdlov J.Class Optimizer x x

Commercial
Smardec Allatori
x x
Commercial
U. of Arizona SandMark
x x
Commercial
Zenofx ClassGuard

x
Commercial
BIS Guard & Co. Java Antidecompiler

x
Commercial
Force 5 JCloak

x
Commercial
Semantic Designs Obfuscator

x
Commercial
Duckware Jobfuscate

x
Commercial
Arxan GuardIT

x
Commercial
Vasile Calmatui VasObfuLite

x
Free
IBM AlphaWorks JAX x x x
(discontinued)
NQ4 Joga x x x
(discontinued?)
Markus Jansen Jopt x x x
(disappeared?)
Alexander Shvets CafeBabe x
x
(disappeared?)
Brian Alliet Gcclass x


(disappeared?)
Christian Grothoff Jamit x


(disappeared?)
Haruaki Tamada DonQuixote
x x
(disappeared?)
Bajie JCMP
x x
(disappeared?)
Elegant Software JMangle

x
(disappeared?)
Eron Jokipii Jobe

x
(disappeared?)
JRC DeCaf

x
(disappeared?)
Dr. Java Marvin Obfuscator

x
(disappeared?)
IBM WSDD x x x
Commercial (discontinued?)
S5 Systems jPresto x x x
Commercial (discontinued?)
Plumb Design Condensity x
x
Commercial (discontinued)
4th Pass SourceGuard x
x
Commercial (discontinued?)
CodingArt CodeShield x
x
Commercial (discontinued?)
Software4j Obfuscate4j

x
Commercial (discontinued?)
JAMM Consulting ObfuscatePro

x
Commercial (discontinued?)
JDevelop JSCO

x
Commercial (discontinued?)
4Fang JMix

x
Commercial (discontinued?)
RetroLogic RetroGuard x
x
Commercial (disappeared?)
Helseth JObfuscator x
x
Commercial (disappeared?)
Vega Technologies JZipper x
x
Commercial (disappeared?)
JProof JProof

x
Commercial (disappeared?)
ChainKey Java Code Protector

x
Commercial (disappeared?)
2LKit 2LKit Obfuscator

x
Commercial (disappeared?)
WingSoft WingGuard

x
Commercial (disappeared?)
HashJava HashJava

x
Commercial (disappeared?)
GITS Blurfuscator

x
Commercial (disappeared?)

All trademarks are property of their respective holders.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/favicon.ico0000644000175000017500000001635611163773610014652 0ustar ericeric006 h(0` }}}{{{yyywwwuuusssqqqooommmkkkiiigggeeecccaaa___^]^]]][[[YYYWWWUUUSSSQQQOOOMMMKKKGGGEEECCCAAA999555111)))]^^'''%%%!!! ~~~|||zzzxxxvvvtttrrrpppnnnllljjjhhhfffdddbbb```^^^\\\ZZZXXXVVVTTTRRRPPPNNNLLLDDD@@@>>><<<888666222000,,,&&&$$$"""  6666666666666666666666666666666666433366666666666631.--2466666666651.+)('&&&&')*5666666661-)#"!!"$%*6666666.#!|{{|"*6666666& }zxwwww}!#(+/26666660$}utssuy{$15666660(~xtqpoooptwy{} -6666"}yv hee[k|"%(-56666"xurl;J-N<|prt~%(-16666+xtqnljgfe50j moqsx{~%266661%xtpm edcb6|ugjlnux{~"/6666ytp jeb`_6{pcdf pux+666#{m _^]wU5v|_cegikp| $(6666)~rjd^uU5|l^_aks}*5666$to gd_]YXWU5|k]bdi nqt{#666 q h_XRU5u{ WZ^`bg lory!*6666jf½VOU5zsyTX^ejmpw{4666 hdÿZRKoU5zmVXacf ry}"2666 fbXVRMKInU5pfXZ]_dgjmt%*666vi]YMF U5|p nj_`_b o$)66hc_XTQMHFC 5}'=pg nu66 gb^ROKFCAj1HI P"[aim"'66slfYVQMICA@iL,z#FKQ\B"j`glp|!&-366s a]T@*CI3 d osw&366 ýXTOKHCA>hLD|cFKORp how{366"tlfaXOC1|AH$qno{&66'm]XTOC?5|AH%vrpw!&-466xbKHCiU5|AHS:$}yv#rsw|'.6iVQA>iU5|AHV7}*x"(66ke`WRIF@? U5|cFKORL2+t#)166ng]TKHA@?jcCI)%&quz+36~ d_ZWRCA@ P2FKV+"{!.66mQMIlHM /$$85pt}#)16r `[XTQMHFt4)&yj_KMW ;Gq -56yoc_TQqNLir7Enx}16mgX9 nrv&.6# g_[[YY_^_djmquy~$6 s gc`ZWVTTTVXYd ptx}6 m_]XXXY]gjmptx"(06#o d`]]^_bdfh tx"06yrm gebaabcfhj orynkiffghi qt{%+~ml l ~#1xtssv $)'"??( @}}}{{{yyywwwuuusssqqqooommmkkkiiigggeeecccaaa___]]][[[YYYWWWUUUSSSQQQOOOMMMKKKIIIGGGEEEDCDAAA???===;;;111///---+++'''###!!! ~~~|||zzzxxxvvvtttrrrpppnnnllljjjhhhfffdddbbb```^^^\\\ZZZXXXVVVTTTRRRPPPNNNLLLFFFDDDBBB@@@<<<:::444222000...bcc,,,***&&&""" OO33333333OOU311233333U;1+(*+2333I:%~ ~!$-033IA/'|zvvwz%(-333I-}ysppsw}'+333I[5ztqp hh ~*/3q4xr*/$ru}%*33Syq eGz!(eh tx}+33U9{smic`fxsagjmt~'-3tnha_;,to_a mu(033OGje\:,n\_jr}%-23O'u fa^V]9,lTX^g 33! d_Q,RX_ahmqw33za\QJHV8,ylc^\]_ z$+33e`YNFE7,z(}\^ins*3vlcKCBP4(vFJT#_glw!3vkbJB@Nyv EHVb v~13xkb]TN>3 CF p 13cTNH@L5+hJN? spv~(3AdV@>,hJNp}ODs`XBN, CFs:y"+3O LHBP6xshEH"|ssz%Mo^XPKF'xFJ_)*9*|1U'lV31}fPe}2=nqy.; aVb0W9|nt}<haYXVVXZ^iz&/I b^XVTTY\_aehmq"-A>>:::222... .V""##V.g&MJMP#VggQCBGI"%gT D>BE RV+F68:C#.S 9heI 2IPV:hb_IB"M,[XAI Y\KFCV]e\(@<[,LM./ WNCUM?&dEfc-/139!gd64: FTg]M ?BS`proguard4.8/docs/checkmark.gif0000644000175000017500000000007711163773610015141 0ustar ericericGIF89a ! ,  kP.w/QG;proguard4.8/docs/screenshot_gui4.gif0000644000175000017500000011750111163773610016317 0ustar ericericGIF87a333fffz̴θνҾ,e HAY*\ȰÇ#JHŋ3jȱǏ CIɓ(S\2!K._ʜI͛8sɳϟ@蒇ѣH&MӧPJJիXjʵׯ`ÊKٳhӪ]˶۷^fPt,x˷߿ LZb+0]Đ#KL˘3k<MӨS^ͺװc˞M۸sͻ Nȓ>ṡFo8]سkνgV_9sRGU=˟OC-ZSNؔh& FR~Wa6N Z_(\-bv^U3ȃQVCh(#sF=_eTyM9'%Hf{BHG#Fh~Il9K p0Z"cX.T柀!ihRf蘄2裐ss(KUJ#{Z:*jW*Ya*+X걇ޓ|r{Tv*c:"5d&*F+퀶+sr%WN+nDzz*조.uk-:PUYo{.ˮ:(p+I :j_&*gtb e(+/$,4*c(7qh~,D}P6#J FG-TkƲʹUw`u!٭͚ʵp-tmx޸ 0n'7'Wngw砇.褗n騧ꬷ.n,7/o'7G/Wog/o觯>p/og7HL:_&H Z̠7wGH(L W\f͐8̡wn"HL&:PW\.z` U'D޽hL6pHG5Vqs[ He5c 1L"Y2 $'IJZ̤&7NNZ 9@є$%SV򕰌%" syJ^D-IbL2!9ғЌ4IMNf.}nrb6IrL:v~ @JrʢsdzF@`dg(:^r(`R HGJRԙXRṴ/bL]%δP(FY Ξҧ fOKJԢHIR!aTP R4TKծfuUWB]e)S` 5p\ȥVΑ̫g|} _j@as[d'KʊԮs6>v6gG[>b´iUZr}[-K=9 p;CMn|\.׹utK 7ͮv]VM AMozgx^׽ @y^>~ L`}בH;3dp< 3pi g 0L;NWb2"!fL8 mc?{|952s&-<ǘwȲ.{`L2PZR+L:xγ>πsLBoYoPF;ѐ'MJ[Ҙδ!=C{Ӡfd@6ԨNWVհgNָεGޕMbNlaZЎEsζn{Mnm?{NWm Mzη~.v O;'N/<͎#7qCGN(OW򖻜gNsN8y?.@!cnHҗΊrUΧN\pCϺַu}sPHo5z}W^N}y_Zb|cFֵ,[;ދWk'O[D'fyk^EmB{W F>gOb\%/OQ53{[OWdMc${w)[Qx{{=NO_h?| Q?^_HG'r0CxXvMYf׀ۤv7;WMw3`"8`tiP7J}'zW0vgv7<؃>87'B8FāHJI8DPCWQmPiQVipQ`CS7E~eHSFSgDkDm~r8ER6RUXUTU{4BWV|HVUX8Vdtx?'{WW(X5@%XHXW艱爑h`FwgZZHZ8>ZEZ؋yq8zU]ѕϥ\匓]H]Hژn]׍h8Xv_ue_Ŏ__Xۘ6Џ9Yy]fb$ab)bb 6 6b6aƐ6P&y(*,ْ.,qdMc6dFcHFd4$d:֓IKvdB B&:94yc vPR9TYVyX>wЕ^`b9dYfyd)w@g֖3ԖYp)fo9sٔkv9|ٗ~0Yy٘R634sgU9v ٚIjiiM8yI9ytʹٜ9Yvٝs5WsAqYyiy9噃ֹh9YˆqLV)=R9v "A a!469) HPڡ7Xn":$Z&:n'vdg9(C7e*3J :5j9z;J@i909CFLڤ*oR:TZVow}xP}7z`ugxj}w}/ FIc7CAC8: jrq 2Jzڧ}w*::2oZo{Zvzn꧕Jp ʧ: CZ99C4䪄ꪲژP @ګyGǢD.آGK`jzԦ~ ʩvꨆZz *ꪮߊʩy*J9_9C]^ICK {[[*^/w-w{{ʀw}@eʮzʭ,*n 1;ڲ9k0@;⺳?K.kdgG' HO&9C%I@4TUk[{R.YCdH'}ӇAE$x(;oHZ㺠<z[*B˭:>[ۚtJۯÏ3ԏ빡۹йk H{b[{g~~%{';[tۻH[>ۣ@: +;K8_k{w۾̓P4Hhx47۲{˼KKˮ=[{5 ˽0 "3D` \Š+|(,*-<2<6:Öq$m'T([wJUg۷6M+~˧Xܨ{ŀ\[ŝZƻ<r@B=DH7Q6ER=T]V}XZXPWHh$,l}k=Hᜆ0UfsL~-`o-qw,X~hUV݇P CkזfۺٜيȜXu =ڡ(ڠ }}ٰm[$ ]۶}ۚ37J(~vR>ZVTeKG\;]L>d+Ρj˙npHpg)\*e~. MMJޤۛV{ZtgKQ;VwhGzgb>No<ߪڪj]띸뺾~鿗tV^lZԽk˰k^~Uvn**~v_$~KƵ S^۵W%' on} (uۿ?eƛMK+(k{2?4_鷛󂧻Nx߿$ _J]M{8굾:T_Vq~Z7.Enholl13r_q/%|p"~s$XEo5H}OF i?ƈ|w Ȃǚ~Lȟ_Ȝt ݐɒ좙˦UTU^ŚUVHgVXe͞EVZ-#tE9ěW^):T`… FXbƍ?YdʕuYfΝ=Zh}Ew[G/[Ɲ[n޽}\G\r͝?ym粦oݽ^xæ~zݿ_|ǟ_~0@c4j fcp;T> 'B /0C?B.D_KOC_1Fgq(1GwG2H!l1.:^IXyzs~zwtjT[\?Uvi09o}oŴuDw]7~t9$8A V0W΋bq @$Bcy"45, h 됶[궱e}D8Nȯx#.pJl ?'NV"W->p7`8F2T4PMllc(ָF8QqtcM0u֪S CR;&xD"GVDDHFt$@M^%-2ҔDV&.qؒ$KMM%-sYKXrL~U9L%~CD2LD8wRd4Yғ|&&'kBY eoHJrӜ)S卆#7(|;NJg<ɭu &1i̓EhBLmz|d$OR D'svԣW:9ґ)&}JSt)}K[RԦ7M?=ԧ?jxz @GEjR;NԒ5MJբK$*Qԫ_ҩլg%Ux+\ֳ5r]ѺWrOGְ`(TAMl(UQ:]5 OB0mh5'´EmjM Ӻ zmZ+վ)ŭl]Zޞ/ lp)׸ǝֶuUυnt/@T׺nv]v׻o;a-@˭Ls+]C|;_׾o~_];`&g:ݰ`7p%qW G]qw߰6rZ'G91=r-so5ǹĪ7'>'qIG}b NG6ԙ>uO¾]RZU &^ؑ>vY餞5t굗bmVr;>:x{U7b)gnl㧹XS1G|x͗}iFiѦěRD~7Qzؗ=gۓ~~#boY5VT7cUJQW g7~f?o}8 $zypF3a">ڦʓ>绾Tv> 7@ x@ @ @AA@ dAD&fbC@j**rɛ$ '̨!LB%)b–—B(|(*D›2(R(*?Ak": ª*"d6a9:;C7C=d??CAB$CC>AsSDE0B8VtWXtEnyEЩE79\hE]E^7EZ ]F]4de:QP<ʛ'(*,MLpGXsDtTudttvxyzGB.*Ģ ǀH(G?0ȃDȄTȅDH7aȇȈȉH4j*ȁȏ3@CQQ R )G3#E$8#~$ L?ܼQìkdORS3rt8aR*SPΚRl@?Ӥ9S4 )R%5CET~{AT&(MQ?>Sn I2B-AMQ}WKS UeUrB.D(G=>TI5SLSUN*CnD_=CR5XP:b[VfuVgJL*Z:>DSьnV= Wb5Em%W;=t Ȼ<UO-CLVҦFuXxClK=ٻ== Yc=ӽٔ=[O|GЌY6|=?7#ٛeZ,Z TAڪ}Zڨ[ͦ%ۛ-,+lBER[][)4),l[)ũ-ۼMrľCGlDF@AC G4\Ferdʕ_E`D`Fe\%FaDFbL͵Ӆ\U]!-G{tׅؕ]Mյ,Ȋޭɘ4EU^ uɣ^l^tʮ_5_$˹Teu_,߻Ĵ_D%M&6tϪYv`4ڔ `Ok=]4Q:n axៈa(a*Q7iGы -V & "77~$Ӭ"C- ?Q0U1Ŭ&V++,N>c촿[2~8=Gc5.W(*d) -HW1d;dc[Nd|AnA^P^>jff eiv^V{W}ͻ}e{]j5HYKܫU4G j6\?3ڠ?}> ۽[ A @Ö@ǶB^7lɆVl6&&[emDžDD,:|Dnۦ&qƊaIa#cV7FPQ'udRF];rKƉX]}ledGanh3ŰrN^_O? &b7cM&ՄRuJgXp*">Iր\s_n'`1fRjV4Oc5_rJ*s>WlWwiL{wtqawrngENYRW^h)hJbԅQz|pX &h Gq]Wx뗇?Foz nG_'On!yW}'~pף_Fqz<7{fg(p_QfG8>|K{|&57W|/w|wi鹇iU= ƯGҏ&h|Kw|n~ragW[;;۟vmsYu~S~EPoGy{w?'+vO>E5Ķk--AI,h2!DXQhB6n#ȈC,qɔ*WlrY2gҬi&Μ:w'РB-j(ҤJ2m)T1=:20ƣbǒ-k؍a>bKmi岅 -޼h3B2T| a3nX%਒'Sl2̚7stjD}f݊+ԪWnꍩe3vuƍ66|[4%GG:ٵk<}N_F=ӯo)Gc*W8 x n`G B!R "؜'}4@'!8b'=wۅ'Xvщ-Xa"7a#A 9$E_qVgZW_ $QJ9%UZy%Yj%RrGex֭x(7Ijʘ"fXkvbz)I-a*gwy*w/G,-)p7q0 +0 ;0K<1 sko rq.F-/1<3<ll3Z=3A =4E}4I|1H4QAnY]myf]ש-ri6ۃެdWvu}7y7}7 7Nq8ObYّKtە[~9+[衋>:饛~:ꩫ:뭏^x>;zN;af; ŝWL(<;>??{?P(< 2| #( R 3 >PTV0RR|.|! ׆B +!s>!(! X%2N|"()RQOC cQ?U"(1fOX.siK[e)`&<&2e2s|4DRRּ&64é; g$өuq |+H+г >}<'<Jizq} Ѕ2}(D#*щ:#L\rc9(W&-=t})LI$AsӝC<3*f(R=@s-mi2_"V*լ^]顒hӱꊧf=+ZccG>s}'>׽Uf8?ɚM},~HSy4e*1L p,h;\|IM>B34, 2Nж+JBmO֚SZV d\ZNMi=*J7Ken@a+V\TsNLۖ&NL[)蕅z۫(On$'կM+$ /f ' Ƀ!,VP-ؤ sũ+3Ni$x%ަxa0ߙDxE0K"7f w"%'EQ^{,+۷C6"ٰ­Y|3 O}2͋L ә']Yr-07`Cáݹ:F)eVtt+< dfbK=khӞ𴙭s-Ws˺ٴ^y{.td=*ЍrWN׹X1zӥ>qc{./uևvϺ^o9KLb]9 ~{x{ m0#0Vq%xИ\#7,$"g;*u{snv :[g<겏=kvzmo[}hUomR7~SK}뫏|_'܉Eȓ_GKYaޯ~?i ot:ѬX qǍY}aY}|=mߔ\aQ`"*9:` X5z Fy M]E ^56>aJ/M!Nfm!ST_WA^h}Ex 轋罋H` ̱` `!둠J" j%&bM%6_ .B_!FeRYWH_^ՙ!ş>1sS`  Ρ'%& zb(~f F#3."1ՅӅcY6ש"NU("b}u]';!5&4 v=c"B_!F:t%”WU $WDH F~ ƪm\(9 ` &q[ _dy#z K[))b$Kf (fYMR][LNSN=Pe~\!SZON%)%=@~;MR@!_]"!%ћY$L(ado 4uƕA&QP}X&T`fpaѐɛhii dhY*^=-&^jՒk&. ' !fbvbpejRYQqrVٯEEZW:u$Uu5CvgSRR!nX'pzVtfH.8_lT}g#[eygME ((&.qE$u^Q ^JvZI @9vX[}P`RBvfa쀏‐)rhmTR'6>)F'=7`S$MRv[Շړw6S094G1)Piq.UmkN)b Q )FN*ZśPqkݒ!h@A@ҌV*ƪn降@]):ݝ:V+&.+6+EYj,nT*9iJ%U~+ku|2\EB'+OMg"aR|:U$9B,.U4-k3ƫ>*2jܑ?9Ŧ? n&*BʮlHPTR+&gjnh$\ASma,6r?k,U[RU'HӶgvEt3ދ #WWrV>ޭeDm_b+.“^RĹZy-ƜۮK˄oz0I4FL49"~.&ޖ].vҸZ.Ж,ʀ MJaޝ<\F~~`Zy[Vc.Vo1.P^AFҸ+g%%@hnI/_! `nH/o/&%88Z/3&L.ǎ@j֨-qRfnԮ֡/{0oJDb)Π46ނVߦV!1E"lf3i-V1g1l..p w [ kqmY!"Q03SvTk3q.0D:V! wqop­ a!r#1&߭޾QBRVp8h'j,{0/r rAaI .!#^-'2K!^Ubf22&smr>Ȗbvo,FJM0o 0.2/ѯ9G$'s.[5M`2߳ʎ +b^xR@([52$rDOM,sQu/453W\2s)l%CPDS4JOEY*q-Ys`'$f0Wk準4tJ424*rK&w6)NN:+TGTO5UW*}S),}4rl%-qtS+O5[ۄn"tJ QQQ?]WuZ`6a3Vs5]P'$uu_7*`6eWea ӱ]hgR^MǒKd_6jjjf-q(QHyu鱞*13io6pCikBbSh.Y3up+UWu_7vgv ֫"7s[,1WA*x63t O5|Se}9]_J\bzsuR9wBu{+f|8E-+&W@ky_4C,I7wx3rQm.l+RuPtqQm9{?,PQ(T.6RU+,KZDn Ѱz8J/,7y؄W 8dKnƘJ,?fƔW9 Vc[ݵHR$r[xd{qxlަnr0p ¡N 02mG̣zDڭIչrvz?SxR_gBp8.7ZrI 'c,3BӍc:[ӝY;'#nn4~0^p2 / Wz /2#{: g)v;[guq{MCnql;xֺAqCz7k1_/{$C:n|{z0m$81 /zWP 2b:ȣ=1ǰ"/ c< < Fg}}(xFw?Av5S?[ɶ='ӏ2-+ps+pPճ%/|kRo}96g3G oG|񊺲g:$ӏ~;%eo[=s%L>kPfu_tnWէF$,C'D{G?|j,w-73i-aH?P>S9vJXCN׈.8@8`A&TaC!F8bE1fԸcG%dIYJR+yx KKM_pمgO?431GTK.iF:5MWfmkWLڜIgѦUm[oƕ;n]< лo_zutAf׾{w?|);R'>~ok+sr* ,0R ?hl箫 1P 9A QI,S%ܓa\Beqmy RH z1#<2$ .?`R%4R-/ S1LBi)iQ?裯9,(4S=Ѱ( ?: bR',J2!TI)K1B3=io4e  T/P=PS%F;}T]y_ V]94&EŴeJg߬WUPoa-1sMWumwW*McCvZLYf(-8[k?յ܇Cɼ)1XA,{?wM)]pBQETYٌkG㟁Z衉.Zh>_dՔ@RfZ[bMM9^tJ*[i>ŧÂscjs۔mYj!SCGKX+Ż VXEtT]ӗ`$Dxz'9ŁtYSmZeq” (/ AuOU-V#3eK΅vtD_w-벑 w}{6Qd9Jֲfw| 2/O1yc<1e E177 AXկwatapeji!vKZwU*zE]'- Ș~(Vh~+UQP|7M+H쥊~`H0e~,'o Oi4ΥRc2 (ə(pN! PfC'H'EpIMLлF%, /*.BqQ, گ&h B#Op#h85jP`(ʈ(p0̀ȦԖ&pF ĥȰ p; f % *"f6 @ ! `z  x"!DA+f "OH-\=A1EqIMQ1UqY]a1eqimq1uqy}1iZd  l`4`Fa21 b@ <6"BD APA+n W1Y&)(@2PĮ1%6q37u3C(3T,E_sH!.N"67p>( />@f@,q ls73)"0$ %+iqXR%Z(Ɛ ΔLkL" YYc A G'[gI7R'`* Z X jHif |09na>X ,*HB6avaaa!6b%vb)va'FW @^ HP  fD$ 2aP[FfFTKOR A5Y hsSiebubnQ &N`x'j`.(@@"b`ъC@+%Z cd17S~ʐv0p T?~ 8.&@H@B F"D_>diu>b.h{u"UD  @ ހ,H@ o k(4^ro&9הu"LcWW(@ !TntG0 [‹yY92 ،anBey@%t@Ur2 A r 7$ TyiRĽVZ R@ dE",eĐ7 X@{`L&,@?HMOʗY9zId 8vYuJ& @( (G0/C&]Ŝv@:EzIMۥ^x x)\8{bxe O`To @l&ef ף:cȸiv#CWaĀOHNE U̫0'B`cc#<:; ֚ !49,UUfd@9ŚLV fšr4' N2{]ͺ5T6:K}VQ8>6*ĀTK`ԠUbUeQZhr'kn.;b U7IpjE[F d(k4 郴cOyͿvEN(wD:̻<YZ+Y j@@ /(LDSh3_YT<(rm^vm|vMͪx5)<ȅ|\cQP@@ ~@ @ HNQTtA"˹8Pi̡LR_)iNjذlfRj<%ȱ3Q('r`b@f€T^ XdO$jp4WRG3]r @̻T`o L[MpoQpK|i٢|i!$TEUr*'`N*P$l7@>+G[Fs 5̳}HvwMԱT,Ǔ Vjn=Y0ѸM"$NT \.D B$~LUh=`kwՏ\u}I^dBu{79 s5n&)6tɄ/5p >~2Փ>c~M;9$\na %54 MMT;ؼʈ)1Ip\Sb7_n~&~Hnl. e>@%:'37nV;2e=IchE(Ă"Z>6@* <Y:ĉ+Z1ƍ;zOJ<2ʕ,[| 3̙4kڼ3Ν<{ 4СDi2,LBVՂ5+/\h6,X3d˚qBaBD]7ܹp!! ׬޽e FPiĐ;~ 9rc+[9͜;{ :ѤK>:լ[~ ;Ҋ2m '9Ngx̗[y V* ܻk_t[>=z_ ?>HK?`H`` JR=n =Aa]VQDv(XPD&bD*D. ;c:hDDB.AdD&} ڷ`N> eRNIeV^e5I% Ba~fhȐI&oe^5&aMDIthdBG-e> iNJiC^Fț,ZF ď?jb ('WUZ\,{J>> mNKmf`~ՅHRX$ @n.N?dO$JŅdlZHE-p? qOLq_REzz^ Lg w$__4 _p 0[BMtFtJ/tӜq\Mm &"!jVX,Zx``#Gve B2HqonV,_mjv> ~ xNxt]Nqla&W\Ck 0Y/7w}N{ߎ{>Z8 L<:*0WD 8":8Ϸ( IH?:;~?g3*5nT,߸[_-$`2Hp~t!+u,JNJ jp0F($#lp,l [3?/7“Řh>H*RN DA$1 0ꑉ*^if ^$}`FJ 0#c@qlluC~A@N"CB,"D*r 6;l":p~E4 lu؊PrDR"lH+Y'dB򖻬%/ui_r,FBql38l4Ȭ mo{9`@_P `t 6qf0pU Z:Ѐ &,O2/UK^:(EQ_Jt(c) eBs$-I)͍uR:ax @z8yC$a,CqӊK)G(uL}DA5 UshGQbU*BZщN#\PB]B8leA]^M? bwqt!lL$X瞁Y%^C"<֓"~ %CqمbWElh;&NfCBky\~50v@)(zьdW,wyҔt MY=z +w)@M)܇H$.A Kz#HV mD,c6d*4N,Yy&VEa#'Y @+ljwX`:f$ ђ|' s[f=Mn 4A\:PP`\A.X Z NK}&':$pɓ}߇ ȀT~% BvxU Y5I7!@ P,P7u**/"WCuT7\g79;0x{cdGBB+w\?!@, Ac,:_a(cHehgikȆmoq(sHuhwy{ȇ}(hUG6DTPX<.g+B@3(VapUt! 6f{Ԁh$nx-H2DB ,0G10gP?x%v kZO<Ѩ117<0I&7b(p V"W!9 M"mZ3(HX{h(G2v,Ng {`B1pze:` mghɈMci-(sc`q! 1 >e ` +)Axteȑ=? UvdƢ3{W 2Z8tAɕ]_CyMW=%YIg 6A10(c `" ot.3H$[U4 ] fU% 阎!7vlv@Ws\?|~79RI%&qE*VtH)#mIeVvdEvU 6YQ6UQWvdUSfP)^ K]tY QٝT&LPۙeT'7_)U!NpNE!!txI]aUUF`)^Z޹Q塃]aP,jaXaY-zU"7 {b%m ɒ3Y\*5XOZRVaK6(ajꙥNViU]j][%z ql<{wcc0x:aOKS J9ܩ*ڙaeY #jiUU&A *Jjz( 1uY#`us@2[e7&"?ų4xd+ڦUfP:ZLɥ_Z׺_Z' :ZxZC٫5T'Wzi:[%]YJe*ˮ/͉aکf %0vVq:OBH1+3H p0J/;u&ڨKϹdj晪I ʨE;yW6e 5jZLWOK:&Ђc'P'"43]~v2QV xA[$븏$kk(k~RCi{0IḰwʚ +)C+I@p["r .k+MaCKt*~XA p&2p-zj h!շk+;!u:ī"b#7="p" .}"(ev ,aYk'|Gfpnv!I;/ 1,$idnqy;–&n2MSq~Wp tApY +2H&&dNLu|o`+pc ` oq Jp .۽ۻ3l-ɛɝɟ ʡ,3\0u5|8v(lp{v'2iRn< B0NЍ*|!K!|23r̄C@ ,Ll׌٬E̖db!<0gwx 2f!5B3 zquR:TMP:  -M]ߌcƃM-(b*B}N%`,,ӤmP7 m;= A-CMEmGIKLц8:+l!N'#2g>o ח̧@umwy{}O^l5]3ww gpYTq;םq̮ ڣMڥmڧکګڭڂMh"n]`!Hw0j{Ɩ&Jٟɭ -Mm׍ ۩ .llƒA}u2ޖn~^M]iϬV۝i=db1-!p i^StT-ni̝N 4^oƩsk;}kn,2pp p 3 !|=$A?ZڮM B}䥝E-:Z=,+. y+ p$M'op{}Ƞk5׀ zBvMu}q}iQ;[w1'A 8{普&MGBB=ԥ髞}N{Wtb[ַ@뻎h* >+cFl ֮ خ.>Ѯ^6ܶ'2ww N:7 @3-2ͺnB~ B? , r7Bվpw'ܶm9 w&2=ė%oV`M+-T T20_3o.; |:Z!Nw~wϑ~u!.` ll''oW;Ϭ[]_a]B[_hdcgcoajQ',V+@ w&CH$~̅ Oo` $o?&¿"={b&b0 ĽI9oḾ/O_/f(w [Ņ< 0 ` jl3gOyy$XA ɡ'Y>â*^| KG!CbRd0)Ud @Be%9ut ҝARh/I."R䗎F8@UYnWaŎ%[Yiծe[qΥ[]V_&\ )JFwdZY)$n.ig(84*̩UkGeϾǤQ3vho'^qɕ/?2ѥO^uٵo]T%Cv,ZRa}o޾}xdej 0d@m"cA#pB +B r-:CCqDK4DQ/Γ-($Lc &t1@(-\ rK.K0)Г0L4TsM6tM8s|12dr1;2 !8AP$3Tp5 -O>Ѱ1а<,SPCuTR!s"RUuUV[uUXcuVZiEQ'$> ,$ t6 I-)^{ZlܔNK[pwOO\tUw]vu]xw^q-d<*[*@JIK> Xg ca^8Xcb'@Lr;cC1 0dSVye[vecz"|vg{&$Xbh Vz&zi$!e3~Z[Ylطk.7hlV{mvm9mL|yZX* (o<v! g#<+ ~\;gw8<6tSWvuc=nn|@z/cSSPgz8ѻ]}z꫷e~{_}coߵB6[o#w}%P@3H~\y0u2z]O$`ɕ%P 薧)F)Hj H XĐ@# ($A+d 9+`o xCPB}CvYfc>vnsKZ * `/XI:E0@Y@a,P!vF8Q#ChDN ` P@@Jg) f_w$K\Sܡ.2̎w|i'խ)!O4G @@d"{8VI:x^xA4ȊM hpRNvT#M;(Ot"*O"<1ʁpS޴;iO}ڃU@,2 K,jH"v8Ykh&a$%kYz:z'g֓4/O>uɣ{2C!A X( K8 R $,pS& yV4UXYІK&"KӦV6g]cb4p`i4A"g/3 m0TXmu{nM-Jն6|u X QbPXf#`P)I` ?B]&X v}hִ#] !x*pH(ph0?K0C2A ҹIJIȃ( 1x'xhKKhyqB*BC2LäIlLI˲Al'ںI!᛾a0 IP؄9DkE%haL3L T̝ٜM % b00MP 0li4M MA5@T,)KL FAO !P @!pAp9D %rFO#O(5 5 44 8@8 nL !0 0؀.4H O8Δ+P ]RߌRAkOE,EP{s#`!!ؑh%q @pЀ/SH/i$ R$PR& TsR\ 5CNtOفO`TAH(c .H  h(XP (2J@Q81IKa46@T_]7B-ȔDRCҦXVfg}VhV{#P Jhh`!@ T"L %p^U|`5bETVMGd;YXA<kp0(XH;];URدR#E!_vB"b/@aF :X? Ȃ7)MxKpO<ϢMJ/rb-d*0.dC@ 6"C'8P@x EM2dA.DFnDj)\"fe*NI eQ!RVT1R`,Ab=Y b">[_IT^ek6`.elETe_1IU 'PCfB}fy>]晚 Sg5 B"JҀ'hͨYhTex^yh[gE clf'h hUu Ȁ& X'H=җ <65fhhWvhps!PLւŖzh7iFzw:e{f+֜X֜@)aͪodf%ڜk"lR? flj'xp`ax!@>Sv>+Y"l&K >el^fJhkg %)B}[vj>1^]kϵ*}6mې8Xd8iARߙ$m>o1lEM(]AkPSFম Ja8 pvPR̖l^p QoB sn&nF(J3/P@h62fp4d~EflUx!07H$Vk s>Cy0q.) X֊o~} jl)s61[)LBP1DȂ1Q.?tr 7VsVosjqhW OC/9/EPȑm-GtY/W'^Sv j1xM.ps `%;ؐeOYRwumJ).sH52Ȁ8HX`A24BhmPv:aNEj2*(HY Ȁ1Gw8wk xJgu>zf "A^IDjywiqpBn/+03Ko| yox6 (B2٨m pF67nzgz+zUdgKA; /pX;H1qz{tp/  _,Wt*p!؃WnW`[v˿ C}gI˚;C%rW18 BCKX~W_}O}3(`@ Q$ x~}ˁN~2p"p*"D@e=pi/b̨q#ǎ? )r$ɒ&OLr%˖._Œ)s&͚6=RH@"Ϟ> *t(ѢSTlC„Tje+׮^zN^|64렂W$*~Z |߅=!Jxs1ƎC,y2ʖ/OΞ?RFu]-[-{6hn߆CJd b-dA(P(Oo d:֑,ɮ}vK6Ty<ϣO~=->KKd F؀(XEA) u!^Hwj]~MԞ'+"zy_}3X}$6j:Va?UF "PEh,b)_dVVje"&cYgfy0Xo7awZUUgvn'`"byUi9(br:&pP7ι_jW4ڪ:QC NTZFj`K,Vi"2ҧBmrf*J?HqPeF$UB֕WzE,~%6[oE@| >ZTu&ˁC=P,o̡Fr1wD)lrĂqꪪk/3/Ư}Lj:y*Ua *Xw"uԎT'"J$ogeסcѲ4k-DYܛ͝Lw9 v=T@[kg}+4$XR&\#1,쁅H?aCꫳۂO;mH72Ύ~ͷݝ P#|3|CQ @}$F߃'χ>["Cw ;Pwhx & p1Z40"a`0mX Yѫ~2! k׍J˝P; @(0a_($@10$@Td3E1b#(Fbh71r;w#"e7D'yK Q7S2m?=(CafXN;3 ?y1&w`cN  DMa@8&5wkbff6͘(@T%9iΗ'?ěx=񝷌gIRZ"p!o@@$KB`*62$tlԥяRIE.a~iDIO!3  P0B< 8{0Zn )SRͥRwIȄk6C*L`8@3PgTOd(CԻ5TJ"1J@DfVI# C!YJ(b6 k<ς&|+iX! U (H3Vz+m AP  76].IF[ZWZ%P7fw]<|K R h 8A$f6ͨ]kmmskZ4nzCA$aD Xc80  /q U88*Vq}չ-it*}k 8- TnY MLjbf8b(|h39j^376Z[8m$@*p:A ʭ|!09Ӛ#fi+WEWSԓ7d";T"wӺ ;_YCc\?S`y<@l"iP[VoӼ6WT`;ԁp"Ƶ[Pnux7'[4h7| _[Rg.|vB/@b$NCvloO|Ϋa6B`TP EHs<:ǔ?ߐ N 6&P`7BR:թ~Vn#Խ=.ϟ tr*يg3Z9rw6@BBwCB `HL=6_;gOEBQ}*ЅJb1Ko-/PB{;b+10wJvADhS(XK((T,RDO h%@@EMPRi~ԙiWZ-h]u#%HTB `@pMЈXV: ]Ɇ*j6*(b ISxYzYFQ6uQ H"dB$PŁ(@wq ד#Vhj*lgmt($X 8>P &$l$DDeD%LTEMhG+2 kN*ɛΧB"IO@(!L{MJ =_쓗6l6`Ś&'F&B$d?AO? @*L9A[8A W *r ն͢4^Hd2Il*d`,qT@P@$BHkabz۹ -]i^f f_uuhȠ*afqS!z.S0`/t4jA'&A-a \p\XNc~⥪$8BBr!oh倌8B%cr&& xHWZrgְg")dgfX|')l&۲-G!4ZA!0*gdĺw]z)T,%Wy X%4({3M1133="v ,3&@SI?EAEA<ςbJW0?G9G#|:AH`TbAv=Ko3@kt+vIJ %oovñ AJ1FTlZD NtOOuP PuQQ#uR+R3uS;SCuTKTSuU[UcuVkVsP+"qB?_D(8@ mX "`JED0w&il^g X#ኜ,$ [ExtBagaQ̏@_cvfkfsvg{64X'I- UGelvmmv uYmppwqAU"wUbkwisc6 _S7v vBP*Cpj yW%hiلMt{w||w}}w~~wx x#x+3x;CxKx+>0䠌,@eLaKnxI&̇tx68fx$q0ӂ7DLJgHx#yV@@_ Ԓ{yy1\x y|gQǙ#Ayyo`mڹ}UnjdnpKShvGO`VWt zۀ.-(aa7 Wz{LB{ {#'{;2Iw[;::lTD[ 5f_ &{{{ĺ{ǻ vs+{0eIK2$.v-W{[|s|{ǃ|ȋȓ|ɛ| |bʳ|ˇ|tptG7x߆Ϋl5} =Q @)#}+3};C}#=̇[c=|ҢSK]T8ffDYVa}}~ ~SD #~UXh;L)|[/OorW}苾+~~~~ᗾ3>v‚Hu@S1UYoe.= ҨeSBks{~> [ͽv0HSnjM~},O 4xaB 6tbD)VxcF9vdH#2yeJ+YtfLygΕ4 S?yx JR_6ejTSFUzT[v)cł%Kף#ٶun\sֵ{op6 aŋypocR|yc> \ѣ6]zIjթGMvRchצ-6m:yÅ7D7w|m^өW~{vx|x_ n|zٷWwџ>=}:\J ­6*)L%W;m\ =0:DM<7@]|UEmpqGy$GQ"ao \gR!dH(d!. [mC䲪LP'LU:<+>@KOB +4A%PDUQFRJJ5mTRG%MtG7, P>dSLcX]]9l u436JN==d]>yh{Zlv[n6pWn=KE]ll5Wv-Ւ Z M#a*ҬjU٪ x -ي-㌍=1 d;6SNYGfd_fYCV=ye Yfu}=;IUg99 lN!$AH`^'mӖ[mVW{oƭ\)ˣBL-)ۜ8|kcjث(6U_yeduc׽r{vi?vu_݁7號ߢNmKJM!tz8O@ G .>  s }rF7}eaZX_RV!ִ5 iXCeyCAXDˈITi)VQҘVE)JYsB `yNiT-2@qXG;ycյG?ut"AᬺHP9Q4MvF6^\IO~(IYJSTW*YJWrEHHK3!sxLO "[cIMTLg>є4YMk^TW6MoN3%0F,P^}`SO@ Ou U?É]REj3yI)%Sd+Ӟ!HO4-)UJYR1iJ5S-m(hBuT ZT #g@JR>yZU^YVU~ժXZV4i2k&,x| \ZW,m U @[XUbX>ְd)[YŢ(-\fQu QhEӞt^W}h[[ny[5p[J@\+'J[]^ f\+[~ Ire p%Xf׽H%jE~k*J%yWYԢE}w_>+y# _9a!5,O )+1qJT\cX,ycA\d#IVd'?QYYβPe/a\f3iVf7q\g;yg?\N3,h@щVhG?ґ)]iKg&|iOԡI]jSթ^sEi]k[׹yk_]lcVlg?іYWmo]ns׵;proguard4.8/docs/saikoalogo.png0000664000175000017500000000552511672471301015362 0ustar ericericPNG  IHDRX ʛsRGB IDATXGyp]u?6=I˖FmP 7mhOMi&j2 LLRJĔ d -[2,Y6k{O>'yG{f޳ܳO6Ջ#TDRXU0pЇi2MY{c$c;ēW-` fx88cVVQ_YL")'gSx&Bx\T1 uQ$7xϘ<ڑߵ.TefQ%e_P2gb1;aUD*C*"8ң#؄>VGuݲ*, ḽ%p =F*QUժ~!_*7U/v5 tUU u? ȋ'"]l G:)k=eJUi笾/w?p"75E^&g=Aח/1]r;`ç( 8ûZ9;Ѡ MP[Xο|X~DXA"ѪҐlm5kVepaSaU%rX2Twl]2{Fs|&Y]:|6^QuW+KBzp9DB> Cǿ<oqEC-+@2m3Oaۚ/a꾓|Vlaq}LCxrzfh?yZ-W.utI] й$||ˉE^%xFFO:||ޡw8OBOMyY0WF[WsW+#WK(`:ʦNjbaDQm\}@>-e|ELC%eao߶p[͢^Śŕt9 c;|Ty7gw?Gb#!67wdNY#qa |fC+bvw.&ʰ<2p?6e? ~4[U{W$v IYxRV/='yv |-DukfK4$_U| :e- 1jyL((рl4 >U_&mm륾[ٹ ?)+4Nώۛ[j`o[<‡<>*2*™th_. 3ÂHg 4"̷r eEWOr9LPnY.ΒX?bZ @'qALmdPMCdŠ{G=oѲH@N NNxRʢie^UTFAOR kj$m}\pw~j{+y=2dTږbk( ]a'Ǹ`^5MщDn,T1/Mz,pKf;ED :S]x qw8*͕=CDD\T H9EEl+򬿈:".0>e?'!!XXIENDB`proguard4.8/docs/title.html0000644000175000017500000000071311757555336014542 0ustar ericeric ProGuard

ProGuard

Version 4.8
proguard4.8/docs/screenshot_gui8.gif0000644000175000017500000007533611163773610016334 0ustar ericericGIF87a333fffz̴θνҾ,c HX*\ȰÇ#JHŋ3jȱǏ CIɓ(S\2!K._ʜI͛8sɳϟ@rѣH&MӧPJJիXjʵׯ`ÊKٳhӪ]˶۷^fPtn,x˷߿ LZb+0]Đ#KL˘3k;MӨS^ͺװc˞M۸sͻ Nȓ>ṡFo8]سkνgV_9sRGU=˟OC-ZSNؔh& FR~Wa6N Z_(\-bv^U3QVCh(#sF=_eTyM9'%Hf{BHG#Fh~Il9K p0Z"cX.T柀!ihRf蘄2裐ss(KUJ#{Z:*jW*Ya*+X걇ޓ|r{Tv*c:"5d&*F+퀶+sr%WN+nDzz*조.uk-:PUYo{.ˮ:(p+I :j_&*gtb e(+/$,4*c(7qh~,D}P6#J FG-TkƲʹUw`u!٭͚ʵp-tmx޸ 0n'7'Wngw砇.褗n騧ꬷ.n,6/o'7G/Wog/o觯>p/og6HL:_&H Z̠7wGH(L W\f8C^ 9@ A HL&:PH*.1mmqC H2E+6pH:xt#7.vc sx`4$ 'BT"3Z̤&͘Fⓠ (GIRL*WJQ IM2%!iK]~.s ML2; <;yAb9Y*򚁔%-m,8IKhL:N8rlK`R,&5+II]62%6{9}:D'JъZͨF7юz HGJҒ(MJWҖ4\'H5␦7gz3M7̈NM3_je'MJ[Ҙδ7N{ӕ>4GMR'< VհgMZָEm^EyHbNf;Ўk`[֫û5xMrNjgw&j2η~owOxm'N[ϸ7q\ ;آwTHW0gNۜws3|'NHOҗ;P7[c3{`NhOקx%Nwk˻C?VA~XLZ;O[G77[.GO=KW+o+fOڳ4(Q# #yz#O?uN8mOrRӴ'*;O6~ ZZޏ9)NbϿ?CxGH%PAV'z AwDf8xV9GJ{lՀ&xXAS,؂.x4uq04Xq wo%qUTه>4DXFJ9L؄N8hWH5P}@Z8=N21uRb8R w[xhhIBxl؆nxJS8i8tHWh g,S0GF9ՇF9WxdXVȈbDaL$SDVTp*΄XX%xC#X5X劬xYx7\ŋŋ\[Ǹx~I^H^]8>u^㥍h^8ݘ^(蘎` `F H``税iu7i88y@6Vc1֐.b+&/9c9c5:70$Y&y(*,ْ*)a@e\eUe6e4eEXeN8yeN&G y 7LٔNPR9TYR AWhFg\)h}Vgg4gq6ghiy`ZfFIAYvyxz|ٗ~8 y٘٘Xj9C)iəs9A煤YyК9Yy9֛3ԛYk93ٜy Yyؙٝ޹9l5mYym? $J yٟڟm6nz n?):=AZoڡcGpZ +:-/-zCC6ڣ>j9CDzHyqNPRq"OCP (1$,^8:2a?j0Y3DqtZv LL7|ڧ~5WZ{RH(z+:CAC3 a a92:꩔ʢJz9Zꪞ33Ԛj JCɪZuںڭt" 8WZㄢF~ |zJ:  :*ۯ{::j !33dp4 ˱ "{v.02v~}#qY:Úڰjʯ`*@ L;PG;G[M[:h*^K;9JiLyCM9CeK4k˶q۶jKTɲF4z9O=˃sVU@˴VJ4[WPK+[X Bza "$9C# +; k7ĺ-{wٷ9~%X{FS[\KԻ{ ;y*c껾ˑz{#S'AuTLLy{kً,+ S۩\ۦJ$\&|$@|VKEZM<{Z˥۩;|VP|Y JŖd6J] nKr@B=DHT7Ԥ6DR=T]V}XZXm;cFb1طN"y͐Uh`ErL|}h˩Xeeؤ(80}ْ9(X\勚}Ȉٖ 4Ҧ}ڨщLAL>7(^]X۳]J.۾=]}ȝʽQwԏ_4`]=ލ_f8=ޢa{۾0&-蝾M]ߘD:Y@ye7)V}m ^ߝfxgm9ޕ..g >ٝ$^&>iy!lI2>74.6I>@Nm^>[PC^:I PRn;d^WM8}HexnZNݴPF\|.F4>J;{! EE{~M]ZA8OV,us{N;{]ڴ^~-FRxE{ZMWxT UMuH]~؞ھ3>vV걮nОZ~nɿNlni5TVne:؃?m>Dnz^{씎nJ񪦿.0<4}8:>{]>p=B??׎LFPkT_Qh^Xbyϭ뼣hcbօ n?:jxV|~??],aMրx_ z_ ASOגhVDګaW؍Eo]˥Șh\ȿ?_(xۺ oߟ|՟WiDMڝ!)@I ,PB t1b]ĘQF=~RH%MDRJ-]SL5męSΑ!N(qP.!` GM>RukV\vUkWe^%+UڇA;d\uśW^}ϷBZ(ѥ?Yr䁎+[Y恙!_shУMoZu۠p [lڵmƝ[7Lp['6 CōGys醘O<;]x%~[zݿ_ކ x 0@$@D0 0B 'B _ϭ[,1DG$DOD1EWd, gFo1G2x'xG>ygq=z駏^a>{{?|'>}חE}租.4?_8S3s81s%@VЂb u98BЄ Uj@"'CRȐy PC0>|uC}3gBЇFtOяt mgirZџuEfF/`S}㭚ʛtD<"-Ek zזG=lb-\B1[ʫsm[ڲvgmiN?ݶ6siq[ڦt"rMw[>vo~w׬@8DqG8 ^p$ чxmt_[F7ƯMqc;65^qqۻ/y^,Ŝ~ퟮ[{?^g޻.s7H=͗RL / L_T.mO.zzr??xD &n&h&@SӶ7:o??  $kӺwã#4A?}bA'}uAyd'lsb OI#D$TBA!t'(-"D;+,BiB)/0BA243D( 0d6tm9:C8Y7=C~^@A$H>DDTCxGHDX9EK4kD NOEgL$R4E"OiUdVtEvSYJť\]ŃZ`ߺE@c_edft[Dh+etjk<S)noǡQ.Ż4:=wý-ct[w<˶Gz-}\-~ܴ^@t\PR\E&K 5%ǝR <91}4dFuGRS}](JE Q-SLD}SeO SETUeOA]NUTS% SDQUU$NMVR1%UE> -SS.=.4(PoJE.=kE׊\UW}<~OeaePa5Xb+G؈H5Jä7d5ӋTD-<8aԏM<#V/VocdV9MTeELKK%HJ̚eS^L3XʧXνBSXA,rzXuO Uڰm.PkzɡmF)tOt6!ۊƳȜe/9m(Lͼ"!ĥ!j\U"j ɥ\SI;#1:3:훻5KDH,砻Cң ==7,]V=Qj={ %(EVeb] &茯 u_,F$_gĦL8-u _+_yA|z'zAz>Fc+%dv1 Vb n`>+4&%FDg?VV*+BE b"6#V%fb+P(bdQ&+b|-.6*0c*^43F1f6b8u:)dm=v:?d*p$B6d@VE^d;GB,]\%MKM5O6TNu2QNAUfḙ-KV$lNjNc.3z[X.\UVVe>LPTJR;Z 4U,iڝYoKfg,Ysf)}uuNZtϕgvVhcM<.BndhgVmV6WN]I``Δ&XoMƣ}UDuΑ^Zl[rsVVUhi,{ddꩦꪶꬮjeAKPbSRKɄ-cd.X.k[R{\ؗ١8EUV[x%]OXץ.}Q}tƊVfhVjq#MzjU5SSђ#Tk>6uҰ)MW+ W^Z4mFmlnkؖkܔ}mmPv+@T.Aˮ젱UlM6VmkNn.XP^eEa֣nk>lVkeF\p%UfXYoDGnpHnkeknWim}@kgom^oUun;VRnkZ%Wn܆&@UooȃP=%s)_S,ӻ&f0rC#GFG$?5fdS<2:BNEWtOqt0rEg9uRgtH7dItsJWwbVtUt^PWu`Q/uEguINd[W6tBNu_hF'vS7vNev,nptGrjvPkc'dWvoa?wa/wi/zuuGvw~`x?rywrwlw`wpwgx xouyvTqOSOo\x}nviv\7]n nxyjy0yyƝ7WzzwjLziazZ{7R ?D8mw{{Ttj|G]O?w|/,|+))}'7}.(Wg2p?1٧ڷ}1(|GoF''~ȿ}1w%pg~gG~$xw{Wa}w,зطW/o* c „`0la/'R Vc9#Ȑ"G,i$ʔ*Wl%̘2gҬi&Μ:w'PAaTXE^TS'RPj*VVr♰br)k,Z. Bi-ԸrҽHcмz/.lʡ@hqr͒2Ur3o")m4ԪSiزc]bw7‡/SGƎ_,Չfsܙepν ӖȐy6=ӯo/򍐗 y\ x XSyxŃ]6 tŵF!!8"%xS~)sTEWQG݋q#5z@ѨcEI*$M:^)vcLUt]UTv`L8&y_^C3n%]WFN$q9'uyTNBZ(&jfzW=U)坕Zz)jjS؟DRyidj`*G:+uq++s+oL *,:QZc,zF~e@i.6S)a:{/껯p6&md;lA[]VHn0uYa/k1/Ve0%|2<ʪj1ˬZ5\Ĺk {<4E/ pS9AE݄f*zVc'G=6eCtL0@ۼ39 $} ڴm6 >{hh-≏uU`Ya6 ޶o\577ᡋ>:{j^뭻z %p#1ЃY뮝Y !r^:J[x;8i&v}[] !@]sA܍B܉ Au3铀xA^ >a. XB L3a 34܌W(FA5~# #AGˊT3$mS vEψ} $&3I52F Z^P\gJ/\r|%,9AO-\617\(aS8#]%4)͒C{'4=d+$K8Y2.X]uS$b%ӚѰ= ՗S}WȽ*/XӉDc|+ߴq_Z+v%E7 ݝHXvaNC,Dx =1OԦY\-`A<'o'®5Y;ܼ.R5>23h"/Fyc*byTJ'^N̒1B5ǔ2FO|7 ],琔RVӝ}Z#jX',h9W3RKyX]rA gaY4Irҷ>~IzWnc3U IDjHNS:`J@uu/ 9?M[iܴRW~6\S0sllw5 M[A‰TBJqMl;B>33nq%n3(!nba1*?z;^txheHq:.Mr[8qܽ x@`;_)m2YyD{wz{I?ʵ0nGߞz~ .ɓ\mnC٤s9ykE"lȟ#Tln;V姿}GɍErz>rCLNBZz3֑>gB>na۶o>YЊ4]gGs`w?dN3i"p[ ՟᝛\ #%P =ZQFl-v $ELE8I ly ~QꙇՐUHNw4]  uhM w`  r`fYȘpEVN؎Qe@a[@@ 鈆O\_! CǡOJ#6"#" a fYq\әh(PtI`l_ j",.=QQС@L/Q~ Iɼb,cHgDl{V1"6މ!NUZbLU !&n:uHI"IBy`#?n!QRDTLY(AAvec?6dqCHD"LN$Nދ2֗F3Pv @p5!UN>PID('&(B$A'#<a8(h^ hǕ #@@!ڕD Bth X() N#T!rȐE^(≄ZAKzI T v ĄǓ%* !hlitJLNLA#@#**YA&*>"AY $ A(B pG|HکNrſYACTT((&Tުb $xA'&રV$AB(t#D)dMYXf^kiM(ƅjx&B'(BkA\(쥺AQvB!(% J1Q%'&la `@&h $4AT*"pR& @An e*ҙѺv L h@@(" t@4AW@ "%^`He@ $P@PxHx@AlKՐzn^)m`g:UE(`Bh4@&|"N|Fh( B-,ߺl;rF`tB'x`&AxLZg[4AD[Ti] lN-H 0EAz qUd,4# $4džJVhVᙛl/aGV؀ѹ tcw D$DώgfM|iA=D* ]d y\@D ZXή8OH1Ξ0 1̺$AYA{*6 P@8 ˭*"zA7TZ)AD vG $D D+w B'`ƒ4Џ-b.,:Hh@YЀXL@0(@@@w D$|%D, u^tn%råGREF@ TqBd@$xA'"ld\_'zf3:b䄶 cNQ <"B(AT%uIvf$ܭM%svj-Ds(Y @Dr)TBAB+lޙA#nJEQ+etC$A @0@WEhD:+@DޒODMS@ @[Oup|B/řȶO fE"HB%HWD[ʕh$"j0YRrV4bE\D؁HX B%|(' FJm:e]W6 sPH3 JhA"L" *%Ll7B'بa(NeV[vN"a0#|N&`%B0` KhɴmHu?Zk As.VtKCv [o[HT|i"%uDOv,4!7z#  D@qF,6iXTmOwVK,DgX$ 0B#t#m8JL*bN;0~ןATNXȣك)F?w\~gVm'!WȘ@[6h|hϺPB{iygfFFȟ |B(X°?>7x3~3 0% )W%@`A *2"IJU FȅbEV0fԸъAtSITeK/aƔ9fM7qԹgO?:hQG&UO,c*@@SG:Ѻ#,_~2V&gў `4H]w՛W /qpaÅ2HcJ GLr#lsgϟA=tiӧQtTJ}=rX۷ѽ[0nVD0Y+y*L\D(0mu&udGrVV-fѧW}{GZkGrUdG[ `8!S:A, ,Hp"2">KQYla3N>GMG1BhD!k"AFxX'\r&#ňl;'kDp3$e,3LS5ƒ X8#0K,1#>ԣ=CDw34$1$I)K1͔7;36b/#l@wԍU1UYiu@!X^?Q, TRMmgVFN=s?0eV6FAqǽ `uyR8.)KSiW}W(jmX,O(WROxaFͻOя]ߏAY1x*ASGul1'[nhfvu!xpHcx @TINZ饙n=_Cy6mvW~$"( > *ͲmjFvZoTˈzyN1p`&1#;4$(׻zI*a]Z6očy @b‹$dxAx_Ē_O׍ 3{_|fktoH^nBHݰWXwsFqcۂY{3@oNr tוr+؈z,<q,(;T QBzR(IXA@BCK2cSKfre.Mtj$Up$~V *KClI.C"ДD5+l*M[BI#pSU8)aW,aNFE.{I/Cn6P @<9ih0 8$rB"щG(W@bDK]i.Aew^bLVQb|F(*A",`en)^ԗ/i,O4 j*@4a/B`@ CH'E1&x"D\eeWH@ A6$)QM (y=?Ole$X‚ e:)D WjkPʬf5pavV# m*``@w @0a#~,Gk˘UVex'N <)'؁FJ`#]&9Q,S(|Mobzz BV #b0CF| 2&lc9ϝ#|>jD 4$ ]*&B:[ޙ \f&ต(E( -¦R"z,_ VxIOsvE{:A"0T03W UTbމy*t*7CQsTlLg&"(щRBl;{%XK{}>\B HpZ qEԂ אդ"1AԲ+aF˄>#tDN?5Xv=Eb6#Y֭X[iBF]]xŧT7NEx@ :ѨAA`v< ]Xbpcq"&͐*BŠ`d?={O?4ݺރG8L8mO}?'/}D s/L@GK:2 %Ċ ;$". *a*"  "آ (0UBP< dP2 k` tv ` f O wbz$k`p +BC`0$. "Pl 0B " ٰ cF$*,lN<08l"B" oT.D0Ћf(c/"/P C;&qN^0ckY vY""fkb ":- א 7fkq ^X8"i<!J 07t8+ (*)G :C "~CaQ7D1K"_(N8P  ,!(*!Ip C 1 I2L(c0Jº8j d XOQe}REuJ(E g 7X)r*rv @PX1 h@`d d$Ѳ -L)g6181/\܀A$ 2@,@"2(pK11-%3?;4%) !ItdDc& -A,q5u ]"s2erDz37ĀPzDr- `-18@og9nEP 49(" 19:S Npf$o1 2K   ! qs$s@m ;-Ɠ<49 @8bA72@5r)@! * L L"1w)K/@sCm-vp""r%CC,G * 8.0zNF2st*% :p`1Fat>+6Ni[ SOk0f`P uPY5 >ʰQ N); :0S\qTJLSPϖRY56HeI03CY:@DXrknR[XUa - <:!>IP1X5\Cv"P @FA>L}2Ǵg)%Cŵ_-j E .5""8@AP ASűJk_5T qJ? !R-A>ADBucmuOT !OV1\ %Ofoii'K礘iy9^2&-U3k).ivlfo6S701+jv K/MlnElm 3nk: BuS#UGKo!_{r^e`A* q gkA7xctq#wu6,k *(f0qf--EuYwxoLW[vyq07 zwz*}_w{g$%Z#Cu7qS".K{v`&J#+P0p 1 P2 FW}o&qiocl7:P nSs`7AL d*#!V  ̠ w|088yC8_ -Z 9q)r Tm4R;bT~DWTeh&Bv hrDC`~4ae+UG(CP1g ((`"r B`7.7y 9~.^M842T J4@R @r,5X<0zc B6 ww @ ))r,0F9(MzGRA9ٹd|^g`D1mbk/s*sQᎹ%N2, p,àTeA9nr6|O .':;2%Ny?.,;r,A@ac"^SiuzBbNE< NvQ|(68d'C=xaIJ>Y7ʀ A: b' 1er a " 5B90i~AHst5$x.2Tm"@(*<){qwL'rvv,b(` -!u[!BiC(ٻErn`4! ār``B&ҁ(qR@F1.A cE !,j]%^FH@ AK7:) Lg}`Zŝ|d{DAX@ (A gY翣( e/8`"b-4oEy/ 0ȿ͟W@B zݠ$zWb!/Nb)^ ,x&„j:l&HhXF81V#+ D4d$̘Ejڬ9$ΜJ 'СD4i,I:} 5ԩTZ5֭\z 6رd˚=6ڵlۺ}vX; ];%#7l$H+ Y&`,pGe0BE :h0YJ>Ŋժh\pk۾;ݼ{ x#F˛?>Hqt)T /Ü)3:?ߟlF\` .`>qM!F@k U &*bcQ ,B2J'a8Z`tB VaN> eRNIeIsjɗ_^&6Ё3B }/E/H`B!J) `NG(V> iNJi%Rea, } jBbc1pAxP . $P $1YdhlJ YAGɨ^mnmږi'.W,9n n5fv٭B="`0A@0 L A(rj,4aB `"A , /v|ڇMeuuV_uZo]Zre,vڴҚ(l"aT(1jߡR1ׂNxw]`?yoAw -XUcaP)y+jF N{3xr7>-2*tS5F%BI:\7l}c`KZ췟~?V[ӂ*heTWN[j2 w vo (dk46k=B,ٹ=7@B(#@_1yH>ՔuD.$*q x71uP t4 ]80ɰO (, RNsD&qt)|j="|W=4E)B 7n,IIю'?!L=*ոu);ItS( dЄ! e Y,cS/t5pe/YUj& ,x `g *[ s`고5I4M wƎ+N8 ЀaC B D2-y5*ΪFSVɟ0!0:'( ΋BNШߜ nblU>e4P +` ‚y/DJ'z_ lvl mO6weݴ`((45x%KR.8LnegL %bG 0~ tRr,H_)_\ mi`ȅ{!żd4 zkĬ#! qgfPA0$yn h@zԤ9e~ds"ո--\Ӳ|BP?($by)+QzN⩑hc @( h֐MD " )" @MP;6f{SsAMv)4qRtÚM;An⫫1aozk|,f Q1p&jIfhZ-XA@$tֳq|W7kBAhDS,0#1~O3^`kB40&a]g$a53z(oԫ;rVD XBQMPzm@WO~;u|WDS0p4U&@.0 PvF>7q1t!hEAB'2+d#)  ߇~4(56_Wue$7I0M0o0U0sH!-eaHr8Y^(uUGx%DVxc0#@133$1h rD5Rn8zdRd!psxsa ` `C0Rg(8*0;)X/P Moy O8~hAÆ+6P P w=WXW5hxy4@MIc|Ѧd8萨|&o$M'zf2``Tx6טI'uHxb:AQn iaC` p `~Qud1Ő(yV(7X}4VP@ 0 BW*fIVh>UViPMk x PsGb@ 9^GkyJ3(SǘTrqTKPg+: u eH*i*6! P?S;0-,,QsH̷YESy"#/.(S):UٛӘ&0cV@]PwA+RBT`*ɟ0  a&y= LSF)煟VT(ɘ6O Q "l7i?#H9-qk9-Fq=<21Tɘ\**7Wր,KlňCҞ6q<A P4/2*јG<,Ra[ LruP91($!<9kjVYҏi0n#%!Ne6=bh7*AJ !,y6ppQf`Q-y `&9*+ZjNv#`ژ (d2`C)KHVۺ# x󩟚oʮa;B_ 0X@+EHq8X ~BљRձ*©FSZ!ab`-3hNW;3I*i\@!!A}<ҲIZ4i8Y!!%:u'`ј F9;q1I+lac|N"dڲpk1zP q$P|a;{TɊ)uSgƪm,]t nh`{|+}[BEڨCRS '欃zVz;{OOəWp4P'`&iVɻkN{~2˺K;Nʈ? 30 k˽i4ٖO*Ƌ{S[B`J&1AIq@\@:fm˿FIyg諾 5U:9(Z9U::AU'C![.P+[(L#㷔$1C#ip :)b`$O|[mY $C\a-^wJ!/I0 "pDZwybD$p 7v0qy`@vP!},yǾ9OWFZ SIq%?e“[FWi .pI#@91 ݥ$ǼsaaspqȒ bȒ.0I@R\ʧ[T %0z$PĹ0`M +1p7‹,;$fT z,7A@M@"Fb\۲,$ g -Қb{UlJ=(Y6QQP,u ǣ:A5k9+C7lP_#͘CQ|YUmW]ծ*L>e@-_]2zJsFz :n8-Ox 5! um!/xr`X;؇xFA^mב-%Q1kY ]0!Bg,?t-ٯ GL{ AP P* K=a`X0H mڰ Ŵ0W0:@,0n n]]@>oW?Xp'Rq@"e^7.!Cᴘ" 3Pf^18i9yb`:=#` nO}ѽaI 1Q權,Ǜ~*GIo$"7´#lci#C DqJiϣC+dp/DohfߡasΌ\N|Vd`meRo0\$(Q#e.dذ!XEbc,E$YI)UdK1eΤYM9uOA%j$X; +ҍNNU/Lڕ+/4҄Yiծeџ.L]y(_%SiȢ/fcȑ%O\GG>ԩ&iԤUg( JFij[۶ZHV9[ jɓތsѥO^uفjٳNZ޼םJQ3{+X`\ ݿ?P< nAtA#pƸ0 /R;)AMLq &H+pH!:. .s"<J>O@T1);3blH#t)I3TȾlOX=N8ACG0Я< sPZkV\sCT=-҈& Ԕ #e?(UdL笳Ybu[pw\r5\tUw]vu]xw^z^|w_~_={0`"C(7BU48r8;2+U0E-VRVye[vecyfkfsyg{gzh6hVzi) <KG<|ppW8w7"|rհ|9(sC]n5Y |սF cgqe7l`E(wHTbH;}ywyK{xD۫x8< W}w;z~yaoP7 ^ Xݭw4O`'(=l$aS~*c A'f1+oDZJ-BPlFWQw·CdB40H.aD(NH]SGdž:0n!D7Qdc%48QscxG6]^n6lO @>WtPFȫYjvȂuUN&of* .~#o\S[/\ O8 tp @ @ t)  $A DA ,A4d| A .A,A\ BA"X@Ԉ3<B`lBDB0 C1D 1 C2C31LC0362C7d7t;;46S?S@ TATB-TC=TDMTE]TFmTG}THTITJTKTC@?TLTP UQUR-US=UTMUU]UVmUWTOTxU[U\U]U^U_U` VBU?;VdXHVfmVg}VhViVjVkVlVmVnVo;Vp WqWr-Ws=WtMWu]WvMemWcWyWzW{W|W}W~WW ط{k ;proguard4.8/docs/drop1.gif0000644000175000017500000000144311163773610014234 0ustar ericericGIF87a}}}yyywwwuuuҾ|||vvv,7B;proguard4.8/docs/screenshot_console.gif0000644000175000017500000004476211163773610017121 0ustar ericericGIF87ayQUQfff,yX^I8ͻ`(dihld;lx|pudrdFШtJZجvzxL.znO8^x~iq[suKZ JFDTSR|PUMN‡N%$0 A#^ ŋ.bĢbCȓ88%y(XXI %$Ξ]NIJT!IM :7ssV(v"ٰf Rvkڲ`j趫ݫx=*@RbL}ҷ ԘU*)cݻ9v]g1?^c˗q6q  s<' BerLԸd[Iد9S6K}vsNC(>z)k&:jkOPǿܱ@~9s{lI3ՓX _dטqA{J}pW܇yod&w xwڶ 4ۅ6_m툑[!և[Ù'dLQX/6Xw 6)}C!A=(@>gp~utT*XV矺ɧR, űPfק2"褔iF(SIhV$ꌙj;N(CFꬴ:k*+* #k&6,/l8ffv+k覫+;@0++l' 7 ⻔Agw ,Vl20*0,4llŝȼ.[Cln@.J_tPG2=@ h6m-c 6fGpÝs;d t?ë7o̅>gSmx|ܷ֗3my}Йoyyޜ#5Sy壃:9~zߞ8nvO{<|{.<;_}^ӭ vWk}m'wkQœvk[@#`h<&0m d~׿Et%@ :pr;\3Apo 9B;_ 'nv6B~C۵Vxabվ{D&zś` yD jЈF_G7Fv1v;aXD//qke>g+WHvZ&e!$;HCqd$hI픬$;3^tޛ,%CцlĢH R#]7d%&MYJI2l&)iNqu&'B)T&*[)~ӕe,YZ%9Hω!IS1d$ Y?oFra ſOދ)OQ'WuW^Oiȟtn)Q˘n"CRj@KJkq)V= ]nW\9w͵]w-^zRuy 3^γڑ++? VVUdYB^֮ehWfMjWZ9VgmlgKږ]-2+Wy- pu-o?[jčtܦo[Uj xZc+%f՚h&3%aD;WZYE귙DL!''q(#Z-oKQ.?X5T]eb0m#wZX^D5'Mxk.V/-bh31Naל쮃7N$?r+,Wx`scK1b ?ֆU,2+M](bγ~7U4T[T!\W7A'pLJKm5glN{S3uo_PԔtdQVҢ氦_MZZdw^3w5gQRkό\dM8`Sxf͌Mn{dq(X"Mߎemz!&бsFNۖ؞()u\e~H N׾Q9ؘ_9BZvֺd>;vU]洌5`S)FP|mH7ΗjSTZno2z-?zL;m{Js i_qNv&w}}KZwaFlpלmӘezwqKܐKoxҏ`8x;װrZ7|VgG=A4$fT Q_G`^s+7emsv"NfcUH"pr(QVJPDb㤃0Da/gM"vUP(NhQsX]C|fQpN~9~H M gc$4|0(~mrV|Zfq7\} R$(tF8AȅNu_hf-6Vt(ex[Kh}HTp"ϤQ&8Cb.Gs6XHxM-(5'gXӇ+Xgc((__XMGs]tKEH`nf hØ,Wȏ܈(uoX|axzo@gYPqV;D]'uR&RQ'~,ywyVfÊF$Oh7uUTT~ȑ*Ɉ->cyٖ~2ek9i3X$<Z]Yl`WXj3ZXyXC(6iwb qx)Xz3{5960ٍGuY9r(y)IH|+OqyĹz)0ل)/ԉ)si17viUBeGJugnhCF_ZYxWU_~9{xBkx|ȟtEuXVڕ=i_L'ɝv6qȎ[ȔR1YLh٣jlXr; HPRnxw9R^ȞtV#&gNjtHʜ_XD^ ։J:r7jEĨɨ}zbĦ&<ה$ZڨhVD&U^zTexDHJ艂*OyESXǧFV&B85x0瘡XmizMG`pZꞆb0z|Pn\Ƨ9jzj{X0I訁9^5DɇPy(Z:O礑SEhJKIw 9ZchWdĺ|Dԋf n46Q)RR#kQMG3-yJD+4~ؓsuݨ#N;2O@볦ڔ*_IO/ nv0sWiiI{zzt:>LkyЉ1 q)Zr IRy \㶀W60}/VPl{8i[fg 3 |ۮ;&gk~Z~)ۻ6۷;agWihK[(n@Kқg;bjg)>;ޫdkK+^[stE(\[˜{{`{<[3 rU<W;`8 VөKkK"lhj5(<\W. 5;K4,Z+\8ܖ1(-]҇zvS?{SԮ CmԀݩBˠS5~;#@, 8 K9k`[6rJ,J܅@E=K*Ɇj>:|F[ k΂,ƩAPmriL)F:yP,[=2x}ډ ʾ-F3,΋Vn1GD׭Xg>gzm 61S^ǍHܓ ռ_-,ŨL޶b^Uۼ? ^ፊ >ʝ*>ڃ KׄMѭztiw ;>I]맞j: In-m>@]VUAK{,T(ڵm[\n]qm/OpnI5f>wMZ~1_޹ s* 5+g֚~+5/WoNA?Z͗=m? gAY$Yc_!E~NtFVnPΫ@$E0T}Sihlp,tCzP p BQ^:3:B+0ߥ嚼bzS FUl7=aOtwUdl[V}O{65?>;@GDFCpkfocfygvyZRp~|3ɋƍ.V}М18;ACEH$#!sد%`)?4~ 1bIA\!Q>l;]{#ǩ\ɲΉRW]c+D˂*Jکz&,BKkR"է&H@KM)6)N^(PLՔD (Vhᅔw :gQb #bh(r[(4h8"}*@)DZ/z8FXVg*X!Xf[xE6鍓i^Ԍpґ$&E2/ycArjh7\nhg0Aw]yuTţ/~,w%!RoWosΩ-@ tꐤx@z؛ݴ<)V]UaLyt3R9 g kn-z_FYWy T_A,K[et>Mګ Ț0/ :$j&.U5lu.Tb(Dh:i֑ ,薦;o+{P,PU<FT#oEqJ2.lup%0Jotbd< ω=4BMlfF1{}|4,ڈDZ-ߚn't**E*kR:mAx)EZ5ߨϘÌu3Z^׸z},&6 &ǣe/g(%gd`?KN`6HuG~T*u㱟8+džtYb7>f,ikt9N7K(*[-0Z lP Iӥn]$2Sϴ";zIEhvh6MiXq ́2f1B2 FDT$m{BidGII+<Z$͐FaHQHuOh3H6=k &]Rɐ2D[ A҉3"ڬ6q)I6q$dL&V0 .71OZA=,!T%5Imxg㎃MGt ]BO]Th2ˈ$!Z4ըHŨ36Ӣa_HGR -Lgz8ͩN:QiJYLxOPQĐJժZZ3U*3f|LMZM(6T:eH6Ec5D-zc.QxlIN2=MN1]1לQ=3*f6b^Rh旱vv`|B'ܠ :V'}'-hC[yy^{Nۮ W> x Uwkx|r^P8{Tt9B]aXnkÅg(EFZ=}H9px鶈TNg:W)ĉ=h)vVD+MS}7vs(-!g4\\WAW1׀˳g 9<4sJ[gu?SLStMC*s7o#I s"IنYhH)2%v;JÎވIW(Iْ&7&ff-WcEV eiiQi*E0cS,A<ؖ䀕>IO%NRVW%牞87K*Gmjb@%'8yGC294I93i(%}޷ @)ǙY XT7GRYGYYdIdNs(М`+*iv)y鏛9VOU3%fT/wEyDuBg0 ezoHMNԚl9.bFIr@\0L@T\}9.DVua3wX١>C qnړ58BDKqo6dyyטnP#iUZۙ٨B":"z"晞!9;z9 vJتV)qO톩֟jc!ي iXubQw\yɗ z'顋% i @@[B/EkyYb5} eFmڊ⤢4rXJshIMipA=bzZs![w_* K[gZ…0:;H; iA/+MuPYeR)?:KK} v{hoZyîM7ƷI{T֩g+$J{[ ;%[<7:amJ2„؏ y&&rI4hRk;F9Ĺ֩Kq g&Zw)nVH1jZ]z;G{Ҡ7EJhOp(5Ktiira`83;ZDž5ٵ1kV˕,{4 gxێrj/B{BZLqnPKD;{!`h)ʥ]-zHl)4|38!S! K[v!t@q N5 "wixx٨~yyNE8s%:i:o tȠƊsȒ\ɖŧêYĺ B>eOgK:6,lz˼V!ixJ`PJ"C\˛J,BGiy|:tLjaBo^q3 vdbYc \V‚Z~Ė4k[, ,`s TQ5d&<_\i'ηj$|up>wvG(3dZ2X{ *}[$1ish_*]+ poH{7%L2Ȍ(}[lk\:P烈J7|9Opm y4"єzɨʼn9xgQ&-'|ٚ ٞ&}DR%n 쬥N ̬la#cŬ}C̴}QmVBqV{c8TlPh=2 jpL ܀D̿r覧)qyZ|8ޯ#|W+gQϘ)Z3/ -mXsܽLYB*H %wm35-(ۇމl;M &@,HDs/P|vS-7GvͰ~Y X"m~eƉ{r~ ل^Mهߌm[$nM֒wmĬ'L,om뺮; O^Ox̜rKACjğެF*]t 5L9ko-- M4+$Xx!r;鸁r{ZN.0I8ͻ 0cI0D+vR6x.f ʼn!eб2zmGDmzY=b5}~ *()$2/1-sLCOZm=1IleQhorkrpDmS`9ddtjuXR`_vz(+wdGg7xwNg8;m3yj.uAߍC=nE\̇hA3ӖV.HX$2[3z.yy!'pͶ1`luC}6)F"Ѷ( uSV#Q<$Y bt$š<|y'J !z~3ԫRt@RY"}I`*LA.:T҆|#u 3ixS86 ؿ|3X@Cb0BU'.@%d UIGQscHDGÄl;J9煨i+ iPgzIUho:gU_]zV=R܋l t1+AIՈجK~Qmf) iZ:ӔH ;E6z01fѲg0W $ں5[IpFv<,NɚPVڠZ.qf}m}p\l*;;hVL'>T8;vCuv6㒵f}n0>}|A\$qE4Shyqiq6wI7]3^l";pI8b;UdܨWوVM Zoxpx$jG G:m&yej^2i*hQ`!^H.Hz|ZPjPJ7\ZԨ3g tu98m~xZvkg=^ĩSXcYr3Z*iwߥzZ](՜ɧmydL08JA#iى]&B6gʢOIuyşSƩ~VrfmgY8*V y{-zwgdTlVR EtuDMd#K7 ۮ=F?sHV:WHB6Iҳ\î-u6PK/C:T K\JXA]0zk*)QpSʧ|ɚwn9|]D s%;)z+'Ru0;{{N~ iwRX[*Y9\%ĩ<1omq׹ 8Du '&fZqZ1ʸ]˂+ڪ*yOjXk>HX pieǀMg9`=N;?>:t*Pl Bl[}< )YF.d{R .SnׁMJ|#?̣A9*q]' L8rMa1Ùj8:LvJ *$JbҶi08OUV˳F[W||ص?z9_< 7,r~gE:V<9lx #H58 3Gwyj~c#'ʁ̙]sQ жKXmK˅bWMkʬn\Z\o]< $wvX0׋ȳF4;=}3\RiaV L]/,*;hvZrj@tjxS*Q(w^ʪʪ|ۍ~ڠ4=xz]>E+<Ԥ6 ,`8+f˸:W̒Mҭ׵bd|a b\v (h+PvL= lZ=}.;D0Nm( jz}D-|r9^l Ǣ5lZ*4C2ɺެJKDHQJ z;$Q*!-ZBC@i\/ .zÔ抟.޶*M-ZJ[mw6GlBhS?ʏq\޻mdmrxm;xzɍDxNR\ W{^ۍPx=Hm؈vtM̺x=m9 {Ҏ о~QLɞJN7^g,VgZeN.- Zg~ƺC-XQ,G"Ɋ>HFҾ]1ilZgKf6;Q)}S\H>A|>n")t'ܰVT^.I4k$ +} εbޣpLl^(GY}MO(TC='^5d _Oa9v~ޣ68RV`^k=&5}{F L+cΛT^zz_cd\җ/֠nP]ν:>q}^Oߋ]zܧSɢؚOlmG_C4oF.HD>c/L__)ri0I8ͻ`(diJC1l@Ĵ̄2|Ԍ'$$l&GuZجvVRx<pMDUVomK_}246gk;}L K}PUnm͇ӈ9hl>Rܵm?D,{'Pftz$zfםO砘firbtyZҞŦmm꫰(fRTZkW2*:y$ԫ$4ff-QNpMkp4_춛B0;[R'\j'EkhKmǞ>w1pIx()dx4 !VBآ@s" ,L7-ډ&abNWm[|ȷ 35E]wjZb݌և[f *Mn} 1 նrS ȁ߭oSAuBj_)f'孖zV?žy:˵hNI@*N{ ϖ̱(;9V?w7m&dθZ,q@r6Fƀ@J6Toq¬ -f)g02 ֳ~ӿ&qrLf/bt 0 2=죂^ҩd*us! EO)Vd/ ьLT 5xG5ztFzt4(čzI).P¨f8Q, Q@PG )\U(5E K 5Oܡhȹ=N O99"烻 #دb2CjاS)3$/U9j&"@_$܃XdrcF-02]qӁ~\c[^)T%D{gڔR+O9vOb)<%)4N{hOXw+JANC[[j nthtK `p8KK"n^{NYs,uN$աnD*/3Uj:db=_\2&5pp,xuWvEj `KMb:d'KZͬf7 mhm ҚMjWֺlgKͭnw p[45.q:ЍtKZr\n7 xKMzs`h+ͯ~LN;+aQΰ7{ G LM;proguard4.8/docs/acknowledgements.html0000644000175000017500000000616111757555264016756 0ustar ericeric ProGuard Acknowledgements

Acknowledgements

The first versions of ProGuard grew out of RetroGuard, which its author Mark Welsh kindly made available under the GNU Lesser General Public License. RetroGuard is a very nice piece of code, but it only performed obfuscation. I started from the class file parsing code and wrote my own shrinker, optimizer, obfuscator, and preverifier. As of version 4.0, all of the original code has been rewritten, so the most obvious remaining similarity are the program names.

Dirk Schnelle has contributed and maintained the first versions of the Ant task. I have rewritten the implementation for version 3.0, but the XML schema is still based on his work.

Since its first public release, many people have expressed their enthusiasm and have chimed in with interesting ideas, bug reports, and bug fixes: Thorsten Heit, Oliver Retzl, Jonathan Knudsen, Tarcisio Camara, Bob Drury, Dave Jarvis, Marc Chapman, Dave Morehouse, Richard Osbaldeston, Peter Hawkins, Mark Sherington, David Sitsky, James Manning, Ptolemy Oberin, Frank-Michael Moser, QZ Shines, Thomas Singer, Michele Puccini, Roman Bednarek, Natalia Pujol, Daniel Sjöblom, Jan Filipsky, Charles Smith, Gerrit Telkamp, Noel Grandin, Torbjörn Söderstedt, Clemens Eisserer, Clark Bassett, Eduard Welch, Dawid Weiss, Andrew Wilson, Sean Owen, Niels Gron, Ishan Mehta, Steven Adams, Xavier Kral, Stefan Martin, Toby Reyelts, and many others. Thanks! Your feedback has been invaluable.

Saikoa is providing the financial resources for this project. At Saikoa, we're also developing ProGuard's sibling for Android, DexGuard.

SourceForge is providing the resources for hosting this project and many other projects.

The code and these web pages were written using Oracle/Sun's JDKs, Linux, IntelliJ IDEA, GNU emacs, bash, sed, awk, and a whole host of other tools that continue to make programming interesting.

And finally, I'm a great fan of Sanaware's Java Docking Library.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/quality.html0000644000175000017500000000431411736333522015076 0ustar ericeric ProGuard Quality

Quality

In order to get a feel for the quality of the ProGuard code, it is run through a regular automatic build process. This process produces numerous statistics on the source code, Java lint comments, Java documentation comments, the Java documentation itself, html lint comments on the Java documentation, spell checks, compilation results, an output jar, dead code analysis, a shrunk and obfuscated jar (using ProGuard itself!), test runs with memory and performance analyses, etc. Most analyses are produced using freely available tools. The results are poured into a convenient set of web pages using bash/sed/awk scripts. You're welcome to have a look at an uploaded snapshot of one of these runs:

Automated Code Analysis and Testing Pages (at SourceForge)

The pages will appear in a new window, which you probably want to view at full-screen size.

In addition, ProGuard is tested against a constantly growing test suite (more than 1300 tests at this time of writing). These small programs contain a wide range of common and uncommon constructs, in order to detect any regression problems as soon as possible.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/license.html0000644000175000017500000000503711736333522015033 0ustar ericeric ProGuard License

License

ProGuard is free. You can use it freely for processing your applications, commercial or not. Your code obviously remains yours after having been processed, and its license can remain the same.

ProGuard itself is copyrighted, but its distribution license provides you with some rights for modifying and redistributing its code and its documentation. More specifically, ProGuard is distributed under the terms of the GNU General Public License (GPL), version 2, as published by the Free Software Foundation (FSF). In short, this means that you may freely redistribute the program, modified or as is, on the condition that you make the complete source code available as well. If you develop a program that is linked with ProGuard, the program as a whole has to be distributed at no charge under the GPL. I am granting a special exception to the latter clause (in wording suggested by the FSF), for combinations with the following stand-alone applications: Apache Ant, Apache Maven, the Google Android SDK, the Eclipse ProGuardDT GUI, the EclipseME JME IDE, the Oracle NetBeans Java IDE, the Oracle JME Wireless Toolkit, the Simple Build Tool for Scala, the NeoMAD Tools by Neomades, the Javaground Tools, and the Sanaware Tools.

The ProGuard user documentation represents an important part of this work. It may only be redistributed without changes, along with the unmodified version of the code.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/FAQ.html0000644000175000017500000003052111757647245014031 0ustar ericeric ProGuard FAQ

Frequently Asked Questions

Contents

  1. What is shrinking?
  2. What is obfuscation?
  3. What is preverification?
  4. What kind of optimizations does ProGuard support?
  5. Can I use ProGuard to process my commercial application?
  6. Does ProGuard work with Java 2? Java 5? Java 6?
  7. Does ProGuard work with Java Micro Edition?
  8. Does ProGuard work for Google Android code?
  9. Does ProGuard work for Blackberry code?
  10. Does ProGuard have support for Ant?
  11. Does ProGuard come with a GUI?
  12. Does ProGuard handle Class.forName calls?
  13. Does ProGuard handle resource files?
  14. Does ProGuard encrypt string constants?
  15. Does ProGuard perform control flow obfuscation?
  16. Does ProGuard support incremental obfuscation?
  17. Can ProGuard obfuscate using reserved keywords?
  18. Can ProGuard reconstruct obfuscated stack traces?

What is shrinking?

Java source code (.java files) is typically compiled to bytecode (.class files). Bytecode is more compact than Java source code, but it may still contain a lot of unused code, especially if it includes program libraries. Shrinking programs such as ProGuard can analyze bytecode and remove unused classes, fields, and methods. The program remains functionally equivalent, including the information given in exception stack traces.

What is obfuscation?

By default, compiled bytecode still contains a lot of debugging information: source file names, line numbers, field names, method names, argument names, variable names, etc. This information makes it straightforward to decompile the bytecode and reverse-engineer entire programs. Sometimes, this is not desirable. Obfuscators such as ProGuard can remove the debugging information and replace all names by meaningless character sequences, making it much harder to reverse-engineer the code. It further compacts the code as a bonus. The program remains functionally equivalent, except for the class names, method names, and line numbers given in exception stack traces.

What is preverification?

When loading class files, the class loader performs some sophisticated verification of the byte code. This analysis makes sure the code can't accidentally or intentionally break out of the sandbox of the virtual machine. Java Micro Edition and Java 6 introduced split verification. This means that the JME preverifier and the Java 6 compiler add preverification information to the class files (StackMap and StackMapTable attributes, respectively), in order to simplify the actual verification step for the class loader. Class files can then be loaded faster and in a more memory-efficient way. ProGuard can perform the preverification step too, for instance allowing to retarget older class files at Java 6.

What kind of optimizations does ProGuard support?

Apart from removing unused classes, fields, and methods in the shrinking step, ProGuard can also perform optimizations at the bytecode level, inside and across methods. Thanks to techniques like control flow analysis, data flow analysis, partial evaluation, static single assignment, global value numbering, and liveness analysis, ProGuard can:
  • Evaluate constant expressions.
  • Remove unnecessary field accesses and method calls.
  • Remove unnecessary branches.
  • Remove unnecessary comparisons and instanceof tests.
  • Remove unused code blocks.
  • Merge identical code blocks.
  • Reduce variable allocation.
  • Remove write-only fields and unused method parameters.
  • Inline constant fields, method parameters, and return values.
  • Inline methods that are short or only called once.
  • Simplify tail recursion calls.
  • Merge classes and interfaces.
  • Make methods private, static, and final when possible.
  • Make classes static and final when possible.
  • Replace interfaces that have single implementations.
  • Perform over 200 peephole optimizations, like replacing ...*2 by ...<<1.
  • Optionally remove logging code.
The positive effects of these optimizations will depend on your code and on the virtual machine on which the code is executed. Simple virtual machines may benefit more than advanced virtual machines with sophisticated JIT compilers. At the very least, your bytecode may become a bit smaller.

Some notable optimizations that aren't supported yet:

  • Moving constant expressions out of loops.
  • Optimizations that require escape analysis (DexGuard does).

Can I use ProGuard to process my commercial application?

Yes, you can. ProGuard itself is distributed under the GPL, but this doesn't affect the programs that you process. Your code remains yours, and its license can remain the same.

Does ProGuard work with Java 2? Java 5? Java 6? Java 7?

Yes, ProGuard supports all JDKs from 1.1 up to and including 7.0. Java 2 introduced some small differences in the class file format. Java 5 added attributes for generics and for annotations. Java 6 introduced optional preverification attributes. Java 7 made preverification obligatory and introduced support for dynamic languages. ProGuard handles all versions correctly.

Does ProGuard work with Java Micro Edition?

Yes. ProGuard itself runs in Java Standard Edition, but you can freely specify the run-time environment at which your programs are targeted, including Java Micro Edition. ProGuard then also performs the required preverification, producing more compact results than the traditional external preverifier.

ProGuard also comes with an obfuscator plug-in for the JME Wireless Toolkit.

Does ProGuard work for Google Android code?

Yes. Google's dx compiler converts ordinary jar files into files that run on Android devices. By preprocessing the original jar files, ProGuard can significantly reduce the file sizes and boost the run-time performance of the code.

Does ProGuard work for Blackberry code?

It should. RIM's proprietary rapc compiler converts ordinary JME jar files into cod files that run on Blackberry devices. The compiler performs quite a few optimizations, but preprocessing the jar files with ProGuard can generally still reduce the final code size by a few percent. However, the rapc compiler also seems to contain some bugs. It sometimes fails on obfuscated code that is valid and accepted by other JME tools and VMs. Your mileage may therefore vary.

Does ProGuard have support for Ant?

Yes. ProGuard provides an Ant task, so that it integrates seamlessly into your Ant build processes. You can still use configurations in ProGuard's own readable format. Alternatively, if you prefer XML, you can specify the equivalent XML configuration.

Does ProGuard come with a GUI?

Yes. First of all, ProGuard is perfectly usable as a command-line tool that can easily be integrated into any automatic build process. For casual users, there's also a graphical user interface that simplifies creating, loading, editing, executing, and saving ProGuard configurations.

Does ProGuard handle Class.forName calls?

Yes. ProGuard automatically handles constructs like Class.forName("SomeClass") and SomeClass.class. The referenced classes are preserved in the shrinking phase, and the string arguments are properly replaced in the obfuscation phase.

With variable string arguments, it's generally not possible to determine their possible values. They might be read from a configuration file, for instance. However, ProGuard will note a number of constructs like "(SomeClass)Class.forName(variable).newInstance()". These might be an indication that the class or interface SomeClass and/or its implementations may need to be preserved. The user can adapt his configuration accordingly.

Does ProGuard handle resource files?

Yes. ProGuard copies all non-class resource files, optionally adapting their names and their contents to the obfuscation that has been applied.

Does ProGuard encrypt string constants?

No. String encryption in program code has to be perfectly reversible by definition, so it only improves the obfuscation level. It increases the footprint of the code. However, by popular demand, ProGuard's sibling for Android DexGuard does support string encryption, along with class encryption and hiding of access to sensitive APIs. DexGuard is distributed by Saikoa and is not open source.

Does ProGuard perform flow obfuscation?

Not explicitly. Control flow obfuscation injects additional branches into the bytecode, in an attempt to fool decompilers. ProGuard does not do this, in order to avoid any negative effects on performance and size. However, the optimization step often already restructures the code to the point where most decompilers get confused.

Does ProGuard support incremental obfuscation?

Yes. This feature allows you to specify a previous obfuscation mapping file in a new obfuscation step, in order to produce add-ons or patches for obfuscated code.

Can ProGuard obfuscate using reserved keywords?

Yes. You can specify your own obfuscation dictionary, such as a list of reserved key words, identifiers with foreign characters, random source files, or a text by Shakespeare. Note that this hardly improves the obfuscation. Decent decompilers can automatically replace reserved keywords, and the effect can be undone fairly easily, by obfuscating again with simpler names.

Can ProGuard reconstruct obfuscated stack traces?

Yes. ProGuard comes with a companion tool, ReTrace, that can 'de-obfuscate' stack traces produced by obfuscated applications. The reconstruction is based on the mapping file that ProGuard can write out. If line numbers have been obfuscated away, a list of alternative method names is presented for each obfuscated method name that has an ambiguous reverse mapping. Please refer to the ProGuard User Manual for more details.
Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/index.html0000644000175000017500000000521211736333522014513 0ustar ericeric ProGuard <body> <p class="intro"> <b>ProGuard</b> is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes. It optimizes bytecode and removes unused instructions. It renames the remaining classes, fields, and methods using short meaningless names. Finally, it preverifies the processed code for Java 6 or for Java Micro Edition. </p> <p> Your browser doesn't support frames, but that's cool. <p> You can go straight to the <a href="main.html">main page</a>. <hr /> <address> Copyright &copy; 2002-2012 <a target="other" href="http://www.lafortune.eu/">Eric Lafortune</a>. </address> </body> proguard4.8/docs/results.html0000644000175000017500000001271711760420066015112 0ustar ericeric ProGuard Results

Results

ProGuard successfully processes any Java bytecode, ranging from small midlets to entire run-time libraries. It primarily reduces the size of the processed code, with some potential increase in efficiency as an added bonus. The improvements obviously depend on the original code. The table below presents some typical results:

Input Program Original size After shrinking After optim. After obfusc. Total reduction Time Memory usage
Worm, a sample midlet from Oracle's JME 10.3 K 9.8 K 9.6 K 8.5 K 18 % 2 s 19 M
Javadocking, a docking library 290 K 281 K 270 K 201 K 30 % 12 s 32 M
ProGuard itself 648 K 579 K 557 K 348 K 46 % 28 s 66 M
JDepend, a Java quality metrics tool 57 K 36 K 33 K 28 K 51 % 6 s 24 M
the run-time classes from Oracle's Java 6 53 M 23 M 22 M 18 M 66 % 16 min 270 M
Tomcat, the Apache servlet container 1.1 M 466 K 426 K 295 K 74 % 17 s 44 M
JavaNCSS, a Java source metrics tool 632 K 242 K 212 K 152 K 75 % 20 s 36 M
Ant, the Apache build tool 2.4 M 401 K 325 K 242 K 90 % 23 s 61 M

Results were measured with ProGuard 4.0 on a 2.6 GHz Pentium 4 with 512 MB of memory, using Sun JDK 1.5.0 in Fedora Core 3 Linux. All of this technology and software has evolved since, but the gist of the results remains the same.

The program sizes include companion libraries. The shrinking step produces the best results for programs that use only small parts of their libraries. The obfuscation step can significantly shrink large programs even further, since the identifiers of their many internal references can be replaced by short identifiers.

The Java 6 run-time classes are the most complex example. The classes perform a lot of introspection, interacting with the native code of the virtual machine. The 1500+ lines of configuration were largely composed by automated analysis, complemented by a great deal of trial and error. The configuration is probably not complete, but the resulting library successfully serves as a run-time environment for running applications like ProGuard and the ProGuard GUI.

For small inputs, timings are governed by the reading and parsing of the jars. For large inputs, the optimization step becomes more important. For instance, processing the Java 6 run-time classes without optimization only takes 2 minutes.

Memory usage (the amount of physical memory used by ProGuard while processing) is governed by the basic java virtual machine and by the total size of the library jars and program jars.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/sflogo.png0000644000175000017500000000072511163773610014521 0ustar ericericPNG  IHDRXTtEXtSoftwareAdobe ImageReadyqe<ZPLTE_jrt~jt{ٔв쪜I*̹¸鞍mVRIDATHn0Dq)'3of!dC ArSp g]{%rR.jjd_gW7T{]Eud0MqX.\v+ۘ^npA9C3ATYY1J% i&bS#Y}R %zZd)Q@ڊ\ÀkZʿgB}:t_ jOH^.<~{LSlFVkj`/?8(8? 'S zIENDB`proguard4.8/docs/drop2.gif0000644000175000017500000000115411163773610014234 0ustar ericericGIF87aFyyywwwuuu|||vvv,Fр31.-, 720. ,:82,=;961-" ;30&"=:7.%A4B<92/=5/*'#>3 ($?:6 )!+)%+%@ ^~%gPaCt@ 'Bh ǏCR9RFSf\eǒ0O<M}ڸݓF6e̜AF@;proguard4.8/docs/main.html0000644000175000017500000001031611757554166014345 0ustar ericeric ProGuard Main

Main

ProGuard is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes. It optimizes bytecode and removes unused instructions. It renames the remaining classes, fields, and methods using short meaningless names. Finally, it preverifies the processed code for Java 6 or for Java Micro Edition.

Some uses of ProGuard are:
  • Creating more compact code, for smaller code archives, faster transfer across networks, faster loading, and smaller memory footprints.
  • Making programs and libraries harder to reverse-engineer.
  • Listing dead code, so it can be removed from the source code.
  • Retargeting and preverifying existing class files for Java 6, to take full advantage of Java 6's faster class loading.

ProGuard's main advantage compared to other Java obfuscators is probably its compact template-based configuration. A few intuitive command line options or a simple configuration file are usually sufficient. The user manual explains all available options and shows examples of this powerful configuration style.

ProGuard is fast. It only takes seconds to process programs and libraries of several megabytes. The results section presents actual figures for a number of applications.

ProGuard is a command-line tool with an optional graphical user interface. It also comes with plugins for Ant and for the JME Wireless Toolkit.

ProGuard now has a sibling optimizer and obfuscator for Android, DexGuard. It is compatible with ProGuard, but it goes further. It directly targets Dalvik bytecode and it provides additional features like string encryption, class encryption, and hiding access to sensitive APIs.

The following sections provide more detailed information:
  • Main: this overview page.
  • Results: some results obtained with ProGuard, including timings and memory usage.
  • FAQ: answers to some Frequently Asked Questions.
  • Manual: the complete ProGuard user manual, with examples and troubleshooting tips.
  • Quality: a discussion of the (excellent) quality of ProGuard's code.
  • Screenshots: some impressions of what ProGuard looks like.
  • Testimonials: what users think of ProGuard.
  • License: ProGuard is free, under a GPL license.
  • Downloads: download the ProGuard package yourself.
  • Feedback: tell me about your experiences, or learn from others on our forums.
  • Acknowledgements: people who have been helpful.
  • Alternatives: other Java obfuscators, optimizers, and shrinkers.

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/screenshot_gui6.gif0000644000175000017500000011040311163773610016313 0ustar ericericGIF87a333fffz̴θνҾӿ,o H[*\ȰÇ#JHŋ3jȱǏ CIɓ(S\2!K._ʜI͛8sɳϟ@蒇ѣH&MӧPJJիXjʵׯ`ÊKٳhӪ]˶۷^fPt-x˷߿ LZb+0]Đ#KL˘3k<MӨS^ͺװc˞M۸sͻ Nȓ>ṡFo8]سkνgV_9sRGU=˟OC-ZSNؔh& FR~Wa6N Z_(\-bv^U3ȃQVCh(#sF=_eTyM9'%Hf{BHG#Fh~Il9K p0Z"cX.T柀!ihRf蘄2裐ss(KUJ#{Z:*jW*Ya*+X걇ޓ|r{Tv*c:"5d&*F+퀶+sr%WN+nDzz*조.uk-:PUYo{.ˮ:(p+I :j_&*gtb e(+/$,4*c(7qh~,D}P6#J FG-TkƲʹUw`u!٭͚ʵp-tmx޸ 0n'7'>Wngw砇.褗n騧ꬷ.n,7/o'7G/Wog/o觯>p/og7 HL:_&H Z̠7wGH(L W\f8Cpr4 Gw?H"n&:PH*ZX̢C0\C#6ET"hA:x̣> /fԡ!)HE6t$"C&Ғ8'9Lf2d( Cf2<%W JU6,gIKȥ.w^ 0Ib"QM~l"hN4V2\f5IrL:y$qe4#oNӜ&>MeV=9trLBІ:&-IъZ-&<Qsd& qL)5zord&%U:͎8ͩNwӞ@ PJԢHMRԦ:PTz[DrVRZr{!XQjԥD+Jir&}AVΔlG׾jn6q {XNbYZRv+R sg SU)E%`WֺwV(־w63mT"m K\ꖷ5m]8f'Q[RRnsgHY΀ek)ARzMz׫bu|8C4~{_֗o~L>mI;{ }_H5͐ .߇;1bw'Fq3>GU(_Lx-1@rgc"H@|d%7ML Xβ#KL2ga,f69c~sL 5yxF|+sπaQ2NF7z4%-HP:4 3miLw:ѐ޴GMFyШNWBߒgMZzu-k^׺fDHYضNk}jV;Ў6lc0ζn{MroNnϹ7Mzη~FwN;ݗZ;'N[n{6F8~7(OW0gr89kEn@ЇNHOҗt\P M/'9ַ{`N]gNxϻN~~p'y;񐏼'O[w<w{K)b&(b+9-b(8׎=gaUFePN&>dKf@IiJ e?9e7R93|gwtdFgqubgag\y{TlTjviivjt j&jxi&my:Clʦklökl4kV6FlIky3涚3nYy9Cp9C)o)89לW{{ICHsٝ)s}c3W{ uCt9t78JCFA47h7Zzfy])^]Y88/6ס X&* ǀEW؟UٕO+4jCy8:y*xEW($CJĬdl^nj ܘəY&Qc$Xu<2+\~굩|6y %FJTRyꢠʆԗH J9>^~?JF|eEW(:hVޥ~nTvnI^Nq~6>xJYf~^Q,NwVP /.wj3Yn DREn]=^ !֨ɟFGed?˸<$_aS L.0w(4z8:Oy3_>}B?Dz=H:Lo>Po=%T?OX=8\9}YƱ=)J}hG/lp m_Shzokom߅tۊ}ڒo,~ڢD_蚼|\+c5X[Eߚq~ ݍmܯ`܃D( Z:ON_x\Uݳ$Ep.Zm` ad  )R $PB փ#DI3>(pT"E$ ʔ,S$yL5męSN=}TPEETRM>5ęx\ UntVX=k6شiղ]V[hm{W/ܲ}HF (pɘ d d/YfΝ=ZhҥM*[W IlڵmcH;7wwp =o?bj 2x] -c,%OG^zݿϞZQ~7z/8p@3:$L? n>203O“Iy-0x矇>ݫ>{{?|'釥]zg*?~秿M ?Q`xπD`X4Ёts<M&ؔ JN" p'ZB|J cH0M71aH,sP`|lAtQDҨЅO ' *VQ w&!$S,8& Zp&)JXLjHTFɌh$q9P r]Fȇhs)RSau@e$KQfƣiHU:w9fͲzO TmZַTjjcJP83u*W¢xjbrS 3V[>P<4V24WJfiݸPgmMfmhFۊTlpX96ߛ,XT&RtU ڛUHiIMqi[+^Q.7sy2ԗgfmtiok)n"Q qg=v)pd|;L|\ S pe?PuA9SNslg$~\s 9fs=#e=iJ;4[EGY4~rgҧF.>RkuS=kZ;ok? kȺֿn\뚹t {v=mPz:fv3g 4=u_GnvUFw[~!/A/ƳUp?i8%0 8D Cg18$t']r(`*bQ6OW淺vٺݝw@e:O_^>uWv1@+uUm^eսL;_}F4Bզm u3Q+- jv%qxپ=uLy/|5ywI F}mMz]|wQOHGQ~?|ޫHXz֤\ctGu?wMTE?~Gտ~俬2-{[N?#*>>C@)W`t |@/鎃k*?2ܢtI)BA2)IJ !$B|+ǣ& ()*+,-.B*Tٹ s24T5d6t78C9 73; (=>?:A$^L"TDEtGBD;\@ DLOIQA{S,??UdU4; W X|EYETER+ƅ@8a4Ɓ F@cFd g$]ik m 0lNFj4Ǔ+ PuT pٸ y<`{G(sG}+ ȀHxb4dȆLj|Ȋ&&HȌȐ}Ȓ̶”TɔDalIHIGɗ\ɛ0I`+ `ʠʡ$Jğ{÷TY+ rqʧʨJd { & $J \`+1˳D˴T6ʄ @J, ˼˽K"d.i::ƀ&/9*LC T;4ܹ풣r̺\ʙ$4ӼT:œ%|B/b˵K{Mڥ?TTdwHܿ9*&MK'NƼ.$C;dt"=ғN/;O+fP:L,듽P%TPDOi ?Ok=:8|/Z3ѵ#Т;+E5)Rúl?2 30 d 9jK(2;:$LB5 T:;ɻDReTB%EkKLT IJEhQ%RNT(SVuWUCUUUJDP\]Y_ a%b5U`UVC@tghd]j4lmnCjpM9CM1sEtBpvMa=l {Avu}[U N@ׂ@}ׄVUSEUxXXWE؉ŋmXQ؏Wr}QS >fLa$%FgLYdTedY=UCJQBYnYFǸFoHJTs|GY3L| 8 PwG{ڳLC9вZΠKTx۫mtȼIH=HՏ9k[#N2 \J̫9͵ۣH+HH#\U]+QMWr%iҾ6Q - ߜ\)R*΅<JYIəlI^=΍ H-b#=O:+?$^x)u]ϓB0"MR5A'̾5u=4q-Tf/`PR c[Rv4Fì?_`B: ^t/2/| a!&"6b@,̵/AD<̨QL-.>bJM$263n#P) 06@AE0Ht:;cXi86 7[?c~, 4CFDFHIAXGd;D%OP.FRN)TVe1TZSveYZ[\]^_[ W&fueoEdVeV.h.7gVkf0-f,*pq&r6*tVgovvwg/@yzg4|V2~2paVcV2.s.gh(`芮 h'i% 6VVVivi(hh6Fcp^g,if7 jv{+PV1p꧆6n蘎5jfgfVh&krioixfkwfj뺶kjCd=t6l>kuiFihFɦ&ˮ켾MiTm9N6fsj΂ؖFj4hނm6{Yᆏcfi^fvfhܞٮn6痾k8m &~>A%ZZdcjuFinh^oNl5dz8[?["b@vo9îkskp,oo,iu&M+ ,Z\|\% _ߤܾ*LEJ$̱c!׹vݮjg(g6*r,qg [{?ܭM)ۼ>*6,_s;FfSr7j'xvjC1EgFw>ȃHIg, `W~uR{wb--?w1Pgy蘗ȶy#~~lnn i y8b!R]B,o__/k?kmm,烇jAjm.zS%^"Zm)wAܼb!b4%dx^W}zgvvhk&f|~XN%,Ҁ?M>T}l&v./vz~v~m&tn| :}H}h~cց~췁~ni_Fmwn/caago˿vt*,h[2!Ĉ'Rh"ƌ7r#Ȑ"G,i$ʔ*Wl%̘2I:xNn̙ Bn)j(`fi)RRE3*֫^rZ+Xeƒ,ڴjתIh̸rҭk.޼zoǚ{gn31sP̘p칳ПG.=kסWcQuRm6ܺwK & 䬱=jң?}]#ڷs;;Ɠ<!=|&?xPp? 8`]5XqTPs 6XYeUSVS6:vEG_r%hB F -"18cK.DNݲG|HמEYdwQyWޑG^U*!]hRp6PE-j5ey&i\6a>RX%}$(:$PXr:(dy)j), ٹ6Q`6*ƨoZ)+)9*xK2|=&%s[IYV6-Vn(%&퐵+{.kr(il֨bal/ d|2$ 0 3.K<1q[Xb*ǥE #&i + בּE2352@93=9w,H]0֣ղwc!iN>,fBvں߻G>7;ɟ[= ٷ~w/GK[cD"??|?z`@{ #d#}ǖY[_Z՜m}(A 0*Ta:P (="ow (!xD}5M1\ęF>2%3N~27,WpIJӾMqkwm[-f>3Ӭ5n~3,9ӹv3=~s;VІ>4E3ю^Fa 'fYRﶎM1ׄ0#Ц>5SUծ~5cn5s]׾5{LwnƆ XS/o+ms68Z>7ӭu~7=MZN5$KZ.;Qe6lUfϰ-38#gZOx1.u9J x['&&6QOopӼ69sg0薡σ.o86nju:@ Gi6[1cLh639.xVLwe387J>z3sp>;$mh }J6WW/zGǑ嗕x7ļٞ ՞?O< ˛Rv/< Vl')/?/?&׾}5HVi-c Kl0T`YH_1SqV^yEeMO'ٌ` rx-4[Ve~Ք6ޣT[aʓA)(S)!nL >!FzїzMz@rzfrv`|h L[x L]HYJ:* E1!n8&".Va  $ M"%^" P&T E"("F`1*odىCaڬT1b11=}?m](QO="2"11#>2.#3623@4.#4>B5Z4Nc3V5b7v3#fSuR{H bǼaPT<#%!=A^#@@#*A$B&AA BNC@CJBMD:$FJC*$G8`A@ ^W UF$0$M֤Mf Ya!$OO$PP%QP~$cIٍ<~ lW!UAϐIL$WvW^\N%YY%ZZ%[Z"o]<6e%_]^4T)V~%b&b#Ɓc>&dFdN&eVe^&fV&\QP_~fWH^i&j&hk&]ጐզm&nn&oos 'qq'r&r.'s6rnм݀&uzKIhGuw~gd g8a5-&zzp{'|Ƨ|'}֧}'~'trݥ_UTlwUurtBق5z]DN(V^(fn(g9!l蓐G;cǀ}wt':1֨(() : L]ViXeTEt(n)pfaқ)ƥjHJTYEa]YIRji֩ŗffqޑE*Vz])tUDœFz^*f"TSJH*F^'vL*I4 ƪ*~‘A$xjgfXtj&X:R.+6>+F͟^+f):TfX|++먄kUP)i*b,Az++FD],_h,]6W+ĮkJVn,:b},ȆiB g&SFNzG֬wN T[VMr9" -,FRk>-tW eEUb_eLLL؎m9Z<բgtKy*z^Ŝ,$cK0ߖDjDؒ- .)yN]@4,iXmB^n-* 1IGnG ᦮]X]۵.m S0U%^9`P)ccZVҜ#mo^y}oovQj$*T+UDlRq*2b.j0;E6#^[pi9h h+Z.۶/ _`Z(RB"S#1%p.")C_=q9z` ` 7qתҚ`fT@1fAx F,R &A? 69⥆!~!!! rבiRpE\w,% \2&_r, 8,.՟%/!'ɱ w-߲9 C$'b'n&P'^.3 !흔P R`X@,.$BBI-"1Q3q4s,2 .;Y2<{#=_#7f#=35fc7B?<7R.Vէf^, T$hHT J=;"?SG+&ձ?HսJdGv$CVERL״"@DfMk$MtBi+TQ`xV @$R/5S7S?R[@4p&iiRKj)K5Y%ZZuQלּey@]׵]5^^ux2$'4-vO.WmrY?6:[N6eWeL$ID h6ii6jvx($lERcC6nlcf&ooef9șF \ XVwQ'C+Ul'TTDm_Nvo7www7xp:'yy7s7esgXh{kq{$TĭEuONn-g~8ߧ[~deV*jgH%A {S]Zg*Kp(R`k@kJ3h68_V&~wi]8wi)x8\Ae X hwMJk3qj2Y`xy)I)7ibW<l!T%T9B~sعz%8Bl"X#!)BS䮗흘+4 h$*x&DB+ª&X!!(T%)Aj.h _:"/;7{&(RPxB+$(+x:,B6؁!,$h#dF;kflo*Z' (<l,#x/A ȧfzIHM˿<ǼCx߼ 7(rtgV(!*@z,<d2 ‚d)m 8ث羢ٟo#Il;~F, &:DEO` L,AjJeb,v'\/z>>ڂ Q@P'^EB)8vĬP@DOt07VRxyb+׵1.2ᄏApj8YuTx'ȁTguh<LAkLjpmW߾פjLv_]Dv:wX@D@| 7;@ 5`XF%L!C>81fpŎA 9VI'QTeK/aƔ9fM7qԹgO?zd&UiCLF:jU%z0C[PTQ[L[mĕN]u՛^6(r"f)n-Ωw"͸LR%l',(`+J KV/K.R5|qb/޻ |-5?@CA=084CAԋAs b0tM =lNˍQI2P-COP5!8EYiE;QW ahGX_5F],(mgVڟhSVmel6qMowtm]l݄5=9#ˬ-S }ݷX|(H8#N%"@=*0c9<ҫb60uU=0OWCJJhfJn17c%vHsrQ]nin駡j%Z뫝ʚ!$;n[xeNNd,KUoUW;UB/,Pa (P Xh BDFۏN;m4去F`]Frhd{\u^y1褋O^~hL^g譯>?/^﫺̏~u4~=a *@ @h@| %J 8Ar̈Htaݛ\A%Dtw`W&3GHҖC=I2 q )$L\b&:QDi8^eZ'1n~i =*R 0 X ŌAPd)!Oz[ٝƘH|P^֪#!:pw T(,L^Ғ8 CQ!2Gt*Ȓ|-o9KZҖ/}JajU*T T)A% 9 A M4qH)HQC MXƖ! Oya#|M4xףOy4A(rPC!Q>GeHDXtmF/ҍ^t%(1ce-]!QE1>0(4HaYNъM8ECcZ:CURMU4*]WX*e5YњVmuZQ*7c,cN!t>KPA @(<ŌFS!3s:CM0Yb6g5U-Cծuka[ΖZ'ToS`Z0Ƞy*,cAIURY8^["ʝwTӎE(j^u{_=&E}o/" @pԥ@%PT8Bt]Xj76Aʆn%6Qb-vacϘ5qc=^vf!E6򑑜d%/IonA4C)hAzHL9 bHE+Jm0Sʀ+FˆuΪyg=/(\hAЅ6]'<䛗7RM @B8D%@ O⏨%p2Ug ͌slgYϚֵqk]׽.Nla6le{t"|F4e*Oڥ)#% ITbS5(iqC Q+Or-wanCޢSZD0X ALcDoL|Z `7Hb_X69b\gկwW]w5g.'t ,w}Oշ}o~7џ~wů>}ԩ <5h)A ,LlR/%p)-e0n/>fdC@*B<@V DB0/q0upy2}5l? Z44a`a`@PB Vz 0 p ɰ.VC6ce@j P&A  6P dpDN-l 1~0~B3Bϱ0 B@6Ex`D qUqY]ѻы6~h>PnS` @,B鰐i"_1qQc,Qjт<1r ` d`` x@XqH`@6%dHf.q.H.qўn#w͟ 1!r!n-(T:e/**Pn#I$h`SNQg4! 'r'y'_!_2(pkA8B@NT \*2D hSFo&Uh#\HbRhv&8--yE'2/2}m``f08SZ@f p&K%p_RF2hr!~ivibFWtd,95]5{!.=DA.D 1`joVR$\h3-.{3wH 7,S5Gs,_o;;:bʼH(21 ~P, 766cʨL< کS3,=94r:&.uA"$tB)B-B14C5tC9C'T,&obJOӱ0VmP1NDN:,J@:StB64I@ H4Jm`JJ ~`N77!d8G*ALBZCrT: ;SG?H-wH4;iIO8tP&PKO&,6C2nR)R'5 D%ڴ|3WAIXZ-TxT.:4VeUVJD4>6 NXY+ `SNZjD%C'.Z3B[g['kh"\." 4PLAm^^A `S3B #ۂZ}[[a TaaÕL'q 9FpV``Sv`p eUveUdw?L~~`fmf /bnhPPEQk$@BF@_9 ^@L@Sa#@P|fqj6k]Ng5pDH*s`>bڠFe]mǖ0y~@m ˰H`+ AHk7p7帶Nf4H Sc&` !<_̳_  fbKj7tEwtApLi3@ AZuO"RetIwwywmttc U .yD d` P?Pw}{{m 5LGWTOHl0@ }{?TgfV^h8x 8xXǪ!ĸKlNTId2 s "`&AoӴ|I` D;a8exsj|p8uxy}8zxQOPx0K`&_2JX@z`S<ѷ]SMmȸ88k8<^꤮R#N@"*R6 6ń> YwD!l](-195Y[ژ,@${r  F$7ҀZyb@-P]M7|*9lM9yK:*t0DrOR ,d@ڑT 8PP'F ذ9y{Ȇ9y7ixc`4)ӹP$gSeHKѷ5z9il*@:EzI*9׋qBT VF>$D8H? 2z:IlNZKw ,(@D੟?.d~ԧ̪ K*Z)zR,/D~zXxs-6e c2?z_Ze:%{Yž<2;;6=<&?!ϥCd$Qz+W[;> xM-Țu{)DLGeS5Ĉ B FX/ .a:Ќ>X rz7ye\\۾{99ygp6sORJxV`P*Ra^2X-.QmxYllemZƱFC /xOk A *cD`@ @R- S;ŵ|˿؆ç!g|'{\zp|yG䃼xKxa 8qOt1k0˹<;mkFhґ%1u="RD| ZV @@ >,>ăhyTI}؉Zf!hIcuء7m;L0BO*@!>y B%,Yu=|]lؤ}M4ʣ~~ }{=D<S-@ R)`ݧ`-/_u=U>l\a>efwfT a* ` B# h =+ V7P~kk빾gw><C :o,@\`^`r",@ˀ2g=1N걾 xl_ĞL`@$6`((#>-?`Ć-ɿKKk:b>@`>N>Lxl * +[9͜;{ :tg>:լ[~ ;v1RU+_тJX~/EB@2$x%B!HөJokַǷmS,:ۻ?|?`(yqVXIA 1DwAO@&r B SA!QؠbIH^AGc6ވc:^}dBIdFdJ.$2ކnJ$xVn1XZzTR%q1arX ,)=47#zg~ z>: Yh.Ve`UQ*- xnZV$~B*!h2*/~*1֖gފk砍 l hdF6n^ em mn)W\Zjjr,&r)1Hn"a;+Joދo0:l lI씷00Ÿ&0u"@R% "ǥ{.2Kr;*r./2L*+傖+V tj 4\Bsږx^krROMuՖLsZ$Q}0%̈́" 0pVppNzw}cuj3d8`ό1[< @`-\B9ww袏N:C1{V>4wqh|aHxM{ZW"瓕|/?II:{UΕ&Pg ~Cq1>&4 >95X#`׵`h{J9R9N!Md낐>A$, OHjMRz ☵فeZ$ qD,p ܃U"':QyCE0k, FBZS+qjtF)qt$#q Mxa,$X9YhbE,Jrk&/RoXFT!OT d0iYIl@Zrl/ `¡$"Yd*s̺IMvRdD+ՖirT7I c 49iN3 : xSsT#1!yV?qLAP '[Jk`Jш:ZSr C%&ѐv#d8s,mi{ 4}n ;: ԠsD-6)U}Em hATBRT2] ְ20XЙI8 N LNpV5GBjh-,EH)Q ]W J%e=ek.kq1lT)ҎhcW *=cVǛmo[T$mQZ-qS z(4BzЂ1 OLbE [k7eSI$%iq+p2Ttk Dha z)4QMtm+)z/e׽/\0-1]7@' 4Q-LS C聼eeqyxmIn2f%4uB2,c<Mu 5Xx0!ֳ%%X&ytߒ\='/TgQw 9b5/@ (,6VȔ֥0}9Lkzӛs? jϨsp%.qG,XKÉ(,/8赯{`;+v=d+ےm hK c^zp(n\ndҠF%+ʂe{*Դ|7){T4%V#V *= /*ZV5jRߧ>q 5~aaYU<q5xbD/zkL@C:7mssՆ2x|+ؕv X 8.5TZVY[lE}k5N k 4*aqFt@GT -!JDmtZeTinp4h'[IB1-h jF 80 r^AԒjD0O7*I2{6e'F PWtJrDtfWHlĎ6 PkT#ٛ"1pAN  oPyЉ"J0 z=ViR8u{2'S:v(DՂrh0 r w>6JAr0 &[ m0cWb8sɏ ؛r)-"Bv A]30HdtD4H<ɻ[/ͻ󋏾c؅a {U  PU") Dz ` "/GpP k{ȩFDO+ڂHP臾®(Mۑx\]G2 @Vr6D X0^^-+MWHY@%;B#Lšh5/hVӉgT Dq.A!dR(P tFUU 8W_|:y SªAs6$% g3n U_h@bJ"WSȭ<5WŪ3^܏dte `e ɬA ` sPi&`A~J(2,Lty0s2AHe~eAH )p P H T\ TU? 1,};V~By1|zr0b8XZp "EH!=p pi"E ;#,o UDi`~@XJ!eW~%Ѣ<բ \, %l1-qL@s[6N!n4CjR܄]׀|h~j![-)fBf W!jtgwݼ}ٽws,2|}$/Pq" ~JO SZٙHwכ\I"0+@E1i !,"Q3 G"GCZU:>.[MٰSz/ &P Pw9Z'zK'd}!# x0@@c.b%'BJeXݳn3aoP+n$XX)Ѣ)x 9 l y\G-ʙ}MQ` RppWruJOT P 4"-%q4-x0t7 PKZ@8 dw10H߲jnX7D8]"r?Au7Tpt+P d OpJ,D"r@zY֧vN,ќSc 3*4l P$L{i` n fBBT}.^~  B %#GlB0 W9nQ+N~δCN+?UB2VU!td`DWCH >c> Ƿ݁D|G(@LW+p{h8%&0Pۄd 0 dOgJC]]_|ǎ+$>2Tp&G-k*GO" pOF E>G GhBH@^֟x>Jc1nEL2`&/`-P!`y 0%f p b Jb2ɯ6o Tin#ڨA x @LZ P YDf ??X?@UHI+ $H[ á>|pKEn4n F5eDSr.daْ!/VQsD 9O=`"Q'J*5*QNZjŅ WaŎ%[Yiծe[qΥ[]y,W >8 ˆ*VxO~l8rcÖ!‚y@ptŪOUuk0vGhtIc NfT|/gf2 O54h\nwŏ'_zL_\}>@B34ȣ9TpA;cB kpA+2p y+ĕV DRb5[B6c:E;rqG{G /Ͼï2cO,',@KxDj f,|b)8l*:W4!c>@4>  DebQF*!+RL3tSNw,2#[J&׫?*Ke PK,[1)a~΋N̐Q`iEO/ѫnjN[pw\O]sIUWclT⥯VUYEklD0P 6)0 - `> O9,AU*!:;8h X"LYUnuecyo?=?ͪ|ԝe]PY*+ c Q/ )h#/bk{OYRz`Qj0qu϶n{o粙h|zk<-ޗŦg[U ?12\c ?&dTV997]6h691z `K M$%QAn )oJhFS͜tMlfSf7MpITt$բG)` @@=%@ `OI<v"KsL+RS e ?J~V%"gЧQZ$@@jl+  pdt$^Q6T;Qo ADxTEJ`pBUlp?$FP&k!iOzVAeZ k[e7׳18<(0 pj_dMцLke-{L [*r%6` ^Z0aR+^GȺmo}{rVlEItZӑ ʂHnKx2irA$v[Wz p;s-iq%;ajjSW^dFX^Ky{ɖjeDIvAִ!sJ!r*)%pMlb#]q7U>NPt/9ˆD$b6 aS[QBʿb,剝Xeq\*~d  !FȞ' z0E#IGBPs*) eD͖|h R AT† ̖^!@G RY#':*̨=YիV(A3Iu<TAh*FaE!hClTl=*8]2X}mlKկfksxc*h ö• X@TQ99"v:7mzSavDHȃ %jkFt]$z'xmD-8ǡ2<!D.hly|H5G{$7@x0רt=/\Cy|kgHBHknB );h-K(=h|1LIƒśl -=A#IOTHё8*H ʭxJ8JHJjJ-hE4Q LP$ڹR*XHܖ3K !+;;!q̌-KC완#6Ta!jhLʴ% N 0dNN6N7N(Md2l13zINQ 0*|#9OˬM P~OMgq6X_,/Nh9:KO0PP7LO=Q8p"SP RQ>O<2P M<߀'MhS`42#3+؉P R?Ҫ4P:#S:c Y0M/xᨳ*R6yFtH0 S,<< MT6xЄM GIPhM>e) ݈)QA՞"ԉƷa ES^ GO J=T $$Ua OH뒚 ,g6д9h O]:Nd_MVs,S3?\ lyWy\)Ђ4H)h8ҍ+^=X..Q=WUtu5[TЬP8"`dA&XWN섃9X؆Cz[!!hg+z `) O+lڦ]!U'Q; Y"DTVވY8 *#pD}Xb E̕`Zem›)2/ N90U%5 ?O@-\նb5V!SِMRC * B 14e\h \T:"[rN\: @MT?KHޒX]eHR8"W߈/eHr^u?e*uVUs\ JXgٸmԤ}_֛EMׄ,ވ۱`N脠uwN`6=CEI0 bZ' D(S@4aJh C->a&v<],&@ hYpU /4//#x%pi%nb6'&[ٚu XD+X 5#kK5ncF7:1QM͐039u[+=vEndUGm^8kVi (e`4ХJbIUN ie[:AQi'XDHO_'?lS^O2`/Ufsf6gN3]U=] CЃ ]yg=p1/,2d>gFt~Hޡ,DXzp%HvhsR~gN]yU} X@Y RdSlF0茮i@#]1L p\ 䄁%SUH>i 2)d0 |c0 PT+LhGꪞkj[CV蜐 ( xS/80fH^ C5klh֝vD$JH%44`kai Glˮmk#ݥC0ԁ"|8XD ^lm~8dՀ=a(p/M ȣRm_pv(V1#KOJp?ި63*6 ro j,dM1<0 H(Tg12-~]\6Cqp 'O#i(D(6@!l4pI6[Cإ0m+,/-L9T z˴ spEXW=զX#h ;hߊՐ,h0?@ADơyEV2' D67CUoSH-Qu.u2HdJESRiPK B؄J󉗖Ab7vFvX;u}AT Eժ.'W4OΟgDS5j]+[W&rbT?q$/qj%B2Yj"6],c]Wte-=WIqWI=&ABakӢ6]-[V[^A̱]ܤlUǖ,-kk"wf4\. _\t}ukb7ڵkHsի3, +ygU8 \/q76&k7/t }l#X&p.sB؜QA9q6ä qW"1;N8*^1[82̒8:qm\- /r-vԼB2 BY !.1leZ2/9b3ej^3fb ֜IgS3L?_\~-2+#:ъTGC:Ғ4+mKc:ӐF4Oonp3dݥ8%X' ֲ5jm[Z֣_|@wE;F^ac#;^6gC;@mkc٣Ni-?#z?@Män>6mA7<8 oj _8m +zXa]v5Sug=cuMb :U7[r 29kn<:9{Ns{;a=7&:w]=~߲Wxip&g0>bQ]>-9o`;s?w>µolW{O%Ӌ#_1q_)WڣEI`ZV^`F`rns~Z z`,P9ӅXSu4E KaXٖi6a2!>aF!J!:anqa^!R:O!4)\,Ƈ \YU`^%b ݊!."vBX"B#6$&$Jb!a!2"%."^b%b⛭yET V`A Hl .U%X}~#00c1c2b02#23"}9)}Y5N)D4 ,) I9"/;P#?֣?c@@$A#@B#1C&?BNdEBE 4>Ű,Gj yDpKQ;cKd" #LdM#]ML.!OM$NPNM"M"\R2%OOOLeS&eFzȩq$^$GVqKZ([e\\e]]e^e\"^_f]b%*a*hEX]Y6]hŎh,&%[bffBgzgfhhfiig"\jfkh&QXN^emqHfdYՠdV&\fgqAr*r2gs:sBgtJtRr"\ubgvjsƦ8U^WHFɷ`4JyQ&ZRqg|nfg}}g~~g'hgw!Yg1RFrS |Zrhz臂h舒hh"܉芲hv$(8ҕ#yNbi i"i*2i:)ARi*)ń6LhVyd{iL @隲iii)i)mqdDTıi:AJRjZbjjr"\ji)g{-ffScע>jj=Ws٪ xzމWFA_NJ22k"SX&7z[LR>UkjzLkʝeIrpk|.ԽkA-+ky +u"l*. B,DRlZbljrlzǂlȊȒlɚɢlʪʲl˺lllN,Țm m"m*2m~l,,z8mZvbmjrmzׂBmjF)ٮ-ڲmۺmmmmn n"n*"2n>nJRnZbnjrnz炮:;proguard4.8/docs/style.css0000644000175000017500000000475411517071111014370 0ustar ericeric @charset "iso-8859-1"; /* Global settings. */ body { background: #FFFFFF; } h1 { text-align: center; } h2 { text-align: center; } h3 { background: #EEEEFF; padding: 10px; } h3 div { font-weight: normal; font-size: 80%; float: right; } table { width: 100%; } th { padding: 4px; } tr.disappeared td { background: #EEEEEE; } td { background: #EEEEFF; padding: 8px; } ul.spacious li { padding: 8px; } a { text-decoration: none; } img { border: none; } a.button { color: #000000; text-decoration: none; background: #E0E0E0; border: 1px outset #FFFFFF; float: right; } /* Settings for the introductory paragraph. */ p.intro { background: #EEEEFF; padding: 10px; border: 1px solid #000000; } /* Settings for the title frame. */ body.title { margin: 0px; padding: 0px; background: #C0C0C0; } div.title { height: 48px; margin: 0px; padding: 0px; border-width: 1px; border-style: solid; border-color: #FFFFFF #808080 #808080 #FFFFFF; background: url("steel.gif"); } div.title h1 { margin: 0px; padding: 0px; padding-top: 8px; padding-left: 40%; float: left; } div.title div { margin: 0px; padding: 0px; padding-top: 12px; padding-right: 20px; float: right; } /* Settings for the section frames. */ body.navigation { margin: 0px; padding: 0px; } ul.navigation { margin: 0px; padding: 0px; list-style: none; text-align: center; background: url("steel.gif"); } ul.navigation li { margin: 0px; padding: 0px; border-width: 1px; border-style: solid; border-color: #FFFFFF #808080 #808080 #FFFFFF; color: #000000; font-weight: bold; } ul.navigation li.title { margin: 0px; padding: 4px 10px; background: #E0E0E0; } ul.navigation li a { margin: 0px; padding: 6px 0px; background: transparent; color: #000000; text-decoration: none; display: block; } ul.navigation li a:hover, ul.navigation li a:focus { background: #FFFFFF; } /* Settings for the yellow note tables. */ table.note { width: 408px; border: none; border-spacing: 0px; } td.shadow8 { width: 8px; padding: 0px; margin: 0px; vertical-align: bottom; background: transparent; } td.shadow400 { width: 400px; padding: 0px; margin: 0px; text-align: right; background: transparent; } td.note { width: 380px; background: #FFFFC0; padding: 0px; margin: 0px; } p.note { padding: 0px; margin: 0px 10px; text-align: center; } p.author { padding: 0px; margin: 0px 10px; text-align: right; } proguard4.8/docs/manual/0000775000175000017500000000000011760503005013765 5ustar ericericproguard4.8/docs/manual/ant.html0000644000175000017500000006456411760416705015464 0ustar ericeric Ant Task

Ant Task

ProGuard can be run as a task in the Java-based build tool Ant (version 1.6.0 or higher).

Before you can use the proguard task, you have to tell Ant about this new task. The easiest way is to add the following line to your build.xml file:

<taskdef resource="proguard/ant/task.properties"
         classpath="/usr/local/java/proguard/lib/proguard.jar" />

Please make sure the class path is set correctly for your system.

There are three ways to configure the ProGuard task: using an external configuration file, using embedded ProGuard configuration options, or using the equivalent XML configuration tags. These three ways can be combined, depending on practical circumstances and personal preference.

1. An external ProGuard configuration file

The simplest way to use the ProGuard task in an Ant build file is to keep your ProGuard configuration file, and include it from Ant. You can include your ProGuard configuration file by setting the configuration attribute of your proguard task. Your ant build file will then look like this:

<taskdef resource="proguard/ant/task.properties"
         classpath="/usr/local/java/proguard/lib/proguard.jar" />
<proguard configuration="myconfigfile.pro"/>

This is a convenient option if you prefer ProGuard's configuration style over XML, if you want to keep your build file small, or if you have to share your configuration with developers who don't use Ant.

2. Embedded ProGuard configuration options

Instead of keeping an external ProGuard configuration file, you can also copy the contents of the file into the nested text of the proguard task (the PCDATA area). Your Ant build file will then look like this:

<taskdef resource="proguard/ant/task.properties"
         classpath="/usr/local/java/proguard/lib/proguard.jar" />
<proguard>
  -libraryjars ${java.home}/lib/rt.jar
  -injars      in.jar
  -outjars     out.jar

  -keepclasseswithmembers public class * {
      public static void main(java.lang.String[]);
  }
</proguard>

Some minor syntactical changes are required in order to conform with the XML standard.

Firstly, the # character cannot be used for comments in an XML file. Comments must be enclosed by an opening <!-- and a closing -->. All occurrences of the # character can be removed.

Secondly, the use of < and > characters would upset the structure of the XML build file. Environment variables can be specified with the usual Ant style ${...}, instead of the ProGuard style <...>. Other occurrences of < and > have to be encoded as &lt; and &gt; respectively.

3. XML configuration tags

If you really prefer a full-blown XML configuration, you can replace the ProGuard configuration options by XML configuration tags. The resulting configuration will be equivalent, but much more verbose and difficult to read, as XML goes. The remainder of this page presents the supported tags. For a more extensive discussion of their meaning, please consult the traditional Usage section. You can find some sample configuration files in the examples/ant directory of the ProGuard distribution.

Task Attributes and Nested Elements

The <proguard> task and the <proguardconfiguration> task can have the following attributes (only for <proguard>) and nested elements:
configuration = "filename"
Read and merge options from the given ProGuard-style configuration file. Note: for reading multiple configuration files or XML-style configurations, use the configuration element.
skipnonpubliclibraryclasses = "boolean" (default = false)
Ignore non-public library classes.
skipnonpubliclibraryclassmembers = "boolean" (default = true)
Ignore package visible library class members.
target = "version" (default = none)
Set the given version number in the processed classes.
forceprocessing = "boolean" (default = false)
Process the input, even if the output seems up to date.
printseeds = "boolean or filename" (default = false)
List classes and class members matched by the various keep commands, to the standard output or to the given file.
shrink = "boolean" (default = true)
Shrink the input class files.
printusage = "boolean or filename" (default = false)
List dead code of the input class files, to the standard output or to the given file.
optimize = "boolean" (default = true)
Optimize the input class files.
optimizationpasses = "n" (default = 1)
The number of optimization passes to be performed.
allowaccessmodification = "boolean" (default = false)
Allow the access modifiers of classes and class members to be modified, while optimizing.
mergeinterfacesaggressively = "boolean" (default = false)
Allow any interfaces to be merged, while optimizing.
obfuscate = "boolean" (default = true)
Obfuscate the input class files.
printmapping = "boolean or filename" (default = false)
Print the mapping from old names to new names for classes and class members that have been renamed, to the standard output or to the given file.
applymapping = "filename" (default = none)
Reuse the given mapping, for incremental obfuscation.
obfuscationdictionary = "filename" (default = none)
Use the words in the given text file as obfuscated field names and method names.
classobfuscationdictionary = "filename" (default = none)
Use the words in the given text file as obfuscated class names.
packageobfuscationdictionary = "filename" (default = none)
Use the words in the given text file as obfuscated package names.
overloadaggressively = "boolean" (default = false)
Apply aggressive overloading while obfuscating.
useuniqueclassmembernames = "boolean" (default = false)
Ensure uniform obfuscated class member names for subsequent incremental obfuscation.
usemixedcaseclassnames = "boolean" (default = true)
Generate mixed-case class names while obfuscating.
flattenpackagehierarchy = "package_name" (default = none)
Repackage all packages that are renamed into the single given parent package.
repackageclasses = "package_name" (default = none)
Repackage all class files that are renamed into the single given package.
keepparameternames = "boolean" (default = false)
Keep the parameter names and types of methods that are kept.
renamesourcefileattribute = "string" (default = none)
Put the given constant string in the SourceFile attributes.
preverify = "boolean" (default = true)
Preverify the processed class files if they are targeted at Java Micro Edition or at Java 6 or higher.
microedition = "boolean" (default = false)
Target the processed class files at Java Micro Edition.
verbose = "boolean" (default = false)
Write out some more information during processing.
note = "boolean" (default = true)
Print notes about potential mistakes or omissions in the configuration. Use the nested element dontnote for more fine-grained control.
warn = "boolean" (default = true)
Print warnings about unresolved references. Use the nested element dontwarn for more fine-grained control. Only use this option if you know what you're doing!
ignorewarnings = "boolean" (default = false)
Print warnings about unresolved references, but continue processing anyhow. Only use this option if you know what you're doing!
printconfiguration = "boolean or filename" (default = false)
Write out the entire configuration in traditional ProGuard style, to the standard output or to the given file. Useful to replace unreadable XML configurations.
dump = "boolean or filename" (default = false)
Write out the internal structure of the processed class files, to the standard output or to the given file.
<injar class_path />
Specifies the program jars (or wars, ears, zips, or directories).
<outjar class_path />
Specifies the names of the output jars (or wars, ears, zips, or directories).
<libraryjar class_path />
Specifies the library jars (or wars, ears, zips, or directories).
<keepdirectory name = "directory_name" />
<keepdirectories filter = "directory_filter" />
Keep the specified directories in the output jars (or wars, ears, zips, or directories).
<keep modifiers class_specification > class_member_specifications </keep>
Preserve the specified classes and class members.
<keepclassmembers modifiers class_specification > class_member_specifications </keepclassmembers>
Preserve the specified class members, if their classes are preserved as well.
<keepclasseswithmembers modifiers class_specification > class_member_specifications </keepclasseswithmembers>
Preserve the specified classes and class members, if all of the specified class members are present.
<keepnames class_specification > class_member_specifications </keepnames>
Preserve the names of the specified classes and class members (if they aren't removed in the shrinking step).
<keepclassmembernames class_specification > class_member_specifications </keepclassmembernames>
Preserve the names of the specified class members (if they aren't removed in the shrinking step).
<keepclasseswithmembernames class_specification > class_member_specifications </keepclasseswithmembernames>
Preserve the names of the specified classes and class members, if all of the specified class members are present (after the shrinking step).
<whyareyoukeeping class_specification > class_member_specifications </whyareyoukeeping>
Print details on why the given classes and class members are being kept in the shrinking step.
<assumenosideeffects class_specification > class_member_specifications </assumenosideeffects>
Assume that the specified methods don't have any side effects, while optimizing. Only use this option if you know what you're doing!
<optimization name = "optimization_name" />
<optimizations filter = ""optimization_filter" />
Perform only the specified optimizations.
<keeppackagename name = "package_name" />
<keeppackagenames filter = "package_filter" />
Keep the specified package names from being obfuscated. If no name is given, all package names are preserved.
<keepattribute name = "attribute_name" />
<keepattributes filter = "attribute_filter" />
Preserve the specified optional Java bytecode attributes, with optional wildcards. If no name is given, all attributes are preserved.
<adaptclassstrings filter = "class_filter" />
Adapt string constants in the specified classes, based on the obfuscated names of any corresponding classes.
<adaptresourcefilenames filter = "file_filter" />
Rename the specified resource files, based on the obfuscated names of the corresponding class files.
<adaptresourcefilecontents filter = "file_filter" />
Update the contents of the specified resource files, based on the obfuscated names of the processed classes.
<dontnote filter = "class_filter" />
Don't print notes about classes matching the specified class name filter.
<dontwarn filter = "class_filter" />
Don't print warnings about classes matching the specified class name filter. Only use this option if you know what you're doing!
<configuration refid = "ref_id" />
<configuration file = "name" />
The first form includes the XML-style configuration specified in a <proguardconfiguration> task (or <proguard> task) with attribute id = "ref_id". Only the nested elements of this configuration are considered, not the attributes.

The second form includes the ProGuard-style configuration from the specified file. The element is actually a fileset element and supports all of its attributes and nested elements, including multiple files.

Class Path Attributes and Nested Elements

The jar elements are path elements, so they can have any of the standard path attributes and nested elements. The most common attributes are:
path = "path"
The names of the jars (or wars, ears, zips, or directories), separated by the path separator.
location = "name" (or file = "name", or dir = "name", or name = "name")
Alternatively, the name of a single jar (or war, ear, zip, or directory).
refid = "ref_id"
Alternatively, a reference to the path or file set with the attribute id = "ref_id".
In addition, the jar elements can have ProGuard-style filter attributes:
filter = "file_filter"
An optional filter for all class file names and resource file names that are encountered.
jarfilter = "file_filter"
An optional filter for all jar names that are encountered.
warfilter = "file_filter"
An optional filter for all war names that are encountered.
earfilter = "file_filter"
An optional filter for all ear names that are encountered.
zipfilter = "file_filter"
An optional filter for all zip names that are encountered.

Keep Modifier Attributes

The keep tags can have the following modifier attributes:
allowshrinking = "boolean" (default = false)
Specifies whether the entry points specified in the keep tag may be shrunk.
allowoptimization = "boolean" (default = false)
Specifies whether the entry points specified in the keep tag may be optimized.
allowobfuscation = "boolean" (default = false)
Specifies whether the entry points specified in the keep tag may be obfuscated.

Class Specification Attributes and Nested Elements

The keep tags can have the following class_specification attributes and class_member_specifications nested elements:
access = "access_modifiers"
The optional access modifiers of the class. Any space-separated list of "public", "final", and "abstract", with optional negators "!".
annotation = "annotation_name"
The optional fully qualified name of an annotation of the class, with optional wildcards.
type = "type"
The optional type of the class: one of "class", "interface", or "!interface".
name = "class_name"
The optional fully qualified name of the class, with optional wildcards.
extendsannotation = "annotation_name"
The optional fully qualified name of an annotation of the the class that the specified classes must extend, with optional wildcards.
extends = "class_name"
The optional fully qualified name of the class the specified classes must extend, with optional wildcards.
implements = "class_name"
The optional fully qualified name of the class the specified classes must implement, with optional wildcards.
<field class_member_specification />
Specifies a field.
<method class_member_specification />
Specifies a method.
<constructor class_member_specification />
Specifies a constructor.

Class Member Specification Attributes

The class member tags can have the following class_member_specification attributes:
access = "access_modifiers"
The optional access modifiers of the class. Any space-separated list of "public", "protected", "private", "static", etc., with optional negators "!".
annotation = "annotation_name"
The optional fully qualified name of an annotation of the class member, with optional wildcards.
type = "type"
The optional fully qualified type of the class member, with optional wildcards. Not applicable for constructors, but required for methods for which the parameters attribute is specified.
name = "name"
The optional name of the class member, with optional wildcards. Not applicable for constructors.
parameters = "parameters"
The optional comma-separated list of fully qualified method parameters, with optional wildcards. Not applicable for fields, but required for constructors, and for methods for which the type attribute is specified.

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/examples.html0000644000175000017500000016146211757661223016516 0ustar ericeric ProGuard Examples

Examples

Some typical useful configurations:
  1. A typical application
  2. A typical applet
  3. A typical midlet
  4. A typical Java Card applet
  5. A typical xlet
  6. A simple Android activity
  7. A complete Android application
  8. A typical library
  9. All possible applications in the input jars
  10. All possible applets in the input jars
  11. All possible midlets in the input jars
  12. All possible Java Card applets in the input jars
  13. All possible xlets in the input jars
  14. All possible servlets in the input jars
  15. Scala applications with the Scala runtime
  16. Processing native methods
  17. Processing callback methods
  18. Processing enumeration classes
  19. Processing serializable classes
  20. Processing bean classes
  21. Processing annotations
  22. Processing database drivers
  23. Processing ComponentUI classes
  24. Processing RMI code
  25. Processing resource injection
  26. Processing resource files
  27. Processing manifest files
  28. Producing useful obfuscated stack traces
  29. Obfuscating package names
  30. Restructuring the output archives
  31. Filtering the input and the output
  32. Processing multiple applications at once
  33. Incremental obfuscation
  34. Preverifying class files for Java Micro Edition
  35. Upgrading class files to Java 6
  36. Finding dead code
  37. Printing out the internal structure of class files
  38. Using annotations to configure ProGuard
You can find some sample configuration files in the examples directory of the ProGuard distribution.

A typical application

To shrink, optimize, and obfuscate a simple Java application, you typically create a configuration file like myconfig.pro, which can be used with
bin/proguard @myconfig.pro

The configuration file specifies the input, the output, and the entry points of the application:

-injars       myapplication.jar
-outjars      myapplication_out.jar
-libraryjars  <java.home>/lib/rt.jar
-printmapping myapplication.map

-keep public class mypackage.MyMain {
    public static void main(java.lang.String[]);
}

Note the use of the <java.home> system property. ProGuard automatically replaces it when parsing the file.

The -keep option specifies the entry point of the application that has to be preserved. The access modifiers public and static are not really required in this case, since we know a priori that the specified class and method have the proper access flags. It just looks more familiar this way.

Note that all type names are fully specified: mypackage.MyMain and java.lang.String[].

We're writing out an obfuscation mapping file with -printmapping, for de-obfuscating any stack traces later on, or for incremental obfuscation of extensions.

We can further improve the results with a few additional options:

-optimizationpasses 3
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
These options are not required; they just shave off some extra bytes from the output jar, by performing up to 3 optimization passes, and by aggressively obfuscating class members and package names.

In general, you might need a few additional options for processing native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files.

A typical applet

These options shrink, optimize, and obfuscate the applet mypackage.MyApplet:
-injars      in.jar
-outjars     out.jar
-libraryjars <java.home>/lib/rt.jar

-keep public class mypackage.MyApplet

The typical applet methods will be preserved automatically, since mypackage.MyApplet is an extension of the Applet class in the library rt.jar.

If applicable, you should add options for processing native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files.

A typical midlet

These options shrink, optimize, obfuscate, and preverify the midlet mypackage.MyMIDlet:
-injars      in.jar
-outjars     out.jar
-libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar
-libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-microedition

-keep public class mypackage.MyMIDlet

Note how we're now targeting the Java Micro Edition run-time environment of midpapi20.jar and cldcapi11.jar, instead of the Java Standard Edition run-time environment rt.jar. You can target other JME environments by picking the appropriate jars.

The typical midlet methods will be preserved automatically, since mypackage.MyMIDlet is an extension of the MIDlet class in the library midpapi20.jar.

The -microedition option makes sure the class files are preverified for Java Micro Edition, producing compact StackMap attributes. It is no longer necessary to run an external preverifier.

Be careful if you do use the external preverify tool on a platform with a case-insensitive filing system, such as Windows. Because this tool unpacks your processed jars, you should then use ProGuard's -dontusemixedcaseclassnames option.

If applicable, you should add options for processing native methods and resource files.

Note that you will still have to adapt the midlet jar size in the corresponding jad file; ProGuard doesn't do that for you.

A typical Java Card applet

These options shrink, optimize, and obfuscate the Java Card applet mypackage.MyApplet:
-injars      in.jar
-outjars     out.jar
-libraryjars /usr/local/java/javacard2.2.2/lib/api.jar
-dontwarn    java.lang.Class
-overloadaggressively
-repackageclasses ''
-allowaccessmodification

-keep public class mypackage.MyApplet

The configuration is very similar to the configuration for midlets, except that it now targets the Java Card run-time environment. This environment doesn't have java.lang.Class, so we're telling ProGuard not to worry about it.

A typical xlet

These options shrink, optimize, and obfuscate the xlet mypackage.MyXlet:
-injars      in.jar
-outjars     out.jar
-libraryjars /usr/local/java/jtv1.1/javatv.jar
-libraryjars /usr/local/java/cdc1.1/lib/cdc.jar
-libraryjars /usr/local/java/cdc1.1/lib/btclasses.zip
-overloadaggressively
-repackageclasses ''
-allowaccessmodification

-keep public class mypackage.MyXlet

The configuration is very similar to the configuration for midlets, except that it now targets the CDC run-time environment with the Java TV API.

A simple Android activity

These options shrink, optimize, and obfuscate the single Android activity mypackage.MyActivity:
-injars      bin/classes
-outjars     bin/classes-processed.jar
-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar

-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic

-keep public class mypackage.MyActivity

We're targeting the Android run-time and keeping the activity as an entry point.

Preverification is irrelevant for the dex compiler and the Dalvik VM, so we can switch it off with the -dontpreverify option.

The -optimizations option disables some arithmetic simplifications that Dalvik 1.0 and 1.5 can't handle. Note that the Dalvik VM also can't handle aggressive overloading (of static fields).

If applicable, you should add options for processing native methods, callback methods, enumerations, annotations, and resource files.

A complete Android application

These options shrink, optimize, and obfuscate all public activities, services, broadcast receivers, and content providers from the compiled classes and external libraries:
-injars      bin/classes
-injars      libs
-outjars     bin/classes-processed.jar
-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar

-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic
-keepattributes *Annotation*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider

-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers class * extends android.content.Context {
   public void *(android.view.View);
   public void *(android.view.MenuItem);
}

-keepclassmembers class * implements android.os.Parcelable {
    static android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

Most importantly, we're keeping all fundamental classes that may be referenced by the AndroidManifest.xml file of the application. If your manifest file contains other classes and methods, you may have to specify those as well.

We're keeping annotations, since they might be used by custom RemoteViews.

We're keeping any custom View extensions and other classes with typical constructors, since they might be referenced from XML layout files.

We're also keeping possible onClick handlers in custom Context extensions, since they might be referenced from XML layout files.

We're also keeping the required static fields in Parcelable implementations, since they are accessed by introspection.

Finally, we're keeping the static fields of referenced inner classes of auto-generated R classes, just in case your code is accessing those fields by introspection. Note that the compiler already inlines primitive fields, so ProGuard can generally remove all these classes entirely anyway (because the classes are not referenced and therefore not required).

If you're using additional Google APIs, you'll have to specify those as well, for instance:

-libraryjars /usr/local/android-sdk/add-ons/google_apis-7_r01/libs/maps.jar

If you're using Google's optional License Verification Library, you can obfuscate its code along with your own code. You do have to preserve its ILicensingService interface for the library to work:

-keep public interface com.android.vending.licensing.ILicensingService

If you're using the Android Compatibility library, you should add the following line, to let ProGuard know it's ok that the library references some classes that are not available in all versions of the API:

-dontwarn android.support.**

If applicable, you should add options for processing native methods, callback methods, enumerations, and resource files. You may also want to add options for producing useful stack traces. You can find a complete sample configuration in examples/android.pro in the ProGuard distribution.

The Ant and Eclipse build processes of the Android SDK already integrate ProGuard by default, with all the proper settings. You only need to enable ProGuard (for release builds) by uncommenting the line "proguard.config=....." in the file project.properties (created or updated by Android SDK revision 17 or higher). In case of problems, you may want to check if the configuration files that are listed on this line (proguard-project.txt,...) contain the necessary settings for your application. Note that the build processes are already setting the necessary program jars, library jars, and output jars for you.

For more information, you can consult the official Developer Guide in the Android SDK.

A typical library

These options shrink, optimize, and obfuscate an entire library, keeping all public and protected classes and class members, native method names, and serialization code. The processed version of the library can then still be used as such, for developing code based on its public API.
-injars       in.jar
-outjars      out.jar
-libraryjars  <java.home>/lib/rt.jar
-printmapping out.map

-keepparameternames
-renamesourcefileattribute SourceFile
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
                SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

-keep public class * {
    public protected *;
}

-keepclassmembernames class * {
    java.lang.Class class$(java.lang.String);
    java.lang.Class class$(java.lang.String, boolean);
}

-keepclasseswithmembernames class * {
    native <methods>;
}

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

This configuration should preserve everything we'll ever want to access in the library. Only if there are any other non-public classes or methods that are invoked dynamically, they should be specified using additional -keep options.

The -keepclassmembernames option for the class$ methods is not strictly necessary. These methods are inserted by the javac compiler and the jikes compiler respectively, in JDK 1.2 and older, to implement the .class construct. ProGuard will automatically detect them and deal with them, even when their names have been obfuscated. However, other obfuscators may rely on the original method names. It may therefore be helpful to preserve them, in case these other obfuscators are ever used for further obfuscation of the library.

The "Exceptions" attribute has to be preserved, so the compiler knows which exceptions methods may throw.

The "InnerClasses" attribute (or more precisely, its source name part) has to be preserved too, for any inner classes that can be referenced from outside the library. The javac compiler would be unable to find the inner classes otherwise.

The "Signature" attribute is required to be able to access generic types when compiling in JDK 5.0 and higher.

The -keepparameternames option keeps the parameter names in the "LocalVariableTable" and "LocalVariableTypeTable" attributes of public library methods. Some IDEs can present these names to the developers who use the library.

Finally, we're keeping the "Deprecated" attribute and the attributes for producing useful stack traces.

We've also added some options for for processing native methods, enumerations, serializable classes, and annotations, which are all discussed in their respective examples.

All possible applications in the input jars

These options shrink, optimize, and obfuscate all public applications in in.jar:
-injars      in.jar
-outjars     out.jar
-libraryjars <java.home>/lib/rt.jar
-printseeds

-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}

Note the use of -keepclasseswithmembers. We don't want to preserve all classes, just all classes that have main methods, and those methods.

The -printseeds option prints out which classes exactly will be preserved, so we know for sure we're getting what we want.

If applicable, you should add options for processing native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files.

All possible applets in the input jars

These options shrink, optimize, and obfuscate all public applets in in.jar:
-injars      in.jar
-outjars     out.jar
-libraryjars <java.home>/lib/rt.jar
-printseeds

-keep public class * extends java.applet.Applet

We're simply keeping all classes that extend the Applet class.

Again, the -printseeds option prints out which applets exactly will be preserved.

If applicable, you should add options for processing native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files.

All possible midlets in the input jars

These options shrink, optimize, obfuscate, and preverify all public midlets in in.jar:
-injars      in.jar
-outjars     out.jar
-libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar
-libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-microedition
-printseeds

-keep public class * extends javax.microedition.midlet.MIDlet

We're simply keeping all classes that extend the MIDlet class.

The -microedition option makes sure the class files are preverified for Java Micro Edition, producing compact StackMap attributes. It is no longer necessary to run an external preverifier.

Be careful if you do use the external preverify tool on a platform with a case-insensitive filing system, such as Windows. Because this tool unpacks your processed jars, you should then use ProGuard's -dontusemixedcaseclassnames option.

The -printseeds option prints out which midlets exactly will be preserved.

If applicable, you should add options for processing native methods and resource files.

Note that you will still have to adapt the midlet jar size in the corresponding jad file; ProGuard doesn't do that for you.

All possible Java Card applets in the input jars

These options shrink, optimize, and obfuscate all public Java Card applets in in.jar:
-injars      in.jar
-outjars     out.jar
-libraryjars /usr/local/java/javacard2.2.2/lib/api.jar
-dontwarn    java.lang.Class
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-printseeds

-keep public class * implements javacard.framework.Applet

We're simply keeping all classes that implement the Applet interface.

The -printseeds option prints out which applets exactly will be preserved.

All possible xlets in the input jars

These options shrink, optimize, and obfuscate all public xlets in in.jar:
-injars      in.jar
-outjars     out.jar
-libraryjars /usr/local/java/jtv1.1/javatv.jar
-libraryjars /usr/local/java/cdc1.1/lib/cdc.jar
-libraryjars /usr/local/java/cdc1.1/lib/btclasses.zip
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-printseeds

-keep public class * implements javax.tv.xlet.Xlet

We're simply keeping all classes that implement the Xlet interface.

The -printseeds option prints out which xlets exactly will be preserved.

All possible servlets in the input jars

These options shrink, optimize, and obfuscate all public servlets in in.jar:
-injars      in.jar
-outjars     out.jar
-libraryjars <java.home>/lib/rt.jar
-libraryjars /usr/local/java/servlet/servlet.jar
-printseeds

-keep public class * implements javax.servlet.Servlet

Keeping all servlets is very similar to keeping all applets. The servlet API is not part of the standard run-time jar, so we're specifying it as a library. Don't forget to use the right path name.

We're then keeping all classes that implement the Servlet interface. We're using the implements keyword because it looks more familiar in this context, but it is equivalent to extends, as far as ProGuard is concerned.

The -printseeds option prints out which servlets exactly will be preserved.

If applicable, you should add options for processing native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files.

Scala applications with the Scala runtime

These options shrink, optimize, and obfuscate all public Scala applications in in.jar:
-injars      in.jar
-injars      /usr/local/java/scala-2.9.1/lib/scala-library.jar
-outjars     out.jar
-libraryjars <java.home>/lib/rt.jar

-dontwarn scala.**

-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}

-keep class * implements org.xml.sax.EntityResolver

-keepclassmembers class * {
    ** MODULE$;
}

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool {
    long eventCount;
    int  workerCounts;
    int  runControl;
    scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack;
    scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack;
}

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread {
    int base;
    int sp;
    int runState;
}

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask {
    int status;
}

-keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue {
    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head;
    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail;
    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe;
}

The configuration is essentially the same as for processing applications, because Scala is compiled to ordinary Java bytecode. However, the example processes the Scala runtime library as well. The processed jar can be an order of magnitude smaller and a few times faster than the original code (for the Scala code examples, for instance).

The -dontwarn option tells ProGuard not to complain about some artefacts in the Scala runtime, the way it is compiled by the scalac compiler (at least in Scala 2.9.1 and older). Note that this option should always be used with care.

The additional -keep options make sure that some classes and some fields that are accessed by means of introspection are not removed or renamed.

If applicable, you should add options for processing native methods, callback methods, enumerations, serializable classes, bean classes, annotations, and resource files.

Processing native methods

If your application, applet, servlet, library, etc., contains native methods, you'll want to preserve their names and their classes' names, so they can still be linked to the native library. The following additional option will ensure that:
-keepclasseswithmembernames class * {
    native <methods>;
}

Note the use of -keepclasseswithmembernames. We don't want to preserve all classes or all native methods; we just want to keep the relevant names from being obfuscated.

ProGuard doesn't look at your native code, so it won't automatically preserve the classes or class members that are invoked by the native code. These are entry points, which you'll have to specify explicitly. Callback methods are discussed below as a typical example.

Processing callback methods

If your application, applet, servlet, library, etc., contains callback methods, which are called from external code (native code, scripts,...), you'll want to preserve them, and probably their classes too. They are just entry points to your code, much like, say, the main method of an application. If they aren't preserved by other -keep options, something like the following option will keep the callback class and method:
-keep class mypackage.MyCallbackClass {
    void myCallbackMethod(java.lang.String);
}

This will preserve the given class and method from being removed or renamed.

Processing enumeration classes

If your application, applet, servlet, library, etc., contains enumeration classes, you'll have to preserve some special methods. Enumerations were introduced in Java 5. The java compiler translates enumerations into classes with a special structure. Notably, the classes contain implementations of some static methods that the run-time environment accesses by introspection (Isn't that just grand? Introspection is the self-modifying code of a new generation). You have to specify these explicitly, to make sure they aren't removed or obfuscated:
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

Processing serializable classes

More complex applications, applets, servlets, libraries, etc., may contain classes that are serialized. Depending on the way in which they are used, they may require special attention:
  • Often, serialization is simply a means of transporting data, without long-term storage. Classes that are shrunk and obfuscated should then continue to function fine with the following additional options:
    -keepclassmembers class * implements java.io.Serializable {
        private static final java.io.ObjectStreamField[] serialPersistentFields;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }
    

    The -keepclassmembers option makes sure that any serialization methods are kept. By using this option instead of the basic -keep option, we're not forcing preservation of all serializable classes, just preservation of the listed members of classes that are actually used.

  • Sometimes, the serialized data are stored, and read back later into newer versions of the serializable classes. One then has to take care the classes remain compatible with their unprocessed versions and with future processed versions. In such cases, the relevant classes will most likely have serialVersionUID fields. The following options should then be sufficient to ensure compatibility over time:
    -keepnames class * implements java.io.Serializable
    
    -keepclassmembers class * implements java.io.Serializable {
        static final long serialVersionUID;
        private static final java.io.ObjectStreamField[] serialPersistentFields;
        !static !transient <fields>;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }
    

    The serialVersionUID and serialPersistentFields lines makes sure those fields are preserved, if they are present. The <fields> line preserves all non-static, non-transient fields, with their original names. The introspection of the serialization process and the de-serialization process will then find consistent names.

  • Occasionally, the serialized data have to remain compatible, but the classes involved lack serialVersionUID fields. I imagine the original code will then be hard to maintain, since the serial version UID is then computed from a list of features the serializable class. Changing the class ever so slightly may change the computed serial version UID. The list of features is specified in the section on Stream Unique Identifiers of Sun's Java Object Serialization Specification. The following directives should at least partially ensure compatibility with the original classes:
    -keepnames class * implements java.io.Serializable
    
    -keepclassmembers class * implements java.io.Serializable {
        static final long serialVersionUID;
        private static final java.io.ObjectStreamField[] serialPersistentFields;
        !static !transient <fields>;
        !private <fields>;
        !private <methods>;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }
    

    The new options force preservation of the elements involved in the UID computation. In addition, the user will have to manually specify all interfaces of the serializable classes (using something like "-keep interface MyInterface"), since these names are also used when computing the UID. A fast but sub-optimal alternative would be simply keeping all interfaces with "-keep interface *".

Note that the above options may preserve more classes and class members than strictly necessary. For instance, a large number of classes may implement the Serialization interface, yet only a small number may actually ever be serialized. Knowing your application and tuning the configuration often produces more compact results.

Processing bean classes

If your application, applet, servlet, library, etc., makes extensive use of introspection on bean classes to find bean editor classes, or getter and setter methods, then configuration may become painful. There's not much else you can do than making sure the bean class names, or the getter and setter names don't change. For instance:
-keep public class mypackage.MyBean {
    public void setMyProperty(int);
    public int getMyProperty();
}

-keep public class mypackage.MyBeanEditor

If there are too many elements to list explicitly, wildcards in class names and method signatures might be helpful. This example should encompasses all possible setters and getters in classes in the package mybeans:

-keep class mybeans.** {
    void set*(***);
    void set*(int, ***);

    boolean is*(); 
    boolean is*(int);

    *** get*();
    *** get*(int);
}

The '***' wildcard matches any type (primitive or non-primitive, array or non-array). The methods with the 'int' arguments matches properties that are lists.

Processing annotations

If your application, applet, servlet, library, etc., uses annotations, you may want to preserve them in the processed output. Annotations are represented by attributes that have no direct effect on the execution of the code. However, their values can be retrieved through introspection, allowing developers to adapt the execution behavior accordingly. By default, ProGuard treats annotation attributes as optional, and removes them in the obfuscation step. If they are required, you'll have to specify this explicitly:
-keepattributes *Annotation*

For brevity, we're specifying a wildcarded attribute name, which will match RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations, RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations, and AnnotationDefault. Depending on the purpose of the processed code, you could refine this selection, for instance not keeping the run-time invisible annotations (which are only used at compile-time).

Some code may make further use of introspection to figure out the enclosing methods of anonymous inner classes. In that case, the corresponding attribute has to be preserved as well:

-keepattributes EnclosingMethod

Processing database drivers

Database drivers are implementations of the Driver interface. Since they are often created dynamically, you may want to preserve any implementations that you are processing as entry points:
-keep class * implements java.sql.Driver

This option also gets rid of the note that ProGuard prints out about (java.sql.Driver)Class.forName constructs, if you are instantiating a driver in your code (without necessarily implementing any drivers yourself).

Processing ComponentUI classes

Swing UI look and feels are implemented as extensions of the ComponentUI class. For some reason, these have to contain a static method createUI, which the Swing API invokes using introspection. You should therefore always preserve the method as an entry point, for instance like this:
-keep class * extends javax.swing.plaf.ComponentUI {
    public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent);
}

This option also keeps the classes themselves.

Processing RMI code

Reportedly, the easiest way to handle RMI code is to process the code with ProGuard first and then invoke the rmic tool. If that is not possible, you may want to try something like this:
-keepattributes Exceptions

-keep interface * extends java.rmi.Remote {
    <methods>;
}

-keep class * implements java.rmi.Remote {
    <init>(java.rmi.activation.ActivationID, java.rmi.MarshalledObject);
}

The first -keep option keeps all your Remote interfaces and their methods. The second one keeps all the implementations, along with their particular RMI constructors, if any.

The Exceptions attribute has to be kept too, because the RMI handling code performs introspection to check whether the method signatures are compatible.

Processing resource injection

If your application is using JEE-style resource injection, the application container will automatically assign instances of resource classes to fields and methods that are annotated with @Resource. The container applies introspection, even accessing private class members directly. It typically constructs a resource name based on the type name and the class member name. We then have to avoid that such class members are removed or renamed:
-keepclassmembers class * {
    @javax.annotation.Resource *;
}

The Spring framework has another similar annotation @Autowired:

-keepclassmembers class * {
    @org.springframework.beans.factory.annotation.Autowired *;
}

Processing resource files

If your application, applet, servlet, library, etc., contains resource files, it may be necessary to adapt their names and/or their contents when the application is obfuscated. The following two options can achieve this automatically:
-adaptresourcefilenames    **.properties,**.gif,**.jpg
-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF

The -adaptresourcefilenames option in this case renames properties files and image files in the processed output, based on the obfuscated names of their corresponding class files (if any). The -adaptresourcefilecontents option looks for class names in properties files and in the manifest file, and replaces these names by the obfuscated names (if any). You'll probably want to adapt the filters to suit your application.

Processing manifest files

As illustrated in the previous section, manifest files can be treated like ordinary resource files. ProGuard can adapt obfuscated class names in the files, but it won't make any other changes. If you want anything else, you should apply an external tool. For instance, if a manifest file contains signing information, you should sign the jar again after it has been processed.

If you're merging several input jars into a single output jar, you'll have to pick one, typically by specifying filters:

-injars  in1.jar
-injars  in2.jar(!META-INF/MANIFEST.MF)
-injars  in3.jar(!META-INF/MANIFEST.MF)
-outjars out.jar

The filters will let ProGuard copy the manifest file from the first jar and ignore any manifest files in the second and third input jars. Note that ProGuard will leave the order of the files in the jars unchanged; manifest files are not necessarily put first.

Producing useful obfuscated stack traces

These options let obfuscated applications or libraries produce stack traces that can still be deciphered later on:
-printmapping out.map

-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable

We're keeping all source file attributes, but we're replacing their values by the string "SourceFile". We could use any string. This string is already present in all class files, so it doesn't take up any extra space. If you're working with J++, you'll want to keep the "SourceDir" attribute as well.

We're also keeping the line number tables of all methods.

Whenever both of these attributes are present, the Java run-time environment will include line number information when printing out exception stack traces.

The information will only be useful if we can map the obfuscated names back to their original names, so we're saving the mapping to a file out.map. The information can then be used by the ReTrace tool to restore the original stack trace.

Obfuscating package names

Package names can be obfuscated in various ways, with increasing levels of obfuscation and compactness. For example, consider the following classes:
mycompany.myapplication.MyMain
mycompany.myapplication.Foo
mycompany.myapplication.Bar
mycompany.myapplication.extra.FirstExtra
mycompany.myapplication.extra.SecondExtra
mycompany.util.FirstUtil
mycompany.util.SecondUtil

Let's assume the class name mycompany.myapplication.MyMain is the main application class that is kept by the configuration. All other class names can be obfuscated.

By default, packages that contain classes that can't be renamed aren't renamed either, and the package hierarchy is preserved. This results in obfuscated class names like these:

mycompany.myapplication.MyMain
mycompany.myapplication.a
mycompany.myapplication.b
mycompany.myapplication.a.a
mycompany.myapplication.a.b
mycompany.a.a
mycompany.a.b

The -flattenpackagehierarchy option obfuscates the package names further, by flattening the package hierarchy of obfuscated packages:

-flattenpackagehierarchy 'myobfuscated'

The obfuscated class names then look as follows:

mycompany.myapplication.MyMain
mycompany.myapplication.a
mycompany.myapplication.b
myobfuscated.a.a
myobfuscated.a.b
myobfuscated.b.a
myobfuscated.b.b

Alternatively, the -repackageclasses option obfuscates the entire packaging, by combining obfuscated classes into a single package:

-repackageclasses 'myobfuscated'
The obfuscated class names then look as follows:
mycompany.myapplication.MyMain
mycompany.myapplication.a
mycompany.myapplication.b
myobfuscated.a
myobfuscated.b
myobfuscated.c
myobfuscated.d

Additionally specifying the -allowaccessmodification option allows access permissions of classes and class members to be broadened, opening up the opportunity to repackage all obfuscated classes:

-repackageclasses 'myobfuscated'
-allowaccessmodification
The obfuscated class names then look as follows:
mycompany.myapplication.MyMain
myobfuscated.a
myobfuscated.b
myobfuscated.c
myobfuscated.d
myobfuscated.e
myobfuscated.f

The specified target package can always be the root package. For instance:

-repackageclasses ''
-allowaccessmodification
The obfuscated class names are then the shortest possible names:
mycompany.myapplication.MyMain
a
b
c
d
e
f

Note that not all levels of obfuscation of package names may be acceptable for all code. Notably, you may have to take into account that your application may contain resource files that have to be adapted.

Restructuring the output archives

In simple applications, all output classes and resources files are merged into a single jar. For example:
-injars  classes
-injars  in1.jar
-injars  in2.jar
-injars  in3.jar
-outjars out.jar

This configuration merges the processed versions of the files in the classes directory and the three jars into a single output jar out.jar.

If you want to preserve the structure of your input jars (and/or wars, ears, zips, or directories), you can specify an output directory (or a war, an ear, or a zip). For example:

-injars  in1.jar
-injars  in2.jar
-injars  in3.jar
-outjars out

The input jars will then be reconstructed in the directory out, with their original names.

You can also combine archives into higher level archives. For example:

-injars  in1.jar
-injars  in2.jar
-injars  in3.jar
-outjars out.war

The other way around, you can flatten the archives inside higher level archives into simple archives:

-injars  in.war
-outjars out.jar

This configuration puts the processed contents of all jars inside in.war (plus any other contents of in.war) into out.jar.

If you want to combine input jars (and/or wars, ears, zips, or directories) into output jars (and/or wars, ears, zips, or directories), you can group the -injars and -outjars options. For example:

-injars base_in1.jar
-injars base_in2.jar
-injars base_in3.jar
-outjars base_out.jar

-injars  extra_in.jar
-outjars extra_out.jar

This configuration puts the processed results of all base_in*.jar jars into base_out.jar, and the processed results of the extra_in.jar into extra_out.jar. Note that only the order of the options matters; the additional whitespace is just for clarity.

This grouping, archiving, and flattening can be arbitrarily complex. ProGuard always tries to package output archives in a sensible way, reconstructing the input entries as much as required.

Filtering the input and the output

If you want even greater control, you can add filters to the input and the output, filtering out zips, ears, wars, jars, and/or ordinary files. For example, if you want to disregard certain files from an input jar:
-injars  in.jar(!images/**)
-outjars out.jar

This configuration removes any files in the images directory and its subdirectories.

Such filters can be convenient for avoiding warnings about duplicate files in the output. For example, only keeping the manifest file from a first input jar:

-injars  in1.jar
-injars  in2.jar(!META-INF/MANIFEST.MF)
-injars  in3.jar(!META-INF/MANIFEST.MF)
-outjars out.jar

Another useful application is speeding up the processing by ProGuard, by disregarding a large number of irrelevant classes in the runtime library jar:

-libraryjars <java.home>/lib/rt.jar(java/**,javax/**)

The filter makes ProGuard disregard com.sun.** classes, for instance , which don't affect the processing of ordinary applications.

It is also possible to filter the jars (and/or wars, ears, zips) themselves, based on their names. For example:

-injars  in(**/acme_*.jar;)
-outjars out.jar

Note the semi-colon in the filter; the filter in front of it applies to jar names. In this case, only acme_*.jar jars are read from the directory in and its subdirectories. Filters for war names, ear names, and zip names can be prefixed with additional semi-colons. All types of filters can be combined. They are orthogonal.

On the other hand, you can also filter the output, in order to control what content goes where. For example:

-injars  in.jar
-outjars code_out.jar(**.class)
-outjars resources_out.jar

This configuration splits the processed output, sending **.class files to code_out.jar, and all remaining files to resources_out.jar.

Again, the filtering can be arbitrarily complex, especially when combined with grouping input and output.

Processing multiple applications at once

You can process several dependent or independent applications (or applets, midlets,...) in one go, in order to save time and effort. ProGuard's input and output handling offers various ways to keep the output nicely structured.

The easiest way is to specify your input jars (and/or wars, ears, zips, and directories) and a single output directory. ProGuard will then reconstruct the input in this directory, using the original jar names. For example, showing just the input and output options:

-injars  application1.jar
-injars  application2.jar
-injars  application3.jar
-outjars processed_applications

After processing, the directory processed_applications will contain processed versions of application jars, with their original names.

Incremental obfuscation

After having processed an application, e.g. ProGuard itself, you can still incrementally add other pieces of code that depend on it, e.g. the ProGuard GUI:
-injars       proguardgui.jar
-outjars      proguardgui_out.jar
-injars       proguard.jar
-outjars      proguard_out.jar
-libraryjars  <java.home>/lib/rt.jar
-applymapping proguard.map

-keep public class proguard.gui.ProGuardGUI {
    public static void main(java.lang.String[]);
}

We're reading both unprocessed jars as input. Their processed contents will go to the respective output jars. The -applymapping option then makes sure the ProGuard part of the code gets the previously produced obfuscation mapping. The final application will consist of the obfuscated ProGuard jar and the additional obfuscated GUI jar.

The added code in this example is straightforward; it doesn't affect the original code. The proguard_out.jar will be identical to the one produced in the initial processing step. If you foresee adding more complex extensions to your code, you should specify the options -useuniqueclassmembernames, -dontshrink, and -dontoptimize in the original processing step. These options ensure that the obfuscated base jar will always remain usable without changes. You can then specify the base jar as a library jar:

-injars       proguardgui.jar
-outjars      proguardgui_out.jar
-libraryjars  proguard.jar
-libraryjars  <java.home>/lib/rt.jar
-applymapping proguard.map

-keep public class proguard.gui.ProGuardGUI {
    public static void main(java.lang.String[]);
}

Preverifying class files for Java Micro Edition

Even if you're not interested in shrinking, optimizing, and obfuscating your midlets, as shown in the midlets example, you can still use ProGuard to preverify the class files for Java Micro Edition. ProGuard produces slightly more compact results than the traditional external preverifier.
-injars      in.jar
-outjars     out.jar
-libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar
-libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar

-dontshrink
-dontoptimize
-dontobfuscate

-microedition

We're not processing the input, just making sure the class files are preverified by targeting them at Java Micro Edition with the -microedition option. Note that we don't need any -keep options to specify entry points; all class files are simply preverified.

Upgrading class files to Java 6

The following options upgrade class files to Java 6, by updating their internal version numbers and preverifying them. The class files can then be loaded more efficiently by the Java 6 Virtual Machine.
-injars      in.jar
-outjars     out.jar
-libraryjars <java.home>/lib/rt.jar

-dontshrink
-dontoptimize
-dontobfuscate

-target 1.6

We're not processing the input, just retargeting the class files with the -target option. They will automatically be preverified for Java 6 as a result. Note that we don't need any -keep options to specify entry points; all class files are simply updated and preverified.

Finding dead code

These options list unused classes, fields, and methods in the application mypackage.MyApplication:
-injars      in.jar
-libraryjars <java.home>/lib/rt.jar

-dontoptimize
-dontobfuscate
-dontpreverify
-printusage

-keep public class mypackage.MyApplication {
    public static void main(java.lang.String[]);
}

We're not specifying an output jar, just printing out some results. We're saving some processing time by skipping the other processing steps.

The java compiler inlines primitive constants and String constants (static final fields). ProGuard would therefore list such fields as not being used in the class files that it analyzes, even if they are used in the source files. We can add a -keepclassmembers option that keeps those fields a priori, in order to avoid having them listed:

-keepclassmembers class * {
    static final %                *;
    static final java.lang.String *;
}

Printing out the internal structure of class files

These options print out the internal structure of all class files in the input jar:
-injars in.jar

-dontshrink
-dontoptimize
-dontobfuscate
-dontpreverify

-dump

Note how we don't need to specify the Java run-time jar, because we're not processing the input jar at all.

Using annotations to configure ProGuard

The traditional ProGuard configuration allows to keep a clean separation between the code and the configuration for shrinking, optimization, and obfuscation. However, it is also possible to define specific annotations, and then annotate the code to configure the processing.

You can find a set of such predefined annotations in the directory examples/annotations/lib in the ProGuard distribution. The annotation classes are defined in annotations.jar. The corresponding ProGuard configuration (or meta-configuration, if you prefer) is specified in annotations.pro. With these files, you can start annotating your code. For instance, a java source file Application.java can be annotated as follows:

@KeepApplication
public class Application {
  ....
}

The ProGuard configuration file for the application can then be simplified by leveraging off these annotations:

-injars      in.jar
-outjars     out.jar
-libraryjars <java.home>/lib/rt.jar

-include lib/annotations.pro

The annotations are effectively replacing the application-dependent -keep options. You may still wish to add traditional -keep options for processing native methods, enumerations, serializable classes, and annotations.

The directory examples/annotations contains more examples that illustrate some of the possibilities.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/limitations.html0000644000175000017500000000573111736333522017223 0ustar ericeric ProGuard Limitations

Limitations

When using ProGuard, you should be aware of a few technical issues, all of which are easily avoided or resolved:

  • For best results, ProGuard's optimization algorithms assume that the processed code never intentionally throws NullPointerExceptions or ArrayIndexOutOfBoundsExceptions, or even OutOfMemoryErrors or StackOverflowErrors, in order to achieve something useful. For instance, it may remove a method call myObject.myMethod() if that call wouldn't have any effect. It ignores the possibility that myObject might be null, causing a NullPointerException. In some way this is a good thing: optimized code may throw fewer exceptions. Should this entire assumption be false, you'll have to switch off optimization using the -dontoptimize option.
  • ProGuard's optimization algorithms currently also assume that the processed code never creates busy-waiting loops without at least testing on a volatile field. Again, it may remove such loops. Should this assumption be false, you'll have to switch off optimization using the -dontoptimize option.
  • If an input jar and a library jar contain classes in the same package, the obfuscated output jar may contain class names that overlap with class names in the library jar. This is most likely if the library jar has been obfuscated before, as it will then probably contain classes named 'a', 'b', etc. Packages should therefore never be split across input jars and library jars.
  • When obfuscating, ProGuard writes out class files named "a.class", "b.class", etc. If a package contains a large number of classes, ProGuard may also write out "aux.class". Inconveniently, Windows refuses to create files with this reserved name (among a few other names). It's generally better to write the output to a jar, in order to avoid such problems.

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/index.html0000644000175000017500000000314211736333522015770 0ustar ericeric ProGuard Manual

ProGuard

  1. Introduction
  2. Usage
  3. Limitations
  4. Examples
  5. Troubleshooting
  6. Reference Card
  7. Graphical User Interface
  8. Ant Task
  9. JME Wireless Toolkit Integration

ReTrace

  1. Introduction
  2. Usage
  3. Examples

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/introduction.html0000644000175000017500000001723711753323111017404 0ustar ericeric ProGuard Introduction

Introduction

ProGuard is a Java class file shrinker, optimizer, obfuscator, and preverifier. The shrinking step detects and removes unused classes, fields, methods, and attributes. The optimization step analyzes and optimizes the bytecode of the methods. The obfuscation step renames the remaining classes, fields, and methods using short meaningless names. These first steps make the code base smaller, more efficient, and harder to reverse-engineer. The final preverification step adds preverification information to the classes, which is required for Java Micro Edition and for Java 6 and higher.

Each of these steps is optional. For instance, ProGuard can also be used to just list dead code in an application, or to preverify class files for efficient use in Java 6.

Input jars
Shrunk code
Optim. code Output jars
- shrink → - optimize → - obfuscate → Obfusc. code - preverify →
Library jars ------------------------------- (unchanged) -------------------------------→ Library jars

ProGuard first reads the input jars (or wars, ears, zips, or directories). It then subsequently shrinks, optimizes, obfuscates, and preverifies them. You can optionally let ProGuard perform multiple optimization passes. ProGuard writes the processed results to one or more output jars (or wars, ears, zips, or directories). The input may contain resource files, whose names and contents can optionally be updated to reflect the obfuscated class names.

ProGuard requires the library jars (or wars, ears, zips, or directories) of the input jars to be specified. These are essentially the libraries that you would need for compiling the code. ProGuard uses them to reconstruct the class dependencies that are necessary for proper processing. The library jars themselves always remain unchanged. You should still put them in the class path of your final application.

Entry points

In order to determine which code has to be preserved and which code can be discarded or obfuscated, you have to specify one or more entry points to your code. These entry points are typically classes with main methods, applets, midlets, activities, etc.
  • In the shrinking step, ProGuard starts from these seeds and recursively determines which classes and class members are used. All other classes and class members are discarded.
  • In the optimization step, ProGuard further optimizes the code. Among other optimizations, classes and methods that are not entry points can be made private, static, or final, unused parameters can be removed, and some methods may be inlined.
  • In the obfuscation step, ProGuard renames classes and class members that are not entry points. In this entire process, keeping the entry points ensures that they can still be accessed by their original names.
  • The preverification step is the only step that doesn't have to know the entry points.

The Usage section of this manual describes the necessary -keep options and the Examples section provides plenty of examples.

Reflection

Reflection and introspection present particular problems for any automatic processing of code. In ProGuard, classes or class members in your code that are created or invoked dynamically (that is, by name) have to be specified as entry points too. For example, Class.forName() constructs may refer to any class at run-time. It is generally impossible to compute which classes have to be preserved (with their original names), since the class names might be read from a configuration file, for instance. You therefore have to specify them in your ProGuard configuration, with the same simple -keep options.

However, ProGuard will already detect and handle the following cases for you:

  • Class.forName("SomeClass")
  • SomeClass.class
  • SomeClass.class.getField("someField")
  • SomeClass.class.getDeclaredField("someField")
  • SomeClass.class.getMethod("someMethod", new Class[] {})
  • SomeClass.class.getMethod("someMethod", new Class[] { A.class })
  • SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] {})
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class, B.class })
  • AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
  • AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
  • AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")
The names of the classes and class members may of course be different, but the constructs should be literally the same for ProGuard to recognize them. The referenced classes and class members are preserved in the shrinking phase, and the string arguments are properly updated in the obfuscation phase.

Furthermore, ProGuard will offer some suggestions if keeping some classes or class members appears necessary. For example, ProGuard will note constructs like "(SomeClass)Class.forName(variable).newInstance()". These might be an indication that the class or interface SomeClass and/or its implementations may need to be preserved. You can then adapt your configuration accordingly.

For proper results, you should at least be somewhat familiar with the code that you are processing. Obfuscating code that performs a lot of reflection may require trial and error, especially without the necessary information about the internals of the code.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/style.css0000644000175000017500000000242711754473650015661 0ustar ericeric@charset "iso-8859-1"; /* Global settings. */ body { background: #FFFFFF; } h1 { text-align: center; } h2 { background: #EEEEFF; padding: 10px; } dt { padding: 6px; } dt div { color: grey; float: right; } dd { padding: 6px; } pre { padding: 10px; background: #E0E0E0; } .spacious li { padding: 8px; } .shifted li { margin-left: 50px; } img.float { float: left; } a { text-decoration: none; } a.button { color: #000000; text-decoration: none; background: #E0E0E0; border: 1px outset #FFFFFF; float: right; } /* Settings for variable width code. */ p.code { padding: 10px; background: #E0E0E0; } /* Settings for diagrams. */ table.diagram { padding: 8px; border: none; border-spacing: 2px; } td.transparentblock { text-align: center; padding: 10px 0px; } td.whiteblock { width: 100px; text-align: center; border: 1px solid #C0C0C0; background: #E0E0E0; padding: 10px 0px; } td.lightblock { width: 100px; text-align: center; border: 1px solid #8888FF; background: #BBBBFF; padding: 20px 0px; } td.darkblock { width: 100px; text-align: center; background: #8888FF; padding: 20px 0px; } /* Settings for buttons. */ td.button { background: #E0E0E0; border: 1px outset #FFFFFF; font-weight: bold; } proguard4.8/docs/manual/sections.html0000644000175000017500000000373711736333522016522 0ustar ericeric Sections

With support of

Saikoa

proguard4.8/docs/manual/usage.html0000644000175000017500000017140311754473435016003 0ustar ericeric ProGuard Usage

Usage

To run ProGuard, just type:

java -jar proguard.jar options ...

You can find the ProGuard jar in the lib directory of the ProGuard distribution. Alternatively, the bin directory contains some short Linux and Windows scripts containing this command. Typically, you'll put most options in a configuration file (say, myconfig.pro), and just call:

java -jar proguard.jar @myconfig.pro

You can combine command line options and options from configuration files. For instance:

java -jar proguard.jar @myconfig.pro -verbose

You can add comments in a configuration file, starting with a # character and continuing until the end of the line.

Extra whitespace between words and delimiters is ignored. File names with spaces or special characters should be quoted with single or double quotes.

Options can be grouped arbitrarily in arguments on the command line and in lines in configuration files. This means that you can quote arbitrary sections of command line options, to avoid shell expansion of special characters, for instance.

The order of the options is generally irrelevant. For quick experiments, you can abbreviate them to their first unique characters.

The sections below provide more details:

Input/Output Options

@filename
Short for '-include filename'.
-include filename
Recursively reads configuration options from the given file filename.
-basedirectory directoryname
Specifies the base directory for all subsequent relative file names in these configuration arguments or this configuration file.
-injars class_path
Specifies the input jars (or wars, ears, zips, or directories) of the application to be processed. The class files in these jars will be processed and written to the output jars. By default, any non-class files will be copied without changes. Please be aware of any temporary files (e.g. created by IDEs), especially if you are reading your input files straight from directories. The entries in the class path can be filtered, as explained in the filters section. For better readability, class path entries can be specified using multiple -injars options.
-outjars class_path
Specifies the names of the output jars (or wars, ears, zips, or directories). The processed input of the preceding -injars options will be written to the named jars. This allows you to collect the contents of groups of input jars into corresponding groups of output jars. In addition, the output entries can be filtered, as explained in the filters section. Each processed class file or resource file is then written to the first output entry with a matching filter, within the group of output jars.

You must avoid letting the output files overwrite any input files. For better readability, class path entries can be specified using multiple -outjars options. Without any -outjars options, no jars will be written.

-libraryjars class_path
Specifies the library jars (or wars, ears, zips, or directories) of the application to be processed. The files in these jars will not be included in the output jars. The specified library jars should at least contain the class files that are extended by application class files. Library class files that are only called needn't be present, although their presence can improve the results of the optimization step. The entries in the class path can be filtered, as explained in the filters section. For better readability, class path entries can be specified using multiple -libraryjars options.

Please note that the boot path and the class path set for running ProGuard are not considered when looking for library classes. This means that you explicitly have to specify the run-time jar that your code will use. Although this may seem cumbersome, it allows you to process applications targeted at different run-time environments. For example, you can process J2SE applications as well as JME midlets or Android apps, just by specifying the appropriate run-time jar.

-skipnonpubliclibraryclasses
Specifies to skip non-public classes while reading library jars, to speed up processing and reduce memory usage of ProGuard. By default, ProGuard reads non-public and public library classes alike. However, non-public classes are often not relevant, if they don't affect the actual program code in the input jars. Ignoring them then speeds up ProGuard, without affecting the output. Unfortunately, some libraries, including recent JSE run-time libraries, contain non-public library classes that are extended by public library classes. You then can't use this option. ProGuard will print out warnings if it can't find classes due to this option being set.
-dontskipnonpubliclibraryclasses
Specifies not to ignore non-public library classes. As of version 4.5, this is the default setting.
-dontskipnonpubliclibraryclassmembers
Specifies not to ignore package visible library class members (fields and methods). By default, ProGuard skips these class members while parsing library classes, as program classes will generally not refer to them. Sometimes however, program classes reside in the same packages as library classes, and they do refer to their package visible class members. In those cases, it can be useful to actually read the class members, in order to make sure the processed code remains consistent.
-keepdirectories [directory_filter]
Specifies the directories to be kept in the output jars (or wars, ears, zips, or directories). By default, directory entries are removed. This reduces the jar size, but it may break your program if the code tries to find them with constructs like "mypackage.MyClass.class.getResource("")". You'll then want to keep the directory corresponding to the package, "-keepdirectories mypackage". If the option is specified without a filter, all directories are kept. With a filter, only matching directories are kept.
-target version
Specifies the version number to be set in the processed class files. The version number can be one of 1.0, 1.1, 1.2, 1.3, 1.4, 1.5 (or just 5), 1.6 (or just 6), or 1.7 (or just 7). By default, the version numbers of the class files are left unchanged. For example, you may want to upgrade class files to Java 6, by changing their version numbers and having them preverified.
-forceprocessing
Specifies to process the input, even if the output seems up to date. The up-to-dateness test is based on a comparison of the date stamps of the specified input, output, and configuration files or directories.

Keep Options

-keep [,modifier,...] class_specification
Specifies classes and class members (fields and methods) to be preserved as entry points to your code. For example, in order to keep an application, you can specify the main class along with its main method. In order to process a library, you should specify all publicly accessible elements.
-keepclassmembers [,modifier,...] class_specification
Specifies class members to be preserved, if their classes are preserved as well. For example, you may want to keep all serialization fields and methods of classes that implement the Serializable interface.
-keepclasseswithmembers [,modifier,...] class_specification
Specifies classes and class members to be preserved, on the condition that all of the specified class members are present. For example, you may want to keep all applications that have a main method, without having to list them explicitly.
-keepnames class_specification
Short for -keep,allowshrinking class_specification

Specifies classes and class members whose names are to be preserved, if they aren't removed in the shrinking phase. For example, you may want to keep all class names of classes that implement the Serializable interface, so that the processed code remains compatible with any originally serialized classes. Classes that aren't used at all can still be removed. Only applicable when obfuscating.

-keepclassmembernames class_specification
Short for -keepclassmembers,allowshrinking class_specification

Specifies class members whose names are to be preserved, if they aren't removed in the shrinking phase. For example, you may want to preserve the name of the synthetic class$ methods when processing a library compiled by JDK 1.2 or older, so obfuscators can detect it again when processing an application that uses the processed library (although ProGuard itself doesn't need this). Only applicable when obfuscating.

-keepclasseswithmembernames class_specification
Short for -keepclasseswithmembers,allowshrinking class_specification

Specifies classes and class members whose names are to be preserved, on the condition that all of the specified class members are present after the shrinking phase. For example, you may want to keep all native method names and the names of their classes, so that the processed code can still link with the native library code. Native methods that aren't used at all can still be removed. If a class file is used, but none of its native methods are, its name will still be obfuscated. Only applicable when obfuscating.

-printseeds [filename]
Specifies to exhaustively list classes and class members matched by the various -keep options. The list is printed to the standard output or to the given file. The list can be useful to verify if the intended class members are really found, especially if you're using wildcards. For example, you may want to list all the applications or all the applets that you are keeping.

Shrinking Options

-dontshrink
Specifies not to shrink the input class files. By default, shrinking is applied; all classes and class members are removed, except for the ones listed by the various -keep options, and the ones on which they depend, directly or indirectly. A shrinking step is also applied after each optimization step, since some optimizations may open the possibility to remove more classes and class members.
-printusage [filename]
Specifies to list dead code of the input class files. The list is printed to the standard output or to the given file. For example, you can list the unused code of an application. Only applicable when shrinking.
-whyareyoukeeping class_specification
Specifies to print details on why the given classes and class members are being kept in the shrinking step. This can be useful if you are wondering why some given element is present in the output. In general, there can be many different reasons. This option prints the shortest chain of methods to a specified seed or entry point, for each specified class and class member. In the current implementation, the shortest chain that is printed out may sometimes contain circular deductions -- these do not reflect the actual shrinking process. If the -verbose option if specified, the traces include full field and method signatures. Only applicable when shrinking.

Optimization Options

-dontoptimize
Specifies not to optimize the input class files. By default, optimization is enabled; all methods are optimized at a bytecode level.
-optimizations optimization_filter
Specifies the optimizations to be enabled and disabled, at a more fine-grained level. Only applicable when optimizing. This is an expert option.
-optimizationpasses n
Specifies the number of optimization passes to be performed. By default, a single pass is performed. Multiple passes may result in further improvements. If no improvements are found after an optimization pass, the optimization is ended. Only applicable when optimizing.
-assumenosideeffects class_specification
Specifies methods that don't have any side effects (other than maybe returning a value). In the optimization step, ProGuard will then remove calls to such methods, if it can determine that the return values aren't used. ProGuard will analyze your program code to find such methods automatically. It will not analyze library code, for which this option can therefore be useful. For example, you could specify the method System.currentTimeMillis(), so that any idle calls to it will be removed. Note that ProGuard applies the option to the entire hierarchy of the specified methods. Only applicable when optimizing. In general, making assumptions can be dangerous; you can easily break the processed code. Only use this option if you know what you're doing!
-allowaccessmodification
Specifies that the access modifiers of classes and class members may be broadened during processing. This can improve the results of the optimization step. For instance, when inlining a public getter, it may be necessary to make the accessed field public too. Although Java's binary compatibility specifications formally do not require this (cfr. The Java Language Specification, Second Edition, Section 13.4.6), some virtual machines would have problems with the processed code otherwise. Only applicable when optimizing (and when obfuscating with the -repackageclasses option).

Counter-indication: you probably shouldn't use this option when processing code that is to be used as a library, since classes and class members that weren't designed to be public in the API may become public.

-mergeinterfacesaggressively
Specifies that interfaces may be merged, even if their implementing classes don't implement all interface methods. This can reduce the size of the output by reducing the total number of classes. Note that Java's binary compatibility specifications allow such constructs (cfr. The Java Language Specification, Second Edition, Section 13.5.3), even if they are not allowed in the Java language (cfr. The Java Language Specification, Second Edition, Section 8.1.4). Only applicable when optimizing.

Counter-indication: setting this option can reduce the performance of the processed code on some JVMs, since advanced just-in-time compilation tends to favor more interfaces with fewer implementing classes. Worse, some JVMs may not be able to handle the resulting code. Notably:

  • Sun's JRE 1.3 may throw an InternalError when encountering more than 256 Miranda methods (interface methods without implementations) in a class.

Obfuscation Options

-dontobfuscate
Specifies not to obfuscate the input class files. By default, obfuscation is applied; classes and class members receive new short random names, except for the ones listed by the various -keep options. Internal attributes that are useful for debugging, such as source files names, variable names, and line numbers are removed.
-printmapping [filename]
Specifies to print the mapping from old names to new names for classes and class members that have been renamed. The mapping is printed to the standard output or to the given file. For example, it is required for subsequent incremental obfuscation, or if you ever want to make sense again of obfuscated stack traces. Only applicable when obfuscating.
-applymapping filename
Specifies to reuse the given name mapping that was printed out in a previous obfuscation run of ProGuard. Classes and class members that are listed in the mapping file receive the names specified along with them. Classes and class members that are not mentioned receive new names. The mapping may refer to input classes as well as library classes. This option can be useful for incremental obfuscation, i.e. processing add-ons or small patches to an existing piece of code. If the structure of the code changes fundamentally, ProGuard may print out warnings that applying a mapping is causing conflicts. You may be able to reduce this risk by specifying the option -useuniqueclassmembernames in both obfuscation runs. Only a single mapping file is allowed. Only applicable when obfuscating.
-obfuscationdictionary filename
Specifies a text file from which all valid words are used as obfuscated field and method names. By default, short names like 'a', 'b', etc. are used as obfuscated names. With an obfuscation dictionary, you can specify a list of reserved key words, or identifiers with foreign characters, for instance. White space, punctuation characters, duplicate words, and comments after a # sign are ignored. Note that an obfuscation dictionary hardly improves the obfuscation. Decent compilers can automatically replace them, and the effect can fairly simply be undone by obfuscating again with simpler names. The most useful application is specifying strings that are typically already present in class files (such as 'Code'), thus reducing the class file sizes just a little bit more. Only applicable when obfuscating.
-classobfuscationdictionary filename
Specifies a text file from which all valid words are used as obfuscated class names. The obfuscation dictionary is similar to the one of the option -obfuscationdictionary. Only applicable when obfuscating.
-packageobfuscationdictionary filename
Specifies a text file from which all valid words are used as obfuscated package names. The obfuscation dictionary is similar to the one of the option -obfuscationdictionary. Only applicable when obfuscating.
-overloadaggressively
Specifies to apply aggressive overloading while obfuscating. Multiple fields and methods can then get the same names, as long as their arguments and return types are different (not just their arguments). This option can make the processed code even smaller (and less comprehensible). Only applicable when obfuscating.

Counter-indication: the resulting class files fall within the Java bytecode specification (cfr. The Java Virtual Machine Specification, Second Edition, first paragraphs of Section 4.5 and Section 4.6), even though this kind of overloading is not allowed in the Java language (cfr. The Java Language Specification, Second Edition, Section 8.3 and Section 8.4.7). Still, some tools have problems with it. Notably:

  • Sun's JDK 1.2.2 javac compiler produces an exception when compiling with such a library (cfr. Bug #4216736). You probably shouldn't use this option for processing libraries.
  • Sun's JRE 1.4 and later fail to serialize objects with overloaded primitive fields.
  • Sun's JRE 1.5 pack200 tool reportedly has problems with overloaded class members.
  • Google's Dalvik VM can't handle overloaded static fields.
-useuniqueclassmembernames
Specifies to assign the same obfuscated names to class members that have the same names, and different obfuscated names to class members that have different names (for each given class member signature). Without the option, more class members can be mapped to the same short names like 'a', 'b', etc. The option therefore increases the size of the resulting code slightly, but it ensures that the saved obfuscation name mapping can always be respected in subsequent incremental obfuscation steps.

For instance, consider two distinct interfaces containing methods with the same name and signature. Without this option, these methods may get different obfuscated names in a first obfuscation step. If a patch is then added containing a class that implements both interfaces, ProGuard will have to enforce the same method name for both methods in an incremental obfuscation step. The original obfuscated code is changed, in order to keep the resulting code consistent. With this option in the initial obfuscation step, such renaming will never be necessary.

This option is only applicable when obfuscating. In fact, if you are planning on performing incremental obfuscation, you probably want to avoid shrinking and optimization altogether, since these steps could remove or modify parts of your code that are essential for later additions.

-dontusemixedcaseclassnames
Specifies not to generate mixed-case class names while obfuscating. By default, obfuscated class names can contain a mix of upper-case characters and lower-case characters. This creates perfectly acceptable and usable jars. Only if a jar is unpacked on a platform with a case-insensitive filing system (say, Windows), the unpacking tool may let similarly named class files overwrite each other. Code that self-destructs when it's unpacked! Developers who really want to unpack their jars on Windows can use this option to switch off this behavior. Obfuscated jars will become slightly larger as a result. Only applicable when obfuscating.
-keeppackagenames [package_filter]
Specifies not to obfuscate the given package names. The optional filter is a comma-separated list of package names. Package names can contain ?, *, and ** wildcards, and they can be preceded by the ! negator. Only applicable when obfuscating.
-flattenpackagehierarchy [package_name]
Specifies to repackage all packages that are renamed, by moving them into the single given parent package. Without argument or with an empty string (''), the packages are moved into the root package. This option is one example of further obfuscating package names. It can make the processed code smaller and less comprehensible. Only applicable when obfuscating.
-repackageclasses [package_name]
Specifies to repackage all class files that are renamed, by moving them into the single given package. Without argument or with an empty string (''), the package is removed completely. This option option overrides the -flattenpackagehierarchy option. It is another example of further obfuscating package names. It can make the processed code even smaller and less comprehensible. Its deprecated name is -defaultpackage. Only applicable when obfuscating.

Counter-indication: classes that look for resource files in their package directories will no longer work properly if they are moved elsewhere. When in doubt, just leave the packaging untouched by not using this option.

-keepattributes [attribute_filter]
Specifies any optional attributes to be preserved. The attributes can be specified with one or more -keepattributes directives. The optional filter is a comma-separated list of attribute names. Attribute names can contain ?, *, and ** wildcards, and they can be preceded by the ! negator. Typical optional attributes are Exceptions, Signature, Deprecated, SourceFile, SourceDir, LineNumberTable, LocalVariableTable, LocalVariableTypeTable, Synthetic, EnclosingMethod, RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations, RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations, and AnnotationDefault. The InnerClasses attribute name can be specified as well, referring to the source name part of this attribute. For example, you should at least keep the Exceptions, InnerClasses, and Signature attributes when processing a library. You should also keep the SourceFile and LineNumberTable attributes for producing useful obfuscated stack traces. Finally, you may want to keep annotations if your code depends on them. Only applicable when obfuscating.
-keepparameternames
Specifies to keep the parameter names and types of methods that are kept. This option actually keeps trimmed versions of the debugging attributes LocalVariableTable and LocalVariableTypeTable. It can be useful when processing a library. Some IDEs can use the information to assist developers who use the library, for example with tool tips or autocompletion. Only applicable when obfuscating.
-renamesourcefileattribute [string]
Specifies a constant string to be put in the SourceFile attributes (and SourceDir attributes) of the class files. Note that the attribute has to be present to start with, so it also has to be preserved explicitly using the -keepattributes directive. For example, you may want to have your processed libraries and applications produce useful obfuscated stack traces. Only applicable when obfuscating.
-adaptclassstrings [class_filter]
Specifies that string constants that correspond to class names should be obfuscated as well. Without a filter, all string constants that correspond to class names are adapted. With a filter, only string constants in classes that match the filter are adapted. For example, if your code contains a large number of hard-coded strings that refer to classes, and you prefer not to keep their names, you may want to use this option. Primarily applicable when obfuscating, although corresponding classes are automatically kept in the shrinking step too.
-adaptresourcefilenames [file_filter]
Specifies the resource files to be renamed, based on the obfuscated names of the corresponding class files (if any). Without a filter, all resource files that correspond to class files are renamed. With a filter, only matching files are renamed. For example, see processing resource files. Only applicable when obfuscating.
-adaptresourcefilecontents [file_filter]
Specifies the resource files whose contents are to be updated. Any class names mentioned in the resource files are renamed, based on the obfuscated names of the corresponding classes (if any). Without a filter, the contents of all resource files updated. With a filter, only matching files are updated. The resource files are parsed and written using the platform's default character set. You can change this default character set by setting the environment variable LANG or the Java system property file.encoding. For an example, see processing resource files. Only applicable when obfuscating.

Preverification Options

-dontpreverify
Specifies not to preverify the processed class files. By default, class files are preverified if they are targeted at Java Micro Edition or at Java 6 or higher. For Java Micro Edition, preverification is required, so you will need to run an external preverifier on the processed code if you specify this option. For Java 6, preverification is optional, but as of Java 7, it is required. Only when eventually targeting Android, it is not necessary, so you can then switch it off to reduce the processing time a bit.
-microedition
Specifies that the processed class files are targeted at Java Micro Edition. The preverifier will then add the appropriate StackMap attributes, which are different from the default StackMapTable attributes for Java Standard Edition. For example, you will need this option if you are processing midlets.

General Options

-verbose
Specifies to write out some more information during processing. If the program terminates with an exception, this option will print out the entire stack trace, instead of just the exception message.
-dontnote [class_filter]
Specifies not to print notes about potential mistakes or omissions in the configuration, like typos in class names, or like missing options that might be useful. The optional filter is a regular expression; ProGuard doesn't print notes about classes with matching names.
-dontwarn [class_filter]
Specifies not to warn about unresolved references and other important problems at all. The optional filter is a regular expression; ProGuard doesn't print warnings about classes with matching names. Ignoring warnings can be dangerous. For instance, if the unresolved classes or class members are indeed required for processing, the processed code will not function properly. Only use this option if you know what you're doing!
-ignorewarnings
Specifies to print any warnings about unresolved references and other important problems, but to continue processing in any case. Ignoring warnings can be dangerous. For instance, if the unresolved classes or class members are indeed required for processing, the processed code will not function properly. Only use this option if you know what you're doing!
-printconfiguration [filename]
Specifies to write out the entire configuration that has been parsed, with included files and replaced variables. The structure is printed to the standard output or to the given file. This can sometimes be useful for debugging configurations, or for converting XML configurations into a more readable format.
-dump [filename]
Specifies to write out the internal structure of the class files, after any processing. The structure is printed to the standard output or to the given file. For example, you may want to write out the contents of a given jar file, without processing it at all.

Class Paths

ProGuard accepts a generalization of class paths to specify input files and output files. A class path consists of entries, separated by the traditional path separator (e.g. ':' on Unix, or ';' on Windows platforms). The order of the entries determines their priorities, in case of duplicates.

Each input entry can be:

  • A class file or resource file,
  • A jar file, containing any of the above,
  • A war file, containing any of the above,
  • An ear file, containing any of the above,
  • A zip file, containing any of the above,
  • A directory (structure), containing any of the above.

The paths of directly specified class files and resource files is ignored, so class files should generally be part of a jar file, a war file, an ear file, a zip file, or a directory. In addition, the paths of class files should not have any additional directory prefixes inside the archives or directories.

Each output entry can be:

  • A jar file, in which all processed class files and resource files will be collected.
  • A war file, in which any and all of the above will be collected,
  • An ear file, in which any and all of the above will be collected,
  • A zip file, in which any and all of the above will be collected,
  • A directory, in which any and all of the above will be collected.

When writing output entries, ProGuard will generally package the results in a sensible way, reconstructing the input entries as much as required. Writing everything to an output directory is the most straightforward option: the output directory will contain a complete reconstruction of the input entries. The packaging can be almost arbitrarily complex though: you could process an entire application, packaged in a zip file along with its documentation, writing it out as a zip file again. The Examples section shows a few ways to restructure output archives.

Files and directories can be specified as discussed in the section on file names below.

In addition, ProGuard provides the possibility to filter the class path entries and their contents, based on their full relative file names. Each class path entry can be followed by up to 5 types of file filters between parentheses, separated by semi-colons:

  • A filter for all zip names that are encountered,
  • A filter for all ear names that are encountered,
  • A filter for all war names that are encountered,
  • A filter for all jar names that are encountered,
  • A filter for all class file names and resource file names that are encountered.

If fewer than 5 filters are specified, they are assumed to be the latter filters. Any empty filters are ignored. More formally, a filtered class path entry looks like this:

classpathentry([[[[zipfilter;]earfilter;]warfilter;]jarfilter;]filefilter)

Square brackets "[]" mean that their contents are optional.

For example, "rt.jar(java/**.class,javax/**.class)" matches all class files in the java and javax directories inside the rt jar.

For example, "input.jar(!**.gif,images/**)" matches all files in the images directory inside the input jar, except gif files.

The different filters are applied to all corresponding file types, irrespective of their nesting levels in the input; they are orthogonal.

For example, "input.war(lib/**.jar,support/**.jar;**.class,**.gif)" only considers jar files in the lib and support directories in the input war, not any other jar files. It then matches all class files and gif files that are encountered.

The filters allow for an almost infinite number of packaging and repackaging possibilities. The Examples section provides a few more examples for filtering input and output.

File Names

ProGuard accepts absolute paths and relative paths for the various file names and directory names. A relative path is interpreted as follows:
  • relative to the base directory, if set, or otherwise
  • relative to the configuration file in which it is specified, if any, or otherwise
  • relative to the working directory.

The names can contain Java system properties (or Ant properties, when using Ant), delimited by '<' and '>'. The properties are automatically replaced by their corresponding values.

For example, <java.home>/lib/rt.jar is automatically expanded to something like /usr/local/java/jdk/jre/lib/rt.jar. Similarly, <user.home> is expanded to the user's home directory, and <user.dir> is expanded to the current working directory.

Names with special characters like spaces and parentheses must be quoted with single or double quotes. Each file name in a list of names has to be quoted individually. Note that the quotes themselves may need to be escaped when used on the command line, to avoid them being gobbled by the shell.

For example, on the command line, you could use an option like '-injars "my program.jar":"/your directory/your program.jar"'.

File Filters

Like general filters, a file filter is a comma-separated list of file names that can contain wildcards. Only files with matching file names are read (in the case of input jars), or written (in the case of output jars). The following wildcards are supported:
? matches any single character in a file name.
* matches any part of a filename not containing the directory separator.
** matches any part of a filename, possibly containing any number of directory separators.
For example, "java/**.class,javax/**.class" matches all class files in the java and javax.

Furthermore, a file name can be preceded by an exclamation mark '!' to exclude the file name from further attempts to match with subsequent file names.

For example, "!**.gif,images/**" matches all files in the images directory, except gif files.

The Examples section provides a few more examples for filtering input and output.

Filters

ProGuard offers options with filters for many different aspects of the configuration: names of files, directories, classes, packages, attributes, optimizations, etc.

A filter is a list of comma-separated names that can contain wildcards. Only names that match an item on the list pass the filter. The supported wildcards depend on the type of names for which the filter is being used, but the following wildcards are typical:
? matches any single character in a name.
* matches any part of a name not containing the package separator or directory separator.
** matches any part of a name, possibly containing any number of package separators or directory separators.
For example, "foo,*bar" matches the name foo and all names ending with bar.

Furthermore, a name can be preceded by a negating exclamation mark '!' to exclude the name from further attempts to match with subsequent names. So, if a name matches an item in the filter, it is accepted or rejected right away, depending on whether the item has a negator. If the name doesn't match the item, it is tested against the next item, and so on. It if doesn't match any items, it is accepted or rejected, depending on the whether the last item has a negator or not.

For example, "!foobar,*bar" matches all names ending with bar, except foobar.

Overview of Keep Options

The various -keep options for shrinking and obfuscation may seem a bit confusing at first, but there's actually a pattern behind them. The following table summarizes how they are related:

Keep From being removed or renamed From being renamed
Classes and class members -keep -keepnames
Class members only -keepclassmembers -keepclassmembernames
Classes and class members, if class members present -keepclasseswithmembers -keepclasseswithmembernames

Each of these -keep options is of course followed by a specification of the classes and class members (fields and methods) to which it should be applied.

If you're not sure which option you need, you should probably simply use -keep. It will make sure the specified classes and class members are not removed in the shrinking step, and not renamed in the obfuscation step.

attention

  • Specifying a class without class members only preserves the class as an entry point — any class members may then still be removed, optimized, or obfuscated.
  • Specifying a class member only preserves the class member as an entry point — any associated code may still be optimized and adapted.

Keep Option Modifiers

allowshrinking
Specifies that the entry points specified in the -keep option may be shrunk, even if they have to be preserved otherwise. That is, the entry points may be removed in the shrinking step, but if they are necessary after all, they may not be optimized or obfuscated.
allowoptimization
Specifies that the entry points specified in the -keep option may be optimized, even if they have to be preserved otherwise. That is, the entry points may be altered in the optimization step, but they may not be removed or obfuscated. This modifier is only useful for achieving unusual requirements.
allowobfuscation
Specifies that the entry points specified in the -keep option may be obfuscated, even if they have to be preserved otherwise. That is, the entry points may be renamed in the obfuscation step, but they may not be removed or optimized. This modifier is only useful for achieving unusual requirements.

Class Specifications

A class specification is a template of classes and class members (fields and methods). It is used in the various -keep options and in the -assumenosideeffects option. The corresponding option is only applied to classes and class members that match the template.

The template was designed to look very Java-like, with some extensions for wildcards. To get a feel for the syntax, you should probably look at the examples, but this is an attempt at a complete formal definition:

[@annotationtype] [[!]public|final|abstract|@ ...] [!]interface|class|enum classname
    [extends|implements [@annotationtype] classname]
[{
    [@annotationtype] [[!]public|private|protected|static|volatile|transient ...] <fields> |
                                                                      (fieldtype fieldname);
    [@annotationtype] [[!]public|private|protected|static|synchronized|native|abstract|strictfp ...] <methods> |
                                                                                           <init>(argumenttype,...) |
                                                                                           classname(argumenttype,...) |
                                                                                           (returntype methodname(argumenttype,...));
    [@annotationtype] [[!]public|private|protected|static ... ] *;
    ...
}]

Square brackets "[]" mean that their contents are optional. Ellipsis dots "..." mean that any number of the preceding items may be specified. A vertical bar "|" delimits two alternatives. Non-bold parentheses "()" just group parts of the specification that belong together. The indentation tries to clarify the intended meaning, but white-space is irrelevant in actual configuration files.

  • The class keyword refers to any interface or class. The interface keyword restricts matches to interface classes. The enum keyword restricts matches to enumeration classes. Preceding the interface or enum keywords by a ! restricts matches to classes that are not interfaces or enumerations, respectively.
  • Every classname must be fully qualified, e.g. java.lang.String. Inner classes are separated by a dollar sign "$", e.g. java.lang.Thread$State. Class names may be specified as regular expressions containing the following wildcards:
    ? matches any single character in a class name, but not the package separator. For example, "mypackage.Test?" matches "mypackage.Test1" and "mypackage.Test2", but not "mypackage.Test12".
    * matches any part of a class name not containing the package separator. For example, "mypackage.*Test*" matches "mypackage.Test" and "mypackage.YourTestApplication", but not "mypackage.mysubpackage.MyTest". Or, more generally, "mypackage.*" matches all classes in "mypackage", but not in its subpackages.
    ** matches any part of a class name, possibly containing any number of package separators. For example, "**.Test" matches all Test classes in all packages except the root package. Or, "mypackage.**" matches all classes in "mypackage" and in its subpackages.
    For additional flexibility, class names can actually be comma-separated lists of class names, with optional ! negators, just like file name filters. This notation doesn't look very Java-like, so it should be used with moderation.

    For convenience and for backward compatibility, the class name * refers to any class, irrespective of its package.

  • The extends and implements specifications are typically used to restrict classes with wildcards. They are currently equivalent, specifying that only classes extending or implementing the given class qualify. Note that the given class itself is not included in this set. If required, it should be specified in a separate option.
  • The @ specifications can be used to restrict classes and class members to the ones that are annotated with the specified annotation types. An annotationtype is specified just like a classname.
  • Fields and methods are specified much like in Java, except that method argument lists don't contain argument names (just like in other tools like javadoc and javap). The specifications can also contain the following catch-all wildcards:
    <init> matches any constructor.
    <fields> matches any field.
    <methods> matches any method.
    * matches any field or method.
    Note that the above wildcards don't have return types. Only the <init> wildcard has an argument list.

    Fields and methods may also be specified using regular expressions. Names can contain the following wildcards:
    ? matches any single character in a method name.
    * matches any part of a method name.
    Types in descriptors can contain the following wildcards:
    % matches any primitive type ("boolean", "int", etc, but not "void").
    ? matches any single character in a class name.
    * matches any part of a class name not containing the package separator.
    ** matches any part of a class name, possibly containing any number of package separators.
    *** matches any type (primitive or non-primitive, array or non-array).
    ... matches any number of arguments of any type.
    Note that the ?, *, and ** wildcards will never match primitive types. Furthermore, only the *** wildcards will match array types of any dimension. For example, "** get*()" matches "java.lang.Object getObject()", but not "float getFloat()", nor "java.lang.Object[] getObjects()".

  • Constructors can also be specified using their short class names (without package) or using their full class names. As in the Java language, the constructor specification has an argument list, but no return type.
  • The class access modifiers and class member access modifiers are typically used to restrict wildcarded classes and class members. They specify that the corresponding access flags have to be set for the member to match. A preceding ! specifies that the corresponding access flag should be unset.

    Combining multiple flags is allowed (e.g. public static). It means that both access flags have to be set (e.g. public and static), except when they are conflicting, in which case at least one of them has to be set (e.g. at least public or protected).

    ProGuard supports the additional modifiers synthetic, bridge, and varargs, which may be set by compilers.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/gui.html0000644000175000017500000005124011754145760015454 0ustar ericeric ProGuard GUI

Graphical User Interface

You can find the ProGuard GUI jar in the lib directory of the ProGuard distribution. To run the ProGuard graphical user interface, just type:

java -jar proguardgui.jar [-nosplash] [configuration_file]

Alternatively, the bin directory contains some short Linux and Windows scripts containing this command. The GUI will pop up in a window. With the -nosplash option, you can switch off the short opening animation. If you have specified a ProGuard configuration file, it will be loaded. The GUI works like a wizard. You can edit the configuration and execute ProGuard through a few tabs:

ProGuard Optionally load an existing configuration file.
Input/Output Specify the program jars and library jars.
Shrinking Specify the shrinking options.
Obfuscation Specify the obfuscation options.
Optimization Specify the optimization options.
Information Specify some options to get information.
Process View and save the resulting configuration, and run ProGuard.

In addition, there is a tab to execute ReTrace interactively:

ReTrace Set up and run ReTrace, to de-obfuscate stack traces.

You can freely toggle between the tabs by means of the buttons on the left-hand side of the window, or by means of the Previous and Next buttons at the bottom of the tabs. Tool tips briefly explain the purpose of the numerous options and text fields, although a basic understanding of the shrinking/optimization/obfuscation/preverification process is assumed. Please refer to the Introduction of this manual.

The ProGuard Tab

The ProGuard tab presents a welcome message and one important button at the bottom:

Load configuration... opens a file chooser to load an existing ProGuard configuration file.

If you don't want to load an existing configuration, you can just continue creating a new configuration from scratch.

The Input/Output Tab

The Input/Output tab contains two lists, respectively to specify the program jars (or wars, ears, zips, or directories), and the library jars (or wars, ears, zips, or directories).
  • The list of program jars contains input entries and output entries. Input entries contain the class files and resource files to be processed. Output entries specify the destinations to which the processed results will be written. They are preceded by arrows, to distinguish them from input entries. The results of each consecutive list of input entries will be written to the subsequent consecutive list of output entries.
  • The library jars are not copied to the output jars; they contain class files that are used by class files in the program jars and that are necessary for correct processing. This list typically at least contains the targeted Java runtime jar.

Each of these lists can be edited by means of a couple of buttons on the right-hand side:

Add input... opens a file chooser to add an input entry to the list of program jars.
Add output... opens a file chooser to add an output entry to the list of program jars.
Add... opens a file chooser to add an entry to the list of library jars.
Edit... opens a file chooser to edit the selected entry in the list.
Filter... opens a text entry field to add or edit the filters of the selected entries in the list.
Remove removes the selected entries from the list.
Move up moves the selected entries one position up the list.
Move down moves the selected entries one position down the list.
Move to libraries moves the selected entries in the list of program jars to the list of library jars.
Move to program moves the selected entries in the list of library jars to the list of program jars.

Filters allow to filter files based on their names. One can specify filters for class file names and resource file names, for jar file names, for war file names, for ear file names, and for zip file names. Multiple entries in the program list only make sense when combined with filters; each output file is written to the first entry with a matching filter.

Input entries that are currently not readable are colored red.

The order of the entries in each list may matter, as the first occurrence of any duplicate entries gets precedence, just as in conventional class paths.

Corresponding configuration options:

The Shrinking Tab

The Shrinking tab presents a number of options that affect the shrinking step. The basic options are followed by a few lists of classes and class members (fields and methods) that must be protected from shrinking (and implicitly from obfuscation as well).

The fixed lists contain predefined entries that are typically useful for many applications. Each of these entries can be toggled by means of a check box. The text field following each entry allows to constrain the applicable classes by means of a comma-separated list of wildcarded, fully-qualified class names. The default is "*", which means that all input classes of the corresponding type are considered.

For example, checking the Applications entry and filling in "myapplications.**" after it would mean: keep all classes that have main methods in the "myapplications" package and all of its subpackages.

The variable list at the bottom allows to define additional entries yourself. The list can be edited by means of a couple of buttons on the right-hand side:

Add... opens a window to add a new entry to the list.
Edit... opens a window to edit the selected entry in the list.
Remove removes the selected entries from the list.
Move up moves the selected entries one position up the list.
Move down moves the selected entries one position down the list.

The interface windows allow to specify classes, fields, and methods. They contain text fields and check boxes to constrain these items. They have Ok and Cancel buttons to apply or to cancel the operation.

For example, your application may be creating some classes dynamically using Class.forName. You should then specify them here, so they are kept by their original names. Press the Add... button to open the class window. Fill out the fully-qualified class name in the Code text field, and press the Ok button. Repeat this for all required classes. Wildcards can be helpful to specify a large number of related classes in one go. If you want to specify all implementations of a certain interface, fill out the fully qualified interface name in the Extends/implements class instead.

For more advanced settings, it is advisable to become familiar with ProGuard's configuration options through the Usage section and the Examples section. We'll suffice with a brief overview of the three dialogs provided by the GUI.

The keep class dialog appears when adding or editing new special keep entries. It has text fields and selections for specifying and constraining classes and class members to keep. The Advanced options / Basic options button at the bottom of the dialog allows to toggle showing the advanced options.

  • The Comments text field allows to add optional comments to this entry. The comments will identify the entry in the list and they will appear as comments in the configuration file.
  • The Keep selection allows to specify whether you want to protect the specified classes and their specified class members, or just the specified class members from the specified classes, or the specified classes and the specified class members, if the class members are present. Note that class members will only be protected if they are explicitly specified, even if only by means of a wildcard.
  • The Allow selection allows to specify whether you want to allow the the specified classes and their specified class members to be shrunk, optimized and/or obfuscated.
  • The Access selections allows to specify constraints on the class or classes, based on their access modifiers.
  • The Annotation text field takes the fully-qualified name of an annotation that is required for matching classes. The annotation name can contain wildcards. This is an advanced option for defining keep annotations.
  • The Class text field takes the fully-qualified name of the class or classes. The class name can contain wildcards.
  • The Annotation text field takes the fully-qualified name of an annotation that is required for the class or interface that the above class must extend. The annotation name can contain wildcards. This is an advanced option for defining keep annotations.
  • The Extends/implements class text field takes the fully-qualified name of the class or interface that the above classes must extend.
  • The Class members list allows to specify a list of fields and methods to keep. It can be edited by means of a list of buttons on the right-hand side.

The keep field dialog appears when adding or editing fields within the above dialog. It has text fields and selections for specifying and constraining fields to keep. Again, the Advanced options / Basic options button at the bottom of the dialog allows to toggle showing the advanced options.

  • The Access selections allows to specify constraints on the field or fields, based on their access modifiers.
  • The Annotation text field takes the fully-qualified name of an annotation that is required for matching fields. The annotation name can contain wildcards. This is an advanced option for defining keep annotations.
  • The Return type text field takes the fully-qualified type of the field or fields. The type can contain wildcards.
  • The Name text field takes the name of the field or fields. The field name can contain wildcards.

Similarly, the keep method dialog appears when adding or editing methods within the keep class dialog. It has text fields and selections for specifying and constraining methods to keep. Again, the Advanced options / Basic options button at the bottom of the dialog allows to toggle showing the advanced options.

  • The Access selections allows to specify constraints on the method or methods, based on their access modifiers.
  • The Annotation text field takes the fully-qualified name of an annotation that is required for matching methods. The annotation name can contain wildcards. This is an advanced option for defining keep annotations.
  • The Return type text field takes the fully-qualified type of the method or methods. The type can contain wildcards.
  • The Name text field takes the name of the method or methods. The method name can contain wildcards.
  • The Arguments text field takes the comma-separated list of fully-qualified method arguments. Each of these arguments can contain wildcards.

Corresponding configuration options:

The Obfuscation Tab

The Obfuscation tab presents a number of options that affect the obfuscation step. The basic options are followed by a few lists of classes and class members (fields and methods) that must be protected from obfuscation (but not necessarily from shrinking).

The lists are manipulated in the same way as in the Shrinking Tab.

Corresponding configuration options:

The Optimization Tab

The Optimization tab presents a number of options that affect the optimization step. The basic options are followed by a few lists of class method calls that can be removed if ProGuard can determine that their results are not being used.

The lists are manipulated in much the same way as in the Shrinking Tab.

Corresponding configuration options:

The Information Tab

The Information tab presents a number of options for preverification and targeting, and for the information that ProGuard returns when processing your code. The bottom list allows you to query ProGuard about why given classes and class members are being kept in the shrinking step.

Corresponding configuration options:

The Process Tab

The Process tab has an output console for displaying the configuration and the messages while processing. There are three important buttons at the bottom:

View configuration displays the current ProGuard configuration in the console.
Save configuration... opens a file chooser to save the current ProGuard configuration.
Process! executes ProGuard with the current configuration.

The ReTrace Tab

The ReTrace tab has a panel with a few settings, an input text area for the obfuscated stack trace, and an output console to view the de-obfuscated stack trace:
  • The Verbose check box in the settings panel allows to toggle between normal mode and verbose mode.
  • The Mapping file text field takes the name of the required mapping file that ProGuard wrote while processing the original code. The file name can be entered manually or by means of the Browse... button that opens a file chooser.
  • The Obfuscated stack trace text area allows to enter the stack trace, typically by copying and pasting it from elsewhere. Alternatively, it can be loaded from a file by means of the load button below.
There are two buttons at the bottom:

Load stack trace... opens a file chooser to load an obfuscated stack trace.
ReTrace! executes ReTrace with the current settings.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/refcard.html0000644000175000017500000004542511745462051016301 0ustar ericeric ProGuard Reference Card

ProGuard Reference Card

Usage

java -jar proguard.jar options ...

  Typically:

java -jar proguard.jar @myconfig.pro

Options

@filename Short for '-include filename'.
-include filename Read configuration options from the given file.
-basedirectory directoryname Specifies the base directory for subsequent relative file names.
-injars class_path Specifies the program jars (or wars, ears, zips, or directories).
-outjars class_path Specifies the names of the output jars (or wars, ears, zips, or directories).
-libraryjars class_path Specifies the library jars (or wars, ears, zips, or directories).
-skipnonpubliclibraryclasses Ignore non-public library classes.
-dontskipnonpubliclibraryclasses Don't ignore non-public library classes (the default).
-dontskipnonpubliclibraryclassmembers Don't ignore package visible library class members.
-keepdirectories [directory_filter] Keep the specified directories in the output jars (or wars, ears, zips, or directories).
-target version Set the given version number in the processed classes.
-forceprocessing Process the input, even if the output seems up to date.
-keep [,modifier,...] class_specification Preserve the specified classes and class members.
-keepclassmembers [,modifier,...] class_specification Preserve the specified class members, if their classes are preserved as well.
-keepclasseswithmembers [,modifier,...] class_specification Preserve the specified classes and class members, if all of the specified class members are present.
-keepnames class_specification Preserve the names of the specified classes and class members (if they aren't removed in the shrinking step).
-keepclassmembernames class_specification Preserve the names of the specified class members (if they aren't removed in the shrinking step).
-keepclasseswithmembernames class_specification Preserve the names of the specified classes and class members, if all of the specified class members are present (after the shrinking step).
-printseeds [filename] List classes and class members matched by the various -keep options, to the standard output or to the given file.
-dontshrink Don't shrink the input class files.
-printusage [filename] List dead code of the input class files, to the standard output or to the given file.
-whyareyoukeeping class_specification Print details on why the given classes and class members are being kept in the shrinking step.
-dontoptimize Don't optimize the input class files.
-optimizations optimization_filter The optimizations to be enabled and disabled.
-optimizationpasses n The number of optimization passes to be performed.
-assumenosideeffects class_specification Assume that the specified methods don't have any side effects, while optimizing.
-allowaccessmodification Allow the access modifiers of classes and class members to be modified, while optimizing.
-mergeinterfacesaggressively Allow any interfaces to be merged, while optimizing.
-dontobfuscate Don't obfuscate the input class files.
-printmapping [filename] Print the mapping from old names to new names for classes and class members that have been renamed, to the standard output or to the given file.
-applymapping filename Reuse the given mapping, for incremental obfuscation.
-obfuscationdictionary filename Use the words in the given text file as obfuscated field names and method names.
-classobfuscationdictionary filename Use the words in the given text file as obfuscated class names.
-packageobfuscationdictionary filename Use the words in the given text file as obfuscated package names.
-overloadaggressively Apply aggressive overloading while obfuscating.
-useuniqueclassmembernames Ensure uniform obfuscated class member names for subsequent incremental obfuscation.
-dontusemixedcaseclassnames Don't generate mixed-case class names while obfuscating.
-keeppackagenames [package_filter] Keep the specified package names from being obfuscated.
-flattenpackagehierarchy [package_name] Repackage all packages that are renamed into the single given parent package.
-repackageclasses [package_name] Repackage all class files that are renamed into the single given package.
-keepattributes [attribute_filter] Preserve the given optional attributes; typically Exceptions, InnerClasses, Signature, Deprecated, SourceFile, SourceDir, LineNumberTable, LocalVariableTable, LocalVariableTypeTable, Synthetic, EnclosingMethod, and *Annotation*.
-keepparameternames Keep the parameter names and types of methods that are kept.
-renamesourcefileattribute [string] Put the given constant string in the SourceFile attributes.
-adaptclassstrings [class_filter] Adapt string constants in the specified classes, based on the obfuscated names of any corresponding classes.
-adaptresourcefilenames [file_filter] Rename the specified resource files, based on the obfuscated names of the corresponding class files.
-adaptresourcefilecontents [file_filter] Update the contents of the specified resource files, based on the obfuscated names of the processed classes.
-dontpreverify Don't preverify the processed class files.
-microedition Target the processed class files at Java Micro Edition.
-verbose Write out some more information during processing.
-dontnote [class_filter] Don't print notes about potential mistakes or omissions in the configuration.
-dontwarn [class_filter] Don't warn about unresolved references at all.
-ignorewarnings Print warnings about unresolved references, but continue processing anyhow.
-printconfiguration [filename] Write out the entire configuration in traditional ProGuard style, to the standard output or to the given file.
-dump [filename] Write out the internal structure of the processed class files, to the standard output or to the given file.

Notes:

  • class_path is a list of jars, wars, ears, zips, and directories, with optional filters, separated by path separators.
  • filename can contain Java system properties delimited by '<' and '>'.
  • If filename contains special characters, the entire name should be quoted with single or double quotes.

Overview of Keep Options

Keep From being removed or renamed From being renamed
Classes and class members -keep -keepnames
Class members only -keepclassmembers -keepclassmembernames
Classes and class members, if class members present -keepclasseswithmembers -keepclasseswithmembernames

Keep Option Modifiers

allowshrinking The entry points specified in the keep tag may be shrunk.
allowoptimization The entry points specified in the keep tag may be optimized.
allowobfuscation The entry points specified in the keep tag may be obfuscated.

Class Specifications

[@annotationtype] [[!]public|final|abstract ...] [!]interface|class classname
    [extends|implements [@annotationtype] classname]
[{
    [@annotationtype] [[!]public|private|protected|static|volatile|transient ...] <fields> |
                                                                      (fieldtype fieldname);
    [@annotationtype] [[!]public|private|protected|static|synchronized|native|abstract|strictfp ...] <methods> |
                                                                                           <init>(argumenttype,...) |
                                                                                           classname(argumenttype,...) |
                                                                                           (returntype methodname(argumenttype,...));
    [@annotationtype] [[!]public|private|protected|static ... ] *;
    ...
}]

Notes:

  • Class names must always be fully qualified, i.e. including their package names.
  • Types in classname, annotationtype, returntype, and argumenttype can contain wildcards: '?' for a single character, '*' for any number of characters (but not the package separator), '**' for any number of (any) characters, '%' for any primitive type, '***' for any type, and '...' for any number of arguments.
  • fieldname and methodname can contain wildcards as well: '?' for a single character and '*' for any number of characters.

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/troubleshooting.html0000644000175000017500000012027411737527114020121 0ustar ericeric ProGuard Troubleshooting

Troubleshooting

While preparing a configuration for processing your code, you may bump into a few problems. The following sections discuss some common issues and solutions:

Problems while processing

Unexpected observations after processing

Problems while converting to Android Dalvik bytecode

Problems while preverifying for Java Micro Edition

Problems at run-time

Problems while processing

ProGuard may print out some notes and non-fatal warnings:
Note: can't find dynamically referenced class
ProGuard can't find a class or interface that your code is accessing by means of introspection. You should check if you want to add the jar that contains this class.
Note: ... calls '(...)Class.forName(variable).newInstance()'
ProGuard lists all class casts of dynamically created class instances, like "(MyClass)Class.forName(variable).newInstance()". Depending on your application, you may need to keep the mentioned classes with an option like "-keep class MyClass", or their implementations with an option like "-keep class * implements MyClass". You can switch off these notes by specifying the -dontnote option.
Note: ... accesses a field/method '...' dynamically
ProGuard lists a number of constructs like ".getField("myField")". Depending on your application, you may need to figure out where the mentioned class members are defined and keep them with an option like "-keep class MyClass { MyFieldType myField; }". Otherwise, ProGuard might remove or obfuscate the class members, since it can't know which ones they are exactly. It does list possible candidates, for your information. You can switch off these notes by specifying the -dontnote option.
Note: the configuration keeps the entry point '...', but not the descriptor class '...'
Your configuration contains a -keep option to preserve the given method (or field), but no -keep option for the given class that is an argument type or return type in the method's descriptor. You may then want to keep the class too. Otherwise, ProGuard will obfuscate its name, thus changing the method's signature. The method might then become unfindable as an entry point, e.g. if it is part of a public API. You can switch off these notes by specifying the -dontnote option.
Note: the configuration doesn't specify which class members to keep for class '...'
Your configuration contains a -keepclassmembers/-keepclasseswithmembers option to preserve fields or methods in the given class, but it doesn't specify which fields or methods. This way, the option simply won't have any effect. You probably want to specify one or more fields or methods, as usual between curly braces. You can specify all fields or methods with a wildcard "*;". You can switch off these notes by specifying the -dontnote option.
Note: duplicate definition of program/library class
Your program jars or library jars contain multiple definitions of the listed classes. ProGuard continues processing as usual, only considering the first definitions. The warning may be an indication of some problem though, so it's advisable to remove the duplicates. A convenient way to do so is by specifying filters on the input jars or library jars. You can switch off these notes by specifying the -dontnote option.
Warning: can't write resource ... Duplicate zip entry
Your input jars contain multiple resource files with the same name. ProGuard continues copying the resource files as usual, skipping any files with previously used names. Once more, the warning may be an indication of some problem though, so it's advisable to remove the duplicates. A convenient way to do so is by specifying filters on the input jars. There is no option to switch off these warnings.

ProGuard may terminate when it encounters parsing errors or I/O errors, or some more serious warnings:

Warning: can't find superclass or interface
Warning: can't find referenced class
A class in one of your program jars or library jars is referring to a class or interface that is missing from the input. The output lists both the referencing class(es) and the missing referenced class(es). There can be a few reasons, with their own solutions:

  1. You may have forgotten to specify an essential library. Just like when compiling all code from scratch, you must specify all libraries that the code is referencing, directly or indirectly. If the library should be processed and included in the output, you should specify it with -injars, otherwise you should specify it with -libraryjars.

    For example, if ProGuard complains that it can't find a java.lang class, you have to make sure that you are specifying the run-time library of your platform. For JSE, these are typically packaged in lib/rt.jar (vm.jar for IBM's JVM, and classes.jar in MacOS X). Other platforms like JME and Android have their own run-time libraries. The examples section provides more details for the various platforms.

    If ProGuard still complains that it can't find a javax.crypto class, you probably still have to specify jce.jar, next to the more common rt.jar.

  2. You may have ignored a library because you're absolutely sure it isn't used anyway (your original code runs fine without it). The cleanest solution is to filter out the referencing class or classes from the input, with a filter like "-injars myapplication.jar(!somepackage/SomeUnusedReferencingClass.class)". ProGuard will then skip this class entirely in the input, and it will not bump into the problem of its missing reference. However, you may then have to filter out other classes that are in turn referencing the removed class. In practice, this works best if you can filter out entire unused packages at once, with a wildcard filter like "-injars myapplication.jar(!someunusedpackage/**)".

  3. If you don't feel like filtering out the problematic classes, you can try your luck with the -ignorewarnings option, or even the -dontwarn option. Only use these options if you really know what you're doing though.

    For example, if you're developing for Android, and ProGuard complains that it can't find a java.awt class, then some library that you are using is referring to java.awt. This is a bit shady, since Android doesn't have this package at all, but if your application works anyway, you can let ProGuard accept it with "-dontwarn java.awt.**".

Error: Can't find any super classes of ... (not even immediate super class ...)
Error: Can't find common super class of ... and ...
It seems like you tried to avoid the warnings from the previous paragraph by specifying -ignorewarnings or -dontwarn, but it didn't work out. ProGuard's optimization step and preverification step really need the missing classes to make sense of the code. Preferably, you would solve the problem by adding the missing library, as discussed. If you're sure the class that references the missing class isn't used either, you could also try filtering it out from the input, by adding a filter to the corresponding -injars option: "-injars myapplication.jar(!somepackage/SomeUnusedClass.class)". As a final solution, you could switch off optimization (-dontoptimize) and preverification (-dontpreverify).
Warning: can't find referenced field/method
If there are unresolved references to class members in input classes, your class files are most likely inconsistent. Possibly, some class file didn't get recompiled properly, or some class file was left behind after its source file was removed. Try removing all class files, recompiling them, zipping them up, and running ProGuard again.

If your program classes reside in the same packages as library classes, and refer to their package visible class members, then you should also specify the -dontskipnonpubliclibraryclassmembers option.

Warning: can't find enclosing class/method
If there are unresolved references to classes that are defined inside methods in your input, once more, your class files are most likely inconsistent. Possibly, some class file didn't get recompiled properly, or some class file was left behind after its source file was removed. Try removing all class files, recompiling them, zipping them up, and running ProGuard again.
Warning: library class ... depends on program class ...
If any of your library classes depend on your program classes, by extending, implementing or just referencing them, your processed code will generally be unusable. Program classes can depend on library classes, but not the other way around. Program classes are processed, while library classes always remain unchanged. It is therefore impossible to adapt references from library classes to program classes, for instance if the program classes are renamed. You should define a clean separation between program code (specified with -injars) and library code (specified with -libraryjars), and try again.
Warning: class file ... unexpectedly contains class ...
The given class file contains a definition for the given class, but the directory name of the file doesn't correspond to the package name of the class. ProGuard will accept the class definition, but the current implementation will not write out the processed version. Please make sure your input classes are packaged correctly. Notably, class files that are in the WEB-INF/classes directory in a war should be packaged in a jar and put in the WEB-INF/lib directory. If you don't mind these classes not being written to the output, you can specify the -ignorewarnings option, or even the -dontwarn option.
Warning: ... is not being kept as ..., but remapped to ...
There is a conflict between a -keep option in the configuration, and the mapping file, in the obfuscation step. The given class name or class member name can't be kept by its original name, as specified in the configuration, but it has to be mapped to the other given name, as specified in the mapping file. You should adapt your configuration or your mapping file to remove the conflict. Alternatively, if you're sure the renaming won't hurt, you can specify the -ignorewarnings option, or even the -dontwarn option.
Warning: field/method ... can't be mapped to ...
There is a conflict between some new program code and the mapping file, in the obfuscation step. The given class member can't be mapped to the given name, because it would conflict with another class member that is already being mapped to the same name. This can happen if you are performing incremental obfuscation, applying an obfuscation mapping file from an initial obfuscation step. For instance, some new class may have been added that extends two existing classes, introducing a conflict in the name space of its class members. If you're sure the class member receiving another name than the one specified won't hurt, you can specify the -ignorewarnings option, or even the -dontwarn option. Note that you should always use the -useuniqueclassmembernames option in the initial obfuscation step, in order to reduce the risk of conflicts.
Error: Unsupported class version number
You are trying to process class files compiled for a recent version of Java that your copy of ProGuard doesn't support yet. You should check on-line if there is a more recent release.
Error: You have to specify '-keep' options
You either forgot to specify -keep options, or you mistyped the class names. ProGuard has to know exactly what you want to keep: an application, an applet, a servlet, a midlet,..., or any combination of these. Without the proper seed specifications, ProGuard would shrink, optimize, or obfuscate all class files away.
Error: Expecting class path separator ';' before 'Files\Java\...' (in Windows)
If the path of your run-time jar contains spaces, like in "Program Files", you have to enclose it with single or double quotes, as explained in the section on file names. This is actually true for all file names containing special characters, on all platforms.
Error: Can't read [.../lib/rt.jar] (No such file or directory) (in MacOS X)
In MacOS X, the run-time classes may be in a different place than on most other platforms. You'll then have to adapt your configuration, replacing the path <java.home>/lib/rt.jar by <java.home>/../Classes/classes.jar.
Internal problem starting the ProGuard GUI (Cannot write XdndAware property) (in Linux)
In Linux, at least with Java 6, the GUI may not start properly, due to Sun Bug #7027598. The work-around at this time is to specify the JVM option -DsuppressSwingDropSupport=true when running the GUI.

Should ProGuard crash while processing your application:

OutOfMemoryError
You can try increasing the heap size of the Java virtual machine (with the usual -Xms and -Xmx options). You can also reduce the amount of memory that ProGuard needs by removing unnecessary library jars from your configuration, or by filtering out unused library packages and classes. Remember that only classes or interfaces that are extended or implemented by classes in your input jars are required.
StackOverflowError
This error might occur when processing a large code base on Windows (surprisingly, not so easily on Linux). In theory, increasing the stack size of the Java virtual machine (with the usual -Xss option) should help too. In practice however, the -Xss setting doesn't have any effect on the main thread, due to Sun Bug #4362291. As a result, this solution will only work when running ProGuard in a different thread, e.g. from its GUI.
Unexpected error
ProGuard has encountered an unexpected condition, typically in the optimization step. It may or may not recover. You should be able to avoid it using the -dontoptimize option. In any case, please report the problem, preferably with the simplest example that causes ProGuard to crash.
Otherwise...
Maybe your class files are corrupt. See if recompiling them and trying again helps. If not, please report the problem, preferably with the simplest example that causes ProGuard to crash.

Unexpected observations after processing

If ProGuard seems to run fine, but your processed code doesn't look right, there might be a couple of reasons:
Disappearing classes
If you are working on Windows and it looks like some classes have disappeared from your output, you should make sure you're not writing your output class files to a directory (or unpacking the output jar). On platforms with case-insensitive file systems, such as Windows, unpacking tools often let class files with similar lower-case and upper-case names overwrite each other. If you really can't switch to a different operating system, you could consider using ProGuard's -dontusemixedcaseclassnames option.

Also, you should make sure your class files are in directories that correspond to their package names. ProGuard will read misplaced class files, but it will currently not write their processed versions. Notably, class files that are in the WEB-INF/classes directory in a war should be packaged in a jar and put in the WEB-INF/lib directory.

Classes or class members not being kept
If ProGuard is not keeping the right classes or class members, make sure you are using fully qualified class names. If the package name of some class is missing, ProGuard won't match the elements that you might be expecting. It may help to double-check for typos too. You can use the -printseeds option to see which elements are being kept exactly.

If you are using marker interfaces to keep other classes, the marker interfaces themselves are probably being removed in the shrinking step. You should therefore always explicitly keep any marker interfaces, with an option like "-keep interface MyMarkerInterface".

Similarly, if you are keeping classes based on annotations, you may have to avoid that the annotation classes themselves are removed in the shrinking step. You can explicitly keep all annotation classes in your program code with an option like "-keep @interface *".

Variable names not being obfuscated
If the names of the local variables and parameters in your obfuscated code don't look obfuscated, because they suspiciously resemble the names of their types, it's probably because the decompiler that you are using is coming up with those names. ProGuard's obfuscation step does remove the original names entirely, unless you explicitly keep the LocalVariableTable or LocalVariableTypeTable attributes.

Problems while converting to Android Dalvik bytecode

If ProGuard seems to run fine, but the dx tool in the Android SDK subsequently fails with an error:
SimException: local variable type mismatch
This error indicates that ProGuard's optimization step has not been able to maintain the correct debug information about local variables. This can happen if some code is optimized radically. Possible work-arounds: let the java compiler not produce debug information (-g:none), or let ProGuard's obfuscation step remove the debug information again (by not keeping the attributes LocalVariableTable and LocalVariableTypeTable with -keepattributes), or otherwise just disable optimization (-dontoptimize).
Conversion to Dalvik format failed with error 1
This error may have various causes, but if dx is tripping over some code processed by ProGuard, you should make sure that you are using the latest version of ProGuard. You can just copy the ProGuard jars to android-sdk/tools/proguard/lib. If that doesn't help, please report the problem, preferably with the simplest example that still brings out the error.

Problems while preverifying for Java Micro Edition

If ProGuard seems to run fine, but the external preverifier subsequently produces errors, it's usually for a single reason:
InvalidClassException, class loading error, or verification error
If you get any such message from the preverifier, you are probably working on a platform with a case-insensitive file system, such as Windows. The preverify tool always unpacks the jars, so class files with similar lower-case and upper-case names overwrite each other. You can use ProGuard's -dontusemixedcaseclassnames option to work around this problem.

If the above doesn't help, there is probably a bug in the optimization step of ProGuard. Make sure you are using the latest version. You should be able to work around the problem by using the -dontoptimize option. You can check the bug database to see if it is a known problem (often with a fix). Otherwise, please report it, preferably with the simplest example on which you can find ProGuard to fail.

Note that it is no longer necessary to use an external preverifier. With the -microedition option, ProGuard will preverify the class files for Java Micro Edition.

Problems at run-time

If ProGuard runs fine, but your processed application doesn't work, there might be several reasons:
Stack traces without class names or line numbers
If your stack traces don't contain any class names or lines numbers, even though you are keeping the proper attributes, make sure this debugging information is present in your compiled code to start with. Notably the Ant javac task has debugging information switched off by default.
NoClassDefFoundError
Your class path is probably incorrect. It should at least contain all library jars and, of course, your processed program jar.
ClassNotFoundException
Your code is probably calling Class.forName, trying to create the missing class dynamically. ProGuard can only detect constant name arguments, like Class.forName("mypackage.MyClass"). For variable name arguments like Class.forName(someClass), you have to keep all possible classes using the appropriate -keep option, e.g. "-keep class mypackage.MyClass" or "-keep class * implements mypackage.MyInterface".
NoSuchMethodException
Your code is probably calling something like myClass.getMethod, trying to find some method dynamically. Since ProGuard can't always detect this automatically, you have to keep the missing method in using the appropriate -keep option, e.g. "-keep class mypackage.MyClass { void myMethod(); }".

More specifically, if the method reported as missing is values or valueOf, you probably have to keep some methods related to enumerations.

MissingResourceException or NullPointerException
Your processed code may be unable to find some resource files. ProGuard simply copies resource files over from the input jars to the output jars. Their names and contents remain unchanged, unless you specify the options -adaptresourcefilenames and/or -adaptresourcefilecontents.

Furthermore, directory entries in jar files aren't copied, unless you specify the option -keepdirectories. Note that Sun advises against calling Class.getResource() for directories (Sun Bug #4761949).

Disappearing annotations
By default, the obfuscation step removes all annotations. If your application relies on annotations to function properly, you should explicitly keep them with -keepattributes *Annotation*.
Invalid or corrupt jarfile
You are probably starting your application with the java option -jar instead of the option -classpath. The java virtual machine returns with this error message if your jar doesn't contain a manifest file (META-INF/MANIFEST.MF), if the manifest file doesn't specify a main class (Main-Class: ...), or if the jar doesn't contain this main class. You should then make sure that the input jar contains a valid manifest file to start with, that this manifest file is the one that is copied (the first manifest file that is encountered), and that the main class is kept in your configuration,
InvalidJarIndexException: Invalid index
At least one of your processed jar files contains an index file META-INF/INDEX.LIST, listing all class files in the jar. ProGuard by default copies files like these unchanged. ProGuard may however remove or rename classes, thus invalidating the file. You should filter the index file out of the input (-injars in.jar(!META-INF/INDEX.LIST)) or update the file after having applied ProGuard (jar -i out.jar).
InvalidClassException, class loading error, or verification error (in Java Micro Edition)
If you get such an error in Java Micro Edition, you may have forgotten to specify the -microedition option, so the processed class files are preverified properly.
Error: No Such Field or Method, Error verifying method (in a Java Micro Edition emulator)
If you get such a message in a Motorola or Sony Ericsson phone emulator, it's because these emulators don't like packageless classes and/or overloaded fields and methods. You can work around it by not using the options -repackageclasses '' and -overloadaggressively. If you're using the JME WTK plugin, you can adapt the configuration proguard/wtk/default.pro that's inside the proguard.jar.
Failing midlets (on a Java Micro Edition device)
If your midlet runs in an emulator and on some devices, but not on some other devices, this is probably due to a bug in the latter devices. For some older Motorola and Nokia phones, you might try specifying the -useuniqueclassmembernames option. It avoids overloading class member names, which triggers a bug in their java virtual machine.

You might also try using the -dontusemixedcaseclassnames option. Even if the midlet has been properly processed and then preverified on a case-sensitive file system, the device itself might not like the mixed-case class names. Notably, the Nokia N-Gage emulator works fine, but the actual device seems to exhibit this problem.

Disappearing loops
If your code contains empty busy-waiting loops, ProGuard's optimization step may remove them. More specifically, this happens if a loop continuously checks the value of a non-volatile field that is changed in a different thread. The specifications of the Java Virtual Machine require that you always mark fields that are accessed across different threads without further synchronization as volatile. If this is not possible for some reason, you'll have to switch off optimization using the -dontoptimize option.
SecurityException: SHA1 digest error
You may have forgotten to sign your program jar after having processed it with ProGuard.
ClassCastException: class not an enum, or
IllegalArgumentException: class not an enum type
You should make sure you're preserving the special methods of enumeration types, which the run-time environment calls by introspection. The required options are shown in the examples.
ArrayStoreException: sun.reflect.annotation.EnumConstantNotPresentExceptionProxy
You are probably processing annotations involving enumerations. Again, you should make sure you're preserving the special methods of the enumeration type, as shown in the examples.
CompilerError: duplicate addition
You are probably compiling or running some code that has been obfuscated with the -overloadaggressively option. This option triggers a bug in sun.tools.java.MethodSet.add in Sun's JDK 1.2.2, which is used for (dynamic) compilation. You should then avoid this option.
ClassFormatError: repetitive field name/signature
You are probably processing some code that has been obfuscated before with the -overloadaggressively option. You should then use the same option again in the second processing round.
ClassFormatError: Invalid index in LocalVariableTable in class file
If you are keeping the LocalVariableTable or LocalVariableTypeTable attributes, ProGuard's optimizing step is sometimes unable to update them consistently. You should then let the obfuscation step remove these attributes or disable the optimization step.
NoSuchMethodError or AbstractMethodError
You should make sure you're not writing your output class files to a directory on a platform with a case-insensitive file system, such as Windows. Please refer to the section about disappearing classes for details.

Furthermore, you should check whether you have specified your program jars and library jars properly. Program classes can refer to library classes, but not the other way around.

If all of this seems ok, perhaps there's a bug in ProGuard (gasp!). If so, please report it, preferably with the simplest example on which you can find ProGuard to fail.

VerifyError
Verification errors when executing a program are almost certainly the result of a bug in the optimization step of ProGuard. Make sure you are using the latest version. You should be able to work around the problem by using the -dontoptimize option. You can check the bug database to see if it is a known problem (often with a fix). Otherwise, please report it, preferably with the simplest example on which ProGuard fails.

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/optimizations.html0000644000175000017500000001466711736333522017610 0ustar ericeric Optimizations

Optimizations

The optimization step of ProGuard can be switched off with the -dontoptimize option. For more fine-grained control over individual optimizations, experts can use the -optimizations option, with a filter based on the optimization names listed below. The filter works like any filter in ProGuard.

The following wildcards are supported:
? matches any single character in an optimization name.
* matches any part of an optimization name.
An optimization that is preceded by an exclamation mark '!' is excluded from further attempts to match with subsequent optimization names in the filter. Make sure to specify filters correctly, since they are not checked for potential typos.

For example, "code/simplification/variable,code/simplification/arithmetic" only performs the two specified peephole optimizations.

For example, "!method/propagation/*" performs all optimizations, except the ones that propagate values between methods.

For example, "!code/simplification/advanced,code/simplification/*" only performs all peephole optimizations.

Some optimizations necessarily imply other optimizations. These are then indicated. Note that the list is likely to change over time, as optimizations are added and reorganized.

class/marking/final
Marks classes as final, whenever possible.
class/merging/vertical
Merges classes vertically in the class hierarchy, whenever possible.
class/merging/horizontal
Merges classes horizontally in the class hierarchy, whenever possible.
(⇒ code/removal/advanced)
field/removal/writeonly
Removes write-only fields.
field/marking/private
Marks fields as private, whenever possible.
(⇒ code/simplification/advanced)
field/propagation/value
Propagates the values of fields across methods.
method/marking/private
Marks methods as private, whenever possible (devirtualization).
(⇒ code/removal/advanced)
method/marking/static
Marks methods as static, whenever possible (devirtualization).
method/marking/final
Marks methods as final, whenever possible.
(⇒ code/removal/advanced)
method/removal/parameter
Removes unused method parameters.
(⇒ code/simplification/advanced)
method/propagation/parameter
Propagates the values of method parameters from method invocations to the invoked methods.
(⇒ code/simplification/advanced)
method/propagation/returnvalue
Propagates the values of method return values from methods to their invocations.
method/inlining/short
Inlines short methods.
method/inlining/unique
Inlines methods that are only called once.
method/inlining/tailrecursion
Simplifies tail recursion calls, whenever possible.
code/merging
Merges identical blocks of code by modifying branch targets.
code/simplification/variable
Performs peephole optimizations for variable loading and storing.
code/simplification/arithmetic
Performs peephole optimizations for arithmetic instructions.
code/simplification/cast
Performs peephole optimizations for casting operations.
code/simplification/field
Performs peephole optimizations for field loading and storing.
(⇒ code/removal/simple)
code/simplification/branch
Performs peephole optimizations for branch instructions.
code/simplification/string
Performs peephole optimizations for constant strings.
(best used with code/removal/advanced)
code/simplification/advanced
Simplifies code based on control flow analysis and data flow analysis.
(⇒ code/removal/exception)
code/removal/advanced
Removes dead code based on control flow analysis and data flow analysis.
(⇒ code/removal/exception)
code/removal/simple
Removes dead code based on a simple control flow analysis.
code/removal/variable
Removes unused variables from the local variable frame.
code/removal/exception
Removes exceptions with empty try blocks.
code/allocation/variable
Optimizes variable allocation on the local variable frame.

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/attention.gif0000644000175000017500000000160011163773610016464 0ustar ericericGIF89a@@F ##..2277;;<<??IIMMWWXX]]__ccddgghhkkllmmooppvv! ,@@«¼Fʴ9F9մ"F"Բ ?F? 㪼++쨼EFE6- m' P/ѡW!t@! 8r <^`C\Ep؁OvWhWh%^ k> N"! Xl!6A qӠְEt DDmw/T\\FTvTҁYba6*o!?cAF\Ppږq=t C ReTrace Examples

Examples

Some typical example uses:
  1. Restoring a stack trace with line numbers
  2. Restoring a stack trace with line numbers (verbose)
  3. Restoring a stack trace without line numbers

Restoring a stack trace with line numbers

Assume for instance ProGuard itself has been obfuscated using the following extra options:
-printmapping proguard.map

-renamesourcefileattribute ProGuard
-keepattributes SourceFile,LineNumberTable

Now assume the processed application throws an exception, and we have saved the stack trace in proguard.trace, shown below. Of course, in real life ProGuard rarely throws exceptions, so this is a purposely generated exception. :)

Exception in thread "main" java.lang.Error: Random exception
        at pro.bY.a(ProGuard:576)
        at pro.bO.a(ProGuard:431)
        at pro.bj.a(ProGuard:145)
        at pro.bY.a(ProGuard:522)
        at pro.bj.a(ProGuard:129)
        at pro.bN.a(ProGuard:125)
        at pro.bY.a(ProGuard:251)
        at pro.bY.a(ProGuard:229)
        at pro.l.a(ProGuard:55)
        at pro.bo.b(ProGuard:405)
        at pro.ci.a(ProGuard:51)
        at pro.bo.a(ProGuard:356)
        at pro.be.a(ProGuard:109)
        at pro.bo.a(ProGuard:356)
        at pro.be.a(ProGuard:186)
        at pro.bg.a(ProGuard:369)
        at pro.bY.a(ProGuard:286)
        at pro.bh.a(ProGuard:55)
        at pro.bg.b(ProGuard:408)
        at pro.bY.a(ProGuard:190)
        at pro.bg.a(ProGuard:369)
        at pro.M.a(ProGuard:110)
        at pro.bY.a(ProGuard:449)
        at pro.M.a(ProGuard:99)
        at pro.bo.a(ProGuard:372)
        at pro.bY.a(ProGuard:649)
        at pro.bY.a(ProGuard:112)
        at pro.P.a(ProGuard:66)
        at pro.p.a(ProGuard:83)
        at pro.bU.a(ProGuard:69)
        at pro.bo.a(ProGuard:356)
        at pro.J.a(ProGuard:149)
        at pro.I.a(ProGuard:49)
        at pro.J.a(ProGuard:105)
        at pro.cf.c(ProGuard:370)
        at pro.cf.a(ProGuard:317)
        at pro.bc.a(ProGuard:55)
        at proguard.ProGuard.a(ProGuard:363)
        at proguard.ProGuard.c(ProGuard:187)
        at proguard.ProGuard.b(ProGuard:385)
        at proguard.ProGuard.main(ProGuard:429)

We can then use the following command to recover the stack trace:

java -jar retrace.jar proguard.map proguard.trace

The output will look as follows:

Exception in thread "main" java.lang.Error: Random exception
        at proguard.shrink.UsageMarker.visitInstruction(ProGuard:576)
        at proguard.classfile.instruction.GenericInstruction.accept(ProGuard:431)
        at proguard.classfile.CodeAttrInfo.instructionsAccept(ProGuard:145)
        at proguard.shrink.UsageMarker.visitCodeAttrInfo(ProGuard:522)
        at proguard.classfile.CodeAttrInfo.accept(ProGuard:129)
        at proguard.classfile.ProgramMemberInfo.attributesAccept(ProGuard:125)
        at proguard.shrink.UsageMarker.visitMemberInfo(ProGuard:251)
        at proguard.shrink.UsageMarker.visitProgramMethodInfo(ProGuard:229)
        at proguard.classfile.ProgramMethodInfo.accept(ProGuard:55)
        at proguard.classfile.ProgramClassFile.methodAccept(ProGuard:405)
        at proguard.classfile.visitor.NamedMethodVisitor.visitProgramClassFile(ProGuard:51)
        at proguard.classfile.ProgramClassFile.accept(ProGuard:356)
        at proguard.classfile.visitor.ClassFileUpDownTraveler.visitProgramClassFile(ProGuard:109)
        at proguard.classfile.ProgramClassFile.accept(ProGuard:356)
        at proguard.classfile.visitor.ClassFileUpDownTraveler.visitLibraryClassFile(ProGuard:186)
        at proguard.classfile.LibraryClassFile.accept(ProGuard:369)
        at proguard.shrink.UsageMarker.visitLibraryMethodInfo(ProGuard:286)
        at proguard.classfile.LibraryMethodInfo.accept(ProGuard:55)
        at proguard.classfile.LibraryClassFile.methodsAccept(ProGuard:408)
        at proguard.shrink.UsageMarker.visitLibraryClassFile(ProGuard:190)
        at proguard.classfile.LibraryClassFile.accept(ProGuard:369)
        at proguard.classfile.ClassCpInfo.referencedClassAccept(ProGuard:110)
        at proguard.shrink.UsageMarker.visitClassCpInfo(ProGuard:449)
        at proguard.classfile.ClassCpInfo.accept(ProGuard:99)
        at proguard.classfile.ProgramClassFile.constantPoolEntryAccept(ProGuard:372)
        at proguard.shrink.UsageMarker.markCpEntry(ProGuard:649)
        at proguard.shrink.UsageMarker.visitProgramClassFile(ProGuard:112)
        at proguard.classfile.visitor.VariableClassFileVisitor.visitProgramClassFile(ProGuard:66)
        at proguard.classfile.visitor.MultiClassFileVisitor.visitProgramClassFile(ProGuard:83)
        at proguard.classfile.visitor.FilteredClassFileVisitor.visitProgramClassFile(ProGuard:69)
        at proguard.classfile.ProgramClassFile.accept(ProGuard:356)
        at proguard.classfile.ClassPool.classFileAccept(ProGuard:149)
        at proguard.classfile.visitor.NamedClassFileVisitor.visitClassPool(ProGuard:49)
        at proguard.classfile.ClassPool.accept(ProGuard:105)
        at proguard.KeepCommand.executeShrinkingPhase(ProGuard:370)
        at proguard.KeepCommand.execute(ProGuard:317)
        at proguard.CompoundCommand.execute(ProGuard:55)
        at proguard.ProGuard.executeCommands(ProGuard:363)
        at proguard.ProGuard.shrink(ProGuard:187)
        at proguard.ProGuard.execute(ProGuard:385)
        at proguard.ProGuard.main(ProGuard:429)

Restoring a stack trace with line numbers (verbose)

In the previous example, we could also use the verbose flag:
java -jar retrace.jar -verbose proguard.map proguard.trace

The output will then look as follows:

Exception in thread "main" java.lang.Error: Random exception
        at proguard.shrink.UsageMarker.void visitInstruction(proguard.classfile.ClassFile,proguard.classfile.instruction.Instruction)(ProGuard:576)
        at proguard.classfile.instruction.GenericInstruction.void accept(proguard.classfile.ClassFile,proguard.classfile.instruction.InstructionVisitor)(ProGuard:431)
        at proguard.classfile.CodeAttrInfo.void instructionsAccept(proguard.classfile.ClassFile,proguard.classfile.instruction.InstructionVisitor)(ProGuard:145)
        at proguard.shrink.UsageMarker.void visitCodeAttrInfo(proguard.classfile.ClassFile,proguard.classfile.CodeAttrInfo)(ProGuard:522)
        at proguard.classfile.CodeAttrInfo.void accept(proguard.classfile.ClassFile,proguard.classfile.visitor.AttrInfoVisitor)(ProGuard:129)
        at proguard.classfile.ProgramMemberInfo.void attributesAccept(proguard.classfile.ProgramClassFile,proguard.classfile.visitor.AttrInfoVisitor)(ProGuard:125)
        at proguard.shrink.UsageMarker.void visitMemberInfo(proguard.classfile.ProgramClassFile,proguard.classfile.ProgramMemberInfo)(ProGuard:251)
        at proguard.shrink.UsageMarker.void visitProgramMethodInfo(proguard.classfile.ProgramClassFile,proguard.classfile.ProgramMethodInfo)(ProGuard:229)
        at proguard.classfile.ProgramMethodInfo.void accept(proguard.classfile.ProgramClassFile,proguard.classfile.visitor.MemberInfoVisitor)(ProGuard:55)
        at proguard.classfile.ProgramClassFile.void methodAccept(proguard.classfile.visitor.MemberInfoVisitor,java.lang.String,java.lang.String)(ProGuard:405)
        at proguard.classfile.visitor.NamedMethodVisitor.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:51)
        at proguard.classfile.ProgramClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:356)
        at proguard.classfile.visitor.ClassFileUpDownTraveler.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:109)
        at proguard.classfile.ProgramClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:356)
        at proguard.classfile.visitor.ClassFileUpDownTraveler.void visitLibraryClassFile(proguard.classfile.LibraryClassFile)(ProGuard:186)
        at proguard.classfile.LibraryClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:369)
        at proguard.shrink.UsageMarker.void visitLibraryMethodInfo(proguard.classfile.LibraryClassFile,proguard.classfile.LibraryMethodInfo)(ProGuard:286)
        at proguard.classfile.LibraryMethodInfo.void accept(proguard.classfile.LibraryClassFile,proguard.classfile.visitor.MemberInfoVisitor)(ProGuard:55)
        at proguard.classfile.LibraryClassFile.void methodsAccept(proguard.classfile.visitor.MemberInfoVisitor)(ProGuard:408)
        at proguard.shrink.UsageMarker.void visitLibraryClassFile(proguard.classfile.LibraryClassFile)(ProGuard:190)
        at proguard.classfile.LibraryClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:369)
        at proguard.classfile.ClassCpInfo.void referencedClassAccept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:110)
        at proguard.shrink.UsageMarker.void visitClassCpInfo(proguard.classfile.ClassFile,proguard.classfile.ClassCpInfo)(ProGuard:449)
        at proguard.classfile.ClassCpInfo.void accept(proguard.classfile.ClassFile,proguard.classfile.visitor.CpInfoVisitor)(ProGuard:99)
        at proguard.classfile.ProgramClassFile.void constantPoolEntryAccept(proguard.classfile.visitor.CpInfoVisitor,int)(ProGuard:372)
        at proguard.shrink.UsageMarker.void markCpEntry(proguard.classfile.ClassFile,int)(ProGuard:649)
        at proguard.shrink.UsageMarker.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:112)
        at proguard.classfile.visitor.VariableClassFileVisitor.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:66)
        at proguard.classfile.visitor.MultiClassFileVisitor.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:83)
        at proguard.classfile.visitor.FilteredClassFileVisitor.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:69)
        at proguard.classfile.ProgramClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:356)
        at proguard.classfile.ClassPool.void classFileAccept(proguard.classfile.visitor.ClassFileVisitor,java.lang.String)(ProGuard:149)
        at proguard.classfile.visitor.NamedClassFileVisitor.void visitClassPool(proguard.classfile.ClassPool)(ProGuard:49)
        at proguard.classfile.ClassPool.void accept(proguard.classfile.visitor.ClassPoolVisitor)(ProGuard:105)
        at proguard.KeepCommand.void executeShrinkingPhase(proguard.classfile.ClassPool,proguard.classfile.ClassPool)(ProGuard:370)
        at proguard.KeepCommand.void execute(int,proguard.classfile.ClassPool,proguard.classfile.ClassPool)(ProGuard:317)
        at proguard.CompoundCommand.void execute(int,proguard.classfile.ClassPool,proguard.classfile.ClassPool)(ProGuard:55)
        at proguard.ProGuard.void executeCommands(int)(ProGuard:363)
        at proguard.ProGuard.void shrink()(ProGuard:187)
        at proguard.ProGuard.void execute(java.lang.String[])(ProGuard:385)
        at proguard.ProGuard.void main(java.lang.String[])(ProGuard:429)

Restoring a stack trace without line numbers

Assume for instance ProGuard itself has been obfuscated using the following extra options, this time without preserving the line number tables:
-printmapping proguard.map

A stack trace proguard.trace will then lack line number information:

Exception in thread "main" java.lang.Error: Random exception
        at pro.bY.a(Unknown Source)
        at pro.bO.a(Unknown Source)
        at pro.bj.a(Unknown Source)
        at pro.bY.a(Unknown Source)
        at pro.bj.a(Unknown Source)
        at pro.bN.a(Unknown Source)
        at pro.bY.a(Unknown Source)
        at pro.bY.a(Unknown Source)
        at pro.l.a(Unknown Source)
        at pro.bo.b(Unknown Source)
        at pro.ci.a(Unknown Source)
        at pro.bo.a(Unknown Source)
        at pro.be.a(Unknown Source)
        at pro.bo.a(Unknown Source)
        at pro.be.a(Unknown Source)
        at pro.bg.a(Unknown Source)
        at pro.bY.a(Unknown Source)
        at pro.bh.a(Unknown Source)
        at pro.bg.b(Unknown Source)
        at pro.bY.a(Unknown Source)
        at pro.bg.a(Unknown Source)
        at pro.M.a(Unknown Source)
        at pro.bY.a(Unknown Source)
        at pro.M.a(Unknown Source)
        at pro.bo.a(Unknown Source)
        at pro.bY.a(Unknown Source)
        at pro.bY.a(Unknown Source)
        at pro.P.a(Unknown Source)
        at pro.p.a(Unknown Source)
        at pro.bU.a(Unknown Source)
        at pro.bo.a(Unknown Source)
        at pro.J.a(Unknown Source)
        at pro.I.a(Unknown Source)
        at pro.J.a(Unknown Source)
        at pro.cf.c(Unknown Source)
        at pro.cf.a(Unknown Source)
        at pro.bc.a(Unknown Source)
        at proguard.ProGuard.a(Unknown Source)
        at proguard.ProGuard.c(Unknown Source)
        at proguard.ProGuard.b(Unknown Source)
        at proguard.ProGuard.main(Unknown Source)

We can still use the same command to recover the stack trace:

java -jar retrace.jar proguard.map proguard.trace

The output will now give a list of alternative original method names for each ambiguous obfuscated method name:

Exception in thread "main" java.lang.Error: Random exception
        at proguard.shrink.UsageMarker.visitProgramClassFile(Unknown Source)
                                       visitLibraryClassFile
                                       visitProgramFieldInfo
                                       visitProgramMethodInfo
                                       visitMemberInfo
                                       visitLibraryFieldInfo
                                       visitLibraryMethodInfo
                                       visitIntegerCpInfo
                                       visitLongCpInfo
                                       visitFloatCpInfo
                                       visitDoubleCpInfo
                                       visitStringCpInfo
                                       visitUtf8CpInfo
                                       visitFieldrefCpInfo
                                       visitInterfaceMethodrefCpInfo
                                       visitMethodrefCpInfo
                                       visitClassCpInfo
                                       visitNameAndTypeCpInfo
                                       visitUnknownAttrInfo
                                       visitInnerClassesAttrInfo
                                       visitConstantValueAttrInfo
                                       visitExceptionsAttrInfo
                                       visitCodeAttrInfo
                                       visitLineNumberTableAttrInfo
                                       visitLocalVariableTableAttrInfo
                                       visitSourceFileAttrInfo
                                       visitDeprecatedAttrInfo
                                       visitSyntheticAttrInfo
                                       visitInstruction
                                       visitCpInstruction
                                       visitExceptionInfo
                                       visitInnerClassesInfo
                                       visitLocalVariableInfo
                                       markCpEntry
                                       markAsUnused
                                       isUsed
        at proguard.classfile.instruction.GenericInstruction.create(Unknown Source)
                                                             isWide
                                                             getLength
                                                             accept
        at proguard.classfile.CodeAttrInfo.getAttribute(Unknown Source)
                                           getAttrInfoLength
                                           readInfo
                                           accept
                                           instructionsAccept
                                           exceptionsAccept
        [...]
        at proguard.KeepCommand.executeShrinkingPhase(Unknown Source)
                                access$100
        at proguard.KeepCommand.keepField(Unknown Source)
                                ensureMultiClassFileVisitorForMembers
                                execute
                                executeObfuscationPhase
                                access$002
                                access$000
                                access$102
                                access$108
        at proguard.CompoundCommand.addCommand(Unknown Source)
                                    execute
        at proguard.ProGuard.readCommands(Unknown Source)
                             obfuscate
                             executeCommands
        at proguard.ProGuard.shrink(Unknown Source)
        at proguard.ProGuard.check(Unknown Source)
                             execute
        at proguard.ProGuard.main(Unknown Source)

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/retrace/index.html0000644000175000017500000000214111736333522017413 0ustar ericeric ReTrace Manual

ReTrace

  1. Introduction
  2. Usage
  3. Examples

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/retrace/introduction.html0000644000175000017500000000500011736333522021022 0ustar ericeric ReTrace Introduction

Introduction

ReTrace is a companion tool for ProGuard that 'de-obfuscates' stack traces.

When an obfuscated program throws an exception, the resulting stack trace typically isn't very informative. Class names and method names have been replaced by short meaningless strings. Source file names and line numbers are missing altogether. While this may be intentional, it can also be inconvenient when debugging problems.

Original code - ProGuard Obfuscated code
Mapping file
Readable stack trace ReTrace - Obfuscated stack trace

ReTrace can read an obfuscated stack trace and restore it to what it would look like without obfuscation. The restoration is based on the mapping file that ProGuard can write out during obfuscation. The mapping file links the original class names and class member names to their obfuscated names.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/retrace/usage.html0000644000175000017500000001167511754145631017426 0ustar ericeric ReTrace Usage

Usage

You can find the ReTrace jar in the lib directory of the ProGuard distribution. To run ReTrace, just type:

java -jar retrace.jar [options...] mapping_file [stacktrace_file]

Alternatively, the bin directory contains some short Linux and Windows scripts containing this command. These are the arguments:
mapping_file
Specifies the name of the mapping file, produced by ProGuard with the option "-printmapping mapping_file", while obfuscating the application that produced the stack trace.
stacktrace_file
Optionally specifies the name of the file containing the stack trace. If no file is specified, a stack trace is read from the standard input. Blank lines and unrecognized lines are ignored, as far as possible.
The following options are supported:
-verbose
Specifies to print out more informative stack traces that include not only method names, but also method return types and arguments.
-regex regular_expression
Specifies the regular expression that is used to parse the lines in the stack trace. Specifying a different regular expression allows to de-obfuscate more general types of input than just stack traces. The default is suitable for stack traces produced by most JVMs:
    (?:.*?\bat\s+%c.%m\s*\(.*?(?::%l)?\)\s*)|(?:(?:.*?[:"]\s+)?%c(?::.*)?)
    
The regular expression is a Java regular expression (cfr. the documentation of java.util.regex.Pattern), with a few additional wildcards:
%c matches a class name (e.g. "myapplication.MyClass").
%C matches a class name with slashes (e.g. "myapplication/MyClass").
%t matches a field type or method return type (e.g. "myapplication.MyClass[]").
%f matches a field name (e.g. "myField").
%m matches a method name (e.g. "myMethod").
%a matches a list of method arguments (e.g. "boolean,int").
%l matches a line number inside a method (e.g. "123").
Elements that match these wildcards are de-obfuscated, when possible. Note that regular expressions must not contain any capturing groups. Use non-capturing groups instead: (?:...)
The restored stack trace is printed to the standard output. The completeness of the restored stack trace depends on the presence of line number tables in the obfuscated class files:
  • If all line numbers have been preserved while obfuscating the application, ReTrace will be able to restore the stack trace completely.
  • If the line numbers have been removed, mapping obfuscated method names back to their original names has become ambiguous. Retrace will list all possible original method names for each line in the stack trace. The user can then try to deduce the actual stack trace manually, based on the logic of the program.

Preserving line number tables is explained in detail in this example in the ProGuard User Manual.

Unobfuscated elements and obfuscated elements for which no mapping is available will be left unchanged.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/manual/wtk.html0000644000175000017500000000467711736333522015504 0ustar ericeric ProGuard JME Wireless Toolkit Integration

JME Wireless Toolkit Integration

ProGuard can be seamlessly integrated in Oracle's Wireless Toolkit (WTK) for Java Micro Edition (JME).

The WTK already comes with a plug-in for ProGuard. Alternatively, ProGuard offers its own plug-in. This latter implementation is recommended, as it more up to date and it solves some problems. It is also somewhat more efficient, invoking the ProGuard engine directly, instead of writing out a configuration file and running ProGuard in a separate virtual machine.

In order to integrate this plug-in in the toolkit, you'll have to put the following lines in the file {j2mewtk.dir}/wtklib/Linux/ktools.properties or {j2mewtk.dir}\wtklib\Windows\ktools.properties (whichever is applicable).

obfuscator.runner.class.name: proguard.wtk.ProGuardObfuscator
obfuscator.runner.classpath: /usr/local/java/proguard/lib/proguard.jar

Please make sure the class path is set correctly for your system.

Once ProGuard has been set up, you can apply it to your projects as part of the build process. The build process is started from the WTK menu bar:

Project -> Package -> Create Obfuscated Package

This option will compile, shrink, obfuscate, verify, and install your midlets for testing.

Should you ever need to customize your ProGuard configuration for the JME WTK, you can adapt the configuration file proguard/wtk/default.pro that's inside the proguard.jar.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/GPL_exception.html0000644000175000017500000000367711736333522016121 0ustar ericeric Special Exception to the GNU General Public License

Special Exception to the GNU General Public License

Copyright © 2002-2012 Eric Lafortune

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

In addition, as a special exception, Eric Lafortune gives permission to link the code of this program with the following stand-alone applications:

  • Apache Ant,
  • Apache Maven,
  • the Google Android SDK,
  • the Eclipse ProGuardDT GUI,
  • the EclipseME JME IDE,
  • the Oracle NetBeans Java IDE,
  • the Oracle JME Wireless Toolkit,
  • the Simple Build Tool for Scala (and its scripts),
  • the NeoMAD Tools by Neomades,
  • the Javaground Tools, and
  • the Sanaware Tools,
and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than these programs. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.

proguard4.8/docs/feedback.html0000644000175000017500000001076211736333522015136 0ustar ericeric ProGuard Feedback

Feedback

By now, I've invested a fair amount of time in ProGuard. You can help by providing feedback! If you have problems, bugs, bug fixes, ideas, encouragements, etc., please get in touch:

  • Through Saikoa, we provide professional support for ProGuard. If you find ProGuard useful and you would like to have some professional backing, this is the place to go.
  • The help forum (at SourceForge) is the right place to ask questions about any problems you might have configuring and running ProGuard. At this time, I can generally only assist other open source projects though. If you're working on commercial software, please consider our professional support above.
  • The open discussion forum (at SourceForge) offers a place to share your thoughts and discuss new ideas.
  • The bug tracking page (at SourceForge) allows you to submit and consult bug reports. Please make sure the reports are complete and concise. If I can't reproduce the problem, I most likely can't fix it either.
  • The feature request page (at SourceForge) allows you to submit and consult feature requests. I generally have my own road map in mind, but this is the place express your interest in new and existing ideas.
  • The download section at SourceForge and the project page at Freecode (Freshmeat) offer the possibility to subscribe to the announcements of new releases. They are the most efficient way to stay abreast of the latest developments.
  • For anything that doesn't fall in the above categories, you can mail me directly at .

I can't promise a swift answer, or any answer at all, for that matter, but I like seeing any constructive comments.

ProGuard isn't a typical open source project, in the sense that I am not looking for code contributions. Developing on my own allows me to do things my way, without the overhead and compromises associated with larger projects.


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/GPL.html0000644000175000017500000004013611736333522014032 0ustar ericeric GNU General Public License

GNU General Public License

Table of Contents


GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

  • a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.

  • b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.

  • c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

  • a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

  • b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

  • c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

proguard4.8/docs/testimonials.html0000644000175000017500000001166311736333522016126 0ustar ericeric ProGuard Testimonials

Testimonials

And now for some shameless self-glorification and name-dropping...

ProGuard is probably the most popular java shrinker, optimizer, and obfuscator world-wide. It is being used by developers at companies and organizations like IBM, HP, Siemens, Nokia, Google, and NATO. It is the default tool in many development environments like Oracle's Wireless Toolkit, Netbeans, EclipseME, Google's Android SDK, and more. Although the quotes below probably don't represent official views of any kind, encouragements like these do keep me happy.

ProGuard is the ultimate java obfuscator!

P.S, IBM

Also:

ProGuard is pure quality - powerful and trouble-free.

M.B., Statestep

And:

It is the simplest and most robust obfuscator we have ever used.

I.I., Hewlett-Packard

And indeed:

ProGuard rules. Much easier to use than the commercial alternatives.

B.G., Quiotix Corp.

Straight from ProGuard's open discussion forum:

After searching for, trying to trial, and futzing with numerous other obfuscators and shrinkers, ProGuard stands out as the simplest, most robust, and accurate shrinker of them all.

D.J., Joot

From the article "Obfuscating MIDlet Suites with ProGuard" at developers.sun.com:

Its friendly license, attractive price tag, compelling performance, and powerful configuration options make it an excellent addition to your MIDlet development toolbox.

J.K., Sun

And, of course, the price is stunning:

You could've been rich.

My mother


Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/sections.html0000644000175000017500000000432011736333522015232 0ustar ericeric Sections

With support of

Saikoa

proguard4.8/docs/screenshot_gui3.gif0000644000175000017500000011033011163773610016307 0ustar ericericGIF87a333fffz̴θνҾ,e HAY*\ȰÇ#JHŋ3jȱǏ CIɓ(S\2!K._ʜI͛8sɳϟ@蒇ѣH&MӧPJJիXjʵׯ`ÊKٳhӪ]˶۷^fPt,x˷߿ LZb+0]Đ#KL˘3k<MӨS^ͺװc˞M۸sͻ Nȓ>ṡFo8]سkνgV_9sRGU=˟OC-ZSNؔh& FR~Wa6N Z_(\-bv^U3ȃQVCh(#sF=_eTyM9'%Hf{BHG#Fh~Il9K p0Z"cX.T柀!ihRf蘄2裐ss(KUJ#{Z:*jW*Ya*+X걇ޓ|r{Tv*c:"5d&*F+퀶+sr%WN+nDzz*조.uk-:PUYo{.ˮ:(p+I :j_&*gtb e(+/$,4*c(7qh~,D}P6#J FG-TkƲʹUw`u!٭͚ʵp-tmx޸ 0n'7'Wngw砇.褗n騧ꬷ.n,7/o'7G/Wog/o觯>p/og7HL:_&H Z̠7wGH(L W\f͐8̡wn"HL&:PW\.z` U'D޽hL6pHG5Vqs[ He5c 1L"Y2 $'IJZ̤&7NNZ 9@є$%SV򕰌%" syJ^D-IbL2!9ғЌ4IMNf.}nrb6IrL:v~ @JrʢsdzF@`dg(:^r(`R HGJRԙXRṴ/bL]%δP(FY Ξҧ fOKJԢHIR!aTP R4TKծfuUWB]e)S` 5p\ȥVΑ̫g|} _j@as[d'KʊԮs6>v6gG[>b´iUZr}[-K=9 p;CMn|\.׹utK 7ͮv]VM AMozgx^׽ @y^>~ L`}בH;3dp< 3pi g 0L;NWb2"!fL8 mc?{|952s&-<ǘwȲ.{`L2PZR+L:xγ>πsLBoYoPF;ѐ'MJ[Ҙδ!=C{Ӡfd@6ԨNWVհgNָεGޕMbNlaZЎEsζn{Mnm?{NWm Mzη~.v O;'N/<͎#7qCGN(OW򖻜gNsN8y?.@!cnHҗΊ;2央[<з{qET,կ5[N]yaZb|?[AuhwY7x'OK 3 ^}/Sƛ{ֻŸ~K^P?<8g'O @ %%OP8;})b!OڭOPO:b\r!M7?WM w3`8``{mSS=L/qS0$XS`~*[^pnĀ284I8+:CWQUmPiQ@Xip;JC؇S7}OHSFSQDUDW}\؅ւ4|^UZEU[EdH#tU`UmhU_ncEVHxzX|~凂eXDX5%}؈zw87yʼnZZ剦dDFCBc&d$dG))d+9,ّ7@8:<ٓ>@B9Dz HJLٔNPRɌtfX9CXeb^6Ccfyhj9pr9tYvyxvY3sgY9>Tk٘٘cPyٙɗ&^Vyvsytpٛ)vvșʹs5Ws(A9Yy)Q3 Hl9ltiT~Ýi9 Pٟ0Xn:Z:nv24}:Y3y3T RV&z(q~ע7ugxV;MOVuj9J>@LJ9q9Co4pKRF# @\ڥ^y7d {EzT9=r:tC:90J9CHIIC}ꧡ|:~Zz Y*^/:Z-'{WxW@5[n:TbWZw  H9C 44JZʪCThwznVzwZֺZx3dڭЭj H :ʓzW৬6ʦ*;ʣ;Hȍݨ_zw[{̓P-xױ ۩kگzx:qJ*,023D`0[;{8+:˳=;B;F;JƃqxJPGl5Dʲ\۵-+ Xb;d[bPc;Cd HkigKCmtjkx;H˴|۷I+&hѹ=9^{K۸;[;{뷚sǚs?:::)[yۺ;{;^~ .p.ݖ[T;MXH@^Ȉ8.,;ymy(4>3nU7מ8$F~\ 㚽h5]ȋŋTNUX>M A+f~ժLxH{U_ˍsuut1DЀG7e抾?Ctaih闎($.j\:Pc~4yA/IdG-9A&&Y3y9Ƣ. xP~$~j}ԞUӞ)eY~f&yf:~Jj]+㾌.gYg_^~/{WK "i_>ɷ| ,Ϡ^^H~_6OLo͏;>@_k%~W"מI/54[{R?v*UZ\V{άLoeNnxt{: ՛:R;2p/ry*o%[#u__pϿ[7T$޵7]*}CI@ DPB >XPx\ @En|RH%MDRJ-GH1L5męSN=}TPEETiщ/ȸ^ŚUV]~Vج0%\VZmݾW\ul*qFP=X`… FXbƍ%-_ƜYfΝ=ZhҥMFZj֭][lڵmo>(y`ߨ=\pōG\r͇Cލv_Ǟ]vݽ^x͟G^zݿ_|k$+S|z%@$@D0AdA N ݦ.0C 7C?1DG԰On "O:@p( ]1GwG2HLяd ('AҐDd"/ dSd$%9C ҔINvғ&?ҔDe*UyJ9ҕe,e9Y64j /[~җ&B%Df2Lf6әτf49Mj*ӖY0MnlHK9NrӜDg:չNvӝ,5Y[ƞg>O~ӟh@OZQP6ԡhD%:QVԢm<癔nvԣԉvXLNq'EiJURԥ/iLe:Ӕjt7iNuSԧ?F*ըGEjRT6թOjTTժWjVUv&B%銘0VլgEkZպVխoYUծwk^ /qCl`;XְElbX6vskd%;YVֲ+B4PβFmHgE;ZҖִEmjUZpa keY.d mnuЖ~ ;\׸Enr\6׹5okV׺7ꑴu׻ox;^M`^o]׽.lf2׾/HlI%,a]]{<`[']Q`7Vo$>8j aUXDLifc. o=mj* {-mMkY6mo}[U[FvSXVJ~w vUFwum7dFbY,dUioP^l`8m!Ǜy]r#p\s:]wsqetsHrzǽWz镅l>vgG{WS4 /q!; v`Nw}q<#^٦5H.6~Ptb((nXE-NtE?zҗoHַ=CzV}YC7$7Aaq;NQEdFtDCR_8*+b#RTRH[#"1$3E4USE\<30u6' $;%% M(e)o\es(,ǻSCԀC;MN-bxK%ѸDTUUNRĨZE̪J]X_lUD5cEdUVQ5hua*^ViI|nE=pq%ׅtUDCruwW<|x{W;u~ j׀؁sORÖR;XZֈ؉Xi]{؟k5Y1MT< }`7m6p;7IŊ=ٞYէ,t8QJeʋJ[mU@Z_9UK˰!9]bKO|ը%J9D۟Kl˶9 L[A4hEϲ[Hy:\ȔL#\: \E1[۞¾\18ٴ\ zͿ \׼НMPsYPeG4"sSE"*DN-N,)z01&cK(}TYܳ7l:;<=>?@3&B6C|;ZvEGH)E4K/ЂMNOPQ&RNFT.`VvW3YZ6Ke4]^_FWI&b6f 'PeLvL10eR^j~%lfknnnppNr6sF$ufuw~aczgMg-dU}\&K^~geYv艦0hg݀MEngl^iFQNg&hXV~臎.vh&6FVfv꧆ꨖꩦꪶ>jgfPFe~NFNq盾t.of$pvk"빖kk{불?Xd>&k.eRƂv^h3ikjwVfvg 0FVӶl~ȎivR^njYT&v_Fvhvvn&khE.fn+^0g㾂~NeonYwlhZYNG/plQlPfP=; 78PWq8p?5:wPA}#rӻQFn#_O6`&owr'o+ngN#-rkl%1h 4Ws!E71G)l= 7lS2OV(]EgvIJtLLtOPu#rrVk9k/_t%ә_E3o[u~uǞ6pWFnpΎ|0U6He?t`v]qs8U_uQWR?*'R&v;.qvJG+E}~'7dJ.腿]aWfl%x%efeK xp7v/uܼgy|vXdyktNrcnڮfFzl!y!@=amzP\FGr\VoFt+?-Ge륇7Ie_:{nQlfw}Vsi'Zfgx [w߾{ʇq&зvoUx&`gocQE潿QVfrWoSP ؁ǁ''~.iV|w)Je\eo3.pl7k-?pmxVfO}WGmV.iLN &)h`QZBᕈZDh"ƈdyQ"G,i$ʔ*Wl%̘2gҬi&Μ:w'РB ,Jt1R~jj+n}d X$bǒEBڴ=Ҳm˖ܸpˎ +׼TNF!.l0Ċ3n1Ȓ_SJ1oxТCԪSiׯWlyܺw7‡,rf2BWKS*QcZkC;ǃ_cyOG|nV.|&n>qm܀Q7Zlq7lv{=H8!Z8atdIgu!}T%x")";rM)'h5WD\uC FՎv0"M:$QJY؋ĨTι'\i} \:yC|p ^YKNy'}' :(z(*(:(J:)Zz)T3݉U f8 ^ׅ6*Y ++ ;,{,*,:,J;-Z!5ʢ{m%^]ZvG9p{^j^Y}^// <0|jkXr& Ff._5*z*U_Y(/d"2-21<3 ߶Rf Wt "zLgZ%4'QK=5'4k5]{5a'k3}8cG~c9]]RI7bH~xdrb;8K>9 st39;,Fn+nn:õvsuy*qe:\|5{cxW; ?<Ғ=f!z;|]X';I=b{G'>~n6x(;6}+/Ybu GYE# zHЉ F>~_ا/6 g!(!R uR6A z9|"}F4uGp^| {1گ9!U3(9QFTf$ѠKThx'VmZيydx$$#0갍i4 x5b3_(Q:V]1WYҲϖ*Fzd%0J4f k8MvdhiR,*8#4\ܑ Gc4<':ðձ-: yS,1wLܧ&i^=(B̝- Q7#KDfYF1ntzxk]&=)(Y?fВ\ q?|!hBsӝtɣfQ{ jԥ2]x ܚE=m V*V«%<*XJD Hs"fHh^j\zYrbɸ~+ #fICu`Z{Qr4m0 ,f#'X+alZڈ;<9Gռ牔;ib+Ҷ-ns򶷄juh F}s" Hlkyr3lY FJS 4%guv+ҷ Al=l_2~0MGzUcX,׌g>l{5`ZE&>1SL ‘]b8aGFg>1{2mkEE ͛80gD'2-s^272pJwZ]:+!<{U9(|.he s?pI6Bg]֍uɝ,ISXUea3(5ݑMRECucuA=&4c-K@308BF{^7/z xꔼZ~6fi h>A"(J|\ *q')>tBa-JŁ6'bW7o;Zj .Mܭ ?]-DLϬ_Ff#c7C<'M]3 }Hܚ/^)th<=oS &|m1ԥ';ҫ[7I{.--EM ;AE"MC{ס>5i6}FV{tn Qy\Y۩~R3{>Ac/5>qe^j_7Ë6g ?izN='YϾ^3m.5ݨcXũ?RWG! K=ճ'z%R;S@j=}=`SNh_dn A| \aA%젔 K9_L͔L}M͜Pb ִ1Pj aAp^\>BN!VsaTCВ]e߲!L=LݰF`V$j!R5FMԪ J᳜!}Ԇ@!"":,"#.۽]#6t DN@T!cD9D"(bڰ!_CP bk_ *_lTlbvbOX "00#11:.bޞhV =i, r!/(v7򙟅ɂM#:q]-1U9I+'n#>>cb M,!5Ӛ#BrT"*Ala8#DFDNOULJ!CԢ*a:,J ju`8Q$KK$JX ]hP$JƁNNOON$-"C&z=$S6SLz MBUf%dE*"J$XzYR1%[[%\ƥ6yˆt2$GzHF$$c``FaFbIK~7>7J?[D#+fjjX-9"Y ccBj")ʂRdEjf<"Vt 4.6Q #p v`k.WԒWdRcw (AUTBI+p,_UQ'3s>t!8N_VB&cEl($fBP@$:KF9m$J4RI]`X`A -SJ`&dL`QU.H`RGaıUԴ6tRyjEDs 2D1A@DFyAn$Zߨ'lEhЧ\_v.ErjeYfAr8$l2 (,U8.wAqGmWܯ@4(@|@ _CH(TBRcd!N9vo>Mjqp7F:{VBp pX@Fh ${($$GO^5,=5[?*Ƶg; ZEwN`99) M9.)SS퀹%X=ΚdxNz|7Λa? z]HD@ iLR݁(%,Un*'7b[b#t՘uXD( LDQK!\ sg$?ώoNdRՍHaqB. -)SaAJ Kd=K?VϣoE`^TntHAA̱!X(*!l$ SHGdoZ}Gd? $B.W+(x/@8p3h&DaC!jy SEXԸcGA9dI'QTeK/aƔ9fM7qԹKe*@C'^QtISMD:jUOfjI=A46ӦM*cm۶AƅVӧTŻo_f9paÇ'VqcǏ!G>sQD #=sU_/Vn]yY>{_^6x+ wܱP5xvքD0gup{Chw5-yk!VL"*9O`0-Az{ۜNAVĞN%:ѝ5 q85uf@R#A6)|(A Y80x`' e N^Ne=hv0` h5otaG901 sHA|Pؼ'uA d0#*` ,JQ€ p bUqp+] YΒ\-@ZaLah a٨F6bk#2BӣTIN3maJ_WΕ"T#}_{ 6.%,80}C&2haIxT*7eU#gAZ95d]kYR$m[EJ֕mGum(  (E,HgT$ Q_]n IYB0sZ׺p"lq_ηhjӚjV]X~pL ɋ0=X""`u+2)lҗ%6! M-OT"p%TH,bm8;x8%9#>eLՕel] 7va]FjިL^g=9kTutkP~xXz IOҒ> a;P ԥ6QjUխva$$'rs_gDS]8D}r6`BB˱cCbpfKѠm Š5mmod'Bh^%-N_VD*FfH̛%jVBEb6p/ '&\GCOxr9@%dh[Tcpr\'j}Y5qs+֕iܐ'Yd7k $`L?-1ZQpOi;v=NīHl̃b5-wNXtKeYS+%5xh>v/wnkFNWQVS.%h[+7"8A{<̫uLlc{Ϟq܋Ig$C: oߑn2g׿ܶ_.Zy>ppj 6cn,Ad \z bHfaM;s0pSltE8tmOd?B) b@ $b*xGfgO&oM}o"O/΂0%"0"Ϻ@qAlYQp pT&QD.+ڦ %&˴P2@z`,Jz hG0R& k>bJb+{4ʼD,tpϞt"0C1?.<"N_"Q1ȵثOAqiMѫ(Ҭ~-۲Jj3.Es4'/FjQ,US8X b,ӡ"0*">Q|333q!(Is9tL%E?"JI"mR).qS<8Vs8sk<+".`Z!@  ,M@ @MD%?/B2$m02@6XF~@ a2.,!;_*;3oC9~IquDQ4KTUTԷ41 ["H!`VG6/` ހ;KBr?C1tK PAKs5SS+DbBMM*!@;xb@ 4O;6~'q P0FMTuUYU]Ua5VP ^uS;H72:hZu__z[Y4 MRs -4 "2` @ /L/P_5dEvdI["[(fT  / @ "q @ <:Ld6ivi d{VR$C \ Pj VZ@",@w ܔB562dQdvnnZE;/T` uB`$0!&|`)kDnVds=sA7tEwtJWR_Y*e?,D>`Ԁ$6`~ BX@; /V44ws; [wyCeRl &ERb>@`>c)L` /1\ODex7Øw~S" qהCDX  6*32}tx?J7wP7~tv|P`5q/V@{W3A OQQPjBi1Xy4T:4bLA/`b cFAV6upr0953`½c.EXZP4(O?`$aĠ3~ ]VoxT P($F.{T1!>8:i}x`<Pa`&6äQH46'˼8Ƚ1,2u>[C 17 $8ND!@vbNq hr;9J«8!xѹ.4W G#x@،u+(FZO)'鋩83!R(0!ڇiuTu S;ؑuyȲ,- H--Y>׫c#zOp7Z1r2+N^+I}2JR3M1Y"2d:'Z`qx1i!f !UmzWS[17E7H`KQ!+1thtzG@ B[y><>ﺽ=C=,GKTQSeP8LC)rh,B j"$~ڷ{ {yu.CO@@qɻ(`Jís䟭GpGLh Z@"T mdc6 R;$Rt-1<5|ÿdWQ^C 0@23e ,z -Ӎc ~۾q<VpO2dĥhFH 6m $!(ɛ\&z©ʭ|sY!l H.Bw6  ga<_W.?NjCnb,rrFpV1킿dȏ Ѡhr4\d%Q=U$l7" %`ZC>llPd,O}9؍ؑ=-tm۶C *,M  2Vp#6#s<޹yza77>x.` Lض"@ DĢ>yW]~=ݸͥu h6@f HؽOxӠh*㗷5YKC! >` ›~g>V@x`> *L3솣F쿉qe^ހ"F4 4 Pp_\ۀj8r:Mb _ŒѾq F8NFDZ :O?Dc8l[^ Z.](75E-iB]buSs,?ʦX)f~>y&md2Qcy㉲7= S9lzI8O 'Ҵ`=!r_Y?>~'gwfCM $&… hy1bV7/-?yw! #AoDG`TFlK H>oL5]rtsDF9ddM !  i\%`%N:)`HnTmfn!*y!G(y{:ԉHhh.ZVh*y9dWwXƩI| HAj4@db\bQy^jegbPAlqwg Ux8]nm~ n]9 ~Mc{UFA} m;fT 9̋dekh`< q`$tyBkoJ "v!jgQ'j+n*r.EEi)iz~Q4F:3k)fB-4FR` N?ROMu; (͵F| bs:*s 0En=EMwuߍwz ~ xw'3G2{?6ifA$dpj.ĤLb^殪jo4@.޶+e|]\7˂D}@5E$-Z])iY`NOo<)=|#E K !H KT01>$, OHکp,l _p4 op< qD,V.$R<*k">9psGb.aX(ūLfpll#8q++W@Yq 84 r؃Z`,f!b؃#x@ D ase,#DV=`t]׼u|_ v-a*vmc Jve/XsmN/y^9 O %jٲaEC`voJ=zOe2tYC%ӵ b2i)U涿w ͣ33/leoO _z`}_aqX_*-+e,5~.>jK bx$.O78]ڵ[-$uMhR 0 jP +2 <xLn</lck@%H> /̅) P(yln(HL.ЅD"I@28. h[.=Ҍ;X̄vhfa31&ߌLk:5m&A'H4\bJ%, nu_Xo֠:]*-qchH׼4YilM+{N4[7o3R * `/GO* ?A !dVCRH:DKks(cٽMoaQ4np`W,PED9"MnohslZLp(KN~S-Xuu}A"ej& nLdbH V@ ku~J`" ;#DXWZ/v{*X7^vzo!b" Ȁ H7Sy7==BS BsKBe @Iq%%jw_7>e0k|b1&'%z'{f'rIqz~ g'qLp~Ivlv_xM2Y;SFW6f B`b` Lg T*FUT')I8dt#j(iuJ8h׈6yZzׄkgtBH`(hMbKCa'P$ >Q*AA>U\|$sywWWlo=!猉vq΁o'XGdeAgfg'o ` b@$=]p}Qjfpf^wfӅn65~gf op%h$bo 5ij aEP]?3uO+ cGsKɔ ֑ehmU&B _p :rZ30 !`detM q)$0" PT : rr  pVWQOdo9əbuKT?H0p{ bŠQ* p]`E.y졙Iiͩ*!Ys D@+S*` r$QK  nH5 ))XF PK Š9ݙ|N ) F^&aR&IjTsdcP c~))_ p9o a\$7b2 A*L'm!0BG`LGd"` TY 5@G`cI PcDikʦmo q*sJuj@6w*0wTL^ao0 O z<ZQa D 8B?'J"2ʪꪯ *JZqOy VT%!6g { W>Z2%mJj; *JjzJcbN` pf $cFblk׫k-k L Ur0W@WOeS& 9/ $;Rm) 9A|k{x;?l}{bdQpU7AaN Q>yõNE(ik(H4M H`C2B{qJlWa5 PJ`YfU0t10(h`L[|$bg;l ʡ,Sk`ʪʮ|ʳ|},q5+P00bNpKl\, q_8_'g'_)w|ãߜè,&ѭ L\yŇ|'_i PS7_i,BP$ `$KHKK'< ѦѰ2& M "]$)-ԖB0jem J]AyIK<Q-S&qX]VYT aM,@aLi݁B$1 Jj~$"?`̢ `saK&dJԋԊّ-ٓMٕm &ٚMٟٖٝMڥmdMEÅaG(4?B`` eK@ h9h3ʖV-M]@&ڭۍmMyC 6(G`=B V!Jpg0 0'⏦ÐA#HH Gn ~L%N~֥2`&/t-P!`* 0%_R *a,N3$.S><WY[]_a.b>;g6kmnӜD#4ws * @@ Xe(T.2陮.^ˣ3 !'a+@6).lr } n_ӫI Nɮ߂d.Nn׎ٞe)6|<9Nb@ pSF&Ⱦn[/O_N' +wr=U.  eAV  xQz~#O P)+-/1/3?/ Aa"K#<0BNHaGo` V:S#a[a &%oWZ[]_a/cOeofo:Ǘ3<Z4 ~$SkM`uPoၪ{ӧ;ϋJWaE&d3R FY 4F;` W*u @AbcGY>z I)UdK1eΤYM9uOA%Zї%GSQNZjS E6ë&YHԮU[h垥R-Z+E 9 RL6Q!ȑ%K^Sryn|-["Eiȑ%fkرeϦ]J?foy{Bu,X_ۼF1A [~IqKQye \uϧoVqp@ͣSpA*, 9 3pûO:8 A'6""ďsqG{G <Г4ѣ k#{Ϫ ,4K4\\3SUu*%09 eRK$ Brb',S8LS(t>NTjZl Uw#o*njոWeEH՜wA h J .6x CBGm#xb+r}JcoeOt T9Y2dL!t"'Zp` B ,9Y̜;3xiv0c)=,Y{l=@h8`A B8@I5;z3) ƹvj 7pezUujtḰVΉtT-0GƏ/>ygy+=ѕjC$  v ) RH,*(D \ǾePOǧUMßSƼʑ  Z4$a@![,ئuPC$bU=\#| B$[(x9D0E b!ř4Q_~F8xH Ī-1\OLb4X5$ Wx LD"3 Q ,dR$RHbr$e)MY1:P"D5O|VH@yC"\;4#xHLhF3 &J RfRJpЏS $}fyNZҧ A] Q#f$ sEh'P| ,% %@pPlմ&\MFT>f8-Jq0VeG$4@T&Pa ODwsp9@_".T;id=tC%jQqSы(LFJ 6 S( ڐ X>@BuBYZNfRE+"CjTUEAjRUT)6# 'M`ă XYЂ<[zYf&u+GXʜEM"q(1 f/Ҥ31UKYV-o9}`O_T 鳹|;Au[ dW^CކWFœ{^Weo{ݛWEx%/ iSsЀ\;P=Z&X,{`G8uƐB1#&*h> 1 `Ktȣ+~ة-X3o1dK/,K"@/Lu1ő"0_,X[栍o<5 ҩ]!TvP YB  +, =sʭH`.Zн>vK0 J j+ P**bzЫf mh((| J(^~ l&h p@%)-JFP涶^ :"Z]|bq >@xG _rU@RW'DQX7:W~X6}p>RiM[ 9V,Q V@-+QxE[(%h;3~'{Vܖka_Ӵ"%~6İ S\gBr$-2yխ0k9g%CVaʹxb ` a Sb"}5g_]{͓x?ola|Y(NgbwDbqfJ{=kM%A¹R~jP',}oZ*pb )x9P,йHS@M2B=ټ,?k>$>#|ۺX%@Ȃ# B$qJORH7`XAA%\”??)t'#Yc=>L+50FIM3G@ܚ>;$dB:A'Ḅ?3JI4ZE1JLaFb,4hdLFe\6H+,; PP3VYFJp 0y+#XGv\zGxGy.BLht#jG&kC,H| %1ڪ-o)"D~Ț:,:v|usnbUta#arMAI&;Wg*N'`'~cBbF=[Vё3,cUm|p%.⳻kcF!:2y-H&mS ES [FNe:ykܖʐHFJEF,F%xEP`CH8TVee>9V?WFXȀE'4gJUܫ% 5b^bX]fxVMgFdP!'Oʩ#h)3x&otFMIxgܡ 0HU!0)0s&F4v.Фk0hsecr Mi!YfF 60gcT;Hj^꤮Ѓd jjNj~/;@ zjp΃7Ȃj= %7jjbu^h YE9,ԸSHlNllZYю}縮iCi? O^LHH=dO5-.Ư[XBiˮmlpdvh8(1XPm~% AvC WåmmX1 ,J@Bxgz>x!g3HFNbUELQL(Zyi5npnC̀#$ &0SHK]G%0FєQ/p-Ɉ7T1e4F'4+Axbl-ɗ˕ zO[ gHKޱQ$($(ЀKK4QKLă_%p%o8dĈwPZ,dsHݴ(L)Uє^"6wsIٿS*t s@,)XHPC.vLRXL8hԬ qD\}ƋIt-_׋dO{ LCYpH@J|FMlHHh^K$ E+._vt7 aOAvvaܺaW'St XqvhکQ0D um[ijQ|Ctxt=ȭw<^C{'0Ґޞ%@Q*HXPc-''pvGgB:wt]QՃB{YђisX;=bg(0Ϣ5Z,-Vq:"w^?U0Xp/So|o|Y0bU),WrozC{*zz, m(ǟ}ڟ+h.+Dvsz)z[S8 !jj*LŶ X'~|*Fy"d7}F}?O, }Ws H &Q†|"q"ŊO`̨QY>NLr%˖._Œ)s&͚6o̩s'Ϟ> *t(ѢF"i$NB*u*ժV:mrSY< p+Md-۵H}۶m!Lܨq.1~Acf0fYdpƆ@ ʔ%cH&-z4ҦONz5kKAj*{6ڳc{ܕlر`;fl9dK4Λ.=zs8֯7ή1bHۿoxxoÏ/>}_n$yXuVZhV\B)$.2!  ڨ6E {Bh!QM о$DAܡ]H" &UIg z!/1b#h31aY|Yu[RaVAz#٤Y" iC"2\$#HݱQIkpKLK:ORv%)KiJ;!LuZJ88tx+%V[2ܥPN/s6 3mX2iDn[>ԡAqYB3'9is3\';w3'=i{3'?4(Ay6#\"<ϴB6iыruPȏ4")IKjғΦw ^[փ42jZSy)IZw&\yJ]*SԧB5d0׶!zYGMbKpCJ5j]+[ַGb(CjW XnA} 'ͽu[P!5],cXCur>lbRz` ]GtK %->6]-k/*ET266-o{[y9)5"7tf7񡶵ҝ.u L".w7/y;ٖ7]w /SŜo1ɳ%R1J,ᆭq3u lxX0C80+l) 0;ag8$ԕ^vHr/X18NJ'z9B2l##!L'yɿK+Ale39BbER 1r3l;9z3Lg)ς4,"&F$W* *mJ Ӛ޴- 56~3KmE@^5[W:ֲ5kj@ֺ5a}I§$L#3 7] m Sc;6^o;7ms;uw{ܿ]$oõOPSLgҗ޷NF͂mZ™6mC<_bac<8;<gKns|TY'=-D%zpףաl٤dڇOPͰܺx; c^޲BOuW=vU>*_G{v>|zziǼ7"%CifcN_l  _MpuSpAOMniiIu `ٍ] ' Π ` `  ! ٵ ܅ELfHeUF[X q!\m؇-9 !&!!aႱޡJF$CMiepL\sPa'z"Ta{iq)f)bL*"++"+,"(b,v٥-jסH@$c W`(2 r'J4<5bc6j6>i7^#8f8vc99#:b#9r;b#<8;c>>Bd ś & r,Jd@ RcDJdS "XEbdFj"]FvE HF~$GIGFF[K$HzHvHEdLd?sm 1\ Ǣ^XZPEDD:STReUZUbeVjVreWzeUWXeVgmg> TS4`AtAlp)0] hBO A7 2P!@=~0~@ ,%{ ɷe}7K6]0A\A!5Wf \N)AA%U>W&XB'X̉fXƐ$)~F=ף?562L㑐NQݤY( lQ5- 8kZSkGYi,k+@,l'0XP x@@&/J64=`CZƸy5 mHYU|h;$9opH fm&k:Ht_02p~X!D %ijk:`W Z7UPjVn[O O +%`sԶ p`z\jaBQ :{_/[/ eRWr, i0סQU@yEeIlԯۗaYkZ*cCezq pbZksZ'Q@VIt2 i&pOz! ~0[ #Ja!TSIlgqK̮ۜ^ .u)%c2Hm'!@? =* sԬU . G+RZ,,p B>1eAbR0FLbӹN P3`r$5IL*خFrXm&f} ̖HVزc(3¼/Ć1WW+s5DV5`}hUhBn֠XF{T]X s2 6`>>QrDapLq٢|f@2d\uS9})M-S k!Jmau po`A]f9\cc%8]DdLG2c)Rzv67O@a҅<}ǕbK3T] ]$1$M3L5J2J)PT1CK6AlE>lmto^$ća%| 0kihEבR3 Cv m1gf 03 E6r:Ӏ2Z$d|msH$8E6ޖQG{BA=`m8/%dÇPɄ5hc{xp!6l3^@LBNB6fHA#7ot[?B@!wa: rJ5ewwfnU8ÇdNp{z3*C2BDSmHDF#d3#9 p5*NjQOd;Q6ՇQ @$kFJ52v/?: 6(A3B!a씉K^E_0a$V4@UsmO6v~.GNWWT)a*Zc vOi2a3D}5i$ /TitC2UXufgf#!7QOe05cZY5XEG/ v1fuiXs]/7M5h#y]YX)c喑vg0S>%IZtIhs3ױgRZR3W1Ujg1)|=3I7IH7 )]'z[(T/xHFUj/dE!kA.6vm8b3,S=oLRbwhXW)V13SgCH%3ZS`ַ[oV2O)S231[hF^eZj%39%U^#8-#w;%8hl6gnTQhuu7u>7?Y5uO:+uٷ-?}r( 62bV2UtV3sHi s5Q0[['X663sCNIuTUtY"pFpcX+8r&]ss/'5":dLdwh#4BdK8r E_`6JU(A4zJX2?:ss%/I`7#]t^U, 6eAEa;Ş6ȥa31qv!549Kї; NB:-srvh 4owYTwǿ6 J47=r5gCg <K77gw#xyYt:×]D18Ժf1t2MRy:z:9|iS7\#DD>5Y PlZc7*ұL7DJEzR AqCZCխ4Ed!tl\~IDVTmBڹdy2RR:(ABCaX6sH?dJ?Vu:3}Xc$qZG 7z71wh5YHoxo$up8P6>,BXIJ]}ȓХjuBTS鴎6/ߔX+򳏰cq(/J(001{1X[46s6>Cg7Up gsm=R4ef}s5 ɏuu|h-SvH7ؘE3m֯svQ[yXz tRoe!SI)L6o29d3הlCA? t3Oڤ &7 &Zd6q7kCm_`HBN{#dLUs3K%AmO?V5ޒ:jӱGOGhi-m֟3틕jk9:H54xA2Ad@ V:Ԋ$mHZ5/ST/}2<:Pn,L䎂3V#~Sѝ>nWLc#˂A*AI<.]҈d@?G7L9K,GՁN4F9,X74gG\N:do#S2VezcOT\zgZwQ5l91b6 Xn1)PZ U2tsG7 {Cw+80t6~/^Z0WH0[Ö@|~Yb=DU04L05k͔1c*;L݊ciT}]?h\EM#@Lj15D:V_Z0 8oLLej%7x38$70l52n˃&ݻ_Om`HY}N%qgI?5˼B r@]gI6QdDq9T]ŔVZ,sWsC8@$7A?SC}u`6A1EV?I&[)d=E`MIgkp$^X#SƤoM|WZ Vh-7L7iW/+WYކ)iwvFA7|@@ET.MNUK%T&ɷTJ c1`<,p$ @`A +QqDLa a@!!`@ A@-/(`78Xj뫸"lMAb` @b/A!a7vHV>^~ީDVWV[ `0~5t"/bźطJ$ dQG#IJDQ_2 4)P C w`A#o$f w L6q& D9tTw6HӒcثPЧ  $x(Š%93 ,0@ ˷18`ฑbЌ  PVL͎<M,Pإ R7gADan B )ɖplK*L` &f"@Or&4$ 8 "T`xD#N!xĂs A. #]c`k7Qh{. %kol @l`>0QxCϘ2Q`@x拀8!C, *3A DN6 @SB!iѹ":I`& @Q@22[K* $@4 \@``1@4W3BH g.*֢1!Vh3D!({(9H$E^%P W^Ds !eFm(&2&-~ /+תI(lH:Q@4Xk% d.B F̼Kk"`]ʹ##?J|e3"X:ܛX-Mc9 b hDS.[wּ-Hi=قϮ3G^دޘ@v뇔:^0P(~,pwHOv6Ш.Ý@h\00E?y֠ (&T]oBsJů8y"Ep*n8Ry*/uD)vu\XŲ(0kZʒ,*\p"`c`kr!WBZ <#lÀD@L?kbz["3] ~" :@~`&DB1N2GrlEg"'B|ڊQLaI$`K GYK+#@Z%MuR(&QLG4T-H S. Gaִ24cMhA%k_u8 j1xlvunQK>53\&D<y̒D@nr'Ӫ@oi6.G 'PBỏK <*@z Vp @QߩN(x#"a>}wGd4: .XXLPѹD,Zlwv3X60+}Ų5-Esz[J0fօZ5ݍu1xV,g7G(Z9o{lNX7~qJ"<P_܊B3 *uN5j +Vg9:c%whU9P1EeH KPqBkT:w̙N6: և CV gؠ mKLX "im7/VG 29[A/1`vg4,^NwI_c_VyDx"1iɫv)*K$=Q$ YPD(в5[^ܲED+?>sP$T#xnPЀ?1VfĨ"`꺐{ X8YNnyT{2K61\KPr=ڠ$e:1hJHGp.QL^!L*GdDA ʱ$+ *Z|t"``Nj*VN7ZPCI0B,F|B_(>Ub6!N/(%Tl B%ԣi$[Pp\JR7oн~I n4O$ 8  I_, 'fH עK,.3:&9@ȜG \*jb@ prHAe3.Lrgf@j lE*:GZ֞a+(M KK(DN(^Bi %nb:R$!N(m,*Nd@A#Isr;t'$^a:BL"@z%WX=ġXa!ΠiQw "EX`Lg|PxdfE*PCh; pc ceV^ 9R'!>Rr") Dn#jas C'T>\{>!(,u:G4%uN,Y)lWN^r J"4K|L&[ͨW̦I#. KA,cl"cLb+G$kQ`f\آuȁ ڞ-)Vu\:1<…ed::Bb$H\B(^kWcWJ} $2XS8G%6bP$)ZC{mTu`\2.D4u?f$+(Ql':سJJbq8S D 6 J(C3r%u`sRQ8bǦND]Vbc?GV D$_jQsU& &oAIjp /2{4( $O6pWU_PD ~X@dQ3 8BG9%!w B012>l-p0h#V"(G*2iBM`". tj#ʁ0|`Hwe.s"մw,jFe֖k85}^b\6"n5./`w}WWnEsEKHM-@?dyD 0 j h(Ju>"ؤ<^hA3:W^CBƅv\LD .5D!aS*l?(  dhC}*^*.X5vCD >#IƁ=ו$^B0=â`zqKz-5W!u:jVC1b@jEhCea $}-@pC4Ԧj$6cKV4Քw'`LZQ@DV:@6C/h/'^a:L$C# iţed$B/9>$ȤCFЂhy  { Dco[i-u,K5 pd״5ox61 BYÛ-o#!&('Nf3r?$ZФK4XNvzp#˝c;cr(< $02l=:)m7jGzdP U!<ŊP,nnхd!H($y^:GAbA'!ඉ$rgyr`0Իf6R~X gZu|0[7bwB }ڒ}aa/[}W \[4u6 y呩ۡ pZ | )%jhpA1MLXglީ1:voa6@-"eEXl g:/BC 1&Z].#~3RʴB0h ]aM{!T e148O$H , , )1$"P A00*  *pX^H Z&$ . / $P xPM"Mt  iV ME 8GHf$@T>8MD*z4 "Ͻiz0Q}*2YaTmC^{e>BԀEJt4D>Muj82 F(@B!YA0ԃ2 3 [  xi\vDI`\+L '{=#Ӕj%AU]!LăE48̈́Mxa5ءUM۴A7a ,! W"*1)"1|F _ |X8Zv#DcScw@E0\CIL  0 I<^H#E$R1@9b b)AB ăL0Do]dޑ $RuV 0P,0PI:A1AF—\pA\v0@ўWH` $4Q9PO#0@OzEi" 7Ÿ`h8C} gZ u @f nf`Ph?Ep>J}X< ߔE0~=0! V_b"TBϾS+)Tk4T`(@r0t8D(=A M60U@4-OqD,NGщ(,O>ڸ<4Ca]ґIjB E@W@' $ioT.hVT\y$A!`R<|S!l?D .P)V>!*cQ}'){xr|>.̰ځXB !r60&,v8BTr!%=Q}=+! pH8r"H'QD>VQl& $+ [2^W$!$KP< <` <$C ,%00 LR6Ě +8$ V:̬zcT)d8 6 'qG(fQ A&j3@n~b^l' 2GE'M!DF4vJ.9⒀jHPkde<ڶX'C2fO>i@@Հvl/EO#IDfܛpP(1Mo,Ҟ=`$SPҋLaDå'/d )=C `Yhē;I`BCRG*UY"t&X=,T@Z񓅺̝#?*Q1G Xz WjߝF%82͊S]N >]e +k LR8LûYNe a\>d'Rvv GQSp\@G1= PSːW\SPR0quX0"lz71x@*IBKW3Sd1& Y|}Tzy%1yc˳(%V =R"E(T8N`ÝI(:˙CzvP ͮ9TWjF+FIGzFOz@;&Ԭ@Hx#8_>!܍zUot(qs*b bCjh% :~=|3|>0G`&@A#X_sLA<%C޺K! 5ѴAWD@rv`YhiXBQ ޅ|[fopR%NGmAF$zH )Uԃ@AtHx`HJ |Vh.ded^C,C\͂e\MB|I)P%hP;t,L|aV%xg |LV>|(02L-!4\_V5PP@?:xцز8UUh,s)Mnc',\]- Q@0#@2 `PI`\"1GW+9:ICt d苻J)8 i>dFPJ \>J #d07G%Ԓ8G(D/mM{DBnW`/iyHyl"V&R![= ƆOH@upn84@(%eC",CK(l)/8/,+ēAJ<HGoJ4VD*SdQIě qAG|ƀ >Q9ր+wIVO@m %%RϲmCxk-yW7-W* Aȡj&Gye`圊EDW4 _s .@CvI^ǒ3P%ܲk슌EfsIl{n|GL35zh,xt0 " 2xr5At+HZМ-6d P0tXIcĵ')̵\;ʢuɜMI]Hsr}|j(+uR\TRd('2@ b/mF33P훎RJqIvɭBreMV@ XjĨMiQVᇚxtHP8C>8a0AгIKD N9A|#DY.Q;^8z?&a;~@bArP0~sB ]̆4&F՘E,$Nn.wKABes)KQH-C|u@tx0n&2x;QpD{tcPST@s`1hBF3YE;xK a;uL> D|X$hZ%l2޸`s@Ł,Hq!:+Ȭ;Bɂ'U)uB^$H2 JHB,Mi al ­y@@{E,AmNsx:p@y uGᔲkR8;{7V,H$>fo- 3@7xG5G/إhfHtxpƒ;v_{DV?H\H؈(`]\h,HY%# tO;DWB{QO еس'{}RFđ1rbI Kd9hn Kg/!Tس1?ɉ$Ջqߎȩo;3՘%fIͶѥO/![en6{'p{+Lycϧv=Nb7];A챯r zƎb8!3prw 8(;P‘`*$ i$fLÀZ;8) SDk p xS,X I 0xdMZH@=ԓCŽw@EXӉ@0)i, WrD H`G @/:$/ F*Q@S)<P*)H]Z$QJtPv | -)0M Q~*آ)J#Ǥ\b  RX `j*)@8;8@ RLt`ZS @Yye# L0h-F HTS`iZfQ#8lEK?:oO۸| .D0'R-NgJH8ّ1dt5A\(,0[sĢ.NmaIDgbHtV@ejnYOzo&jIZ`& /-w2(4IL %.L ~UP  D pH}RFzM NA1D v'LE)e)/@ 3"<1 1s#ṡFo8]سkνgV_9sRGU=˟OC-ZSNؔh& FR~Wa6N Z_(\-bv^U3ȃQVCh(#sF=_eTyM9'%Hf{BHG#Fh~Il9K p0Z"cX.T柀!ihRf蘄2裐ss(KUJ#{Z:*jW*Ya*+X걇ޓ|r{Tv*c:"5d&*F+퀶+sr%WN+nDzz*조.uk-:PUYo{.ˮ:(p+I :j_&*gtb e(+/$,4*c(7qh~,D}P6#J FG-TkƲʹUw`u!٭͚ʵp-tmx޸ @n'7'Wngw砇.褗n騧ꬷ.n,#7/o'7G/Wog/o觯>p/og7HL:_&H Z̠7wGH(L W\f8Ր~7w@̜wSHL&:Pr9 粨.z` Y7DީhL6pHG5ZqsX 'j=Ұr4)HB2~d!/E&2d81Z̤&/Xⓠ (GIRL*WJQQs< gDҐˣyK\R"/cYML2 <;yA&HZRӚ,+9kz3֬/MqS:v.V̧>W)ӟ%8Jv&/ũPrr IъZͨF7юz HGJҒ(MJWҖ0LgQVrNXMrn!POFӠ"сMfR̪ZXUMLRFaX0EL4+ZX\I%(CJGrQ}k]վVq Q,[BZVu,c1Xux=h#eTծi)U>lgK[ rn8C4p[kmKZW\'Uӻ Koxѻ^.y^vYX"NL`Po3X !L[o~7{8D'A(Nqgxb0@cb?4UXLd H&;3dr<)3ri+gJ2L2;ENf;L:wa<@r3QMB΂>4;͐'M7_je7N{ӠGMRԝ~4WVG< @Zָεw^UbyXf;ЎMj[ζMld{;6Nvn#ۛ7(NO;'N׏v]s GN(OWrK0̟q<諾û*@ЇNHOҗts\l[7uU3Ϻցxsu}ܲfNhOew:!Awսz#5zE !O;񐏼'x]<#.ѹGE3WbWz ^sΝ=qU> ͏~>5zƞߝ{q_jsl~L/_??z}.8~|~wHMXVʧWPwE4swfX(TFF?FH蘎d  `0C}UkVguDf%JdQTtOguE:(hɨvXgxY5YEY#94BY$ɒY/(Yl'wXXvE[I[I9\5@5\NY\M[LIX)G؄T^T8zG|d<_Iȏ8$x^v^wY^y9>^꥗x^{9} _*Sh|{j9Ȗ@CɑFLvaaF I9aia I:/iIمBEc=cicib66cyc;;c'u58ؘ7v⹃閙)kfVfXe`b֞ad fcfe_fedR h9z剙׏hghg6h4hyfh ꡁjg\9.7iؔ4 p:j6C>iDJmUNVhM5Zwo™֥3ԥ`k_:czT:jl}XzJDVvzxنӐWԦڃoڠ:*|PحYcb4 }$֬ ] @lT-MڐÝz-ʋǍmɠ*՟.ea eYmܱ2ǩhL`;׫MA\ܵ-r}{+]~}-s̛mm;-k)vhVF~zEEn&P Sʅn,kԎ{]/|]zM);=Zλi=mL;|G~fj }0ʶmz+-d}\T\ޓM,n5\߱MÄu@t7Do;;˚JLwC_PmGZVX_yT Q5R;d{[ jo_G_n$>zIS~^ޭ/ˌ>Ӥ_ kāL\o8~CS?N__ڿxһ_>뫗o~ ) Ld00B 'B N2*3N#2OD1EQ|LlcaFgQGqrE!d WR2I %J+2  3h3D3M5|ls8:τO;s>5%t#?DR@2e4F#QNRL#TJ%INN UG:gz OVweueQW)tj7\nW$uWgu_=vgvY\_ Gzp>韕nr#'8wxyLN'??|'|G?}g_Gy-R+w~$P]Lf6әτf49MjVӚl&/Mnvӛ#eDg:չNvӝg<9OzSg>υNCVS$*INaEhBP6ԡhD%:Qn)\ϺAΤ2ɜQr/hR~.2\)șu7iNuSZ%3 Ia"ԟntyF!ꁈgTԩO?a@qAVUvի_kX:Vլ])KԠ4`Lh/ue*R)VU} ³a䠺X%j4UI$Vֲlf5{'v}]Fʹk=hxp?llnu.r{ O;\׸EnrV&qN*ǻŏ%mm;C:kZ<ּIo[ɒ%8o|;_׾,y(е_wtȼoj.f7MmZ,\77of{8]u@OyG^rxe> o<&f]sوF?y~"9y~Q0^1 `ꤴW(IO׽.(APe'{u+&NN.(!Ńk,<5-ox7>wҫ3۹ @㣮J3@!(4H{쒱1Ԫ<*/4{Azky@ܿ34"-J@>ɻ˱BϩA",-BA)S@? CJ!z4C:*79,h(23->?D,[Ě1 L#3?;CB\4̙:D׳Ø"&5B>Q$R4E=eU*NXYMJE!Z=VErѥ_`aĥ[cDFD5=L&lhij2dl^zopyFm4s|nD&bvtw(@yG+Qǂ|}(ô*"ǁ$țG8TȅdȆ4+!*ȉȞ8йȍȌ|+@ȓNj|dɖt! "A\!IzHɞɟ/.+:DJmH{cʦtʧk>$ɤJdpʭʮ\LB?ʲdŋ4T˵dK>#1!˚DCUHX˼˽KWF 4@4LC˶Td:+G:ȔJpsʅ$ eܻlzC |JS@ԋלǝJ+88C8 {JpM$lTɗHNK\9{N]Ȏ 9OO!ODtOMHc [C<;OdMȴE‹|ceU> %42VSDӔĒ\CF4F""B4kӼ4&1<-B.@%.IJPBD=4@O%މ0QT0!>E¤VW~ˉT5@C|>ր<Ŗuٗ>rX~Ձ XM=$4vU)4u49V.]0=C*=Z<2"EW]ŭڮZOHY|;5*HbT۵e۶ݥ5YSڳ[j۽۾&律5E\{\e\i[/B~mm =)7CPduE+y\D۠V5]DO5+'*Q%ŲLdH5AQ+Ek3$;< H+UA}!%*1K߅^2c?>@V~WKَ_ ުR7+ %ݏa`NeU|`QLAݟVmܝs &DװtA$L`ZzVgahU+] nFث(2bWWXWH3b&4^E׹USC=Y,kae5Vu¢%6Dc5&"BSH$cD+T<I_E.V#Zҳ dt:`)dmKTg}T^͒X斘eZ6f[z deNffnf ^`o5X >h6bovf)jFgEeqfwFx֪nffg~gi>t|Zg-gyvv{~f|}Vghp{h~ſDsa5PX.\ɼf>~rgfpv A8]~((>ޔ~e.wj&cd,<ͫY%_$*_!ZޜH-S;<>mWm2fdMݰͱV9fȌ^WFab+c- VkF3^m&.+*0,A)a`EdBOm%m>۾ ׇW.&UyMa>W QVTڞ9_U`DX10㌽lf,n~6YhjeGFKddm0o#6iWoOe__GpBVpH |qp7qD ^G?߬8]a:iO!'"əD9ngrtr)t".;Ģ}䐄D&kd3G47^SBN7Ga2o<=W^&NRsOTEoK?EV~f=t ˾MN'5G'AXt~〼;l6FwW6Po?X42PTW55i<>׸6bLY`|DgX6s5w7XMv5$r ٬rӠ͆#`یLww6{?U/ed2NL9NÏwsq|Wxq99Otx|ui\>i$Ai:A7Qy>ϳy3y wgМ =fhA< /ѥߘm=mQ2 o/}ӯ'6?!W{zyIԹI#I2,#?z['_'`9n;lxp-ȗ G/U,v|H*| i_xgַѧJDt@G}گKj{ YZaخrO[5G~Zzvdl[~ibcxeM_~;g Oyz,h „Yqj'Rh"ƌ7r#Ȑ"G,i$ʔ*Wl%̘2gҔ8#MX9` !Dx0 ҦRj*֬Zr+ثSFi,ڴjײm-ܸrƽsgϟA=)Ĩ0a>n} g|:'KƓ>蛰o> '!o}ԖcҀ+P`C H rHсNx!j!r{-5tS9uv,6#5*iZiVa9$E#1dv5Aє$Uiѕefa9&eqz)דA"tS7uiً] @F1(y(9sX>(%eZ(e:x )Z`J)fjF:fz+f^JYTGf-޹yr{J|ꩇbKr-.WMj+iKQrI ~ꮻZ/+V|0 kkK'{+/ybc)$!2f΢%: pŒ. "#߰W3{(fnƟ=.rﻴ -;ү/D [?39_9jгZ*֙,ID:M Rp޻\l2 SoTXu;U"!؇8)V\ 沿D/Q4!-q{a()V"h8p\(0h tn|#( :rL(fը~\CІA ^,d!gA=J")Hz[ ¥I6ʱ$(C奉SX8鰢&p(B]om,sK!%Qc'E)acg"U^ ?4)iִfzMkq&8P+તLc|R 1I T' "S[0] tCbNx2}(nY@T |+әNpRk:"q"*\DFP.}J$z!bnN%|#Jȡ4CNwz$hZ!-~R:8aj0*X"S!^Zjn¦Mm>Gg#(^?m~STd"_av +d#Kֳ,֌?6D::R> XK,U 鶩 jζ*ֶn!nؚ=.r_BYe"Ŭzdԫ]p'9]/O#t,tv}_vɽ/~\.Ӭ 3Q$"E3V:sDw~]D?+gqG7^}}b#+]$Y:9na>q !y?Ĭ voެdׅ N ELb+_.|pf i1MJ0UFqgg&vAdiI'?頝);}3a-/v̾ӟbSLܗ5̖.3ˊbYL?ҖzMA2,mrYdgL^;J[NCG#z.l2geA7D wfD[-v ,+V9ʹ-p/\vUov;U.m=a<1ͽS7F|ÿZx~nY<ߞӟc #-t5!0Srov ӝubJN69Ӣ۴AgՈ/Wx&5thG[ϒܜSVΛi볦̟ #-^V:d#nY ݋ r +(r㽍 c\L_$K@s! M$T82ʍ'eKP^$L!cޅDwF^_%WvrebS"S1hA jWƥ\K`ABNډNBW h _N`OΥa7)U#f;Nd1^FZV"iٍ_&bvgJ]rdA&Gf,$g&lb#+$J&&glT%wgJf}Pjc^RVҪU i)cUcT͗A{lZ^R.$:_cD)Lf_-NډC.o)f)5n5&Z}Wb!B*]|"e)]S9ATǧzΰEyޚ>cmXi*I⣪[*F2b.J`fd fk&rh)ddul$vՎ+䇕[*&_.1އ-T*F|N #9ƮEz)Z!WLp}r%,bpZ[(r! IM4ch\27`FT@VFhO*w7, elq:7==4Q2Q:ُx~NU^Pp Ag_|"iTvy4J4i"=#Ѳk4Mo]Urm'FZIg6!tU[_>fUr3b+*/l1/:u﨨I^o5j?HVjZ9; hdu-iDLگ$Ln+Wb+ pz2q`oC=3P3{79WNrZTծd=}=yc&SQ0ٽ@B%B>c^,jO1k[:w e >//9%箺nDsԀh i~W8D3N79WMw y}!!p myS~8 @8Ќ ̈)$҅b; !f EB ,X¤Te1/aƔ9M͙1<`ʼngOVz'QNF-3)ҠN*UjҧW6eJRRn%:6lׯSͺkU]ݢ;Wntջo_\xJD*q"JF'N$tew'O%v[ Vib;?lۻe翏 iS" >ԏ/- ( 1P 9Cl.l>$4R4HsQ@۴ j(R8YD#Ez xhCSBq)L#/ĐE(I/S1Ì8HS4s7oSEroAo;@' 0;ۋo UT-)K1TM1 Q2,L3{e,pC51G9Α~#$;T&qқxARt0! %E*2LG@Z{ pd XFʉ%yut+aKYΒ/wXw8>:UK|mlSFIP .P(܁^@ T %Ȝ$$a2 2Cq49љ2GM77G'J7h8 D~]H0` Z‰t4rMi'bb\W݇/ 7M-uK3N#4` 씧;OT@fE-Ѵ("BE$680XІ3g:#%{o8ڞI}t1&hHVHk.*\aW.2c.+fWMY|I"xPfP@ sBp\(*\Y *eVI.5A{̶ڭ~˔ܦOh{pwK7kfPz յuW\P.Ӟ V֓"5*@ t hĠݒ'(ѭz#F9٤Nʺ ǍFֲV}^R+ 5]Tk~8La @#0 B`@O$B UD}QQM m\$Ie9׈|:AapaZo(v˩bwvWUrsы& HJD@ϣK"B7u6a*Q.(VKeN32z->{(̵.akʙsqLMYZ<|\|/dݓU&U}>"JJɠD$U =~?|->Kϓ/eKF4U&0 A iFlү 0%P.bqhXz2N8 D@ \$hFUpepi*p.PzIG(5D` 8B L"HetMb xnP̏`e l'7~j& @( :W༊B^PjdԪ伬h0 IJ& N{jB f`` @rZnc s+0/ROi"FM`$N!u<pCL +k%@m q.+վӴkf ka)~* ģrl$2"RcJ2+Q$srEDjn,xi(Āv @f@ J~m( )D)mή0=M# Al$r2+$XrmG d%~ P+(%u/Ĭ^Sm,*%2_zS䴍*Ռ#D2)8]2/c4{i[@ Ԁ @CRz r#IOmp02619,8 >ݱ8 9S| 6G`%@ ~@ L @ u<`N;-[<ae椣c6en*K=ת1Ů>!*?uS`Eq~ura d` x@X4JH`@LīĐKpGLiG1p<鞜/Mi$: +PN5Pk@8 PRVHIVM%uRePMgQ뙠 <@PT \DuUY5D L8@; z1R)5WuU,+q嵆*Xʨ|h58ؐ  GQrpuWu[UW{I\F~N.Rg5%K g[^[uSZ+Q ~P@P+OfKBωfVuV_-b+2>%yni6+{ !%$.Y], omdm(x^f?y0gwgca4aP tjvkkm@VX`[޵;bV+<@rM+biqt026?@0O<.1p)E_YtqŪGb&I,N A$s P6(n!LT[-nk\W%v!Fu[u7uo4xwvvˌppVphidnG2 !>#| ,DVR);" "epn#v"E~2~s2hmWDc/S'oL%T<JB#@!^@ ZG(׀"3_8Esb|PE1c۩֤ _E(w"6uSGWqg8P[Q ǧ {'KI6tGm-N.`ZM@H |8$a@ $:!ho{ w"<18NvyC~RGUA\r G?;p0!<2X^,!*Aͬ5ΓwXWiF EK?aTFCDOݦnÿ~թy=@9Ù,M:G  :<` s@Gڲ-ỜRX>-9;6:6YĹ*!xC)mvY/?_x-~ÊX#B!dV @ BJ* F9` .yᓉ'Fx+N;z1ȑ$K<2ʕ,[| 3̙4kڼ3Ν<{ 4С!x T!#̔!6r8U㕱d =6mڊ7PpBe7 K>Z@A%N|9%Ō}|E-d5fI4͜;{ :ѤK&mRNJjV`ytնF~)m 9D,A Ļo0RЊڱx=zoʇ˛?o6ۻ?ۿ:ҦONzv[mZ c3XTdn9JT 0}1QC %Z`ex_2Hc6ވcBl!蕁VlINloDHAd`A W / BXcdH"ffnrʩJ7% 0S6(GtKJ :NJi^*l0F`jhY4Ep TH1C<@DDH"I>A,H< MKx~z!INvvbnkW)[dLNyYjv^)@ B@VI%M6Λ1r22$|r(:2#y r0m}\/w22|83*mtΌe.N? u8cF/ƊxݜrT <rSa=p@QLhJs7<ƊOP-QԤĚ#*m#@٩TSpd<1b$AHYEVi"T[ ׸ZK \#5AJ X4 ,8ϳa/mc :H+QNkY#'BV4˫qvk_ ضk=r]S[UYle Зq"s'XJwԭh} ` xA [QJd0ѵ}nEU$)Z* ܃+8fmp`""XƋIBˣJ9,=K'Fg" τ.^g&ZptX`'A֞>0kKDyK41q@lb}U13e 0N w IB 8yts@yϥ"Ddg>yr^ˎPЁ2? /ZO3Ј..9~m3_(˜8Ol<:$" }BHwQ8Ajr"?Cc=̶i0~H.d/']U7دn;C\7 GM/g̉BeSo:ţ~K|W?| (?sÞrأ\̗d]Ok/sԫI!xY[ћ,H~ùˀ^ _'OmrNvǽ'-PּzvFLjۉ-l{4?B`;/b~(d!I%P{?\4EqPqUO3RPB/.hĄyG}CMj[+~wa~0`-YAlk]~pW1(3X[ۧ5'ȃ{lJP pwP P1GG wM U Al-~&v~{4a(Aa7w.pc 0 I Jp  v'sIcȈ=Q6jܷ$iwv  $;mRR 3 $wGo8py򈷈z+X+2~7hq`hnNx3~RP+ <0B~ȍh0(ȋE*VHl,/o@(PV`Bp Wpp@i㨐 i}vPvsܘ7NrdbJ8@%IGt ƒ,yb<1vQ}3aea4Y| ɓ*5%8~imgRvgpY='Glu((QTf퓓G3ٓi#?9X)l0jVkV&/tdxCiDhIjEh3UP4c3)#SjjI–gx1܁XHlu(Bk irtplZZIudIbH9VcHG9K\>LBanaY)Wh Z)n!p mU&cwa'uiyWxȩLGGq}4YxIr؉Q.flvW~(2pp pW1o^ DCIUW|Ù3qLu] uPuhub J#5Kg1l숉ᇈmfVg `k$!ƎnG@e*I,|GxChĦBߖex9qEFyUsMe&g(dl8Gk&t'p $J\bzmyL'dg kʜڦljiLojdGZI:IAt&ɫ&yo@*ź` Dw,f:1e0?*2ںs7UinJ^&/j1wwIob aceʰ%\SfVv!w-~ڑFp~9f-)n ۰++Y EkFor~ w P ^#,kG?.'W~frbp Di;(E6}EekOiFJ{rzo[z"R&bN 鞲Zyk>])זj\J~w@]@FXk &cd{4*as N l Ma7)*bUV0y1Үק۩ɻb g6{@XKӕ1K7ļ[i/+By Ȍw؛}^FWЛyZ@:4Ciުi e+1ai"Qpto,J &jr[zm89BwZh#'DתOBT>#ҫfyK (C\4 AN dC%NXE5nG!E$qGPJ?rL2@VSV<}>`E%I&S@T8đ'KD6kW$H @T Ғ$ImEIQA]y}_O&lN%/NBǑ%O\e̙5oyɔ+[9M9w3(kDv]4۵hPbIL #սd̘e!1y u3i_{/Ň^a=w,zϧ_}AdLl)1j (ccż3 ƠAXcC7C?pE0RLq x#FTq4CFo|p+rH"4H$TңDQDaC6f+n ܺ  L2 "!OF #괳N$! H3@NAr8*fS+\QH#tRJ+&# M׆*50aKlRO" \qbTÐD]wvabGDLԀYhvZjU23MfWJQsBTs S A bMuwn_8x㘝YkVxava}SnP[#*1"1S]vPV7e*4TXwby洶2e ˨g k :i&Rhzjxm95P$<SEc]/X +rny|uF!}ioWbj#ѫ*Xj\"x G {K.dWk]/l}w%r >!W{w{{|rW_?NTsYm0(hE@ ;ݩr4`vY]hjMD`)&/."GBz>[^I4āP[_}T~ڔ%V(/4 $`+}Ħ- 'PpL`Xb]buEuGC aHQȃ# 6r,8<#! yHDJF.ٯ6~dH@P"qI tI);2V) $fD&,ќ2ҔJFMc 4^34ta h=αsT1K2Ld5yM,2kETNB |f;`AJ .g ;ǃKo$$!9\DeҠ h!yQf4s.'a~¡ T Vx P;YXZ |`W$ʸ+bm9UW q$<&SHMe JХQ}jTCMUSG-6?"QiJcy ( Y:]akP5%"0GI* T "C`%, 9s?!;m& Jy{s,&PI((~䠔L0$`V$B 1 xc"ϫfuUh:B1;GX@ rf]H `7 w!vb3/),]mp.#7G[\lj~2,/ ZPX H&P!`"jW7?mU?3q$)!gH˪M~r@sTS{m߫ \6ym~sP0*Z2 D ,#$@ p@@@ZD(HQMX4%miˌCt" 8b޲GREyLn:o難M'pA!`$AGԓr'Njkyfv2I@ֱW큾{Kl#YϦq'3dV|dT vܿ]c(w u{wdɃ_6"PS˧s@nZ 7 G]y҃T_~:L{M x6H@J(RX2**ETߛ*brZ?;̡#k?#4(q?DC0R,b!)+@yJ(R1'|)B*' Q*<٪s(z=䠑;j?;*A6иA;#¸"%%3Fc@@S &jY! .<=/\(z.4=5$AS\MTAR :;|CYHZܰ E!0/B2'B(|S1 zb 9 L\!%[ETP4E4t!f"AUOEx̨GzG{l/;7V05 )P58/`聨x8!O 5SKkld?Ȫ CSEf%$,ZC:Ib?6,=o axI"II1$'C,=0A1=pKPO7@I"6 Kˌɉ C} De+@0E G HH(LO @,ﲻ5(> n $KȌL=s@$ɂ7ҁuaL#Kpy2|*(D MݔʌߛH"ʋ33@x8j4P$>zNĽބߌ'NZbK ӹ 9tZD9eFMN·O)8@ ˫O4*ۑ>"O oPи#O>$ C:a:.caB#mWX0 #K=^IBP0D'kq;6cFndhATZl\ޟP*#RNC/9!@X5 cGe[HP]_, hxLXF"Xy`%04,]\[fl\ pdp!pNN TȀ8HX|B4Zf|f(EpPӱLHg*5_ Ȁ1GD.ބW}h8K ] Ax2%/! u ^2kKe5֋Hݎi@RJ& ]Uбu΁U_>½Ɲ^HFUjaFV$*_:~4N* Ah ŀVkah7Wzm`ɰlk`7PLa'Be*P(gY_jCռͅ,.% i'B֮ ȁ)E 'X 0 =#6zYx5mVi}ۿH.Q@8o_8 CȄ^ffolnI>"JS*Ȁ }7U p0Hdco\ʣoNQAhRk*8 'xO:.m:Ntjݍ_p#'Po6ЂQ(uÉQr7$e}T%lR1ȄQ۞5Ymiݹ7_tns)[4XQBS#n gtSgG`mbXqpMqDS"6ܫX^5?uaTnr?2'p@/*-ǻds)avF.v`p*pmx\;uvBtnwv$"XZ 2)75P";ORȄ;0dnc hv|Sh & eu,$fNGNP7\Ds$YhÙ[zG/|QN#sRChґNNƙJlwYM?4RW=Rr׋& 'IdjcV5ɏTwS.U]=zKI eI@y',PAKt|J|)y+PӰW>ү޾FY+9tLE75n;!}('mG9Wm| (<)~f\  DҥvYZ[tCwG}"}8yy7_)WLR / LÆ }@(q"Ŋ`b +?&Y=0)@I&%͕5mYӥM={9eИB 4ΦIc" gTD4u*Q?REZJdZͩεR*w.ݺvͫw/߾~,x0†%p.%QNec$SrG=7 -z4&Oc!Q 04r ]nf7޾.T#O|d72*}зПOԧ٩:ݞ;l~u7ٿT,|_x?(b9 d>aCeMHOPXbxCr!C;Qb|rJ&bhb/3h4ZDZ;Vأ2Ǡsb5xRUT\@U|E~Y`Wi'A_~YiOIx9^٦osu]4I>ؠag!2AN) bʨf jEZhIA ]5\\UFUZE$eYY|ZA߯cle, w^KŠnkt[.vօcz>Ƨe~j;oXtn e!]ag]+8{oOj:fxml#\ҥ*.23L7< DI%b(3QQDjn-R[k۱\Xܵ_cω\*'e9RoSQs2̉8KG PI%C#ބ;28U2ٓS^cXi#yFD y?!jV8ЀC7!E3߼Cs6~ _P<q_>x8RdqRl,p޻z󏪪>&e  h"rԛ"2xb{ӂgA(9p b Qm[1 z7m{.-#r!*bKj+76Y o a c8> 7!y{%&K'}&[u҉[0v/kYzڀ/ !y Q0G4b7B9Nh@O|2eH"D:lmi5XC9ъސ%W>5q3?PivCv%J B"Ԣ5C{(~-75`m[?Vd!_[!)硡uP&8A݈37VXA`B*p{"kAyLdmsf%0(VPF  +^ 2b#ؙmt#< _nҡ6vpVHi$u4o^1M t434U("yBݷ,!!3k[QK)ޅu! oɛ|Ad_+o\ Wh9,'rnτt | NhAH J`{׽>ִ_[|ZlҼN>|ѻE^D@HP~7vGj7AP0_-a_ #s=_i7rսK o8]AxJx 8(bwN+#;ԫ_u3>OeU! X$@ٓ;9_afLP[@8űեYhEIɛQ}<W Wn)Z[(ߝIJZ`NؐA8Z @$H @XEdAEOOfPΈ%!%ccFKmmEFA*SnIA MJ%eF@oA"P8$$xȎK5 8N!Y2fcr!L"b]Kfu4 ,''p&N$8"4D kzoD[9n渤eŋ[%BH!oxA"4J--Mh$%foy:o.#HxQ"Dq@(B%A0DĀ 8x'H! ^^Ayg:hթ'QHrR`hb|'&A 9A @$yM^Ф-{"rX>hhEhyļl|'XJJ|F hB%@Lh GD$$z.XiiJgM-)㛢|:'X¢Xc2 P@ <)$G D7)͜"mbRjVNc\FjF0`)HQޑ|FB&8DHC$An N,&D i_4Ҙ( 2F޼XZ2Ld."dO'$T l j%$d$ dX[%|Ld`^:VzK "ԽTW뿚˳Mޚ>ѨH qj+ F D(굝ƨt I ^S++* l˺Dk."r|ag"D6g M $']t+ a f"I9Brm"FVVZ~jm!N|ށ#p':- A@ $$pUn;piɊd/];zBNdخimF-ɧH nn^t,9݆8UIJIXJjڮ˪pYE#+Pbr'@ "E@X:F@^ޱ& ֫Ҡ.nz/" Y.errF P urԁnAJM*erig̦ p#2>aKeV@@$7s{`2dv+q21q9jTHȰg8@ $('A2Q6čӑ'q"+ɴ1$q x%|q[E''%1ƛ΍VmpsLdEctM۴L?Qrl'dŠDFeE`w''%MtTcF.{T6"MK)[+OdQaZu[[u\\u]]u^^u__v` `vaa#vb++?kD0 @"B%DdLн hܢNvkkvllvmmvnnvoowp pwqq#wr+r3ws;sCpn۽D'8BmR-e"]YETw{?kxrD ͍ۨ}dԂ􂮷{#x|G fbQtu%xx3xoxlcoc7bPx֬r2f7i& wz|g:c98 ?uԺNZYߕgG?jDoHOBd9E8DGyɯ GE5zc0o9z*AΒkF@'9#g+lOi{TOӎ1a̰ 's#{++{b0C{KS{7{X{ks{3{{{N" {Exg]RvL$| |#|+ VC|KS|[|;<]s|{c|bȓߗ=g븆^[&z(~~~~ +3;?'K4@kKh숞e@OFYf)ÿ) 4xaB 6#51aرCX ^` a!3x2={M/XΞ51ڜXIK/E[L!7y{up6lXr{=i#Rr꧝6ej֚jZ;k6k6Z뵿.k;l9nf!v[ {nk \&pȝ%@mKY7V]QZ'z=ۖ3h}?yQH%~R@ygꣷ~~x'_'?{g_y{ysʷ/z{>2S(X,h=Ox2;Zt9)zntbʹk+T)nw%x`I0YTJPRTNTMRԨXVURO+S;4V2YTֶ:5^]VJW_*W׹c-k`+WêUqk^W.}_JXNb]jXvYlY.Y^B!{$#0%h.kbDnaU#Hȍ.sR׺Խq\Cs]Jw.w\7nvK^쾗y׻񥯀nn}7'\^'Fn{X.5T7*oy#%eE~[T(b;\x/PĐ\d#Y2&LNr e&;YFr%CO|d,cyCrɜf5[R299erg-yŜ6inLg*J4>W3;w1]Pe@S5Z۞VGw]' vn1yk ]lcV!f?іvI5mk_=jwֶ;nn{ڧF]+KHrE;ũLs]sE^U$D5^LIWҙt?Qԕ!_Yֹu[a^]0{~v['t5`|)֊X+x /\Wx?!_9y[I_̓^-QYϿ=.j.ϖZN7&P|W|?P_}_~}??~_+>2.zź޼zF>y0th`  P CP'+//03;?-pCKp"*bPfhs_ zP C  P p  P P QPeF() RfՄu9@Q ;Q'+/%7Q S ˰lPyS>>>?S???:;proguard4.8/docs/screenshots_gui_small.gif0000644000175000017500000047237611163773610017624 0ustar ericericGIF89a@...888KKKTTT]]]^`cdddehkkkkbjrjnrnrukt}tttrvzvy}~~~mwozq|s~z}~z|ť̫éɦШѳijɼ¬կٶ̽Ļ͵Ѳط޺ҽԾٶ!! NETSCAPE2.0,@?*\0P†#DÆ$jQŅ; `I"3~DɲeKxp%@`IϝAx ϟE2ӤD:zhҪJ zuӬ^jkحeU{-YPu6kݹo:DBLNca'F@Bm3!@x D8Vhᅗ Hqag1*b! ,h `@m(Ga7~-dDVidAqv`pCv_@R'(yhƚ^r^DCgrwgr=BDe(\J%PhvjJ*.ZCu ԣ %[%irjWR(J)ڪ}??` F${*F-64,f;-G8:Gkށ춫nFֻ[zG7 _ls 7\0Y8TPA H0Y\ r kP%q"'k!ӬgL3&ir?-/Cm _(]L-[Q[}Wm $0 uEgnGvsWm_6v=%MymCǴ5-0TG]u\H RL3XxCYw:VN7.FwTHo;.~w..{#@1Hh`C *d|PK]׭3{_>KdwR"n8M^' D 5M-|` D~̠[x Ԣ/ cB  @ 3`y k\Q;n@!n%jxRs ֺF0XbC-M#5*F+oHŰl ^ ^(;ώ; Hdž Q`CBA 4!H& |$7BND(Nze#F wP#X6E bpZF%ZV0L8|r bhR6"~D#^YTmnC4E!,I@RJo"d|`Cl! wb'<~❅0!14p 7"s}D47L334Ol"a%(m+)6dqhdFhNqS괧>iPe#9MDH6Rcĕ2,[S@ 4pҕJT(AND!PE+LSpCJW|us4IF2ɕb\9i.!KOsڈEaiNaFy  EXOJD8s,l#ԠMMvQNUWN0lV$k?~inSE$"i3Ed1hJ;|5m3:Vڶ}!I_r.B^@Bʃ ! ! pP@/o<πۆNS1apNz"3ʻ֧j#6wg1 d9u4lϽvlR)kI*";BhC)-gg 9Fj$M?L ч5 :p9\ 3f7 !70΅24D&K)w|bQ;UsUPVkLw;l5غ`S3ޱ?Ǖn8. -NPehuDu#1dn2Ӽ P@aV>Yx0`0(^ S؃T'5D0/o1%u<2QW۫|ن?u+WKl~:i=W6q*n,#ޱs3v؈~"tgۙN3|j핂$Ma[S`xv}<]YrC [ ;mje"V_~f{uk(BrZPI̍(31H3j9Q+shk[[@ԕ+n=+rY_E =?Bdl[\maQq ~s?_qHNnquW]A0fJU66ifb`zm6e{%Z%|uj^? A*j|C\cvSn:metƂEvtcndp:@}vٖS|4[X0`}hw>W0R0VHVXUx\؅YRQ`LwM~W{2thRbgJ#L7'UEhsZ7^~ ;ဵ?LF8$z5mUuIW?tncA\JWs'WD2v|䀶LC<-P-bbǢЂ-8,,Jp>Tv"צ?cc\{$aUHWU?!#︈0q& Ak;0C&>|mRHkPuVvN qd2afj合0.qcA\VIt$KG@P*,fuO+)%32f>UҘSynBt'}kJݸyz:0M7$ז{fhz ar #';E'զmƦ>qNur %671tt^ց &:"ɑ`}9f'zQN6YBYB9kcJ18JK`y(Q'DJ`D̦mrpbUx %A~cTT M /&/# @8)>6 n#0%VX8bEnXYU.5Zy 'Q+7vEFY$luJc'SLxQ&Vs;Mxf SwSG#V~@847({1j_>Q*_V_Pp\@D 7@8@$u09@cTpFZ.QW嗞6A`u.ERenaэaAvi7p)Or2%71x!I]v4n৸Ց M6ڑHPz[g#_* k0p08"p *#0Š3)6+1.1 $x7]~"#$%c\*Mm`:emS?Im@Aɶc8D wJX&$' @6my!!"8JA{z3v!/0-%00"@#8z7 xzw3jzĩ1bqIʱku0ÈKW w{` y8r82,jӛȱ薧 {|Cvȸ:@GWG471+xpw~wGxGrpsp10mlwlx4sk4񸷳˱F8!ٱwj m#g떈@Ir &6J*aˋuH8ʣJk'w~~뇿'w~q ZpZ;`9R˱ Ų +Q$㩊8a51chۈ̼3m ;GFX>@B ]0X@ ,[T_ttk [!7ب\۸a7mu;k'pRď6ھfe~C23`ǀȆ-|}-4`3ЌeE uK{ 8 K ƁĢR3c,§ذ&\88$$pxH{\A;1fm6, |fk;QHj;Q͊aa3K33QmɸD\[&[m#6e剫󸹷%ՙ;eS` 홇Ї`P܈K1)ذS lۄ']m.E\6Lv ۨ)Kc mcŊxZXp y`ZwMmStJ k Sfc m{n+R0 H 8ak|1 (5a8r9EM_} vC?C`b`TCpj*ail@C0tڋTI 1l2T m 3y۰.1Q?uMR8p@=MCPC1J0UP#0%p# ?Pu PN! w@h@JcK;ʍ7A A˕c\r}5̫j*݈:ˋ1-<1FފE=zo|3>&PJg  NP@ J=^!"P64o]͈֋P< 㻣Ÿ9݌{`;,Ui A%1%fK!0]ZF0NvFgpto0wppo`op[@>xzATU~6_ m1H$vJ&Að~+ùk6w`ymEVh+|ý\tCGxww{~{Ks~s1+%IL^ۺC(ϊlⶶ[ZlzQ:MN |aa~ rm@tJZE7LT˙En^'[pS0[D^X3s1o^M'Cը9IaX•-=h8#U`g3, a ;QJ:0,.li|h/ؑ@tؤdO;=뙈K{ geK>Aij3 ?/o404 Wj kI6Y^ޱq|C>BHp bNxS,k?p#7SXk$0Rl%dP~m~iJdf 0\\̝͝Ե^W 96gJReJ]60?_?QQ{EceaѨ?5 #PD=<D]|Ç /:|(Q $LpH@1̆nleN3:LD7rD䦤  lH`!)P* 1-)IdD=h ?4 j) DQ#5AƌC$QDal̘lĈacEEY=zu6H!Fl/][ڸ{ftwoܴ3JA7'ƀlL̜Q`hFm\6bC]`?oGT^@o_=ƁgB[0\(D`!  :Da .衐A)>m5z{Pc/Ȕ(m)scZ]f h1Ý^HԸw"~ B6RB{vT!箃}(vv#:P" F@ @jǕ%A=ab@ Ѐ* Hc'K%vzB&]lI$#$m UEև,H".T|G%- |ZK<;~ִƠa.*]fGeqJz$;L2 ^B@-l g(p-XaZ9XA^8(9IJjL X!fiB#;rL*3 :IDڢVk?Ha]EܖNޱg?Npde0q\ߣ.":2IF9O";چƈD:ÈHGz CD8DԢtE5QvTZ8J:a{ ,. aJFR}?uU_0uaya(Ra#Nbܠb" y2U!ss2/[jbZ?O`%"ւA212!yj/4ֱ} ƾ^eRVlnyi!v@LL<"EP%#n1=RBc/ `RU s_ dm3 !"m2Ltvqquv!4ڨ DB!y/wV=YD :a`> h0#2pp%`3 >j03l&'B%#UU}h'$j8_eO5fQ]%t*?OPeE9 aPrc7y@C|FPn0E'Zl2Cpf6ykV3,I5tPU%f wPOyFuHx{v NYwW@\IL{}Ȇb2X-ozƷe- un5`H44|S AP&4æMF|w=Xܛ 7U8` 8` t 0v0!A"ȥ.|'zk@*0}n>| >@v8|o{B2$5zս-x>9#II! B0,[*X ZxȐJ2^dznf=r\<{ZTCFo^7yPD {_>}S}UP~տn˴. l` _8\x> ћ9t@9X@\ d@@ l3@~;9fK5@>!i6K n4  $E(6)!<8 SƘ*Ȍ҈/ˈǘwږw"=C#ȭv+8wc7و3k5H=l;@(sIC0<`ޙ(.PB3׋spC9[ _5@ C?BD(EN^@VkAl`_*-8@5 R9  "P-c\->H; w:5Q ©`BPƫ8ok HC!z4 xx0'@ϱG[:C=yCċJ`4qBHG>IQ0p+A; `gB ġIa(C!) ABᑥj*f;s=H˻9)1 p)AK?:#|G\*xe\FHI)I a.pdhF u:BypD Ėd&j3HFؑ@Q d @b07ۃIJNK-ck6C+>$B<=6ۺ9<[`CA`AqWSn.SI<I<\Y ,%PvcCXCp܇y5XשSںmڗ[{\ q3(@?0`<0t\H\ۍk=9B0z |^C8 =4(pC0%BX -@þ7$ߓʰ˰X 88X*Z>ܥ߰ͺKo=XN`;؃$N%;H<#)؁)23b%9D@((~"^a,FbX/0%@(8/F0>%1$9>`%]!h85>1h840B.A0D.C^5ɥXlF_0#55h55`6OdPn5PUUFNF;%Oawd8]*15=V4(=NPNfP6fTnea&aFdYB"V6q2ò\>H0a4Vea6e5Xftdr~W4l:?NxFi `00{ AJ}6-_oe;C`ghgcv6eMWga6j~YD xa-q68 Ց5ذ;韎X#Wٰ CQ͘[i6nfWUS&h~.mӢKkk>kKZN38f@fnftNy&gh_( 1 6ـ x8l>&8Ry l!~=i22 h+2J׆ rf~ ٶvVvm>nmێmJhcԄԾB7qfgi.fPv뺦ONSM>i7}٩r > {l8m6 00l 0hbY p q7GqpGxqff~f6oaftY);qðʤ5LNk+7ū*ӛf7`)(-)QQj,f%d>̶k^5_s4m6=T5G&O=7(_fgUdeN?6CfYV I.j6ZAϥ$ޱh-(."ƯVvqkwezs[m_7,n`utF甆CWvcNv^g Z`DkTtVFiY'w\'tHfkvZfng>gNirfGdvyofS?eu(nkffz_o81w}Km+ "00B'dp?A~ۤvI[q-Jvntf?{_eVqwxBVSK%x{N~_ubN3gh6vp謗gYvHukc`v^/Ϙ(Z1 ߰1(rp~G0p///w<{'w?v4נ!hM 2l0!" !s 0A"AndHF0Ё't8O6A,K0:h1dn(٨tȖ  UD܈牒DFl4H@>ǎ-1PB! V'pj!NNNf5/\P h)KlN #6<:7)rHgJ> 6͹Ъm >1-\C*("#a|䘒+ݹ.$vn 2 cMKD5I,>:`h6ڃe 4!@%Q`!8P!Bc6mrRcٵmԗM7H@GnϡKkjeBa T? %@P1Eַa:d y)؂UXdiA@(hVi%V k{ "irJѥA)"$򗩧)z*"'u:ꭃm*&iI4ik!V;hnF*vbz;`{.ǦK )`=Z!6ڨjaƼvn <0f.~,M[d):D"Q! *,5cfnFbῪB LrAB7FZ]fN8A#KE "Rtbjzv!ЯxD|,3S߼kfP] X9լ󶒀HyjzX~]_D:>Fk8X)fB&;`!e,:/b>%bޱ6A0=WO<5cDfn;QoisJLft:HYfK]Hc\[ U43<}paJ2eG/]aJ tp'~xKD(LSv?,%7u|2h\z[5 @3}AE<3!l&CZB$x w^$/Ix K`FNG&WqUt GӒ$;iوt6RiE#t%-s TE$]Q |H\n"C"-GD#$(ai3*'9$*zs`H"ă=XXRZ~SC,oj.12ɅuHl *.8ecdH0u%"ى"]4&|+c÷O#UhbWeCjW"+[ժlZ_)_ŭU –,6-FEa{ѕMW,gCb5E-B"+NZhML~,!xC`* (cDކJ"KB_j,q vO"-f*h<лE QFl, 5(Nc@P X7t*gT&kSw@BtD|"RP!: +r:ߨh' B`eV @&F E/I%ef#ؔ S!>SJ9!RjYˉ2EgI] ͛|BC 4 :3{p _;FtV O{:KI'cMPǤХ-iWH(+tOzs$Zّs 8l|K]IZv\6&Hd+^`=! iE}B!,(x|Q46"!JH"kL+~ANVY =]o8>ϪDIF2:zRFќ 9W2ӕ\+ lm@p)S/CVBPEd ; RA lQܨj)-o{*y>Y{CI1K 1tSc̀fuW.uqN$'֙5B93h\BDn•Ռ\|eÊPnaXyY3 (nzГo|kTYh=jAgaL&ѐbg e=vi!gL֚WajčjSꕜ'Tg HU'ʥb&iv)=`(n"@$*Ɨ)*`*]͊ J=oHDjf<K jG  »͛PTAU͟d0M(\h< 1ϬFDGa #r%^dNjN`,]gcBi-Ў[.IDvktn+FBe᧶˟i'@h\id)]bE`NL!GEV:@G\XWdEuT-Ԟp4PDmXDф9P)Gt^ĕ{xw4Š%iU SU"aXYXQ=3i-}m "XsdytEg-'Y ^HpDELQDUrKHFm" ڜ%"F~p\$v%E1tc3n#㖬FP[,IA\Iઐ+VOGɓ8((*h>w<1UA\j: L-JJPԱRZU,UW4ˬ^Cm{aϔ!/H `Čƣ`Xh橨N ]޼ ҭBcF")6>ݍ΢\ 0SZ` ɌlK(g(No*1 L2{eUPLFbNj ):^ SObHRҬgV˦BU*0pKujGF!ӑ BPyF#=M*aJL[BIF6b%.l/ oqn8P߿ %'# ?'+r`0H,FHRH\t EnXF@Qs]mQtUiDqy\l:r P#h}8 .)Up꜌sdw..OGOl9hL`vEJ^ED?Xު~Ċ_f. T |2DΎ&2/ujDH؊Dnш+E&tZ#Y%'DGxu֍x2G⒓H<pY̒&V,`dMӪ iX`dBQbpHH{)Iw*'i?bF9>H>2<pH*7BpI%갎аB*lR2 Y)0O=M}vѭDYRGKЬlWPmO{ J?uh"<^nCӆ'O#a:qY$9pbc琹7/o݁2U `,D; :4Yl酼6u!L"xxuq1=3ߏwvp Ȓ fAHM~GltMC9S KzJK ӈf< bm>v6k72z q7&'HZA/\NQAqj#D_p'z:jb,+`k#\:w:[:b4z8UFl s!G(j̙z d@AnFz30JKs)cI@RԴtN`Y͢{#|& \i@TzhRء)h979,|ҢjQ:ﹺje O77oL"dsiÑL(QM#qԏ { K0{i({~Yeϸ1#| 7ΔҬfЛ4pth oR~a+i7lYH0̺ f<;ӻ5%c?^ "ާ3`$˴#*VʬzrҫAc!%}?qC=H'D .F@E7@8pi Ƀ(PC!FQ1fFA6ȒGBLqąDC `Թ'0?jAhP3fЌq2$U7'fUVe)kƫbU 4IߺM*WLn=FMξ}J-b&Vuqg ;&[o1ͼH;!޿sdX;qmU!互2 a,\5Q M>FwbD1Ҿ=k_[6Y69䘏AʗGYO1ڊ<Q2䊋 @ʠ҂ΩT?!eQaJc080c 12# 㾃k6ƸĮ\D<,BB;ӓC1 BHCÌ;&K TrIH$QR0* Z?H)$6BC7GCp1j2ϯ>%-C'm SQM@$]ml8zj 7SGPΌ3'SX$S"$$c7tD!B";,pqBrP.UZUU5s-vXL{ " do/>31SCӺ7l],ӤU4 @/1DžS%O&Ր$KJKJF B*LUf=蒵jiݬ\ 8(V:K0ZoSDMkhJߥR_k7:KؓTvҒ+W5)"Ըq W74LIۺr+*$GTyY;{Y/,Pu7r(福@훥?]肯C,)٨6ӣxcµZl:"=|#۸n^/%-'Ž?D.AI znP| #3M w()Mw)IмAߴ!KԘC1d{)HrhOn@0V.51*49ᠺ՗xk 5)*'4~(9$ SЄъZ/1]x;䁎nC3tܱ"H:юw4rHHNRrKNh* a0eDc6XÑ|7H2q"w*LU^`s"OdؽJ*pAaK)(Ph.MlK߅!1ۑ *X)A1Pb5T A6/u|VsYٷO)'Af,m(TEѢT6(JaϬaMN]L1fzZD@[AnCDҠsYjUY:*sTy_)"h_q$01 A>lNT'[?eu`!D8%6( '^o}2%%˱Ѻ XH9U]"3wME2S[9 /;H말k?$SuZπMhA f mhA:znmAlOg6Yph&]h9Dܡ D; K 6TB.,t@ Jp.B.g.. @ OЃ tAV:ҫ/@ 9@J' *s VnH^j~@<^ >p( @)` NB2OHBP,J(C@^ taEA{p:X O8C|z \`Q9h+O~>nХGv@o /#P2 ֠ &p/oO `Fq4|Fy2ZlD茫 h lqo0i   p Ҁ  0 0iҬ)^ 3"!T`l#b6" B 0 @  P @ !B-lz9c'('C8%X]1dq)igqQ:+RS.XZvmѣORK׬Yjw.د~l۾l '6JT!S1-gּsg̛xMӨˀNͺ@WW6"۶Mcwݾ-Yͣ d#A#ƒ!NHHr,m|ӫ_o:e/3&4ȝy}t(`i $0`p@@ p0jFg!ȍa hH 1[,8]@ @`(dp]'t@bfhWafDFa\RGqWF 9Ù9T ufȽpW{5sy'{)蠄\G% `~U.ԢVeNBidQ覟VjTZ&XY^ihL:릏j묢2U+T:jܦFH08фV1mZ+mUP҆k-b{L4A'./k/΋/,'poDn G6,1GF#$l(Ɋ,kdb͍<9EoDs#E!:+ !7-uhBiPp!BP&p!@ jP`I gH#g$o`C# Q 4JoHBֶˆ!05~k2V/ [B:z#oBZRm lж-"S"M!Ski@g+CVG@AB0\?~Hp> 7@AP ܠP(A d ~(nx Y3} L fqDB~3:i%#.n-`9Y${mj8n5`̾f~O`&gpe`<ء6qolcwk9z׾5b!UH/2C,͆i=[m(?a=[=mlىpAgWvY}gi};E|V 7lhZә >4 ۮ6)m7,B uDzHSzhӜ$9@b!NG_ґ*ܒ{XI\W$`uvUC an8znFD0!Fc˻k] xs0%qxs=c~&A@dV//h݅ZNp$Q1 e`C6\io@$a [74( Ht3~.gH#~Gxos1u"$8/#  80?˯~PduQ!1YLC`cDD&{B@l8)`)@kgDaR c`CQNttuw(MۓEŔYd&#cOp50%RCAEbG(דzl`@zC9@HW7 F"xA#Eo(y`mV79yW9 VPwhWX|cy3{su}J8H^Pa艚xXX^`o8$FCcCt"'0DPCn`GF@Dgbl@ e=*8|aG7d 'p#pǡuSfrCL78D  F8"BuCl0:`90{l)uPo(s2%@39d($1@d0p22}950a@^T9>=T;IT@OQI^DhCFPz< WK9pS&D5R'lGv9 xChD8ςcaw=bfcig) 7 WVAcP3z"Yu\wfWmwGF!ۄ‡\UR%UV " @jk\A%9(@I5;SKK`8鉔@^P_v p}{ow:) w)5)8w|'x}w)ikP;sz`ktp=pB`%`x`@`]U(2 0]%|P}s42 K*4P*^S04`,03#P+Zt_8tZvzxzvij>c9&"cvBcUjs*d_5!SyOj  `0B4j#Hp9ewtBu0wp'xkUw"vD74IADip79CcvopUìʧz Y__^0]`Ц`Zl1A`S+*P[H,P5 G0G^`*afbb7EGYJtNhCJH&b ?ptA&<#g͡&#{ MDCf{v Vf>mm{pnno z w˷ux 8_BT`03=H0ىUڭWX{qՊcFZ{k=78Eh&<@E(WGtC҄HMHEMDE劶ʻ({pY0`һYս{+;K𼈘螛(* ;뾛86W9 eP"$53"`Yz@p`ppo F;P?4CϡGz|%˼.̼`5|CAԈGA]7<<ÐDFGCC<D|tI\Kgt֭*ؿ*Hx(huvPwv}G|X/bwt9<:$p?QR4å}22,>@wsklȈ\l[Ȓ~Ȓ &cɜɞ|+4ʊ$0(1 ; 'yP1`0lʊS\;{ǜȼ国|@Ѳڼzy%?P$p1pLpҹ'=U\I:n9B<9gg}<||y0<]*(s*|`_XBPY\_]PLS`PiU7J>r*gf1tA;9 s9YǙ`9zxOlV}ih :*`ݨ7&_:fv3AN`2-Y2`V@:`nP:\$:tX؎N`tX@tMtU`MHUPc2=%>eڈ| ;` %U Tfyŏ]m~*V0Ic`1Ͻ}؝-݅;\&}\z $2p-( 11%-@eU^;^_Ŕ`?,6%bbC_OTk#gdt@v@s7Vtu`iSdc6U<0wY9Ag0?g[A` a_=,ڡ7g HnKGsp2^V~`q3o !^Z<~nXڦZkޮlnr>r,WVio5[!%4z@bZdCn5~>^閞5Szs &@ṈZ>F4==5>E\`\e봎AS.غ%a~VUheY5(49Lէ|ԇ|g}bwؠlb> JLO b' -L9`9x( ~VQ ݪO-]=2q}|)`V0Td`VFV@BVP`|/ _6 VgsBJH]fD/@ݛ$`u%T%|P8DB>@+@?K3E_e팎A@\mU%`U ?PP@ 7@0'E^.pa,`_5'DWB 褝ӈrtinrq`tk)6F_V/ .{ {5H^ NO'ꏮa ]~.s%ZVfΝ`@ ~IsP0 b@&]ĘQF=~RH%MD7$|2)gjp4hK XћQCT5fTŚUTM$¡RXe͞E;!6.WDs"]i |G_6|Xb~Y3h">i-_ƜY3Z<*dhѥKrI/[-3^@"A )#ݹsG[xoἉV5͝?~ym#խ_Ǟ]vL &#eZ%- FIKZP0#7510ADpAl0 -&1.7+rHa 10"+cD8p 7h#2Ê<cl< GLk ."*F əR"f/&,` JxP :@20XBH!?9$2PAH@"1@MFMCɠX2?6!Z(<@Lb . ZHntS*,BVP!벫@0!:XT!ސ4Ib[B =У[,.4@(.*,H# 9 [=`&?C(A76fxjBx;<8dG&dx2 fXb 7ްfk™f *ġ0:iV8@Z/HG@]:kDf(dllBl)3rh ۆJ侊&Hk'i:8A zF^#g_; h2|lwO#IH0?~3Dk!Z"AJIGRX>LI/ptA n=7A j ЃP|Gk Xg@ )2CDĠ @T g#Q[2E("OP>pANЂ\j :Ѓ4y@E,ͱO9 \C/] h! b D6LiC<Sy RUȠ'X';\` C̐ѕZg>0+bĢ\b<1XXǀ_zû. y1 X5p v^Jr3m -gBDRhlgKI_S 0E2̟,Yպ7r?k#v=p$%9m$QZԂUD*0Ԥ'E)J0R0A+iIVР7m΀P4b?-PsE-Q(BGJTHU*GUq@^QN<b;NҚVoR`tWկ}_8ӦcEY5͡},E!юNEcYey1G{cT<4- B$bH*jQSg#4lO|[&#!lk*.Kzl.={Qp $=< "EW7 oKBhVnłPB2a R**b["H!?@Ġ ulbD0Blμr(pv2DL=rS_#q@ PPTATf`# 9A2rC"[̒faImr;s(im!v 7`9ņwo8 އS!oB0|խ ?x'?$UOG+X\ <3o1B~JBҕׇF,J6B4,62%gbtw!exp-5mMS3%"Ljm%Ъ_OBuBBeg"pԫ']L# QeY9q,(3vPh1Qv_pЄ4#3p'#ev-1qni5ɪN;}2 bX(Z(znA C wN5,[BY4 :AhpB,Zُ*1#~@@"Ly@?!X(1K.ʐ>=t*{Z| SF 39@9+#XS*  >єC>G3[!A`;;qA!A ) x4or4=Jc;`:4&*7*| 245 kL7ԙ8C6pC;C{[5c\Ci7S E@ +$mMD96NDPN,;DZ Fl bEW''p&hY[E &]EYE\ `E\HS)[Ddq|T4͠ǵTVT=A}Ґ8+΂S:N6 eοTRUHAMOE /EUVen-4I:EJT }JD] r0, VG-s! EVINpϐ NDQIVdUsUPRC\QI WSLYUȼXI\]Nm͚|mPMVM %G~u˗ P%T\SQ=]Mn=GAZ5˜wlOkAD YU P|۶PߌPW8 6}P]O_MMѤZTD^Xtr6jZRϔ,\\!5ȃA ]AH>>(BhM]U]ԅ3]?}@]A^%^ܝ]mݹSB E]--]Meu^^-ӥE_;ӕ^5]U]]]%Qٜ=VIͩ5D$BqڃŠ؃!`A%^`a!~aa!>af"a"Nn'% `.9-U/^1>cl;܆dLdYPNXHn{d{3T6B6fPD>fP.d !VM:7`Kn p^pfC;t6GItF#qt2gy&gi_x]gqVqhy B^vgv{gxgh^hqnhugɀFgi+ Ä՞ ndi1WTciߊ(B&i.^.j&jQEvj) PոI"j] "!`dj|@4u:nY+kG$( C`SU>[۞UH똖$`mАGB C `1G p1F#H$G#<5Q0{ZG8H%=0"1f9Hӛ@nk.fDfjxS@ӭDب16 εmCISc!82H1hBF7D2H2060 0v+Hw#o ppWq0p"RMe"O@l4ho88 05 p(6pEgpN7qph#\]^_ia'b/v-ܔmQ)B[ 7|8TRcP`K)J:u#@@7@-!,?@h \6r #i!mTvX 4%'xU2~nwn4Mk}x)Mx ( 0Ƨa+YEK5 =H4@I1J:Sj騏s"y>%qjX[.Nz W; Lz 9bFFj~MnvGk>n.kn܏wk$aSDxk](yDP(G|/6|f7ΆlI1ʪeٯ<|YͯPe!}Y>W}7Od?dxӏ}/}}'}?؟}}ܟ_w߃yW~ЧO!w4~GGs4ҟLV:y|vfL=5HaAػ^&= "(`@| GP *8@#PB>,DdAD\ƒ]T&I wt&ΐ@ ɓϚARn@R>(Dу؇> th @E@2BX$Kȇk &5B߲:c n =/`;z0 yAs`:A,d!HL˯sF1l)>-Π0Sa;Ə%.sj r`%09a)hʡ r()#"cUehL#m3ZC0#]|gjHe=O}S'πⓠAgXQrE$)QtlX+@Gp(HCB7 @R:T.U)K_6A5WY=ap %zeh="}*TR!m an\Vհj`Q#`d6@kЦ,pʤ%f?-&EԪD&Vخ.~yjUe Wf*C,#U&Gc²j kYrl0B ʀEAjeP 0Һ_RUk͒jI#ݞ.` 7r|r[^ހĊwjUqX?" p&lm,]%{,!(X噏x޲WK9_iѡ1le0]"$'YsZ.xc!GXUaط7jZ!7By.tJr&7(EYNBG_-F=@І@Y`&3Ϭf0ͣep $ٔ'ԋnZ̠ ˆv1t+.:y2%F;єt⾵02aE2lӳ,C63`74Y>4K*6 NskgΤ5_Ȩ_5J[5Y H6$8vN\V[_0m=qPSW6X, y5 [Gl8kpjR6㊘kϦ7C ޿ Z'ηxuj&O"@ gt mkH >c:'"p7TjHl):'n|.bWmdq~Eـۂ,Fubu1g)g>G[c?|;gm8ȏxヌkɧUi#A>*`A]IK \=5Ս]UXyN9FhY3bmH >EVqbU"' !(C}}ZQ BSդ- ,}U!zVT)I WL]Y˯vIe&`Vma6%AInd%*XQb]a8)_\܁]!WGm)Dc\Oz=&ݕ`$YՕ #89,_dHe^&^UWxbb.z2 1[A81fLr :jfAUUH|bM_g''{'!ߒHgfb nn'wW f((J[A<̇e\dQa# nbRlsxF''zvbzjUՔ'bmgBIg m%h*a!%~(qБGXqd!ɡjhRAE!6#g%%V`_TV= ؔbdb5˰(a"H±a_}]^.أ hEd9 "aVQ`rΡ,Ss:Y5Bgi9Bd#6# 7VNzf!W vF QA%jmoh$  d]@` )hedrY'V~N!b0kܪXIJq`ߐ5^剤"jj ,[yRdT%z,kM]9J>:z]6rlMX|*k+r%ݍ\K l,=l Ă!|J8,t1+(N!fR,e.cHX!&SNcG X #b%ZH8y- Y%*`*:āڂgNجYvM-iգtOƖ dUAh|1RMqiRLf*`\Vע4*QF#V/66`y֍pb"A4MjaAyq /hV:Im 1obYgHu*unYM]V['bKȱ]Z#N)ƢA/In.WME! 4SHp>tC_%+󳦦$}/<mvc McNq>s[&C+o*&RH&;UXPS 4OsZStP[%s5,XWHI5>CuX->sP'a*q|ȇ.~Ru^O_sZ/Ks 8Ns2!d=fT$g[.OfpF}_riCrm}NZWP`gpf(_5QepD/`u85*&Y^,wZ96CwTvD۳]z_vՅW!iH]v'uvu5V+f4cJ7-VgH yH8$pJj?oV^^kQe3f#sJueZ,f8)esk6pC+yxaK#ϯcsRis=7 sfFu* Ub`sw9k2ݩue;&4gl`F+sȖ;HZCOw?kt>IZg7zs18w|~tRڣUi嶶浱w%CGT4pWRjzz74W|0bxpubcp^]F=]0V{/Yx[sd? vgT{1'9i#~&mKORStAu쁪GdЪHBJ<ɣF<|p|˟| cnjʃʫݳ7>3>>/=/~O~C#wxͰ=xjowFeaӗAVQDbQ!4b5?*Vsǩ)(>'VG~w?'-7k[m ??_'EE$y(@"4B $$C|04 5Xd1ƍm<)F4ye-_|9fMpnĹΙ.]9fQDy3'Ҥ;"TjLJ$3Pˮpv $P@f˦tjңjӺ!G c_G1#6hS:Zt::D45 y//$TL9= @20B,S6SlTR_SU45MI&`ccVcdIPC=Zh lDRȽ2ZC>5OV\Tw7V,_^%t8 Y#$> 5 S6(!`iqCh;v6"Axkc!8>@#15SrVw}dUMznU ML1n/B25`F ;l>8X`m@@^8Dl$6;1<8aPxNDQc2g ARGB 6!S YTi)uxM'u^?u $ ?pCw<FJ9?[S lm+n_T X Q;x hF5цgB ц3qt#XG;lq0D$+T#d<$LxEwAɋY4켈zUrVdf&ńQ ]xTR <*UJTr'R Y/`F4SgrGBqK5ea$Prp8 - 89s%J !sAʙ8;$'}dY􁎐హ< \6E1GPt2]DFAzQ85h#NjQ>uiJ-RG-Hk:R>&)NGSE5QӞ.Jmq ԡFBeRRnIxCP6a XJVm]B WUt]sWꕯvͫ_ X&5_ Uwb$< mCC79gAЎ5iQZծuka[ΖeXma6 !,@...888KKKRRR^^^]`ceeefilkkldmufoxjnrgpyoruntztttsvzvz}|||mwnyr}r}z~v}y}~åŢȦͪŪɬҳIJʻ­ӯ۵̽ļʹԴٶݺҽսڶ%8Б@X C#B44Ć0FT(cƄ/,IG'=$xeB/FԈ1dA1a̙rO.wryM$v<9tdɘDD1 Z] uٳhӪ]˶Yd۞+mݻo7o߿|p[q=#1Cٌʖ1glffϝ9Mth̠M4kέazmԬkNןM 8Wk.6sH4G/urسkνv ;RC ˟]rzѡ)cL>LsaFt%!@`8 ("inG~H 1Y x#h(@ H&]tHa qm`i(`b&cJ`ccfCnX+hxji|^iFfGo1蛃J]=$蠆>JcU:b`Yi`]香zzFj_[jiJ[):j CPO<DTQmRX[U8Qڎ+UK-^Q%VVYe !Vq|/LpLo /f[o;R\0 + Vּ-!@R0daf$ 06T+P8<`bu@o|[R9>)oQ'&[iR~!PC/@_ <'hp/A ]JXԕ?)@ xtC>H9H#t_:P5 l]I8 +!t`:asBj%iI nr@A bOUj-]O*&=9zҹ%_ݡux*e`tyoK (D!/ gX!{dZTLw#>"I53cJWv{IΚ Ae]%xx L1 bw6;/A Wp#> nhA'@szk'ȃ)SktFnLV/D]}qw|40 jG"Af4k^ H 0A q[")qe&CɖlnE,fnLHsx`֊$ r8C!Bn +STDWpv `7̶bKÔʏ4;VhNМ"aU;sP$ =Pa;$- E0t_d ^BA`&Pi[ڝ,ċED2ē gx\ӊI=%,0#z07a X`,`RA03P$Cā^^^E8%%d}z~+8ur]%g䲛E<۞@=j-2| "0A>pA oȀ2`h R| n$"G:u{z&iG癞$QлS p> `~ fڇ?v r  3^@+PTDx ^4W8 <^5XIk`> ِ5iwg 'mЀgHg(l((' l'hkVlfЃOM>A؃=zpzPwD#gU^UVBSx[PSVueU]UmuMwo@>S8eskp@jc:CoƇo#n&:}@p@P6:j9y d臧ƈX@È9@HM8cz@:n d:|ݖauYEbZYbZYYEkpk@S'|b(0PfCrkpj긎؎8XxoЈ)p0 o|p6 |t7K7`VVP[Б[``V# ّ")i1tv:XA7;Ɠ>AVLٔNPRmlpGXpC !@30t(`ep+4EteF4.rIpvY7@sI6:yIvy6_PvkCpAC=@bP&;H8Yy x[p|p3p }R juCaaI)`YͩvvZe0_ŀf` cZae`pyK٘W`W]^OOpOp.Tymb y)ީT7 aVmx8o;n@B:DAj@9*JMLCʣp@VzRYGNC@ ]_Ygj:fz`MP ͩJPMM@MPUp&`Ϩql|wAY[ vZum*w* wj S]#ڑYUpz?0I Y .5P26PM5P}Z(:[Wz5z=` A=J=JJӮ꣮Ѯ3=3)j뺮:qq )0 +J!Y@$;Jp$@YZC=D'AcDAB,DU2@2 #PT3"F35tC:Hk38dC<0$ij?[G{E+2.I11ӵ-3B5[%;/R,yi6.:%z+{;9!I~EOF\ø+]6wph6daccdur_5`%5qqv2vbW ϩY% \ !Jͩj|Rl*Szv;[+3:ʽk%1;!0SCu.WmXqZ湌Uq c!PB=73"SCAB0a62Ht0132e B,C2Al8CE5\/!;{C84D(9,ar)Y`7f\_\x)h,6c0;(HE@U j+ȉsȍlJꃱw'M0Mdʶ~yDg2OXڄdPpUi+GSv٦ee=d{6:@̢j kLͦk~Jp6\JOW!wJ ]ǸI\u j`IitSE^,z 󶟐@o?l|сER!&-qX" M%}&-=)=(]/-$7< 1>=80])(J}3<5I=&KmF,g4p4_T*pEH|pkg`d0l0w @` yqШ !zP|صȰ9gNBKZ_'9ٝ-@Z:;Hj== 8ڣڱMۛڣڙMٜ۬۟_:۹=ܰ9 Xܯںͥϝ̴x׃=G)pR)p p?g{xp7xD`۽gPPuz0o[`/I҃чx؟ن6%Ry*F$@4'@&x4`24}ʰ{@52JkX($E1(0C`mIogP'^V~XmmrRP~ Y\r`u`j@ryjtijwU]e%W'gH(;(A&;CPل/ >mK4ŌYŦYxgYYtpEqgtplPdAp;A$<9;mn>^]F4*bޡ>߮_ .`Pyp]W}oH(@0؀q6ưMl̐@l x@o__? !O' Ռ0O<,/?+O/,/?@  4|,6:ROoUoRWoN~:`ؔm%|j_jgqo0X8v/rV}uvsO?sMMBP|uR}P|{pR6^|?7~/ Iߓ꨾.?`ů_ڟʏ_[!nkEs>4͍03@aСG ttPAE yĈpT&E3n|31F)brcɎShƔ,Q<&Ǜ$9j)MI>=ܩRʟ#/b$ PL 琣8[84dɤIȞC,YHJbdv-ܵeʕĦaWGΜQs@9B\#G%Lad6ŜYfΝ=ZhҥMƳ5P!G_.iIvXvXe !Xʐ$xʰYaH,|d!4[l6 G50c 1c̠hɎ8HE|eV 9_~rm"YD\Ą,fHALP A92@0! H0D3)C`>pd V$1X"$1"8 0J)(䊐B>0x Nx*Ah rMT?3 n+>:1z v@@ ƀ/2 bJQG%TQÐ-b;5./ 5ЕV5ËYs :tc?b.BC y$ 4@(q EH!YC6Idv[7^w卷-xߝvUw{.^}`Ww^xݵuN|{#x/_H+.H4e:RfuGV3܅Ʒn(A}O'}Է:r e Iᰆ0&Y IR":#< 'H Jp*b2(! ebP 9R"2THFp2!|<X塈F4=8bk/C9C$p{1$ST2c8Gt%[qLZ5H?]iDwp=12 #O>c(E9J* HOXg+;#.e"ՠ>!vGN~1p H9MjVs4b GBe"D6a |3 ` HVwàD2p@Pg[B`M6ԡgAU!Et) ZE, PA@@@p AfAXЂCh |pq!OC @ \C0VժWU&^*W:VլgEY#FU68D4׹^"J:hPiDS@Wz!s ٵ棤2ACH3uTuֳmh;і(+mjUZֶVqp *%0YvBr{+J `ie mh; g6IĎI#vkw])Oyw{~׼.yg^mWuv{Nu]v<&A fn&#j$3a(npC{p9WM91;b{'qm<X>{9\ '%COre&Gbp!22/b,L!!b1B`t}ֆ˼o3$E:Ƨ}}sg@yƳ ` <""9P fX%Ig6sEm%eK:^WXZֶuk5|/`@QVL (Si^H QW)>v~ny6|"|+X=Pl<.BsP].Ml5+kə%dc-T ^qz'[~Ui-QՕ/+7hI\"U )2`AE&!ůwGJ2D!9%ьD瞆Zi\[K ׭djю&y(fTE"ވ"D"%)L`XMw5E%쾡+]5knz/v3o~_Ow+w7>v\Y Ҁ*D`A{H;ݾF'!fpq?,_^2EUZۂ(#: .x/)P"e @<022S 6r 3 (AWIWD.`4xuQF$؁@4iC4T%8GU G (ȩB,-9B(B,B/*\0C@@hy#hC8ӷБ@X=4+PAT D BDCdCL$$`HDxk U99C؁HA$~U6 l)YZYZ./@4E`a/$鋠8Xq14< xj8r8xFFFlǫlpƇ)Gt4n,t@A8H0AX;r:2'3!3 d|Ȍ?6ǬLɌLt18xLLhKKEȁ>6H!8 ֤ iM*C B <4#B4cEp#|IV@>p+ 0ȂJx$B@@P(m!4!$<5Pu 0Ghc>=h@#x'''')+4@P;GTMGOԚTQIz$LTUReQIW-XPVeUNYTmUX% Bb5c='(V!%bUVcejEVcz,)#tqHa# Pתiux庴 ;x w};Y׭a׮ÚxewMWפx X)wWWHh `U"@s4؏Xs ]560ؕ]Y3PSι,ךYq x0F(s`ڟE E٠}ΆHk WxG`Z@کE MY֜ڰE = ٞ-#8ۣڥ ڜZ5ڴu}U۰YZ[=#U8 8pqi7\ kȅ6M8x ]3#]%UeE]3@-]M3ڥ]U]]۵]؝]E]U^m^}]}-^E}e}]uE$e4X6@Mrj_6\\Mߓ]YQAV133_&_-u`}f&`^v  `a>>a &aaf~`aVa^H}rM6p*"5bŰOľko˲,ź\S¾`ڪ, ]#bC5/2^c4b1nHʷ%L9-bE_˭\"#$\\3.!-JVh8p| Y71/tc.޾ eUfQ9.@޾eAFe3NcV\eu3&ff_fas Y\Bfu_}pU c'x#0!@b_V`wvv_ygza6`gxag}~g ng {~gygy~fhN`XJvm_aj6bGܒ_GmBpyہ~ Eqn1X&!hݞjޠj^M.jި&jv꥞]Au%\7xjkέ]< ( 80F]G8P8XKeY^e+e4kR&fcacl쿎㹤cAƎ.l8.#^n^bZ,#͕ܔkԆfkfTy.,p>^ڶsը"k>j\J<0\>:Z}QY[nd40erIoXp66fV[>o4\6 "nG&jhߓ=Lcc:d#h#L;hؿQW=Xزp iGpqO9жC>nj~W20 Wf>cGl0 (r)+rD.r,/+7/2w4r7?2s5r/0s:?s66?+('(d^Yk>X><!(8ʨ멅$y6t֘ڎEm8Uu@#_fGYi7!"LeJKCh!U|ўu-Mi>m[)NP7!9w g3Hg(HS0"eh6i C(2\_mOe4V)@^)Cirv$(("(7儢.6&kv.lOnHB(5 5D柩TtBWgw_Iܰj겮>=pVtV#BAѹ{G &{{B{?O|||W|ǿ'|/G|a||Տ|gGB?@$#_%q fbp.&~6ngp4a~vo~q~~~~~iyy}%7m,hp6 sCCnĘ!H;$qF!!ĈC)Sf̙6q93M?k hМ@L D4mB]sN&YU*R8ne*kR4F%PQB84dL:{/„kҤiSCOAE*T9fd.̟?klCP LIgӮm6ܺw7‡~#3.躓\P!CMF>3C>vcPdQqdGxE9x{. e eHeXgmPyG:H,vg0Q3|C?ZK/S[u$B z>蹑$ 2 P( S"$#)Iی^q``MrH\`O/q!6Ň(Me8 VPxǐ}ғ~"@dHώs=rJ I2! 525攁j0lC JzŐk𐒍kC\9Bf# d%,jS]1g>P~ (CτFt 5hEZb+~rZBP/zP*3ejpx@`/xeMӐP*Ԡ],h˘E겡|Q*UN jS/VժF@*Pzկ~UaļzT*uQ]+6BCѡB ̴3{ K{&dQ#DElDOdžαᤆl2-q,hvfN5i=ZԆ]-gA–hIR-pG[[>hdSӤf B3sl5jV3N,RVIKlr񒷼=/zӫ}/|̥St`/}! *jʇ2Cbr̐b`eҹ~Lμ0'eFeKڐک0ڕb H !!{=z?P"|I>`8%GdFf4'd0 N0L0ԃ!R7EƛcpG!葘wGAy@ ~݁=đ<2!VTsc*ħ^:Ы_qHbQVr 3C9.$8qnd;ծ͆|IXL-4H\n gHhwLvӎӢ}6P԰nU?j=Ol?APmp[v}V涳u"s:Uug@@:% 8rXnV6򓟺ᦨ*Ojc[-*F3q[\a9DM>Pw+'}r?UY5((-1~OYy$ͩ %A-sc6}U?-p- ۨV:սugݵc٭Nݵk?HHo:/Ag !C'>(bc%^ XCzvȧ7/ {e~ۼ:_^COгyM?^#OK{}y]߳EBS6vzqݛ#<ڛ|8cް  Yi`< BMVjCqx5_- .qK^3_|K7|D$qC81o~}B p,X Y]\A gtR`s@W} x!! Ǎ= (;#.3iuFa} FAS \! "feāL@  v=21! bqHjЏW` c=ńG՗]P H!ݛHa(bhҍ"1=q]M8JfcJI:]MYIfcdJ>J^$gͤLƤMBKdefLҤJڤOQVRF%LTSjSA=_ȎJ$1wq$4%ٜ, м^^塞%IY_%`&^%ab"9b6_ f`Ff\1B} D ڠξA KBW!݂ƭEpFjf A t#A \ $UŽ"yL)Ap*D DB$(u-ɘ@!!By8HXBVHAq'U) ad6WeAAH"(B zҐ ' !H\ I'З!jH2D@R(eӀ`$N d !/ {{jGwEVzJ:@A A h65tVl9&ޝmiD{vM = Ќ~.")n fP ɜ^.j&*2* .j+Jj%B8\pf*| BI$_,&;1eWE\D9=z˴Г *ӱdT4kARkB#Vp1] ^$Wdka)j~cm#8> Ae եMU5eLkVLVVkkI,P:lSl.Ll*lVBe髽R,b*,rV,&WXiCDD|JZXͩHzDu=#A\jHBIc#/ FPMmՒf-^-z+b-+bQhBKC|!x T ImOodD.)L)jXq֢-LЋ敪68Jc_#  @/!)   Z:gn W `a)<@x' H@H$턭DFo MT>]KqK \HH2"ba#kp ?DM{:w!D2lM(;$.yȆrZ))βJJ*2L(r)2*(212) -r\/TS(Ņ%bJdSe B=Db![fM k3??1U!̏}ɠ헭F"JmOOΖBdYRK$qhAxg 蚡@}p|}Q  `L~LA4WF%u%5$/剁_/I.1.> I5 5\0ԛ%A ubYҕ1JH^J.MýoQ@gy0{ ܈3bvn(F^!j$/"`0_L#OFDb}f튣 PAwHL!i|m7www7xx@D!FtύR^EHqosz$A! 47^8_x7!<98kWc8clw8 8/Ox; q2M<#4_tEqH>&Ko""%_G0BFG #0B<;#0%wI;yaDb=y9)gJ0y)yG!h W3VkĐ #\r(aPIJeS06`51:_U^gCc7:g֦+q:g:zzl9:gNK:s:ztZ5u@p9.:-JL7Į0u7-N9O{vw;Oطj;VOFfͫ,{n:ϙƙFfFfHv) J;5V-~#;?O|I `F9זFYJ;Gl#au(>`0 id'!{ - 0 -#YHYGv?{@T ^eF:#7\-~F0|ٟ9ه}SF'g}6 a%@RB`ҎH/zTo< t y`/)$ {A3H_R(z<@e`z+z:'s, shR@pظAT.ՎF Ax!%p萚lɇɒ!@ pzGC@HXc; hP˜e:2c1>|P1;s!&"I$IXtYdLC*_ʄyRL8KTSJ&_2K5OsjәF-$dW-Kƌcӆm6uڌSh[$m fo8m&Cq"TM-nM8KAK%Y2!ArftJ)..ˇJmilm۳k;}7޹-<Ə=\m滓F,1۬i$ HU vi Fn 3^wsG70cEPcĸ4-'o4==,qTd1C3 ѽ)$GQu [C #C@r< -7 6 8d 8(7lӯ8|N6c :6b343NDO:OA36']R: TRG NSPMURJd dcXլVZm5W]kuCD ĒضNYW5K"Ƞxa1Γ®cI/M;>iHZE!6P`4߁/5 _4"g ˿k8A]~{> yD)?cT@3G|8@bbaڐ1 i0P/N=d{A(3> jPBvSp dp9ATxf!`a 1zE4`(qM]`E)jE-nYE-Ava $C;x8Ǻ%-M Dqp}s7T 4 HE.^@ԣF-l\ƲKkd'G 4)'17տI"hSAOc%q_NMKz|C jKD'vCǮ6آK63gl"r)0R=йkUZ\/Fl4xx}F]t<ǡ 9bJ;,H$-ѥs?w#qՕqAفܑ#׸v-sq0LljPn,ڦD΂-%(DOMݖsԷ6!k q}"tK[gxmoma @6<7xlY/ųd&Kxd+Fl"oR/旌Ԟu6ci1q|PuBK2~Y{d~"Ρ^&&qp'=x9<ɮJ Ǥy{?=m[R%qXs[+3+q&sݞx%ب3P +oSS]fS8rsaZvů~1숗=5sab/smS\ur RXjDf)f5عe1u苹vfLm#zLtb eHbvK| ۮnN PP0/:;,F/֘F̞\NN7<$c->j-ѲsM402 2t#@+%N e bj#3.lʧ - >LL`s;  k/Ý MSMJ a'z L* jJ́DJ Ne=o( 邂ɞp: Ci)ODFp >] AlY,F+bQl1|fő/|+ky&+/:) ppQo1q-  RqoHMo1!!Qq 2"'" R"2#R"!&<cѲfRV$ᮣI`shlP'{rP'('L(R)r)(R)dP2**r)R+R*+(M2,)r)_G-0Ҷ1n<J֢.Ov X&2c'XjB1 '+31"1+&(s5Z&s33S29S4130/3+05G&D5 s( s0"&"s0S3,BS0q)(10p1"+$&1;)O@kV$J$%'$S%s%3<<;ۑ<=%ד=$ų;3;;==s;S%3$1tf+aqűNQA)~,q:I0LND@ 78?c.1DCEDF4EQNLXhDEOF?pE?>p Vd?RRr*ʍ8~&-'1),N0sV+h0+þD]7\4 :ODtLLD8LtMTD7 5POPt PuP`@PQ` RQsOk>͒` BΤ9ZK1 NOaHq8"kF?PWLiOa5N{UXIbvhwxf$ &dZgԞY}w u&) 6 ꫰*N+ VtFkX}NOߕV7ִ5_tN8~@RnVFZ#h eThc+W_L^^GVdcueQetVOv^dd<#> ` , iU bd h >|5ZI`/-;d_5fedlvNalV^mU6r?a !Voff H >pIT @ Aoa . `o >zT >R\H\H̀;uDK"vf_Ŷ^ulG۴Xٶeom.DxCwU5%|` ` 4@ D< | h ~ T 4@ x`v,fllʦuWSn ^avmuN_nԂ5v7vl rP    ` ҷF@ c0P jcCKаMWVmA6wyUXMve;x6XChxh Wx inplUGXN[4gvV%xexlVM` ` $y )93 ɢ "YIY`Oy $,f1-t-BfyLż:15dmu#5}eYX{ J9 <ٚ 4I$Jٚ'AQ# .908jIP.2唑H-y>9Y> 1GZ1-I"9:]ZZB:ZBz]*0eA:[[>,0)ʮ2szlpzM~z8mZ:zک:zک::OZk v :Zٺ:z麮C gzZ:[ !,@...888KKKRRR^^^]`cddefilkklcltjnrorujsztttsvzvy}|||lvnys~z}v}y}ţɧΪŪ˫ҳIJʻ¬֮ٵͽĻ͵ҳٴ޺ҽսڶ#HL G Jp†#J(bE ftXF7^l#Ɏ F|rą%]6,3&D2 eΟ9GdʁbXH!1E!rԫTNUԬYv +V,XavݪV׷lR%nYpݾo̷pݽtV<8UbJ4*"2D*_|seȄ}YeӤS^ͺuͮc|e1S۾=˻wue‹v̒ܣ靉,ν!40U 6JD Okt29vS;۴vR6󐾫jW8BvTLZI%(a ͮu^׻ujWv53\io*6p63p<o]TC\5-H?V(E0‡"6 sIKZ>a3"ÌP! 1L>X'H8AeA> zFXMa%)+lC\SBPwt[^_L׆|W F"v(U!̩]d/ybg2Un.9A `#! B0BS a!X,tkԤf5VC R+2.!9׻uoq@QDx =( :p#aW~w`+@cF5 Y蓭wH݆^2uM;Э5ILRnx8pA#, \toS2g|U;'FjԔϰ$fNAG5ϹԐs2xDb N;@7:t`-;a-HF`7Av0hLuZNk5m;v5]mR6m;_w{gC~w'/yá oyʻ jCAC,"G!Tz/7E\9fABLYʅ:̔3CKԥ~Ǝtj(s=$EYV'Zd _=/.{#'ԕntR}`ec6a~3fhb9oeb|`ROTNWn5V ($V##ub]:%'opo&b@zWl00l tppy0h~l0q 5@QVTQpe0 $Ap$R~ q0IhRe j T(z|؇~z8{[x>(`AnFaE536ZXUZ@xhH[PU^-!`X(3G !X >[EkwD@lB%bh-!o S3l&!=8l v$%bXهx8L`G[DB1Qqd'@4(fE(Y>I8'*.(y0')0(ɒ)8Z^VVph@'S@ $_; D{cQFd1G x@pbqp)cR!9qXoNqdb&Ssp d rBd@ 9Y8$`p2p2`  F0QiJgR3pYzٛɛɛfWbTY@P,[B5b 5p@_SC5pp{6o"=[q1oK_d o@DeebIhSLnpE} хGyhs 79nzfS@V0i`v.)j]NP-QPP@h3s??>f?ꦁ~5`6Y5a#_er[n\¥l_ʥoe\{qPjpef0nxn{J2n_JjjmZL^`w0,uR8S,S,(Yȡ :q3e^6>gs=`Ie5U^$<_ӫs7BvTXRLĕ\$'IPYJKYNYL ZjZ:a?3EGBWpE6%`nSX`:pCcneQњX M:0+&+6;۰KZbZ YCZ({)*۲0˲ Q#8$+%;9+fX-Y@bE-C{L۴YJ):q``p$PzDJf[ Ѱ%wXLh`zJzxy|۷~ |[fɉ0D34j$A#ilNc{`!1`-*2 #!NDP\zPd~ÉĕjțʻKW^x|V9HR7{258e⛩{s0t-0%Z6;|juU QڑHFfͻ LqPW 0G0npc0z0u|pmPtPpluaV0:Ù1lcE}6j"qU@9 SYx&J9Ø@J9T \^ %i WBqcA`V'@zPw{a^_l`} ȰhȈNjȸhf]Rs``RSc9X;wP1(g3_eT_ʮ|hə{Pp7V0!10it5,4<6@L5`޼NP|`\-j0 YffP< Sk( 9~HЌ~0  } m(яFA} '!e^·Sy*{ip?mi:]0}^P,\95_P=P=R=V]OS+W<wr|jxxn l.k]s-oqs}~}-tMn=؀={ y n`x|sͥ!qV]`ڢU}ڧmڍl_0ڡYZFkST"d5~ mMп]m~] -m] =ǽ=ͽ -<6J0)I(jX5۱KU~]گ>O=۸jgD"~b/D !/| Xk x ).n`-E..0vzKRa@0+,54G>H04IIL FLR}bl|ll n.psw^qzz>v[cn&,?sl&|?*PX>@4 Ppi{vqogߩ#53H:$=Ű5XaG: X8+H@_?@@  b{`nL'%:VA#y U_ufG'|ge o-v荫qF޶;@;*&`2-sx6R=mUT`Eo-Y-uzpi76Sc;eA!@J!`G0ψ;(5p8q@#`q#@>0 {{pJD{9{; Ȩ}~ձ=UZəs^)_xBꑗt9`=(aB <?r?:POC ^@-1C\gO{Ź5~lm_PM]]C(Y\I;292@jǃ!!,jРq(RK&})ҧTh2g9+WbɎltlٵ` BG^zx_L0Â3n佁r%L0=f/C'7GشgƝ;>jN3MY'[.PƝGhrŞv#2wk:ZdϜ;v^Żw[]W^ڇ{\> <0:k3 ÌŒ BB.*PB PCPP"H Q#aHflWđFwdFH Đ*Đ"CI9cR㤌\N-K)";r{,4 "J I$dN:%;lN;sO=;(rAP# 5D2 A/뮳K *BԹr6d92|UYLVC98pba$1bha 18B+1"# (B+@c Bj>(d8<ؠ|!(ޠ rؠlC<(" {n1:#J6UI&CpcĩVo3KUzS>Ï? pHypXn8I7cۣ F* 90$]cx n5PؠmK0^}="<(zЗoU' ,'.K~Yd!7;Q}R8@r! ^/4<`zV?䁀\ 2+p! VP]`w QWxDpa!pB$/C3jp&Rb>*p3!'@#&0)cLȒ&mDHFm$ˑ41M)R 7ܧAЩXHǥUZ w>IVLD! (OЈr1f-cYEE LTS82~V.K+lBXA ie.lf49M̴3&AUTM"bEY2K'"uR)H'l7UB8@t ^w@ Hp HCkm53FңG >bG.Nu}rSHTL[H)16Kw;ԭF;դӃ XauP.0 &I@Ύ4ld^{{q(d1 '0y[󕜄/#XďIԨ^yXy=}8IeNs'stк׷u<#~E"BtYD]bJ%GP %9 ל,y>b'W02M@|摐D|p!P_Bod)}W敖B ^bW # ^8sM{Ě||=ի)ň;uM ;uHwW?/ Ve v^}.Q⚀ " xy)yуc#:%멓)K9A #!h`9*t/rAp ;0BxcAyb11@1 dGh(@P"9J)R& Xrv97h?@DB1;@ Ӻ@lB+Ȃ;C=Ksv#8@4#=@!K+80==MLEs!*{t:d:C E#**2!x8>0AЃE'ibt $2*Gq= {]7S$7]tGt 9=1(CC@E@DF/+? }c$0CMTEM$pTCE$`CJKk;9ͩ*1L^^%E^bM^^}^ ^T^ETAHU>؀5(!@!X(`DHEPȍȭ]C(5cBJaL- R[HO=Q ]``$8q?xK h=8X,?L/*B4+A"Awq8hñ!áB m<5 1&}<N (;h;&+xM5F(d61 1!h6h ѭAU{6H%*,[G1x2F#>Q8ȁHH=#)g"x""p(I G//""%"(I')옟zqC28s- sz)+80y 1 wWǖ/n>Fxp KY>8;$ S"V[&{c9z!(NEz)2PY]z" |'Q:O%.%F@[2o,7y U~P2"hO۫w~zqI$l,"F "(y(LI)#͔#TS񈚇B9eeZ iHFo<"" 6haSTMJaӔ ЧKNES&!Cp 4L2pJ)(DI(Fjf/F~UCP#Y8qM@oD#Gp( 2!e-eӅ ]~݈pJ*)cCa#LG!ڌ;l4n6#@9dm&Nˏe#1;J6eujs##jEXVpae:S : PSI(P.FlB!d4") 6v_.Ƙn6#kmBx$ndE1F$K&;GWe]HWbYf`eydi洓!B4U UPh:(uhU:(b >jij )֩!zfZ*+ Be:Pmh*y*N_VY),U,kFªl.۬Zf[vK-fz-ԶarnhGn !ի%(J* bfFjY)J[8=R! GR!"*r%<.s.ür= @kt2:OJxT@ ʋچ| #Q@]WyFC]tuuolpD]FVj qgT]ouhMkH3k9{9衋zӉ$>K5JTY?urjAB4A  (Af{Aӣ =` B lxDlA %@Ao\_k Eb1S!DBw< @5&9A]>rgQ_Zݳ!p {`D(J`z8BuXH=$mڻ`6p^< pr>~qEz)"9xPr^"V}DBR,8-|  4 I).RpIqrG+f9 jS6D1!w r]X]2kXUl*Y5Vj‚+婘[J^Fcz fT0f"VMJbڔl#^U$Klv풕i]Yr1XZ֖YiFӶuMu~Jay(A!֍_ Q؇9x܄08y!r9uqFF&t1+0.PZ>0(;DOhU 갷sq>ch[<@@az^x`B (D>~x lEWhCR#FoO#@ E8s^\`SP*R?fF@<xzl91 Do5́xѰʃ׃~ 5m3 HB-kɛ /^c+kQ`M;XW(o@x d%Fy44Ag.td9<۰UCUJR.zIE5e`VvR:nz)Ti_(~:*![ZBiTNqg3uWd5[XJ"XUeT_,5ZIV[/ k=L_U/ZX28e^Jq{X V65ŗ,Ư1&&7Ph&-/7rpjEF8g%![ڒߴ-؝}~c%lٿ\AkRJPd#x hP! w{(yEjtZtq pؗ]h=kX! } dLAZ4sA#A CBQ㘚&oў_2u%UsN8XN\ aX@8O#[Q4$DPKCB̄!HtlePI@vf*Jjj򪭺jBM@ RnLETґ|hkfkgd{^z]m ~|`{LVVhVVzR(Iܥ{krkdkfkkRʫE6hw R4&HHYHFyFYEe ]gJҫ^ָS Ư+YL|9,z&ޅB_ڙΎl'gȋ @:xx  nƔٞ-ڦڮ-۶m-l~Hݚݺ----->PgEG`l4jM| \O|4\O,``ޅe.n>.ʮ떓]n nڮeoﶮ"o.oF>ooޮnnn2oZ򪮹ٝ ԩ2wFqxfyax|MuAy1^\OTGy(8mS,>f ʢkõ ^[pg7Lp0ps ;p 0FrK6adфA]-ʈHy0h⁝/17?1gr(0QQ.fUy/,IáW:o HRW|1{pq11 DZ+lKR cެ^b lF&&''hp򏐲d2()**+2,2+2--2.r,.r/r.+ 'AbN0.`2% H9핃qp ,ĨAi :3:a.;;3<s>>3? ?;<t: hx-RK{4/3!dAZF~eSqnZlJ) IִMߴ$4?3OtPȅLQt6/#xM$@BT@G@PVQ [O@AX/ FhN5\Z΂4Xf}R\QQ6A y@lOc#"A)F#5j6-V,nRMQP4eX hQAlA. `TAb  DEj7xP!*SuEB-sIچ³̆$q]jTeE38 /8x389A_xwt LHf객B%c87o }J> ʸӸ[88ZJ) Bxkk 9+y˸ S?#W9Oy㸔F9{ybfOO]K |GLv%_rJc2Ġ1S8:9(っKCz2KF_:g:vz {:SO:zcz.WFT؏Z+8K9W9;[{ck{W{>{s;kw{{;û{{;;oJVG_HJaPׯ`HND%V8,={TExsN$4pDO dHrP]M8Iq A$|D͔Iuc#":⊭v#8"-OX$ L (~o=ׇS3 F$6)zsT3F[tta Ys#f Q !@86}L?7MI-SRIspIwiԨPP^AxAll7O#ճAB"'ZX!OmG@+8>/w/_9T’E6RБ e 7HEN)N7 Y8+8c8+x?cx38@4`AT᠄jgP7 6AAlĠ(LH"GAǐ!8ISgM?:hA| )R 4)TKNEtҭQ5+ٰdR:5U]~kmZ\݊._vI"F"c8RJ6ؐfᗗ;.&HpQϟAƙ!GjϜO6g읣kNӴP֍h״:ܻ%;u>n[7韺;iK#!!]rȦz4-٠F@p`~TxBp(AhB!@ 090@1pCA?1,7,CT1F_4pF CFos0 =PO8(SBk-47ւr5 N6$3L,*7Ü2D.PrcOkJ6hю54Οlí22,<G>j 7@pS-=ܓW_ ֳJ@},>1J!Q hrӠjMpG6UۙL_s7Ϙ 4Pm:kqq\:Unsd0*tC $RD5yћ^u{_Η}Aġa{X3B0^ ~OC@u0lK聼Ab! VJ",^$ IBVb,^0Ya+BňPc]$Bv P8a{}qe-o#>1"  !B6Hdf"lBp >%#|-lq R _~r!iIOqiMo]Np BiNjRM'_f e`Å5*9j386^A umiK yB| .@>A0mqG ೟C`{Ļ᝞ lro}CZp7 s f\[?Hs8*1o=q-l +߂.| 5ksZuXժrf.ӡuEu#DZձ^dFu%n` ʕ+Ld˨#PNӔC.u='NT @IYp,1 ї^61/iC}A%Rx:X$؈Vkx h^/I,w&(Q2!S9%P+$ &>$뭄~}c^| Bʠ1k  k9! $x6 Jy8݁-+(`֊o #%J J|- pIpPLi9J0b^lM?e e>@% -Kmv)ZtihƮFViUn&bm ! Qf-L JD Plm0Op@ kРlpY Nj0n@ !10햯|c>l$J *q߆p  VDO&.%P &N_/ċƐ¯W D OXcތbHCÚ-(o0"$`0(&` c d"%N e 3dBU.<RO_e^1XШgnm2C!r%mo(O qS@E KLQl>K1%%Rˤ6)*/|&M.hI%h2⮫k1),KD;.i5&0 qѦlͲ/K*F +r0030 31/#EBMJJQ?B)r3G!)A-Qz84C-+% b 2Υ196?`5) lnYJ&FB1\f H2X#dT,p:M>8IL>Ho4 |(,C:Cİ=k&N4ү&A@rlR _42ČH? @>!\1']C?O0$CS"}  ҬJ`P>q ?b Dq"tFի)!6-5D'LH)^XDO@FUhICpe''<(3` GL/iF=stNNah5j=ICb Ƞ @DtJ6q$!5R%"gK2{fY8Q:Qi ("rUGi%Bڮ̧TMuFn7)Kj` 1E>Y TaT֬J2^˦g63'6s F[R]vl&jlˑZ,gSo & 5$ ` v ig[h_04KS45n_Py–$kls f `E߶jnVoo_pr@ďϲ'+1c~RPw3O kƯjgrEEXqmtuvDIOtR+oM \pCJؖw9S q7Mi3P% Wm1_yMwI 4&"%z (Llm Z |N *,\ P/ D/w)<:o(tOR0$#nI 8>EM˲ޤL.Ϭ$ ~>43%纒&xMz|[ $e,Y7'FYtyoKP8;VA%|p/9Ζ^҉wX4W?A'=6⸫ ޔtd)5kD"ǐ,UJt_r/x%uxR1mH+*dB7iC"!,/a-|q?=؞ZT3X[S8X75L3rV4o2mxWe1L8$ג7TGU rlzlrTY⹝九yjYL99:y 9%!)>#7< A3؈E53 UڣRZzaz UZFf:Wڥ]w{Zsu=JzZ JER:yUuڧ}ZڨszmZUʇ)wii7J>+4XIUVZD%M|wVH;*[f5zVHU=ϱz UA;ۯ?ɴ}H(洵WuY?ʳ2U^|r'4q[oÎ@ANsrGvV Øy4{V{nq48L[{wKx1[LTiiɜ雨IgJ!|Ú3۩3|/` p :=>6,e>Ѐz`8ݮ< Vx2sfV~R{eeׇb`A!! : .`L >8L^@ !~wN8@L! z!X'![?}S> o !  :`t L Z^`(`4  7 n B@H2r`k&E:=(`(݅Ya֗]-YS`@? @U m  ҀΙ<~4x!6 &bD5j$ZdSƍXDȐȑ$KldR$ʔVt$L4Mœٲ&Μ5c tϔ7ԅΝKq4=SJ#E#6gzetiX. "ڋmHt{D5h1פAmIeѿ}90͙B $dE(PLR(/CY͟<լ[~Z8 L葍Gq]b ^7$x~NЇ6W<={8qi=oă^7pƋwfs??{"uܹVm)F[B qq! *$##5H?H1b=($-%QF鈐W.%%^ &bR#jf"ѐGb(vVxgZyzXa F$(oh*J):(n .).餡F:z*hh il$jn` JF< 9DKm^mfAn nKߖnJ[m!,@...888KKKRRR^^^]`ccccfillmmcltjnrgpyoruks{tttsvyvz}{||mwnyr}s~z~v}~z|¥ţɦͪŪɫҳIJʼ¬կٶ̽ļ͵ӳٷ׷ݺҽԻڵ%h萣3$XpÅ#6|D:rdhcG+FiQEEbaǒMF>$R%͖4򦡏E;\8L9BňPCdzׯ_+v"Z5lYm5;WnXuKݼt;x^y#&,1Ŏ 忐z K"dΈ>C$ңINZtԫ[-vhڵgͻoަ&s6nݬo}|Σ&;tiő'c3#jOѝ: Gϟu!ŕnChqd7Z' pB8@@`Q,RVqvgq jqFe!ugDcDi^'@@`H q`x!G FE\ƩXd,d蠃zy^*)rǡc}hu裒Vj`>00AZ!@D" btQ׸7,w_;QKZr%U,F$%ds$<2^>ؒ0@ 8HP Q0 f |pZ:xc%&Gnz3xZܤ(i7Ο$f(GXQAr }Cp'NН8NuUºη-,pMm*6KTK9fYF$BMDt] u]N 5-u 1y p;qL bx3r5xq&߃VN!_DN{:5Nq8-[>U)&'8I"j&EHwH\H,x ]pBF0(QeX/T1?%I5*f<#+@e :#S(Xx+`e J 욚d@yER145NWedG0Dzy@ | F(m@ `(X@ HE" 9Tͼ;ةބ(a}[5[teIMZ.f8v; %pP+Cp-k ?)!C $1sЎ觧C`{&Ǵ& xCrtC]`!ҵր3j ̖ؤ%?Aԥ%:I]Z9:JҰa{EjZv SAWsCaB8zD?NAbhND@zWbgxAOd:+mGP#8.h ZCz҇}O?z֋ da 8BN{ƒP>a=' q~x?8!t@Qf~ʍp-HB~? 9X?ǿ?A~˿AgG)ws'`Dr'Y}gG zw:=9ŷ'|E[ &NW\_^Fiy*[G3::p]Ħ]?x]>=?ȃ?>liW^]/Z4G<}e\`eeYhe[`(_XZvembq+v<4(X7B4&=}f>4Pq7XEy:.Fey爍wXi`:4C3 rd3hcSi4Kf$m^0r~EuWT0(=J3: 7`BWp:d<@(`pShhS@4G{P:D'g{'g}RDppPn0NVpP劇P`揢陧u>qU7u)Ow'R/`qe#' : 9sq:`Á9pP" @CYe^PmcR9He`ΦIT'O`vd!*uu0]^wR*tsi%8"nq(GРu'r 1s)d`:tB  0mypGOXGc`8:8<<8(C65WY7}^P/+1`:;ЏU 8-9`ilj8hjrh5 x7sv5XI7DJVpTM^trm Wn;(6dsj sgs:imf[DMT 7*DPlqFHp$Zlګ!Ac1@Ԭ@t2J/S0ؚ0Z0 Κ:c@ʬJzJ cqSl5 5O4L[{ATSp C Qa [ aʱ9a q,;-{:K:V$88j P8`d8cC88C7kcp֔ɞآr[Nae*43764S *`F`l0Wr{gPe m o0F@84D :p!#ѠJKUp7g_S<7f#*7sJf#׺D6jq5Zi6f˩f>PW0)`P(f% (k0kC;Ķ/*:$>G顥+{/;/;ۿۿ l̿ / l˳mٖV(62  k>&%APK|3LKV aG9|C[mxAwJN_DMŻAld]wrr!R\ ٟ:SJ \2˖JaJekbp|_bȌa_bX sx_*n}>t #aW el59LPcPӉ]\\`؊:``AI{m Ӹ9v|=@|q$pv99p)++,[*͵ץ]#2=9p3]IPHl4pLX5HLPL5@>`mhozlr>uGp{|DP>#׿G_χێ9{'g"ۍ'XGy0|HpEN5pp -427V[>xrV  2Ғϳ q l1GPuGn%%*uW8$O:,b84@-DNpާ N-ىd5FP;שtCJ ;6vS7Ɏ'~LF.`BpaXLLpVb`ޮU`UUmZ6QlTU/xϒq7.$؎c5 Ӄ؊>= _;y1b~Ow7(м), 3oyh`KE`6SJxHfFJ~GYgwZVOlZOYZ|Zpc~Q/xj(#¡E1@r_ 撂59}Ct_mN=W8\QHN8@O|d_y`OOx2ٍJmsxE?-ޗB`I|* ֻd&؜4J) :{o}MdtBqvX:Pu8M#z?cS3=I@I lc萜C|C=@PN耄Ct㉋!AJD@D&E zXɒd9D2 G iځ 'tsQC[rXe͞=+ZGj׾ Gt)zHHI +$"&ܷ/I#VXRCce˖,f !ɜj2q=:G8cȑnl;2z2ɸ!"vkGYsܑ sGw~zn7;Y{,Gy6TAIltqC6ry 66` 9( 9Z=BGq:-H EAqGđSG~2H!|D@KFQDi0 \  Hd<yI7h 1ꤓIJ:N %,Ar/@}@*M <(aP0 @L >Ƞ H_ċ8s<=iEX; f‹4搶9, j#cC +3@8j-{Įn}^Fz4^`@`Z=$-%Xc88d񸣋YC 9$f9M3 9Cb gP!=CfH"zC6m_. Q:NxmDN~,nheC@(ATi,@9":!j'"0č&zp䈌Ȩ)@H #^' ÁԙJh';y% ׵琫"r!}gկ}mx~@}'N~( !BR2@]aAu7QIF"p3 z;As#B  ؄ RTl{727p-<,v;шGDbHD$6sPd \Ђg`3ei`sԈ8qiZs#P;Ӎlc}e/Slh$4!! a;l)Bp0|: i#IL/MA"!IHh>'2NR>䤄(A{[܅EP-%/hG9/eK52.Df2ђGD=M `,1| d7N Ϡl՝ ;xZcp.씤29TI $%)%Q@!(B(HAPF T #6^H_ ObCyȌ'x7&$&eD#R6(D( @#,F MhӓڴU m8e%;1u_ ,-"aZTdG nłIv*"B*7j׈38ـ>F!x4A"ܠb#PH43G I1rB;?Qk:F1a1}|1уsY<G6A KȆ(t˓s(Y۞ظ!.!A#?+;TI=۳)4a*_IwA!."&x%x.,'%X+XJ%'J'ʩLʢ'țGPw:*Iv2 "#p97@a4:5cd74LL7=*~ѪwK7IʼLzasKyhp&$8K٤͹|7ۜKMڔM<= 'T,К<62= c=-#pFy3Z=0@,ᛎA"-h Cj7v!>0ߜMͻ,TP,LT07D`7h @1 x92@ P@ 4 4PRү' Y4PкlP7?݄MMTbBCס1dS- &;!Ι@1/t0ю(ў s!։A 0D ucܞ#20MRRۄ7ܴ/K2'[ lGE!pX4RCјGbET;N!A jc$4k ڰ o\4}qVGR3 $=MyT\; <̿LdPܼ:,Lټ|P98xó`⢥*7aJ9~&ȈSs \VPUȼz{-Q͏V Yiz!˜KˬٍL[Xv!K\'ϼYI݂]-Z=x졪 YM&M;Ȯ #۱+] Mێ#۸[ۺۻۼۺ-ۿB[5\]uVUYTʅɭȓ\ܜ\5] U]M]A؃]ӝ%}ӳ]͙u ݥ]===^M^]1^m-) [W]P ɭRd^{fta#sFR# 2P ꀹ'YKܸ90̕-L҆ 3̙u Jva%6v "E FP|E*\H+e*ēNǀF&Bh+W`M$.];in>&Gꎜfܢ_!aXy B A6(}(Lqti&!^k0%k UYKf%G3x; s(H,Ld Ϻy#6x؎,UĒvR(!mYpa ۔쐾`3Bڑ}F*xgѓV `X6ҝϰw9Z)mHLjm>^j蛦55x5 QQ 00L HۉhP 1C `)᱌HfnHڎ~ tͰ=kW^jdž՘>lܴWČ)9@Gx OQĥE0,ƒ ϑ )<НeAhQ#O|Tra¾ޖoWolaB@fVOëI[OaKABe= !Oiw>lWq(VҳURoVY4rlbwZYo$s а׼4LlO޼gz5qhdbX7M:+5,YMU:o\>(pɼ[!hIIw;kZ u8x&@;^C():Yȶ8 =;mdC AX>BUҒEٍ͏`5<8{n@t6"3 {!8$+EURm d9(K!teq#'bw޶K5>PHp Rp0pQ 'NvB E ʷ#'gYg|wYϕq vEUheWHl}l vق%GG8Q 2@/ /?qO@ dpBQD1rWjvywx"˵:2B[mr ,47 ã۝yA $hРAz sp ā u:t( -r#Ȑ"-:i$ʔ*WXeGeH3q@"B 7nZȑJ.#͛R }#ԍ|y襣^~%)eٰ=t-ۚrE]wnȺ#Q͛x=:h!!?RzȒոdU*㫗cs+4^Ө^)xݰ!)oƉ7p|ǹ}yꛬ&4DCh~6tXH W2W&ݼk!R(ЪRR(茛{?TUr PD}fp :!gQr&^+jWK#T-RaնEVeX e(%V G$0†#t@ *=!D=pFDXi%GX$ dDAqtGd`hEWgW#}5[{?X#dGe\H TApvp§J*@ "QAE)ڮvꧮT.O1fWAFPgSA> Z}lQGsAnZ%$By :Cj ڮ gtG%'Dpi+]i& QD UTPE=m   UVE mX`!8PB/$Hb pCq#4_,F4+<ªŦx+[Sl1!gTWed ՆE QRUI\qX&w[24GGMHP6?hhS֋%HI٢Wm(HdFUgѶG-xghG.5HNXL1n[lB%@anU57hrrnA>5]x.mUtSOz!zl)DE&;UmA]*"@A"L2@#!njTف2eGaʏwgYa<σnY z>t+])L3{7cнF%dupa T5É ȸ/?;B 6#e&NpG*fPLZ2q/ J/ !?HFno~GHFy^'{7/w~7_G~_߾ hC ik϶{EA):>5 f8= Lε?_m:BtVT%D8DDN8ET#&M'kb_i&yyLY[itM!h `A P=v#F WYQYr !0Bb}[TBZxUYAK!1aY(Y!pDnaDat혛q aXEF II 8tSt9E"V)(O*:*"),A*-tb+~(,")".ڢgŢ*b-",+342"4"("661b5~ccc6:.z+~b+E<)#J#KJd$H֤Ld!TdNJMMdA)>$A!ā Z\VrzjWv@fcmp(ft*m (+kkK  bGvAziV2LMyl =%4f*AƌNƁ2ž,֦щHlLDŽ@ 8ʞ5i JƬ>-`B J œSE899dc,[BBnB۾m]fZl\-YVJTϦE i2 .&o­­_ Ї~E{Ϡ\TTPDf B..: hU ߎWg9\]}TKfn6ne@Wn٭VɁq"JVd aqD/̆ie ^//BRv@PAo 쁽/C>6ݘY݅H6gcҢdy+W,kw0 |T.D//TRZO z0*=VD@dpTPV\4Do,Bgq@I% $E@ z_DFQeFAv10feȢ 1oŃ܎np/e$Z9͙j wrwED BpO0b&BHܓ%zfWWL&{2/+h~,Xi1# 31sLʮ.&c2P&27ogfs399s ;*f99qmw3>W8~h@kt4B ƜAd Ŏi#J Ip>wkoǎY)Z:w HE -O/.c'{4NV` ZT}똪 XxUo3PQ%jNO5`2R1u>.Qn쎍NYT+3U5^JUw/"ЎBuXߎNEYyL Wa4EŒt-8S>W4-eK*Q. e]^C,1ufOۀpue 8ɁODR\70 DҧGcnXtϼFk BDctVj:/@q 7j:$gI!F8bE1fԸcGA8B'QTdGq@"BF7q9FA8kƑ#0N7k,!9}:jUWZS#_z$˜3u #GȜv88o"%F f~ֳeOXi(6 b7錣r‰TOX; 10=O%U6A y;(*Hs 2:B+4#Jѿb o o"㼹8 !ր SLp3*K2l4m?z_~+ ?:3 @ O~@pZC%BAaKa AȰO ,6/!O.O I9_(xWhd-pM|XH qXÁH"%Q!bD(2ыE*M/^^x=F$Tl"8o[Cе<o]ز45: ShAܰ9;uCBWoVWd)e,eK  yȃ_%`Le. yid.DH7 {“5'9[ҕD;C=qzs\>#FTo#Sg>za|LK % nT_2K#r '- Z'uiRXLq(!"P#D$+D#!A5@9ɩe.EcZsr\tWS+U~Fbbxp6Ȫp* *$P 0 xR`al ($(z7@ :YUå伊_ )24a5~g˓ԔmkO25(BP"2P0)| %Pu"0HAmQ)v>Wl(@0l 6 |իhbjڲ61=IOJ4 0p > (<̀. `> È0p;XB |(4a;0_s!:0FEȳALwrU.A &egJOЦu,|&BxU9xC0-! wf=|2@<9`|5iC?xA!UTZDނј-Z<{oXi\ xfQ,5IRo!iPjX˺uBY *S{Rh3gV2]2΢ d ]-*C< Pml`6kW[YkkR6-h!mo)EgR\E|Vx!,@>iluj?#B#7h\ԸBa8~q(OLPDe(iF3{4=O)| t+Kӯ?pDӓnCS:ӻ* ҉VO}f*ԟxuϽr:mv?ywuG$R7 xHC^rWQc&|al(A:fHtᤞw=ׯ-{ozr%:Oշ}o7; !,@...888EFFKKKRRRTZ_^^^_beddecfifilkklenwjnrgpxnrukt}tttsvzvy}|||lvnyq{sz}u}}z|åţɥ̪ƩʫҳIJʻ­֮ٶͽûεҳٴ޺ѽԾ۷%H0 G*|‡#JHq#3jŎ C'QB2d%AnDgO<}9tIMB*MӡLFJU)Ԣ>&UYV%tϩHzZZdՙRP͌pLi,p`4 6pĎL4f3͔Aw$fDzkɬ_n-v`~ٻDHmXwȓ+_Μ3|_#d.=Mzws&.,X@ 0D`  ́߃Fhqf,1ya!p${pAolHh-0h,  0<&[o}pt\Xd%.Q"%_Shex<^ AH| =0hs yއ prĜt|&VPAgOeYj(ꨢ*z蠉Vh.ԡRa*%Ri颔fej]飬>zbD SHZ ;E ZhDF+EʁHvK!z$!\fآ++k&>bDIlp#|" fLri1LIIB0q.}kAJ42dB3\KsEmHCG4?|T;2zJ2$`-ד_{ ivo" Խ*DH w*@p--D -P`S- *9},R騧4[ڴ}K@v#gڼoD<! ,.ߖ  }|;B#t}*]~ rfjWش-+ X 'sP׎0A!lЂ+`r #@ 6:H07tK0.K?`xB!8!3cz\d !2Euq`vŊ[ZZ6"mxDp"P 6!l 867T @F ktЬF %{%2ia GؑO *9 '!╁`7 <^"衝|;)O>aOxz"URSh7Jnu$BKUswhF`;AvP:AhHARvTKȔkdҼHʄh ԉb9r XTJUNQ*Vd0caCC S̾2JTQsµ$lPZ׹RkW "< Q(@g1 "]lo)NKk҇86-~$_:էE-_JM$Tc"F4" qqK]F KCA XAF$n 0(qnc$lwԍ([INvSe` .[6a8 І0B6.N-HKWom!zbfZ-}[TѮl`CCLC4x0r%<Z a2.2]&x8e0綔n68@ b {TpP` 6؀` k qxm݌qPoJz}(y56BaHR#H &C7p(@ @ HM7F:s5JfM1nٻ'C]f by xp 2 @G ^<@+ An`OZBN!1paHi/|~/=q/3[..zOSEPy09P:s烅N0e],9!2!81gF+f;TX(J|#=Gu0 rD$Aq)0= NsZC$yHW/G;+q ^%/d|+ycY,0oG~27 @sX_d38%Koo]ml21hz/M|3?˷~3U80 ЂuFG|i g¥ ?.7xsUQV5\ ؀ xx (]xlE\8e2%JrS$8pD.7iPg|GTZׂvExx5TW6;dӃk @7GPxu]֦{,8XNwTPJb6d6"`@6tPd`76`dD[aP\jЇd%2q[T(FBI6WT/0 F[0ffU 7fg7p hfqB7F'08]PEG*Ȉ8÷l3c 4jŖ ~`"`!`G?"0j((XlFt7fsHC2ars0aa koe&c&[(hIt8M Jv |$ 62P+p7/`7 (0yp(7H@6D~Q@ԏ}pdMW֖_ył3x3 F0ONo0Rzj#+1q3Gt@z19~3 C?Bi2a@10hp`D PЋQ'xGŨl.XtQ (\Sju_Q[QuO v4d#gi]#*@15NAi0b~ 7@p{b x8xgDθFb癞_)牞b0ٞɞ]EsZPV&sHbV!V.GxIp`ppLyXW苄)mj_F=$ZW(:%#L:|0]pTswCBWZPXWjM7HiqGMeFZ3iFN0Xj(UF@lVZl[jH6Ɉ H2sIvxa\]mo@3s4:=3dj5IlH{:s-p7A7c%.7i#[7kC7C=/$2,I%S+ 3{1싾{2۾e۾37S髷11s1%Q2gO.Gawz@m|PoPQb@Riq&=d=EE\8>>CH`_0bS7;9f9sp8AR.4./?Rq!Uȥa2ab!"1f " A?hE4;+ĸh[NrbA+5-{S-/=P,\dP ¼|ż]Vi6q.ЎnpIpD7c>mzUa{ܥF `$fK`[pVH K h6IWg;x4-MpKpˣgG'x!!IZIpWؤMMNN@҅\,0!Gho !0U GDHl Jp5h>~=uH`q nt8KUԤyWѳ}{W[ ',"f("$n,@+ кkay1Rlap̣ZD!1m|I-/Epg m $0 l3w 2ow.gO$s&xnЇr@;[Yi9xhu#7RePjekve~&cd&ԧ=mWZ_F˿\cPv@̈n臮<N(Nщ߄g[۩Ϸ99:.뫞n^깎7a@8EKI;sHQ+[JN5 c0侞Y0꾞)zx8 jD,Cn?&/EcA$s)sy݂m"A>Ld0>Wن7<< cD}%i8K{9c%%G$?wB18ZBQ>^819H8d5[i89ӷ9tpyOb <Ԥ槮'?_ocRp2 l@9 :HmCc9Dϳ>cZC>c>9qċ9CY0n}]N6APfhG KZ,Y"*Ic&">|8I[C#aeDB>$CA̤-$q>ҌDEӗ[Ќ4Vlدc5K6ڵhپ= Wt}DУ9#1…sh`.tPA&F$s;sUOy@ܝ1Pj(d | ȠJB4Th!"j!FŒ>"i6 |AfvD;| +e-~I~=4t1jԀY8ͭ`C5,KM"'9 rCAY Ǿfˌҹ6Tp:bNC!C $nX:%F 2٪{ 'f#{_H)DEX"шD$PD$L8Bֈ*,((E(B4!5@}.EHI$(@YZ59 D9A( *p ,XP"H x !D2X0L;9}[nE^oO{zDYHLMr(}ͤ$ r/oY,xa&~:ϙN? `p)! `6Dh@ʇjC@:Rf\rq.Pr9@hp iz4AvC4*bL_ZT,<ӝ?ՃO{SA@EF{!@aaI1 A !@d 7f TWVP&%yœ20#Q(i!Kh$))$Mk3niwd4ld![v #OAW5!AxD"o8e-p7!!f(Qւ+^CxD2b:R0>Azp7eo{ߛ-ַ=`W0 х:,HDk X x ZHE'# HGP"[1k ?tD,3xXDyJ u1ے]f3';Y4F%L +|ic{rsp2B3Vc") "TFfYHD,2GH? tj`!~ѓT7Ǝn5Nz#(7z4InZYFcs'qE@({AD!؀ @p@ " @!\@DyvDwp8ah ,d|]BX<M(kIJ `кA` ^fg}WN[4@*0D! R ~@ BB>ިl'9;BX!0P‘ll"Pݖsֶ)}T}; wS J gHQnyj:g 5=5@=))3?:PBP0B ;pщ s jI1 x9ͻ:B<˴02#,Ϣ̊,$tB;rBP 0G2Z$ 8  -c3\ ݸ2۲6: <6L :`Sځ))?@D)?$D>?|+h*ia̷87J<9*A옿)$`*A[8`6pUtW|4hVd8E7pYdE\d]|É"ϋ9LyCƞsFb H쉃8kk7F8nqr4l 1:!H89c$aKJxH<3hDA ѿ-1rEsrtU\(8pL98NJH\IU8UCH6 1G}b)X;v9HG 3'9gGgHÁ?#kHH\7HtʊFnLGUtGK;>x:k9P.D <0jc3B@  $C @䪫0Aث4J&-D/ZHQ|<ŭ2o,ǩHpq,GpmH{ >:X)4X۾ԭ0K Ca>k¡A"BPE'yFy÷NdԀ4WWH_|ȏEE^1!$@h @y$ي,,z`0hAiA8q0#0A% ,)J)H,6l̐єʩGmtm430+dC_A CB3 4T 3 "3R̴Σ,G`77ѯs;8Q6е`Ld˔1bMZT$,~宒tHׂכMǨT|s+5Ch>x谦щX +pP"HT֘7d{7`, ۭFuoӜV:S^ C(0P080&ExR*2 %PijSܚ/$8k nJJUN8hTjCLU^g, ] ==0-\T_TuQHlMs5eٱ _=e _5 `N _~`_ .ppU V``H^5U\u^UWVָKd7XS"99ȅS$ltbo$+~drr=b8hb(b,.3Q2b,c,c<1T\bL"#/0bu7hF0$F888R8: A+^HVXLLǞu>0*E8R ( \5YeW[5Y \[`&fa.\5_5bvfYZ jCp=x a^fo=YAL/&׺\dO_SRA^7؂ 0`VJ8`C[8?FPVLٚO~P0@'=h$#hح#`B=蔗Oryyonyyy7WzzwzOzy_y=m>nSCcQ4ё9xpX 7GY_ۏ$կrBP*\t9W IstBGW|殇e:Fp0MXLM V.Xc]'jƣ¦졈 B.%03*'I$0v_h+i@%P7H-098=8%#xH9pkQVΏ؄U^C?pQ*pͭNc % T"C!Ĉ'Rh"ƌ7rCI )L0"Q DG}=33qq lICU6f̉Ҩqā G(E:lĈ-Ziq(%#TkFE |h"AG!DІ7s3h{ڶ Hإ]ÖCƓ_ Xv*$HG?1_  W 5>x7v("ajHB8B|mmGqц:#7ATpQuNŁ_YTt]uWy )# 9rZ2fiY}!{Az'xgwi(xIǢih.:y> )2hb*).ꩠR*~ Zhr\q+vz+`0J-p((]Ai ju}d7!t;.gʩ2"Ȼ2r潎Ko({&Kp;  K0##pqM`Cl{<^QG!qXcthp(zV-vu#EIt|2 )N -ԡ*{>-ՂfM5׭z4خ[ud]cO˨#gy7ߗǣz=zy'@\NtT`UOIeumvXAt粹.}a>;~;;;*H"I#+oK &Ϡ${ ^wz8X^-Kd.ՖWum{sl8f.xH{%q1$4< @A$$3(ΓDFD! 1qiVTliZx%.!k_$8 iT8b- Ђä0$0;# -r^B!F؀ ->0 5elD(?(Iˎ#Ȩ8i0"Qg3lYfÑzD1qH,!JT_(3Ur1 蠙/ҲHH(@ #`)lP 6x P2E!M!m1{ATdT+%8}ĀCA%AK>gbhM%i|0}\%D#*чm2@ 7X nD\H^pԀ|( F\F`!2HA*Vbf8)a)-a25ue2כ!W&|*D! ?^-UrfYӪֵl[*Wh+^ZW!aÍ F=`mdÝ,\F1HHB2_nfx{EK;dP%S6@\eW VlP۪'-m_WÕmqu[v=.s6Ӆs{&"P񒷼b(/zjI~d%N:qn@81˒,NymuR5̦5LEC0 `4ͫa D0x=Œ:aQ33y8^"^1]l?h!԰T5A hP @N>[Xܰ3!Z3$}uj- xfs2z,f1ysôe5nf.s6gf;YЊǼg3φ&4 tCs4ˏM q2j얱e7n!?Ԭ^51ZիNS=k҉$bu}|k]˺⁝M_6cٮu=m_Kήv}ke;۩Om]TV}]v~+Tg9Ke XL!uL+P` 2ui^VFT=-+U_WţArra|u:rNծ(n\窣*7 R* 9*2t0-X!iabMx gq7nxo;ws\nx:j2.KW,SP%3dC}Z1-XB P2@اxU*d" 2oL=/z_|g(OKq͎}_~sg͏|>$dN!9PS9;ӯ~R>t ;e^|!@@=B!eP E{~  ppS7-xޕyTB#Y9́ `ACIjjM!m]aIڡHPKFMa\ౖHU!˘PWYPS!LS@U@pSܬ4^H؁AX`$Qa',N(]]~ÕNॢb+ʝ-,--I+0vb eaBBT &IB(~K@N[ _L 5K˘=™PL9٤-9I:cz㜵:6<㣝#;:c>>=d@B>ANHhMP$=N|\!4XG^U8 e˸;Aև\9x %y e}Z[)%]qUQ:%]TTZRvUV^^ie[qRXīZA޼޴eA[ee$N0#zV *Rs(GqX Z,MdFdnQXQ!nVfJD؀p T(NS,A~h $S>(ReL d @@ `TFP)oA_AIʟTPjZg`Le MiQ)*yAVaͩaAAbiAKBP@8mOҁS0ea5h^*zFX؁xJi)꩖,v8B8!hЅEh+fC.+ *X<0nm z!F jndrU|`GFԂs rlZ>oDmMr$ǔ],^Ѧ~Th L=ٲ$,-LZޜ( _^.a"r0JT*C4Or/'PJI#5btRGaUxr60 $GZKy\JrnTiKga#on qo|"́/M&!ɯzuou`;)qg<Ρ !Q"唋́+R7rӖdsϸ `ErG!n/IOk E/!F.Q@M)˱0Qjٓ)ς2.gxl 0׹ s33Ne UxERTo$7Ňr.ߌ!u738sq~,N*vo`r1zY6k3(2Q2^~j9nt@pEBx2=?C0![ 1XqZ ̄OjFI4 C6+ !!+U09 :W|~21KD̝.Zr2K-jbOh&G28<'5➮1TK VTuN3RVdlinOysLOJ'.;1[8홤rpv_W򖰁N#"v=qdo!I rgSo l:b:4iNYro7p6qop+MlIKL?Ԑ8&n30aݘ=MCxk\ld5kJz:S[4wwf))F_p|m5VA7O4Fm~?󭉖Kg1NxwT(SAΊt, 1!1 S"cװ7gWoT@Lh(!8!CTN/@]5WN5:n+d[@,OE{&7VsEE/WH1G2?ߕ(qШKx.޹]hko҅Z Uˑkwrz^n?Gګɰzrڶ,G"~M:+6y{P$,Γkjb@]j^״ϯ{ т#!|蹢7hS+gYNUYCøC/KF; *(X\c7l0Z׮n+ VcG{%YlQm7nijc}W$z&RhR~{ɕ@a4KЁaC7aCǑ!:} I4cGA9dI'QTeK$:4f͙hⴹNz4g!$f4T:3iؘ:uBWƙϞB/;lYdcɓm۞94ѤI6MpΜ8ӗ)ކIlcǏ!G~sO zQIcN҄TURc0{w$ r"N=9pgeSpph p6z '. ?Kc ί8b0֤5dPIl) .Kþ,$lx+J R!=T$<߂AÌ%L0+$ H" SD2I˂rE 4B-+z/+/|2;1 6 L̚kM{ 8,+!(zˇJشOC<:Dӳ+"<"B#¿Fñǿ5O: _}) =:Z<ZBׅdnV>f`Qi37s[y\" ٝ%ʻ:;V_}1B'3U7|2OK-c "(݃j" 8O?8&| X2-+Go4fUa4Vp_y6C -X-{)N34Tˋ!?=Ũ@K-9.%x4p9K9ǐx9O7 ?⡏{Xዟo?|ݟޯ?}'{_{Ǿ!~k'7A*Pfr$( =Y+w<Ьndlc‰! qP'(< kB0C iRÛ2!zC$Ї8d X"Q8\a +bj'8{>}c{}Yk뿧G)lP89Jcm'UCІR#0 0i0"m2$+p9aF<C0A)6?poFJPkQ0UJ\Z1DmDyi[9h/ FFp 0 p 0 p U0!,@...888KKKRRR^^^^acZahdddbfiehkkkkdlufoxjnqnrumt{sttsvyvz~z|}mwnyq|tz~t}~y|ţʥ̪ƪʣӦګҮݳòʼխٶ̽ü̵ѳ۶ܻҽտٴ))IQ5,D#*(QŊ!UcC@4r>iA 804GLtE"uA3l#a4EI2 5-5Lݴ[k5n@-Fw kSoCZ{ I%TҸ3^Ky33.GLE0 !BW’,F-)B"\!J)}JG)EIId<:A!//Јs߸#*2 %Ti"ǬHBx,;>R@:H` {}@` vXT+F Z4( ̃<Cدցc4@2l@l! z! aF2"vi;xQxPؕGTV%Ԥ"p^pĊ İ& \)gуԤ\ w1 l<65GؼәŻG[O B|DSp߸"@1@\,x! /~? X83}@4F+3%c2?1DƁ>Aj` /x(RpUȀ/H`b%O1$f9DηFcF%6u' ul.@:::A;J :F؃:@AW3k`35ozor&"1;9RoF #!oD1(]#kxh#EWOoWZ)b3;;d`IJQ7uGlv 8hHXq3w#,s{ȅ$ N?y aovpJSq[и>8O%u[Q[@:Qho_{b _x |ׂ;yTg}7Ba9#fAk Au0(S1E&Fu9 /!$gaT_%j8Csv_()! A#DASvb.XX0Ap1TQG}UeO8b>P TI9[PTfPN=A?A:dfZ34U{RzWfpiPA!533SSkAU\yU}2t0j0 [p3h\[0<=@42&73>A(BYbb>a93* @3UWGh[3u3*HH byyՉbYr4A,6eo5NJQpXdBx@ <'  1'bf3ZQE![SSJ㒫!;(\W%2D~EAEX5^2x,DB Z^)8)3! E8tE B't%1Fgu#@qDqT~L?*U++ 4L5q%`D ds [X:Ȉ!()9%9_ҘX(x*Mʹ#!~v?(9$3 sx"8=@|@yR:lvl:0s:szyuGz~zoX@ODa ӑi'aUoɸ?C h"f:fVjSۡZo)=Ax/K/ȁn !@m(&1mBٸVkل<Ji}&vl@yyG7zTv'\'' zʊ'D?)FA:Kfkf\3b{ щ4T5!Mi<FOG}U%EgE=Fa{} _l۶nppVc[{&\_2Wn5`9"pJʵGxKFc{ Q5뫕ZI 2 XF P>a`bv\u3 aCsKPhwtډB9 9 9GiE:pppE%DC0yi2p0w?o |=SfٗkYCtxy6GH[@ԦǤ03t}p!G 6n59IVVr!M4?4S9EEW yMdIԉ9ŗw6+;5llWsJqP+?<40DmUDPOx!*l'+&%9%N3Nq,@ZVc(J&M~+Xv!Jkc\=3OL b` xW9/DX3dVTYTIfy83tCfUPɛa^ xoD3{>j0 PfW27Yj!@ˬ)w#0'%@!?(ކ0 {H?B)E&䯆F#AqsEQA^3*!6\]{ǎWpUhll`b0bPb -`a5%za,!V\o^btE6;o-F.o4'6'׍g;QIE}Eݲ/{`S!,[')X=Wk_Q9;LjV,jg9ƬL{PeymoOgox@xPm`D\ AӚmI { d|^H@H 48PB >QDVHbF  D4#B{@cEC\܀S̙6`ڤy'6|$"N$h L!EI%nTZZEW5jU*$D^M"礝DVB\?} ޺y @{]d 4E y\4>րŜYB^0gn$+ZmWt2I6ٔhӞd;wnڏt{܏U:>(`ƇcHJ_5{GkjȑiH'ܻT&ǟw~$jj" (4D4[8AڮB /o*"b-%D+ဃc94C:AC!X8ÎGf9 r"𠱴{r°*BXKoĖ`E.D" "PA9E`C4aBAsGt˚:d::!'$H>QaIM ԠF :O9TR)JG'pRrϮ ?4%E$ym! 1a5D6@Y!:X! h( bPfa7 !p !$ Ħ#8p"]);Dl$vPx N_E5-4(pX1#}ķ(-$ TެC G̓Q{"0u#0#> 0#. ?vs| 2NJa$VAYa@~l!9FHFÇ[SBc-"`0"R@;s:-CZ=cYʲC#9 `*O5R i )'IjST$)ID,R8^R 8&Rsd%BՐ.Wl 0JRҔDe*GRv!W $5a)~"EY&QCYT)EIE/DՋ,bP~)}ͫ,JFɆ ;78Nd,4c (Rv g 9xdhg>2Sdr Ikhۻ&g lgAc&7H@2{[ڨ#r(J,3 @BC"&S3&3՘z3?*HaAChdmdS(`Qc@xm&06bMbƛT6su@g|*OdMP6aSȂeO|ޓ \x@EŬf"PCM3#dP`2)bPkˡ^K!U +wdme<54uG} x @ ]܀Qg={xrA M$$GR'b":$R (.$SRq?23vmL?\-՘zV.@(v6X`sh˼Ƶyq{[D5Mg_}KH?u'$@JhDp8bI@G@(@?yQI0IAdJ);zsu+̎?)?DGAGBFx(   -!!p#x0BFh A;SZ&O/n <#+v[)/Y`L) +4̑TM֌d9ڬۤt;=%\9DEa2 K+%4-2CJ5l1dWF+|)MF땇8|O8OKԳA#E16C(ZQBKL47M,Ϥ?.)+ZFx\M9[rQ[Mּڌ9͂:)LQ?Hq> q X[%QJrDzO wo|4SmM[ZQIռM7-ѺDڣ&k2#[ l-&Y ઊ5GMȼT-$LtT/<2ձoG -7hKjɼORd"RDq`0,uBX֔U|QU8DP Nٗњǘˀ@"6Jc41Ɣ Hk4ФY0O* BB1̀=,ֹˢ5ڢOh}ئ1*?j О5_36n#@S >k8 *̉SD մeO|քT[݌K¥ma.ZA T2 m8KNM-!bD Sts62׎hmHU+Cm2KT0AjӂTECh֕e_NspuV$QK)NH NֈS("QP+#TJ8q*nmI.^ `^VPqPf^04*$H1YQ ZEO"u杗+m6S}jMKPTݡT[Fp B{?P1;Ha NyhKY+BhC*w9]i-w+qFżtSm`q _7xV&C!۱}F!<"[W!=eb۹&u1a[6ejNC6؎n̂H:%[C^ɳ#=ޫfm"fuQheMy_v5T`4˂cŰ_&j JtIDMAJY Mˈx%rmT\>!vzE%XOMӻ(XGD aHz*rP;Yts&o9OKe]N-_D7]cQ媊:?5i 16:Pk*{cwlt]o[( oDT$牎O3˻dwEE*BG$Eҍ#*>$^H~-b.:h@^"arFmԪWnmL-elhIGNQԩp)n?!kU-:!Il04uck$!C߸+.B^, hȣI)%dE(y-ivij;aK:Qx!4!EnTTpřXYiVrBhq3RuiCuR\xrDcv"JXHDGO $XSb~PݓQ}RHԄYTPof4Pc4bRJҔIuTreuAc5ZgYVЙmUfE'tijj&e)EIEڨiҝ. YkMtm":TREqXQGUJrx# PʑWliXABvYж nb!N*ڛᦉn}Nh:nPK w7#Q!LR~ahUTG}}o]wuw^~LW!l]/H'ڻ$BŞAQtn݌E]UU|hZ[*\>WA\u^A!yM6_;ԷvyyٴSGG.ᅳVv$RŚuÙNuja)u'"y L,̺OY5<& I4Zk_P"R :CzTqّu.2sv&b' 6traOƛ?&8W9qVh!['Bhh!:HUL+TG°"T$(@Ly I*G4 6Ԅ}Y@;aZeBJ \2-5oJZ✴yċ񹙑r3*g(XK21q.&L8SfEӥ-Im@2`)yAC`Um QIzc=zA"dYg@Is$NLYLs%Ṫ1qtkRW9̨;vxٜM-;d[wR!ADZC$RɄ-sHp B2$Dׄ'7 >kHRcBڢEnNʉ.t$)H Q.d K)J╄$D "`A2D,B1/(ajS_3}fC$9"En +5nvm^Lɴ6aL40!K9>Sm^MSjB:D8_<!%)NhTUɴjlc6KI$Rgc a4,dLkt78Gntmmd؁FXH,5LMdv"(bI44'9pI>CUk~9LAeٱ"(fnqY< L0e||斠+&q`ң}dzOTUddJێE5 eWCX2U'tcX˪!xH[JI$#\݌A#.rK)] SyCxbFTE军aUTРfnՉld%_xԅxLH`h,W]WN- aCe_0fa! e&q} hzŌvʜ4͘҂̴S_,zx<FI|Aե!tF-TarRS /n1b[UhIr$7)Gz8eQT TLMBAThM!1ۿ!L&YZKZGwʠAp$D *馼 QdEB T5>T YJdKhOLJK&Aю1D61Hަ uWFz*󐇒W( 0Ԫ8c䡷 /LU~4Jbz7"JU0ϡ`W\WGk>Fye)EH(6L}(]FA GB2 d\1"":HEzAM0d_ȁ^M5[< ͒ǔE4moꁹcC^dT Rv)$|dZ'e'Σ@zeTX4GAH,A|ID&džN%DgKD)=tQ?Z5W0#֌V%M Pb`Q J$߱ _$EJ(ͻ0rVxٔ%G.qXWKu7W XlX|E'yڢF,)Մ=kl޸1ڪv="[6d&#SEnW,\ zX]+:d+nջLFUTg蒮 Qwa@Dg V\;{0dLh^$Ɖ @ g8I),MMjv aqA,xI"HtIgX~ EJ(Fɦ Iӎ|W^@{~fmĦV,jLfKSm2 p jNЁnz+]#xFjшj:DMaWD~^1PtٲCDc[eפt ṞH,DLΚ"V)B9DAɔUlYM e FBqVܘH^!pR V]fMg{D.jW䜂 {$ȁ}>Y ݽWjdx>M·˄cʊUԗ El2vjIDZEBf]Xkz]jFbDЁ2KB1VP͒Τ%2Gu2A\"l?&J,X]AM@:R|6yiª}N]lD_,eJMjE- XOSd)VMXsuD6 Ĥ1ēr} Il}g|:#BqU|h\Aۑ;|&@Qd",|X`AIh1qNĂ H w@,reCŔ93&57C&Br'͙|9"EMiMGB:tD`fʉdh3eǒUf9p޾+.]eǍ\Y#!0 k"+ JVhMCn\gG $8iFKzPI5 8R2΄ΡH^lujcС?vΑ#ڻwUT&W;vy\!o n>쨃6:B`Oo5^j*;(pD; 16ELC yNDJ*ˈ9moⲋ8 C*րJH|(k:*'K31,HR( UDߊͤt68e(=cJN8+::"K7oh{ӨQSEL=UTUiJWB+#N-! z묺+R,CUVm4MnO38K2`" 8PÍy?{o8# 0PАMV"BB+$>1=bD tn<~@C3L /ꐃBlÍ@ôaju E6/Na.q4S?FϬr k^bݭˎF2dB=d:[1^芛›MD?:cњԮ^A,m:7#, &HmRVHM-gNs՝I\Euj4ϼ׍xDKb T 8"90%ͱKX女nꬳ"Tc#>~ Y4 Kn hB_:X>o-$#9*kb]v5FH ^_b3 " #IDp1$`j4=y+al0($A_H*SA#$\ҘZ/H ,bJy[z:MsCWPЂn@C_QyˋF }7`ỶHP2G1žFtd|ӳ! { p{CͮФ@PlLy]r]#ּ,e}ȁd&D(M< q9ؔH2-e+eQor*%8DmmqrPM{v&0sP!0U ]D&ݴ%y`N,uEľE] teKeG0^sn)f02әHzqlӬĤCcvpA"2L v>k6#. 4 N@IseX`ɡf$C9@c0k"1c&D6iȥD(פp% H7 "0Hb:Ji,R*;;h=u vuE859?t"8B ,%;eRbP'io׼ؽhF[( ڦŮjT]ج?K;jI-?\g@w~vHKL0\_t !LӱrUrTTML+2rt^\],kNԬ0$*ig9ˡXM-Fq\t[s{7SGuno:lڶÜd)҂R"nd*P8y# !v.]@He/ka|"f CrLP0EƖŘ#Kb R\i,ңȢ/B>:kQ>q1qQ qΔqQPd* ٸ&'`m0uL 'Q(\( Њ`pQR&ڬ*pZ P8TΎ /mNJrM[R,L2gM$_L`&MdiVpLnKn "(x<"YE#{`*r,***r+O*+r+,+2-+,aֲWƒ-/20,_s-\!-.r+I0rfBP^3?.C*"ԠL44R4UNZ5Y4g`K hS5w7OS`6!64c5a8M 7es5is78i8M38353\r35S6Os8s;<)WЯl(eE\j ԀZ UC4aQ Y)%E"#gk}VJ'Vwg&$`Db`h@V " 0@`e@P "o{1>w fI#t  aL`f 6 F B@f@^0`K`֗}ٗF@ f6` r`J ^FV@P^:^FzT hDX}@q W} X~hr`؀Q re rB8t`R8FXs aX $V xp!v~@`4 6~@ `eICCf2_*(4)f[b5 % s A` Ā@Y-(9-=2 @ t uٖ  4Y9U X@@Y 9|9By9@L` |y }yXY 45 y!!afD:\lr3<gq#@@EY`?zIZ@ BYI?]iEY LBCzmc]h Eb` ʀ5A )\IZFㄮ& 皮Z   : : 蚰{ڱ t'۰Z:[+Z{ﺲ A۵G;Q;` z 2hPq/n/F'KYJ'6Y*頺0-j0ۼK=һJRZ{{+ջ;߻C *|·:/>!CH~$<(FU=2ƜD0ZLXc\Il1mo|u\#m|<{ɉ|ə\ǃɅ\*lɗʋ\AǡƇʛ<Aü|w\\+a zp;q<ϩ m$G|}!U=%r}1=5m#%@v@P=M]Y]a=e]֝vmku}y}ׁ=؅KY!,@...888KKKRRR^^^]ad_fmdddklldltkosnrumt|tttsvzvy}{||lvmxu|s~z~v}{åŦȥ˪ƮʧҪҳIJʼ«ԯضͽļʹմٵ޺ҽվص HEpÇ ŋ3j$(B *j"ɒArȲB T2KEKPfbG n<'r " 73 S 1Ha@@F LaLHl8DH#m\>;Hl3949!Os"7;]VtFwD +l;҈m-qM&3] ۹QBR(q)Rg xDA7[t=۔Q m|I.褗PNob?,t'F"k3D¶l;nނ oyCr8:(F:$Dlޛs+Ʃ~~/~>?r/~sV0 \amx: `10 `=HE\% Ù2XٔQwϡt3]D`D%BLG8 j]~Ȣ8A[.t`1vp\`xB8-a ,ӊ9em$oCfr&k$dFT!u(Q$'YD@Ċ>C6=bp&F` $ p%.;I.t5%ha#+H1@y"6Yjռ5I;dĦ7IkzS +2 3e>䑖;fHyJqt,Fi @JЁ֡[H@3=)O&$lf"ӊ3H R)$M(Rt*M)LR& Ԡ4!T|ΌǪA4HR ̖\TsUf4 XvU`VRAzC#q5P p :Pj2}'1 #!؆Ulc1>iȩАE>A^DPgbԵKWEֹn£r[Mc@:| \@͹v"6Uu$AB~Rks#`;hD *n"»CncDİ+ha 1JF2d1Ik_ ,9Cyb{ABpA< #k.Pt= .>1gR a'jI2(L5a>袒a td0Pas60`  8P`s,Eh"ͱ<,g Dʐ=yϔ)>c0dOt`A v|` 0X*a'F@$ >ѸT]] ! kPr j ΐkؾuwl70[<-6k]zn06(7;V-nrW;^!7=oy߽o ^ɽh уB D!*KYCG aʪAX4 Nl\50MʁDZMos 9 P %"ԠFmC#FN#t mԫ?]:ֹ֬NnQ/|ub=-ҷޤPW;}Ͼ;7x6=i";mvЃ" ؀A/WAC8 $\ܐꪁnDN?8b\u@04 Gra`ƥ20P#1-COJ@?(8 =?;t$cX CX0X xWЀSxRЀ ؀W(gecn(<0Rܡ=s#AtGbQ$I}""xDa'DEHxE?@]BGIB!r%Wo dXfxWwhX~xͧ c&P!P]VCq7y-`<`h6Ј؈Xh>60g&,(8 `@2ts$D]"td`E\z@ 'RhA1,ϓrWi@BEhʘWr8 n8׆1SY}NV1PT==@{rxEWYKfIYq]dJJƐf]DpG3B±bx<(HB6HRdk20';OB<SS/ɕY'?%\k0r&i"nuqw:_`\uY9_Y~oGgirK\@tis@h\pP-Bw\`a xit6kXs2 3b9=spmrmj?mjooxxpnik`jA<oxmy)nY'̹yٜIyvpߩYx3yWyer깞 Ntyu0@yV6^iwC926: {cw[65k)!HTT:&9fgqrfg>fr֡ 0!L, . xL@GX0@ЇU8aU`QEbpEʣ!y@FtV:VgA֥ib:'Ob$sBIfu4{0A9^ee$pr:*?S@s?>@ @s>*@J/ ʩT*j?B.xEԫ}Kx@F,'1p'00Κ0K5$ڭ9zdt9 TIL?$z9C9?IWʯ LQ`:Ggo4spPŅMy@s@u@hLDM10D1+ H@GEbP0C=QBcKPu@T yF P/yNy 1cB&s <዁#]TaЊS̵pe5bT4{5^#4pGw[F4D9Y:4~|s|$65ڭ@A`YP{\p8O=| :PoD nA0!1ъ<1 77DzzԪ4@.>s棩ʩKK瓽 S>S;@Ϋ/6@۾K۾K4060KfD&k8}&C\:0&I718Ef u/QBZdnvdpEu~PG}0=E:@EBd82]n%˳RwVcƍ0_NM_]s`:; W@Ty Uv`Z 1w[f}Po6_wJ\olklo6nmp,olnnʾʵl˨l˶ nnіʮl&ɼn ˽\˷k*@`t͍@=U0gФU\g0?D0<1C1ēmctVl;=]m = wM] M]qdW$@UPK$@'j$b$`#0]F@KvG@8D]F}H`Z>~j}T=Kp4 pf,jXJ~hfBpr=t]PXyp\[hhp_pu~sţvَٜٚP9iM+yM+uٴ]۶}e fE4_Yܾ}]\m8%}쫿;=-} F kvX ٚٺ@]=^ڻgx}~g];lLfPUNwy\P[h0닍fr\Zs2]^kH sXH˞&״n{n~7`GlV$.>"_ _O2}6使3`彿4$OVa!(,(,V -F3_;:o6)<784oK/CM_@QKItvp `_?bodoboe/nj⩸JB[z/xk.}w?[?'jEMkh-@@ qk"2;p̣'inB8Ё Lܨ˂!D* A`Yz"=z8Cp jMp:;nxazަ䊿E|~=)Ϯ\ę]A)7${CP?Z* ^R(>̒z]=(RaH+&W`JuS,bBb!|"~Е`pPnv4$m< Wf, )z3/Զ^y6VkK~wxi%[)K*%B`db0F@ P` '\p0&y,^%ٸnc]ɘƷu~^Cen=iB:, rP*0 @l(5!Q*[vW]{,g:s,^ Ai!> -9ܡ5,1UldMoӺ3h-6 RU rHXja[j׋n3h>?`Ѕ!jBޅ,r_.x N0! 85A)NdOA‹9ðy r~A]xӡ%  HGݥ4_Po qJZwDs6kdh@"9ݠYV?w;..'"Q|@$_ӹ %BXjq>,?SOCKEr6@ 4x 'ž"=~j%2' Ai$B SMb7p"!#Hꣃpi"tꞓr "M2? '7@( K'qZM –'*$"0Ah''@2j`a;k; Ȃ) h&;));{;#9@b5 5i !E!˝ <'2h'쑝<7D3E iE@BG ZzU#ɝ7h):ڟ恞c @QԨۙر@J* Cpl6}1;gI. )# P XXt;5|?ĨI:7y{b7 \8G6ӕ 7`+u9:1˷c5Pse9;4T, wd$94zT?tp7봗1w3[z[HQHė3@|?Dh89J (ik$cKDU52Yy]CJɽ]N&\eb2UX5XOcޕ1^⅔P?de_NiCCeD6fǭZ[egdb=cB] PQU֝mVYc} dZVfau>6\RUжuTbP.dP1~a6ߠuf2TeMKTfNCn[}T"5cgdu~_igifg`1SN@ma^RgLK ؂2;M:;Qm=c NcvShU7m}d۔`ys俭]^K3i- b938jU% P8Xfj&؃!̆]!2ET j =jB%`IV.W/MֲݗP^OVn1(Oӆ9o ۷uЗk,n4c"GeùʆDm^ ]?8\$_VkFe>sh^ DGrnd6ȂVs.tc^'f3.LNVY+ 7`=̞6XotAMnW-~5u-nug]Mvq!lMolR/$s׀Xsr~ե^wwϳgeUbA _x~`vU݋%Wf7ĕ[fNvFۄs&uKDoYHD PGJ?6KӠfOTVXHd%kX3wpl¦V&wfT77PWoST؃oLz4'qu?XmnPsxT7fT<&zvdzu`ZXGXS[&z4 ևvgj-Osed&s*"}2so7\w~W~/F\īwxgky_qoyʷe-y}4לYc0L2 \6i,dhQ`3o z##HAC$dȓ!GDYK2?iG8[̹g͟BS*S'MEo)rAP( %b(QA!c"F|Æ͛?%[GFQ]-IHҭ rѶCk[Ƞz]M1SA?PWD F_7SXƴ{i]Y4(+oꙃ-9;RO0Pתو sk.H5 1Q]^:ýYk.mAUtfL5/OϜ*Ejm~;]HFTxw ChW"(%RbEd1hƅo`to$~4Q8ejsXx "(Ӎ aL%ۄqfAWPDtTLW~3`fRbǖlΆԂ9T^gEdXUQYt]w%Qv;el(&B JSVtpQA`a(L8Z%g{ţS:zb zd^ @hBA1xy"u|z 6KkîTfVBiAbЭ}8-FQ~[Zi*`d.R>&j棾ED1AKffiDj2nIhHPYɧW='h9oqQ #\%&!ƺFdf^QEIkʴ9]& n Fl^m^>;o}!gпmFFA+4 SR<0垃k^Jw٣lږ2t:YuR_2YS;#}~}Pkz:VK~vG\c=T:,Q[WwJ_+9PD mAjCYgy^ke.y)s-M\j>R_WX|ZIF=fra#h8yIbHL{H"ONQȭ:#4=Dy^ [l$:֙e;e Oa01Wz׽݌MF(B?ptMډʂY#(蟧S B# |DNlCEԌQ7 }Ig@Ĉ+=rd^$Z bJZ30w%8u7dʵ22!mnJW8:Mp?s&퓔UN8EAy#q hjo'@sE)hM{ON&( I::_DTQMT*!KAFD;m 3Շ,Râ㕃/iCz A;a4{Uͥ!Z% r(5hʡJuXֆ|55M o4dm1}l!sٗ&\EÉD u eiF ϾZqi|n(Rʭd :dQ'%j՜X2`7sQUҙD3M ̥is-.%NYnХ3M>tAXC ?e䡭[_ ݾ0Ե.԰=UȋF3Mh;YPSnWWy0Bn-4pm +*ي`K$!31jafm`c@A^P)"_ tu 8:Qq]9]G3"Sbq[ג Ӝ@79hKj{%K_NϮ1x<%P=dC!HMD[Ԡ`^uvAgP Ց@,J -c|S8v!đ$a{##r(`kCV)`/vv盭ڢ֘f҃_BC$茨t] b-b&2iqR3 Fd A0ًZ$W¶&j N:[9ܟLZnH:tBQj?`j@ ?y,&(lm-123jA,fzGƇ/aʳ%L;!30N x(^Ȩm*'[fn .m#bbAzp^[ߦI6կ'([*R VHBj7j6j&oru8 D:5O=ht~͆VbHT+Rcvc݅sd{8pbisJ\jG/mt+f>Gm>^σ~>G6WX!jIQW0|)ϲuݻˬm ]QMȒba %)#N 6[aQMHӍXE׃F,o4d

b$Oa*F"!yd˭\KJ:QWKd7v0_MA$^T:3ɢ -$Q==S`X ]$UU?Ne}_,T$,#k=bf)![>$)$TaNsXZE0DШTD́ S8>ݤ Վe@ VMe2(do8Aj%1 $iXEAHrWNCa"U*Q\dn]6ȇ%%Up=RTᔹz!b$շVыu,݋@%|2!볪&HU#ghIUG-O~k 븖k" }+zk뻾 k+F㽆+Ѵ+k4vkΫ-+M+6«ą+ګ(ljl9pfXfGONiNIXReEJblib%M)H)^ˆif>6.-.BeْV!)"Zm)©NmZ*҂ f* Y4$*fDiHʊ"BA㶁V.&F:.VcXJJalE.nv^Kf1 4 \@0B AQP#ZE0+#|D\0;@)T%4B""̜ax1eY0"gܡ!2}h Ѡ@/"! "t< B,@@"pA@!A4! G 4! 4,@4> A? p @4ex`HS)CeUR[mAt\@@, `t@ < @( s( |@ < N(t NN pAXV @hA]`A QHuFd7(i5g{l6AЁihv́i|6p+ ApvAs7wnnvqgqA $TJ7qRGZ蝽OLȁ}w}Ϸ}7}7}Aׁ~|ˁpA~x dvyO%yCeLL!d`dA8g888g丐9|8A;yGy8$j#XО}JX۷ ProGuard Downloads

Downloads

ProGuard is distributed under the terms of the GNU General Public License. Please consult the license page for more details.

ProGuard is written in Java, so it requires a Java Runtime Environment (JRE 1.4 or higher).

You can download the latest release (containing the program jar, the documentation you're reading now, examples, and the source code) from this location:

Download section (at SourceForge)

If you're still working with an older version of ProGuard, check out the summary of changes below, to see if you're missing something essential. Better look at the up-to-date on-line version if you're reading a local copy of this page.

The download section may also contain updates with sub-minor version numbers. These versions are typically released shortly after their parent versions, for applying emergency fixes. Please make sure to look at those if you are encountering any problems with recent releases.

Finally, there may be beta versions of upcoming releases. They may be of interest too, because they typically contain any less urgent bug fixes collected since the previous release.

May 2012
Version 4.8

  • Added more peephole optimizations for strings.
  • Added support for multiple external configuration files in Ant configurations.
  • Added support for Ant properties in external configuration files.
  • Fixed parsing of empty file filters on input and output.
  • Fixed parsing of '*' wildcard for file filters and name filters.
  • Fixed obfuscation of private methods that are overridden in concrete classes with intermediary abstract classes and interfaces (workaround for Oracle bugs #6691741 and #6684387).
  • Fixed optimization of complex finally blocks, compiled with JDK 1.4 or earlier.
  • Fixed optimizing signatures of methods that are marked as not having side effects.
  • Fixed optimization of long local variables possibly causing verification error for register pairs.
  • Fixed merging of classes defined inside methods.
  • Fixed stack consistency in optimization step.
  • No longer removing debug information about unused parameters, for -keepparameternames or -keepattributes.
  • Fixed updating manifest files with carriage return characters.
  • Now removing unreachable code in preverification step.
  • Improved default regular expression for stack traces in ReTrace.
  • Updated documentation and examples.

Dec 2011
Version 4.7

  • Added support for Java 7.
  • Parsing unquoted file names with special characters more leniently.
  • Added support for instance methods overriding class methods.
  • Added removal of unused parameterless constructors.
  • Added removal of empty class initializers.
  • Added peephole optimizations for constant strings.
  • Avoiding idle optimization passes.
  • Improved removal of unused constants after obfuscation.
  • Fixed removal of unused classes referenced by annotations.
  • Fixed simplifying parameters of constructors that should actually be preserved.
  • Fixed simplifying parameters of large numbers of similar constructors.
  • Fixed exceptions in optimization of unusual obfuscated code.
  • Fixed NullPointerException when specifying -keepclassmembers without specific class or class members.
  • Fixed potential problems with mixed-case class name dictionaries when not allowing mixed-case class names.
  • Fixed obfuscation of classes with EnclosingMethod attributes that don't specify methods.
  • Fixed preverification of returning try blocks with finally blocks, inside try blocks, when compiled with JDK 1.4.
  • Fixed sorting of interfaces containing generics.
  • Fixed paths in shell scripts.
  • Fixed filling in of text fields showing class obfuscation dictionary and package obfuscation dictionary from configuration in GUI.
  • Worked around Oracle Java 6/7 bug #7027598 that locked the GUI on Linux.
  • Updated documentation and examples.

Feb 2011
Version 4.6

  • Added support for synthetic, bridge, and varargs modifiers in configuration.
  • Added detection of atomic updater construction with constant arguments.
  • Fixed merging of package visible classes.
  • Fixed optimization of fields that are only accessed by reflection.
  • Fixed optimization of read-only or write-only fields that are volatile.
  • Fixed handling of side-effects due to static initializers.
  • Fixed handling of bridge flags in obfuscation step.
  • Fixed handling of super flag when merging classes.
  • Fixed updating of variable tables when optimizing variables.
  • Fixed removal of unused parameters with 32 or more parameters.
  • Fixed incorrect removal of exception handler for instanceof instruction.
  • Fixed inlining of methods with unusual exception handlers.
  • Fixed optimization of unusual code causing stack underflow.
  • Fixed keeping of constructor parameter names.
  • Fixed unwanted wrapping of non-standard META-INF files.
  • Fixed filtering of warnings about references to array types.
  • Fixed overriding of warning option and note option in Ant task.
  • Improved detection of file name extensions for canonical paths.
  • Improved printing of seeds specified by -keep options.
  • Improved printing of notes about unkept classes.
  • Improved checking whether output is up to date.
  • Updated documentation and examples.

Jun 2010
Version 4.5

  • Added option -keepparameternames.
  • -dontskipnonpubliclibraryclasses is now set by default. Added -skipnonpubliclibraryclasses as an option.
  • Made processing independent of order of input classes to get even more deterministic output.
  • Improved constant field propagation.
  • Improved renaming of resource files in subdirectories of packages.
  • Avoiding making fields in interfaces private.
  • Optimizing exception handlers for monitorexit instruction.
  • Reduced maximum allowed code length after inlining from 8000 bytes to 7000 bytes.
  • Fixed missing warnings about missing library classes.
  • Fixed shrinking of annotations with arrays of length 0.
  • Fixed handling of -0.0 and NaN values when simplifying expressions.
  • Fixed copying of exception handlers when simplifying tail recursion calls.
  • Fixed optimization of introspected fields.
  • Fixed simplification of unnecessary variable initializations.
  • Fixed evaluation of subroutines in pre-JDK 1.5 code.
  • Fixed updating of access flags in inner classes information.
  • Fixed disabling of field privatization.
  • Fixed invocations of privatized methods.
  • Fixed updating of local variable debug information in optimization step.
  • Fixed print settings without file name in GUI.
  • Fixed field privatization setting in GUI.
  • Fixed saving incorrectly quoted arguments in GUI.
  • Fixed handling of regular expressions with only negators.
  • Fixed unwanted wrapping of non-standard META-INF files.
  • Fixed regular expression pattern for constructors in ReTrace.
  • Updated documentation and examples.

Jul 2009
Version 4.4

  • Added new peephole optimizations.
  • Added option -optimizations for fine-grained configuration of optimizations.
  • Added option -adaptclassstrings for adapting string constants that correspond to obfuscated classes.
  • Added option -keeppackagenames for keeping specified package names from being obfuscated.
  • Added option -keepdirectories for keeping specified directory entries in output jars.
  • Extended options -dontnote and -dontwarn for fine-grained configuration of notes and warnings.
  • Added option -regex in ReTrace, for specifying alternative regular expressions to parse stack traces.
  • Extended renaming of resource files based on obfuscation.
  • Improved inlining of constant parameters and removal of unused parameters.
  • Avoiding bug in IBM's JVM for JSE, in optimization step.
  • Avoiding ArrayIndexOutOfBoundsException in optimization step.
  • Fixed configuration with annotations that are not preserved themselves.
  • Fixed preverification of invocations of super constructors with arguments containing ternary operators.
  • Fixed processing of unreachable exception handlers.
  • Fixed merging of exception classes.
  • Fixed repeated method inlining.
  • Fixed inlining of finally blocks surrounded by large try blocks, compiled with JDK 1.4 or earlier.
  • Fixed optimization of complex finally blocks, compiled with JDK 1.4 or earlier.
  • Fixed obfuscation of anonymous class names, if EnclosingMethod attributes are being kept.
  • Fixed obfuscation of inner class names in generic types.
  • Fixed decoding of UTF-8 strings containing special characters.
  • Fixed copying of debug information and annotations when merging classes.
  • Fixed writing out of unknown attributes.
  • Fixed updating manifest files with split lines.
  • Updated documentation and examples.

Dec 2008
Version 4.3

  • Added class merging.
  • Added static single assignment analysis.
  • Added support for annotation and enumeration class types in configuration.
  • Refined shrinking of fields in case of unusual -keepclassmembers options.
  • Added simplification of tail recursion calls.
  • Added new peephole optimizations.
  • Fixed optimization of unused variable initializations causing negative stack sizes.
  • Fixed optimization of unusual initialization code causing NullPointerExceptions.
  • Fixed optimization of half-used long and double parameters.
  • Fixed processing of complex generics signatures.
  • Working around suspected java compiler bug with parameter annotations on constructors of non-static inner classes.
  • Fixed obfuscation of classes with inner classes whose names are preserved.
  • Fixed access of protected methods in repackaged classes.
  • Added options -classobfuscationdictionary and -packageobfuscationdictionary.
  • Adapting more types of resource file names based on obfuscation.
  • Extended warnings about incorrect dependencies.
  • Added start-up scripts and build scripts.
  • Updated documentation and examples.

Mar 2008
Version 4.2

  • Refined data flow analysis in optimization step.
  • Fixed handling of exceptions when inlining subroutines.
  • Fixed inlining of incompatible code constructs between different java versions.
  • Fixed computation of local variable frame size.
  • Fixed optimization of infinite loops.
  • Fixed optimization of subroutine invocations.
  • Fixed optimization of floating point remainder computations.
  • Fixed removal of unused parameters in method descriptors containing arrays of longs or doubles.
  • Added undocumented java system properties maximum.inlined.code.length (default is 8) and maximum.resulting.code.length (defaults are 8000 for JSE and 2000 for JME), for expert users who read release notes.
  • Fixed processing of generic types in Signature attributes in shrinking and optimization steps.
  • Fixed processing of inner class names in Signature attributes in obfuscation step.
  • Improved adapting resource file names following obfuscated class names.
  • Fixed interpretation of package names in GUI.
  • Fixed default settings for Xlets in GUI.
  • Updated documentation and examples.

Dec 2007
Version 4.1

  • Fixed shrinking of default annotation element values.
  • Fixed optimization of invocations of methods in same class that are accessed through extensions.
  • Fixed optimization of invocations of synchronized methods without other side-effects.
  • Fixed optimization of some non-returning subroutines.
  • Fixed handling of local variable debug information when inlining methods.
  • Avoiding StackOverflowErrors during optimization of complex methods.
  • Fixed obfuscation of potentially ambiguous non-primitive constants in interfaces.
  • Fixed preverification of some code constructs involving String, Class, and exception types.
  • The Ant task now allows empty <injars> and <libraryjars> elements.
  • Updated documentation and examples.

Sep 2007
Version 4.0

  • Added preverifier for Java 6 and Java Micro Edition, with new options -microedition and -dontpreverify.
  • Added new option -target to modify java version of processed class files.
  • Made -keep options more orthogonal and flexible, with option modifiers allowshrinking, allowoptimization, and allowobfuscation.
  • Added new wildcards for class member descriptors: "***", matching any type, and "...", matching any number of arguments.
  • Added support for configuration by means of annotations.
  • Improved shrinking of unused annotations.
  • Added check on modification times of input and output, to avoid unnecessary processing, with new option -forceprocessing.
  • Added new options -flattenpackagehierarchy and -repackageclasses (replacing -defaultpackage) to control obfuscation of package names.
  • Added new options -adaptresourcefilenames and -adaptresourcefilecontents, with file filters, to update resource files corresponding to obfuscated class names.
  • Added detection of dynamically accessed fields and methods.
  • Now treating Exceptions attributes as optional.
  • Now respecting naming rule for nested class names (EnclosingClass$InnerClass) in obfuscation step, if InnerClasses attributes or EnclosingMethod attributes are being kept.
  • Added new inter-procedural optimizations: method inlining and propagation of constant fields, constant arguments, and constant return values.
  • Added optimized local variable allocation.
  • Added more than 250 new peephole optimizations.
  • Improved making classes and class members public or protected.
  • Now printing notes on suspiciously unkept classes in parameters of specified methods.
  • Now printing notes for class names that don't seem to be fully qualified.
  • Added support for uppercase filename extensions.
  • Added tool tips to the GUI.
  • Rewritten class file I/O code.
  • Updated documentation and examples.
Upgrade considerations:
  • Since ProGuard now treats the Exceptions attribute as optional, you may have to specify -keepattributes Exceptions, notably when processing code that is to be used as a library.
  • ProGuard now preverifies code for Java Micro Edition, if you specify the option -microedition. You then no longer need to process the code with an external preverifier.
  • You should preferably specify -repackageclasses instead of the old option name -defaultpackage.

Dec 2007
Version 3.11

  • Fixed optimization of invocations of methods in same class that are accessed through extensions.
  • Fixed optimization of invocations of synchronized methods without other side-effects.
  • Updated documentation and examples.

Aug 2007
Version 3.10

  • Now handling mixed-case input class names when -dontusemixedcaseclassnames is specified.
  • Fixed optimization of synchronization on classes, as compiled by Eclipse and Jikes.
  • Fixed optimization of switch statements with unreachable cases.
  • Avoiding merging subsequent identically named files.
  • Updated documentation and examples.

Jun 2007
Version 3.9

  • Fixed processing of .class constructs in Java 6.
  • Fixed repeated processing of .class constructs.
  • Fixed possible division by 0 in optimization step.
  • Fixed handling of variable instructions with variable indices larger than 255.
  • Updated documentation and examples.

Mar 2007
Version 3.8

  • Fixed optimization of parameters used as local variables.
  • Fixed obfuscation with conflicting class member names.
  • Fixed incremental obfuscation with incomplete mapping file for library jars.
  • Updated documentation and examples.

Dec 2006
Version 3.7

  • Now accepting Java 6 class files.
  • Fixed shrinking of partially used annotations.
  • Improved incremental obfuscation, with new option -useuniqueclassmembernames.
  • Printing more information in case of conflicting configuration and input.
  • Fixed optimization of repeated array length instruction.
  • Fixed optimization of subsequent try/catch/finally blocks with return statements.
  • Fixed optimization of complex stack operations.
  • Fixed optimization of simple infinite loops.
  • Fixed optimization of expressions with constant doubles.
  • Tuned optimization to improve size reduction after preverification.
  • Fixed overflows of offsets in long code blocks.
  • Now allowing class names containing dashes.
  • Updated documentation and examples.

May 2006
Version 3.6

  • No longer automatically keeping classes in parameters of specified methods from obfuscation and optimization (introduced in version 3.4).
  • Fixed inlining of interfaces that are used in .class constructs.
  • Fixed removal of busy-waiting loops reading volatile fields.
  • Fixed optimization of comparisons of known integers.
  • Fixed optimization of known branches.
  • Fixed optimization of method calls on arrays of interfaces.
  • Fixed optimization of method calls without side-effects.
  • Fixed optimization of nested try/catch/finally blocks with return statements.
  • Fixed initialization of library classes that only appear in descriptors.
  • Fixed matching of primitive type wildcards in configuration.
  • Fixed the boilerplate specification for enumerations in the GUI.
  • Updated documentation and examples.

Jan 2006
Version 3.5

  • Fixed obfuscation of class members with complex visibility.
  • Fixed optimization bugs causing stack verification errors.
  • Fixed optimization bug causing overridden methods to be finalized.
  • Fixed optimization bug causing abstract method errors for retro-fitted library methods.
  • Fixed optimization bug evaluating code with constant long values.
  • Fixed bug in updating of optional local variable table attributes and local variable type table attributes after optimization.
  • Fixed interpretation of comma-separated class names without wildcards.
  • Updated documentation and examples.

Oct 2005
Version 3.4

  • Extended optimizations: removing duplicate code within methods.
  • Extended regular expressions for class names to comma-separated lists.
  • Now automatically keeping classes in descriptors of kept class members.
  • Added verbose statistics for optimizations.
  • Added boilerplate Number optimizations in GUI.
  • Fixed Class.forName detection.
  • Fixed incremental obfuscation bug.
  • Fixed optimization bug causing stack verification errors.
  • Fixed optimization bugs related to removal of unused parameters.
  • Fixed exception when optimizing code with many local variables.
  • Fixed exception when saving configuration with initializers in GUI.
  • Updated documentation and examples.

Jun 2005
Version 3.3

  • Extended optimizations: making methods private and static when possible, making classes static when possible, removing unused parameters.
  • Made file names relative to the configuration files in which they are specified. Added -basedirectory option.
  • Added -whyareyoukeeping option to get details on why given classes and class members are being kept.
  • Added warnings for misplaced class files.
  • Improved printing of notes for Class.forName constructs.
  • Implemented 'assumenosideeffects' nested element in Ant task.
  • Improved processing of annotations.
  • Fixed reading and writing of parameter annotations.
  • Fixed various optimization bugs.
  • Fixed wildcards not matching '-' character.
  • Fixed wildcard bug and checkbox bugs in GUI.
  • Setting file chooser defaults in GUI.
  • Leaving room for growBox in GUI on Mac OS X.
  • Properly closing configuration files.
  • Updated documentation and examples.

Dec 2004
Version 3.2

  • Fixed JDK5.0 processing bugs.
  • Fixed optimization bugs.
  • Fixed relative paths in Ant task.
  • Improved speed of shrinking step.
  • Updated documentation and examples.

Nov 2004
Version 3.1

  • Improved obfuscation and shrinking of private class members.
  • Added inlining of interfaces with single implementations.
  • Added option to specify obfuscation dictionary.
  • Added option to read package visible library class members.
  • Extended support for JDK5.0 attributes.
  • Fixed various optimization bugs.
  • Modified Ant task to accept paths instead of filesets.
  • Fixed two Ant task bugs.
  • Updated documentation and examples.

Aug 2004
Version 3.0

  • Added bytecode optimization step, between shrinking step and obfuscation step.
  • Generalized filtered recursive reading and writing of jars, wars, ears, zips, and directories.
  • Added support for grouping input and output jars, wars, ears, zips, and directories.
  • Added support for applying mapping files to library classes.
  • Removed -resourcejars option. Resources should now be read using regular -injars options, using filters if necessary.
  • Rewrote Ant task. Input and output modification dates are not checked at the moment. Minor changes in XML schema:
    • Filters now specified using attributes.
    • 'outjars' now nested element instead of attribute.
    • 'type' attribute of <method> element no longer defaults to 'void'.
    • < and > characters now have to be encoded in embedded configurations.
    • <proguardconfiguration> task no longer accepts attributes.
  • Updated J2ME WTK plugin, now customizable through configuration file.
  • Updated GUI.
  • Fixed various processing bugs.
  • Fixed ReTrace parsing bugs.
  • Improved jar compression.
  • Updated documentation and examples.

Mar 2004
Version 2.1

  • Added support for JDK1.5 classes.
  • Added additional wildcard for matching primitive types.
  • Added possibility to switch off notes about duplicate class definitions.
  • Fixed use of multiple filters on output jars.
  • Fixed option to keep all attributes.
  • Fixed various Ant task bugs.
  • Updated documentation and examples.

Dec 2003
Version 2.0

  • Added a graphical user interface for ProGuard and ReTrace.
  • Added -applymapping option for incremental obfuscation.
  • Added support for filtering input and output files.
  • Added support for the J++ SourceDir attribute.
  • Improved detection of .class constructs.
  • Improved handling of misplaced manifest files.
  • Improved implementation of ReTrace.
  • Worked around String UTF-8 encoding bug affecting foreign characters.
  • Fixed exception when ignoring warnings.
  • Fixed various Ant task bugs.
  • Updated documentation and examples.

Aug 2003
Version 1.7

  • Fixed various Ant task bugs.
  • Fixed ClassCastException due to explicitly used abstract classes with implicitly used interfaces targeted at JRE1.2 (the default in JDK1.4).
  • Fixed -defaultpackage bug for protected classes and class members.
  • Fixed ReTrace bug when retracing without line number tables.
  • Worked around zip package problems with duplicate out entries and rogue manifest files.
  • Added work-around for handling malformed legacy interface class files.
  • Updated documentation and examples.

May 2003
Version 1.6

  • Added support for Ant.
  • Added support for the J2ME Wireless Toolkit.
  • Added support for reading and writing directory hierarchies.
  • Added option for specifying resource jars and directories.
  • Added support for wildcards in class member specifications.
  • Improved handling of the -defaultpackage option.
  • Improved stack trace parsing in ReTrace tool.
  • Fixed processing of libraries containing public as well as non-public extensions of non-public classes.
  • Fixed examples for processing libraries, midlets, and serializable code.
  • Updated documentation and examples.

Jan 2003
Version 1.5

  • Fixed processing of retrofitted library interfaces.
  • Fixed processing of .class constructs in internal classes targeted at JRE1.2 (the default in JDK1.4).
  • Fixed -dump option when -outjar option is not present.
  • Updated documentation and examples.

Nov 2002
Version 1.4

  • Now copying resource files over from the input jars to the output jar.
  • Added option to obfuscate using lower-case class names only.
  • Added better option for obfuscating native methods.
  • Added option not to ignore non-public library classes.
  • Added automatic .class detection for classes compiled with Jikes.
  • Updated documentation and examples.

Sep 2002
Version 1.3

  • Added support for wildcards in class names.
  • Added tool to de-obfuscate stack traces.
  • Added options to print processing information to files.
  • Added option to rename source file attributes.
  • Fixed processing of implicitly used interfaces targeted at JRE1.2 (the default in JDK1.4)
  • Fixed processing of configurations with negated access modifiers.
  • Fixed duplicate class entry bug.
  • Updated documentation and examples.

Aug 2002
Version 1.2

  • Improved speed.
  • Fixed processing of classes targeted at JRE1.2 (the default in JDK1.4) with references to their own subclasses.
  • Fixed processing of static initializers in J2ME MIDP applications.
  • Fixed processing of retrofitted interfaces (again).
  • Added more flexible handling of white space in configuration.
  • Updated documentation.

Jul 2002
Version 1.1

  • Added automatic detection of Class.forName("MyClass"), MyClass.class, and (MyClass)Class.forName(variable).newInstance() constructs. This greatly simplifies configuration.
  • Added options to keep class names and class member names without affecting any shrinking. They are mostly useful for native methods and serializable classes.
  • Fixed processing of retrofitted interfaces.
  • Added handling of missing/invalid manifest file in input jar.
  • Updated documentation and examples.

Jun 2002
Version 1.0

  • First public release, based on class parsing code from Mark Welsh's RetroGuard.

Copyright © 2002-2012 Eric Lafortune.
proguard4.8/docs/drop3.gif0000644000175000017500000000025711163773610014240 0ustar ericericGIF87aزÿ,4luRiKbM¦1a Q)HEKPHBD a @*x;proguard4.8/lib/0000775000175000017500000000000011760503015012327 5ustar ericericproguard4.8/lib/proguardgui.jar0000664000175000017500000041630511760503015015366 0ustar ericericPK@ META-INF/PKPK@META-INF/MANIFEST.MFM1 0F@Í:$8uԡtD#=k^.5NnH4e`w֜_F,ޒ2' Him?RBuBo &?J诃5|PK|PK@(proguard/gui/OptimizationsDialog$3.classQJ1=ikzEJzyT6n#Q@~%NB dΙs&FǘqL4i`YjȰP^Av>R%oIMɍBI[ғjaԛtзC*=qnDpkM}=D!W^EGxމ '~;pā H09 9-#Kr\`U<6y!jrϵjQ ٮF2T 񒶛GqaX\[]gXǛV* Y&ȮAnB ,:QU1o`Ğҿ_H;xEmq$@GDLk!BGFPK}[PK@!proguard/gui/ClassPathPanel.classW xTWof2ydd&3[!@MB$T2d&μi[KUZm yFVm]k[RN.U\9Id&:7{z=z3js.g fp OoeE~Ʌ-e _qAIo!d- ߖq2w8B>3n'x<)aXBF)epQcp ߗqȸυ* I O~,~?>!?3㈌_ȳ_Fvxą<1x[ ]h<ecO2cO3 c2c3xg;ؓ=ӌ=س=.]?Jܝ:ެBpPQ=V͡@,#¼߱'7.O խ_ 3n ݑHNBjE#YehE:@4X7խHIɶ-HPj`N5% 6Wz$L{l3grkPfӪeFP51\c3h̘b|ٝU Խj%r^ (e+`rrnYP &0tq:ZTtjAzCfE$gtR{Rɫ Ia |U);f\n"kV;k:Ze<p} gv)Q&R&R[T>S/ijJqP垲0SH=HN+PMj,E;+(焛 8anHӘA+L0Л(A#1g0\^02ޓ'fzGw w$7xE]p t~{VOwgv@1K@),4A0bJ"^?Ws| ) b)ЋW*l*D Mq3}Z܎u!֎!w'Ѕl }T٭hQi_t !]m_U3Zxu5c9Kw7ӗdhur?a^G4i2Po\d;>ZbabZWkmd,k lXZwPJqRU1p~9V  xWlՇХ Y Ac}4.YpmI#;RR[.?Nǚ#cQb`h3n!Y}ؘJy/Pz3(xDݱmv#2(iu99 5gRMsm~_N,ThʽJ!rPw ].$Qm`kl@|h6@,PYb&*E6jDhnI^; .]֡Ztհ=6[m-6vaCi.Ry"\+%ȵrr\Dz ZX4g/U36x]LE%c˔H-9ҽq ^(k$Vy+~'$zR |J"Z-Pf,JO-Q|)-xJӋ8+Gjħ& -O3IL)YތyGt7襕ZXh PKj PK@-proguard/gui/ClassSpecificationDialog$1.classT[OQNo[ X@rY0*(fiĤNrpmv/??59kE5!nߜ=sfr3)І-h FŘ#$&RT &iF] 5<`r;m=(u^rGd*?4u%"Cw8nQY4q/7]UXR a:r&]gFse-UW4Kieai$ݒrY ^g/ӌum1Vݢ`hIG p+v\o_a '0+K݊gR)EG/fu@kHTХ:5xG:/p_3gu,᱆':cK523/$|ͩ?=aĠ)ݜik*%eIMEpje%_nY§i!,5xv~좉4cY enFۨM#FD'fuF:h4S-Bo/nG9$`x c1YC7z5$A 0AJ8F E\7#ZZH5d!}oL#N}ĕ:t2F74oD;QAIT'X C![G2E^!EPKhOPK@#proguard/gui/ClassPathPanel$1.classTNQN "7-aKb$%9mny&R?|8g)wlbmΜ/Sx@C~1,HGøQ)b2քO;)Ŕ>1(\hVթTNI8Z)ivda0Sb[XԤm{;mn=A%МhCn=CS,`F3f2fdZeQ`f!WCa8 II;!fʋuM)Ot[A>^(lpV >,*H`I2V+x 5)+x 6a6 arйQTr"O\9XFA ިhx ێL-4>2Y4bC,-eiYhNnֱ_ϾbWEv[8kȣ麫( $`VD(bG QƝ1+?B,^ y<ڪ}+;4pw/M]ouh벩9TqS7w2 tQ~\Y3"JvC!ay+.<{K~Y{I?'NHHcRIǿsp)Zj]VC鯛g*PCW֣5(Ҝ$=ŽEG''#F1]!==Qbt PK+YPK@+proguard/gui/ClassSpecificationDialog.classZx[UGWZNd%7I![IS088eVbK${ NKBgm}{,oo+X y_93g9gf̹|i 2!|o^w|?t|녎O%:.[?/ #%["@UIHb 1jTx2(0Lp>"/2ʽD:U =RSQ^Oe*Le=F^Lg 4^u>:Mi_jt):QNy14Y):T@ycN8]Cdli3u:TY:&:qNstjiNt/Btt:R>Q:5{iЋ(-aTy:h=FNt:Vt:^tZd!/R#)D.CQimnu:t ^E,R#OArMbuXݬщ"x;YNS4:Kr3l,=[,#عp d \-t.K5L %5k^xɲŋ$sX2V:{"n~" d+92 /ReMىHPټ6!irrc4>4caH3LFcm #]Dri-ӓJcQY<=_Hu\TG!Pgg|cKG"[ 4vD7 tT+zb(2Z#m^뚞d8i팆VOJDc\Pk2SX*X Gr+BX#׺F,Is „Nr+ ղ ]S+]Pӛo u Z; "7;g@Mv\.NE s21q14ڵec]I>)R;t #)SZ74TB]z"۱3ĭޖxO"$ޕ~oas.IKhSR IWp wa^i`zj*|DUe).kDž[^Vs'0euH70|S2_Qɾ62~i k[ mLM^ []4Rm9:\Xbn OЭ&tl͡Fwt'ŵwhwtw6jнtp")JsAEz >5!yxOhEeє$f|Fٚ5 y8Jsj R~DY}u4zĠG|5Zh"f ܼCTc(;+N2Ko]xΗnY!N+7EMnyfdF]xKH7LϕU67[~'>SOB~5̠*0K>{MϦ{T\Y8Q[Ez{j򐬱$)XY!)'Z-ۚ'ju{yʚh'簶1mHqˣ6FR͜V9:h$s'6k{v*2/>t'infA{ɞTsX>+"I*/[".0ۀrƸ|J{?i2kClУA>$wOK4du\Ԭg))Q˟*/Pg2xo0/nXd&@ojo|ʩ# kVȾ+q7Ȳ879_%m=rwyՑiriH9܏#x+v̜+`y7Gx'U0!0s<̯GrQˢ|x2Jk;#Z3+uyg|_tƗ?g|w8#?4%7÷})tx:{;\J?Ԡ+뇧Sz_ļ~x{QlF.aiz8ӾԢaeiܦ+t%#ًQl*(}kcWڋqTTE޽0SQ{ DSDM~&d žj0r5I-5r-22>H5MZ14,a6|D0sM%֒%T-Ue@0N4g8cr ```x SJRFG>rci~)CdaEf .b%̴5.CʬTf2XrAMsJrԘTs")u=ݬ&gȼ̼XUBz%~4Kec<*?6s Or\$|Q㇞Ҭd2B#͑,:#9% I7ɒI.`3+mi:F 8~:sT:-.Gn9z`q[nUeV `+j񦪮Og*󧲨rOUߐEU7fQ#(ӿ9Cy' Q*Ѧa#Uf'3ᔕZIn"[PMC-!&4 b&6cgoÑ+q_\ɽgA7Cs!Jnɋ65TvAZ:hhbqjA7V#Ak8zh6ЩHgc]tNkq݆S>J4zgk8YM6K_< ]ñ5% U\ ,\隋\GjѸu,sZ-qrwV6z ^7xg<D{qw#p`qxݏoeGx^uRוrÛJ=Q]eWVC); |lNF|(NfNBKph)~6Ny\] Y Θ0?l2[܏u>G[h[l%r+J?\?VpnD Zv\އ+嘊L^ʞ2UGT7Aj38 spN]h^J;w{LY콳18Eh-XDc]µRaq}U6;v?GNJ8~\s4]ix9T݇kgIy&DuUJe~ܐQb-߅t7=ʥS'5x,fqonZhnZ$NA9X翤\M*un,Zvk5qz6SɒbuLqn qF#`XD:,"@ HG^l E\lz2.\g7>q4=ŗJځ܁^.M.y=;މ$ Gq 07A]ѝy@)}r[>vg0o޽U[Q}!YNS˕R32Y= nFC5w}leͥSx Իp齸w+*{Dfݳˍ" 1"Ժ9>Go_W}?W82 ?SͣM lqLE]CD]y'Ga WF@ _r9z{_PKc[&'PK@-proguard/gui/ClassSpecificationDialog$2.classQ]KA=~dTkRQ:XЏ,A/ܙ{s9w.J&O` &e+ 3@=֭'#[Ȟt{"0$%JW#ZeJ~!!Ӓ8;¿❑ᎆ^ ce(TZC~m~lq'\eS̶7q&u$f0aMi`5]W!H ߈}3"Zn@ b2D+T4 wLjz E87(rzz:MH¢:EYj}c^j;ψGL8ʄ[%A}'y_(D O+:nP'}>++f XS#:I7[mBgzʍӏS?1Y c :X&=C2PK;"PK@&proguard/gui/OptimizationsDialog.classX |SWnr{Ӥe.]6mi).,/ir\ inInh{`>p:s`өe:9uS7BM&% ;=wsNЁaN"N"#":݅(b >C ."cp7v[99C;DLèwNELw]p{9c/'!n1݅=N߉XQ{ǝO'D^'_D=> "sT>%"⠈|^!ܢr/8Q"|sǾ$"V+<µ'rrT8"8&฀ Ζ@W' 1=3V U+17uwZۚAQ0LG mXE14=25cjae.6EVgy EQՈG#r2-+fTKEaj-EӮEU4⊩F6(CYZ.p%kpsUe 16Ԕ>`X maZ=F.%e1RQA5___ϰ}$ƕhn0u;ұvC'.o0أǣABHYۖnE|ZL A#*!Uz|Uc8I+Vi 5r30ʨQ*A3'1b\->nʌ p B)a!8-[m$PNۮㆀH.b([a{J>~ 'O% ? MY9+߲EJ~)WxW<% fZa3ya[ߎR Q-a%S(kSTI)y%(A,+A.T"A\"7-z8C]~Qx@_{(sZkbFe^'0jC0+'v2ȹo֣6%hQb|Bi5J;`22d<'tݡDAq_SNh:ֵOڬxX| aNY,u{\ Ǧ;][i5VmW3“wW;S2\3p28\O%b Q#-; HX <--C[sE'\гkp한rM 䣼 >9QwL`1> D :YLf Qz1W^h"V#|ΙYҁH/Ә}i!L5k- iE-1 VK]/ZE6foX%H熓5jhZn^G22Ѯ^ݡ$ϯbC#zN^u似YusyaExhM^ 2Mg[˂5ݓ݋R~1tI#{v 1_ul$#p| 8,>[\}I5qxK!դm$ :k9>og%&(< Mql8Ɓ6o)elpl;-^g. vx9! `ZLF iX])LI_us)s7b\K`f#[RoRE\$dZi[!{R B\5~(,enClo ɡ9܀?7$0tõ$8}o$ITݲ;>_MVMEަPY #9kQՐay#9k ql王rqWCߔ>YL ea}MԿEh'XyXJz- ՌV`5׋6JUt `nME;n-6^Bt?@!8A)%JO6myЏW|`X ylc f~,l= DE^vvp'{ 3}X!5xRÖ%8bYG-m8jB²ެٔކ4]է1:})4/Kb9 8ʓJoHú"H Ρ /@/B諦K&ߤ}LE< `CTw_! h>f8:C$akF`6UWa(⁊1Ǡ!$U\DJAZ%aAjU\BFYvYޖ,+XameVnSoiW [%X/Lr_ ܈:Cdir^FÒÔq.o2rՎgF}}#0ْ Zsz  EECW4cBAQUW5Cp qCMRp[Pº{V}o3k `*{ Aag7}Ģ9y2sHIo*u/(c99$D-׸EPxnX=bv:g<'fH2A!CaXNka<4,vGW!譓aRa]j8&#MMYZq9tNB~!ZqLSPF=R1⩊N K؜!1L6Qg)."Cg=%x=)X:PZX~r!rJFjFK,0R.j6!uK%^ޖ-E͢\g{\oTP<?0!R n+KjB&HA~Uǂg:cA\CVQBGK2uQ2VB^XŚWx-Cez\S ým> 6wxQ0 5%|)AIIV}h f}?9=IϦ/FV\:XL-o؛t 2dIqZM`ݍn0},4ѬW?CQeݽ}בԤ 6ZT3TMSTHItzA~b/Xt}0HicdIdN2eƎdƏyY7m# B0u 2?QB)PjhkXߡ'5\C :jΣBk~!ZCybcDq0XP&kش3VC|u\-:l@83u w'Hfa]p-:[4U)&8?bqȴRCrZiuO EjN9H9lNjPer?Rɼ2MCfHܮFisj{>?\NMXd)X:Cs'sK&9 W%SW P=2OОLvPdϙw"VdQyUlqLOQ] |;[f&Xl:eIQ--n~L,^M?[T_!tgJ,m)b.w.ݪHpB}t]s:Dc&T'Y YgO 0vOlO]VȑIٍVI% sV/<9jIĭ䘎2Z@(1NSPƠPA;9hLqNIrVp@sZr+05\(U6/^A܈06@"Xf~Wkp}V!%1kZhr(|*~h׶ МoC,p^.5 2B < $8&kp"R|†*5 a) kKƋb_w)Ȱ G>M鏹}&KIA/)Wf^WNJKuI:=)͵J\ߴYٔG6Sq̋6nc,”R;ROY\%~S?ȋ=vɋ('vWQ㉭Sä*#L'P(xKVK%+PKq3h" PK@-proguard/gui/ClassSpecificationDialog$3.class]K0[n9?Td⬰ ^*La0>k.ckGMY?%OϯMlHC K&X6P1f`!22aMxDڭ!X8'dK> c\W}C'җjXϐj`(/'xw3[p$\F{S+,\8nfvIKm.ya k`#tG `_c1ڐ}Gm)A Ɇfޝɔ/]mqir,izs#AĜ&hqz^xUׂi]@G_]3HMglb초 QPKi,b_PK@,proguard/gui/MemberSpecificationsPanel.classWwUmteP(P$mSPP-m[Kr[$f7|?~+[-أsx/~QIZLٹ{f3'8Qu2d`=ՑlŰܦvu N!w [%dĨa@=I"q$H@ "5LfYqa읃}O2>ApB#L#1!~OIOixVCc~5Se*f1˵S+V fo22 q!ԿvnH d\eDQ[%E=HihKgRcY+ehK9N ݕ*S{ݍjmMX{;9ݒY];WI5+ ,Mf+뺩_r~r5m0_(<9oYND\:KbdX%[FVj5Nk)iwj ),& _+_L[:5H@p8JR@&(For"U{xgY ,be{Yq)|fOMbgʞԞԫܒ--*Wh R}ٞxydkUzb OQ.@%+')g'a Q+p |\| XBYtq^qg>5! {fEin`svҲj(9<in;^`ލ0Ɣ&} Z_|yL¡T*0r(oP27Sz~Uo!i hRI0q-<_赇|Ө֦O"Fp?{&>oRxs|g>,8Nx גn< p.mWҡNtѱ|B׶Rc]b;{_:F8proguard/gui/ClassSpecificationsPanel$MyListCellRenderer.classUsU6&Ҕ-))~bU)CTMز ?g|GtfqxqAgs2ݙ{9{ٟ㸢b?* `FE?q8xY+xP"*fc$/oÛLņo0Cw8) 8ԻL-2ux)0{Vs ֍/kT3g , DOZ UH-K=ˑKZIz+F&XUҶK,=Zu]4el˥uiŵtKj\ 29 -:ŵ ߗ^{naxLaeb]V2rH{r&Njם ,S@- ϔ '?9 0)GAajv{=@b[QsP$ ݈:nɨ{[V9ě/5;J0M3٬7;Ez*n61&J짿2PKG0~{PK@@proguard/gui/ProGuardGUI$MyViewConfigurationActionListener.classTYSPn(PdZVPQl[h/%L0IW<(udFQaYrι;ͯ? ᭂ"U0TMRj9 6a<6ox='|ĕX XWO!.];Q8D;Y? |»! fZ:5PB`z;g{u2 +!3ԋc@$0Rt7*F.?$)$#"!&1!5#. A<%ub^jCZƺjσ_/[jE>D<ڃnaP~:oPK_-PK@.proguard/gui/MemberSpecificationDialog$3.classQ[KA궥مʴ Sp .`>F?+=Ktf z)p\w@%I3H`2V X7R=*(cXڗbAs$\ّ.WN%CLS=KGғ꘡6;Do #=q5[ w5F?6V Dx> g:M\z 6-Q&|D0!C.7^׾nudu2+ZlV=ئK},S@9-G+X#y$LQ'^EQ"EE'*7PK(adPK@(proguard/gui/OptimizationsDialog$2.classRMo@}'5q -_i*A^)H(RPi Ǯ~p 8sTZġ?fJ\"K;;;~3:V=LVL{9̻bA`mT[iʴ*94jJX?Q2Jzɨ3TCԵ]|3dKb8PJv"žu+Xo#c&xAZ?+浓aҶG\|p5],X²H6 ?cJԚTF,q/PhFrm)m3e4_J!iddt: bBϛ} \pCOk *ALxI(D㈐][z I!;e<:/ˌ$HZX7,P%%tbEb OXh'?CkxTVkEEgO"4r$ў4*`۳O(EW_(p$"@͆z(Z-h'{0c$aD|fu:=>~_BG:c]5CHAE !8KgBwJ}i<4u}UT9fȁxګB"B G ٤RϪDuH#l~-ڣ|o7zf"Oet)V*PxWm>#4n_gbC 0J@Z{߭^qGXH,Fk;JJ:хjr:XKXVg&V%=.3 $Üf{-FŪƧ%$9=Ik&QT/T6mx*4ROIb!`i@t2? ўL ٙTF cMi&"j 5HR|֘@kq Hem?gBOٹE[E|=U$4ė4/i߭=7i&SC5U*ߚzEa3 )¥gQg(%HPe9pJ=qPO0muҷ!IVrQq]N2WA牐Jfe'@8m+_pDq sZssjp $PJ*[\kK]rD^}$H>,'8TMBÖ&t1!4\M *=Mɶia ؅e_lw,d ٱsv7k-ƃ#j3jNŽa> ZQ^;>'^vD%ćm&8@u!'ݶJԹ7KoB(JhsǰL_ ~n AK׳M9+ Z{оJea[b(6(O &|W 7&4 /p)3a<:GŒЁ2焦\0 _= UMo7ɫbF{.!1D\AFx3B [`u*m6btF]uYyCmOJνDN%9): w O:POr$/zsT99c@v\\1T@^~Q/9'@/ɀ~;9Л:`&z4pBn*C]ЬT>{`81ndpA&E <-6_Ao<[ܪ/ ,E>PJ˰zDq_,mk悯8|su ޕ9 ]鉚u+z21( %Kp0 }f X;"W@]y `|e:,'s3=>鰄鱙zӅԥ^n_3nMoa2:u"Rm%@ؾ[P'Vgrэm%n _ *ǫwA]8< {&+!6i L |&H&<7%6p}n.~s߼t3$+Lk>ezk9}`Y7|0Ep~j[P/9ͪ 58G"mho ǴZݕracJ2J@5~d`?s::6m0g+B!ױۦ?u96x0 i i6LKЇv|UC\"]aK+;_0gYЫvTY+ 0nj"eFNI 7w|pl=` To^>}X?]YjBjH:z;`IxbR4fž407Gn:uPU!T{ L[ ONn 4n|2=bH2}bF+<4 45687n~x]m#ح8I t?RZR#9>s1k?eX&c|f?PKuY jBPK@Iproguard/gui/MemberSpecificationsPanel$MyMemberSpecificationWrapper.classQ]KQ=g߈DD>X"V`v]o˕uw$Џf zI;3̹} s0PJLĦBe*#tԓrL> uB ޘ@CBRjvE8&OF'KB|y'{18c X; _zx6,´=BweG%G-PjBuuپ};"2mOnv4Ό'* >Q W)ĞE9:gD}j4H5s_ enj S yj1%h]6{*؂ PK] 8PK@?proguard/gui/MemberSpecificationsPanel$MyListCellRenderer.classV[oUN|MM\bI uR ׍}luk#YQ)JUK%$^>"$`ns*b33gwpY ǐUpRCqN)x-(ވML01W1- :*6wTa3*ΨxOEYv0Y1V`ly&\PpQAQ b*_3kS͜-07/˟%[ #7k[4WmT_)KOz3n:2IuYs++.׼g6  9FC6NVWTVf^rDź,Yd4.>!QQŚK:Q02Vg*T='O(1zۃҳA c p|ofvs349U1kwBoT+FɳK[R,זB!bZnɥ]s#Go[UciKўu_zi6mՙǑv4a=%LZ~tN/}nՔiEHb`ZѢW65"4mT=ň;riJF'ltvy&uUXI-s^,qStǣ8lj#*ҷї-}F8R]KBd{梉P6Tr",nb*dB5L T6%Tm jo}x l [80=?x8Mp4\66-(  ql$ݼ/t/?B?~~aƟ_'C"BI4rG'4B [Yv~C_Fit(Nui|_PK SPK@proguard/gui/ListPanel$2.classuRmKA~6ƜoZQ/)įPƕ^?J:{Hqavggg晹{z~x@ͅeywE8X( UwZ?Ӥ7i*hKM@}2|X_#NID-ߥDvcQ>G)X[r(ye6~9~m'4&[aimĭC?FvӼx oQv;0stث5簜PKȺPK@'proguard/gui/TextAreaOutputStream.classuRRQ=7 ðc" aŊ;q 8fR;?T)XZeGYEazOw>910lBଉNkCF7j<..l 2&`0k`U9V%U>@r/9OY9Ԃ`?5c/*x\6e殗$ߔ[xF7dEy_5 #j+DjUxswG|;G,"̈́nXH!m` z.p7,Ĵ[fp9[X@Z` N)򜓔^_xpwX\9ƒWG9jכ:cU? :<+x/~)cEb/H$?m'K a"Kk&>HwH_ .Z`4(RHN&> ,6&`A5-R?'D!=E,Auq-IG~L2FgaPK2!yKPK@.proguard/gui/MemberSpecificationDialog$1.classTNAnٲ.慛Z˂7.&$mAv(eٝx}~H5| cѧ0Y5ԄM̜;XvЉ1aԄ. 0*Ƒ3 6<3  ^p͵ Tq&VUo]/ڑ= =7>C:\|u*]o(CkaPU{"K",Ԅ/7/y5̢TR/3O j5k%( TiPyj*7"mQf,ўhf94U8mh\cE/\tE=69,Șm.nᶍ;.b dɌQ0JG;U9%|0yiAHD\6}f Hұu$de td }_D43345cZ :./1h6MBb׊B/0J?N4j &`[K&lVk%Ri{t:pĩ?HRLWLcC8fb PKlNjNPK@.proguard/gui/MemberSpecificationsPanel$2.classTNA=Ӗ.]*U@Kl IQbMvvBxD[#C,Qם3瞽U\nHc^Ât,"% Y51e!ϕծzk4E.ZWX)-Hw# D ".d(M!Vqa*񶧐xVn) |usN` !j5YT g:^U4g`3?!}"|] %P6*}dnp'w#[#}_㉒3QƔPfL<;-]}OXxVGUTsC%|?W.Q .v[cH9F2|8fX:%kฌ{bE|32 Ʀ-:aJ C)eIU4_jI\5Zei,zaV(~G+TӘ! Di^/|CG0G|hC{arĜq?4Ils#yPkޠ4nCo _PK1PKX}:proguard/gui/default.proZ]7}_1RE!!.bwTă3I 3`{C$Ilϝ@c#)ZB69 RVp)%L 2?'ッG*?0 /e ʌO_U({^U]P=/YQdl: 5H얛AɸxJ0K9G1BC)b<*{}>_ag x4L,ƗFa޽煖GT%r bQEdLAS2.0 lnJEd?|}vÊ! ||af0æL+~uU%y"Oġ~;[ۮf$;E>BUcYVRvc=rA3)OVQwmpao߶zCR'q^P&&C5@)5ʽ6P 4.č7᛹FB&||S+dB`5Vme yv// !]cl(gx:qa2T& 7/^&*2[!lֻ*\P^_+Y/8ћּoqC@fOrɪ3Hc چQOPsۂmf;yI )KM@FhU2ZVo،3Aj<`" JOPlJMNOO ¿/煔éEkG7JֈղUab&˸볩>"Q؇ ‰tUwM9lj%X}84f)."qTk"dZ]$}WnAj=zG'4pQ`JzOB|^۽*y)oocܻFv\٩&QB(diNtF}m>;Qx񾒇zRp\KHkN/Љ%0mi:>\աb|IѴ5Ωu*z w"tV qǤ=1 eH{ 1Nu&" hx*s̴%hs!d~n-P2n1iJ3$a}}Az'KVl a!cvHKmp{1!'!Qܙ>gjG|-&Ct!EEۻbqiq(4j$FU,0-7A{DpƝ"~LO ]9mxu9ORD9;OD&bSelGŕ^I\pR.Z7=J&?J>MCҩɥJ2IAgn 6=kLLTڹ/\zQ Cd2qdI6%TS87%;3y 0P4E r]M[}w>C;^,jvzr&#zCRy5fnQyvjWR^@D'V)&BtZw9$ld*F_TGbtT06KHH*nGdiV8AmWh֐}CF2JkOed價9ݶxBThM} Jp' !3ݷ+pL'Mbh W yp* k{!] jqg.M }<ubeCcfp[K!qq6-@~)t$>fld52]OWaLG`9+QtTi:L!)B\A7z+vd2r@AR`X2Fdgv34;S0]=S0uN !fqb31eZ7Тte$]P2-Zpgɉ#홶Ν=]6-oq[>̋51uѲ];j:|tʦ]p|K}TQzS*^`ZKȘU s*O֞)8.y"t_ΰ2V%r+e2XĒeAVU IiLT0X>O{^\4!60Ժ'(V6Љb;j;iG.Zu$Kԉmܡ4h29kXibRA&G+[XCL^;&zU^z Ov{4@1E;cU3dN rKXiW3k\p<<7+JWS@|am#vBĕBoMD%4xxi2ʈ/F/Ŀ"|SH+=?Bh9*V/l_rhٽ3?CD1r[)8^HED4Ni 4Qb!H+> l}ڎ6QZC=PKqPK@.proguard/gui/MemberSpecificationsPanel$3.classT[OA K~ RXDAB-$1mevr1EM l`|GϬ&s9gsfηǗFф0Fze_¥0j0 ePU,2b".İ^M¨1 WjMӋ2䊺rES[uf 07LCMVt[ pf7oʴMabC(d9CcڴrQD떰]yGMoۺ涯!BSt ` cLຄ nb!Y"K{e|]P.Cn%eMZqOAS naZm!`F¬$cA]S"S*Z ,iַ3t̴UJ*KCh'CkУ]1)ע#41RI9gEnemj4[2[DȕQ"vj[N.qaLdh$rAJTpo1tx/fSOtv QR;WV-IYK,-'P:ԣ JEKPFhnhgI맵ȱO`T}94$7 xG>K}CR|P/!} @[&Oy3{tIW!0%4Gɧh3 948^b0X[*bpN\zB#PKbPK@-proguard/gui/ClassSpecificationsPanel$1.classSn0n nFXf PЦ&u⿛x4w[ "簩H-Hw|wl;[pۄ;=ԊUVU 3T_f- $M!O7J,_I+E`v?ƪ/)zgo|`k'`({2Hy/kHt wOϔ+NE9M/v.}[2۰q:64ml≁ [6u)Lfj{/EDưӎx{WDnj'̔Lb]>Ӧ ?\IZc|:åLi?5?#y3ܡ7yY٥C#tN$4Y]\?OQaY]%סI /|`N <( Iĭ !n:(h8œ1?B',#\W\<1٥>Rl4B9WPK WrPK@ proguard/gui/ProGuardGUI$2.classuJ1tkm*kWFhmڍ5RV},xPd`$3|I?^aA)c˜IS1c#gc!捆k\ M:PK\D7׃PK@1proguard/gui/splash/SplashPanel$MyRepainter.classRKK@6ѦM~am /ExOۥm$B_^Աcb+&RXj:6 l6gH}?(2#9E캽w nkB}Lk,>%ʕ5Tc sM_G T `e0'H (M`#_յo;BBE % $%ydlPrs?;vLQ-!uj6 l1oxԖ#B/‘dz̐w0N>e6ꊤͻCbJH#DN2qĹTrd)i `bۂ {$30d<[aM!B;a?׏^wtlt 4T<IQ# E!tR м3Q [!t2T)npFCtuFy} EE+j~(-n/PKs>PK@*proguard/gui/splash/TypeWriterString.class}SkOP~κTnS*Rrۼ'E?`Gto~F&lDM =aj>9v~9}} : H⬎cx%O9 .2\bfju5ޙ`x]UL2 ^paa81ë8cW74 7h_Wm~)ƖebZj;C 3Vvܰz6!CB AwB25Q|s|I% )%9厂cXce\{]zܴLvqrr):9vj򴯋}zf^|7O8Ejy9cV)3S;-YN1Tp8{ԷJ' >=pmdzCTu !y(pa^ igs)x}O |,5dr ,p[Ų@yJ ";g]k'*-cOL7WZ|z2dg)y{n_4Nd$شJ?C|KTyPEO2?25?F",TVhg YD*4* )N*:# 5 TjG$M&T lަ'98:JШ2hR%R8hB->ͫ >C|9|/$k/ PKZ6ENPK@(proguard/gui/splash/ShadowedSprite.classTsU.& ]C`liBCJJjkUԱ76Y\38o꫃Q|R|E=wӂ*3|{?&c r} Q$p\¤ <' <:FI3:8ڴ0+s ;K='duA^vqU{Nΐ[quۂȿF>!*u0nÁÖUr7v{]˼gwx[FX,κ7cz`#ad*do(5\_; vۡg{m.vE/T\>MisO x9BcqZҲĮ]GjnadT&'rJn0ƽf)I_ zd~rM.f4J#nR`k& Q@Ld| ]%[n%8K/n(9GwFuFR˲B:^>o: @7wdD- v"PKEpPK@&proguard/gui/splash/ConstantFont.classuJ@IӤx m*Pх8)RP>%"ss `m6zm4wp\ X .J>ty(S`7I61EuZ)UDFe៩UV39UF۟d(haˇawgI%9O*ŋe*`S~/D>`aa@/0 H-z[,=zalh`&>ֿ a#yl^PKGtPK@%proguard/gui/splash/ColorSprite.classR[OA]X.V]dLL6hb>`xpc.jR4֦9oΙ?J#b I,H3Xfވvo$o/xgeC"|: +S[QUW>Ui3u6i;!$b2m%O}E788t]D qMtd#] f5[7tT`( Ci=0Þ}޹rk1({$!sd-y?[(8Rq6 2˕6cR! } 峘#hb|ּ31bfu +HuSZdDC5,4'e@Z7WpEZT);>qOT}PKƍ PK@%proguard/gui/splash/VariableInt.classM˱ 0@[D O#+(v+}7[!Hkb;F8O-awRM!owdQdaM&, ԞG/`(BDYX PKPK@'proguard/gui/splash/SplashPanel$1.classQ[K0=٭knNE}V}V ”al [kGNYAzs|~hcB& YX²k %5sӝ0S&'#L"8b0PP9wPD`te(q_7PGi": aٽS助{gY^q.5q6Lm`X@6Csr"P: C?>(3Z֌ DXaRȖW 9v)A)t=:3rv[Y<*SY"7PK̈́HPK@%proguard/gui/splash/LinearColor.class}RMOQ=3}"JAk3@?b"RhM7&v,v΅F[M,DMd{t{x7cHr"\p5kȫb 9 ۪NbH7͗aq"vn7&۞^hvlcg1w6dը!C=]m ;gVe ZlGV*f͡pqv|SխUۑ{SI R92X8s#Hs 81q!gKq[,q#͐=i#ii}IEUӳ~AY(/4[#z]ap X Y^+YVޚo/JZ9YR`8@J7"Đ ;$dv\Ƈ(? IB~b>CDAg{P?p0Р)1Gi)ACb#d'a]suMQ,--8E#+~VMp?_r8C"\I{2b؋R/PK'CCPK@ proguard/gui/splash/Sprite.class%; @EIOc'-^A3 !&ݛ pQ[Nq LA)L *;r{Wٲ6g¼_m4aQ8oǖv3+r+﯑R2Bq&GCePKƆPK@(proguard/gui/splash/ConstantDouble.classuN@ s ,:/`ܔ0FC;i`ZąCp1|~؃ &zkbBd8LH%7)ՃHslRw\zJɼ,FJl>|pUiQ-y׹_aR<Eҕ\4pTgaS:Go/0%QIڋ+gH9uR}@Q;^cؤNrЍ~PK[ xPK@'proguard/gui/splash/VariableColor.class;o>=NvvvF"Fa /MIJD}5#Wp~iQr[fN*#PXbQfbRN*XVA(?4(E?4S '8CE!#ܜļt}6F&`dad`f`X$PK&vˎPK@%proguard/gui/splash/ImageSprite.classSRP]M6 PRD-TnmQFEgp@}ʹv xG?~OH*qC4Vɩ-{_O5;ivV)7M\V,l~^*!rA!\Ec*P4Ȑ.{ߑV#ǒD\L\&# x}B$xvI\$$7<-cj,Lڛ@O\$bX&K<&wc?PKBڠpPK@0proguard/gui/splash/SplashPanel$MyAnimator.classU[OA,,"xh*-W/ x[Zdi2P_`"C&(.Z&Mz93̹?|Ѝ-8FZUqU%W!I’\JT=UЧ_K .3ۋ D:cy3)f:)b$nCch؋)RG] u4g8_XfRҎ,D] 0A0 n-; T8>\LBmq޽:pXpHU CVpMkŘ㦆[`B$i!྆b8)du#0lnӷx96\0Bl\ͥty wHE/bEs&Ÿiy0DfZ+[3pkY5 *2dZOezO5EKrzzhˉeT4a' lVXNLV,I4~SqF?s@4`)^y]f`%5kF2ؾK[F7̕l b\22T.t%_ ڋ54H_%4Jm:=r4o;7켄W؏5 da6hԼ]0;L7aB/;u3ik:XYϢ+!mq%OknD[e`gqyW"(V / CWA8 Ѭd8ㄖA1 *4tA-ـ=S`ZPHOvȯʺ _2N]if@:41U{]|PK?v&PK@)proguard/gui/splash/RectangleSprite.classTNQ]N; Rp(W-Sh"^@kXi;uZS7 LDML|_> 8kϾۇObX1G~1#6!!4)p89qYD\1/2gK/dp+p"S5+źjźUj_SM]͕$7JSZ =;z*QKW5?t>K35:82?0_cО m(|Siͱ7VquNJ/jk4Tf^[y{ZRbY[ŸPTɊQ#[RIJGB/I'!̡ACqMBEܐEKRHK[Я,S2tŕIۦ]f{B$kwE8C(jC~3._/%.mvѲ'wzC4?B?Zl$8N>.%܀[hL6 *ЀW Ӏ_m@ڏPtd) ڰJUߥ=D)lN:?SETy {miŒ@p7q=%.9G=ѐr 1y"DPK3JQ PK@&proguard/gui/splash/VariableFont.classM10CKi 8#,; $$JP„˲z?J a=X= Q7\[2RG#Z<՝jB2$QN O ӯg(>PKuHԋPK@&proguard/gui/splash/CircleSprite.classRn@=< IKBijAB j*.jg*X7|k$R >Bܱ@"RXsxνs;-P#e +nJX]㖄:6tqA{-|uX[^G%ž> >n%FɄcx3y tƎP}K̠\1â;g}p$CZ8'R^ha$bwKfW \E@IBE&,-htmƼvPJ;yGSwHegM%@qJ%38f=:>nv铥sNOz yz1 P7gTXr3u\XYSd)V{ Ū)Sh*5hm# -2*qu5XiUTU#9.DmBOSVOx:x%Rj PKU[^PK@%proguard/gui/splash/SplashPanel.classX x\Udy}i!MҝLfNT )6mJBRjLu7M Te>Eqߗ!Bw" hE낻s̤d)9w;Ͻr `0~&odJZ5ǏWif=N*T7*xP<dz7)YEoex;nQx'[U VpN~P1U~ɇU|e1~
    O+83!|S+;$t ԤbT”FRq>b9)bɜ =*`XE(_UъXXoh7U4[ ]ujw.< *xP`J#g8ZeNkZw]PZfٴVK;3No<5nݲ٬[F$"rJMBd܌cz1yiȴI P';^O¢𻞝z@J}OV*ϱզezkD3i@e͝el2}Wf/•@EDbSZmG|>3H~+FsL+%U=4\+Vx-M>3%+Ya$vdcs6NT@e1]66OfwGlkvY'i|Z]аְWhI LD'm,ˑ4:9xXh!|+G4 +1Q' FccwHzĸN;)+rk臥'~Q辸;@>硵#qx\/_jxkUi c њ63݅tTSEAj='8F$ƈX8N;gȺiR흭ɟ揇1sL2&/᯼l_~(PSb87ǰc+ZZ4%?Q>L_L=G]zf#h)U? /F&|ڄ&dR M{{ktgX.f{z4i_6uLMW>NgFF%-YWN?b7bgjL=Zwny=P&;XV8Έb6buYYm0Z&z6"M'sRޯ!c~4zR!F%5b8|:0{>*Gک3TǕurE9|,'3vF9j(zg鳅䆲WO~JEvܦ;&58!?NR, # ?׎oKbcDJd%3䞔cg-*]tKytRT E,§R:dE WP4#5me)JKLה%w0i7N} )H\gɖREm.9%u\~)-AeEPGA ɯf"êը$)-G(: 5yLF9:@ӆƆPIE!h}pN9ԕ-!K%g1ji41ӷgVR\M؀MXKqӓØ>4:l:1gy0V[6pyb9,[zKѯ2Mݳ{6us )1h.~o-OOƊD 2F-4[q0 [4~kዃw<cM&!qK<6qI#åyt5W6T6:cU9"a Kl&_I=H\|h#XGqjqTRZiQgęxd^K'g7΢*9y\jxEc -+P1 *ˀw!jlH"X5[et`;a?;/PK섁-PK@&proguard/gui/splash/SmoothTiming.classmONP=adGkB5!&jH4. hKJ#\3~1(\ƅwqf9sf>>԰A4R%7RX>G$D)]x-׳ GA\ȧF R46C"^}3:vز:#bҎj%CLî}Q?n {KA V(X°?gj=Ùd<&}㯌!Dž3C?OXڨi>~t{[RB%QuEU ze(`)KV 5~X%+>^_ ̞ e<ge*Դadm F%ȄdrLQ 8#uo|PKxbPK@*proguard/gui/splash/VariableSizeFont.classRMOQ=3e0( ~@BǕY԰meHiW7,X.`Ϗ"7Pk%=]^:PEՆG X'<m<Â-,Y(ZX0?F<&Y膟a7Vö2evC6Tm"HG6N{-44˻d6j*M3A]tR!n]/v-J B[kLb;pwpJ,Tb́Fy=_l2ް:r PK&(PK@,proguard/gui/splash/OverrideGraphics2D.classWxTU>/d2%7!t&  @ `iB0L&L[못ꪻ+숒At"naw { H>ws-o{v--Nns­nYe㖝[n2Yĭbnp[e*V*UPmƪ9P0aPv8ap #F1f0PP0a<F &3La80`8a*Q M f0aCkZ0a6ce0a> 1,bX̰a)29rn`dXpÉ '1̰Ͱe1t1wOwըjzwX8Iz_$ZpDҔE$\fC1JRlHXG88 iTMp*I8-X4?셗ţ*K J@(Qꖁ*JBV"KܫF}̷p %iz]J-]D v,KsLҕv-OsMf1`+hDu$sCIrW][e3NLݟKECr <;$j?2׻"&76wD=A;@ ׆'ɜ=66OgC3 !IVo bވTdS aox@Vˆ/R+[RքszA'iX`yY46͞k_cdinS:;~w/lhAh21v\Vޏ>_\Yo/ Ӓ; G@_GiE|^5IoGO^]6.fzwPBn. 7!.+uL+E$*&/Pt5HҥQ>P䆚bF3bd8l Ս} [F ;oԍ37N56е7w{bH;Su)`45Mr`fALM?dQLҽd3"-nZmY*Ԍ@Suwnao :݉1 ;ֻ9 U}HBg-P< ;Xkxp^2;q(aV~UF|f]ryVz"&ϼF#ӵ喟r)GU[3~o 7FsK/1U:٤DrAi4}N_}-=?V WJR 1&R5ʹJOԙ|5&?j^tH=06(u(O^Ei>&>4>sDR@/ao*[D\ x$w$R vBŤj\!W'(blRj\-rh V +sS`4F%PV ˵|*/V nFf11]*щ`m_bJ !(w,&^ƻIz4g764)MVUPeUٝ'@íVsI[ IT?>4NےokQEYiJ,'K5mj8MPiGHږd2w"*i$ݑ,e!IqR%eA1iJ- w-qrMVo. m,wb˶~i-u7$NNJIڞcRNƂ]9B%y/X;}#UZ|m18wv4UȮaI.Q*' N KTiK6/+{J:$oJLIz g*\ΓsF.BXf+U1S]w}~JFXvpZU&5X=`BQ;{`y,yy+w@B7>Vç\{~ {/ikݡz|F^XMs9^8 "]/b#+skR2uM1 !/\\+eJߓu 29cBYyd+ XXBRj?u *̫C>6ΊJSC<','?d2 'n'$FJZ$2)}rJ ?7Kxʙ˜^nr8u+:eJi/ʙm[eR^f9(X j.,sKt`P %_,g)ȁzGpz9PKCQ %PK@(proguard/gui/splash/ConstantString.classuN@ƿ b[A xi4zᾴYϥăCgjzf6 `&Zزfhx+id3X')0s\ Md!.T+Tq2Q4|5ݝ3,kj:z`3/U5\㬑qyud[.Ӆp WRka= =_/wu)(7Ȼ#Xt2 ]pH6.ymG0n<PK<8PK@$proguard/gui/splash/FontSprite.classRN@=C Vpq/CA 4m2q>~NՐ;w9g;/O SHb$J38&ҘĔPK@&proguard/gui/splash/LinearDouble.class}QN@=CK+Py)UibF]HPk()eL F~eSи@7Ϝ;@(T"P)`K@>UUeܹΨÇ ,#ųGb(&coɐOvP=S{l{ Z_k _8}Ny폺!e"5?UDo홗m .Z5QATCLue ʫ`H cǖq=j][jbߛ.YF30ABJۤf!Ǒ LRtF ٬sHz>-1e)[Ȯ7 h/pVBx*HpF8I9p` 혦3,h.1SD;X?fADBX Ap GbZOz 3ڞ [ꎢO#F6F'5o ϵWIp0T**i|X>Rh_)^#;RfIPK36vPK@(proguard/gui/splash/VariableString.class;o>=NvvvFԒ̼tFQ /MIJDļt}5#Wp~iQr[fN*#pXbQfbRN*DZA(?4(E?4S '8CU%#l6F&`dad`f`X$PK8HXPK@ proguard/gui/splash/Timing.class;o>=NvvvFԒ̼tF /MFҢT̜TFn^VbY"#TAQ~zibQ~zi~qANbq>LH~Nb^RVjr #00203X @ PKZ|PK@'proguard/gui/splash/ConstantColor.classuJ@M$z[gK=(ol&k)('*vfgfyx}0 :سgEQg BǪP:Fb082LߊgU+kocFz]FǪ\UB&؃lRzZղ; (s~.Y-X'&f$ʠYbE0)b!'CHvڍ`<|#yl5PK4PK@%proguard/gui/splash/ConstantInt.classuJ@Ϥi7fѼ)х┘3Ečg;l`Ů=Zs \AǫZY-Qe$eER͛DVfuIf+8mCc2^zf&8 3V}lpGT/~ Dͨ7PKİ| lPK@$proguard/gui/splash/SineTiming.classmPN@=CZ("*j Ψ񱀸)ã%1h\~ab=3{r_?_԰CFqdeɩ'oX4W~o:԰Ƞ@]`{|y$<1=&hTog~xBxU8j;A]g#TiT zs.$WCo%Hh6PCqnȃž|ҳ ))svLi~ S]idzN.eDhQi0Bz@Aд=NvvvFҤTF /MFҢTLpXbQf"PH/+,A(?4(E?4S '8CU%#H~Nb^RVjr #00203X @ PK,JPK@(proguard/gui/splash/SawToothTiming.classmPN@=Z U[pkh\4FL?3Dbw𑘸97s9;o8QF,[8pPIE&՘E t—s/CRwod"nPd}>SEޗs$""k+OD)l9PuPC4T\lƅ /'_#Î3p*F92 h =A-B^g0I XZkOD1lol%BЧutSСI arcҸR!z`PKR!W/PK:proguard/gui/vtitle.pngUPo- oqwkX{p)^R,; N!G{f=O/'Y&Z;JUY[/|Y-.+P5FANJ\gq4`0}1*jկ&AHB߆-G[7WrM!x6Vc8t+zoSZx+:2hsNnͿ%wYl=6ߥj7fM4I}?1XdnVթ&^P"YQKv&Q0]9(57g  U#gэĘ;r+,2gИbv5;p {,na,cIY4)2@]`N_o1zl>B83JmIJ7IB3 |='x9(3h ϽN9DUP"DLkۊnrm$6_ܘx)L3ZsT˅"N&Q/u"_SLY$H\Nijwt0jycBI2-47< bY/Ƨ\#kiy% ;nC6l A6׋(5" ȇtNCmzM]?u]@'҈"tjNux0jtdWXQ/'0252b&V VLedQ2DP.q td1n [#ȳl|A۲"1S"4 h %C(d`dnjjTJ!yh!'E6=/.Jib[vWH RƐo9t {VEiMڄ=漬h_ 1Ž9T gP(}9sQ=ade:5کŴ>9pR_f7C4 ZEuԓk4j1gVUO\ oEmF~W5Os=q#pZafᓦ(2|/74q5lGӬ{ DBT "zKc-Q0jlek- %w䌪Tn.eDԸi +YvLbF dB"[;/*'@S2ҜRƮ#hJ?!zΤG>Yx*3e$ S1*4+Wg}v1]>Xc6Ewʜ~WqbHe5 CND1D"_8-Ee bmijF{LyLY{L~Rh  LjۣP/fM=xx#LzDvYer4#`(9kGFo>gT'[DK&"&/e;*_u$Z%TrRrۇ/kgd# !^CA<,E+6 N×0f`Ҹirޙ.ˋ%Z7ߘ_ fSl@ @CN:oʶqÖ!3XVYMUxvv11HS; IV̬x7od2gԹ\=_q5u1.r7K=9uL"*n7} Ǻ:e{HFfZrX?O}oq9bjK#ϋ<}SlΨ0 j'OaAy3 h\ٮ.r#uЧvhfp'"ׁ"KSeѩD*)R&H܈Dv/4E6([TZ ToˁuX_O)^ -GI8ՏKoS;s9HEF?vQ_pLL0Ĩ$0Gg~m~Ak%] 㮎fZ]GQTnWQvt\ݻf@v:蟃nT\ۅ$;d̫>f}Pр `w뱥lQD:Mgnjx$!rlBɮc1@R{MZdq,~d`N$( I -|U!T{^=H20nJuL.2=*{[8蠎KgK; Kja,D -H mI*՛;TB%{}SIؽF j(%hd;j֭XGx0cך_H|q4QM桄vX.3KcSB}gCkt7\I$c#)$ʙy(;<3U ԡe7C14q -*tۙx.~`Q%Y _b'ޖPz_ƋټW]p !ס6x𧦂=!u*O/C}jF0ofr>s5Miչf<??w]q/%~7익Ѱ]` 2$HS2>SbZY+qB6+i pZ5H. R{]qPM#tɛY;èHr!ەzGX y1Zwcg%3 yW'HbO ɹ W҅])+vޭ9vg*蝛=c|~X<%5Ăc ~vlrm*1ꖞjWkƣ:J{'c\Qâmwggq~XY+~#<# E+FdEeUJf6oB/&gJ,3=J _se5܎[(4VۆǑ+2lFS~NԼ/;O nmP8&4I$~,y *Mhĝ^f*Č l9z~:]+0:GNMD{G,.%vz6^ ZS[z¥7,պs[;qHDs&J:;-$kD3 И/ȏ{M*Kk2G;Ʋs"m5w0mPPfV.9&vl[eBbjp^ǭeY1A(9QE1p|n6;Z2=WDUEx,ZuLʞ -m&q]SHUi/w&,a|YjJ&fX{+*!ʋmn_Dm1RX/%bɿX/%bɿX/%ŒbVŕq_\Wŕq_\Wŕq_/%Cq[PZr>fvۦn r}M+FKBy;HTzٱ;QW KQg|ȓG({E~sx&zl(K@6:uźb9kS ʴz,Ltz߃O!H֚t͒KXEuڴ5>-tL8ut= ǟ=UCl-3u=J07zD?0ms 4;).&&!³N)3E?9jֺ^qdti#W3 mb0iu|%q=B07dP*8s)KhZHBQe7Á ".H`2EG( cЌЌŻ-DlQZhpUpT~unqю(ˑ,eqp**Z (ku`$1ZOf2pݱ:( ̧1y;"\p|*] B( ަ_%& [- X7DRpuc㶾i; 5w\qFAaB?e[F6V.p<)pZKuN#e?z9/<3m:`rUU"z3/K&RofyQm/%SVcƢGϚY]wPo8Ur0QM?ɿR[6ҙO9Fvݩ{CuIx*_|خTCcEc. #@ mA.x=:\24|4_!֗F.MtA]PP5V {[kn쩞uJlmki!ӫy!2?sid6om7kiEK"S4YKF9d>=%BD#$2B"OG/Z[wpt?(Zͤ6v%ZQuʊ);oƁ΃Ԕ uTv5eAk# ڰ{#eS"O 8ؿ!+wI$tS'R@gͰagk̯( r6?E6ɚ$褑sЊ&K=PV#<tbrow\9E{p?-4KD (ϫ,L"T k-VHw spIoMmCߪQ]Ja  #Qn!جvfC|JaЃu[s.CI(IzE& .AT|qXO/ &ֿ Um97 w׿~yh=^fV ]1lL+oLEkBr:"!M!-FBK澎i֦IP0aƜ=ɿ̖=p=Gk)"P^+n< =ûT[g\ӅXҞx׼ QOm'Kgϯ=k68 ޚ'""[h7z^PΌ]&ӖN7MT ezG㊶Aja܏ʸu9įC#U q?S&d_BιE1BtZ;=lƊRzZ|,@6~w:nʠJrjFxP"?Vl<C|pG8J?gK2jw3|-sNO&;^F mx$/I'鲶i',6sfN2RVMVMiMB cD `4Ss- rm<R`A̪x'ۄaJz]Eݖi_K ,5k5]:˹}+ ¡. d}SR4<$+._)9'!ZF|+;Ϻz-i}fj7860Yѳ>$^EMI5)kd|T}jCCy«?Kj "s8hT3~ںэ,uDEMP̠*}65N}}@E_mdS+}۝X p=EGnNPF(0yARc`Y(C N*ח/#/aDآSHyΧ/ҩa.8pdRY r3N" @l-餞y$a4wf _6gsZWGQzZا{ܳ3s2lĊ\ƚDV`<F {\F r}FܽiS5N'a_I`\NF( @$d!{YΛ~޺6@5oQ%AĎ_#[h$*^ }(X)m,~+ Dy5l(Q}2d "()G[Eȇ1҈CZXd3 h8""t6 B5eIQ?qVW [V{wvh }u8 0!K(;4yxm0ZÝ7O&l@/yO` -) >Va⤠SQ ~$N؜)kymN\CֶӘ:𗢥Mv< ց(I-x3 #7^WggQ|c'ii+A݈֏{Q/th""^ {.纾,L*dRU Mn98spq*[d`nνP;Z񻞵{!]u/"֍r5-@_٭ ~d)os}h#e \K }û:ql\chZ{gW,A ?9f#8LTsF}|[^&5w{sBcv8.OwV'}nDraDpQA_(d<_1ڝE5<povßi(y YF9|:U@&84Ci>Yg0`s2eG5|a5_(Ku^s C#yEG.V|׵!Eф=E[ }KX/PbSA,hS$nCɂJb;mh%.OUƠp>6l|BiXp$ٸEZM&r/=_΃ο9R27f¶\<0cт?5%f_ /Wr#w0 >%[֤YO>=EidvyQBO}}ow݈uGL42KlpiID+MJ6R.mM$Yev6l.< CZv25M3ŖO1/pD6B.jDIoXX] }h0d0bCzHzs{_ZcsYe䟓=20ͧznдɟ^ve^v}[Y霗 f2=F[6 Mg60,M7~ϚJרD3@fI%YR%+tNi}؏R/]~}M(vp۲ҾtMֳ'ZfUt^E5Wl,Z41ٔuDs^ꌲFw&?暬OB8v[]:6'-)OdqJL1ߥȋB:w*l6ƨA?|~$k=lN%hcaO+`vEV9b`m+,O5ŝs߾H>9^a^HeIeaC9., w~֐ڧ8TƭtQٮp<:}!E'm"E.ˆt  E/R /[4`v"k̯5l7Ij-LGk[9vSb/DgE-"V{<*Κcb̭A, dM@ HGPaO~ s!91ViJxe41Nݢ8ROz]Gw3-uNBb4 k~=m% if8>؎Xre ՜b~Өsx%?YG\Y;Bgw÷ )k۫|T?s$bp@+(SSD*"f 8 O%s5uIa$V2cAH-搀ÿ UW40@5ei*_x<䓹BP S)Չqrp ;Dfu8O2@d57wRtlck'ئ٢>x/NGvi6vT.GEQoW): }J#7kф˹`*)9kD(@RTf`Êl_k5"٫0fi (Qs ]qb!c˾"=-8obRk1|Mbg8v=?RDmz[E+x:@A7e8pM6ƍ +V!/[Ή99-:"6s?0*@|rEZ8$cxro^3$Gt,t0[ky]5gq]zXEOO&˛샀.h͔D+&}<'L?OISy?D+8.hc dMp܍ |'Rn-Q:&J0\OqnMH Żi&zk]zwEO,X$ gDiøf1`M/ev  |K PuTx"[i~V ]ICLD8͙X{ ,Eqp'.nY(?c\w9??QLGb&ڤi.>ie{ؔ10%pk *0-VK3D*L&Df6B<-( ڬXi}(O]ZY$eml~ckCo)Tb< dU|:AXpPPz]3f$|ƢN;ܪc-bMa䞈O-ķRCA2u3>Ah70v6+^=?`g> bhzT^&j$o\sbx6Dڜ5ƏEѝ/ })fOKW% q5>GfKf[:8fbz׀`ʶ7錹_̟9}8}.FFб;zx2(05M͡y Z̤T6\I9ߥk޹'I 7mֽPDBY6jm\'))*֋q24 d`yr"W}cMYVIXJzC!J7+%$y(igzpyGz,h  0QoUfl$Alf-[L_9'0iŇr}C܅Ui] Ӳ\3_5eR mݛވ$m0PdA 1K&mR̀eQi]O .`m1mo = C羄c@j8x[L SNjC4J7JmV=]a1$_! PB/MVx^"q*lAK8z<;VAD8q֎[c5Y1./4Pz8sИoud 6OBEoA+Կ\΍L"^G>YUxMJ4JF@ hT Si\ԦR rl$_TtD PhptV5~qENُc 8|if<+h[ ËlaaDf#3p :c -ZnGXe& MQ[RcI3)' w0 -ArfBV >^wB3 &#JSR mp}P3!0H7]PjGZ2 wߜSRB*0ڤh?rtM*s~2rõ/IqIT Ydj95Uia2xa-?Eb[}D N.U  $.l?LG=Gs_ilMjv|F|#|-5qӶ9u7gC `3hWg8BOuZ}jG+=~xͰP7:a(>Ǿ W$q*;}ߞނ{@jXq@&aUlQZ(4Wl]"ӊHE KdH6G6[ 2ŜX:BBڈdoP^Jy4˞$K4ɲ!nLV=[\;fRz.K)CU'i"2Bf eld2 xZ8MS|I#jpl }vdgG'aBl$dn \͗.9; t}3 v:7Щ/Xb?Mnxseax0am+qn9t 2hPꖺtOnWsn mvy"+ KƇ0\K}.15N)n<826u1EQ96rT{6Y#xEz%\6Zi^ig [u`$Q=$d1̊p *TPY-2XMSn&lR/䔥F %3k^N(ac)In2eRIUt6Y5"k1 Ȉ[|qQy.Y%@f?؄urnc=_JHJ ,RU<@-]թOewMo [S[*}–K7%%ph+H+Շw0&=41=Met5K(ͬh^6 (AL8S8~ɛL7Bz񵀂nuC1K]rasPz[FhgKNZYJ$PKͼA[PK@=proguard/gui/ProGuardGUI$MyLoadStackTraceActionListener.classTRPN Tnb^(d"NfZc(9Lo>'L3sKfAǘ^h5&X괆')""bZ l/=ː*0݊QmƮ+6fsok!V:sm\gJW7@5V\hFg δ,yY W;GYBMmE2@Ew>rD:!2ykuQ-۾mZ KAy<89N aҐѱpᤂīUD0߹ypѽiћH""'];G$wfB0uzJ޻҄nYR&b#0 qzARJqe)eYeJ k&ca`%?I\#%\0ZNgPKx8PK@proguard/gui/ListPanel$4.class}Sn@=1&mS(^iSp*E JRP_t+F:<H%H<(Ĭ 3gΜ|<- E1Eᒅ˘ւE,Yl-X1f"PPG2l ̵Q/bmDy!w:"%WRwP0#&[2GiChU2 (>>Nxw\Pܭ,dGՎҸK(*i6JXq61QQÆ:hpinr)Wn @n!ہ$Le/칏;UcjLΎªl d ?su-зw|k-y na{`v'=3JV3u۟RLL Ĕ.$uX&f^Ύ5][qT&bFǬG31X2T^k^ϩTװj{W|Ky2ؾ= ьЍv!CW(U| .a7dmK^.-"Id7%=):R)bCSctCZcOa!C#oHj13/ N Oes'`jU@&ԃ,"PKG#ÉPK@proguard/gui/ProGuardGUI.class}|Խe.R % ŀGr$ MEPĂ]`{% {{.yʼy󦾙=|#Ж/d&1d2&S=seLEtcn.>KI&/w$٘Tx9&~S .@ ݤ//G|EX0K]Hd)L5k]LL!LLd&a?'l&O?9Lwdɋ.\yW0y״)`֭c{])ɛ:ɝ]}Mn?ru?š_.U&.?G7 ?/n0_Q~D?[<wnM.7D6s,.U.o[Gt!|.]H+qKhpnQruϱOE $]ЦoJw"FdD̟FJK£ &|d"7MďI/o.B7~.M5] X`] P榙|& `XPE(E b#t1(m4&c0}.b.H(d.&b N.q.t1Ut1]3t1Stq.uq.l]TRst1Wb.t1_ tPtq.uXKtq..EOq$2]VA],E.V"tRhE.ºh0E3&-UtZktVtq.qXuAuqKIجaaO-zar &in"`}rKs0XřnNlD]7]/`-FȊ\|7݄ tq!,"Xk6]\Ktq.`-t+]W9bK\qpUպF:]A7Mf7 [tq[&nGXNKEz]߭uѩ{tq/~x@<#!Lv ¼{tx%w]0y"Ob04g\Yϡ.>$^DK.r}TɫHy-/^eDɛۘ:#=C}{JK|⦯On%>w7%rw0K|o];7P|\G7DI*~\66WDaش߱?t:RWa$PL&MSj.BDwӿ]2MM$LL0A;d&L0$ďI/Lzcä?& ˁ`L`2a5 6BLs%n9Rh1}`}yr8HiWY ]rЫr")$,`8Br*`n 3`Ht\rde@L1 P ʃa1WJr1%_ r\䒇%B p.<%k2Sm3̞߅V/VhRKg̘lySo՜U&(^6wy3re3l'ϨoӦΙ7}֭}f K2$;*wep+6Ґٲ:a5KŞ&,h H!F."\%.1!\,oÂRVW ¡Uq)l24OQvٹj rjs*.'lyk mkO5"Є޳P oT:=jq9 n=ܽ>Uz q@kKpAc֠efnj! 25iS,AJ5;9 a.dq aYagsjYy,Ӳֈˬ`U q61o^% A.gB#6 x=L_C9<Üqrf$=ҕnXN:, ,cFcPcuVW^1\Dg 5U h]Vm]z 9jl==2+< nDIa U`qs{5)zKPlz{s!2lۧ/| J=mRC69tS7{ gp8YeeZً'W6)'M(n턁gcyFuYpk + ` tQf3X8I{X#5dYq61L _H Pcg *a-FJ8}HH׳% ȡ5!Ƅŋc/Ki%S bގNyp J}yAEhRgSW/3`n=ke}5лXB֖Ũ9:wYm0YYmjӢZ<&ijsxuK0J,+HՖ$o*c_JGԟJ[^`i.67k˨CqKfspo,`]ʂ * -5&b^J5C "@8kͲA]gD l v3x^q9vkyaېKvlQ%jXL3㱋݉`w)=f2N& ֆ^c%D$u/ٵv!ϟ`Q /FnvbeNշ)B/ݣ%]ΐ`nzaF@b{ra{P5+y fޔFحQ]k0أH Q) y y<G&=v`O*Ty rR`O͍A]gYJ) "'\dLzkiU304Ko/萓 2b&c&ob&oc&b&c&b&c &b&c{%!gfShfLNĊO ^t0)r!O'Ao;:2rVsvjN=359AtYtmSpYZ-7d֛މFLn7-;m@ j0!oX=VyS9ˮKa;]) .; Kv$Z7 M=!w˻aX 7@I"jk.zXr<nq!Q>Pո]ea\s%.Vgz=E @MJA5ɨRS씮9!nJE v:˛{[,D0=@P4orɭdaRgeirÁY-b!ҏo2K`ʹp30ȭBRoGj4aHzER89nb %9Պ,' OBa[ͧ,IT*/]1C>.q LDč)x}t}=>c櫙&SRFk^?mú19pUtݫwgy.FMoo~UN,<4EC>/_0xϴ4!:nj={=,o{/,{x2OH<FQ ;i+4Ӷ+B}i4EBpmnVϙH5%_6+UC&_ǵ%G45ֹ|Seȷ;|W!G7 u_N@˰5{m[Ʃa D F$6џWjKN>(ihYZhCi^Ci(9-4(ɳ 'w BC5c0LDQe<ՁyZ_Bz,ވI&͘D0Y5Xp=3߀ nº#z ar:&gb/RDC 4(rҮ:LG moovL ui SrBl?/E ,Ѣq8k@B=+4iepQ}[X{p+XS}d 8iHm^\1c~YIy̑e3gTQ1Іl(kEZ@h#apbk3Qp&Fkc\XC}y~8J m6&_ m2[ݨMmgMЦitCs m&f ځy}P+Vh(bccSjwi+cSGusI)PE+Z Š՚~ $M"zҥ1)!P>j`|_0;30^]VD@mu͡աȊ%CM5\eW.Y  4{ n5 [" ނ$F^0U{d\LȌI]уTfv2&?xPF; ftГI9b*PAR;reoXWYu)SLcj:LM\B]؋鈎N^o0y-uor[jILWc)[}YmŮadCp>%E̟` ]xIvCFwTg-u4hŜѭҞ$2?E/, "J;mOlpA 7V)ɛ.mlU} _. 0T]˳!& ThrX}A|Q_üj ֖7DF o1w!IawQsɬsUEw,vK}p1VSp2) fofuټl_3ZBSlB~F|+CޜNXT(J0ža*|dn;_^b7%3+M!%PoI-HdB}I'ȳq(~U.H dӕJIa.DM`kz:d3!E\NmjM@+7)o|II'fҳp2}\_rhʇ'+^BOي0d-ǵG391̜Y:ݺzCZ]!Ӡ$aS7Ӧ%LhF#ѭzs03kc׫tsQy%m8A=>?~'ַ XjOͯ/S@ g]?4hC΢l\n̮rr񃐹-2c+Q+ZWJ"=DZ ?t~'mU y&|k癑RLW: sFvajQ_h(?AT z{eHʟE8l(p!uAԌs":h1u>+Hmyu)jum]k`cjym%&u#LJhW4/.Nձ[.9\4E9Jcb`E>ԢzTk1дEZ)gIVe )O?hlYK5=w)Ľ8fElmaHTSڥXj4o,hjNˊ` ~{cKނ$W;fk~j"b4)aSdyip#zM~ KnbF"VbOʻ~稤 gP`Yc~]Z134gns aFV@7#R"*Ik%,%ql=x8N6V7?ɦomx'ဟb ?yma5j U<~_ E nc+x T/- %JW[kص ^gzoɂ7[vYvvwZ,ӂml`wYp`ς[ >h,c >aOZ) >mg,|/Z% ^QU f-ߴ[|ۂX] g-?G؂XS ~f-d_)e7[0vg?@#!^%>- $ړAۈێTi#^  :H^%~%ޫ#}[鷋wm$D&>(6!Q|*xIN2Z4h25UM|(F &>1O2Q|L|jfӣ gQ(^aQ|ύ⇘(^e_QG%&~X?#=KEMtemƔM|y3Q<=Zҕ~($}U :-j|F~!S'_;o՞y~WQD~-P3=In'3y;S2;)y렬B*;V7:4˟ue;YLx4Kݐt^jxiI3;hVi?ۤd9,R/;煊 MM> 9S"whI)#J(=,w/F{EhoyAѾbo^P` H@(e {P'+,˅&):@2o:᥃Nk 50,`^:j@.{i!K,8:qk{{Yɾ^Zs{iIL+bEL(^:. 6K6 ^:.!IOv St]?AK:=Kqfx,/gD/(t^Zj8)QK'6{D/ ⥓%N)*/=.p9xT^:!KN ćUoopsl I2o5 fmg',sاXvZ^H;^:A(Ҋh?K+Ήҹv&+jRli?3?/x^ZBAK,F/]  F!^c%L/]dM|ķz>񳼴biNv$nՠB /= A/=!=l~/]YqISpfeN q'p.ZbAF`.4` 6ɳ`s[ɂG[TcFJ @x*;??aXP-IU?k2N^117Xtbch1 tbQ; E^ٚ<ㅇlxK]J;=_y-xi+2U6"q|''Iģd~X%u; O-SaRKLH/=QQ`QX i3-[ϊyl9?*ypD;t @ƟN/\EDmňb /](vbCvF.zya;KlWӫ5Y49KæZA!RT"_oe|1]gmmgglljꇭX3{6KoBT1?Koɍ[r_ov?ޱ)*W HLL#roYL:Dȡd&%rMtoin~6ߤt6]ut}z|zݐ~8ݘ@OH?nJ~ݜ=%5zjgCӍ>{2c铙ӧ2ϧd^Ge>F|}%7zՃ5UD?ȚH?̚M?:~@?ZO?J?˺~u"Ae֋Y?o96;~=~===@ϾϾ]L~_fYzed2s(a9'g`y9X?g1땳YsbrnasМ=lx+0V#+6“FzўlgLfzf<~ZVg<6ѳM&{.fxee[TϽlgy|=?UxXzDzCelw{W޵lw+[ƖxgyRHl#Vzf}.V(_[ۏfFƚ|!ka- ,Z}*-la|| oFXq)vzgl'na _R+P JF$!tҝ.A;fw]p]Q' wN;=mobĆ"rnz%,D1M`dAܕKAِ{I_ؒjR !GFet)\vˮ$5dLf7Jv 9AdwGvFN.hoV#/ƻ>z%8+W1Er7}x5sc} ~vǡ!$~aR aܷHVqߢc6qx yoM4.d^2YL4 lˁLLgΛNKhKM/F^>f'}pLr\dFfӧe 3Y~#7C xY$g9SN+@e0u/vRmJǟAz.UJ?+TSH?~qkDQE}uj% Je L ZG+:c()#5)$k,tvHc 7Mn"s3E /^>MBC"+z-w]㏊e?bDo1X CTHab(vQ(EYQ,%k1B)FJ-sX9PcD_Lɰ}@en_ aABxmg%mKTk+- 'zmh!F1F HV.Wig#j'7䉯 )?} ~yU+Xu; Kof&fSJ"ƦF&Bʪ;JN%lڢ=~ l"V-j q ͈7a2ɂ}!!Ė.4' A e&%2L^rAH?}H3ȭDZM,zt8f>@,)d{b0rLaY EsMeE'sՆ=ExIfWX'-`N"rXesv|2%R[a /"} O&JT^VHLA? z6jLFtdMJ$G r),"R  0$H YC6)y߷"vڑE j !jӡ!dӡuuk9Z!W\-?TaTBBM-y@k{DY la5hPնZ ݣY+/#ir;ɑ\WWC\U4܀/GVG;`K+aBsR퀑+Y`ю2\̀sa2025;HŵgPɜ&cI !䐘oSFHn2@M{py?+Q()8M>N*'<4y~jLXѯyhDpl=YtbX][Otm"fն޼J1=$5 +ݢ]@O[%B9,.į:Y]a|P/6ڕPP?Ϸxd.x'ןDXE^UQEv4>@fՅ~kA;5Z+e:4 efsܥ!&/I3Jt>!,9%FP5t> ڟX\@Aܩ V~Vh0FH)K%/.QKJm>KXR&ڦ|LD*} 웴,uqI 3iX]vd?V\L9,VF\p\p#cx,7U c- JӂPKCx?PK@#proguard/gui/ClassPathPanel$2.classTmoE~6~zI7n6mJ q@i)upP.ƾp w!@~ *$ # ̞4FX̳3][<܂8$'4HHE$ьA!d2?ҌGp^FbXl\ڈq!"#e Jx!uwXnɶJU.JU=5jh3)0CK~t tQ7u aTb!8j9C{N7D2im9ˮ"C[Ԗ27Tw&筪]Wuppi"VA)1 YxJBNuL0(>nDILIxZ o :fi<`7<(Bٲ>َYIx^ xQKeP (((X@IAE@E K^%p;9kK04_@,;.H*;(ADOk)gE5c!Zn/f͢^\E]mWV5>w7ڧ1W SN Yw&R˝e(6$Q;yZuz_ N@4 N[2˻6'vCdhs{E 4"^v/3XFխ_v~Gju{".ËUvmT6(*ZE攭%n +vZ%o5ML+6$6NjG,s ٜ2GY%[l.h̷zXܰ3 #1}QN8į=i'i-,r`}BӏIa$Do͟D?#}wtosX(\gjd,ApIX!=w&7CxakMCT CkޞՒ5.!bQxm{KEᒓO"0= ,c:7UXBNEY:* Sov箐es#yidt, ԱՓmNSg1.j}ef/|1ۿ!Ocs {GKبIҧCAFÕ<+٦54NɎv:k7XtynOBI+B %^5S폣ER\"Fq|~T~go^Cp dFaa}|zckȒ}G%|*>]9Qv||?PKА _PK@proguard/gui/SwingUtil.classeRn@=Yp I۔@ P Ո !(RE T޺[:ZC/s(<|b6D1R0;9Ymlhձmeڎʾ`lP}%a6RZ+^*JN T E: ?Z;3'r`Us;w#a!AVXQNwGN/uְαӘah -L$aZp"0WNeL=Mb`e2QdxP:&yz-`_ۭ8cBsFp(`jCׂzW /~odQJOgO9Q)&61v~l1Eoˍa?5Ӓ犦7D֊d'*b!FSE*,y1 )`El۲U\30/1 aA"*1bIcY0M$W58Ix.Wa£vVm2HeL%Ou ֩%.dPj}12~}y mBe.wOjXB,J^xO ~]15}>D4\ca=CVRy q7|$9vЀBLN]4PS{4} z:9v{X8s|O얉E<?9C_"K;tz4zKﷅ 2MZ PK//BPK@proguard/gui/ListPanel$1.classQ]K0=WZ9uL"2p곢P ߻-t56??J)2_&{9ϯlȢR@&lj`*CNDe9wan8X؎ԕ+P=J5J  P _ L7r#$oeǼ;rLJ 3v' |¥Jz%yS pτ)N:ykQfk1KîFʚɖ}4?CUgQK=$V*6Cd%GS,@ms&ݶdo`GSGtQ7(j|+ҿh3 ʉjI>-7PK(@7a7PK@proguard/gui/ListPanel.classWixTg~of;\ B&4&3CR(IK8 Bնu[[W\K[dBL֍ںѪjiwL2q~o;{;Va;i(±RlC\EBC18.dX 8q1]xu"B%BnUq*.xZ!Wq:%8PA>$kp#*>Q8 O Ri q qnh*h}"s*>/a)(/—qZL_u!g~!ߐo or,Y ;sFR1⼂ҰOtECFXΣma32ж8L ¬*op'џ0D"Ql0#fbe/a:ӌ;XOPXvc0zܞŝޡj6W[Yj;C#=l_l ^w"F-EXm izѰzOhĈ$,NmH؜q[N2a~ш5l 򆂚ɪ:t`f嘈S_L|k'^g 'f$nBoqq#*f,Ȋ1Ub 9>j'aD$Sr9`ˌX 6P\ -ӷh2o`Jƕe*:vaށvio@.?-х4ߒNmH4IG1μzA$bAq;u|O}! hyZ] FpJ7-U=p07k?cD98P2 [< 8Jyuz}).?QGQ!drqT9cE qQQ@P0ߟBÐt3*Hۨh~.uKIc V`#Vo]MZ;9ѝ5q;WEl8c7FM)\U.<7=^~moN 9łQ[ j5Nwzg@P}QF!IIԻx7Qwӻclu:8ZK&uNaܻ{qp?w*Ӹ:9K2L_~>\x2a ΑkeP">o ˜1,tnt4j|^w +"tH9s٬Z (c88z1=_|_'i_%)V;C))^fr?E sa•ñ8* νZ&.h]M ~7%'B 7: "Z% |^Dϡ.c^{xo;9XwޱYjZݔxtؼD26c.5|"6,Ғ:&7*LnXohMaeӫmcoJj8 *RF^FG+m'IpӃTqaR?6]U3 .5jjVC$~RoLk7 mtߗ3q?Ut̕7lٞNSY78)hTФ,"-~t;=6&{*H<$Ŗ;<c׮kK} [|mQC&hLR4zs/MCF8yNCڠbr%tR"qRZؿ8=c=PKo%}PK@#proguard/gui/ProGuardRunnable.classUKsU:=I'MC$@Q HF$Hͺi/EPcg`f|Hx])wB&p!yI?:"= 㨁1pQhӐ4 Ґ6p e\ѐ1E΀ >hٱ TY6F}ocd|`knocd2!\jNمDR3eb`I XJY1˸DZСẁPޢxjTdmgy@Hrp.eKc 541ni-v(tKtش6P^w\y›pDRw mCd8 e]A+3s5BIuLA]O!Tf2ݨӾy-nsX-602̾V98X cɐaW&2K c̴){3̌.νd/gmD+sǟ :,]4m,ICnP fiR$-L"@STDpU+--|r2D{;+1~!%ںh h BwW F%D@ :]G7&>1UDU\EVQ}5{G`Ұ5k_G-;N5CMU+ܰ]JTQzw hM25Uױc?= fnp3=k,V4U"}'S@>I,40F mgс8YQ;\ "fp s7g\c9m_v)| _#oTܧ!;of pb?ee%~-WQA$XzW)eVmZNjO|8eNPK[( PK@ proguard/gui/FilterBuilder.class}T_h[e&rfiSwV;]&ktfuMsem6&FPpX!C1hCVm8Ţ >&vm%?|_&Qc<.c/(k, !"H(b 'HE[P#「' ZzJOf"aKSlF6??Ԣ5cڦS "H|9Dhoj;M P?['JY)s,X)!m.J̕zmdr6f pW-Ɗڛn\ w/^x osK43}.{GA4߄gUGq1}܊[vaw`- ~3 T`$(G!/A4>e,_>`?$55RVv$ϓBR~.CRgR6%hIP8By iGs.]@(*h[FfuI=Ƕ ,!OgDx.| UcƪՑ$AI!+n#jhB3J)C[ PX\@ X7%!  E 3!2O~N垯W,!fS?*^CkeAQa]~rC[mWs}\ ^Y>6v=¯. : BI4aE^t o7+80Әi=~ w|OeچyڋOh.R>(Y\'_4ny,eܡn}Z3VW@02QFPK&PK@proguard/gui/FilterDialog.classX xfwgv2 @nB5ڐ$$4-Nvd`3v',hJU>hM j[b"U>ll͒n{{ϹwOXdpf,KnVN>nN>*MqNc>.{8W'$L^0>NN>-3">g9/"  |Q|Iėp '_5>!8$xLaG$\.a91$`XBpLqHxOx|S·?-℈oxFwr=N9 I ~(G jkjC[X#Ō5:QCAMKKk%u 5CC fuZU63=$Z]:a9&%%jlnңo׶ 0̴^HҬ5f5ސmOj;If +F 庡W30jV=9*ܵ- 4M(I| ʹ'd(Vz2'Lkg(6a걵dIv8NmS5[JXNW@9Ѡ]%x9)oH0F+80}蚸r; UN~8Rc@H֢%ηIlOS k,R,wբZ{~Az:ސ&D.&2LC-JNiEāsŀi Wl myZ%O0xmTM$4k,/+jyppTwgĿh`PƿqZ8wd*Tý ݸIuNf.:p,ea^ (3N LY>3(煕1ii:_q+bUUK;XJ*Vӛ#f/)h3)*BR{zMƹZo#G{u+/Rj uE, j،ɗ?L`jfW:9Q-Ez,y GYܯnwE>/ݴW9~tU~xa^#u_\\ΈkUC! \^@nF'+iL&3{kKHd7ka3U&l1_|q\1W:-toQ% ̱keT%'K9QKH0~EE8קij6+bǝa;+&Py^X4Ӵ([FɡmP6.~8_w"(a?d2ӡX |Z(۴D*eŗ ȾsMhcyPb(g;"rr}#jKo-=(op=Y; Z*t+q.ߞ,l@8 6_IF?vc.ݪVoj ilBoA^gQ`Ax2o&#d2b& SF9"o*<((D!'EEAWY$C(DizP[q6n{wx_+{GqEiWZ^kz `("XV)BQ8A('Q-e,Ƣ"NV3|yø2s7oJU,V)d#;yCJ4{w+4Whq\t*!X)V$(O!Hl~E Q-.xb{l4Cuh KZ-_ЊmCЎNe*.+, TWU%JRT) sWS \)MGMDc kŕ(UG&!XEHf zIj`-vQLK9u!\ndO&vQ^nncovW>*]+pk%q^}u݊\{qk?A1<:Cx5G]/5ȣGg3_]c ɲ:F58ItlN_FrǧPZx;a0jgx "NdKN ^NI͉kc(ax$}91 90BNȉA1O ax$DHҟhch9W֜| +'c/L"I<'a0$3cən"F*H1Ԭ!иPw< >6la oK[$iy)˨O߮1R1xX;aBv5m줡tn:dBpv`&6eLn8j.PK6x PK@ proguard/gui/ProGuardGUI$1.classuJ@micORV1z"HQN[߉kW IXT4օ= #CU:]dȗm3 e扙wƺ!5Űi>1GY+C/n3?QJJG8p m0 Ued)ś!2ZdG(_LL)[L=5nɿ=:G* Xy XQN}[L3~={u(HMb!aOPK īPK@proguard/gui/TabbedPane$1.classuR]OQ=V.+-( be. 6hPPb c]hwu77y&hH3-&{f왹32G* .2 2 1\]֐f{E]`j.Ъn{R͵|^ONr=U-P¤jJ`<5cdI R >zE *T CY$b=ׂ| ~T)l8HӀ1 7n1F;k2c;ʖStA7þx$ }q'lšfC F;tl/*qM)Ki@ \cnoĬ47DA= s" vQ  YĪsٲX(I?WGT92XP4vN4}a<ƾ̯ $Ӭ Ua;uu?2xBO#obftkCn#,DxIJ~ժ#ByuDMm3[HZd[EwԡMt4'HR[~@_:#)n߇Q٣^2h'|M4o["On()Uc_c~Xd@)bPK.&@uPK@.proguard/gui/MemberSpecificationDialog$2.classRJ1=ikR*EjW}Uz>۱M*~ Fgq(4$3̐ׯ+p11-LX0- W 0eXsmE%y\yRU7ҕ_7H+WzK`];AʧöAj˼H@)< My%]y]"_1dq1C)0)Y=H[q09d |"c-ݣj<-tYE), r(kl`YK<솪rRl=d {𽏳yQ\G~q~)!|B$#%?L,;I#ĨPKaPK@+proguard/gui/ClassSpecificationsPanel.classVmsU~/l] -PiRHABb1a\vM 㻀3~sꌦ@gs6)5i ̞ܽ{ι?;vUnJTJC]TF Q˳nm9q D2>xw/إa~۵D D.Xpjvzք:6;SVFlWOO5pƴbC] ^#1ۛ&婅1hhtëI)eSࡆGxqڢliv’}( ի|>S =O$rcqvKrm1UMXmŌ4V4R*/yQ. ɨ굥fE6srC MAim^خM75,!he aD-WbeA*ߩbkxCvD7zLݼd]t1FH؏&ćH&>A&>g&>&WfP2i6qa&e[>:Pyz[(s8x{Q2[^A*3mLa7H+Y5TspbM'>ν*WxjP9**aeytk):.qg} re[r֔V<| ߰ҚEה2|Yy=꜕v:u QGY qE>g)ɻl'?Ü Cjw+HbNZxd,J20P< XW}*+h0~5į^4ਊc QR Π$+JgQ6͠&|VY8e(Coz7$v2V:9:d\OͳX5Z.:ŚQ6`.eP7ﭚVSXCXʻLPbQ>Pu#D=OT3q$ET̢qtX.]jr-Ԗ*P VLx-@L2h*tpIn;}uP{s[B`k遆=lpd:p%ȠJӿm#dCUv5#?j5pΛM_=YoB6=K6A],7fvRJod 7 ܠ no3جٜ?2=neX B4Liy4XާQ,P U[G+A/$b;$woC?PK\{t PKX}:proguard/gui/arrow.gifstLa`Xg>{ P̠ y&9+Oe^Գ8!,u{a]7-[ٿ]w5[$ 9rIeЄ]gxYPK $*qpPK@6proguard/gui/ProGuardGUI$MyReTraceActionListener.classTR@- XXi@nrUPbAgdҥK$)߾o Tf|l[={n_=EZMSDVk >Dd 㡂DЄ9`Q1#Řq2&$otC }u'eqa_.M1Ԭ[L2Mf•S^1bv3'L'{[зrbG7<Ӷָm;{<Nz?BĚ `P,;eAEOhNYM?*hE*,cF,x9*bxFp M[UT,`QF\s,e+HXe Lo8yH"!R2T4`Eǥ"C 8qZPӭGgW1ÂJ! 1K4Ϙu6jun q&^p}Ds\A'jA)dѪ=:8C]{s=pɪoh`hڃjjC (G^)aiqiIɡV@_m~6 v|}[=&UM>7PK+bPK@,proguard/gui/MemberSpecificationDialog.classY x[Օ,?;/ !rl'l`; Ȗb+Ȓd})@ ei Sl0B[eie:e6S,vY{99jiO>›^2Mo{q7-/m~Gwegu|E!>_t| 'Ŀ}o2@.F~?X??)~&u'^çKV_ bw~/ |.(O,/O_ |` tg.0(_נA4 A *1Ԡ2unPkNht ӱ^l8/:ߠ Z` UTePE:-jTKu:-b>iQ bZ:Qd8٠^ZJѩb4 j!L女i j Z)*V{92Ise8OfZdVְ3&^ZK^u:iqYkִu4i%Pd*KFn:"-kk[fJGS H8 h{m0/H ameuXOݹYBI"2Ls'pw*٭FbɡX7޲Lf @"wz$II*sZ F= xu5Gbցp#eNY0D?Nmcu jzrͷchC<Nepwdk[ň03g M >fUGM&{ܕU|iMKA7j:vyS;'p\xarSWd&N&/ZߞEK 3*Nv5IhDwxUD2jak/^ g|R) 9tK8%M|.<>|ij2<'=U`*`$R7kq(م&]DdWM nǝl@J&PwE Gځ6i]bRt~.ęp;k"|@$VN`~5N@lI/# >4ymx ga&fxoKw#]Uu Y%cibpN62Б&ٞUMQF[U}62)&rlbRlizxFUA$g]mBWUgv;L&[L2\ee[اr0Cci9Ssrupur*F_LҷͦX,hO*%S& РIi3 .qnIx"NV'&'9w[ X:vF&`hPQKCt9Мw'Ѩ q7 lD|@]MvZڡu&]&@Wp_HE@:kkkMItn[tդv6tӤn!$:d}ɤ a)0;eELz1vSRMzB]pt71&!)ߓ[\l`r=\NF. Zr;]/eot^?Q/GʍGrÑ#?z{$ C&P8+C<2w"̕je7erݜ٥\^|fr{X&~;6;"hf[,hg[d/9`^vszWVer*ikqW+Mv`~Q?z6OQ bvpYn$SDc^Av.WCMCFn\\3Wo2l(%M],ou@ӧJS˜O~DS>Bd7Sr掇A4bnuqc/1? NS$7WҴ~nsE˜W[IO/o`49!ȟ&ɲ\,ߕڋ$w/ϯ;>HaoiEV['{mwG"d68k*N X(A>é!WSG7G+ln*o`Q3Q㔊$3Wy,Ot>x<}N+&^ C} 2^5Lr"܅=81L?E ~yA3ǩucܭK >=|ҁO9pv3PY>tɗ +*_F}߽.m:}3 #&DA@9Q1f NͣyFkFMF)UKy,%qbqyRgMP-]JUWz0- e & 5Ar˰'&[>enkyIs-XjL'ZbM}k̴Ll*eW$ʦUk*TK*B[2ZYȽVaNh}Ϛ?a?f`ۏc̵|c?E?~?dOpU?<a0^u/rŌ/q?Of|Y@Q՘sP&4\֢w=6aIlS`3n.q!t nFk؊oo!C#_!#?I*A,  Nո`pt-bEq-%q]Fd}u =븝^twқ=tҏp/} <`ˋ\e횏=Z +m&>*Gm)5Kk%4mykI|~*P5'8.ĨO)TeX;|:m̼>/iC>)rb t JWʳ4u6a$5;5KoXF,c4E4sh.*i|sM 7)HFul8s" r2'R%-cƿJWknV24Θѫap3ҪPKpPK@*proguard/gui/KeepSpecificationsPanel.classSoP=Aˠ?m86Eas?4臙%NL0&[7|Z҂S*M`K41~2n¶69=zOl0ihHK+aIBF²Tܓ/!d`ȫnNt]22 {GXGjK;%=UnmRKt2-^:W-ǮsHYXUUڤLpý+m^b轘͕ێN8N(1$]ޙLgʆP:5+dsKk͂\hEDCTBLB\"2^K XS!64lbay$ltEV.ȟ̎<fӦZt}KCml]scϼ%ՙ9Щ Рhrbl8E?"7譂):k@O 1ǔ7>FRCF4 d 6GEfKxL%R5(I\FQ#ȺG=(~9+9ƝC>_POK#>(Ru5 )PKgf@PK@4proguard/gui/ClassPathPanel$MyListCellRenderer.classW_^0pI%/Ÿ¦..! BS;,C2;+DGVij.(Mn?C?=g.)ss޻Wƛ/7c؋}SQ 'yT'qjcn1QYw=b tug"``Rq LNf5,8[$٘ܣb'U,o)>ؽݧ)N3 >&aYÃl!fGyJ#yJ-h uCn2tvhѨL6ٽH9)mb(TI)P~ WAQKo 6qH?LLH21jLOM åd %2WedΫՎPgdqHOP Т㶕b@UX-\,TX-Pn^BK1]]ɆK%1sW MQ5Z_U։+K Lk' :PÄPD)mHlcX]5%ޓV^5z3P cQ~ݹ'ҵtq^WIX bwy%%T,3u JC!N߫,@M%T֓چ. _p u#u2O>2Ժ!ͭZm ^B= -#ڜA[3fצyr 5 m%"E"p`? =vqD{D/]wO bH aLƤ8K wbVC(΋8x[hd r 尚oa*ڼbCCCUϡݤj0K4fpث47(LZ"PL4DK4(˨iP|M99FX6ˮU.o3 "+eۊUQ6M/fɣGO>yxLZw}=ֲYfTY*'׀\.E%4i ̑UwI ~9OL/I0fh 0mA3ն^&$Zk;>k`97S:x.UY7*OA h:Κ`- bUN/aEWt NYUb~.mqߤ#몝Eۓ m=dZ;ϯyz$SY#j3Y\rzn6u≾Eer8p[}A|*ae*2U*&oc7oV\eCwO +&<" uFиu<ӐAfsh0W 4p  HVp5- *1)䲾TFEPʥ*[>ۦr(t56vч`o(u1?υ?sјS'/xQ'eRM7ڽ:c, yk=Lb9U 8C=E-\v=F! U5| ^!k| F(2'-Roَ==$Ԉʡ6:"#CY&c݁`]Oo@I1dFﶧ݀ěݷCUWD) dZP{3Lc#bhzJg`Hma :n,XE9mlnÉTBoH-Ot03 =);sM uY],pa J+7Aa!0~Dhgi #^@;:njag`p@%KOEW"00Iu;z T:2ot` 1*c.Ag4'M rUZו{ĊQb]Z!ԖCa^[d}s2'8La&9[H͢`5^"qHT£LDX~ n! \  '_:S*" yg<毼6&tQ$1G^Ugw3H7ς uFVC+)z-΍)*Nغݦm FUTP;i/o̻#G@O-~6ߩ-X pI9 ]٪f`-9@zcc/![;E؝{霉Dk@I'2 G7=2Qm?`bLm{ fbȁ.)VmS-+h*`ҖuFGSbyCQ1%FJY{Cf%^pv Eؙёo82; <(Vi l*4xp|JÀT=(,9-4pg^d&o1^\<ѴG/˽cSMp X-qBW&9d>lH=Av!TNSܞ=s.{c<="Yfwؼ(LC%9cwӑʩnd7hHM6a{0u3rHۛa6Zxdff]ֈѬW[۠;l劙Sހ,&#&#\㲬W`Vh5t7mW68_"tP;;t(uw^ߣ8`;+֕ծcag:ȾZR5!uwޑ~sLoLK]}pCK\-5k$0[X "X3!c~qghV1p%*r>E )6C+Htx;9?#N[38~,]!yYʪ#jŦ I*pΑSZ$VUv2iJA.YD/O%`GrMP3s3$FKxt *ȪV)(be; 8])" Ck ;7G O/ r rXH;r WCua*OR6X|"藲ܐ_آ_Ҧy39/F %J"`Bܵ6v{S>Ol`AnAS]q dbǓBF]6yrˆN&Fu4Ĩh26nRcr܉ƹMys$qtR&F+I:x>< (Ӱk+\{F%b`K0Zl SS9ЪWn:q0MdE&Z:k4|}4ɧFK^9_pd98{-vrߺΦȢTeV*zJh`̤&o9:bD*J\([9p8 %2J09JVtz%RJ@ 2~C#'>zP4G 8@H)z9:;d˹|2KZ(?ga)`;+o}@ dgKr.잝 ͷBsL&50aƀLXpį(vĹBOA58|)idM'mg+9Cil%+bLDh}:xS] ܵ v֏i,]J`>)p_*S54|<߄=U҇ `\-]v,hHP4GDgLoj_dܯ{ 4h#EC5\m5V\.yV?b2z f~2)$Š@xaZS 1SPδ9H*$Sr$K~R%>:Ikd옴ԩ*oOlYE+n=rU&M%1~y4La|)t1ZneOy&)qnb$!F97 ADS Υx&{9őao,{.zXRSD$ja±GՒ97J{hPś+(MqaJ1nfؤ .MqVamR$q` yIGl>By Vvl6wBַ4t%θJAj2$RxFQ~t]TzHx8]QH[(nW-ϲJgȮ6 vy:*/sԌ̉mc#NEi^˄nw=k8e>2)4PALTPC%XK)aљ QZ5>˿S~~>Q#OR5/H@b ~<pZ…֡;`01 |Xr:p΍gHƠyOm;$~5B$5<|@mWy<;s rc5S58'TXF ˋe]JV뗔ױ:4M;9׍G~K-V&Ρ7҇/ ݟNq+5?SPCmT6RFi,m]EfEef wclj]|l(f~vGz]QDZan]MZu0Ght5mG J=](j0Eϕ$nŤy&5xκBȹpFt_p_&!EuYg:"e}V4wvM=:= 57 MhEURc BN*z vрQQ=) (S'Rup ]~*vW;[@Z2'E7Xuva)sh _jYN l0Ls]mG|L4o3:kl'z*m%S@nKJ5`9Λ>5F&FرeD̑`ګu^*\{u1UŅ-5 gVeXRЄ`#?>aad冡 "N6@;Xs^VVVeoGк"GO`썵AyYwVGi"Mr!H%m;|SK5ߝ`" Lي%7.h|v ((i 6 UD; UO]Rs UKO>Ľ}G8zޗd5`pdu.j.9'_o/9, _l#zJ,8EOi(G?HJMv}&д_[w+K;RhfV$213?Qc*zSˎ6[\ ۚmUL̝]Bj,ܚ6Mkk_E^$' 2RFd-? ՠՠ+j S',|00?l $+n&2.a].}ǖxi4G: :Q,Bp~ROeuxP:RGR}d]kץ-YN wm'aAR,K-^\T @ LbNo;Q;!WP*/^'+';Nf??>d ]Uc~^s!~A%bi0`[746oCkmh[GA#pic3'#ΖwjR.\bdgҰ,_(Lw7?'_>='4t@\:'+4o<7!+$(=ȍAK V.|N{!a 9~!\Bq[!(=PKl2PK@ proguard/gui/ProGuardGUI$5.classuTSUݰ]@5H(ZRZR\nj_|ujҁ`GgtFꌣ338@i̞=sw{n 1ڊ>1B<b\/%LqRB e0^5gtbJӭ8s2fDŞx]A o0a uNyx+O!Ƣ 2ޖ$!w%t- =iV>OJhlY^{FV;eXwZXE );% ,+&4;E2&@J,?gGǼcJ=U0Srp&܇Tq#2U\;*UpU "'ǪE?I7!Qwй?t>9w+H(G"O'oXz/"49(Lg[pTM_ &*B݃ʾF=[0ξ G\d? k_q*O찿pC'v$qI42 PK+ _D,PK@"proguard/gui/ReTraceRunnable.classuV[wU&i-HSRLRHP@ZZ q$ D,rW}_ri$Ϝ}=?W1| n&39Gox=Q7dr) pZ MVЄL09+:`+Ƙ˘P =Wwx^dLFi <] .(qQ%Y9 )#oY1*죦$lhsqkVg'KN 0 KH%4B }z8]nyO`ŲԥQSK4&jdq6I.=G$trF"g%irدi'7%QmCNhAޜ'\DД1Sb-a1l9 *ࠊU1qW"^Wa ȘQ19=\VJgGMSO Ma-'㪊{&as ;D1!vL#hf:qxpnկ3&nU|Z֕Masb݉X{rJ'T=7iE'#I=鞌'rk؉ĮstF#q[޹(غA u0M\NA!$d| |)M Nal(U|ŧ5dSq1߰d GSEʦ-ʸFci&%)b:1]6+cöx ˪O(r/a2RV02oقţ]ز~*R*-R:j' u0w./OpOBvT٨,SrI %\3V2W`*#.az95JXqk*Dʱ\Jj@X9Rw\ײF* lLBWyr­5_x=j:Xhg4Cpa-U ޜ8nΠBn/R రQha?.H‡ >z<ܕƟKx+~Z[ːD[/-^e DCGщB I\Y o'x+,A`AGPOb KظƄoMc<2elNC4+Ul K?B9h}SM ;|vyW gYmʸ%'ϔ #c2Gt:ʹ\|0jO)C57B tHm4"d 4Alc R}" |jB1ʄϊ.4ױx!eyhpW=BAa4=0x/,R9ӛ #AHjv6 XdKw.sŇßٔVw gd-etkTNK3 .auTд|[`OӮW%򯑵M~_sTsT?r$Y# \ߠ=4'TbB]"UZuXV⫸W0j8PKLOPK@(proguard/gui/OptimizationsDialog$1.classR]OA=nY]|@-I &Z%4bRƒ>MvpKv>K_ⳉ_ww6$4̝;wϽ̹ X0Ep4fRLYOG1jz&Ӧ[˕=֥DUj~9^%|^65A4}AD|$.یۼV_|̥[YwyW )gιK#ܝPKUJTPK@ META-INF/PK@|=META-INF/MANIFEST.MFPK@}[(proguard/gui/OptimizationsDialog$3.classPK@j !proguard/gui/ClassPathPanel.classPK@hO- proguard/gui/ClassSpecificationDialog$1.classPK@+Y#proguard/gui/ClassPathPanel$1.classPK@c[&'+proguard/gui/ClassSpecificationDialog.classPK@L=-w&proguard/gui/ClassSpecificationDialog$2.classPK@;"&S(proguard/gui/ExtensionFileFilter.classPK@2 &*proguard/gui/OptimizationsDialog.classPK@Y`F(z4proguard/gui/OptimizationsDialog$4.classPK@M-06proguard/gui/ClassSpecificationsPanel$2.classPK@G^. 8proguard/gui/ProGuardGUI$3.classPK@q3h" ;proguard/gui/TabbedPane.classPK@i,b_- Cproguard/gui/ClassSpecificationDialog$3.classPK@E ,Dproguard/gui/MemberSpecificationsPanel.classPK@G0~{>fKproguard/gui/ClassSpecificationsPanel$MyListCellRenderer.classPK@_-@Oproguard/gui/ProGuardGUI$MyViewConfigurationActionListener.classPK@(ad.Sproguard/gui/MemberSpecificationDialog$3.classPK@|VZ(Tproguard/gui/OptimizationsDialog$2.classPK@`~i!Vproguard/gui/FilterDialog$1.classPKX}:uY jBXproguard/gui/boilerplate.proPK@] 8Icproguard/gui/MemberSpecificationsPanel$MyMemberSpecificationWrapper.classPK@ S?heproguard/gui/MemberSpecificationsPanel$MyListCellRenderer.classPK@Ⱥiproguard/gui/ListPanel$2.classPK@2!yK'kproguard/gui/TextAreaOutputStream.classPK@lNjN.ynproguard/gui/MemberSpecificationDialog$1.classPK@1.?qproguard/gui/MemberSpecificationsPanel$2.classPKX}:`6sproguard/gui/default.proPK@q6"|proguard/gui/ProGuardGUI$MyProcessActionListener.classPK@b.wproguard/gui/MemberSpecificationsPanel$3.classPK@ Wr-proguard/gui/ClassSpecificationsPanel$1.classPK@\D7׃ ڄproguard/gui/ProGuardGUI$2.classPK@*x1proguard/gui/splash/SplashPanel$MyRepainter.classPK@s>&proguard/gui/splash/LinearTiming.classPK@2ѭX[*proguard/gui/splash/TypeWriterString.classPK@@.i$njproguard/gui/splash/TextSprite.classPK@Z6EN(proguard/gui/splash/BufferedSprite.classPK@Ep(proguard/gui/splash/ShadowedSprite.classPK@Gt&proguard/gui/splash/ConstantFont.classPK@ƍ %Lproguard/gui/splash/ColorSprite.classPK@%Pproguard/gui/splash/VariableInt.classPK@̈́H'#proguard/gui/splash/SplashPanel$1.classPK@'CC%proguard/gui/splash/LinearColor.classPK@Ɔ Vproguard/gui/splash/Sprite.classPK@[ x(1proguard/gui/splash/ConstantDouble.classPK@&vˎ'proguard/gui/splash/VariableColor.classPK@Bڠp%uproguard/gui/splash/ImageSprite.classPK@{i08proguard/gui/splash/SplashPanel$MyAnimator.classPK@?v&(proguard/gui/splash/ConstantTiming.classPK@3JQ )#proguard/gui/splash/RectangleSprite.classPK@uHԋ&rproguard/gui/splash/VariableFont.classPK@U[^&Qproguard/gui/splash/CircleSprite.classPK@섁-%proguard/gui/splash/SplashPanel.classPK@xb&lproguard/gui/splash/SmoothTiming.classPK@&(*"proguard/gui/splash/VariableSizeFont.classPK@CQ %,Dproguard/gui/splash/OverrideGraphics2D.classPK@<8(proguard/gui/splash/ConstantString.classPK@u>$Zproguard/gui/splash/FontSprite.classPK@XHhI&Rproguard/gui/splash/LinearDouble.classPK@36v$proguard/gui/splash/ClipSprite.classPK@8HX(Cproguard/gui/splash/VariableString.classPK@Z| $proguard/gui/splash/Timing.classPK@4'proguard/gui/splash/ConstantColor.classPK@İ| l%Zproguard/gui/splash/ConstantInt.classPK@Qd^$proguard/gui/splash/SineTiming.classPK@ Q)gproguard/gui/splash/CompositeSprite.classPK@`JoF#proguard/gui/splash/LinearInt.classPK@?*proguard/gui/splash/TimeSwitchSprite.classPK@,J(proguard/gui/splash/VariableDouble.classPK@R!W/(proguard/gui/splash/SawToothTiming.classPK:ͼA[ proguard/gui/vtitle.pngPK@x8=m#proguard/gui/ProGuardGUI$MyLoadStackTraceActionListener.classPK@_5-d&proguard/gui/ListPanel$4.classPK@o- (proguard/gui/ProGuardGUI$4.classPK@G#É@/+proguard/gui/ProGuardGUI$MySaveConfigurationActionListener.classPK@Cx?.proguard/gui/ProGuardGUI.classPK@T: #mproguard/gui/ClassPathPanel$2.classPK@?f(=rproguard/gui/MessageDialogRunnable.classPK@Щ]2.tproguard/gui/MemberSpecificationsPanel$1.classPK@А _1wproguard/gui/ListPanel$5.classPK@yproguard/gui/SwingUtil.classPK@s|@{proguard/gui/ProGuardGUI$MyLoadConfigurationActionListener.classPK@ fZ#!|~proguard/gui/FilterDialog$2.classPK@//B%proguard/gui/GUIResources.classPK@(@7a7#proguard/gui/ListPanel$1.classPK@o%}Єproguard/gui/ListPanel.classPK@[( #ȍproguard/gui/ProGuardRunnable.classPK@& proguard/gui/FilterBuilder.classPK@6x Yproguard/gui/FilterDialog.classPK@ ī proguard/gui/ProGuardGUI$1.classPK@.&@uvproguard/gui/TabbedPane$1.classPK@a.8proguard/gui/MemberSpecificationDialog$2.classPK@\{t +proguard/gui/ClassSpecificationsPanel.classPKX}: $*qpproguard/gui/arrow.gifPK@+b6proguard/gui/ProGuardGUI$MyReTraceActionListener.classPK@\Ŀx!,proguard/gui/MemberSpecificationDialog.classPK@pproguard/gui/ListPanel$3.classPK@gf@* proguard/gui/KeepSpecificationsPanel.classPK@S 4proguard/gui/ClassPathPanel$MyListCellRenderer.classPKz@(Ee$Zproguard/gui/GUIResources.propertiesPK@l2#proguard/gui/ClassPathPanel$3.classPK@+ _D, Eproguard/gui/ProGuardGUI$5.classPK@'* "proguard/gui/ReTraceRunnable.classPK@LO6proguard/gui/TabbedPane$2.classPK@UJT(Zproguard/gui/OptimizationsDialog$1.classPKjj:#uproguard4.8/lib/retrace.jar0000664000175000017500000001537311760503015014463 0ustar ericericPK@ META-INF/PKPK@META-INF/MANIFEST.MFM10 HGbbC$J QCnezcteڤ5bؿ,G_L}Ms ,Σ@EM<2LU7QvxbPKD^sPK@)proguard/retrace/ReTrace$MethodInfo.classSO`~[R AFAƆPd@#Do|î3_/xċI$}}W׷fpG 209aLqvCE",3 vW[c`edP9Cg=5˭}q ˫ Zsk֬:븎a(r{BWۤ6ЭhڪщR|{SbI?Al7ٹRU6N/.V\5*^ڲ}ϲy1Җ{NX?p];vyQRorMTh!,h `ɇ4lE]oL c?2"0h!Kw4Yh>QH qOt`A'LbdR!PK-ÑPK@ proguard/retrace/ReTrace$1.classuL; @oMLa)VY< X #&l6WJ|Q[`<_R qV򦨘4WC gU_'9t1/WH{ue´ѕqK0{^_Q ?:'PK@PK@proguard/retrace/ReTrace.classZ |TfM&/ۄ└2&91uw_4ChMIZt2a[.sN!Jy/Q/4-E)c䨥 9F,+JE4MtB3UEU:U:uV9*OyTbU#nh>MThJJ Ů21wVר:S Zv%ZJ\FHZ;Y5H6ݖm\T9*-i| aT%\J|Eu: XC PimzHhu|{SFJiJkAiWn-8TjfY*fhB˓ztJ„ڬ`mUjr²սݗ-֏yHvSU . vM%B Mz:h"a1{lCi͛(%=q<ڙ[ڜ˘46N]ksKĒBtvlGW'V6 m9 F꒦ؖ]bt =!8uƺvSFʨExl5/B5cQf+C>tý:¢qtn83yl<:u?ӑ K 9Ub5Dz4+G@2֌yx9eǑHds!;)UgeGDjkJ ?/z;T5l>dtcd? rÔ3fd^cǩN3SБmmDZK̑/9r&=P,__*P(=iĞ6ǿZ Gm/,aH5r:8m;9Q`3AA*&b Vtύ;+1pk _Oo0΄[xO"W_jx>eVѫL |24vظOe ^_ǭ5pr2oy!y!7¶ѡctx'˫12qiHඕy"l%Q0C̀9fI䏆6z HF@8aiթkb\lS=x~[ǁ|=`\C~j< a0ŊG74W_~./"_'k/b}~3|frIIhȕ4YxllQV{ #KdpN9-4x8>: cJ0s6)Bi֤9\ח@> ϗ1G4]sh:R\DdũTm'TO]aq'z\|OtOQS_vKN[-ζtYm1G!pe `fqR?Kfh gRR 39%?Zd3Knf.dq_ϢaoY:&Gx_[2 Y2Y~CK.Œ[^m!w>QQvs̉d8Sefqlz56NAe2$FH_?ҍƤmi_MA-_4C[Bs ;?@'xbI 3J?VbF [ ̽ Zܻt 6!$mq?쾌& wɻ{9_5L.tJ=Fv2i<g!yWs])t#'n9}>)'9dJsy*>n'1>$gB?6ĝ4 R+R9x#t~I1xSt#k.SIǿM\҅Dҕ$K&@:9Ô C!%DɲDr.I4AFr.MϠlG*ʵT 7PB>4WB%T*IKh|5˻ii6ߣu i 6BNWjx5XjG^,>K}>Mɷ0>܏;5^,#g.'1"^S*B͎#oz7H ֠M vlTMxCGv[>ܦzTc'ҴDs6}oQ*GQIٵĽX%.͖/&Fvq&7;:S(\Lڂڊt.VXC`=;T]]o=-`|WN~Wiu;;[X)O,2dV~|%*5D!߉:q dCqu,BΨ:գ*25BƊ#wh̸\5B\I8,#$!ƞ v %E 4]0Gh x 4z a6#lG@a5:z~z93rz;%A/cgDpw0KG4>aZe|= rjyA^j~(ll ،i-_B|!f۰ȳbH֬Q"3.'pIK 2LD4KJ<) UR:cZfJ~V^jg^<˕tL&6cF)eBNu#g3$gQ]WJ~?lyGSEǘqEdA!I4hyԾbyw3UM@v~UƤf7rFBơ9 cͼp=C<9u\U7hau4/3)Iũ+-i)K˰XZΞZ6i% ngNlʜc5\J 1n X0L,3!> Zfz3L0Vf:Lw`lތV Z:vVL~w+ *y ˻o'xY3}6оIm2eͬG : \m>#y&aY<;s|6b"ه1/S/~ rɴEŵ%S0!Q(f G({Gv`AmCpK#i4i'3S(YcbΔcVHOa4b .]z J/:XzCxT:;xJz}S~W2ByDpuPKo\8]"PK@(proguard/retrace/ReTrace$FieldInfo.classRMo@uL& @-%N.E .*UDm%u8q\.Dā#([cZ)Emyfp hX)pON p@4k2H0ڇ-w|NzA)9 pLxsWjYh{"]V1b(!b0Ѩl6mOT[>$I}cPD!wR\9C͓G5$D6eKQ֥J{it۞LƄ&`e(\4&`XG sY/u1dRZqz,͘3~1Rsx,U4O4P.XS\d cH KP ;G^@2'!؈Ke ~~rF #i*L ]NY˞B=&-,&C{|Mܞ P ?$rf)q D!fq#H!:D4PKCPK@ META-INF/PK@D^s=META-INF/MANIFEST.MFPK@-Ñ)proguard/retrace/ReTrace$MethodInfo.classPK@@ proguard/retrace/ReTrace$1.classPK@o\8]"proguard/retrace/ReTrace.classPK@C(proguard/retrace/ReTrace$FieldInfo.classPK!proguard4.8/lib/proguard.jar0000664000175000017500000257767211760503015014702 0ustar ericericPK@ META-INF/PKPK@META-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu )h)f&W+x%ir&f:$[)姗&廃\\PK$`cPK@%proguard/DataEntryWriterFactory.classVsU]n@)}@i@H-T PͶlmPOo**~R? c;8 M$ 3}9{ν{0*@)qNp9r8T)NO3 qTF?odqV9xNye $C0F$\"SFx/`LƸ, H?lI[qILH I W ^T/)؋%`^^:5C %i%1*̨ѝ4x,CVۢ5ga1wŭHR"1= ᎎ 68T*f4/kv%vVy*]%=ͱ`xL{mˌVrƒ֐nm.Cv̚lfUA T*E›**.8*>!8|>Q)>cX[apUeu>SK]s|AI\2F#W8CiĴ"V՝Qq9w H*pK—*m4oW6U|oxR5hciiKڔk=pIMB>n8*  ѭE/8 "bDgm˴2$'Lzsɠd9|ؗ?l0'ɄmjtPB?N\z!,x;X+LcUHP}Mxz_,mH$(7Q/c݇L?i CfPj 吋4$*!*%TC(Ey *<Ө݂P;SмI+7ѳudd=kk4iMGV:YSHgש&4|Ө~RMf e^a 2. )%3 5WO=q.{hHԳRMF=}O}^B. ,B 9grd\m~-rݣ@sJhr%\S+\b Woʱ=r!׿o?!qnru@<-mK\$ŗ?cvĮ ljBw-4 ..\-Xеҵ sOMRI){R =PK% PK@&proguard/shrink/InnerUsageMarker.classVsU ]قVj! &4DC,4JKh&-ɦI:gu_ꋾ3FϽ+%ڌ/=|sO_` x+0Ō1`g"uV!9}+Xy.R\=#$.D2e\qIƒ$Du[%!۲jUJ? ~r?Ч7Qh6Z$H"Ŋ^4) '&:"MKgj%&p0rZ`uP!MQ7is'؂'╍ Kf*A'Ϥ" i2+ÍY%jAE̚嚄c0GDzC7x&vM>n[aZWҫ"@VלQtkkpUԌu^p,WUd ޤ -==o*ᲊWpT^Sq2Xkȫ8)ױb۬7Tb7dRqywT܅NOA30pfè$Fub VZ骑l&۶-'&g:5Ƴ MRMJ8jxEtX,-j[]?ɇc&%uҴ3_8`6[g4=zev?45$ tkZS!n;T#Hbef1JH&5hs1DkJVݸF<72M8I "D_4FVbkԖ8N2F;=*3HZ|=Ҏ&&Cy'8q$~*潴HĈcBFlT !kO֞ $O0aK8,LWJUB,NaAô.h=DD(Ƹa*nxqj7Ts賘C mC,R*u\1L$61 %Du 10t? '1Ez.##8H3xHx|I_Q&!1or8qǨ;w9a|E/F"xWŌҌꚘz o`"I\7p#F¸)7ØVo r:Jw (ؕ4hy me~ħ׬Vn*ssՊS*jh[DNq]ذ=pzzR.֬r]q6ܤ1!io. }GfԦƜSTY6A,/:=[#s:Jznn\nu޵UYm:"WY[\_F0/ȈN4,Je]w;>oL؉FJxTj  =Q[Y 5nby1< !pcß*KvZ>0qEB! 'BU ?Ync0Wu^ 4$W ZUڲKjR}S+0/o;bs69íf~?-e^hFM>~a`!~ #@$_ŒeG3=Iz4BD&o~}=9ꯈ-ETvZEg<j}tixx7,88좧 ?Ӿ^ͫPK`: PK@Aproguard/shrink/ShortestUsageMarker$MyRecursiveCauseChecker.classVS@DB( Z߀"(JEE1TYcތs_Hf w12tm5EɮG|J5vɔ[Ƃ9ݬScl8z1I3S_5 2ʷ3qM/mĞqǩg` Lר vJr >~$-٧X"y%aƷ̙;8Q3@:db(D %@:T6{|X0K.s&y,b9>&_ XU1ާkE_a $#a IFH,"H[jI[kQͳbv #y7IYФqqYKv!x_.G,lGm?}ڟg f+QL.w*J~Cs$P;ùPKl{PK@*proguard/shrink/ShortestUsagePrinter.classWsTem!@ٖZ`q@A,3<>pb<eÀ23d!"` Fl"CB@-l H6>L16{ |8.^|xixkaM7e7![GeÚ %} b Jr4-TkzL3d!aq׈4&E-Kfe)AmJR1pKoۮ .%)1Y+T4ql)Qו7X4KhW%N: 4D*GuL.NjfzTduٽQ@,l6vlk9'pEB>sG\yYXdВֹc4}k<.LN'%@1 .I #TJrz\T=XSVz3<Έ8hc""z9o<7Ey#]\xCm ) X\3Ë">E'-=8(".2W𡈫8OY.tH5|zAqKV 79y x|!Kq61)YI db1oD|{At?v 'f;6"M*r"vUDP[YYʌzlH kErHjsi:)̆[,DsuPYuTh݀s^ZNivd~;وJʊJIB t\ .δZd2 k.; J9ll"0.snErdčr^C/MQ~C(QJ %fȹMSPI42orЛM+1b]j#4QPS&twVwk3]f0tH#⊜n0<{-19x }_?)LrC cN|>(PӦ)쑂8Qp#ܼU⏾'y ~fg_'݊97+ș1õlVG'o=?>s Qi ǘ/댲9>n ՙSU)D X}B1g LYE;+F -ʦgQ[TtSi86}/Qpv[E;*8'G;  '*ԅ_F8-ߋ/wivaZKOEۃX^)e>2N8UdXPC^ 9 (!r!<-|\^jn^D`䊶He>|UxMAk]g|*҄ XTU'%U\j\_HS+:]rui1m.XX#&pAV]0ǜOJG5wB9e5ǞKD?Or=F7ٞb^$U{=NJL$7qCsPv#{ P>]_=vd"6Y|kJP7Vlci2ja|3 MZһzש4DH>/H~k<^۶->a\%Y_u~;)N4%<Ӝ/]vU_k^ _7\Yߑ>d'+VbOY/RO8gRmR_`6lk?[OY4pX&Ne"Tq{m.U/j 3^8jPKV0{6  PK@+proguard/shrink/AnnotationUsageMarker.classWklW&xIډt8kou^ qҺnBi4)M ;'Y]S)-J[p (Nܦ*B?HH;xc'3{9.fo`#86_ Ұ dwCmS8 98r18|Rĺ–FSXCQ gpvVƃqE3qEa#q G |q|A:E_/xZ3ygmWC7whT~uSGKwio _,GvZv\+z@{c. ޟ.'hXVg1 5=m?C5N)tgǺ})$S=̙]QOYI2}4%zZLFxp* L_`UztR?BHYR`}@ gw$2laocV<5|ӎ#6K{h^-SI rO^Wj:WTT\اhAv5"u.EF4Pည 6n(V zeCq$:HO(ZXаOhV ;V54mu8iu2eUB苝;Sj"vD\foF ";Y^5٦JfU2P˳5j؆gM):_11n%l'_񊉯&q4-mau&=:cUa~M [&wM|OXu3q7[&~uL8//`;xWE'l]*Ijbɤ8#gбD軭zn-))FF- ?ү jcDT,,g[>[́kMbו~cbVe =pt4gu/yl.yƑ;g._|vFlCAN{Dw N2x%n4U:(/"/5!э%!n٩QX{9Ub|O[bDom/U̎/vUEɖDl܊GOVѲWLҩֆ١\.7[pǂrhژO%!b6m؄с$At`&L^;unE`w_9Ihi8v7!Zw#*nVrq!: DUG 3K/+qGyE92,4Nm^)U*f5/wXk[{mD}Of_XFC6۴y<& E%o[!W-Pa-X*cDQ oz-aͤYE˝X&6%:Ҵ_?d=(gHٹ#WK1ZZ'-"1R VI+_A]ĻXCQGv ')^8_PK3 EPK@&proguard/shrink/UsedMemberFilter.classkoAZ@Zz),&VzIHLVKLF:-fS&V(;@l3;99gg'"qq+VY6H1wg(֣FHZ`|;wU97ZUPya=5]9x?ɳOU[u d  D;u)*|3}ڤ2yCv[%%uIa̶&VCE3~vEv; >˪]qjØ_CyzA{ɒ2p(t.箅4l ,$"o`U,Zn`I`uHt gz"k]l$Κ"1=@HA)0i:򦨙0=xθ]\!ն9E0!Ϯ:N箰X D[k٭k={q=66ciK`!@hi(wH PKPK@Aproguard/shrink/UsageMarker$MyPossiblyUsedMemberUsageMarker.classU[oA*ak-,yicbAvZBvFO&5}Ř11>_#3Rh$ 3gf}ga?<~`+~(|14}qE7'&&^" 3LNplv*%̼!Ħjr#ۨV["GAB"HmCJI kB*,7 SXnU &\A5mQ "m6-hp+_"" `PҺ ; KKn3/fᖂ۸]p_A %Rad;Lud"[n\pyJM 3-*WD!!\ےgR"lvQ@m]nbfs -/xْ I8R_Q>3(CWeFWO+oxfK[ԺMfΙ99ߜ'5i$q+ iS(`iwP԰CRDPzPh |;|˛ Tk&CUeHԽgk m,D ;ޔxcpYw,֩y$$͆T%7yA3Av]וG*XznyC/Y:t\U)5uT`hXŚÓ(xs9>I{ƐV.(P l{wvU;<>,v3BdeU#[EtnW6CS@3o6HӤ\ $P_VAU=%9 %SݦsN+tLG9ړ$c0hwؗNŵC$oY8=3aot79*IeMգ?َ'p3sN2K"I!2"PKꔟ#PK@%proguard/shrink/UsedClassFilter.class]OA٭,K˷k~6MiԐT!Qn@ilKOg/( IkJ*7gf93眙c%q<ǡyGObh98x +>Isbt=i^p`tKߒA0=OӛWHtۺ[ʍ@i(TMq]ޢg:eq$X̉7ҚiFJs"iKg|A%x*~(O$^#Ť.b.0/?dmX\Xizt^J}߲:aA7d!, g'i6TDxv;]}$Ѿ n׌p>7X\ ?`"vIn%Xs5eR<16xOGj]ÿPK;PjPK@8proguard/shrink/UsageMarker$MyInterfaceUsageMarker.classRKo@6 qmʳB47TBJ9ɶ]:S8rး8QYR#Q|gv߷3;6ȆyX(iQ5⾅e 5 Ÿ'u1bTEW{J']ՉPJ0Xzz!Cd3QmV =Z{Wpjc|q@9 ڒ0:CP lPWUvYړ"{?(OX|㘟qS6b́I uh8h⡃cxup;:s3Wlnuvݷc kWNrh ڄvu|FÂE=rz/Zv>s 6=Of}*}"OxUZ wyz3{ 3d-#m7.k4!'eE15"{LkiI~[?ѐ?F2 VI Bz 6%҆h^]਱$.n!AlPK??P%PK@+proguard/shrink/ShortestUsageMarker$1.class= @-,-B,X_62P⪭ox0| 8@ "DIJʛf4qlwZ*Mq9" 0",dR?>+1,Z[˖0yTMǒSG!̫:z80PK;PK@>proguard/shrink/UsageMarker$MyBootStrapMethodUsageMarker.classUmOA~v' Q"RA&"~9z =i?D2E-tvw^ٙ7(ĠV Wp;J1EcH H* QQdp7FdJô{kxн8ғ*d1 )3C,Yh!:۾iZNz3Ū7]߷eIHHFsmyPB5CS1Cۊe5)Wf8{gɜҵ6}ISŲy[VYeÇl#qbdӡ{״S6љF TpL,m 7䜚IGI-eK|gA"utKG;:4<ґŜǘװ :t䰨#t,+3.>a~ >F8~FqIOgͧ3 7Lh-<3Er (FPN ڵP PKob&"PK@5proguard/shrink/ClassShrinker$SignatureShrinker.classVOG ^{&PBS NqRHiCZZ棐~df[kzR JԴA8QIzi7kL>0FJf{7cϞ`9Af!hd(nJx[a I!-AnKxGF1;2ŘzO!b\]NPqO„$|pW gsh[ng5g6oTAw7(C(i52v0 w;z^l!ee9Ca q.᎛k+%x/ fT(phxFxi#on/XN) `P&M۞aH=Cr*~jyIb}]Wp |KX >g Z JQ&Mۦ^, m5,Sڄy-M\ 0` q'cEתD%ϱ$aY|!K_kSր%y0 V@!LMWwsS Y,*~Or[Pyr8m FQx-=<2QQZX#SٓBxpu`XJ8UI37{Y*'ܭ MZE+zhEnZh{w= Cݸ~,/$^hެdaq5# {" 4! y$OJd0XF1VĨд BI_#H-;p# DBe,򓣧jp+HcKb¶R%U~~T}}8Ybj$PF[W**,}teϠ]̏kD @cAba1jfX+Lֆ ֎huv?a18Flty3@o|tsCGB)PKɂ.?PK@#proguard/shrink/ClassShrinker.classX xTof&^Ba dAY4MZ}8 J-ZjPj[ (֊fBkH}WϹ͒1 ?}̻={rCGԉ1n,v~{k=pܸ;X {/Y͛f`q [=$ncq;2XܡNučqXskG؍=,>=}n|{ O5V7,,ag,>bc|}}ׇ~`A_P (|I<-0hS1PQeS4dlѣ1K_Ee˻2 w%hG}LN_^,P fě}*-",0.ٿ6T" 2P^wh}Y_2BU9T 8!C_iףn)kI=H*dΑP{TT͜#UK2ҙ`dk4zh='?قZR>"'K x,"pG,:#4TcDU*xQOg ~xI/qLTQ27N-~*?wY_TSwSTagqUm Ac"O8TD>ER[xX4>S&)BUE(s:b6x%u+fjU9fWy97RI5wIARMgPέ9*޷X|VY܉H1tjAYd6 #. hdZFi;Hm=rD sQԭ{@a"`iXT ~wnK/Ӫjr3Fl3Q-~Q@k-+xiGڵsWΑ6¡`&ԙLsV6W]9H`EoVA:T2ϒ6偓.RNvkFWzjf]/('zfCÑ^A3T݊iXpo[ш @ nrwU@IrG} <G_kI'+ +NCc"EŘy8wB(z hwkԥrB=ӏB.Xe=;q,JY`(WcqOlO `MXi0 Z:e;ɛv"6tJtaBTvcT7ކ8vc+wi+MyӦ_=(qcV4R c(+h)dxFqUTK2dG 7?~Qx}z &HE?R'݋SWdB΀٪#5;WOko?7fү'Iiv=6 f}OQ/'m:96! a5mA4 X|zg`*,Va\y̗曮.b'.DńBG ^_*.l:J]y>k(<*˧,E؍~NutQ zMXD< -Z(c 5sD'4A0"M8'~݋J&)un֔:iݹcs:ԙf4=!v@7B,z7c^e҅? PVVpWƢ~G O"BSe>r~0I/:rQlB ;ŗ^\ N Ie/0dX5\ ~ɻ&$bL8&XI \)^pF2crUcf,0c!ϸW%5x UĢڜ&qLjIT3L= 4fОM,-6bk)K "Kcce5g“,4c"oP-kBMi|yCM'$$P=u{P@p&F@ czZȥ5hɅ#]cĦeI50*L ~\7paՈ1׏V-#8ؾRq^x(zS׿i%Ke[LΌjkT)f !crQ.ge]#$e(0FJDFF0eXeZzr5s<ò>+ⱌ'XaU1IOe| ܚ/*\KrngTgHrv^(XEN@tMuk=9 +Ѩ4:hbBroj5PRN|ǟYQjO(j na\mv3s݌4MI7 rZf4e7B_6ŅTO)-+b ˹#z]3I!GVG84+jYvckg(>aLbt5UHp'.uۏF7ejl'+N1BsVeVU1B^z&JZ%%;mT4a>#`^ 9: :tEF܄GiDҳ=VT ۄ0zL}o%$1Op :Ӷj =lT 1Uz@y u8hB=J}t!iWTRZ4璨vRs slgm}v= h5m Vk ǘ:}=F#VB?5Dž Ո 0|adOݓLNƿ"_op Q U0>EU2}=>q"GJO~zvKxNC%uzzB'N3PK[y PK@%proguard/shrink/ClassShrinker$1.class;o>=vvv.FҢT̜TF!̼"IJDFʼԒdvnFĢb:}=* Ƨ #`'$1ɑRpBA9200lĴ8Č8lq|p9<%nV-xHA)s-8(K(ģRc_8E1|IPNJ_Vp+֟W9& +؅STO MgE"o%aV]<9x{ IJ{m1;םTl2eX1uf)~̰ā̔pS&a8&yV(H SĆj¶+;%EN:׆;bHƦY=f1N礝w:u p%q*U0\`tja0n絬>+4ܜH93zT\fҶyY h'r:D4kg;ȆM[Qq/8'ʔuuد; ˩Y-[eܬrFW<ψ~eT?}XG?On\˨ ''EM0Rg ["Roɞygts)ͪC9z9&Q?q·nV=U’mi9ːeٞߒ2I:*M `&IE\?~0>Q>}avo>H\JnZIGBz4wT+◲a_׊4 -ڟg:jel7*~+S5GMfys>#єXrp=T({V g4j*5aaynF$5u+Lrnִqnj?5;\ޓw*~˾jB*Rg NOMG~7>Q8!{3\@ ?Z+~ %刦!i4| eACnLJ602yf]_[݋ կ$#g7' Q2Cju<ӵ+)ۥk{OwS  iG\i(~` ^\("i;VޣDJ%fe)QW&as3t¿2l[+ՒRuua.c6uZ=&t/+*B2^M3F/26yiU x~&^!x>zEB!I"nkX 1<#ZKۚ[.oqYT|ΫRB+(a}ml` mmmWG4Y`J$ p@solj9BVh}mx{bPۘ?l»^wH^s se|@;eqA ȼ/U;ñ^WE}-j/A XokuԎhG`Ǫ\5uYIXQ7wqU+".>ݷWZ6c3Z-ĤpKiF U{:ݙ4=&Pj~6Ajc #Uj퍀}_Jp(TMCvP,;O3@l6tjp0`q .3+}MA*!HPRjfFͥs:@SpD4Id`3dpkֆ a92OC+sQ̼&Q:Q3kA\+XP JlMliޱyBKc{$C-}U`1ς`3> 8MXCA]_$4Cl>kH2ia0H#k 5 }$<j6Ҿ3NMcc@ |8 LZn2Uf*34kZB5!%}Ueui 7c{|h)jX5Iߪ>K jp6i[gm\pp~ GiUԌmҹ:SaƯVm~_Lm>(ggPUgUZBX<Uи¨־`ܬ.KuZz_I݇^s[H`}&٬GCu|fGj'5fԗw_RQG\Xkn?H͎ĦXG7/& |mmv_++oпس8PXDQ=g:B0իkx0fx!Z!QZFp{`Sn4}ݭX&5YB0]"u}[9A~}. Go?և#5>bD־!ŃAAzG:As6a%%u+Gރ9FK;S\7E'f[qJV'ch,;L0HToLkCS(;^CkKTeٯ xyvK5!0QjOX ыPx5>9;ؿGԢђc&L@ajHvTLP̙8rLxAñXpBǬ$] w{gqTmN? 'a۬O(Fz̺B6ى6rzz5j3 |+dfhXa^SW|,Pp0)!2~)G,'?QϬ/ ~*?W _w U|Xo!bT+F*$h$,S ILYȒW$E<[(Ri*R.3 E,R"HCQ" %0E.EiTHGY-Kcdi"4N*Sv*KT!U*xJVZA:a @jE=HaڜdcyUeiZ7J4=7DBnmYںk3{$g{&ďx8![׫0UJG&zX֘=7G&kz/5=$ÝVsz ؉0imR--$MIO Ǭ%d7ekOL8+^k D9(Q\}_sJignAYNwkcۧ89J٭wNiӐdN!qO,-6uuyhdB.ԅճƫը?h'+2/4G.$cqG֪߷*LcAFwd*^?w >JClj'r-X lb?y6yڄJlgWj,s[Ci"1y67ʍXU؅wrh;!4W7%qHhqR[׃v[B9D`_x!h!/LO5L5< ǫKΨHrM ;NDDbR"IA Q>?DRì4FH3%g"Ic\ i$ltЋpE.Pp?zg-U2z)[yS|E&hEWwj& JQ>}5jE%\ޛMļ>YzyIK}{AsmbHVwhȎ# xF-{[>0 .t16rW(ʹ?ζY^q_0j ſb[0BZ}鬝6|m:#4͗$SC- }VaXLF+T6Wm7]XN(͑ mR> p8ķcKihTSBGU]Ht\&%rȂ+J6\W5p-\wȀ"-yNx~lvp OOW2R~jYHeX]%Ȼ ^< @,ߓFWNFwt F9ss oP ]UgAi%|(P )Z|D-!,)4r `9d*'{#<91ePH-r:nV;hwBP\Nyn!e(CP&ȁf(V Ag!ǩ_ s#QGyB#1b?x+{ɒPsW> *?˴6qǁ)dd͐prQ8cq&L%ǩp ,[IQxLP<\S(;ұ; n!|dJ@&JnC1 (\j8څiBST`h*i>2X@ZH0:((1Pe0+a*N֝Kh/L;0l1.l 9X6ȕ[g C%O$@`'T8 6+(2|:a8构1'ujysa$ s a%̽O`F' sED[|L7Sn`*in湨eٱMot t{ifkf*& `9S 0&#-kUL2tl*}+ HBJg{%{9^IWQ^^O7MTCx^֋AP}>q$վ?3D @AyJjY{'0ֽh!P!Xre—e~_oᷩ3V&zN&x' #x5 mL)}F`_ؗTsZ$F "hnI ߄ !RkKZ%Ph I }9Oli.oY[:Jof3!e:m -!e lH˩-uj:J Zy~#H2_CW^EH-!Ro!RWOd 'h=$QYj#*aNT"P,`Ăf(&s <*}O-F"L—PajvY$j5T{ ͑*9Re'‘T&Bn@e3pϊ mj>? gH%RGbٯeZZG>B}P<&=J?q@MzEen__.$+[O@ %\>uj5aXs؊WL`M$1fm\%x 9|DeJJ5yp$*oQK'6VȊaKXsҿW閜)m_ÿ4s)#,:6?uwk pA 8 |bMվ&P8uh{ "QD՗v2xFwFph R\Ot0î$.ѬJY3HiY]S 5/YVY$52h4CxdqOW-̇|DO~@ͼ%%,_'4T𺖑d1y/tn:ak Ad6>h"?At=| la Xh3]n/7*pƈ=qp\d4Cɧ &S&drɉ/f; ٽܮ-_!!r{ m9nq|dbAT|?!nN+["2ю--Ab7h:xʇYOB;8ޙ=)+[_&m@9+}p E͉ -a5Dhzn7e R~ R o[6 PK8OPK@6proguard/evaluation/value/IdentifiedValueFactory.classOPǿJ_C@D_lc[C,ix!/Xt$FD_MV#iq{>{/EGNB cȫCAAQ8, 籊A, gY zT 㹂 VR& ʐt<)xf :p0|>w-%Wm3]ĺW Æ3c|nV5-2Y-ӯ\]X\-Q0A{X,ؑDp&>$z47d "<w}R2mہoyN1u<9)ջJ^˷xֹ i(kŘ1ѐƄ_2zơ&@c0)(6KXeXꅽI )_آƞq[DX|&fȝ[Jy^}c7w ~ܔ++sҌӫ5@쥞TNHysmd0Z ;$oK)BPj}\{?FKY y6wɤ$m(2{ ɔ$Sm xx IMZ׺$a>"W"Azn7Rp3O1\[4#2HiޒNgPKc֣~LPK@5proguard/evaluation/value/ConvertedIntegerValue.classRnP=7qcǸM m)%>֏w"UTB"$7`M A"XQU:U.tfxΙ}'tZ2[Sck)MUV5lɸ-aG)f~,0ļΰh6}73ю vO'iQ! Q=ӺETi9a[䀕0#?=&K$@y7 O]xİ]e튐2 9moOK />>ðk5G?Ok]]7Fi)IpN6r=o}I '&0JWO ,_s~A0TJb"HHGVgi0ՏY B?ϛ?__h@Ge(/ :`CdCúmw$j0eT s#>HfkG+$c? {*P:?>bNУ֕뎈Nxg@LIIalwt*tGQ-%:(v)^&\@p($,tn;P X?BaK{(;(.!6DQUr }Xa؛~* rv!j62 ;Fd)@H}nl;r_%9 w"Lʒ) mGTlg5Vo9b JKHWvڦ>2;K섩~R^)yJvbYޘjgbK!alPKPK@0proguard/evaluation/value/UnknownLongValue.classSA_'! adQdQ% B%H\I'Nfxћ'zʃGQ$AB*_^z~_/4Ýf  aJȣ0L`& gtOc y3:g+NqYYeJ3DcqdC|QánXR5!i91Κf$]oӆIm Tռ SI |DUqfQC?@W*~-ۢ9Ji,ⓢczxHXIS(tўQ&l"y^TW mL.FpuډE?嘨ărfD-vqJꙕ {PL;=4(גX-'}lsͶt86Lʱ.Ƨ{rnB8@K* fy 8L N٩xw&0"QgtPd ѳwƙ3- +bjƬ{&_VSYȬϩ/*}3۽Fj̞7hY4 A ūgSo`!P~Vhs^%zavr.>/EӤKDdKN^'N)P{$'W$y^ n 99 fb,rU‘s\pl9%/C:0[]\ 砎Jt5*AIpoQ813;Աʌ r9Av!4!ⱾG?T:^BK@M-siG{"+PKԀ/A PK@5proguard/evaluation/value/IdentifiedDoubleValue.classRMo@}qbLSBB[PHƥP!6&uڕ_qM$g~b֎P˛}of~h`[Ge঄[2]p[ɤ.Wu :X-ђ`Kp4l0G.(~`qKyB$B7;IO050H2l7i1O"_0TZA(o:"~;}۔jfqÞs dzP9[1-D$üi!UVoGi@6Xj"Ln QJ=f`p@ \Uw)a` L]SULslGWMa(.kB4H@O jK|_kõ,kPL {o]Jʱ#1I-[&^XڌOϰbx{zafQ|auV_hF`|1sL`o@dP5 +;X 57Q e~ pP)p(pgP Y\dBAr >OdOF41uU޺E 2WDTE=prX>!GqJ8js|ਵ9N'gQjJVf>lB? *+pN(pۨY4ȅ pK~Os K7^A2]c 3:?F*TƥmA_/}AIz^.PK\a PK@/proguard/evaluation/value/ComparisonValue.classRn@=Lӆ7BH>*!"*XULRWK~b$H !|⎝"*9ܙ3cpO}\S Xu+ȡ`f9Èo2TZDNг=;k loQ s¶ =8CzUt3$&GpP[Αco`n01x?tco J_S1m? + ܱ۩ elh(⊆k`?IJDɰ,yt [V34m9}|xX|pp)F1TF&[#U~frl#\!2ʊ52BxVT!Q,S0:EƬBJj&ꄆxXEKP1 2/,P {U"bB?A>+IHXeڛbR+!ԬU)KhbK"/P>җZNlݿPKDPK@4proguard/evaluation/value/CompositeDoubleValue.classSKOQn;LKP b;It5 )3 ع1n\h"%ĸGϝV&lsΙsy ܷR2?-{@}1ܮyHXW̚Vnja巓\B-p%-d^dw9'W*U[^ZPl){@S/8@":+PKBjgPK@.proguard/evaluation/value/Category1Value.class;o>=A.f>v~vF6̼;Ff 0FTF~̼TܤԢĤ_rbIjz~QaXbN)P@GCӧ(?4(E? (Xb;fd,-bd /-JNuY E/+,AX{q+`Qd`zAI6 OH3iV  Fv ad`**eڀN ]4u@$ PKK<PK@2proguard/evaluation/value/NegatedDoubleValue.classRMo@}qmSMT=@AB!U%mM*  @BQQқѼ7ϳPv lG# #eUT4䱝ǮU S0q/Ny? z1]G\RG^;2uc!w^t`䘧 ʳ1M۶O85/z<4{b޿`X3;}Wsщ8K*DA+ =ǰJI*ij ;']Ǯc뒣cE,(aaoi {:zӸ!騡.q #Z^U—{@.60Fߒgcd(Êes/Ӊ,d4kfߐ2^%,"KX!]PE&լ|OɍuB QشWؐ< C]AU>B~J)=!+J*# d6g4吐n*8 #V!'T}[3xPKmdePK@1proguard/evaluation/value/SpecificLongValue.classMpeۄn%%"4oVUZEnd7l6?zqAgTf;z͛7=8>vo6a3|g >ЅUUib\ |Іq6]dyek,reJÛ0XY|/"XfXva&Ta (Rak؎+pX*\e'D= vN(X1-1R)N gܘ.НVK {=c+KyP1\ӶRm'է yy(H4}[m MiTeSv[@OSxUcfvW"F.\v#KҫʹcIRpRyΜ78YQɳ`tFA#ixwWޓ9f 1l +=24f~_[fe7#E mibj. GU\qre$ M 8T.Sل%lb^iYt|OtdpNA1bM!`R$ 8;[R ]ͬKrU@qҗ \__Rv_C h:7L P12#S C Cps24񮜲4  Up F:zO.}Y?ЇU(SC -=H֝xw2Iw4(W=Ugoe*۹.A߾>ZY2q}Pw=Az8ثA#'diң{y[kd%RWy< /zRVPZ+ &}1ػAQ^#=}J" nIOa(y}o,͟CME=<#Sz_ʣlLĒ*yq_%f{v|o !d7G'F˒ "r%MRAAʘv MqYʞ;4C/'_Lj@ "~JM?A˰ /B O/}vym'9vHOߌWkK7)}^?g7$b-NίF"H3 mGVOPKjpZ0PK@*proguard/evaluation/value/FloatValue.classrGeɖ͉,dB jR0*g6, \Teu^ -9(F(U^PJ;1dq%]d2r Uyk, ,Yn,,d)|r[YwY|2=iwݹ@j::se'\Y^(DYS=rs02fd~QŒȨSC_uh)# h~M@dfZ̙ VۤZٚ;ܟ(q>+ݲZ/GDVkX :}^65jz]uٝڊ@_ԥW1TzC/l5/6%o84G ⮸ϭ ,mcFn%d1ugWi3fpVa64'-5G}~._Qʢ'Zq1 ]kZ \>]oU`.p 3=Ǥ,X ,E,S,GX ΰ9 3lΰ9 3lΰ9dNao Uк=ޏMӥW µݿ>>t=]#>[sӆN &GA' hirs%q)AV(øq@&T$U]PKPK@3proguard/evaluation/value/ParticularLongValue.class[pUvY"X@) m-M6b6JA@ xaqt|uqtLFQ_|'_|_|76iJOk!srvwwvtㆆNkCOը=i 8 *U6<K%bY2,,I / ˒cyaɳbqfP0YN԰ Xδ,/Sq^A- ZYmW9fKsm.LwH8emf Dy 779YC^IǞ0]o=3c bp6ŷެcx "obؽNџF4h-cڦkd3&" ͷѬTJAk8FfOu{]'GWrŬg峓5ahN'<,@ʅ6Ϊ+q+%4c h344?vfjaDC=X4try5qKWF"1\J{5X{ʡn#v0vLz=lh7 b%oٸ޼uZd[/;ڱ> :黄c`EOeIEbt=L+C|:v4Q6%U!ͱ}^CZnnīVo!Fi껋~?| fJ//B, _'r{<WGR$B>,/B$jk'%~K);+~*;'~ ,p}/H?Z .J? .KHp[F->|bշVwĺ[05}4_+z 6%k٫EҏںG^< !,Yݴhxj^vߏðE2@el $;=7 9ՅG|' ~4`7j,ǣn_A n{^>3.<>포s!WuH6Qa999(**=$&]Px ʣbT"8&K׍,6~*p=13[_CXF}PKwC?CPK@3proguard/evaluation/value/ConvertedFloatValue.classRn@=cܦiGw"UT"&$ueذ  $ĚBqC.t{93| 6Tl긏 ٖؒ eܑRa3,( %{a?S-ҡxCouʠ}@힋^ܲ^0hgl.c*a'`ȰbZfUNI'ܠvcŢ*FQ Z(v>!^%\Bp(ä*3^vޠn;S/Q?|BaK[(wKn S&Y] JvT_) Կ@{>EOpmF5O>pDXXݟPK5>6~PK@.proguard/evaluation/value/Category2Value.class;o>=A.f>v~vF6̼;Ff 0FTF~̼TܤԢĤ_rbIjz~QQXbN)P@GCӧ(?4(E? (Xb;fd,-bd /-JNuY E/+,AX{q+`Qd`zAI6 OH3iV  Fv ad`**eڀN ]4u@$ PKm#c.PK@,proguard/evaluation/value/IntegerValue.classYpUO$ #K]@%(*( V Ig:;=⾠ >ZfY>>U>Y?cU{}Ow&ɷ|-/ҹtFM "nE܆qN] E܇؆b;AC Er I5B46Uuc-:& vtTqS]cǚ1>/Yfsǚ҉b/_*:^kWu՞q0uyF,Z6ir5?P#9<&+Etܫ!8FtΣs!\tE+W"V!V#kkW!6tFf9DXu(G>Q2| e(G>Qu}c](G>nu#ѧ9:,Gͩn;/[ a4(AgVE^fGU},jMaT-c_5(ۡff10Yx& Z0v.0Y˃3M^H% jgv nvEKȴ˒vyҶ&t +Rn/6n͎=iW&IkvYìRcN3:5ҕYYY>i7$Ƥ*i7Uƻd|ݜ|$mOҚW[7i4*v6m_1ٱ_3){:\"xfޮIU^ztvd'lJva$ɞNV*,ޮ:{d[ [Qe'K[xNlaKTvNl ldCkJv pNVAe=\.ه Z}ʫ쑒IЂ%]u5A/*[#ٯ RY)tkk LXS*|L 5ǦYS~U5)MÚRY)5RSd֔JMهTVjndMԔĚRY){kJesYS*+5e/eMԔ})kJeVJMX*+5eY*+5eM1נRS\JMwz)dMԔ5V)M֔JM{XS*+5eeMd2CǚR){֔ 7XSZ;kJegIO֔/ٿYS*{`36kJeOl5%{(kJeHX֔Εl֔6Iv!kJeIL֔Η֔.Ŭ=I=YkX*Pk5Y\ʞ"AeIv5{docMiƚR%k*=<ϚRFɾΚR͚ٙ* )^֔ aMY);o.8f%'+K?Hg]Wc#\9򜿙܂PKI;q PK@3proguard/evaluation/value/NegatedIntegerValue.classRnP=7qĸ>B]IHQYUMr vp~@lXbG!&K$3͙9߾2JPpGz*jmTWUQPV;J0$*,b`Q%8cX5ZxΩ 9C񄟝Lg I8lǑx +47iZ;LxKY幎$Xc:Qa*tMI/"VQ#q  }ϴjhq|8AaϸkjjdyV9e2,M7GE )Ь1eDz!(T>2;Ob քR T)M)Q|6FiYڔ0UplPKPK@+proguard/evaluation/value/DoubleValue.classrGeɖNL.\G !X1ؘs-UͨW9<@Yf$TeŚdKrNk$e-3W=|b&=pR󛶼 >:xFWgoft'VlVg/~V#G lt1“&6Om 6lTzHgU6]:Tld5VFvDg-e}CgGFMݧl6:W6:[R6ٷtV62:{Nf_6\J+UԹ8c*փ/V g{wOYgg-.3\yw9PKGvŸ PK@2proguard/evaluation/value/UnknownDoubleValue.classO`Ɵw|(6>&~B!d cbm/صص37^xQKYNs_08Zn&LI#Rfbং[ 9ԝyp2Y*3bͭ]%NиCE*ٖrun-3#+yho:U̺j:B6CL5ej g%tv:s5a ;z'ɀO|*a^0jnɱyzSeζtgW.mV[TnV4kyG)[=nt #*^ܨ1&37L+N6zᵝeZpl]&C?2QoX]9]Xߦʴޘq)YU0U\(N0'a4ЌNDl}urk1LK||am m|at].|&%(jfq1zOLAү!2}@mvC=4FHp=.!?9N@I2''I{{;e]Β^͓^ -IpH/^^qaZDBM:9E${'~"G}?@|D$g5IuYcҶvIK%'GIPKbձdPK@,proguard/evaluation/value/ValueFactory.classV]OG=×aYgIR`m&iӏ5&NB,dY&UUUK/*!U}A2QQZ=UR 33ss}? ♀DpG$)qӘ~\C0a]8|RƼ h.pHp"Ņ%Y+9 }h<4 DC RdMO-SeՐ3ɔ+7eeE?ErHJ[ΉjÑX SPՔH$ЍU [&Cd(HS芖طuژ#:}ld"̎LdGcq[5Ԓ {"ZT#IM ,+ ;RdE^}-2zR['RRU|AUϹK5w&A7LIJIOW}%嗐$M`9(%.%>Ttn)|ln)pz,g 5j*CIRWa.Z..o8~y"-‘WD1V'TqS)CO($o&!,'2)}cCBJxcX /"tidDXƘ^WD?Dz:d&$HON7vΆ!D\6q gY1H*bq\x0z_C-Xs4#yM{$9>z{;f+H<@^f ]E*$U^4i ]U7(E=ЙԪń(V!i+`LWC'.fm,tjwĸOΤr n] ~ѹo0gLÜ醘=_6z0~ ߢ]͌J.د`JXe>@H ~gQ3s#4h~̞7F:m{(PCն pyhBuG5'TvFQ)axRa'lQ+L浼i9S :L< 'uZdQ\5I5s2`HoG*4z ҬA!zMY4|=4z;vѴ-TD71nCiA{:3N/h]!I%<{hE[,z8ynƩڿS_j`r$؁NZ]A.ҪkiuiutUvpo]+7w-*n $:U }^PK*PK@.proguard/evaluation/value/ReferenceValue.classW tTed LF 0E$Og .ZKj5`mUk+UZ[=mz{/d33f37"l`&7ٍ+pWj޵];5AƗpM}3cޗ:J㐑U75><܆oJÍ8q'?]Nlcۍr07qv2]~V't!>ķxXwX2nƾQ7zǜx<^19߉N6-R]T*l-NMPEiGjW+tuK)!:O"1vh)CekA>KNHy>$JWoOw, QJZKīS(,R"Dkn ڮ&uzv!" 0CA j\M*Qm3e,03o~% ¯+6%2~(5b1USpz%52hfmߖ ]'} *@ٱJLAqȸaQY?JRm L_Olkejo[!2Ke|!nXCD'2:ɸkG;3{YI*S]z\D(׻8WSԤ|N=tYTT4ͦO=ZI"ΕP$IoyGDܫ v(HIU 8fΙڥ/o_R۸~mFq"$7kCϯm]X۴x׭XvՂAy% NvvTMd6}7-XLGK.}/ q( m8RsY$ՕTӊ>n(2 J }v5웣wVKҗy5q5LtVJ8kK. V3GzPiִtdS>'MX1vd3͹J@ ņ "j͋iey(+|Пthh(\FyDk}^Xὰ¶G,8 FÅj Lz&r 7{ԡo'+G!6Qeb1Ðl=($Զ 6+^UiFIn< ew~ثm!vkG^vZis?\(6L 2Rnb'qkud5 .wx^\96حMβ'yYD~)`m[l!_1Z:W+hCx\?bIh7 CWЛh:Z]͸7V܂q@7߉q?v }xyx{i1F7!#WmJ= W 멣# $!o5C/s|Nˌ;d0-A[k>fD*{|0& Ty1NS|ALS<>L sa>xvPseeY!#ߛ2\ǒQM͌NЭR]Ȫ)@@0FwC}lf-zvb?v +xWpa6x=Յ={|1z]PEׇS<5ַy+u#ߔDemb^i?NplN>Rn*m8 #WڎJ4B Ã68J,K9fPMxuG(߄ovJeާS'7\JE*bŠp`pp!NQ{E1%q@E1IxWLb(l1SԈh!IT-!p7E6XMozbh \#Zb jiQKHXֈV\.6Z2rƲM\oGH]>s焍lf3ٍ:x{U )j`T;1[:l.K&:99~QG1G5^ P;!c2Lɘ@+2fc69\ggy"MX^gyÏ%释K%i,RXp,+ux4˪ CBM^M4 RDBe `cf5EuC̭4kNi:vCK6 ;LT+xBM#,GҦjs_Bs4eϙc4KB,J|&5SeaȦMr̉]teHifi6ʶ[Tl.f[jܖ\'gҷz^;SI ~K[Uu#Y'r\ͨ٧;bqܔӪe\Zρ,>թ]٭)D2/ҹjk957]Qj8TlEl[Vł blsֶtVʤ-8I3k欸9xv7S NTp %tm3zRBO%S`.#t%f1&!\ zddŀs,},,Y.\`gb㊌<ޖ[˻,ø`2S>>p.,w!oIS5 ]a6:dpcf،psFwPN $BoZTP(aVPD*u&FWZ8Cz5$ݳck xU:$[0⇇JVd4C{GeJvwVݮvЧ(}%pQT?WUBHcpIy}[:5Q&R+ICt'hmx BHpz'R#O u#o""  iD%=9 s^#67InoM^6iҋ=n%ooۛ'>!n]x[9̝巐C}ncAIR2E@bI [O."eW[/"e_ [yPv5/Rj^WlЉxWmؿ-hdȂ6H1vй|]ǤYv|ΪGBmbǨvRη_{?HGESH a 8Qhoyvmy&}7PK{ PK@2proguard/evaluation/value/SpecificFloatValue.classsUǿI6,V,hbZBՐbU7mX&ͦ3/2<Gf|?śM8$3~瞻Ҩ>1 tpYGWue(r*G,YXuc6uEQM[4|*h6MgY Y*&fS:FNWBMY3b|˶jîfQi53<\2#mh5Y@bú}j:'|wlJۨ_q^Q ۝cG lAwciѫ ַl0fWs|wh6_@J-JlɊmVrz+9f;y˯:F-03vLh2{,1k59hMcWd]t74Ok8)Zmꁏ- d[{{XV,X¶!z 8EdI,YΰdXβ,|\{H hYmӑ^ Z2*HlGl9> :g!6$ebWݲsJ*نa;:V(^Y2(hQj֍6:zRp^P+u^wGh)c̐܋ӤB: #[)8ob2>s8݋T|t^êi]fUQoI< bmxĽ8.AU8b`9}Tm(ϒ^OD b.e`;Pb{$<{WL] Cf|4Auf5r:?o;U2|LI󛤫Q)|Es{t E="QIU2=2nvޣf;S/aA  PPu,Q\RY]#4ANI]yJJgȓ }zrU 5O)ᘴF{PK6#PK@6proguard/evaluation/value/ParticularIntegerValue.class[pe6InCP@KTD.*(m-DZd,&e)-7E/>:Ju}A_|_}_sگ_wRao;~'O~-0\!&QuÈ .!!47 ! ) %9FbI, qq $'e8Iΐx4ŌU XY`nqՌ& E }L5cub*QK5%)' ӚJ =.A#Sx^)T(i(g2S_d; ι WuT |ht(tfآI-L#wR&'pbژF)wGQvTShN:XauQ]<;2 ݫi-) է宺Cѱ21NRe➤N$߅iٙ u.TbZZ4T{]Hy^7ëKwY5-"_2 U&2xJ:k$Lo==7J[ȘQ5^kB7f u6`Ke ZʁJM+ˡt®Z!$[Itl#N""AdI"nx]4CzI>/E6I+ܠ p z=x anz|`[Q5hѩ`YiLJT}%~y|ݹC(wê+ w*4Q7=/ݜ~|n `\ړJ7i[ "Y[Ǥ%ح.)gO9n- @Y _BgDA ?p4r23*\Ȃ#GP[YY_] bPxUQ6V.ནЎJN1USQ!1USQB6!A=O@{ޛb}6N~jX}~K]{?gs-.Y{e9Ky=|Q{g=b>yWW!^a;#h +|`};MA3$Z-`" ̂s"-Ē31k?tE<\'`TkJsɶtYN嬻bJGl1QYKDIeI>S\5&f~:HYIʒN 6m`n! ml'kؤe=r_p;\]Ί}8 6:Yè0ǖ@߻o]>@so"Q`,~7"Ͼ M`GP<"_i#<(PKBԃQ}PK@3proguard/evaluation/value/CompositeFloatValue.classS[OA]zcX [rԂJ4)B>-e Knm~ob|A)&gnZlw;swΜwSHf8rߜ!<' |b!(< ,q3J* ]eVmʹwRMRC oy׶fvsdRiVzm%Joq8Cgdi D\jZe_Oȧنe*|+c,[2Læ7%aTk_g^;+ymD RH;єf({GzND_Tꡛ핢rVήCD6%^:b(g*}UlU [li'swqO}DDCH /DD 6zހ$bI*,"bdl_,W F(\r@mMR+usC:'DKԶO]+1lć-bM|&~ThwQ 3Ė(V /9<9rg?!@,E!ytӟ7^*#!.qE < rx] .m>2!=F8~j9 ;SQ$GHUo^3,Jt*u{iZ7Έ~PKW PK@%proguard/evaluation/value/Value.classV]sD=;I~6J1%nBBKqdکHYPfGΏn8J9gw^I?V0c(C $8vXCEfqLaWC] ?hhhxY ?adԍ +0ɺN_vODe[FfL$ӨJƎW(ՌUX.C\%rr&39.nea^*FΨN3\[WklP.s|f45\+Hu=d$W Ѭ Ej|ߦ̼}vWj Ŏ{kKJrr ~7PFx}u*T]pI;kN/*,l}Y2T2I7t{Tp5T=y%nѸ>6>l%uzæ]U Ύ*^!L^TNS>5~.-DXK1HRw.mztqq+W ] %cNX7Go-^SSMe2H>Q/J.Q\CODTeoT5"#D1:D-R8DsoƼP0Ĥ^(n03ze(ga^z(~/¼&zL :;WWunR/NZˢo^W8}ץP[_Q C]s+w1(PK PK@1proguard/evaluation/value/NegatedFloatValue.classRMo@}qb~-m!I=qIHHQ9Ujod2vpEJ%@BQĴQj7yofg?TlIo[3 ϱ-/%T5䱙GE SŠuG܋C^Î#.)#7 ~Wc2(1*P닣}KxˣH=c;b]0,s~=m\yʐ?gY|C(hFi%Ma[]Ѩ]ժXc:V`OoxBAŮGxL/nW lOOΰ;B/nm["= 1Ɂ;MxZ:/o2,)7CBYC0({,a*(`XIxdTnzKɍUBFz(Y'[+I f*d^҆2,5FLcrHHJ(NBYEmc>lׄd3xPKuPK@6proguard/evaluation/value/InstructionOffsetValue.classVoSU޶n nwk7Sؘ2l0xr[. DY`L &##jG7_ 蛉Ƅ=^YƄ~~?ۯ~z@ V`K<*6??/e^q^>۱CA?vrˋ a /rzrщcv1lfy={gv.ɓ:[bKO 4Ӗ-NWP'Sz,+k Wz/|(`nan0>C",Q>{x_QfsP+2[{ߐZs$۞HxƯh (bS?p J_Ink?'X)R>dUmG 5uȏa}9^cf(𣃜PJvaa޴"UVoGi@6Xj"Ln Vd`p@W ,[CHCu,3,L4vEL ؒp n08{£ydܤ9d Dgoq=fs.{UVUEd8j = Ŋ=33(_İT::}@h< <'mvFPOQ !QA {hGʧE|MZ4;)HICBz1jziC< ›OPKxPK@5proguard/evaluation/value/ParticularDoubleValue.classSUƟ%t(RZiZBB?RHGR@MI6l6Զ~z7/xMg%qzxlnLtz眜}~9~ЃO}8q/ı&CYkpKRFJBզj n Jt.Psňѣ&ɈfΩxlOiqբp4YՌ5Pt#SG,A 5Ric)Kk@Iܶ>l:J)u;d(aIT /4SMh2w[xXLBM&L5J!Hғd6aM:sXjU ^SKz*Ƨy`O䨑L&ٯ=vcԜӪilB5ߙ,?9DF/jY5p^W7`BMŃSu-j fMͬ嫂1Y9(v(ά5ZHiq}P2^g]Bo9s`.-d9N)1!h2edƠ3,,},gYγc`bᒌMܐ񾂛6,ø`2>T> pvuU3'tŸsWAWK{6EU=EV|⦭  $DwaR+#SѕQʮ*&FZ8EWeU4[4B5)4>[WhRM]GQKvo_;z;|J}"j}@/x(~: [:m8*T~Fŏ;H! ˶B9,sm!\gkG+*8|OHlUrx4c\*=)  ON.э8]')}m&h3bV'l/lmߤn0/PKs0 PK@3proguard/evaluation/value/ConvertedShortValue.classRn@=cܦ m J/?ڸ $RAnLW;_ A"XQ;AK$d܇Ιw5(a⑎ؔTlаaG] {Li-6˜b`6aЋyqL |7Lu‘{1$A9 :4|"lo (Sob>1 >=eBAQΛ)%cX5kYvԛAsOX4A%+$@eXG*˰]Y튐65G2 &e`{P?9m뵯˘\ΪDP}7Wϔ|^9驕1ҍD#OIۄv )^#\Bp{(¤,)R޶Cv_bF WPPv,\BEڠ`'LmO)ORJ)e}[3Q^$DŽU9< PK!JPK@3proguard/evaluation/value/SpecificDoubleValue.classsUǿۤtٖ+mi~4YbJTQ$a$7//3<8P(s|{s=AU>R!\V!% E<,,|R`Ʋ²u\ Ui8ugC&nR3KVrM] XiKY7K5zi O]mN;fm0x$%M&vcG8pEU8 }>vQU0L9uk*zPǫUEC8f{=>jߕY(%1˔Nok5ki+֎ V8nZ ߨe4ob7ZSmvdeN-Y !3/nxឹc5Q5VKDٝg zlr,$kv)ŭp< ϣ R0;*/'wEŅvP][-[AGuX,,,99/pAE|KwLpݲ\!ma e:qoP0=йh.q=X- r_\y{ۡ^חV7 ; 9X]^Y];!u\L)jp5E=w.}{8 F ɧP@$i{8Azoi#1Ex葄36aƇe|tgU%A e|DHH)Tr^$Mdvt6e6KfGe*i&kF0{Xfg٘$ f_ۤ#2kwأ2}6L՟&"*qMasql+K5zuH9{ tbd[=b$b|Ur|շGVFPV?xUc:(Ə^{ĘW vL> }I: &qҷO#tN8 CC1)}|"ʶ]gr XPKleE PK@5proguard/evaluation/value/CompositeIntegerValue.classKOQ-}QV@^)>x>a-"H`HeJ7|w7.4hb\T39s=s篯ԏ >1Cn6#?䫤)?{>M/|kv ^2jC m,5?^m*Y'LU@5{Q1~-O`,(z4p{ oo<rւmF# 7K,`S ӕʦnڳvv)W05v*.rO>>J;i\;1}\"/ٸxƃDC6&l+Wm|oߴ-߶q8lcauσc&Hb5uN  BϤ3LC):9 fq,҄5#H)!q!rcL _\c;,r&vdi TW03j,ejy5 S tX!:yao"ui Z6[<PKPK@2proguard/evaluation/value/ConvertedLongValue.classRMo@}cܦ@(-M[$zRJp$ԕS_ .@D qG!fS!Gfvσs!qzà)hZϩ8êiCVI+yriD^+ 1ֱp8#TI/"2 SчG*vg>gx/U\Ůj:ݞOnvWgaY/z|NKơQws䅙 3w.ܽ0s}-Z]o4Ңd!xZbcUOu2\A/4%CuES[do-rƩts*i6w6R&DzS@$X9֫el6- mBaߠ>&ycQL봧@Oh%&vSr VMm7tP`,mLꔺY(3F<}|fdٌ\3BSkx^ 7n2n1+0"b))bc3YzO( ܾY;9=`_ Ęq&.#X0+*ZCO5] 1! ejߴῚN_ɷlv7V8MЧu1]Gxe<0%x f4/IM>͉ͰMwr # )dM+xˊ#V1`E2ǭ"5^ư*߯t+lL:EA};ikdZlh>880 ހgh|Lc l44i8h(4:N¹3Tzr(mCzꜥ F 0O[SaUM;NΝnpMuiz}3t^JuWjx:UlGCWGƕ H~%TatO/R߯6jbmLmژ%3mCRSERi*'jvMT3Ut3$a)i/E%W1-頋ZX[E[@w!24=BX!{?"gy rG2 +/PK2Y0 PK@4proguard/evaluation/value/SpecificIntegerValue.class[pUǿMn m([.-mB hkW(R.Vpltl6" ^ P}@f7q|'|E;٤IfЙr~s='+@\e8+PLǤ%tU@CS?('I,M&'yi'IΐL%yJgIѽH'yE$/)/+ k:!Û EނIޑ].IPܬ"nP_$֓֬u8w -xYfS2LwDRKUu#F+P;g->bG,wN- 6|*FJZxMb#gz=ݮW5pf<&>iv2&%_nJ $T? ^3B]iQ}DߥpekiPTQ b'6Ilojd-F<4sx ԕrx7%}wcL .6CII'.$IDHzIzH''!>+t A9Hm$H1?|H 2|OB)eT9 έc5_pS+8qϧ5DۉQ֣W +xC!z["$+oR4ܑV&(+g\岲ı^pt t;>9؉oضLG7K˭PYŬkv{RMa//(¯[$VQcQHPUv] ^vx P>‹x|#C"p76Ky+61ǛPwB\ ߉;x- ݍ!f>N1[ɳ}]bvB%fnd=s%<; ݨ><߃{Ů+1],>kgzswM<{u]ɳPU<{O̮ bv ^d6 bK^![ųWX Bv-^E=(w^CykCbv^G= GDl7Q1[óQy#C[밁`&^987'(Y(b. B[\:887`g",k\C˟<E#Rh#,re E%RqERqEͥSj˝<CD9dBG(,x"#EXr#cRXʪztީwdUqU 1kGJ7o*p[[=ˤ&W5E)%Pױ`A"z܍=Fa?c? 'q';͠k1?aovcО`(@&o"zŻĻ*fqg{ xzÐ[5-!8>Òi#eU ;lPmy"/Vg` ,ⲁ2k 2,OO,DD4%<0 m:CR|K!Eॏre3OU5sMg%| 9CѪ,=GptBX`vz +VRFX#ܠhb$Pܲa1oP?1Ga *TP oEL>D&UY-`䏥4!=ɄLx+Qx=F$0A'Ƀ>~9n!sSgċ+鼼^,2Lq0xŸI<0˳tj14Y<7oW29y.Jݽe8X2UPu|Em6<0.RތS*GIEMKC_Β1M*B%\epIƦКt5SPyeH:]@};* "; e T\4@ЖdErAx.+ZE=yAZ@Chh"!袘aDukK-d27(0Ir%miRhm1*oR8$h_7 ]zKtӿhAM$q7qڸoߴ-~&c6$gq"uMk@g?2wћnz".c8ľc81\_(pl'NIx1Eӈ4btKUSzIJ:Eůp~M# RiMe^{\r~:/&OdikTG;F>u,d-U÷v&pfK7RNps )s?PK#PK@8proguard/evaluation/value/IdentifiedReferenceValue.classTKOQn;m  E))0 H*Z XCq3e0) ,6.46ĸGϝ> %9|=oư#hè x0)/t*^m: Bx($0'YyW3*}x#[XL,^H٭$Fk`Jt EW"%v݅ exPUHHGtXLl˙g蔣!zߺ~zPFmi6]OQ:#5F\!v,'(J!)'mtT!"Bo]}ߤ !W!BVjhW?A#-!˛ry'I+U;*4֞#T&~PK|#PK@(proguard/evaluation/value/TopValue.classQMo@M8 .MҦ@KK[zS5@HCJCowqrm+?.R$9oWۙf䟿}N560q&C ej; : CD1Tid O^=`dTzY1| yNg0VquSdk}ƃc_~39^G<9fTGQFQ<\ (t &&,l㾅ؘa0 OYK}P>0GY?`&<}h~B HXˋ7`ՂZ1>x; sM,<zV]Z`v?`Kɚ}i?$RKeW>"\F>:?о /򈧄+3/ň] ᭙Qv;PK)'PK@%proguard/evaluation/TracedStack.classVkPU~,,,躋"R(xC{{fԏjʦqrmr*44MMM~44~| `ys}ϻ0 p$o7"mzWPh3G:^X0S-3 *P(cn2:>UpqhuP(9cĻV}K=}Fv#&xoԈ-x!O-N# /7MƽC+}M:@ ;E~=ޭ4z3L#E{G}"1CHGq#, \ؚPKdGLͷMwq-cd+K3wEFzuYlv=f:kݖXhU,T@I/ϦrZ9RYGڍƠԘ_ jLW(5L4:!* 1SݘY=k#!sqya0Cjw> 㰆p6 hP"1MbY"YR1-@ÃxH5,r +LՂ֭FD.CڇR#xT<&Kw8N*(t)^n'm?,Σyf9Z+S~*n0ڠnjPdwY"DyĪvCe )5RIΨ 2p`5\^2wyF\ ~Ҥc'm Wpq3PH[+H^}  _mgXL|s>E)1Up I!L42Rm$f!=b_ag)T@)XI{fY(-3*Sb!%ig-.zO$$K^bsXIz`% 8 ?/bނ RpmI5ӲX*g7!N#1z ~tp~DI >%g/ئ]kVbt?'1_KH=ĖYaɌ%UK'1%~JJ(;%ğlu4ct2~>u/M(/e.RFL)Si҉Xj䦒!7@Z ARRh*^aʥle)l|U[~%/XMɌaGEʌL)e(3`ѵI'0/lH?8:N1*pv+={G&"_MFXIYauѨFC;Z^ɿ0!,6E3ߜ>4`bYmǤOuYN ĕ|S1SkF5HS'.%xKoF1Q(TsQ5+^yv}e>OF_Ղ6UiwkVg PKGOƗgPK@)proguard/evaluation/TracedVariables.classT[S[U9pzp $E 5hH4j vC&MISO3TG>&O"OhLe׷}Nh'fLNi1*3b5qzV ܎+x xÉ7CB 眘TЎ)buޅ[Rlf\x[I Y R\BS,laVuch\3r%0z4i \6"VztZim1%88Φ c?-3aK"'ucFJƚ1%}QpG?YLA~WvQvZˤc%guW|`ACQ2$OjZ$eSU}0*]״ 6mwrɂΦ$tO*VV$sEcIO ;j CCU VS9fl0SkuPn,噸}WM㨉dUmmMϒnl2*T9߫tG/?I /|pOYk 3aM\[ )9xJxc3 O; x?f=P݇:!N2)t4} B8W1i &NKa˿o 2Qw w @ ?hfj\1%8kS\A#߁$ދR4 V\VWm9)^-&aE *1()%|mA*M98_e(c ˾  =v 'c>OG.%hU|py 8-ȶ{;w `N ާ|nXЇ S`w ;%_䫖Z}'>c _0&__+,)4EM(%װ~ucn(M+['Y9Cȥ)X(mU-ȑ_/ )!>WFGvybBt VZC:Gp=W\³%t s[pVKtKn`Jl \f1|<;zPK^D؉PK@)proguard/evaluation/BasicBranchUnit.classTkOA=uy|",&4T XH 3eq-hjM(򰩋bܙ=s쏟_I$q]n i$i7ᶆa # g[eh $Č䮵^,a,%r˒)S 3X Y\[E)}۵ 2C,CKvBe(dBKAUGu{*$E)B !&ӧW|3Y0,U(S7xfm@QL>ǩDD&\pIäOF*$?b)_ ŋTGQ"H#DŽ\FWuc+z:N3im|Cl%GZ4Ќ(U9 =t)N*} >ztU*}G _PKr!PK@3proguard/evaluation/ClassConstantValueFactory.classRN@=BWŷPw7$q!DwCɘښR_H\~(]ܙ9q=_c)h0G1B:0 ҕ C![FuKi@znª*{*Hɫ ɲty&K^s1CٔAfswڶrHGXXLNXx-ReMHA7TFUiX7M[f؏` C62>23!7DLcvpeϰ;\ i<FµEp-h[ |6"1wi-v86H;wW_ L-63/=эVAVoY$#dx833bf|#W$^|GLIPKW{yPK@(proguard/evaluation/InvocationUnit.classPJ@^I BqqW6 }.O|Jܤ*{f+ ˓/ޭJYs*Gs4iې]+Kl o(͹ C~5yG: l#46rs^RDIK .}'mdc nVPke.7k Γpn(dM)\MT8QNvݥkWP~ݞB= #?q@N` PK|kmd0PK@$proguard/evaluation/BranchUnit.classN1  JeiTT(b`B/UH4WP!`aă[wC 8!g+k`nѰ4^?jv;k!x]6!z\.tz@8:;vA;Ƽfh!}BĻ[jWi w/RНK5G WoV7L8a ӒuER v!ʥ!':He,}8h0itvcPKξtPK@.proguard/evaluation/ConstantValueFactory.classVm{Tt,][: P|ۘ ei;G{Qg e ]׆~|I(m/;?C (,>馄[H$s;=e%qM`6(U%lIN~uQ+{fVqm@Rj:v9UUg3kؖsԽ@fF X9Bgn HX Ie*)̔ Kn7ugW7)2]YmZaj3 1Z[\;Y\@q oLoY<(V/pwR gy><65/PT`(Pv#C+ q%OfULFH! p@5@-[ Wv۩yݽlud,[K$⁌x$2x,;|/OeTPAMFOElLsfjjVo &~ܟ7\GF WF?py-,K $C6Z6MӨzu5v//CEքFNBmܩT&JalGhOapuƴނk'3z'G\g9X&g:*J4ٔ/(qG;'IT$:rlts OP_nx"79PKȹ PK@#proguard/evaluation/Variables.classVopW=KűD?Y#0IhmI$`I:IIp)w6-%R M0F0t0L?v+_Z=e[t{owvǟC{v=x܏:&"d2YJux\4)&i oH @ ߒPY&9npQ@6co3d&a'x׫#wԍ87~8qD4LK^Plynj8oj%9¢Үbf/25N˰ -/N23Rbj,`T-QM@Vͩ}=3gx"]䛔UmeJy,0I|gdd]i'ZPҤ(#9[ͪfL/iEJlY%SRZ[IetI'@++)%NTs%=oLXYH1g4ԲłSDKJ\Wr5eJ35S16#]K\& t<"I`cWdCh8-:.^|~|O5||ɋ]W~f՜}rJͳ1JW ʣ@Gጩ̪a ۆf]Ox?`@h*2f󊩦I$l3*MRcN8$;/x/ Zi (pZ8wh-VO\2Q[].^-أ!K[k,h,F#ͶWdqC8(xUO𚌟u?e2/d2N-*Cu6ou?B[dlM6Me қtu¬RTlJ>#Z*Ϊ-Ռ"9g,=ewr M\[I)KG&lf +4 sJiY[61D({Ms4)OH)SjbTrQ|ڪU{*úbQeoZ1<SëV!:C/&r cYi2Һ #^/56G@DC6*bCsc~#h{xʌE=fP%ts$JM7WG z{[QFs7A x$+%XKmt}k_{ ysm8ɶ7Ps׼b?O(=F]/SW$o"# x/:^*n5N>_9^R;VGS0!:T } z-)u!e-3t ެ(SAߤypJ`|zNvAlpR m0?=]1r1I A$0`n7E"Yq)=J~VWWDwT❕}UķW ?p|Dm a]h;i-|?ccnωl/羽x k zi}Nn zyG}JĿ1;Yf d6w`sQx.0;r]l(6pf#<7^Q8;0|28f].\l q_wcXȬY p3ucPǩ2_$"-bHA7/EP >Ziԗ?f Id?ė G.CrT:y&Y"P~P n@R`ٜhEvM!J(::lGGf~WZ$DQmԛo\rU i }"v B Ge@4/0$ϡFblpw~^38I.G"_4 LEɜhqRT;0\N.'~N;8v":9n[b1 %]n.]7-cogߤ-Q%F^8 pr?<#]'|&T`Ȅrxa !GLx㧮9; GrTۄNKMbL2t/&^3Mgx%6q^e8k0ҹ,ױtכxh?qlVf13]Ɛ금:%:.^Å3[Œe-clc"􅊺S@^VZl 3Y,gl9c[\ZZZz+Yk\{kpA=ȵU\[ŵ\[͵GGǘa8Yqfkk:>azܠFzMYǧM|5q >g/ g |T(Zת(CEbmQ)PRyI6L܊/2{ /1qGo[:n7mwHL|?0q~hG} K ) ;qs7~n{+_ ~kw?&~ŸMEh'q9o&4q7vAf I*{0oCSr *b ?HZnBY+E^ ]M%)M14tUAhX4ٟOw3d G]mAJNu"v2\/j8亍EwSC~) :guLrߕk%$VZL7#;4F9j9KV&X]CE}Vy4ɸe<$EmYCYWqpm5(}.uJ%lsV}ҦCZIfLPǴ;NDT_$,7+@(M()S:bѢ墩VQ`O bO~J҃c,ֹƢi;25_:QDE:BncuR] ahQaھN10<\7Kc!TgSch$H]( "x#@+D(--FsQM(*&Pi(/K_BFf:zAa%:]ՖK 1XsK v$22vQU{`J]#ԵZ⋐MN G[޹)K/,8#3­a[M>Юw9?W*[?lZ QwGw{'ǦX b G6ٗB[X+a%Ј?5P jxH#|x\ka:W@x%J@gdWfwݹ.fgegj. {+\CO?RTQ_)ZQΒصIơ"Io48-f_&HQ',Rt$E8Y -NVC's&?W"NV9R4<)duuʕ"WU.`L ')0mKK,زlnN$6#Pb)(L뗂Xv vĚcD v1c} 6Nb;9$΋EKJD#U<8\"U;K2FL#h5QPթz@um=LB(ǖ5p(Yڲdi-Ҧ5+ lz"/=O@fqTazVEGf=Y0=a#0є8'Sp%l^OCS/S~ zZ.e|E\ Sj{SRLPA: QP0Y BH aj7BzLSr\}f Y>sW*Z s/:{k*ܠpn2Vܦu{^@ !Hˁ%X{5ܧr-+(fBv%Ү-v7<-ǴeF[kZzmƵ'R `lހvxV[sتm^׵KvLxv:l5>u ]K`k"|{\׮;]~r?^\=u tQԧ`z 6gaS}6Ibl/C^Q߆]E{4^;y88=Hwp{q߈8RNpI0߽ ݟb{Nv)d`sF<ݱs*yi8S{83ūbGq\kƸ$Vqn4&slg?p_yv4|{:=1bA;?^;wg{s}w~}x7]݋?zMb6_Fyiv}fw<`x*9Q(f@fPfLkD40EcR417-s4fGhmm̯EzE{کI냇X :Tm^.."7Ď;tyʵv.+2nv] vT>ETcu*r<@u|vلK;ϙ2()|VdPdzlUTšLjMI&X=ӘM:dEo",Lܙz9*[^ha94Kig'^37JT/<8\lzf[AcnHrha6JHNwE/02<ˠQ$5wg?rXO|R AslEgWkDX'΂E?xYO%^q.6cc1[8^Bb&Mb>%&Ӣb|SLT!EwQ*l"U=HJZ.^iEl=sB}e1ju TgR #D#gc4MA4/"G(;*odz=SޮA{Z&CWIH9dh>OЛV*^[Z =P+ ] ]'Hd*ϓತЄzN|Rd~Z?4osZs`8rL\qr7*S?C%+s"6X/WJXT bMS^œNEQ<,^So;jP)>R[/h R&7 dIk$z 'ED-!۹>Tf&|HlU8pz(4:w:̷tp;meuұ=-v{V8v3ծC*ҠZ2bFmmMc,V7HϠ‰~ͦhN8{l-K-nБk0ķS(*~7b؏ NUKoS4B1 >4Ƹ_Jh4m֢V Rڋ(R:.X+=ū T+v)>eQ)r^Q\2JG>.dwBWzd\Cs{e0{3֖N5\w+멫LR;墟;y?J k6mzHm}ƭk^5ޓnW"O}!)DOsʵ"1:&cmCX[/RCAV @ԣA< Q T8 xNW5 HD X(iH@fJMv6#:xezH +JTRaS9|]J/X9ӥ` E{׉ . 6U7I+ج*x(x ~7@]'K$oq`h )gVŎ` @ԁ(,}:~/(`tM.tY,rtj.cnh'd"ilqG"2\) [Thlov6uuL)s$e2 evoQRf+s0e}Þ pڮf]k'˘.3Fl32ױI r86)lIq88c(MJZ\e)gݎ!mҍ[5l饤3IrJʖ~t;\Njق ,ܬ2.r5u[ QyE(i,K! .^0kz<_ IY|yK/] &b#qij\C;y/Yrcu Oc8q8K&/80!W틄hH!!.Sӄ0`ŏ=m`Hc"x SBax 9wN[>\9ɥmo\A _!Tf`v?dN(eFͥ4Μ1Da}%W>e#>!AL7_ΥQmbb+-l]"j+xm\$֕3҈ ߖA+R>℅[quȱL2Ŗi(LGs=2Rp1ܬ1ޠmzÓwbg s>d8鳆щ]dL\ٳpYjPbE`eJмj|z}37~9Uj\-PK C oPK@-proguard/evaluation/BasicInvocationUnit.classW{tT 7{s^Y6ȣQQ! l. nHbZ@@EmZj`<ԪEK}j_ԾNO{Nϩ{fwMH鞳3wf~ofs` !P.h.a "R;D1>B!vr^^q]]\3.ݼ,/縶~ ~.z=$z}Q܁Gx^O£ϛ_)|+=ȅIa tw ^<"xJ1OxAQqQzwMDY%CՆLu{dCmѸu08蚰9 ͞QJ40;%=۴ZMcvF-nf0v>ܩ-6ǻekz PLת0Q͎m7bΫeҮLj$W%a6_A4 Y wkUn$ Rb1]trdNX EczoPSC ŚR}1phQ-֨N]ݖTpefVUex > "m4/tkJdQlx38c;?Su5WS8#`ãخ(A%ѵP|ܭPE%vILbbF\+*@Hו4!R%l$ܑtd3+uSqEX^ٝ4n#K`K̒1-t%~JםIO*Vk7Ѷޗ%]y4VwnU\j uڨt|Ilda1_J72>_U .⸌oYߔ-.hEMX'2fnz?EDO񶌍h3 w ^oq#nKJįeEV{IDaFq0a ˰~K ڨfPQj ՒbSNPa%E4[.Ͱ <Siʊ3# Ay5vYv&|fp b^M~^82_E;?|DHVr]#% W!Jy51XiG:Y4# RgIS5YH#/f S{p乔ŭ.4b.nA֢-6&mPG'PFvb;vSk:øRxh|)POBU"F|̚A>^'G24Cl0J+ܢ &{}C(9L**4 ̡Y}sd "Cͼt \b>K+CohGIIނ[-M\Ә_#~v1܎Q;FGJ jG^eڏbH`a(m{2Lʊg"mh_#(TL ZC6IHprnd{?; ߉_(&،`K? ,vd)uNdnzKkX+%(V0r!3O*V+f,z [F` fы& a@b0ʨŗCx#6Y͸;&mF; -[,- !T ulDU8't.uJ6UOQ׉G:ۘ=||ΈL[iFQsyrWUϘ=˰=d#tLF>M' bC<@=[Hz' (#ghӸjPKph PK@proguard/ProGuard.classWy|>2aC !\rl#$!P@!@0@Iv.{pxzփ4$hZжbm֪֫VYmVkߛ A?zo#2t+8bS=BzLxā>P*ac*~)t<.=!{K!O yJȯd2[!yV6~'dd^d2zYF(vUYv^su!(xSLU[7V9݁wHE2_*Jd^H?T,B>qˁ+Tr99yp}K25&84HIJVh9QP!PTp˦S4mvPB2TxvP*eHFwƨ4Np8x&n&ܥ\2IN=.P)B# u5ՄʳZWօ_BZ kp MDӤ ¨ i&Cdnc'j-ڒ &i5Vo2yfs, D-/ON,ۺi\FYڨQ' `WG,u7:nlU_j%E+E ,[Z7%_Ӕinbvݏ84S.YĶ{p|ߒʫqRT^N8Fs*J [V+IZR%YZ7/F|5p/aj-;nNzzfٱA=SR E.'mۆŎ478>wRe%m uvw_nԬ=4w/f |U9mkV7˥x nNcpۉ{y6hBћ} !'ͦ(2r/y}fedK(w oa'Кi8ss dQKfBGo9>^9nt!,GH3k뿝{!Kp&95Uf6RSŞYYȁ㵿zsbXԻO"⍄ڤJF~9Op.JZk>ӬyWx E^*{OַzuS!Xi`#0:FveC>lX|UAYzoe=cp9J 45XoW;xI|pr0I;|p-ӑF30&O\&˲X4S*iBp ntc( 4giG0`Nd!Az1w"y?0d>cvP.%Wp\EYq-F')q mm! J,m1Q9M I9;҇wy=ϵr3xQN*0!dsy|rTUXHQo|MMb_wCŽs=|ћyyMnk>D֬s˟d X2XpA2)@@yAs |M6H2%)@ HN 1o$l\nyi"@i,fKd)fҒ9{O1K, 滬G|>)8Q[4ekxl5 ECc%R{u$!URutaNJeqݟ< JGLi(thdwjLj #~n~ b 6ʥr[k==fʽn YwNrU6_lJtꘋWY.X_qFcQACeژd!QFr@ʰ*ەT` z`YÀ bYbӅDM1q߶`(xG7i鯏DX ?xk, SŧJ0j&aþaY 1.F @]tV󷑮Lм wYC1>S㬝ׇ>x!zzE )l>0EIBf!bj.DhxaT6uAOwwC;8`wagӑfC=id_}|'؞'="f}ȤGYx_QlH]PaO!-YSiGJ5'߭M>m}8#}wsr^_p/Z-]|zQ.¬<#STN&>ф.g^j'`$o?{dY囍%d`z"%Ma6;S=/?@ }]ΔϰyK5APKSv PK@&proguard/classfile/LibraryMember.classoPǿ sc,#s: EM))v-i7h?xni&{O>{=_&!% (PQ(MEDUmwf5 |56$⸦yG6[;1rvU-T;kڃ:7<5G陴j}m I%'饖iIpk=*Ҝo7_inv3ucWuKc2-j/tw@yq` 44`$؎^W>ؓJ1c\P8cW7L+}+UX,c+2rXa ȸ g3;ðưsj z3 HQȴ;")7\ @Deƿ3؇LQ")F_} W7&H ¯kdQ2u?I@]fyn#%AMfD&GXT/BtI!Utt /!^QecLQy "i4ҤPe7[?PK QPK@6proguard/classfile/instruction/SimpleInstruction.classVoUMJ lBThPca؝nG,Bcј $&5<Il_?7?wf]FO9{ι3߸ 'h†0G!^rPB=Ɔ 8(OU,vaQ8vٮ ^ d,XiI}iX< lJ2L}8~RNfhľ/6%3FcC|6]dF+Fe0@ٕ0s=^? N,E/1HR32{rI<3`ba 3v߈w u-7Gt;z)oXkf_K&]Z61[mgneSU4'3-3R9e +Li1$]QIHU*U UhSڊeDUfH0aCM{pW.>E|9WirSEn\ ƶ1@:w-pﮜUs|,W&Bo"|x ݷLcCj 4tiSy3?uNn7"21~ *.uM7xď=NrȳB|#GLjSv|SX&kxP0 $7q%Dd{r"sD7 gn~YW\WKe<seieᄘ9ޛlrZQf"J`nIPKɞeT PK@6proguard/classfile/instruction/SwitchInstruction.classRkP=i}uU͵:gM/ D*,MjF4Q&Gau(w={~8PvXM!

    tG7T61ԑw!&(cZJb04-[GHR7ڍWCj:Uh=u00̞s}3mKi}1=S.]}AVaAjGgUVWDJMhW)bAD׉|Qm'RSݮ$)#!Sdž vUEN؎<$S:nuҤKƍJ/s}=V7O_8&RӊܥH2eQ[@SLZ@] ;$T9?DD^"*WOh@!f )l`t-.VGJʋwD(ע#9L/ OyFBWZ[?D&9!IBaRFL|iF9pF \ _Pfcrk"7o/qPKY=NWPK@9proguard/classfile/instruction/InstructionConstants.classme`׶5{{;RܦpRFcƱ\N⒫XD]C23333Sڔn{{2sցzY|k9/ֿJfu4ƴi-:N`:$Na:4ә`:,a:<.`".a2˙`*a:n`&na6ۙ`.a>`z!az1Ǚ`z)az93"^fzUט^gzMfz]gC1'L_ekL_g7m0}{Lg~c0gL?g/>cLf o~{?0OLf _w0_Lf`aa 8導C氞Np"8r8Cp:q1p)q89܂-9܊í9܆m9܎9܁9܉Ý9܅]9n,gs8ù6p8R0<.l Tm#h2$W+SAj2:3vAj"ܴs5 7Xaejcʚo*k/c,jS],5ʲkZU8%HjJwdc31͝fCQR];t{~Bě8nxS-o1Aj|;͵cb ؃R;;9:[kǮv:jǮsڒu׎]guvԎ]g'$.ڱL4&ڱΞL'~fcc3bc3Zbc3c_]1ͱ1_nLW1#6#6#6#6w5Y:ʲ*˞,{Z*ˮuhejZMUk5WYv*ˮZeٵͭZPeٵVYvte:YjEU]ʲk-ZVLs_uNSt;9qzM%y֙44H9c7 o=#ataX<jqvl1nJviGtcu1r;~n`Xs=\~+\%?J?*?%`Xs=] s=G܎G\c~5~ǵѹZha]to2xB>z<3-ⓣ~-DߡS5t_~i>Ng.sxL5l,PC#j3tND-;iH:/"y~DGmˆ.v^o yID҈.>K#pEDYCWm^i*n^wh z#h5xCopzSvqzρ4VU[nivm=Qeٮ;&ڮ"1r{}{=,k/u}^ @b/̢~?18v<ډ%Σ8Ghb<^vg*yy={=ҭ|YhTXYԺ$h/glmN;Ywޏw\Nwtv3^qi]j@]]zS6'[;tۓ}^ؕ6/lm^dxͭ{fq#m|ncvvݵ4b 54w>|֑鈼]g~ݛd"پ2&7 Ύ*xbwהɴ6ab4/lDOмE#'Gܒ5z[Uva "3xO˥Jiow3PGfeKWxr2VFt֗3d܆d8/OxwrB9YuIC>n]^A<^:A f0T_}͹Zg^hn}/墾ڒ?r4(F|4EѠ?Dp  r~]n876$Csqr[NzIo1-&Ť|қOzIo.%7֕+ǣb<ǣ\OS3R_I} RS_k+{+⟀g+?J_+ ?O?+ _+p` 8T\\ǃ'(x2xi<]FoTf7oxKVox[vxGNwxWLŻwWxOųUx>x/{Q/x?P| Q|(QqYq Uqx+gwW*(^^xW#>Z1>ǂsEUՊ+ACGU|'*> |S*> |3g*> |s*>| *|K* |+W* |k*|7* |[* |;w* |{*|*~G*~ 'O*~ g*~ޠ%ˊ_5-ۊ=?#c'B3H?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!I?!OTB13 ZRw9C=Π0bT@ǥROO?-ކT e{k$loIm.;VZ'Pz/dtLN)2:EA@tF1t#l D6n*3tslRn%@mvme{vt{Qv$@w]L讲tM.{BY=e6t́Ζ9+ 2:OΗ{>нe_>t__ A!ЃP!=T mhB[ * m@Ѕr4-I;t,Ktd N.YhtC%Y ]"ˠKLʑ#(r4(9zAc}+ˡ9.<_ мet@JZUЕRвTeZ!aq2Q舌AGe tLB:Z9NN/'BO'Гr*9 z흖:M0t9Ӕ3,SΔM9K1l9הsSMO0~yД!SMyH1ayԔG1SMyL0qyҔ')SMyJ1iy֔g9SMyN֛`zyєd)/KlMyI^1eyՔW5S^MyM0uyӔ7-SޔMyK1myהw=SޕO>xÀxVRF3|PKC(+PK@?proguard/classfile/instruction/visitor/InstructionCounter.classQ]KQ=w]]]-++z)rDzkݽڍuW_?z ~@?*?BɅ;3w朙3&te@ I'| 3 uΐ(Wz z+p9C#|~\^}2!WD,LD(ThD3<;c #[a8Z=6*\nlVJ~N?F;,V"5ANf7/lZu{{bF& lPFJxVWƞYrQSf i &33 YyD6 _/4%E>[!~ m$)@)ev(ְ PK WPK@Dproguard/classfile/instruction/visitor/MultiInstructionVisitor.class͕[OGa I!MRcn %vF H8*%%,]v.-\DUPEJ(7(mr)";Row^6qDуnŘ QTF&WdsdB/#bb~in~>8;7;K@\_28b m^P-)Yuw@BsWMUl^_l3kjmT<-0͹ 3c3Z|$ʹUS`9|^6[FfW1Q6f5zY36eUEZ"_t̜鯺զ)=,e}kԏ8Kg' ~N~@{SYmҠ*e?XmM*~M6o!E7*ז< ۷Ϣ5cя'pRG }:a@`pudpMy|c:.cqIe|#9B w>i ^jfV}Mͺo t򐭸MDpؔ)afE gЋ>}ׁlwNQ85̧7c%3V:G˜~f$eOvO$_#~m8k; t e&9%%P9C[ -,rz /irϰܿ##_'':eA{!Zf [&~CXyt,cMq&ªem* K Jz,<NwHӿt|KV ̐v!w;䖙 > wUrW]c0h+Cn\<pn#n1í{ފ{ܟȽO$vJPKko PK@?proguard/classfile/instruction/visitor/InstructionVisitor.classJ0ot *e=KO:6n)iZa/" q__~ɧ4_`=\1K0͕,"EJ|:ʤTn< s <[嚩%at_[cyg!Tr._iǶ {~A.%MI.Hedž|[%kvH̢kw}QȈ]ÅjP})-)?Gn}^tބS)q+h:W`:&7ir ۺ`G[}PKM -PK@Bproguard/classfile/instruction/visitor/AllInstructionVisitor.classSKK@ƦT<P(I+1)ɦ`<Q$jX3}z~xPƒL aReȘ1Ǡr/Ad {ur VEf`kaۯH yap{\T*Y3HUvFksˆ 2 !ވ{U]YNSTMc.qG8|?y$ʉs"~mLlP,@ƐȰg{2G l;n}[VjIyոH|а,%}O# ƛV9(tӐP{0t5 G#$Naʽ%B~c`(`+Dhoֵd (6;s PKPK@;proguard/classfile/instruction/TableSwitchInstruction.classTKoU=׾iSMbGqƭS i"ᨅ"dAxxb)%Bِ ( ʹNmHY|!"ӰB xQyY&+2=Ι8o(`6U G 7}X[~"ϭ ՠF5߽7ݍ&-|quG;U@;]7WnS޼DaAk^jKsGcF>(Md5U$^sC?Ʀڌ.qE[zHS6Ҹ>Q݈[Z9l-GA8:ZTRsoݰ]P3WnN) `UpLIE.5 c%,ZEKwp$.7&U},pn3^wwUȲKiYȉm9lFŅBDpmU!vQ#TNYQ#_60++Y}gPK)wGPK@6proguard/classfile/instruction/BranchInstruction.classUSU6d [V[ $? PME)T$du͆VgO3 :0#팀}(ܛ-Z{wsww9d|P:c˰/FxD1EnŐl1lI4c DL3"fD2E#"]/ ,Lgْf <úۣ9ㅌ&uZ7rJ)w0BSt*ʪ T͒mӶ^0q~T^<2IfӪ1[L(8][HGEKS3 3[ BEUK5443gIj0bRiHZyPWWc,5;_5m驲Mi[,<)+zI V c:D$.3'H]Qj օH꫕BvK[Z&~,69}" 0$n WqE Tcʕ5Ӿ6x9,+G 6)-@h %y Lbyܓ:HXުLyDl+gB \hDJ%^|(a *q.R\AZ9G(@@߷4uh Z,jf4;T+ΩFN!9btX0Χvz5fe z:AO4$^.n'Z= qWA@{+sU:R:pG#}FЄ(ZO )_b711!A'~5P wIɼ6k =7}&KCEvF^&u5pyw "SX)s]\G8r)O߁/nIن63-ېvp*4Ӛ$s8I_D/R5`YL";0PB"A7V%I*Z~EꗩVȳ N{7¤S̲ɚI6|NM%Y"\9i/?k*M}ځ&po_[^VWkB"E2L)ʻcmUwpL8$ 'O-C1Q3?wDCiC^i}^zשkk_=:gqPW)[kllpPK% PK@8proguard/classfile/instruction/ConstantInstruction.classW]x~f7!$ "MB*T* $jOfff(jRmմZӢ$AxzeUۛ>M{ޘo YŜo3y99꣫ d!LTI0d3`d0ӇV8G)?)Li|_WL%cx{"k|`d8x:g2Էx?],.^F =e)c) RD?ÓPTLeRTsRjR$TYI5QG5kPQ >#JX7PzjVN$ rŋ'j$% &M#VXW4RcZB 34C˚u"DfEе8 C}dTj C+""MUE1=;nXYLz'wC6r%U3~%ӧݾTq#I,S;H|̺#+240]:jُ)3Ҝ-˘̾UөqG`P-5}̺wgrIY#t z@ovPX>*U\^Xcwߘa9%oΗ|0\MMLu,羒JhitN1Oʤͩ. }d+9DULqq7E@XO3D7o^"CjrAag*tTǝSN[MA0L*rl0ՇӚ FUkԻYO&w8hGN&q2bLƘ%ܚ6Hq%kӓn `)h.K%ޓqȘCTš-u^h*a; of$\.2BF(PGc8DTCGD>'T$[wv(gr:7h~^4dK2us_?h\c.#2216ĀnӽNO;o ;VswPrUtn4]C5T[\;p<&2?ho&;S/|w.oq/I.I-gJ^gV9Իz*AT*ɇO_:Nyǭ\϶pqDm\q^?u wKٵbaXud&699ºLyfU2ezB-(&W_#c}z VpƳPw;Pث,mPK&5dPK@<proguard/classfile/instruction/LookUpSwitchInstruction.classTKoW=~fHB IƔG{L!FCByd3@̶ZNK 2[6`R hS^vη9Κ3KSI׼/禛wmQnZUVӞ7}صR7>j!m|1/0ʤXR$7[T}7p:Ӹ8^li;TZZXԼʺOV\;`97Qln <H3ahBΑ}9J 7rۺkEy@:tlqD88tX:Nָ8I:%qiEmjjARzna) V-2Z$!dgfYeß BI:$-e?zbSUvʸ U's F=(S͡DLcQsx9 ֭$xWƐib;xZ8Ō 1#D$$uTRk:Fh؟.dg g[;+.{ɚ0Wzâ q~9)s}(k-Lv .,6]㷯1I0np0Gq58i}Өo`,GD߾)&jV"tY=0Y[lUŃ H솏ڤnk+cك7"0 iedY}?Y+RFJzb8O<ڟ-PK_ZPK@4proguard/classfile/instruction/InstructionUtil.class}Q]oA=튥Zj-,aFR@b}mR u jOf_|&2ޡFָsٟ}PMROኁ8ri\vAS>Ema)),3$7[ qxy0H2췄-" ;E]yRXȪk F U[?א@~ล#gpVo\w+ v>K'I@9W ]|/B@ o2(`E*{ %_yv`%u3f`Njv@}_-kr\Tiajk:N#u>2rwO L_),2S#2qpӸH_ƍMCGx@(¶:2kYȬFf32":A٩!!R49CL`f}ܦwGelQY;=S<^r7PK PK@8proguard/classfile/instruction/VariableInstruction.classWkl\W]7;~IcISy8-N}]wRPEWOiG; ~BBB R!|szQh@[3̜3sg3sm|0^da1aN1aN 3 {C O\Tȼ|sF>x)~G^g)U4ŤRHW8_+ k6k~cnδ٠]ﯮ6ˮTʹa!>trUsB{-"ubAB`̌|k9\=qߟm|+Y^l7HŜ8c7RjZD g[Q8[:* dzk7@>@5v:vQϮZ[[or5Ð4qc3F#q[Y<qˇW]_oN]w!w2|2haG 38ČcQGP{^F|_>1 XAFTBI44" 8$WiAjפV8_~S^/W*s%:lq7WwsAI'es\V;=ڼuy|z9#LTS(,ߖЛ%v a=Jx\B+Jv1i 91miM99 9mONۛ5&:nx7G| w|DU5Oi98y]_AHM俢F\V_%Oz\$;ב"HS/0e^Z{>x{:KZ0Yx%tNS]%_Z{sެ˨{o`)5n`#o۵ |+_9*\ VUcň _ #XbگUԞyڙUׯ`޶Vи-t|%M7K[b'73VlR"{Xu CHxVurx9Dh@",$Q3%L%{~UW"}WKМ*j*R :+~sǹ_r|t˴*6SL;(~x[+w.NcG=ִ5-̍Qj W /I~RN PK|xu5PK@0proguard/classfile/instruction/Instruction.classi[;@F4 ( A ("B JKZkmU[-Zv߿9o F8WkgyfI?QꈣlGv]xS\n.#F/>t Bꏧڋ@ ӧڏ 8dB<阞5dmꨮլni]!mv luƎjks JR˛6U.4U|PRrZ4z8^{joۻKCEy}~+dw;<@q?}\~w)ɝ=;CAg1ΨrgVVz2 Ui(NFX g_PC&c,f3뚰j>ⴄp44Ͼo/ؽp1/ 6w*Lϝwt|}L ]j_ˋ?n dޅo7CYS]-vOT&H[TGI/P(Qg:N -] \'Gm(Qlj,Qߓ&_ps0Eܵ"H HO/8deH+HhRPUױH'$8ůoHUTFz)OF*H`iheT]NofO;RP__ҏk܃NKގs?kF CfskYK'c~K twoXphk&MCf_ϗ"g϶1R+܎&o|ѬNGpܼBmvB{_ۥ_]3}z_N Pim3&:]&qJ&߅߳9s. wL}|.RhaKisMMWtZBK8ߙjlR?{GH7>E>LS ZG|cj[~;>R HH}H'4K~k/:jzZ%騜g'^%*uU,>F(>}$9)OJ5?ٵT2g3 J%%C]7v]L]J)Wp6%iKQT%K]l`j"R4nNө RӇ5`2 ]ZH6H:oQ)u b3CM6f6@Vua~Jm3Btɒ!y{PP7QJ0Bj!O=')%,Be-RJidVȬ/ Wj|u=|Ws-v5|755ok#5QhzF |)+r䧛7dJ(-otU?ǫ~WU^ _UD1+n 'ubk'?L82aSphSA I LQ1)i&R*,4 F``.*<0d"<P"PHJb,PiJ2PV k@%ըX j:@-PQ6`݌ A i;h;P^( 8Dr u!9\H=Hn^]HH^$R$?R)BGڋ4ii?HsJ!|T1Ò_/'xJ<-/gijR~N|E_Oooşğ__]2aʻw+V={X{X{X{0q LF0$D`I L fT0 t``6, Y`Ay B0Š,@)X :frH+@9X*jԮ Tb-zTl`#CE=5i3 5!@3h[xFiEڎԆHH/ow;;H]HNn$Rii7ɇԇɏ@ 4B8Gڋ4\#@:t0#|T1 |Q/'IxZ_ψgx^_/,u񒔼!^6oooWwīx]@P!WxSLZޒ|[ɟK/Ļ=)R+%?K[;{G"*%)ֻ{p] bL82anz}DlOH>{n|F<>tlEuxYfS|K|["#^C}7[m2!~)C>tlsۇDlR_CG_> ]e8KXK/PK9 PK@7proguard/classfile/instruction/InstructionFactory.classV[OQ^X EE%6KR!A"ɲlB٭VI>A}!'FCQj!1Mfٙ3sΙ% uhqᔄ![%p!$8,-IȐ]Kō!;%d g$b}.p9=P*91x'tCYӬ\,N@<'Җ(|DM) =Etcٶ2F$Tm\+WT۴t.(g*r\_J5z(GAS WC["!_킸"q8%Yh$H,ҒJjJf4þ|_9mmF2I$4~X4#+`Up^0IJf<°8.xpD1F-fjڮ-hM)-Ti͘g 0Doݶ0T;÷[:'QSd`QIWj>f$Loު)4]~񔀉 A#IMc=Ј@QK UHq) ?-\X^<|>q|7Ǚϰ>x]6kOXd(K\mPKUj PK@;proguard/classfile/attribute/EnclosingMethodAttribute.classT]OQ=-]h(U(EV+RD Al$B㶽%eK[H >2ln}9s̜q~ ! CgHba!ž4I< c V<PkBYVsfQ @1a>J70h#iI /0sjUJ5*#, DZP) :7Da JQWw SN:e\3ԒJVT»cLOu޷-,7|No4Q(S[`Q5슕vR,6rbW]} uxХNݦ65%+5 mvxiRlu: ^ciӎ=QMd{+oNa>U:nd#Z >m~-~@u[6braU!'׿S;xgBm{IOrǔKȸ(^M>Zm Ox eIiZM&ӈڍq1@ 4Euæ6M]ƿ!;L֍ݜ3{~8]p!E 'np1M fݘü3L֓eT}CɕլZ)[ ,1_gjDjE&е\PvAR2jx` G6t@0l/b86)FMLxە|^6 eeww_jlU }C|ԩuNVӌho&R㏗zYyuMv[eG( nHFpYB I H$ý܁Xוw^`dPtEAg#a/_ =*1$`cG:f|,}}@ZE aE>M(< #HB BaRf'}'ؒn>hN2E~Bɞ3ʸIg؈)!O;"uLYUO ږEș|@tb"Dh  )3PKE䳁yPK@6proguard/classfile/attribute/BootstrapMethodInfo.classRn@=I>$-)]IFD* u$ʱ#{\A|  5B8†ͽ3w=c; )LcmI\ ilE$. nyÒw]W3OBM"2X@6dd$ J2<I '3̏oİ1%1{|eXuǎލ>ǖjX?r 3S$f҇0a&(OщHuLV/`CXb 1:m|Q=N9'1muE?@@C-B>4Fݏ赀iJȴls(P(S+bJ{}3q4P>,jWrħDX\ ?2N+1 7ӹ93wn?>q(Af2Hc;Qd( =ӺK '3m{d R3wh1Ⱥ3!iE#`5zJw 51|cL$Ml\OA@+nS2`L HQؗ!bMā +;'1,%x].S#{ vFT)荣PQF;S%f:{2E ) xTc\^#oV-͐R/EjP32hC~^xD\fNj+x{isB6(OPKH\\PK@5proguard/classfile/attribute/SyntheticAttribute.classSN@=Dt. FBBbn4KeL $W.?x1I&s9v"aQRXQWZ hyO0h%f+/[U\U-uA4dNUe85ݴfVX\/YFT1tD%M!mG/~37_D^7F- n G n[B-k!\ 7woV !6l)fЇ{-C51[}us>3G]7UWL>av=Ӏ!Jpn{׾GӉ.|92׉L~p6~ߏ~1ٞ$If4&O__p5s54Ebi'PK{YPK@3proguard/classfile/attribute/UnknownAttribute.classN@ƿM8. 4-DrU)AJET@.9996HJ(j}>TB^v3fv0k@ieӘStCVbHșWiaߌ(d_ @r$d|J٢q|&Ϥ3PK PK@3proguard/classfile/attribute/InnerClassesInfo.classSn@=$nڤ )r 7'ic OURdP/\vK<|buHp 4>{Y?]nqX5Dha3-rmv-4{10-ĝ_ lap۳P;f9 ޱ>UKG~!ȴM14 3 K=ɀEHe}-$Ո6'[3=y,h∵i]|Eӧ> w:@w!GUuv^T'Nxy?VwJ4SּUd_ɋƨD%R8ukQHC{sH !K=! #CH+(Diq)<#wiCB& d"LkxCo H")YLBd?9x.6Nٸ;3&NnPK=MCPK@Bproguard/classfile/attribute/LocalVariableTypeTableAttribute.classTKOQ.@;CRZ8&Q$#I7n ;tDwlX@. z0a!;|ہBu,XQ؝.eѶXX@mBENea[wg &~/#7b|3~v)᜙s9s3wOv"b OׅxCA!pobq D8a$8҂8[x[wDĨ1 JbQvIZ|C2dܤHŋ! 텘{qT63fONk%tO$rٙqv>?J=R'2 `~8[xf}L{SOB  &Shav͕# &*q޵J>zUbiҥYݓ33= D1gEJ.;Ztt>Oy\ qdؖ\ e^u髅$jRV*VVI K)IqUj[b/i ا2pպUhs)lDx/ 19:6 I"ylp\ Lh@I|N8 [äN8:j13R:i1<+Zr !H'g9su>&~TQF.Y'$^QC Zc89u|܋$ɹ7עGX|-'I;\Uxٳ\ $|,"m_O)t4(} 6v^] $"$.Me^-wvL_w7[vKob݆twABe/d|H}u6EpeE0"TP,S+"h"-P-«{#hN J[aBQlj*˦9yWOҍJ7Romzlq2ƙG'9gY0eh4-R2YcuvX=a҃aq_1Myjk<I%efj| "t<ǃƼj*LLzo5-(?&Ч0}^1F !*l eC&v `ACEOdW '29}z_dJQBo J)?WM5 n1cޟyg*._*HHCU0bwh*3<120LvliaW]Y?9FI /.Jt@7K9=`bڴbb{iE_z+g"} 2dSQ /G).cGѳCȧa~hproguard/classfile/attribute/visitor/AllAttributeVisitor.classU]SP= PQPQJZ RD+‹/qIT~L2ğޤP3-!ٳgM~< RЋ%U!)LJ9piqG] 2e,ɸ1LtDZyƝͰڕu6KՊ2>,٦ CtΰcvmT ?z)oگE+?o_P6D4t &y[Z1nh),';E}h+N `3MK<]f;2zPKXHs+PK@Bproguard/classfile/attribute/visitor/InnerClassesInfoVisitor.class;o>=NvvvFѲϼ"bϼ|F ĢdDZfN>PIU56Ē̤ҒT}t5KS݀JdЕܐ_X`2Z kf02LIKOJM.acd`d`bFFfH21PK&xv+PK@Hproguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.classN@RQDn`1)^ueiR`1%DK𡌧E1??sf@k*F0G 3*f1`^EHOfvdםK qu}ӭUnJ銊/r_DatGB2gM^2gH w͊ET0;d8s2߫ABӵce7BCc*?7 _2c)c X*Cyf3hZ.x- fE3ÕaU>j7%G4:=ЅN^qi!Bj`Z{1$(NC9NP3o1$Km([9'Djh\ t2)GPKtb PK@Eproguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.class}1@E(ZYjD  .!,Y f<)&~<Xx< N62Ѽ sW!^j%%oLKX2n`#`7D"~;N-XOCXY+y0.Db\a;pٰ'p?PKfAPK@@proguard/classfile/attribute/visitor/MultiAttributeVisitor.class͘]lUtwmRhRЅ )BjWiE]gg DD} Db1&`4 1GL_{٥[x3sϹݛNDA:ͣ4K{aԙN:3I!f^a`&̌L.f2nfzyטy̼fd 3e03G9[cmf33'yt*ޓhb1F-A#,Ѳ!#Q PV-*jD5h MU9K%rVDj5]lQmJK_`Ɋhy# 4gn1 ^AټIGITS:T C4kp6 %TAآאʅsp}0b4HnJX2X\uEs[š"ewMS4 %*-nS[Hh.#KaCBDEx,JWW$}:MX. )]w/FJDKQ@M+X(yPH}xe2ο~)=_]AY{=TY֯U8(g8VsyWizg[()e5k *p;l) 6xlD:C`Up[ p?Ax["Qx`/4<v1[L,< -@o#<8lCEۀm@'mzl#O@<8^ ?QvC8ŠSW)E.`o{8=w8SE>>I̳vyR*,&46؉fnJq`9N6ieklLʐ )e.;%Xa:C0S ,*yͶ3E*@WZjnY"@=n*"h-QܩmCgnnZ$6 (ߝA爠vhvxRHPK![" PK@>proguard/classfile/attribute/visitor/AttributeNameFilter.class͙YpEc`E!MX!!A!uv6Q@}=X/ebYX/e׽kvng7Y鯧===~L×R:}(&6s壞-FBTA͛wí͇۹;]\lKLJ7;xs'_>~.A.b߼߷7^|GxP<'51*MXh55zk43vDhf鏕yshl[MV"MeœffNұ iG.{E  M6@UE cc]~rӄӄee|Nꢭy`œ|dl)f.k{uLj y1@ӈE@[i,0,p,^4a9aS sdЌZ`/Z2m45Ad>n%rZXʝX V6CgYÒ*;Rxp a{LzI;z}pKXaL(g^>} ⥓5u[#+'Xr&?3}ה2Mj?R;rtnc3.Έ\m v P1I^llS1M%9m)zCC -5Сo%tiD]Ǘxe6Mw1Osqx_W11ql <^𢆗4 jx_ oj8- okxGa>[ûpT1 k@Ç>S 9`*V6 #%U0àjּ nĉ =5fWmP5ÐROY&opVq%9N -Q цWxK`rGYJ;]Rly-*&ͣQyQ׿jm0|GB[%l%Ř Qh'\  pHJE p3iX ! Vl#m͇ p I]MKdTɀ=x T.&zT X'ꂵiHc$r5aLx/e^Fee8DA-+. ( TʄO *\ b _Sj e·D\^PN ?G"D&z̕ 2g"B_ILpLҮŕjD'"ߤ]l@p|@T/֥!gHF$+VNW>A&ɐ %0^C;^_ gʐ*"^G[f_ gɐ HIŞ-C&d AIFDϑu`!T`vLE 1 j¹2aQ)"`9(څ2a5ȅfAب&T˄D|I#&Ȅ0 "DIKMȄ,"$HGBMʄ67Ы8MJUQKPWW{O'dZepPKU['PK@Bproguard/classfile/attribute/visitor/AllExceptionInfoVisitor.classSKK@hm*xҦxы"Qԋ{lu%MJE'QB`&/OX1$"i)֎[?k{˧n@DMVtNM W aD‚ v z[;-Z[ vs0JˮFma"nFm2=!UO+Ky2Q:ZCN qUPQxs!? Aw s[d$ȱ&[T)RAPK.)MbPK@Eproguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.classS]KA=fM/k؋a,b DE/=뮬BЏiZf,s9s93w]bK棈`A"$,KXʰ,,;ESo6yl+0N}NU50#*V&%T!R!~*,~+ܹ+&! [Ci!) Lcm2P00/l1o搒doCk1H6G*paz! SܺH///{"}גE(mo c;v&@=M#關UQi D +`J{Z1(HBBgJ&>8>iDi^Fy@ /HCH~PKkn_PK@<proguard/classfile/attribute/visitor/StackSizeComputer.classXktTWNr3w2H@&@ZMBhSãDIr3 L3w >|֖ࣵ"jZ.(/F # K̞_q|&Rg $w3:J9\?H;5)ZğT$NɱےbooҲaLsQ0s)f ^)cEdQfNOs&.$HF0Iȗ#+Km*?,s{ȍBC g-H aK閑6Fo/ U Er s^ R&'JY,g'|3?Enp?fA!,#fLCL#L'L"`|T@E9X\{]3~,%9я$'QHr3INCr(Te -OQ $ELLL5;a!rО_W(VQ,aHj9@bH-Kn*妝&u>l蕣}>S<)eJKAi}qˎ#Fetm/aKx"oGpWbRnuUI+JEP~U -mdJ wvwpoPj'ɤ,:=)(q*rDf ;ɌU]A>C_!5˫<)ۘe^,ʫ]\è}η#ؒް*eUdɺ\> LW5rg-m΀v3 YE.fCp 0j2r7FQHbU4&4M8$ZpJlyю]x]E7$07ы>jPKAUG PK@?proguard/classfile/attribute/visitor/ExceptionInfoVisitor.class;o>=NvvvF׊Ԃ<ϼ|F >E饉E)9i99UUd|SK2SJ%e&秤:xԢZ3+8(9 AE> "IJDFKAc3Ad~Nb^RVjr ##00203X @ PKAķNPK@Gproguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.class= @ X('F7,l6=gJLPEfoޛyx h,|,_,Ų|,Կ{wI.+N0UG~ܣ"X1lU21}ѩ&nK.n6‹[xq /nŭGW1aJ;;JfW1vA8-Vt*L kM-Xc1[3&-wbIk9ڍA=bTIA^L%GiQBζ"~B{|bHZpr-$֡GMef*LgI&?PǷUZ9ryl~Z"z++ t9tɡ3<".6iZ&OuN}qh|B"sbg!:00:I2JnǮwyVjQ]{A1BueI!iLi=^asWc} S-=bw!?7M|% %^FW5^ -o+8ࠂw|xWxO>B7 !=zԇcz܇>⷟(a,y$0kfEsuT0|oFhA!Dӳ;]c<,=h3zZr=dbxVD/= `™ 7sz eNX,(cZ52*fEc,cKg/x@O͐Q,Itne8/Ò X[?'{7PC #ޛK|T 4y7&&\NI0xuxOdX]CI<IH 3_Ba:鿔1Z*- {*08XEQ ;B%ɎpQDbBŕI,zƟU=v p`0 ɳu×#K^ b jȻWyI%'z,!"c <אbz#aa0([ȻT*ʒw:,C\$LH`꒘/Et=* mt'<d5BESF7J)Sh ]t'h FirJdn9STVxʠ}?\3Mq2y@UXu^xyBC5`?y`Y] 7'A pezp~7FO,N'ʺ016EnSL) 8EpŔDyʅ?TK(!:F1?t[('\fYBu4$.C`s̔? |0"' Aw #2OE-]g90ߒ ?W³W #o+x 'RƗ~,ۆ .*'ZO"—7v7p 13 PKE(#PK@;proguard/classfile/attribute/visitor/AttributeVisitor.class͘RA ( . REU}g$ =(w.w`7>e99iIf3\Ott_0 OaНg.<˝%%4lT>4eL}|lΠ 6='lRIE>5U4O[<11yA<[jF9;0{YaN'Tkt6)s5l3(FZ 86v8z:POISp t*= Wڭ^Pڏ:QauFP/e+0z8\G7R:j”JQ]z0PKoPK@Cproguard/classfile/attribute/visitor/LocalVariableInfoVisitor.class;o>=NvvvFĜĢĤTϼ|F)>E饉E)9i99UUd|SK2SJ%e&秤:xbZ3+8(9 ACM7EzYe x-(Ŵj#ļt}6FF&`dad`f`X$PK͖^PK@Bproguard/classfile/attribute/visitor/RequiredAttributeFilter.class͘[lU-z~;ۖt r)Lwev\T "^QѨ/(`11F__w:aB6vwΙg}`6b&Z#Zi"v/Lf"DŌL,alf^tvn;m'dU^b?3O1430saX]7f 39#*U񜂱+nXzhm[FcaG,kV9Y!0bMFXk7;"F1pߠy ӰW(XZaHHWPXczmQja4j?7Hy\ame";f[ZtnDB1^}zIr\.3t 8Ī ˡUO-g4.5K3M 0Jwv\rI\p Gbٜl֌5t_f?p\H3C2jMS+9L.nm#80O4.Ւ>L"pV&A츥LtNkM=1[3-wb8 Ek9ջ:w.Yy0]x%=rE(ܢG'6hQnKXnM-eg>9:&ԍQćwk&oZNZƳ> ebgxɳ5p+ڧ wW}2k7mY ӌؚԥ݌ faO?C(s:# aqdpJifi[#vlP'Ydx \g<2&2z֛xv/9' z{L"Mʛݪuh( PPŋ*xIq/xEū3'T⤊7TR񦊷UQqV98₊wU\Tdkfcc,IReZG ;! آNheHH?ͣzv? P3˜YH9\l<)%r"!\g"+/׷[oE[]r`&{ؒ-EKbnVea>+U9`*fb 9(a}{QACmW\r.&B{w*r|U\Fn/X\UdG5c52s{%(}oPPQ.`HoA TԢ;t DG xUANɻ%="LAxy~ /Q-m.2 .*݄"WhHЖ$a @ 82~ȟ $ VI.g?GxLP'_$O[gE3¯Qs|LD$+"ok΅)?w=_[ 2"+;yk_!F& WT&2#F"%r+F"C%s'DPhIVr0Bɥ˭I##Sayh)F F(#)h>TyO |&D~PrqW'l'"—PK9C&?EWROį';i":iDPOmo'U.g|xf67PK ŭ&$PK@@proguard/classfile/attribute/visitor/LineNumberInfoVisitor.class;o>=NvvvF̼Tܤ"ϼ|F>E饉E)9i99UUd|SK2SJ%e&秤:xԢ:Z3+8(9 A UAEzYe Vx.j# ļt}6FF&`dad`f`X$PKPRPK@5proguard/classfile/attribute/SignatureAttribute.classTMOQ=vh;RPH+ZNbWBi!~D2!čk K zt$@؜{߽>n?PO" $0#^ OJx$aVEAØmp=Z LY1d߬:g8)[o2ğ K biAY;!",}hsghw)+Z 3h|etDOS7l7F(Ẏh{Itmv"h_Pp;|Yʬÿ{cАƘ4 70a*t eT$T%gXp.TRGhkbxrˠͭ]zs su B>$}E09%19(d*O`_I" MDwDQ?D `1_Ě 1J>cF\S>D,OϯAi7 *Z~,V1G~/b@gTNR3^RS*2_-W*Ct|Νp0M"#dPKbp-5PK@4proguard/classfile/attribute/LocalVariableInfo.classuRjQ]'d47tZ Th!^RA8)L)}E0H}|u2 g>{YdA4,kᖆ& &VLXDE/,5{Kl[WoFR]mḭD!_)_|8~h̑PEjggGCTW͚dL_]r–mV VSg[z &c{͖Ձǖ<ņt{e+AvgơmyzS@4 k019aZ`2|W} _+Dߔ9dݳDHY6ݍCqHyF+^8A(S7/ݲ,,~-O3.rk5AҚF}җa7id6b ϰmVMa:^bw}/ z. "Ie}^93_pV?Dfk|?L}~ii4פIdhnHSzG#u 5"uG#H~2H3s\'0PKe@;fZPK@8proguard/classfile/attribute/InnerClassesAttribute.classS]OQ=n]QEUi@M HI /X@%APf&,` q2a(;n^D `!í^࿉`wdGT( d+D<4Nю/+ғ*A*o pSzb=~pdreWY{t:PF~Plv}q^֥Pok?bML"2v} )sDyYs&aj=.;aܢn9J҅_ Յ|&a2ەl0^&4Fo Z,H햽'^:a~+'1s!PaEGc SGGU&EdYsΌZ0  w}OYw#1ͻ4yGEt%ieK.M*k~M]abx3u THXn_`b%?1"n Dc)adcH`1t'o\CAPUy_7]~4N .HSG$ݑite9VH2Տ>yi!ৗ"ד#B^|lKjR }=!2)GRT~zZoÏo>&]5irTiZY#:1dPK}PK@8proguard/classfile/attribute/annotation/Annotation.classTKOQ=--}.)EA2}iE&` , ,Dc )38!JB 7q hp?ÝBthK)6w{9!&|#CHD!.F 1Jp 4=7Sƛ Vs5K3uKr)T  #˳jz.˅ŠI0t%c4RU͐ ES'ZtufynJllE'JA14=h kjr>ƳA%ה M LV&" ^*7/DlC V]%UϞfId8iAKA)N$tspҏJQdReFP Ui -h3Ȭi$!t34$J3Z<ЊFΐ:[˗14Wcc?h9βKV tO- _Cet}})R~b"BSVNQMf}:;W vpâw ZwQ ڇCهSU>Ar)B>$g$<zl$G=8P4O5^#;w}vќ#bx <_/i=CWK|SEA1:EH\EW^֨\5%fY+.kEa01;w-p**ž~IԿԭx"xK&N?V ۃڲTpÆ>~ > PK=*PK@Rproguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.classIKPj׺-.Ճ".PPZxzm4&xǓź"M 303 FMDѩҫ/("+Җj!8d06`H[yy"R:;ڹtlD+ʂȲmGq%;a.^,KŐObe79|saJ$t&ԩ+yxnQlK=}VBl|>]gMZbQ Ɛa-# Uϳ| ++>_SwJ,E:iIuL ąn7ZJRW;}q5[udKdRlxeي+i[Ґ}07MQ vrE{ȹPvsbhT+]l'[Qj_ qm{)Τ+R-*CWo %сݡMwya>:֣&_0U9ӿⓛ]ԞAhC?Hg!qhO̟}ieR}g" {l7'ķ1R;mx)D9O^0S ^$exPK'jPK@Jproguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.classV[P .x˝h֨hv7]E,գ%%|L$>Q9]nV(t73 tNqUcq^\fAf6#Y%$%ajsmnCee/j(u]m)m[ش 6D){,3Dor۷6"1$V9͚fm5"IW6ޔEejgP%͸;͛PCCyFߌ#t"W\0U~i/#7ڢFǯIl/㮴iOӨBHԦfk6aRytVIu3iQH>PIsI$\a;7n1e:otŵ /倧Y7=az]k σBEwgGϟ߾쁎-=I*C0:(^\bN$}eAP%.E ӣ%Gp$& /}Cx/ש sa\PE︠A{*I$uQ/fԭ$/htj"h3ƙT#_YZpPKB>e PK@Iproguard/classfile/attribute/annotation/visitor/ElementValueVisitor.class͐J1OjӺEyPWBoXd oC3)hȹpsro8Ѝc8+b5PK@Gproguard/classfile/attribute/annotation/visitor/AnnotationVisitor.class1ò%<}'H$DD^(nwx( dfrCGGLd$ V0LNFocn,P<6R 6T|pk\uo %ᐑ9BsTFT؝ί;Ӎj @>.ӟԦ ' '3"RS<ܲj/[& HExI+}APKz̙vPK@Jproguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.classNQS,PV E BDn)QwDl*Cמ6m Bb>=?} /pG]/{„;q a/yi6C/$/̤Sx aZŒYgKj r U1Z(yq+} GskHJTI JZ8a77;TG ;'g'aG0Z2+ ڒ4 T\0`8Kep"ƊngJ8'SV2wۘúX6faxk6LlBS xDj.Q O^ߗ]):3si‘6WΩ{-!!b^?PK ZPK@Dproguard/classfile/attribute/annotation/AnnotationElementValue.classT[kA&dĻ5/u HBhĒg'1lwf+|R(tII( gϜ9o+xR5<Jcᮅ{ %JA`X܍~̣E+^H7ZCu!RR5 g`m*VڔxD{>Y^8$5#WĮbVa@0u,5juc:43NLw;"PzlY…ayL2BƯ|{FDܷq 6ࡅG6c9yYڥq O3NHԾ0mOav4\_ʗڷ QߨқbC"m4Z*6CV#Y@:|> ݠѭ %k3BXd-&:KvqIWĪI˸fURvFy08M$ZDLͤZ=Č_7[\'=PK$ʋPK@Bproguard/classfile/attribute/annotation/ConstantElementValue.classRMo@}8v~Q( PF"Z!PJ*.To%ʵ+g] n .HT(6jA!$.3og;ٟG><ܭRhyaCCV<5r "YC#SӕI>{:敀ӌZ]NW:Uoʏd/amFp]2թ<<ͳA!~;Np^'I4&׽ifY~s '6YOԉM׽햂wY@c,wFgֱ< % {X {_`{R4>16;^qr4/{̗!>"O!+*~x \ΠJ"#$sfGmpUK pn 65;ddfz:4}-kkip{Tfjn} <`dю|7PKPK@Kproguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.classSn@=65@R M,HJQ(`@UP7Y9ĎPKaDT ;~]*6{|+ d1 q-bKse7ddȅC+6k;5cS#XSMoZG\w xjX!Z,5bUͩaaŝ2)+l>hR^piC18Z;Hh.çM\bl ]ZYja[hy@"?fyӏ툎saw7&Vn Ɖ2ys|Ҥd!Ro LCG{Ov˸Ei6e<–9˘EFcؖe?c,_70,O4CD6 L /MWl$HdȒ3!IGϓzgCZgW/,G6z\I ?C"'(WM) V.+#Qb« Uyq# &rAd'^>G"p&$XקMG6Rwd T-&.Gܦuw~PKFaujPK@?proguard/classfile/attribute/annotation/ClassElementValue.classSOQ^m]p Zź,?/BBHB d}m,dK gxb!x??DXmMz023ofof~r ` sY 02( 1 p nfp!UmvM^b`&X<[u]mg}/;*v\^A!p!5 7&Kn"aêmaAg:TdrQn[٘۾eNXa8($ ߫c~1}] ˍE-? lu<S^ZKbV0*rP3 *@g?(& StyɿD{>pcDj[L܉,&NE:Eݐ(J`eZd](8}I9C;D(~F4"C5LV{1p(`|rrr(wЄ.V7O]?B* Ƿ34 F|)<4b6) ƍxdpV -]H0'`DM#9s L=NPK#PK@Bproguard/classfile/attribute/annotation/AnnotationsAttribute.classNANmWj-*.[  $kcMCvK\[M$D/|ħP,3wgN󷏟,`6&9)䥙̠)i.Hs1b pt]/0͊1dbik;,4FrfpEGe(\f\VmvW0&\{#|UfݡmV' I}aYwcZMx~Lo0ɶz iKuvzz }ˮ ywF^3撊42*TNⲊ+4JQbX#j>)0EF%A$t*gqMCu1P`tD/,~@B~3uc rm^䧕<9qbrqb~fާD|"q?1isUƢ+PK߂=PK@8proguard/classfile/attribute/LocalVariableTypeInfo.classuRMOQ=ofڡ h˧eJilԈUH .$1y>v%.nܘ\W,N&={{ߝ5db.%,HXpK’Xi+: o{v 0®{͛hQ2Zu{;~ Nc8MQ+4x- Ru>wk9SQx!-^0h&FJ-fUe^mPd(]?ɆiǰՑն<̕@Bi+C<]:G1p-F$Jp:21"bJyU= -| B*oZ7 DAaB>&HG1aWߧq Ô< )9Ξ#͜bH{uhtʖ1 HxI$RFH%s]Idd_ ٝ IH݁ $5Z / LY_PKpa0PK@5proguard/classfile/attribute/SourceDirAttribute.classRN@=CKRC"+`L6T3RRZb+𣌷aΝs}μX$n {O C6kÁ ܿdRAl!CGKw:+#SKEWp^cTR* p[BZܥojTNjV繡`wES pOaN)8# ~uDZ;0:G/O^+~*'7\(p`HDWTJu! ~礄D%wU{ fuvѕ #@B2nYR.Z{/Y AJ=wEDڱu6kh {SD2DޓP%}@#xW-l:'K F~Fg4>@SD*#\LO2e(kVPx᷈"Z><ω6> R{\/FSm<=PKd@S&PK@>proguard/classfile/attribute/LocalVariableTableAttribute.classTKOQ.ہvRyMG`%!1L2tv:C3,XܙЅk?PF(&{9'˷ỌA/I1)FxqCń"C!Z|[xU9ϥfL\;p煵e9e[Bl !}mC^2(~"[nY^֜ ]MˈiaNFꉽNS'Ӝ/lwݦAľz|:SJBE!VVg~WvjjdbWhRЇ,40bF,t 3]][ ݔU1ԕݿ.=3 @ /˓Ez'G;&ǏB;Kt*fq16 !GDFl>/ҽBz=D1v1w3P{DHW:!6ܺ=gs>!5iS scw(G؇ GHs繬ѳ-:!qYPKSg+PK@6proguard/classfile/attribute/ExceptionsAttribute.classS]OP~ڭUAm:ΏY:،(In#Ԗ o6K{j7 $x~'ۏ/_0b a.CaE̠V,*P=Dހカ.qo3b`&t&!A`9 ϭ3]@Dm)YMseb m۵v׵<Eӏ#uB'vgYXK=V=yIGyؾFun+?l+hֶki8\0UCn▂tFmƩ)Ljxw(spF+kP]!KyF}Q4F?-&ڑD[<#7>%I*% BJGqQ=DΘ9d,@9>Uy@YKLbZA` yy'>;41$gVZ!}@I^P^b~?9C| )%QPKraPK@0proguard/classfile/attribute/ExceptionInfo.classuQn@!iCh -8F!זBUQ)Rz@8ԕ#{]P!qQ%|xXPB̾ݙF|+]BkEu03l05pπi+PLr"u+ Fҗc_FY:=JNSa4BsؾLM–xj[@3n8&cu HFCgӉah;өﹿ.ts}){DËSes+n+qarao\9U^dž2jh0\+c22T XQ8IhlGvQWSKY2}YyBB,8MʕS,(92U(ZsϩNXBxZeM95fgЭV]GбEAQm+xB븑QOhY_CY?}ݯޕ ^lmxM2*1c|"lv 3I\:InPKctPK@Dproguard/classfile/attribute/preverification/StackMapAttribute.classTNAvwiRZWA,ۿD*4MѫLqu6].-7Kc"|F=;Fc9Ι9l 8\0.!ejp!M]^~kEoU]Vb8ax؛w6ey"_sĶp̊YiWEϲd :kVMHM1 ]2⮷.Une63_w.U|ˢFxVf;;3<}botu_?6k;Is7Hפ;lbn{#sʢhwomcQ_ #C :"aB,r _"x az?jS ߮Gygӽ_P6{R wQX.L=)6̗CM'?o ݓH3:4LɌF5HG}cd#`+q@9b|RogF1VH`:5(-QwFDbGFIcMUJ&}h*+ϭq yFJDb<"97PK^PK@:proguard/classfile/attribute/preverification/TopType.classTMo@};iK@)TiHk 8P JHXomXjlD~H~bݔ**UTf6p צp5tX,ᆍ%7-J!__2v`e(^D^@k nE>q <~tO A봓Bq*{68NH$rO\(tG2*J6|KۜJ/?0QDc#%ubHm_wl܉/KSNjb]tCp-V K)\I  q݅]#-l&H7%W3T#,â,0=e˴[Zl|D7]h_l RFh7׫7,]FbSf$ZLx"1 zC̝,d>&&e`0\ㄩg.PKv@+PK@@proguard/classfile/attribute/preverification/SameZeroFrame.classS[oAB鶶b.+Oii$А*n}Ňh5Lg6&M|p||6g~3䦑ƹ|H 5uB^kIĠu=WcCbo 35wyKH¨*rw"*]y%ɰoԂ xض[];nW[]W9I#3}Ḱ$:V8P㶸t}}W]b!RRү٣bb9r˽=B+ ?[bU ԉD~R:t긌+I\q I?#BK0PdXi𰜷,+ KROU⑌NM/ ۾| 30z?k8/ROd꿛# Fc ^dc3z PN)05'$V)<{Gl$ӈ\iDcFWj߬96nR[. 3fZS{7^C7/ZduY,&򟛺^0?"a2 *j1\èFL'>$L{ +?PKڧ=-PK@@proguard/classfile/attribute/preverification/MoreZeroFrame.classVO[e~~rV_Jerڵ[+aE^ڷpӝBCb2Mov1^y`{zkLvs???ǥhd8ӊWqVjsRc ~LuL0%C/tK7ʼMD5cg8D0ZDīբ^ nYZDbMaE=ϥobVE1(i[ 2'cCGV/KUa.I,RD>yZHe:2,4iT>/*Դ"2%~X3MNXFj?+ٜGÕWu0(e.+RքiTsf9^5Rč/IC5%^^KzM䭱+ u^]oTFF3KEfŬ.ؕ3LqE *Я0|Q1*"aHP*$a,/ԊEa"&sx< ,%C!ۖu4a%g6y>5o;Hk[-iUaMh5TDkf bp_$?`#0}P =@'b;t hj`f/F.Z5x%ܶ&(͵>N]x׾g;YIEރqۯEFwnKÇq#x\{Ͼc3΢ ~4/c 0RyBJ2;xwVw2TEQ.S%ǰu+J˘W={{ΊZ^q4*;=^U 9}WIB/ K5KxŸ#ЖFħT'5)O{{Jvm7g?$U ęJWZ&N} 9-#@Cc1$B}2ԏ.o^Z?~JSEstpw)x.:;t=B:B{$ڀDB{~N&;DTW]8i?7PKl[+ PK@>proguard/classfile/attribute/preverification/IntegerType.classTMo@};IKR@iHk .EDU )R(5[7蟁?uUJìw{6aj² +ܰj&XR?e6{ h Jm7}Pr?h=O 5Z{"2^U48kdN"v'flPPr_z\(t2:Rno*};|؜5^Di̕4݉'F :PŐڴTl1wQPD# Txۀpƚ[Xwp`Is*\Y ݑqL 7SnW3ǔx;+HMud. L"Vie_> })4 .}ݣ8RS֢uتߐv E2R^媕*ybfY<;!#\R\I=egL=X1vq7PKsqPK@?proguard/classfile/attribute/preverification/SameOneFrame.classTKOQ.}L[TD*b;-"ZJ҄j"D FK[S]/tEܸaQ jb\ϝP  ={f~ @>"M1v#!\KR1W|DDZ|qnH}\MoS2ܚ7B%,4 =0Ef5a%MZIZŗ5bpOݜbp#9l(zEm慱e8 cE$`P5igիA0W]{H*Tpuݬv{Y|ٚ]TnۣF<؎p_udJy&ԁ?HJ)S;Ukx(c}p%}P*?{oFwoi ΫD(y uw©;ѣ6-7/.aPQRt內/+'b=>b[,pĺذp 5 QGHOI Od2҅Ĉ9=uZh<뱐9jޝ/M= ӏǗlVk| Gz?@e &E`jVsk|EEd6)E8T\5b^%O̬yyNC㙹̻ļGX0#1 .PK~j1PK@Jproguard/classfile/attribute/preverification/VerificationTypeFactory.classkS@Phi7x-(T;z!Z3abÄ?lhICʗsNo>g'`C1 q,l wH< ɣVD{,obyG2^{4XB03p-? k0ь=%fVDC Tu+;E4EUwM%Pu T("+>BDH≥nzb)D$MK"ڃoPK :BD PK@Iproguard/classfile/attribute/preverification/StackMapTableAttribute.classT]O`~^ڵP*(0(8A`d]j^RauKv\+╚D/( h朾9_={_D@.hDȥ\nF7\q]G/C<%_ׅsd`yZ ӹ[E(2\JY Ȕ=QSpl.Y8?ΠqJdPK j] sNIWW$&OƞNOC-Ԍ7zrE1^O3/sw?,~zۊ;2K?Qc&_'}E4h!ƂxuHE;q9W݄f&a7u$M2сCD;P(G GN4F6R 6FC;OGgM/(J :D~?術DǸ,Pbm/ѳ!B12;G G ȼj %4Z{܂ȣ1Lrxk`%X-mL5Kīq٥gb8{*GP*CYe4jq-qmhLǺm5teiQ͇sN5\#ؓ=/JPY\pmٸuw .$\م~{#1bB߻K7cqqc =_Sb,5!`I_&89ڭh5*_> } 4 6&2>LṢ*5i͗V1SߵsHQR-Z«@-qdƼA̴u2s332XH+q Em׏PKwR.PK@<proguard/classfile/attribute/preverification/FullFrame.classVmoE~6⼴.;iRHpv .4oM֩F@8c9 Q *"8P |?A=_&5HQUgwg}fvs.x %1.8.: 1$bkbFDbԅF<Orqʅ8FQ+)i523Ԗ C9=XPH2)-FеFrZJK*Dfo[LS\yCI>gw _h -5`eTQ' > 0eky'PdRQF TsK+},]jp1׌~G%GY11,@((~mӟPrc#0A}s<eEb5iu=\RKrw):(C t/iyLe zRx/ y`7JhC;I ?Z$aЉI L8#,F7CϞ.-!n#TJ%<9'gMA mcg/DT^5Fմ0 쫷nQ_^Y>گL ~GY=c˩P5RR6ngӣƛf9ZE3VGhGFC҄ojH]؄?`HH/ o7Q{1ԡa:Kz6~ۀMo.7\}ul@xjH$u Wqi 1AaLZ ѝ#7`~! =vu\g~lF2C#3YW(wW!I_,]-~+&ܺ^%4 彄I:o;:' Z~De8l׃C }DSyd4>8`K)<-^k֛l/%PŠVW" p%e4~QNus xn-m$r^8AU Kx|<k5D插MlBQ>WEW_}AE~ X'$2O-ߢhDs"&dڃl3:DgH05|i*p*{t;S"5Q4w1O~"tp58PKv4E PK@@proguard/classfile/attribute/preverification/LessZeroFrame.classT[OAV xm`Hj@b biXuwK" _'_xD!jb|/lkMH|0M̜|6gۏO_ aAxqqEU?bRKf:ðV1uQsS煪Ff`9߂^; n5g,EпăvAAspuQ.7xaI'\D<+u(7YLkUnY%*KU= Yv(q6B&:t)q;KmݨwtK 3ns*/|[ʬSxUlZ9Vm2*ܪ4u T‡oMm!n4LM,gaY4)i  "Ǽk.2dNUUc7V010D1&n1djk&R{a0:="Hla?&jw濛m%{jsP"CR=>=yy4Vz}B1A߃bЃEhHiAoc8B2<;g[)O=Rp`xsż=Ɖ)!9!^A,vc]NA WqM9ηG.G̰'nKQzIC[#L"O^^+җketں^y (0ejODLʡl7Sv\E,n{l#LOk\6,0ܠ:hy\xmxiPިEV9D[0PPf8_T c1^eaGq?k.]8 YtѤpʹ0^O0ö Zza<5ݱM!GDKފnD/hwt;we%{O+:-?BFVt$GK{ځ&8HAl :V=Фa =65O-H4t·Q;9MM_ґgD}Nj:qz_ o($ҙpD)2w*,EUy[#Ir!#$ ӺSQ PK((^PK@Rproguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.class͗n@Ki&\Z.1]VTRE'4by"{ H,x aOo} ߵ1s%a+-!| Et;O/t@}v"l Ӷ`w]ND8gx{q#6ĝGܗ<4dCD>qM)uUt ~+xĆ5=#.n8 NX4&$(6RFqfRK =eeM[P,)l8e$dYQz[X,*4}8 ď6k= Xi+[%+;EuG̣YmVXZvg$A&V5e+x]#--N{Zl!g=mwEUMwn4= 6z;~ 7Ar}g3v] _I .$@a P/4A9yX@]%eXAB uPaWjހ[p 6A+}ώ'}KiJ;:|OPK ]OPK@Oproguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.class=N0K@ҲqXdBH*5đd] C!CD `+#RD?rmﷳLutBc|%$m~S&I%)fr̟8ӼZĎP)|~ks{xk_PvRѯCqAUu NlS0pv%;PKiPK@;proguard/classfile/attribute/preverification/NullType.classTmOP~^1 Ё1M4&Ll2/vioo&F?QsK $$js{}9폟߾½"L\ TuXa&VLb0IO F!C%=뉠{.eP>q#S5 Aă< +5;y-W*HDla F"J=T~`wKv{ojӡ(x uwHAmQj>˽}m2~8=ً\WWH LXpk`]30ԧu_7᯾5r#cm=c'WoZa eYX | G3FL]J }(%:e ZgJEd(6&e0$PK1'f<|HOzDYb>5,$S0a%Ŋ_PKĢPK@Cproguard/classfile/attribute/preverification/VerificationType.classT[OA-m)"PV[դkeɴ euwD~1GQ3ۥK5Atf|s3/_!AWzуruMCn1l9lfZfy) Q%rOlCdQ-dc[(ΫgU  "al5MɨZna]{tAYbp,atSR۬N-Z%U(mfku)2 05o, C*14^uT /EbWFF\妹WE*[;;nGڪot5q2RӢDf?h C뵔s" QlifhEa?lqCc'2@Tt_h|ۥ],~X&WM^5#Xe[7Y7Xsyۣ8QDq'0x3 y#cI]+aPT43R'LEc!qKG8\x !<#G]8F >;'hEE䨦4N6 TSmuiY`q9jCv{q$.:i'm'lYjm%a8o Ess8['r^]?PKj&!PK@;proguard/classfile/attribute/preverification/LongType.classT]kA=ݘnjZ֪1"(QB%!t]w$`?J%BApg9w{w6na.nŠ %\f PR?f76 h(*z|Pq?і{iOHE¼COKQ}b>,SZ0c Ś_PK@PK@Dproguard/classfile/attribute/preverification/UninitializedType.classT[OARHXm)T+"b0$E&Nbֽ`џ/ &gv$$jf=|73g~(hPT\iU$%$cXER#*FhP)9^0&a\C3n eNR` -0(S3 X<+C[F7Cٚ0WZ,؂+^nd\NT(էXbnS^J7, X7tq65&:ev/p|p zKM1l՞j-zv m$k_";d1Db S%n6DN3*Vw:dA[ Z cļ.A#C-S 8gT\p75m w$\D̉וЏ_;{N L3ai S00}kWF)cx{ꚧnIe4POc}~4JEyd#ꛤzUtIKGR{W6 }5 a'  F@ d OD?wip8TdxQ=}@P\$a/PdH$ډE fy$*ˋPrxf!"Y^.%'Fп=bb$o#?TA ,e]OLyi^ծ'kƋOyдpG.4E.Z?ԐhoPKGPK@=proguard/classfile/attribute/preverification/ObjectType.classT[OAݶ,r^EmaP `&`ėi-m<3|P|A#B2.iD i9;93?}`s1ꇌU(b2b1>hb*  Ju"SJ_0$4k 6;M1xKY!d곴nt$HR襼nm.<çR,jvQеJY֭RP,HW-S._eS馑322JEfT dj&˲3OvC `8~! Pdi׸Vż gDt+YU^#DC`T53]CAE0.lംn1:n(McU` })-Ts9dp3HU0cj*_=q4b(͉'iS^9'n$>`'ڿ K\֋Yx}g>`4azyO;?6װG0DP1ۼ1WI.4a?tM8AI 2E~ 8-o$[ ę٠7 y/pKhMlX Ig^il^KLƼGݸOsG3eb^ y!55\qyQq5xu4Cm!iOyڭ4!!=PoB6/¥PK!v(PK@1proguard/classfile/attribute/LineNumberInfo.classUAK@4Icblj'5B֫x)QAI%%&n_gCx}7~|~Ї\]zҲSńYDUUVd` Ϟ )Bx<$gƱDzRub^Mh pZZV3rSH,]!rY,}TƀqxȤLFa\w6Nܝ`W1CN|o_nq ъװ[l ~4s_PKvwPK@6proguard/classfile/attribute/DeprecatedAttribute.classSN@=_@Q.$2JI),+WD~eS&@hәܾb; ,% VX b!u37 Z 钬CEe^1ђ!C9Yj]U0yy+MLpDZe-ұl$r϶E)0V¹J ][-EuL4lapGTo1 D4ul(TŰoGOĿƒF[qKWG;䯬(F; 1gU=т!L0 WwW@*ځW:1 LdҩgR#2ݵ$(TSt<˓ϻoo yNsPKBPK@'proguard/classfile/ClassConstants.classxǕTdMlIRl-%H[lh9$wr\z\z.w'q;8?[o}>yyμww R=njo马N>ysa0X.X zd-%eub- V}Pn*MIm܈BFMn#3)-w1??N3]hrt]tþ:ϟN7Ituruw5Aap]'WG|W#t K/:Z1ܥ Vt)]p{ő.eV')|*}}HOv>~POR3Ul;>גUT=کx/&Z<Mq.h3ZN)%[:szBXN9-8U?Lc>ْd7)ۂSD&2N R6l3$Jڽ<.2ѰI멜>ZhHgZ`ZaL kL;fэ2u2mR[bй ݙ>XRiLr nzjz >}i(>fIS`-Bzn"-;ǐaJ_ N8e UWdwN(UK`J_0RxJ2^M{(R[rRynmI*}GnG*}WE*}uD }_3T)[ACO(G,&rU5ٰY#eMh\)ydZrR6 lݼr\X\=\SH,y!7 fLų e{B HV|Γ gM͚˝=[ٗO9k1Q*sVl('eUF/u{%BTtF l3ZQ(c1YjKBQYFx/mN-%TZ oQcUlSҨͱR9X@V(T :aeU5Q][reVgYBDϛY3&Ʀ/ePoЃ_"`mG#f^U_Pטe_PePU7;(Wd2Sf͵ϕc B$]!F+] ӰꥳX eUĂڽu2H! 5D6V7 ){C]ж~iœ/4uBN=ObsĎ(5Hl0)6;֠߻ZjivJԺg^SZ6Sؕs"&j TJϸIk]MchmщK)=n43&vqzI}rfǜsS8~R.Vœ鬝%hYBEɰ);hW鯼6Ɍ ]bwqMTo\Hڨ8FC*p#1 m:*kccMbȴtɄ"5R3铺Z*xӫƐ_7҈ 8mS XnYxәxOFGTGt e~z* # >q]7wlFȩYdIG2D`wxV#N錍jlUu&e:L kB0aU]ڡ{X_Rr*uyB=UY߹* ,Ls4 QZUHUR{ڛjG i>N"[H8ߵl ̯x#)zyFJ[򶞦1 4*K $9wb_Qπ<I=vCGy!?95d !26좨NnZKv;OpIM1O;BvScE UG餮؞QyJC. Qwr&I'kl, %|e'!Eͽ7^B'v j"e&m@5.g>`eOmNG9kI<m!u)"E]$?%wR!p7*jw⫣\U4XTdɳ__K{oC$K_Kos$^f1_Qa= \iU)Hql js{6(vSy/i-؇Ta4^zFDDh  .T5' [*G5d2Vf 1YCFߴʹGNYS#|F6No:)9tV|sxNo[}j't> t_iRB0V*e``H4j"~0k2>` >8 dO88 1H% OO3|㇀8~xq<3^a\pYŸ2~8x\g/11~$Q hƏ??g'07;Id ~oOIt?fs|?_1~1%_ ~/g?WH{(Y~Co7X~Co7X~CoZi3cCc34 a|nf|X>Cg3|X>Cg3|X>Cg3|X>Cg3|X>Cg3|X>Cg3|X>Cg3|o| =1z2c3O?`L??1oz>c+2/fK rWl>^ ~W_1~= ~71~; ~f{~_}=Nv6vvvFҢT̜T -35'E/+,A(?4(E?9'8 B, R\ EojnRj##33# db`PK>[tPK@Bproguard/classfile/io/ProgramClassWriter$AttributeBodyWriter.classY xT>g2c'k@֐}Ih$l G203o\PDqZUq.Z[ZMZ;{o }9sϹg=`*^5574]v np7[.6o~<q)|s&_Ap!RϘ|I"&N7BEl!FI>%+,q$( KX,HkGW#7uCQ%Hd?VCUVwrدy|֦j~/!Bʲ!& 8B>?oQ-xv#~m}p{03XiaF vϞyzC*K%ԇBZD ++T-X[_ZPxP6 {e$hQ*o)eKaGˊ&T A5,~k5ykK ( K@(Ɯmѹ.o0-#zMu{~$4*kPѢa{T% U#P0)AE D9[W. I{.U;4? X-GKb˥ŕI1Hw _OX`!tݾB迫gKbo U%hYPFH$I}Nn%%$E\n3MX?&f}ȫZ$N^@zƧy&0 %Hܾ%xxB|և|c< )SF5 7Y̸vĆUe%N#z2BbJܖ㲍9F˖#XY մY0. ;Ĭ]YbXk|mYq\1A:R}E((P[EeU#3]N39ESVE62i_MTP-g٦zBm~WԔ5[zB 5A uA_,d^L㖗Q2ڥe^7)oGDkT3tiRZSVnLT͢5. / 6tW+>Ibf՜"=qfɔł}m,&0.ԓ%E°Gw+-BZk3RNmuWVU$ 0 (ELU`i6ZNxKn )ƶh޽}:pERb[W#w3ISc d>t`Tc1s^H8)d.bcDɁ.6wQn Z1˜K$zёAY*M$C?Tvb,*67!)*3S8v3 ;mq 7v3WOx2LI$8LY(vVi桒Nve?ti$-ݙ@҅Aq,{(gq ̬֚gj(/>cCK\1/uZd86Fi@o! 7^jQ^eG#*lWz/?s("Sp8aqZMIb,1N3\x?3I|la[znHԽg; M!@KFˆ%}7+bԄGf͒T3AgBX*ğh#h] L4 ;;e@ d ;aEi<Sn'Av]p#+g)8 j~==ΩԹ߉x&l 4d΂u=wylvt9<֐NjX%&k8 B9RgJM'^%q?,/f6㕰 hR:|"gŔot'I\%CFM `st qNs2O9D0w=Ľg`s<@0B($ LY"̣8Of@kE/|fPA=|$.u'/鯮@۴M\WB~3 -0]ScSv0;PkFاdۦs%ߣm>LCq\U(4iS[kkͲfN,4|D*?&\^TRWh%9&&7ڛ*N(Q"tH0чz* 8@EVLI!-]3&? cĽn GRXdqqrFq dc)qot]:XEVoo6؛Kͥ6b 8Ɠ y"ygy ;&ӈXf>jYE6VJVY/ꋾdu3Gfv ULwM=~3ZLJܠPׇ>+cT0aQ0yoL8&xI潛|8yoJ-_nSp;6DS0Y:阕qTF\FBB=$9hV4kTLnGjinn;l6:$(iÞe!~Z+G4MJ6LA`NbYt,n 04Rf#thrA9 㶥P c.@r1Cs1֓6ʌ$/xB`(b &AzS@!d&Lf((W,Yuk[UֵU]׺9{fB7{={ߍ>!zܧ}ؗ>[ů?c0[}DZUQ8@ t28PԧBw$vИW!`gq":2Ĝ*]|НSЕl:pЉs s87s87;UGiуc=}ű<<#z9q'UxAK/9`/[{ͱ)C@`(TD*2*7_>J 7b"PaQ`'a8ԇbۉa8`<1$V&szL(5݇]=̙B(a#V!bb"1yb"1]f'#qe*l3}b8X)jU9%p^"ʙt J>%:,UTs բD8Uq8" SfQ >۱"W1(QN}PM*v5xH>GT)*q}TRGS*xRŁ}JVi_|4ǞQijRNJD=* SB_*_"BPM,P0&#C˪`xX(LJC >_bviSX@dMq:kd)⯞v{vuk"Ɣ2QS`azVSЕ;;u D׆InVhN[2Z(`hѵwյ@dj8Th(O?Sq)9ԥmPmpqό?jV zt]t1ҶHT䰰( :[9z`IbN5 LWl3>: Kmwݺ]|74lkϪ<h-D3x,!\,m`P} |N8r`:,-VUeXigY([am%t7F[sl,j?Ens@_<>Pn C __{Ih{ѯ֍q!50_v@ap9f{{*Ogqm@L T̋?pF|ᯅ8$nj]Dgj ⸨%mZhْHĿifX ',G& @!8MKQ9O6R{Y-PlDod-SZ͜rc 剝=%Ή63?b%_"C? k"XV.hr,Ѱ 1iL9A)Cf̀&5|ɹ`T4'k>0 YcZEΧ&%>kr) i3#Q/jr1rB×eEɕ-N4y(|U4G_kd"ijd&+e&ʠ&]іmKd'՚ IC Dxr,A:6pp98Mڬ-M-0'*i$6q2ǶS4y*'Oɓ bgx|~¦|P y8_x. ֿT)V_^kR+CS xi顿{*-#eg>%VQrw&(i_Ke\N@M8\+ȫy&"tt?!iioI%Fznė%sCniN^ Ω7礯@TiEKm.b[x_@(}³-܉xP-+nB1M Imꁔ{\ ǥ\szs%k)90kw:zh{0߾T -c}y}EXԶ}%mp ;560joکOUG|BSu 6la7 㥞naw5.eZy*dGLR5-yV.!wK.״ŠW8N̆\VgPjk,lz}]u_jM~1R/-\#L-Tw-5|Wʭ0qvKHe 8x :Ώ+Sp,Nj`]>& SC<FKKzJ//qgIVX|mM/9˻ԣྲxU\\USҕpպ[tK%.c'^ŅSąݗqq[q1kc+ΊH{pNY_{MR>S4>H"6_ɧ8}k!lm VPbKBtd /ZAQzAi)FY.bv[{~8\55iN1w^ߴ2e"k>q n)b ɬ DlA5dգ\WXBH" GCT(Vr^_%M/7#M=;5.?+ 45:䪴0+C6~iśFs <>!2qX v>6 Xmo8&g8`{ү[̥DK8ݵЧ*%U_G.CQD6[mFRlWݬD.9-T;QrZ)~nq1j1_*&PՆ!-4"BRf߹yL4{Vmź,unCV̽/hIXyG8}-t'+JXrDZ,]> IiJ7ܱe8$kqnI^olWD4>sOG-KlWrּևX],*lnp׺J1ofjX4,7Ps%O"Sk+9FZfLWָv#g,\QQc*G]\ӷhaO~_^䴽YGVn6\|uxy_Tך>N l(%1+c᩻vK'JA|bj LȹVq8n#܎CEM ȶpf,,(M [V s?2J6Xifi2?Nx-}p YU˰Xx,PV/]) Sj8 iA i,NӠ#L'z⢖*X_8h(b02'tba^*A;S"BbiMоFeqr'L$HƦ (7}7ty-3,ܞiH;.vf MƳwBnifyli kI섾}16}P!I\u[A/VЫ  d)'voO}XA&,}vB VL~v>C(`tA_Xp +a&a5,? XpΠ+n"FGa<a/wa ;؊ d́Op:3q<3\Q i][<.r(}3\E5Ũ9~se`R13]K7誢x;:h [xljxQwP^nڢMjY[(m"jpԶ`>4PkC-Isd'[dG!vt(f pK‡Q}>A`%OF<ҫ&l+^bZQ|(%T_!g  R#`[ z8'$mQnIlÓcRG9'E]q[3GSTSj:1̱bKɱEt 2khP[E 4 ➁g&Q2&J&(${IVEJ:=MޮS]$ٍ8;hH*5-Փz| 9vtpRЗ#x0RF4&feܗ`3BP:`C(bT*wKyj68˜ڥ;O#̢b6B-s}D|n;4jGQy4a00c(='PKM8݄SHT\W$疚IRĹJ^\MWvUvU^BbRBQTj&y/K=CWZڎRb(uޘ%td XOh;xiRGHjq7GRZ{"or7dA5ڮቐMpZT=T_&o[ {x0YSxGo +ʄ%qpnZc^8W5Q a55c3 eNX=Pf(gT flv bl^ =} sh;ieTZZNӤ *1Jos*ozM~nvщԴdGŁWR&XA 4ZFnXyA/]ј$`,iQ;N&0U&nPLNG{lGI Y+@" ?@F031*ymbRMi8;FPDAZ+n(OgʳyjC_)/S{uC358.Nl9ǥ7&AKP"( (o]*y/uZr( (`slC٤CLPN9[R@|JP S/*@&ʾWMN2Vʾ@lۉ}R[k\Va j`Tr>`úW!iupܓ9TO _9yLsR>* ^cMpvf ͚Qj5V233*JRJvfoL^>+;=;cEΡVƾͮBJY%:E#sD.,LcE>DE_"v΢B T14ߏ]|M\t4=wKy.WE 1`CW1rASMvoG/B/ ݈\E?+R'@71$$J`4 &Z" K]qȎ^lG/j1LAfC1\}V 2GM9;W8W,M,H/r7͌!3{Bw>_ :ǵ]AjrD9q@KhseZIr-uRLn>fyt"Hב0 (aໞGO&7\ ̧qSl3  D. nnzIO6Ur]PO4[2hؼZr6 NN(4*>i"\@G-:[n Peg8VEnWt;9"S#UlE\ q!-tq1̣q9W&q5lZ y pD3<Q}$Tw|6n]$@hsOM/D!,>O/}D_!*׈DF oKD"o}=aQ)>|8b3X>dʾZ`-?8] Lu~#r'ҴF4#UVhwo7􉅽OO3lx+x__x m"$}m!޷"w{Pˉ_=8#7 DALYÙf1ӉQXLbQaj1S/bfC=̎1;b13W.b{=\\ك= fy]Qfd1٧V1G0[<efHABYDЮ,ۃCyj@N\XDh\9_KoH愿OMqNjzz(I8_'p&;s(sF|q~93To6z?2A~d 7քM`"ЗB#Vo]#F6FGt< D'Dt2SN%:t3Nt&R aN.8c&F`ir=̖X,khr*YQ6`<1~bFqDb;٬fzLyV:/U=ZgZmK={>D]Dt1%D=❰\nwmN8>r|#CO^$_J PKb+y!_pPK@-proguard/classfile/io/RuntimeDataOutput.classKOQ)J@)H~AEBx 2vzQwƨ;cԕFj"1QJ58i3ZE </E> l]);K%e)R׃}x5K,<蚡m m7↵SAo G;a]Aq؈뽩Sz6#?0,:dP^/=4czLh=/K3㤂1- Y #m.2BK}]2{jF0fj6 ŭ,lƣή1VfCA>3҃+qJnNUQnX~˰\F"{ cadmZ5TFP#eXVFQ/Ш&֠EE@FS00)-1iI,+(& CDy>ِ'խ=Ԣ܍2__Σ ;Q1UXZo~ (p=g/e]<:>(}*'j3sJz^!y&|©)a%0D60&[\3-p̪K1Mu6UͿdXLiW̕:穻"ae8{'xL\\g" dI/R|+6L* k_&|d34D+5"Kz;cצQ<}G(~HcvsBd(|]͵5i:ߊIwo(~K{v9/r#O+9OEs7)A/vגPKaPK@.proguard/classfile/io/LibraryClassReader.classW `^v;=&nHl2&&!Pq; #xTmzVXjQGUkjb7;{$IH%߼{7Oz)b-p @;n6nq+{vp;W)Rs w܅]"5w>?~Ep={ws܃"b@Ps\!}ϝ{7DTG<&q /}BI\>)˟XS"8gyZR.*b9ψg"jZ\_Qs"Ny/hv_E;^exUk~PXֱaEKuKdžƕ Ǭo 1%HKZgX i߷AmTV;qUX@ VQG]$&-*hu5o V# l&S Ӽ "Q%m sM]LT-ZtÌs^gݺy ֚OeiglS:4׫Eh31!Llb75m\t4?5 uӎGICOx<7&:zC v60fOk 1HK tN*A:LJ4_?UQ8:~2HAJ0(5Wh v`Mk0:zCMʾC I6֏Av%ba݈}v<Gٓx=Oc/i*ao9g ԑר[NJ\,sFsP:u卟7E?b|ZtF18"^s>Ḛk4nfɏivfD!قI1 DfsiM2lp0FΧ8_Y4k_\)m٘e9|8YQ$d2^N"rF.llf6%d3F.,K#aSjH?֪ Yl>\Bgh e椽[D6'S Æ'g(or| cWQƃə0 )3fR/ Mދ/ƉKn)hWk@O7=Azg3=7ҳ]0ts5=CF,ĺpN"$HrɓIV\LKI.#)$I YCr%Zu$IJdH~dc*  umR{BF5I'ϸH,xth+;B| P."sṃo,c f(yǎH(oWPKSN PK@Eproguard/classfile/io/ProgramClassWriter$ElementValueBodyWriter.classVmOW~,eq (Tk-e\ėAt]]E@WoEٝܡФi4hE4~jϝ]f$޹Ϝs?g8= c NAcp$8 H8a0㤎 r^x= ɉ-.,ϛ%NzU*UWH0󋶜RaTB1 $S04e"gh6˳ܽl͖Ȳ{AxBfۓ-Km9c|zQ߹3汤tŬ/ɶiI09ktjmR@jJ?mZWk tv:|+Yb5D6{5ZH,̜ms7=7ygϡ 0F?+7kTСcY|+9q.41s&Kj3&⚎&n঎M|;E7S\)9B})J(WJbN* fnH7%= JB"*e zR{&:[/e~ƒ֔/+N2a?T9K.X7zҢ)Sq:[?$+|*/ꨫm NʚrچU:2Dz$3B΢ mN8,G oB:V"FWB: } e*v* GmV;+"}ö:Vߦzۡth;zJHރLP#ivS۟M4%"vMw CiU{HNtՀ'j:P'`}ղ1yD4ѥMn]_CS=8fy&'q<4L4L4,gNE /h, _I KȊ_e JxMސSPz C3j2%jZL3!5jkAS4S`ՐfczX*q`ݠoW=;gòL}ԶΑVwōVPzm%lK/amՌ91=}a1횬NB KR ҙpZw`F |w>'غdLu'j@V˳F:w|.ЭݔC9n(G4KtCc_dԭ\oq0Ӧ}SMsurL]]F( {-8չ5'EQr k|̺BAr;&Ç}A3%pn| Ϗ-Y[Va-\׺i_PBaMhnc{΋68n֋A * zt>mOS 。^!ع!3\x)gKR`}{wPW `s BJ3 Βo0wo)6sa]&c}@~~O~. ~ɝ_% U;^' Vd.)K0Mu*ejjL`K5=s+MĿ)=|TmK DEIdzjL_6Y-n,+Z2fٕk,zm(eOuOSu/e1IK`mZ:X7hn_C{$'dp"nZkPR{hWn*%;Nv\.Tn'UP㔘vȚГn;'=6Jn\JLdg[V'˄7\߅XibC-f)*Ty_ ֔Υtv' z\Ȼ{ s_̻;5k:lU*gY|Ґ&s߻}ZW:XS/A;)8wO\`Aחh^DZ%GFH@xjG:Ў2\,A TitLb9J88\-b zU65n7c/ˈ-m_IԺWo$ֺWunnJo!ڋT e=#DhtR7Дø1܄ލQCa'yD* BPoܒK&%f rB&Xpיa_:1<ײ妓ڷI銵 Z"uyb]$N&\%[QgYb5>O~\J`m@ ? ۶/] G3;}v$Ǧ^V`= `3z7iUwϡsޖ '&PWZn0WTqB?^2[-`>]Y5 IUMYXU Z-?!Yz?vv[F祰 t<ȡβ;,\5uX\XQƅ?b -/>ePrmxzb$]C&(uj$f>#E22;9.g-4s8IfLl:.q[SNTS!<g s<a#&+76&3TJf/3W\i//.9TVB :B-NonRuӇd3;jWX^8xJz_u0Hz}غTP#B Y'i@ *BIP={ۊh_z_"=1]OO)t0 tZtjP@mc[CE{.s618oSic*`UL`>y1R^ڮVK ¨ 1UUJU-]{3)9ѿĤbc QehB ybb!Կ#. z5]"} *5LxR[l\iPKJ\PK@,proguard/classfile/io/RuntimeDataInput.classOWǿgY\妠7awQz @Ł:;ki}2MGMc5iSca@!lݙ9s~l8R&Ї10Gq!a'$NJd%$NI$%&$&cGg(VRKnfogg $Ġ8kU q Iq#t1!"HN1W*"|'c (/󄬾U^Vg_`j,r)lpOB.2LZ1ж9!"\8,繿fKd髊@%}Q%*4y{{#.tʒP;X-dW|^V0hkhMn:G]D'VIlsc@6c fu&[F&9/mPmMnZUDj4q )L1q:L¼&`ae+S GM6Y"ɉrDnPx'S54psK4ZulArn.\G> ])%PVBIw?vf8d]d`Yץm)Җʪ,_PӇ3.ʺC[V K џ#Ndۭihϐ6LFHAK}B=T$(¹}|d'a>l*ؙ.b_߾82Բ[$wdAz.\$]y)>鱽F~;p)/cd7}Nih?PKhkPK@&proguard/classfile/ProgramMember.classUwU=̐aEZC# $Tj5MBMhlZUpRLOO7n\qn\s 9x}0t{ݏ{f@F 8E.HpuTeM IXC?`)bQV18nW:Kk6nP(լbp A\ĸ .&u K 걳aؕcm'}Kf>t/+_՗+S!#! Y < R``⿰C[)ƛ GD u.j^1DNWʹxV$#ut^n[\Ov_Ev"F> >L0jbxH>)nݵU:WuwKJڤqݧ[UiGZu @lN &Dx D=;ukMǠ=EDM*0~җi< ޱr:_:pbw;Cx g]ص|O=1޷ܜjx~O(eq?,IQ 70ff,v?PK[#m PK@3proguard/classfile/editor/VariableSizeUpdater.classUNP]fZf(wA+"s"pq!a0SIۙ&\D?2pK4{?}0jѥ; tP[Ag"aD !0݃d⾊ l&aMw9QID`s[eC$ Ma3Dgq; 8+HKײţ!eXa]d$3ea yHw\s][.\Z)G0P/HsI9{+} _IʭK2>{d9,KJ[} -#̗rvJLIZ y!i s {Ќ5 ⑆! xaOTjø&4\UiXz%tj"(ZmB*kmbjmj{o[{>ksf23$$ߗ}k{ؿ?b;׋%$_g߸@dit\^ nI<^ʡ\IR"iPo944\C#%;ʋ3hh Csix/)9t*rh:&J2)&{ *i x1JrT8IR.IE.Mi^N*%w$gIR7ՠ$&3tlIΥ9̕dRU{i-ViΣ%W#] R).rɭd[%T˴KkZ/]DsiE6JiD6y AiJ0S$(IS.mmҥR3EI>K1jͥ85R6mvà ܠq>a' AWt%&b V0jA%[5x>FלG ml4X٪ ]&kioaBNs!PsKbf-1dD-mEڂz [n,)f3[V$y=hV\Dju}T V|YE^nfH} yŪgN`LTM*e4"VC(UffEFc氕Ƥ&k{0 />dvgsCP|.A/Z6YXۚ7[ E.7ovwRFpHqLHٿjҽhjq@FWM+G'dQU5i ՍldZ%=Xeod쨊cmq6ˢly]vl-iE-Oa0@ˬhC?rd(#{ʞFTjᄐ[1Vi(`U"ҤPi1#Std4FXwtzGtE-=;P2>YixnU]".,[7nEb, k UHS^zG M/Q$"nΥ^BـuM܉%5q71q-6q7&$I 0A,RF*ja)5I=9\ဉ20AlCI_5 : ߃&uPI]x۠C&}70=a;8j6qpg]3x1M'8b[O[e:IRD7ĞEy2.IM9'C އ6\痄 ?K2ڰp:vؾ2IbwX+éI~iX(By%Jf:JQWeVWQGiǿy/3L,ݧՁ69ϋtfJTx_{@_/ ;(b<虛-aq`5![S{oK>NmlX|8\4HnH[`!lŤѦWVҾVYh}=6zAwAQ͇4lh$&g)-۞ju4X-kk[lWmټ;{աh؁\1|')\j> @5-%W9ԗV}ot79ߛqEܪݪT^x H^L 8 u?J^@0sdΓz~0јn1 [7b4p `2BlfBG- f3~<ogK%w`H1vaLFtb<83.S9߉.(PPZ+F | ؉-ְ 0ԞØ>PJ]80 3Eg\Ʈ!4HcE'Ɲ0HO!6 09> =6Ɵ=NvgfAׅc'L^gyB $ _-ys g#Yh<[G,O$Ԫ|(O3bzn=%8u_4eͷM1v7ҲNL܏ggt }j%_GxO(ޥ+KO'W޻+NTtbt+pfzQeMr\Vd a(:3h,]4S5>Tˬ&وwcq g捊gGi ;04Љe8guavf2}΍؍1*r.Ou0Z1S(s(j*ڎ:/gP -4,u`EU<fnyi¡z qu&5L|-_ǵ_qC|Znb$032݈\Et;oytp7p73ic9$\dhwKf'3]>W^*g|'\p#t;]],BeBtvź0x:I$Q@!g9{Q( +gJN,ݩķu<+䯱~zm &/XӼBn`7VrLw#>k^ ׎. ˦{}9O2牜e|+d2؝V<xz񼋱Wv濣Ùa˩0ut Pp$%lY@C՜lIp{y=.JV pkjNHm2i8] D+TgkňIx1/R$»(G빢Lj@Vk=XcU+υj8ymݡ-Mv5MNiΈ.k cvʵl8_[UڅجVm=Z6^r\a뵉ʑS>ã;2>B|dly|=ysZQhmd;k@)ThWcxΑK˕Rl'E#\<_/LL4oEH6g;|.YߝJpI6d,nAv'L Ax`zjN&5Ztg)!ĚY>8jiӎa" {k_axQu  ʵ/~Oc!÷ooe  dZ>.\Ǽt|$] aY(J ǗFGܤKKҦ.3mNW.OEϺ%pGxW JfSzlLٔMY2OeXdn} ?vdpVg?҅P8)]JfQ@>i:b6󋙹LRVieN7;0ʧ2 \y\dGw3&> 90WǪϽ#-ic1jepi'b$ñh] ~3f2YL\ddBV&-ُfq3_#NӛEJaN/n%N0A%+f1V+PV@*L˙c\C e.WdqcmtY}.܁xdů,&נL[f-]m223e2nf],6w|xeeI@=#{10PPZXoc~9X{-K_k@x'S!|?$% m^o'n!is3#>>xInM,qGl˧BVU㛅ݼiy y/Es(_aY, Y>s%>\Ϧ>CS}j}0{jwu]9kFQ*_c6Ug_+k2fd4` PKȓ`CPK@-proguard/classfile/editor/ConstantAdder.classWUNt'SڤIR< h!!t$-}V&tf'Lf#V@4DPyZB;Y~BQAO9w&;{s~={Ͼs?Vc@ 3 cvVWp/ai X{s4d0½oj ۥ[v|eWkra|:k7j4u7{5jna܆5jNF@ 1֎vcw1q֎v~;~;w{^oxTǭcM:7t,[AKm d ;dʌB4M X:a^@)8;N:k,66;XV]AJ fw'fofϴ})TR4ٵ-VOLi&\ϮQ NGpQeVԌ$$rιT$*mrJ#ЫzW2R82{9XA<-̏P Auv FЈu96ͦ3I'a%Dl,N'jJm6bPeIF m;#) >PxT\'pulˉ[H>`LƠٞ.-J&-VƎ]I~:'T퉄i4F _4±MU?:`_xxX#XQ<<اWx\mmזs4P{=7uU$6m~L,rdٱT>Rt:' ̤zdpRS=4I'rz*,(E3R1? Hc5.:&BM(yT¢ LqdTNݹSY;d6q3!OzF\*X()ۼE:L$O>nj"keѵ r5: &}%>ϡa}7l[C0{R[L"\J se9Îm yYC8։(]H,6ULk6&dlC2ܒۗWL-{V1ϧT_]F8IEb$>qi}Fi՛E9*M6wgAAǷf(Zi)(Cu<(YrQ5LHRr*$7N*6@5YĢo5ɩD4@U!( cEPv$Ԟ2j4q搁Nד,p^uf}ʦ̨ XGDFз<8B7Szj?憚\t>$c6.%tg-CAKE 8Iz;brY$Fl$%Y^Ijt e9MPEjs%#.l֩ܮqQ+ȯ%6l-m"/Fm?*CGP|EQlA3N87pAϩ& ͔g{0{1b1nCwQM3/>Z?lK"|ELbqK}Qx`=P1v)7T}2 >~"X$27I_ A!e QM3)[uBAG3LM$wV Yrgιg{?Gd܎# 0qLᮌ{1-*13+㾌 ato8eCfgif٨vyl:EZ{|%Ruk#.GHqI ;5,  CA s {W0Q\QP0BU|ةKE˅aĨVmʰ9|ܪ[h4cٟȧ3 ~srX JA:nGFv:v~ Έ@q141$K]Ásq MZG0PK^!|MPK@0proguard/classfile/editor/StackSizeUpdater.classkK@icckZ]j ]) *qڌ:6%Ua($v.!'3s͟+K a# D0G7F՘> u|1c!PrV-QtuO au:w-bFHJLfS6r\g!]֤Zcf ZѱCr[ĮW- wmʤz?,FnVBHؾFP'#@;Qr<"6t~d)or˰> 00A1m` Jkbv ]"rx9_c` ("]hXHVQP7s+-!eʦi-PK sPK@5proguard/classfile/editor/CodeAttributeComposer.classZ |T{gra!L"Q#B@B:  08oQ|!V%ĊbֶmѺ]nnk[9ޙ+U>ws;=,zօ. 1_ĭw)~%Hk J )o5 E~8?RRQß4 GB|(K!*G.Lnj""E U"pJQ" E.# t+QI!P .X.~+]7 h$y".&KqXRT) dbfPU3Xu"T#"EuR/ETO'HDD .:+ż"jESba5IҢBj.ŅRHK 4N~YT,gqZ]FˤX^Hgjt2}F.ШÅ0\#^)U2Z5ZihFE+N#jh/;ᄡPtmE--/3^__~ptS-;x(9= X'9ԓiV#~љ֙`$ aYDpGA?%:e>#'~xY$1"TƨśG'z aT P7Nbp+6x,>7RZ#]yxB{ KOFC[ۍP ţ| hL¤#4"ֻjf[ٴPXYolUe3LJݡHs]e_z{HCui 1zqV/eeVj4"1LĥP))IFh˷9غu%L"/ypیhp2LMIKӗ1>ѱPW3`zF'iJ'GvGg0-[zsyd鑃e|2^e>}裎VZ D:7d˄\4nPD+ɸngν|)CGeG&@&K1lyF[4f6b#M&%p:|tҹ;H L2QBƘWDc 'B?d8X35JE‰ 6wR|9]bD1#͡$fz&zzSoU5g9gtg?[f:X]4=Ndy׹ڣX$$2|93bPǽ!v2z7F7IqVWm=?0oA:]Q=؆u\%د\F2d8ltM=L̶ܢDW861㛷~s/z}^y^3FлF RthNݴJ!!6t!)L=:~" L^."Zޜ!"{݉wF}:)S?mih#XUٸq#MϙD8'ܛzn7+(&/ #b N%:->ӥ]ӕMj?4VznuI,somn[un~t~5Kq5iL5OiF0QKt4w*~}޴4;']/ |ef?/AZo4WmSb3f7`;Ѭ%HMkNOuzR4~)FO(DP̧n7x-+q15"~⡰A| a;{uD<re;Ώ:頱Z6;eI4͕7SQI^|)^KV "hٗqi;7ţz'tg Yw5*wpבQ?*můj"3+J͜X$YCi7zxa  lna阖htC&wȔ0Ё. tY@Ag&f K*&_;&; v(46TZ֝)sMy-uWee\sǢ 1q$ЏM،-؊RLp1Py_R˹EZJ}K}]_cuެo\ɛYl׷Vs6nwteZgwX}ܛ:c/t8Nga97ŧ @:Bf5+u]k\:"_Iɋ1W b9%(yP6:A8Ќ"K ?sЊ&YX v1)}K1A |HDpe{1a/ɋ!.ߪPDunxj?b.+߇I2 nC &$T=ώ1\GYqq{ծίAwjI|B?5 d&,B3iҀ\^j\n  ENg`\%lY;M%͵T)nBrpXǦz,`l!Lq,cx 3u޽Wxɫv\c;XIl|7'<(vٔ-Q>Lދ7a801p? Tum2ֈ18_%^WۇOgS[V!‹*a>)XF*~,ԏ-27mGLS-hj=auzfݏVۇ*s<8=rOGqǯ'R I4q/ʶ#Ⱦ&؉բ{Eڽopv ·%fz3wZx܇iQRp;2T鳻8q(nШ>*É44-T6Ju4T;DG Es$óԈAZB| Zi)9 1[D:Ucy*)eUڊl[+fkpȊeWvŲmz9L5)܋*5['Vװ4"ps5 gl&$rܱhbB톗D/cpNb!kĢ,fevpmvh-@K6ef @spT;P;A>Ӳb$zGWmF"E7Ivo 6<.>6N-S0M3{Ӥ9YBs;hb5wsHɺ}PAT xh>EUawAr] r[@keD txEA4ECRȫdI:U%iyeYJ)2^>$&˳L<̤G,L̡YC$)Sqo:Uf7pM|^Vm8ͽ=;ٔz+'ȷi$l&DŽ<M12Α=vZM)V37vȈߊ,'RZX%-*~*Ky^^C2:X.#%ceYF;X2:XJT.ɾQNs<% Í ;&y!HZ&Z|:+Q(R(Q0Aef(w/)J >^A,5vrBWTs|*9esE?ʕxu 6cf'P~MWGU}9!73 1$_jQé ,x]K}G՗ (N3}^={(.&Eȸ%Lqqy >i|!`&GY_⪀9_ P `!{p:mby H1ҽl ꏔ-E6%yaff 2CtnXԝJ[kxr+CP$8.GE#QjsIW%6'9ϫ˹##}mSt[ ^]})q@qB.\ϔ_):QG% j"~@08Q,Km} #M1[oPKWE0 PK@+proguard/classfile/editor/AccessFixer.classW[WWNH2$ \P@hHEi"(ZG'JX[SKZخ}Npsfo{}9{C;1~TaHhN1I1w#Bq }Û5x g|8s~4񶀜;~\E?jb"ᣉ\̎#%l/1),t?.( IW `P,ú&7<)m2bf&d$!zGxR2fH"r[V >P)9DJs33_,AЭ>@?䄋MĹyJIS7gu눑YK3,ʮfed G-S,a;Z)R"UzS+h&Dpo[2㚑Ls+m H@~JX$}Rd?^ΗH5?M5őSb:LHS(kZ)Y8E%n ,%K"+(aՍQmk+ZNf_eą:]{gyG'/rn hް.qKOLL]^0%;.kS*B ɪ؆.X*rR.U=*HD*| |ຊJQS7*[ S=~P#n wUpYz:2OLq'DyeY*oEmV`YD YaF_œ(>{Sx! I҇CsʍHS| O *%O6{5#9F/d-ݤO[Hf/0)BU(C]%lJbJy,A7,nZn­']-a})t7Fmh]C-}Ps"zP|WoT Gpc!BrpFڝ['fYHH)`ɽ5ĈsW^K{IP{Q>!}mK)~rH@ cUXnC Izm0 >GZW))9E=k9ُ6U^ƫ"'($ib~]NIɼ' /͡w/FIOLhمhx hruۊh)*]^uܠ]!iA(d:@9lYPMUYy¨T.w8 .*UmQ5c+\PKo =PK@Eproguard/classfile/editor/LocalVariableTypeTableAttributeEditor.classSmOP~N[+mNT2:H| d%,)rwkO D~?x[P.Y/s9=_,a9\*&,\u7Ls6^⳨DZuvI)V*9uDN\?b^qw0eV>S MԄ|3=hqS,y%hHRa 2K16 LL۸6`|z#&fm2E}ck̜n/ z9t,!L@|K:8BXy?cF+`=?ԾVZZ~e[S1*WjM T>qǡŽ<LjChПQ泪d~HƢ~r>c0Kvۇ^i-?PqE >BO0*xXW 0PK$PK@:proguard/classfile/editor/LocalVariableTypeInfoAdder.classTNAZ-B) ҖKuEQ`4A%MCY.Q0HPsFʥq|so3s),%Ѓa h81a4(3!G ,8N50 ȱ=`hxaZ:5_:~4'Yj =3Wei*Lw\мV.=KmeWQ}*Z \ 6g9?/PN7b[)Oy"(@1^c>.)\>)+/ ۳jl_J#M 5Sk^#dj+L( Z8 [ږ{RG nX BXϛf+`4xc!0:Z`HፎuV` G$Cҩ>UŧRkX4hMM\_Vh\nW$ [9UK=0CL>~ l"{:Z!;1QG!o 0D''.>)66HEgHdgA蜍l'-=B׿"ч< PKA:ATPK@-proguard/classfile/editor/SubclassAdder.class[KAQsû"p/A]I$#+ :@~T*dŲþ߾wϷwlb)9,XAV*443ztxǐ+qeAN:¬:|8¶бa M$4!g1mV[4`#.=m;Vc; ތ?]0}Hj*!D^JgI1Ӻ@^A. 9v\\zBoL~R#D~#DŽPKN`gPK@Cproguard/classfile/editor/AccessFixer$MyReferencedClassFinder.classTN@ŖEpۮd z⢴2Lɴ;4`|(C&69szw߾ `m9qFnঃ[Xq+ V~ CsH( /X DϲxCw,cU2LuҘ3n _  RL2C3<-uMF''[eh 6V>B3^ԫ56^:P ]70tbFk.iƒZ/y+.#ubXJ<r=qxBJ*_f>1-ݪʇH;WŰ8y;*B qabٛ2]Fp޺>Џ CɗHZ! g0'wExGtYgSN1^8qWHְ1g`fjA0ON:I@EXėaPKBwPK@/proguard/classfile/editor/VariableCleaner.class͖oUǿӝtRVtiHB*RP8ݝ:;[Z|>a И 1[J41$cb 1ĘhV$1Mϝ=s>{̽|؈}l@O{ QЦn,!1.³9!xhN!zЅcB?OIG^<3 ] \(8E%lnfhI!Zm2R.Aꕰ-pm^#n-\5=DUF\?-g#FҰ[c)͊Ln3KhsKNEP[D^&q˜tix̊L&+mtᠻ& LX,jz_v9rR~K%4 QnA(mKX,7 S֢.mn'C)᪯ ݂D?L]݅R/OI>-xiiPL!Hь #G"8َ~w8W{6_rZd0.23k&uP8veWﮚ@si* N۝18 ŸJk, qt}K*ۨ7!62P&|xwpJ P Z M}nNEKD6Bi*9&b_Mv(֨89+(+SX6p3gX~/b C }7;'8BqH6~<[a[f\V6psDvl7N?'mlH'̱3o%X9Һo}׸GkGKTYX*FrN7PK8zPK@2proguard/classfile/editor/ConstantPoolEditor.classXkTTef.3\JGш lEMDqNHxAvEFU}A/҂@zL C@[q+*˩)TT 0#oML6E@z}Oiu(FOZ2=mmn_PiWQf4:ϝWw, =:M=5MUZ tϷ$~SڋJ#ȑ-[ {)L%/0AuǿQy:;ZcT rkS'˔zb-^3y֮Cu޹a"}F^I.`AUvǕ ݯً5MJ`^KFnhvx8T| +@ф*nn ƞ:٪GsVCVhr[f2+pRr,ᔌ_ᴌk/ጀd%$5/ OwVF=#_a`2РȨg2lɰ0#gRo7eexGF2֢EbMcfPl ' ~Oޗ'pv6etO&:!}Ey]@H[d2)/Oe>E#>($(R#/je|s5 {myKgr"JNd\SC]EGKX N:ə,, c#6~AUcZtA$.VƹG\.#X:?dgŜAj gA4|>KDU:*WNgrx %UPǐSEm8Łab*Ѱ%oF*GH=  z(P!!'7AA@`6!S"[ta3\V wc ( Ƒ,JtQ\ϙ#*c_8AX` Y5D Ȭh@\)dA@S@.P@.R@>|D7 g˄~ $:>%VQ#ZFbRdn4 )bh@:XE ['aoFKUhFq5!:Πpp&)7vtnt\st,H鸒ӱv9dz/\'Pl7F0o3F\*1Z ^LDe6,c /-⃄&>њ*(W221DQza*Q],0n"cpO G܇\/D$S{x*4ϐ,nϰ-ĕPV]Q}.,vWiԝ*gI0}~>Ib"_jj_+%Dp@]z4гcBOS6:jg]\6DȀ]=}0G ċvx!*Cj ȯTy!\tTwd{`(?4xi1$fv/ lvתc+7?e/Lkb9*Sԧ"ł5)VtȄ PKN/u IPK@.proguard/classfile/editor/VariableEditor.classS]OA=e?*ZJE4 FH,"cn!1ф? owSEs{o?>q- ׅ A!_A&07U Rq!͛|[&[`PM˶\[߆pcɶf8J3kGOQ(XCtɿ,XbqV2w)e{Af䉼i14O]yw jj5B /Nֲʷ̋ϭ×J.bқT=Q MH37Oݡ|YpQw[M)OWFp4UC0 ֐m pw50 bVa-Nl-#*QŽ:qUWYX+ PM[\HlD4z:lDhԛh2?HA~zK>=E[I~Z[*֐=Oht{`zx\O $ {Wl#!ӭ}'Oy9|M4Quvt$EOPui;dGa &O8N b%* &r3P1Ky=K<@zCgdH*X|m{A&Mur |A0)ӟ7ѠGdOE)闒JDB)4"{J mNv۾.jA($50tJHJSmoX;/PKF PK@5proguard/classfile/editor/MethodInvocationFixer.classWit[GƋޓv΂BFMڀ&vV8 $giD~R'6Zֶ,%mM 8l ;ز@J -`Á`#~V (x5pϸF\XaA=G蘘K4`>RKCF,Qr9ƅﰩ%witL4nG|S~>{ _H%*>*lT >aÏxăGqR)< >Ps- Òt:'<X2;,+m f-7d!қJ'z:%LfHHBm |.!⤃h+֑dQ;a|d Ӱv0Z0 t0٧&hQ#cXx :Cw:D'^lF9~a/RK؝cCn*+J{,#i2:1e @銂\`"C" %RqsQ +24cYWR_++ڕ?Mx!@m9j&c`1xzQ}Tm m*}:ѥS&qFç 4܁> sVk8/h؅n _ė|YWUMw@5 _74zobJf4̊'q^÷() O; {}@@#h1eX設 " Kn_mk^"^"ي5JoQVi{Y+mSS}zZO3/°S =Gi9NVe$"H*a <~@$8WohʧKI1R_Iv2(X_[a]6T<éUtbuePch]LMHI0yI C& T xz]Y=A*$GŒ${}ڎ*z|ݥG(Y"lF2G-&iJU`XS)r$C؉a}ԐѥZbT9'Qqr;`u+ԔNJRa-4p3-؁J{jЁFqېcGȾ%z7%+L Xuq4sjnv &]@8!a%U W4H-9Ghe'IA!'kތux  D5p'02q/&(N]niG>Q'cyM1a B;x( E# HX]X\NnEхhbyk5_.1LwvAP:e,)kA\.o(υYsƪ-i܈ z0dҕӅ""UH+"ݦ3@ }5qdTՌp>7 Gw\?ٍaӑ&䌰rB>1buX猖ӌY$λë H^3k9(줸dIn_$ֵiexTZd9#7X|t360=i{kf~+2q 2u7pS;bjUĊ [y%{\/a['12ְ.cE42H≌Ml1N.Wd(HIHPApl F3z<` -ZvvZFh}1ֹaabhڊF u;ۄoƌovy,X,5)nl{ cr{|Ab_gsiR(kk"TNqupIyR4h|*Vp E1J+5MZ~0\>1h [ mS65nS65MdN#@2HO+Fa"B8e8"\#H$')6}N .chL F"X`dw3L #FLJS *jdSG Fֈij Mb"w^Ioё+|CtH3:^+KI`"mV¥CIk_j/ࡥ}Ws(/Wt| 7s-:IVs+ɉeijkzSCE^{5EqZN a\~|~ c5oE;H~@ PKX6PI PK@1proguard/classfile/editor/InstructionWriter.classW[oUNlggӦNs1ms1 vi^Ǜ:k^'i(^@BBA UJ>#7"DY_n !s7=39B7Fp'YD\8.8qZ˜3 4gq[αxEI|,^c1s,ȫh/y63+Bԅyx_/,be WxpU5 iW,WT}L @ +Bih9SkfeLN1XJfZJ?\  ify{%sLܴjWSqjV5ay-\&Fib>֢0Rn ֲQd:^ӤnrHhrEy8MjE77 H bhێv b KneQXC܆hYŲ^J ۉja566MөJP3)%1N[aPT gsZPr23bW:C8ʼ"2zы>8])EGR)uFIܜ#15Spd-#I^UcяYבC6sj 2^q /ᘌa.afӿDU S;gj%45>ť͑7n~2c,'SmEk\~΍K_ĬWb҉;yÑ 44g+FUdE8HX7V6Ϳ8>9Ӎ:d7Q#駷N Ђ$-e7IǢ h:2l_=yנnI>dYY|xU/#pzVJ pl_߲?hvrN]BךǭJ(}m  -Q+mڦwïx_C؋OA|&#/'B—b_XHAڽYRߑn"$H ^hH7}yt"l}=q#+hֶѸN'5 EcUb 쟄cW`%)$4 'a˧Wl'][w+8HI4CnE :E+YNX?PK.ttPK@Cproguard/classfile/editor/ParameterAnnotationsAttributeEditor.classT[kA&fKV-Tz)-HJ/1lIvdV_ T>*MMC%9s||f~;PIJ l@G\5MdpCGVM%e[W\PBV T\aЯ(%VN'vĥ;s ~M91h[G4~ ^FݖoxC9ycÚ]cܰ#m?kOT|-"g㖅۸c.1% acX Nb 15Ã:bHڱ̄!z2(^f!=)i?:1+e0|C)\h@:=Ɠ#/A,,s+>AYVXħaǎXPHT-S Zb7ֱ:\:,q9SqW2Wq5Sq2׹q=nd#'<9-x6nS8VHz6W hb#6b39\0maP!%n<Ü"LE0I̍;9Os. Rۍ{ڃkxgjE l \ | ^E^%^P 5h_u h(P5jy վ7ijC>V/J F`l0v"x |e7!4B*Ro7x)Eie[<,?⏮!ޖEl2'#2s+aoxwVQQO0j4qIlϞ9N_➩!慂MIwT #E$FK; #ł86L*tTA*a=u7C֐ hNhFЇX}hghxw%լxOr}om5,vYQuNpmٿF!l4&5-pAqn Ӛ}dH:A7S82WTfN)8?XdžݭJXydQDShZm1j6U:mNڪ =.(-bͺ",9"pE{Y 2JZ!)k]vXi+s" LDg޸hKԌ5 Ch$D}H2*b}(KHPQY9NCЮKEKYނְ:sm9ᢰ. "VtnLJ-6ZÆ5:6Qs/ MUo z9DPs&M@LUh:sbn.=v֨)lo%,skR~uKp4,Hѡ7^l)o`7 laC(ܴU4 .ä.ݵ`(o[:<{xNТ|\\/Ŧ8hxR10zeWhQ3u+k-CGs8)w:۱.:QbrDC!D8W}C=NI#^<:U u0Lo+m]dsu[ T):hXvVSPlC)}SX `}S3:a2&soRjiFA_/jix:e; 5]٤tw+v)]#9c0cWbXy2N検JZ-,d2b$DK5.seK5AYlpػx6/lx[Sݥ BA\A+L &Oiˬ XO|B^py^qyL] xS.x_kuq_ܫ:Ŀ7x ުm{whxwqn{ux>F_t|_!$#:>𐆏kOߧumUU@]¤l'!LtEF&eCٝGsNJP2qQ<ǥʲwfq`I&9an6lʪ]1\9$^XpsVs8E3񩟲LY_$ PC+`Syp4~r#j(yD}^ðIu!mŐ8C##jx]}ٞ݀x"{۶'&>f&: ~M]6=;ќ4閕P-(,*lu cƽX]Vo@N?+ba}DdK[6DFc5- ǹHʳvC#33BT:*ك Xk6*{_4PO.DK gf-Yրʻe~ő,>B_Yl=Q%vw9ۅh{PmhE/N1U>_uڡzvg0εQp]q3Oߒg9ņ2$u:&C N4]-Nnnі>R*뜩1des1`Cm6ڮd̾fhhS!QN8 vnp&|Qy)rUG@CO{RZHTpq.-1/ ^~)䃇8V!_fUW쇂C{ ݓI7^A7'}8T1zRtX% 0$8 0RrKuԟRm_JNvPz\ة^W*vWr;k:D*zWW~~v |7p=˅~ _ z;^Bg79X]Z87-,KTĊEXBHB7-ҷVIa@ =s7K0vfD;(t?pth1iV1 ĦZbf#bc&:C +c'8;L/ %ؗOS0Et`@0߀o:VLDˤ: `4Ug qix,qP.BW]!tЕ 9lXE_-}=uD:XCӈ$dEbs=xљ"V-d'} ዉ|_.\ZU^kxf9$G":iw,-vu`N axi"!0fz~ȣ܌0 bNEeAm2?sJFFɤ F`3L*Ct&-[RW^yPMCI2?΀rGY`G9P&s]&J}cJڻ$|q^fPP/$WYł8RgGPn *ͧNt`,z6jhM4 nTm#<@C1>Bᗊ P,aYp x{~8V &W* +u>{s=rϽs? ؃pW6w=([{׃}sÓzЍ4( ?e4&j!. fBMz)&(=Ҏ]oD MFd[ݩ6&R%XJ͘j]s &k*=Iv0{c)-^k1ԚnkX߀e(ۚPݙGql+FtxE,Hʸdw)΄lDۏx dt6EplVYj͎*LE}' 6 (JDO#΀*L$p,d, X5h1"FH:c lƒWqT1Ҍ D&dTV4#8Xl4*2֨.ք HbT  T*? t:f4NhF:͡:ͣU4괐 WNȧщ-֩hT- OҨFtFYrNu^VJN*VthNzi6PNiNY:mALoԩI`u2٢SxP`@,%,\ꌈvټ 3aI ʔvB֩)B슨IU~vй:mFu:6iCS s]ӧM."y#g@{G00Jyܭ 9+Շj\K7`|%G(~Έ-\..p@}Zq9 Vm^w1^(C !^JB ŸMMFGTUAd@#:"9fh\>7n^2}]{2$%sASBʠ[!49)fNĒF~AMXa6L@6ǣ'!k];倓#m};ոN[>'է_ߤ*T:űaBp|l\"s{Hy0H+Sސ>*L:&(C“ /͞nkuX j}ju[P|{ Rު9$3K7fKzBx(CpT>_rUDq26kH5tl;PFЊZ9dw;}qƁ]ۗ_M-+u*e(jY|7s|3|8og*$MfZܢ}|StH][mwPkM}՚Y̽!>q- Z8G:g9d@8BrmpĈ/N{f__Yp 37ЙXhAau -YoRcgȉz4.w6@OSX봑aYfш&4@ Z.r%`"oAvU x G=vp.T1 Ò[h0D4ҸcrnAT*= gA刬&MV2 6ro'kM“dr41٣Y/s >g Lec$^Y,s\,WuJJY,Yly|?dMs9ޔļDf<g@eݬ^k%63JQrHG rͣ_—}vB2qpS\8lv$h4{vL TTT$ "_v0oI9[ y]e@?wj*+y븢Jk0bP U73p+ cCdxi9P=J8[K݉4%[ֳM VGw) +I-NXU[eIB8 NmL™Ld]oa!l.ִ3"S+݃jR`$f1}kLu.N#.$ r{]5v]KIֵu}u}u]úqJ89y%+Aތo;/eboQH\*$VFfP@ P.4ta:~܅i82s}RݥS+֕ªˡpf܍ңLzsIHz2sS6=!.k by3}yϺ\xgwa7˛Y12mBwq Xqsb kXACY Uy%f7PK>\-PK@4proguard/classfile/editor/MemberReferenceFixer.classYy|\UN2ɛyyJ6]MBHHӤR҆ K:e2fMVYEKTP@"h n(.o(x}oLd¯1,9uh886|R{(}|JT?3_AA>+x r(aKVGUO#߁=`p?r q1@`!aAEuH@(='%OXL䐨dPTyBU<#:tHhxVu ,~TG1$B ķT|QW]{`^T~eЁǢtH8SbT*p__vΎEv^ TGRgQWSw dmXӲ@ Pou"z&+~Qwq r}w0q=>w(պWvSmߣaSMov},6{tw:weՄҲ[}{HWnqKnoz0 n" 3_{A [J޽+z~VGUHERqs8wu7{"ia}qv6UI+sQf%]{JSe 5hmPڑ)qfI'AytsC^M0H[$aQ{oB}FlIN*“=g ţfCڞ ^i{髶R-/AyvXE' z; '`=Ƙڶp43՘ >K7QMlo2VpMH5[NT${ p2sFR {k (!u$a1rwpOX&cmN¾ :؍wь.IP@$خ7zqitb=E=X˽ۭ"cHhѡa4;5 Љ WxG#BPF6(9H(T4&Q._dRFbS kM׍rPNukG00*ԨH=I4E}itApvh&ayzGjf)4[9T\P|hi W+T**ר*roBLh -pnWhFrxBjtV8B)VPjN3xQ+9D::9U:Z#ư(nbjQ*oFkZjШTBUѶBF(foW=[)rcn&bKFH&*A>ƺl5,*;%ƺTĚb:ǫ#qi)Դ'̿@DĴ6xcDr\؜ b¨uKuδᲴa9R|R1XTcM*Gyj%N5`tx# qWCFJ]SoK l}bj,jT؅~&&HӶKov;NbiG+R5jI tjz|>of0}#",Xc+L8̬NKXY{wZiSڳRxLgu07՚.Zˏ8w9XsVB>wgHQrG{I0g@규axM1=zHB#ay!Lp"n)wQaBh^y8`y&yFAD!D¯?|^=mYbÏuܴoӄ[Oy/MnlFqus[K{Ba@D C⥭ȢnQS [Q[Yip\qa{'Z\@buϰb#8;~\ p vP\e/wU%Ә/LVL.!dl@?@Ea mJ^’6(g,۪}Ⱦs̬z3( :+ #7RuZS; s dl2[YbM N?:).[4vx+0I[ʅZiD^j*+GZ9mOh'G0%n`6mx^Ȩj" fÂ{ ۛ* o´DòR0]BEpfKVcc+coUG*<"2*:&n Gs.O~ {#a<6*'5%|^( 8bf901 QC2311ՔJ1&-4 4[.M*az%SdYt,O=P$ԩ#NӒ" QTZU T˜Wj*F%B$**]uUT+ #֠9|2p+[s$ majU6- &"l|n[b:=Y:GrH1.n D%Br\"%z|ܔ2%rM ~]\.W8IXJL"ql)^,E.]n5IՇZ,8fLCF*=ŕrOiLSv;Oa t7=(8=g۽ômg+<MYy]*sȍMT61qźeH%LQ;z3~la9 ;=zDu QAFaD弉8$%BwPKf$ &PK@3proguard/classfile/editor/ElementValuesEditor.classoEǿmBZ7M8똺iJ6uEFA $5R*U%rEqӂU;k+Wy3y?!!\c? :bH/pQ)N9#R7Rѝ/ʯQ?^¸* 9`9,ПX %DRs-"WͼeLrbP(:-3ΦJFOU%ٶ2V5s%K`{sfکfpbNLu6fPb hOd L)T]f&SцF2kp֙rc m33 $1wiX h΁&-6&0ݼ y-[XTVV࡚71:E{H4< p][a*kႆILix4y5EPˈk@m@T\ *5@r=41ogrꆕv/raؼ X߾ <.E=bXS$vOUbW(j+_ùeDO MĠaӴrG0g[Z1P!-PD%bf0ih)buekYٚsz 6ePKPK@2proguard/classfile/editor/ExceptionInfoAdder.classTmOA~^9ZEQR9Pc&MPIDGڻG_gM&QƙT݇gogfyvg2|` 4ph]B?n2B7n33aQi˥GĤ{}N෴P HeՕ\O];,0:jV Z1s"G#=Lm%2QaC]^E eN̖jj/Z J1K7K9*#z Q9 2)!L Ln[$P8( ӘPb!1cO,bNx/!0װ__6fO__FDnTT RE@T̨|wQiCn];GjgcCj+]UFOjIsU8}>&)}U>;Hpidv}Ä#Å6Da]m$vaH~!$6N yr=4y>WLCg v`LƆ=a%ɒ&'Y,iR̓^_ PKLiKPK@3proguard/classfile/editor/LineNumberInfoAdder.classSNQ]qro2B|VMHI$O;8d >l Ghc0{fk/s+]\pqvLW ķ"z)oؔe㬹ˆx>^,YV'gZbKYmXjMSlke陲nf֬7@,ɉӧk?hd(5h,}-Er+1a pb3Ďp˪*qzptoh/-9݊Q1Ѣ}bSe豼DU_chZ;2,bmgp1,~(薆5 @C i $Fð^!sωimN3fGhj(H W*UbHrxԬd*?wtL,>Ө*(nT';M$hD+y_2R2үKS490" $nl&(3՟?%pS\B?(nA:H'AsXYHr$I)%k?dgx7q CQ"Ab6a7Z7eс,z#4Q92PWc8>FI)]23&}QA v;  Ҵ=iCVR u 4ߗٳ|~>$ +<5>i_&Oz <^&3ts^ +.0$lYXT­Fa)m)Njs28y5]31&lYW9L ~UCuZ,mq4TɤmQ\ƪJ,AKEU˞U=SggLevg^6fG2=Lrȡa貕1FVNkv>nYQü%f8~p]0UUJ!/$ޓЉ$h%! _p^/`ݻAJ0QbyJC}/`N—&a K _K Hoi 4N:C/OM 6%S|!NJ|T 6s̘tUzaW!*QU!Jq0zmw#_VmvU[}Ik}A]M%e{Q1kn6Wh[ånV'NfKe(lrm<Z)Oͤ63Bk_ K'=Ng\Ѩ#w/cWEP{e=N&ZE]G5(n~C+o?ߋ{B<)珩OUb=5qPK~Z D PK@6proguard/classfile/editor/LocalVariableInfoAdder.classTmOP~.ltE(:EXT:&$KPI4$|1 t-1 D?xNys=Ϲ|+2è^Sp?$d\A> E vdk!ؚC f<2=nP, Vv}o34|K3ذI<_Zu

    i|c 8㌱mš@YR{vp.Inok')ViߏZ[uLVSBbMQ w^rfD+m{ _2D #3&n xb0zK,%U?@Fs wS{[ߖf@%RcTqk'yn ntS`* jPwl tk6K~aYgiQʵ%oRLJ'V*_trC5E%0oj$#ך3V>F8rR:s Y 8\lBѶ>D!d''8"$ԏ0FN鶩vи|z.q4Cx[GP']4Zs\!GYT$z s; PK⡋PK@,proguard/classfile/editor/Utf8Shrinker.classZy|T1,@ $Ev !h!D\f^d&Ajmmjhk-Zъ[\֢EmjmZU{^^&73I19~Y}wf䡃&PhshxЃ䗇<8<*nn!OC<ƏpXȞ'=؍)7a7~ltgxƍ'_=_+<97_7m/ދyIL~ wEh^On*zn&zu7777W7x[{Gh;p7D/Ѽh>t##Ǎ=7schGЈ8:ԇ#KYlxHb!j{mӨF4hFhTQF4LpjO_ɷW򅛫mdyH8ေug]=В/DB+_k%L\4'|@?Ś!hUrf\BVYj660D#b-X0飾ZANS3Kp;K AJXfBEI6ABI/@Ijӎ$. h0][DHgk<_k1jmFբ`U8;!}|*RC$ xCӲ^kRIe]= _.'T5T\G#жڔRaTX"1ޗKH:t|5j}q#pTOA\mF#Tl≨qtTub%O [ %B=T h QrgV4%zhIrd\59R~x9, :萺 3?o;b 6Uuѱ1w8qDGCZJKWIG&}վhPLHu@I(|T!Տ',XeM8RϷu>}6_Z*?R7j+.9tVti5IN~=QnERYaqq.ЩuHM:mpF-:y]خֹ%劉x0Tli ې0,oi-fT9jLTf*jjI-\jet )5=[9I79G[dsy,_Ĺ4bɓ0]yeZXyMVd3W2)wk9ϳE3O<z\7iBA $D.v Lv:$ Bn:̯O˧~:``+lofL*/P:&Ei#HkQPtbO+rbܤQٟhbaIRZx}N0o~VC6@?@v}p[l,,D!J v]&lfӖ9-}І<ȝJaO~|v7G$%C%B-&U1CrdĄ0"洱FTT{x(Qb ƒD dS 1Eg:t1/a.ei _bܕ,قJXJJkXvnw&j S\70^ M&AWbci*fFN^*}yvb 3B1{Xr)>ČT`K>/(CsQ<84XzPJ*J3 \+1 & WIs2c{+y Ʀ,CCg>Dz[-v8"KWՠ2eioՠruo&h C0 0zS| x_ǵjJTCfM>UO&NbK73^I)pAyY]I pFONE1Fd+O> `J=LàQ)+o&|dEMwMSPơSf|GMqM1]AQbKoCVgsfqft'n5ы͒!}Ŕ` a3rP8((EEKx6|OA<"fԩV4J&nd5L|&K52"uI:33]tܻqTپpzqmXr弔Wpk}1R1νx$01vh]pe2qy5q{ M" :XfMseep-.]-ʮSJs`K6,a*r@,*i,v}z[ZB`yi-3y3ng?݅|ڍ"9K{QI|t0f!=etkxz:gg|>/܋EtnCPK. -4PK@7proguard/classfile/editor/InnerClassesAccessFixer.classTmS@~UP m D@Q(Tt{^sBҹ$uG9nB_"8{׽ggow/` ELg3@VCUWPP@W`aT6%tݭZe ̐^0$s=S awAˏf"pWql7JҔξoʺQ Aq'IQ=n*C̖}Trl3mtEZ+hS#!q(ץ~sm(O?WDU(&<fa_ƻv>yoL5!~pUK5^$$&WPr?ﯘѢd{MY>іެMˬʙʕ2fA*nBC"iDiONvMhM} @[݂,IXA?AI} }zS$##Jk;ؠQZψ&]{Iv -XR`idR]J~RxM ܍&hߒL'6T_8AyTLPK@5aPK@+proguard/classfile/editor/ClassEditor.class[lUgwζYvRn]ZDJ҂Ec;: j«zIL 9|sΝ> `ChG" "=  1>&!dd? #òQ1*c*x\᧏ Yx>TszhɃ@KAxF_Z蚼hm$2`e)l=뤌4Z9pP`W?{ (yhrT1;og #n\4J,%l3lVظ`*afef uq^:u{٭rRٛp$4 /9x[\\V)M܎Gk<q|NZijcs° y{~Yװ4<*p`BQ ء!%qB`?B Уa'5LQ8%J5".S'tMVeғ=` ՠۂvg'5x*|7[m+ y DwML%nGoGgU( M<,G*swNW;`;vW3̺G~0L4`xDDQD#VYU&)3<9z!ٓZH!:68#UE/ѕ2eTI5^Y"W='\ݞ\E:P:PV:վZ/}\ЍױW7(3Ԩ[CjQZoPT}c>N2K781Zޮؾ A!ma>'}|k[`Zۭll˶5Ƕld!_t mᪿ+ScR"gr/o+gW~#mNpQhOf97R?PKNk:PK@.proguard/classfile/editor/InterfaceAdder.classSkKA=lܺ4VG&>+HP R~ٕM>_?Ji*Av{fܻ7W6P1; 07 :2TO:t,Xbȵ}/:*gc] [82?P^$op/f0=x&mhaw UZ ZwCPz=O~RPF1qtKD j"#+:Fm/a3Kb'6~>7Q2ʄ)zD/[f"bb5AcHvSv\ّi)Ur?d%JҖ*g `fjQia)H}]RV_PRќ"qvK_W/>FZOCMWF&[$FxOn"i?V.F|6'd6;PK ſPK@4proguard/classfile/editor/ConstantPoolShrinker.class[y`oɗ曃  h8$*c&,lv==TlQV⁶3ZZ页Z[okf~3{$B?27>͛73o`偭 [x9Ə߫0 C?x(G%,?VYV﯌M?XO%bVUtaN>s1OEǰ$GE8T1YN CIg1UJT2VZ*V0Zë`xg%VXr8N@}ǫ8qNYrKNVjqXnMf8Eũ,7TrӰ^E/yA,7g؈3=`f\SqB.,YiLKYY {(Yb ZV,iS kaIA⹦'Z+_<t8Z0;"POD'8.|P`Hj?&т-$y2d\?ң*Iּ j&fw5!ѧ} Z{')/䊷ƃAS[GҶrB)a%xNy x .CB1D jm~Fzo:7ƩTF սf E%𒕽a+$X9m%KIpH$7P-z@BFA!aI\9Iݣ@]b\mٚ85F6V7G7Dni;4Uɬ4Yg6R< lnSvBۦ!YTı,"hGfk4 > hp1|aDP;1 > 0} i°,F4$q 5{p;`'\E^LdKbI ^7$Ochx)^N /ghYB+J5>xkxy od]~oR ެnF_f[hO,iHjM[q_6]ýxNnܧ= ޫWk Ǿ_W~ |}V Qkx1xPqX|CLoj$>46>w) U{ >Q ~>Lj?f?'S _`*L49 |YpU|M7-_ |yٚX~FG Ez9 hHn3 ȮYqiWnuJbg%ﴬ$6¢6ؓl޶!VҦrnlY5kPto7ߊx=l|b%0%6͏76wVht&k©闽Lj!Zz|~n5jj=J9]*D:9rAyiI (YśD8 4J,Y/Tr6(ԫ z,DC"7uQ$O41eڣ>]O? MQN2U9ūռ T*ZCN%Gq)=V rgVd-q73t Sp_o6w(g5GMWrYKca2/OenLQn_ft3E- ҔuS +C >I!$O,i)Y|a]Xdw# ݢ:lnϊҭ4NAaMՊ-vv!PO+] OoɰD_mF\y(=D5WSZKmK1Җ̴KcߨlcEC3<5'Xզܖq["}+ ߂t$c5XvdWE'}B>!7r3Afq^ɜ{0ȋ@Βmh.o6n}ӟ{rPėg)ȨCpc+}V YBozR>1`WN|nk׼!bL{除qؙh͐* -7t釽k2T@S~'|'l¥"3dC.p*J.?oL+3!$Ϳ1mmV'ڻM0[l+_k 6 :I (m& N- !}0 QAB90ҷw RR5j"}֏Ex(A9(>DQZHU K.7avQ+][@Pa KTxX*_(Z\2{oͣPX?,cқ@ Th'M@)* |>XݰtKϚ.656 @ i3i`z%DP쪒eKȮUdY+Jlʠ@yCt "^ N^BQ~'Qϙ Ls%7ArS+ j¸:*)(nz=`2/2, bq !@%F%SQ#Q.G{ y$M%)0jÉ6BypJn&yOJ5|I򝧈%3)<'[^Wq>Ep&lsOԞ$i5DC lLH?#z.~{L{"fg0fIR:m|-Tû4ޣ;?djK'zLԻɹn`i|@#W 0{Yd&M*@ )U `6h 93aT *&`1GoΡ:zej#ja:!Tg KN9;qprIܫI>X:;H'&%֊23WqMFK2ӯVu9I5K [6ͬ%OMk];2WS5.JX3фWj oVw^cIR8<,Bhx+N!Է6;š!~~Bx(!;L!ɢMa8=!;0Q`\??5fd|R^Â$Bp܇R CL)dv``E~aZ)SF(JtDJNb=NSᜡ|^\ x`";fc31p,K BQ):f渄\5 [$b1%8N{XUiU;^a`aJZGvg1j2 ܧuiGOdI`<G-ԥZ]wF/XCAZjѱQGfa#rF9zLEjYᄕNA sLwY!ɥ1t1 #%P±x {ѫ~c@ߎURrVGa;?s)/(0W^T%<㗸!I:!+_;V]Jħv숨NObwD͹ Wa}išfNJF5ck-A7"ːx9[RQW\` SАxxrPQto0v'w{Ëso JY0/`Y6wl&Rrr2 S&,Rv2X.{2_I9XA%QȊKXApIZs^\E{pRͿb˖BuH}wSqz e(f<*4{z(qT!A`Eje‚k@*G)y)˘..2W`z 2v:N:# [/B < jy|e6΢T(}!׭`_G5[j(?O"_:D60-2I&!19kDxH]@Gg5uvLRqײwYm>)W/˭KXeu9W*Y^#)ڈ66bz8ڽs Pw`gW+Kʞ?# 5.^"u]#)$3+ wjc%.N'\ޔX,X. `ZT\]OﰛYIyz[9-nOLZyF%ߒroʙ/C[Wһ{H)HLv UҁQJ'Q嗍M**TRih1\}Q-:Cn0tu4à4YWXC΅ݎ-؁m,(!B7~I,=,Y{xbBK7?PK}T'PK@1proguard/classfile/editor/ClassMemberSorter.classS[OA],Q@R^Ղ7&I&^xnd/dvȏO^|1!`|G$a3ߙsX Leq 0YS0ױ̐yn{v!],0hu#['6#-6o;=;|+nAPl#cZʵg;<SS5Ԗݖ\]z>&N-=/[ZdmDVZBMPd`#:*l):xUxa% ! #ӘNB(3=[8Z^q} TcI|ݏ<Ț֯GTK h&n4˴&RG|Te>nY"RqW4xOO/vD`I>a~GSOp4YFv -fbgz5JM &HA#;HFH2&1x}P_U[ @AdOK Mh}?A׎xVlvƓ9sO  &'PKiyZPK@/proguard/classfile/editor/InterfaceSorter.classUOU]cvi+"b,Jn)|*we$Ƙ`L}Qmj/}/OXϝeMLv{=?7}"x]a4[Ш/k^ W"pR"CWG0,F 1"`|]B&&|HpV aM_k?j8CݸIge3b4 kӦd+%ղNWIf!V!Y16E&1OSqckE&vI\f;-|0*33jYfQaҨoY]SeY琕&ޒ0.c20-m2'c [+%\j]-ͬ1Yjk.d\;2qQ‚wq^NT})%=NMqEEy\dh&(Ryn٪n'fDFQ ]Fن8PAo[ZҊ/̉6],&ܠwVNRFH^Nޯ5f`fLS]'ߢB6S|Ӟ-vj0E$:uG+màIJ]iHkElU՚0L.:rjίBC'IpwtF 4z>\m3[ط0Pe?;aTWW^`{RUej6 skwPG+~ɉy^p3md\n@z_`Z"N62~s$Ex~-|= iѸm~_~_*nx\ $ERߠ>7L)Q.#u(Г@?"Hl т|'0n/C3[J ㄩDO0L<.S="}DH5|iQM*VMK!|˃=#iɗ )!%p pTRBpn#DiP%wP7tȗ +aa/>B 2hՕԅ0q qý.7\.gѲWejЛQKB P}U^Kw4 Aaާ">Ƨ?Ѹpw|+IjPKO>PK@0proguard/classfile/editor/VariableRemapper.classWSU]H$, mZ[TX>Z hZ .qIK|Rg|qtAg_0cgϽ$@2s79sνx)LIxӇLyqq.}u/Y_o>s-/ż=xOm.pqGb%|_] IXgo2{ 3uYRJЧZi-89lZw,!ZN1PUbPf y֕)gR7uCkphŁ ]Is);:QB+ Y݉p Ff ӉFLp߽\M:Ӝu+}H=1D"vR*&?=m`'r8 L]?<\sI7NJ=$4]+%^w_i?'s[&GO8XULO 1ۀakJ#7ط`lU>I}f4;P+2.`!Ա/e KH}< %CEZUD%X.!oI0dlp LJ0eXH14 >as_ '# ͟aqэ؂1U]K/+c~׬RkʸC+!+c>W̺7/۲Fe.kqU2ufA]wf9t5k ~2GWO1 Z[.Eޓx3r,<"hsuAʍfZ{d@?|bS=E2"s$rp@޷lA*m{Ñ|OzQ‹.L.= 8<ג/Pϫ#bV F=r49+ \[A6:j&:Sm>.>&&+UCi4pQPuY`;y̞ϯU İGѱ#c C+ʽ ΦڅJ!_\Vj3D+ 97#T;}RR9W-5[ =ghC:?Ŝ5Xuĵ J4N\WjO8rtطpZ˂!}>ڷNOt|<|aiY)EfWQjw]2pHMA#TL >f24 V@{yr yqBi303"~@#<:i7PKhaPK@2proguard/classfile/editor/ConstantPoolSorter.classTsUnvlR_͏[+Ih)hi#)ZǙMM6n6vƷ>0 CҎ3 O F)/}|s?=0E cq  C6&$? 8O)iIΝi28Wt+5߬JɺvѬ2 E\5=X': LsW2Y]˰JzFf)Ͱb}>%lV0v2ȓtʮ-0db˛WȽg39ën:1iSɻuh]:[UsTq /qaE2%DHn2b^,K*਌s8sxWEx3*.bVr*>@N%y̫#\߉au}1vWl%pJh)s^a>Ya^5Z|du-򲶖yh癫$AQFfZFǬ,sVOg$Y_MZt'$1CϲoaFcm/r)!ĺ-@՚o&W\t .J_ta+g}.G*A3VکiNjx }]ho~V} S)~B oAIDݠ C e2~[8CESbRDBG'RA=+QZ= MԃP"߹I KIBR[(p&OBzHAP{SaJHNp^7їT4%tI7z(%qٯe|SMk+M  &c m;y_SIhH[)u1i,` iLcMh|>+,~O>uwy#*@ p $V]DPK@MtPK@0proguard/classfile/editor/AttributesEditor.classUML\U. hCW((Px3XZ ":tO W:4эibbL\.te` SʅFƕ11.w720Hts;{}_\‡ǼhQx\'x҃cxJi)Nx0$mC8vvOzьuJ3^Y/*sffʍ%lV+IL<+:OS\]4'bZ2KØ&'f4$9K P-g?4[؟fd#Y1#P;H%r#=};R$Hd$Rt^һ`%i`)^cgx$JhV*EPL͇4m}!p/nw׈{ WKFLOȆzt%UV7q[lo:>|®`NL>EH3A]'Uq@2Ѓl Q{ND[DDlH%R>%ę#pCET_ W'df$.:;X,MZzC+p#Ѕ~wzpPK\@o PK@:proguard/classfile/editor/AnnotationsAttributeEditor.classR]OP=jCTT\EAn7Ј|$+dqkHndi>c&l4&QiAVM_3s93l\ &Z\7qM̘eLQBvUX QRWJT桌$yO+¯F(Tzbc+YD3ע̘!znũ/¬l~b/>%v`6q,:9wp+ '-̉d뉨jE+H;a*]$[qqgjJ ߝgn,!w>4kQjTwy&weož~ 1\5>m ȭ }ΫَCg[Uj)#F8tA89',dQER/Yaa[co]aUL ^xƕa~PK)~PK@.proguard/classfile/editor/ExceptionAdder.classSO@}{WW+`QDE#bL gﺐ5^ߊM~(lU*fw߾y3;;ۧ/0q_,p+:#uxUeDǺ:1Plz(proguard/classfile/editor/LineNumberTableAttributeEditor.classR[OP-Ԗ xYQY$ݰ&|XC"pv{XKJK&G%lDx3of9~b\`⊅Ĕk6ㆉ& i%T vS&D3+J%A3UPIv*k B鉿qoPayat5*X0!|Y6cv#N|d5'-E8-ln㎃!TD,%nrH0B-R\&LÓ3j|OgZ ƍnGm%Dt[N#-Nqkr7@в[>E\5~mȭ}ѣ,G,` {0~C޹v/A2`lPƼ~ {̔nlWǍgrʏX> 3Xfmo0PK5 LPK@9proguard/classfile/editor/ExceptionsAttributeEditor.classR]K@=D㦩n]m XhZȢl2n#kN} RM(-yνgιe0L Ћ a8 #^ॉQF O}Ra?+%zB%FeMnM{7GSe] P2,U/` JBzx/[;q"}Ab9wO %}((øxcb$sLg3C16ypGW z%60q{Q NDP0`tJ3ǭS@YLЯ1Qtci[xBѦʡZr~93]h)~ )ڏ;z6Kh?ݞUiU6~[]ݝ^^|%7 w$9>P\BGª*U_a-nPK{q&PK@+proguard/classfile/editor/MemberAdder.classWYxU/I3tڦ)ECEYҴHiK "]4iR TTwqĺ R)ZQp'?|>?ϙIXR0.s9|χď2*crdA7z$p[]fy^YȈ_nc gU#%n+p+#lml|;;$1 w`';+5[ُs{sigvr/bɸH {X2Cn0+12S23<$@Ub@~]47Ԉѡ؄y][禚mecў Uj<ޭ*0bzWЪjҽjQЉ N( L4n^ŗ N2_)HVw^?!gE]j6z CW}a[Bc}. emeHmZ[͋|2]Ń1߄*qM0 a'nfKєz$cVL2Om@ F`vj(nt/Ig@/^q^bQ(iS!B`ی7KlYu3zh[j8~ءK"^ajLY&m_7Ww^Bf;G8ff}mjm oD>=k a:jQGLzS墾R7[*fKulR"[$htHr11dIt-י) 'L 30 jnC~agg>@pNR,B60"@ZT?-lI$ ZX.uV$Y8 B3.u\'T"y{QsR~`!&QJi0c,|YQ>Y#>) < /7ȁ QhrBP^\ }Xmtlb1~z!a|F ?EЦA35sM"h -ZJr jCL|ʚsx1Ci&}44MܕgXql+OMU'p |]t*4{Y61$!=MUD,7^;K#eO%&M1IO)ZgD~%͘_Mq${ ,_陛RF1,u WTbٍBss;#(6Ur/PK dpPK@-proguard/classfile/editor/AccessFixer$1.classM 0[.w A+=AcM)$\x%q x} E" bB׭Ӝ ӵ}fR]!o9qc8>MKZ Cч|'~~0Ac<!D D @2@ J2pLqLsprq% `CLr7(^-]o`_Z1҄.|~ wHWtbR\iuh*ҺPOPJ@KHe/QcW(#VX^xMX6VG)ZA/hj5x1y#Aa^"vD#!w \:|ȣ({> PK;dPK@2proguard/classfile/editor/ClassElementSorter.classS]kA=vݚ6~Ukl&QUAR 8Lf7LfcAnXV_;{߾ `m+ؔ塄e-qْai=öĎĮDCjbPXZñMSeAdh"q :Mo$8$~TsSr񉉍{&PnzN2Ќ;4~ھU7kR;͢|~98nP4ύEG:v$߫ B={u>Xxs 𱖽@aUbGΕU:]3Gfh`>/?zΙ0c| T0\\Fe\Zֱk9ykF b} һS\8Dsy #lui`j)uJ폐p)=TL)zPKҖ_PK@.proguard/classfile/editor/AttributeAdder.classZ |Tչ$26 @ % Lf jm .պۢU+]V!k{ݗg}ߙ{od$!<9l;gx/`=?q~KI~*4\?k?/5ʇ14F~+tN~/>Lį%5ɇ)R3s5t>̒YOIKϒE_}/oLJ )TH}"^D^jꩈbJ4c9O#݇UmĐcJaJ5/ :&j4IF1*_tFSt4S4OiMױ-]3Cjfj4K 5:Os4:߇½j4O|F踖ʥPQң49hBWz:/Ѩ^GJB.!&=btFtΗkBR 4Z!q.9Y. W_ÍR}#5hF|Z'_4p>o 5鸋6J26i0q֖k״4n'ص[TMa\e[ӚgŮM]hG ݡYcDܬm;\۸iK3)0@슇(Ccf|t%5x+W 0#6f0'ϐt3bMG~Bu~Q3z3Hi }u,0$ D#q$ D^f0U,u797#W"*¼YJ(c7"fsB osͥ ZQt`X'u;""#.7o8tIB3El&bs=w1m2";E.sq5!MQMUTMS.2]lPP@8tl6{Agː9sa슙 <;1/ M㉘9")7*t-]g  B~YqAAڤ݄C [W#5h~< x!sa{ Ga5SLӗY~g&d=nxov]rvvEYM2Q&v[,ȰNܠ7z[=zttuHf tPs5 >Uh( zXjӞ:No,2;Ѡ턋:t`mylyqD~A#g%tK-5 V’nsĿMĿqKV4w:i]t7aXPnL}uO,]^Q=g%#9Lļ{ϰiڧ zx(lgW/fP̭oj6LgNNL9h~1b<@&h0hڄy ^X m2#=EVԴkrE'Ad-Mu;%h CK8#9^X~Q2&T_ f|.†iӛ؊wlmH Zqvb1.´<`|Y"cyyk(3jR{B;%C~.)$9١op=) ek, 'LPocwɡy%_d~'~C1ek=6eF&̾i4beos5egR[%Q u鳸*e/}8&y~Ҵ͗ۆSنYAmƥ0cpZ^sh7B;Mcfq|f۷iw.ۇߔ665}} ޡ_Pڞ ӽ:Unke)lcTqѮ!٫; g;xb }qR2:Ӊخo`:}m&sg"V½1U*a釸4%(WYE4= z sc0 ՐT !yej3֐x2U=(AqeMJ*'`de Z[Uz7fRq{`admq| uźsgQu^ c*OWU}b,g4\obB9$!LGsŵcdF*Ȋ&:Iv?f0>a8e.ة vZN؛kO2;3.L97gmMa6%yiyZ9Jk{nJ>'Y(.乻g$"_[rb>?u0n jbB:㧑Hbs5SMzq0jS5tt[K4ssX5mxnb#syoO:/IFg d-%=x,jO;{\0cXMs˷l#-㭊Vx9fg3 :w0#w I wYEI݋w$y铨Ϣ>S{x9jyiEF]~t8[w7rq ސ'[u#PK|Y 3PK@0proguard/classfile/editor/InterfacesEditor.class]O`tc]M*Ε! 8 Q8Cqrn}XJn:ʄo/Ƅc A98=ws)L(•0BTH\ #k)1BΉcαwAY5ݒxf Sc޲0ߚ*"" EE?.0nX*n!`ӊh'IMWL^*n %| ׼mwekMb53+D!lUշ9p#;Dc@Mӟqz@%y43&[|m{wDr""kzC 7b>⡱=sqb0kNYB{l<7YWfDY&:CoU$*Ea4 RV8/2CpClcq^ybV$ްTzrَ댧ƌS 5-<ЯSO ~_mYKc^'Uwc-mnAuzQ%zq%- ~PKPK@(proguard/classfile/VisitorAccepter.class;o>=nvNv.FԒ̒"ϼ|F MIJDļt}kb4u4KS2sRA8&'遴02(姗&'$꣩dd@7XX4+P$PKIPK@(proguard/classfile/util/AccessUtil.class]QQOP=wV؀UDN!A {ŀ$0]]^],##kO'_}2~kFc{o *PPWT&tY fX6Ga0`"҃κٮ}ڶ$ndzLz+Cٹ8mۦD C0Mu/Ta| 4{ Est%Ⱦ= Ňɧ{S/-D@oɳ"ձ /;i|Z5PKJPK@8proguard/classfile/util/InstructionSequenceMatcher.classY{|Tuj]]$]ew%x@聥;xY]ծwZu&n'$m&vAŽy8MMmܤtMӺM<ΙݽZdIWй3gf9Μ/$_ubK,_x_+,`3w,7ī:;bm'j::15wHӀkUu?b؉%<~ɚ_uԅ ;?.4?trra~㿝X.\_KJuBtQF`Q"6 ;.p9)Jta8U8Y8Q"QFD9,*JDrjQíZձtօG^]4vtnٳU@$CP4eA4儃{wuҬ鯛q zm(n8΍BjtpH|8LXĈۆT(FF"Q9&4gfTIHh]i'P2|8;o~HɄ*5-12cɮhh#ځ1 4:'ٛlα'OZo3ʜ~s &3}=?{pdpYrzIWܠR"#ej2w|K=ECAӢ RBQ!gY{N:cnǓd+4N=XRMiIKDxG$O5U%z3sS-TKa ٝ6ܽ,Ǩ> bX$* q Ո O'C*q2x3Ll aY볭.3ePR g=⊫{܈>nx'fԿQaK?@AK0#Tp1E $ZJĒO~W]y\[I|!|dNEnEPW*\u?pE8qn)}"Z)/{H.D1@' r\2UCNl ɑ+VVfQA(f_@\~j%9 PDr:tWtCOmܫdBs>H* jjMuϽ5w>ONs MMxPMxrM6w8GA|O2ZE=gIhMD?Cx4IZ4&^ A?mEYܯ~tO|spS4,UR}AttwӤ.3^AyxKC 6ֿHR$.lQQj~wA+A{1s_' xߤч9 ]f&N+nYW//SpS*ꋞG%=Pj_Dp չ4} % 4> Wl 6K5l`DM[DN#£ Eb-e[g9wGSXٲlc?MM,Vi2ݶ&( U&;*BRHI]b]ai_i'݈E?#4x\H'Gp?8F;/)WLj" ,>ZՐjPj#'ǺWCڏRp3XVZ>8}aG=k%a|t az9NaKc9E8gP/Β YWƹVrZC֌b  Ԋ'I$>Pv)6-iu(zoIw)I_HJpuIo ,_&ȻɆfE,P/D~O]aW H4StN=G&i/~*~/SgtَbLT'p=8Jx7ڗ.Z$zFWi2sɗ=ٕ~:;vyu_@RjepjҪjPb,>d9;=}tOCdޮ5?t-J-He 4%\zdUJnj׹U_`<88 ΫZ+24eCG6V^jh:hdeSVV!y+J?z]$m!VI8\-7q\m@ z5pbYm#x'gs-S+E n>rj; l4uռn#>y|A"re#eǛjLRj=d3*JN%%0_|ڇ#_5mf2̦*G2u;]҅K2?(\~D8 JOP~p5}ԓw._'\(Tq `F~n9t +;_gsu UPV_lwTbSy "WPze4i_*[ؠ}mS{S SZߢ_5PKc# {(PK@?proguard/classfile/util/MemberFinder$MemberFoundException.classPJP=M}XER7łP]Xq&cޔ4,W ?]^9ǎ.l4tsUzA( )7lɝ?֜ "7'4 LAEek6CCN'gfwmGNU@pq<< ?~eTlN I%ybM_5 ^wTxyP B" ,rH'^EUek/ʡoXķ%%QU[؄PKH&PK@*proguard/classfile/util/MemberFinder.classV]oE=]{! I4+v[ m>; $ʵ'ɂwx D_B!*7~֩ڍw3{3;_ T cJSV0`_fN ΪƼ q >}X@RAœS  DU`EAZ7-7\+ VnJ5|/Udj%O^Z]K/0,V-gbyṩyVՋ1]7 w5!Fݢ$;3a7YfuC1H:(8C߲ntM`.ig(t^,0TYy'WŊ9c+2tsUUPXq$3-X8]ȗLW%@hK| GN+unz tH)@pJW2۹B*>0L_+zu޸S!d=/::V3)]U0c"dnŏae 4<1 y UɌs;>0 6p|W**7\`|\6NAFE1Lwu\&.n6jxψ'AH0[2No|2j@'T j5%󁃜b 6a}:7sf~hCpd|^C'FeY|=(Y lhB=f<=xXyHyrюi2EEasQ{4qpSp4 G_b| N’$ YI`2oK)b?0۠;AvV>a|H )sBċn|tr4Q % >7ׄPo>>QdAP0[~kwjVǭ5@ۃ?v1#6u?m 8@Ot*@47PKxu6 PK@8proguard/classfile/util/DescriptorClassEnumeration.classVoUv/ôl[.j, R j[Vj[)Lw:`4&ƒ$FM=QmB#!D㋉x>'3mu;|9_Mݺ `+,`vD=)nA##6"W}>X(=%viAyFHw%a: !?z'|=G> ʨ > t2R%vRkkhcO2 eOI:$(ΐܩF4u+n-Sj@2-&q-JX#%T:^#NZzÆidZZSa H2FK; S&uW"GH2kf$CrLKw%-)94`2/~)“ SŠ=ɬ ڽ3յM3 2F*lQ1PUS6`hRp $UK*ԇUǥ z#emL^踂C\AS͠v=CRA [%4hVbvGֿ'-\[kYATVgw*14'^V71C'QʦIX:BjKBͥs0 ibWKt3&a]@rjOP?L蹴=YQ7)%Z :,849HձzY^\rh+^"sI'tWYnOWM lGMn/mp<}D>+Iܕٴ\/=oG3&OB] .vmX֠$WM%%ԛ\y㞵ev:eB3\. c.1Ɨk}ȟnPKlJu PK@>proguard/classfile/util/DynamicClassReferenceInitializer.classY xTOfy a L2 *B:lKę l֪]\kBkk[V-I@VvnW[s{3&7s9w'zkŋjاK^8e _…{5煆5|Ճ^σ~<8AP)xPa _sb}^Lׅo!)7|˃e|D/QAM OzqxFxVw|Os/C?c?S/g~Q_W2Wo/%/+j)/&Qy 5epكxo^ʼn%hD^lDDRr@cP*2D&ihF~ϿaBS*FَH`ZX"O<,4o5 ӛZڶ]ޖu[ַ7]ҝNm뉤cD$'e>gt%aANjm!&=`QqVfd}0gC}klkbѳ;6hD`њ4ҼQ8F6];%D4jxnH9Ţ_H&g2Tؐ'FPULQO6I'dcFh5BYҮs`;F$y]$.S@[Yˬf)צҭ.#/lXGm͸3 Jڔ5E2ټ©iȎH9~ɓuu'.# A0?:|zZ ^ np:\j >Ll\hNxÝBZQNЩF@-u܍{tzAaN'9ӆ&kuOgIniS*uZJt:\i*D"S.*uiaźvt25:EBRS46ⷀta9CUZ>bUߗT1&_SyܥQNkL:Kpl,;K.VJ)5[ռXr;ZjZJC RJVZNnJ3nĬVrs᳝ۼґ aN0&I4t Q%솪PNoהּ?jYapvˋeZ;V˰jOq=E;y3|'IeIZ.UbB)a U4܎)hI9M6ZXQas6? M*T*1R7sG [3Sl3-P;][..y\. Y4/Lo:o?XD@Y#y9nuב7=UIKM;wl*b/g,vn0YeJܖOD[-9X1boƐuHf*&uQtm:ՕgTMRL2)X,So)+^;A!?:)a_>ijp҇I8}n)݇"`_,F gG®0stfUlS6sqeyyag{nwHaA7*7/ԨN aBw5ص. h)UCs.Pc'MWi&f)R0GÿyTg\Hv"EZl'U)҉>, ai ؇e gN Tpr݇SDa' 8q&wl$i?Ļq݁iBosqOɵ8Xi.(yJ³x1 /9feG%^q,īZXZ mťpX6XdkVƌ80ZۏS &{b"6_ *t0NEL:\`:\! t*zr4pDeih>a7·Z8V58k5/ V`zi1&R̥e |x)G)G0UQ Kn3N6+! LY8s( oaЏuh-83QLiNbȗHA~l=͓8_68SKx֦4p:ζ>btI W+C{Aա8Pm_*Sh-XC[quJ.fOw*D*s3Ŷ7@;Wϟ{ )tOW ?'{ *}wZ&? 5}ߐ,݌ t wY! W;ud+ ɉ;QJwLj=ڟ2xnL]{؁{yelGkQuޖ YvQjj=딽[N97\#\%y(ElB[ f t@08LC3@4$"iF4o ILhJJ[H!C7QJ8'HET%4W(B`j-џ~ T(A)H-RfRK'{=!y؏d"vHw d?;a->lS*X[e[}ڭբUm]w*=;L&~g7|~;s<7RMxN~6ІBs* x?V|I.d$/i.vTLFd/˨T\F?]l~Usx dk*^1ōx->JůUFoY{^mG^˟yyW{*?}_7yU) DHRȼ(d"[6UQE*ƨ®S8b,4λ6QBUL&dslxR&eE )楄7/Sx9MU1C3UQYL媨PE%Tb*v*rUWE*0l!/xYVwKmb W5mشMW {}ު7Y Kօ7 kAt\:kRj'F۽ kp-m`Um Q_8 _8Bp҆Y 㯛{B8n?RX:$)gZH3`afZCSMV$0KW\ހ`/~YpbjaވoMZBh xcE8ogtv:J/~ dX?m&&_oQRZRQ_g( MPwm#MC)0BLG$BBLwc*r7࿆/ɤD:]ho8h 'XwSd4!BK5dbOQ6ējl1LG2ndUKvԊ`pg/qҕ}#Fx, ]⽪7T5#K~_}^f_NE[k^)kiUmmH>팤2je&%0übyML2bٴ۶i4膰Oq>ñӠqܖPoWgu3%S%+hǧiHIe7#==T}{|a/8:ަUdBCI;h+B,vQ#N?ncN$bu9^6su3|cG6vƎ֩)j}fLjƝ"0]wvld,hkxG8{;bFd̬ފb]\)6RJ:g=6*E㓠@(3ǔUF f_DrkbIs×pX-`CU=Pg7^eXAA6KECJ\E>Bif® x,£Za_NN |^uvrlR"~.Y IY{װLLVՎϒbn3CC mfJrm QRڽ Wb6&>f'EL];~m}ߵ{ap䏑]=dy9Ob#_eӌY~҄^NAb0H4ȉF|DI v^P#BNm]P wl[v !hG٠xy8͸Îgش)3Q$4Y5”(:0MDR3o J3ɌC پ{Hyό)љiNf zFL&el};8H0C Q } +'. Ƙl4+B+AfB9{7 3i`AA*fxg)ć?¾NJ&oejdNcoĘN_tħlLOۛF+|y3$tQh=D"z]B#-f)u-}F3Х8yy(!K> c*=Z"< [YdOR$I94y4ujDBsԜ&Puu POX<س;GGcPu-GϷNz >>: ӄ<8Ixr s=#vZ`W N^[9]۝8bi{[yc =c证F%0f}젞? IsP/ fh #|GcA >-8m>șVlsq%'>5sfL9e~^ʼUSj b,M3+*(Mg:xЏ★>ɖ,^6C:"?IZVA7 \Bgi\gwqJfֶpG_mkSm :ŰգN-1SC 5:Pћ:AtR1了!bgyW\fZ)TőW=BFEZ6"KjlSچSR^ei?ަz4Vrrᬥ7W2O^&b1&QDŷ9Ibt+I;Q,t Z">I-j K]|U'^Ҷv5p.kbriu%ti-%oti ]jVF K[ۦ8T9.m:oOxɋ(3hH抧pylJ<\]-9xp(mQ1䢓)1rC(}qBzOHGxoH/˾(hV̖U:J˒.L Y)Yw(D<KT?U?c+md'LE8u,g4̦4wv^NϏ a'rkr*ֹB<81I.@<d̗X& %a)qRbM1Mp'˒it/E Ҥ4 <'buB<%e^059zkvzAYiT^K|oY|VZC@96NrvYNO|XYasCLG3YZ-MH;Y m.!r6BJBI- ݓMkIp wy&#ȗ41\_*ڑIytkHʾ:jx*$'&L[1QThb|/ȟn-pD~Qg=#9!<+?gޖts7 I99 i˓HJqCM_7L~|"'F9/I|+o!8*1(C{xZ~Q|ݛkE6.G_!7JS"%SJ '2 yTST|e"&*1SqB)Ru(a2{Z2R*pT€2gy8S<,e ~,:1QY%f*k(zO&OPYNfjuw-zWY_cj]ەbAcb6'nwfh5@[ⅲaLr=y&LRbr3ʔOcr~Bn uuƜ纟QdEɜlFEBSr8=TnP@Vbq*m?EOgKԁ\Dc:T~O,7PK|TwKI%PK@/proguard/classfile/util/SimplifiedVisitor.class͛ |$! a.IrUz Xngg(ժxߵZoQRxjmUo+wMf6ɲ~}?S?0W(Zt-QQ*g,Sz)Kr)oMPهM6 d3`6C eSflFf}ٌfSɦ6cٌclfl`s Ilb369eBŇBsBUK* u庱H[@4` jѨB+gGf}jj|~TS\?ZcHrC3ֵ[R+4N9܂d֛RtK_Ym .8)7WmWQ艮o_,i/n9gK^yshC¡Lj<>_NEЍT n$w{8"la 53l[Ep KU*A} M# PXl6LiÈshMx^.5|4ID"_8R qm:p[78.HQD>!'8:l %u]LKKѠt+e5p*TҒpvFў'DKԎE"tӶD}DZ>#dK57TѤEsfey3UI$ZDCCCR|o% iff4HSR>3;/cPicO(BR:_ڀ!:'h>ϔ.w1Ygs ( g|pU-REYSZ=b>2~DUٝ#K,UĆ7d`]\_iѲCW!vkʐ+1Z!͌zVZ-\2Z,7k`|,т1yĂh\= =Q,7b`BZN2n'z,'KkNNzn(Xxk+S.ɓ $)N\\*-" mBnw長<(8NHV㛪p$7O=MHwUMf\~:ڤЂ?ӝ&Rz@4ވ|?֦F$J;nT\lXfzK&jMTElK)ON."m+<=S›O.6}m+BNU<ٖR$Pn?ihf4W[)rYoy~Ϥj}T>֏ "߉4>|CJ[uD¼~kKf߸q~$5f%s䓍YAQO<EbV)g (P ZQ\]t[w@o Eq`&* H\@)2c'S2B$*AT핻Vj؊v`2)8YS?;1 D Ŋurl>v`8YS;q,4-9.@Ϲ(%NZu>]@VxA.rd+|O_blD!6N5hr/\@~8O_"#q.<.@\ &ty`J[cMyF  j g)wVV x\9kb'v@%ijnQs64)ډ7-xn[]xmDQ\qjz1eYӕ`%bU˱Tۧ?T|M]oKlR{ {^TA'P>j@u³MR=fv0xc >MnF &@Dx=PAq5 ?aW힪{=ၪEIz]zmOcsQ`<;YI4x=P N (>좗KO%Vx!~䅥T\YߒoF%KDA?A|f -vd{#IQ}R8Ng*\^$ƃQtrIbb%q J.AQOPKӇB&ZPK@:proguard/classfile/util/ClassSubHierarchyInitializer.classKOQÀTi05&> q5m/xIit~6MD,]U\ 0i99̽}=u:&tL"#8Rc35,hXpG D5W-HY˪!_{u*uz7nsuuX4t[k[ե}5'0;eUqp`՜vSmja"fGݪ|̵n(v%@9uu$ݕ]1``X]K0 -d XiX6k=װjz=U5 ucʪ'ԃ`:/0#M_];ef/_U ONUMqDI 7 6K1+C%F/jgKOT0/vqmnSf$">5o4f >2vR"M-4LS?MY'c)} O\491,،ޠ!#9B!1Ro ҹc$V.OC\'Q #M*IZ{jV9uS5s[}U/'^cpg*Cے|zS5VrR]+X:KХ ׃XP=g*ɰX/jg#z,. -m)J8pԤ$^^oAfFL]x.[zj,j*+t.ݻ]% ⑄$2'W/aޕcKO$(ؔF%"AV! I<q얄}`sD禧~ d|$SACcYoOB2D@^6>f8SV1 C3꣄OgSjZ͜\z8 QnMKhj|'WdmdK%;k)/TPC<^Q,tVXl,f)'lU$\nPKG UHfDIS>w \ UKr^;)*ۨZ+ru$ݱaz( h.;Hc6C^vsZ7Z; K!hl]lXJhDW+ 82631aN08|pDƑ5҄>ဗwSxyC8TX w {}09P@,Y}?.e":M6nb"sa$uHgS'BUI+#O!Eߑjr`H-9ڇX {pIL:]].%}.(V=mCh=DҏM' z:_W#J/CW^^%$?CgP6JCrrtՊhmӈ2z{h ፄm4Nh8@@wtXXND(j lI6iǫꌎ^xE:ʌB/Z!>n }={y2~sUhy? ./(n<ȮWv}"8P?jp·˲0$#U_aLq0!>L:U?^o(ٸed촥nIj\d̶ s< 1sV@)JjsᮕQ4. m&xzҳAԇsfNG5KKne FײCiK8QU>SiZLP]02ݖrEM'Z[F4T>~X:g~Cbnt3s)l#m 8^-\SqUhqD @g8!"fbN< 5KDBgR*n`ݡ$:H0RX鹜fFtGr<#@ӕ@Ԏaዲln p)KS34+]M*7a^gFR0V&usΞw*d`,T5vmȠnVSΑࢍtdP]Ka-YۍS* ocigTd\_I#24dƜ:k)e8^n[AY6X@ <܅]E8|TrS%mxyL69/5"tщzzs|;C$G0+\wbY/T2W\vSr#.@)a 2egǨ/`RhQY%.S<]ur*{6G|㲒Z*ަk0fL"クYrh[>^'a p[Q򨼭5]{u>#9ޥ8l,|Fbe{xTm ?\ďcCjVQ[v>u.WpG ڀ~l&PZ7\\f\~o;&\pPA l'XbAA}R~4~7!w"}B/Z9PKsDPK@?proguard/classfile/util/DynamicMemberReferenceInitializer.class: xSU佤mP(ЦR@hK K)m"60mR˨82n#Vq-XuAEeqq_ps{I^ڗ9sv9{o=d!w8 pDhLJx!mv܅e|؎0_G;~ pKOJt|\17l6He s+JjjVz+ʏ#6/  K˫WV,,uU+XVTGmydE-iG׮-([9wQeMmIem +Z¡6_ں:/קY,Q,_VN*rگ^2vQql\h!D(Aovxe2gm| q|W,o68WW-7制W$(nH ,DZ  UNOx"xxUޅZDg7,C$w%r<89=L#Xv?&d"<,#r?X[cPX'ɰ!QqAHI*_4S O<9/^DSb`{3WWLYS21YL҈s^BdGDL%'I ݘ\yј"Jy?*TIuϠ8׷" QH?rЏPTA) }\J5E3ÎN_^RVM^=^޿hl&Jjj~ A19 B _PIx aJ?5&/xR2x ^`"2xm2x{ g|c0g 1 d|[1 ~d CA@T_o0x[&E |_QU|MAR_CqPu|C77m ;W4(.~GL?QSL}_ ~_37~w,=Azri/]5[g=|E_e[q0|v ~l;قviLȲ])8lW l N[0IoOX/Js[(tsMDp|%hNJכX!%.4IHA ĴR-=~}Wӗ~}o ¹*>~K^H?~ūTU#a0W L^MRS8VR"Dpp:cp421K\ `ۺ ; 7bw[]Nn \sI*$|kO9|Xap-ap v8J =ŜYNx\8'vfX]VNh9 %].i'EQN8AwɚDo!ta QS0^xrrEv`ݩۆ{ e $nwBk\ O!5Jo|]a=J`M" m"t@ -ϏQY N)NsqZ3SwA{'wq4} _@#իD V2*fP60man*)ZK`+w]p&!;[3u"b)x'&RvA[rv¯،omͰ΢l qv.M]JɮXRbWVp'De]Zqwtv_#*rn:v)A]^T]||( \i@v^oͽ:`u{1n`߳ClyB\JևaX\V׹mtqZls[iJm8.tXgd2(T^ULWVx,uz0s3(F^UѱdC8u; j#^o!@̆aX)(`8VE*N3p8.bgvHxK+q(.U2,p ;Kc؈kp/>Q c6!W\'ptKq--E^ v.es\MV#;Zu{=vLS4}7ɚų!S\^B ;[``fUmw0eܚ} }#7uf'>sn{[9my3BsqL9o3MrW};3m4;>?PK%a@);PK@,proguard/classfile/util/WarningPrinter.classS[OQ,-K[)(Q.e{S *Ƥ\ FS\Rf%QqZX9s͜o;$ %@GZ!!\\a\cxʌY ʦnXE̞RMz`'ۍ׋G./s;)S:K”&"J!CNwxK#YdTPKkt)PK@,proguard/classfile/util/MemberFinder$1.classM 0[(./Y5w~'L7}PKʐPK@8proguard/classfile/util/StringReferenceInitializer.classT[oA[֕RZhm [xKZ/cҤ6 d̲,K#*MZk̲ Ƈ=s|93orx2qS(qK'6(sW{:q_CZCF?rE7{c1,(_|Eyka,Yv3)m=gx9d`ڑm5e°})█F$`ԏ1G؏Nsqۋ E)  s \pYw%L/)JK;"s\<Ẻx$S"36ԍeH)E35eKMMb35sg& +*iy5]~e4[ZI3R*1\%F!WVx'jSVtM,%Z~#Cw DJy*5tY3ϷV03hrYG:3s=R+:񲷧TsBXW!< Q#*5S5qeWk73+(ʎ2s_2’ K ьn*22Xa贲Օ|.>gZ>wr>Y.r2VX9ذ2:6dpqy>tR[6cTgݫwȾ1z06mu-GehRfB"C68)Gu b1bKbUSƙmp C,ZoL#*31ieP1?Ut{ZuR-e h)Pnf1{kj\$R,y:'gbw&Xfcnʝ)*˦5N'A^GcL>[hP#>su7TE]G,=)F2Dߢp p- 5#ߨ O aDS-KDZYp$bAH G|mn$uQĪ/f4R߅4.$XGڞCuex%CGogp.£[*8Lx?q) m \t.|ѠG OrҘD;twp1Hc>XM"<4 ?)V*B".=GW5vU.XZHr~DZ~¤@jNR.3n{;k{r߿#?||Ox{=5kp^GgC?OdA:PK_ PK@*proguard/classfile/util/StringSharer.classV]sU~M$]Zh)4E(B XZk)ІJT$lfSi?@aqGr\??QMҺ-|ƽzp(xQ AQAÈF،1M ӓA }YhODqF gxp&WZp^^ )\]$ ȩ}:& 1LݘΚ.S8uHBsdYJK9JFuCKWak\Õy}.!ZBq._PѮTie->7vw<^og u<`׹QM*Z?zЌ-\=&EgbɜC׀cM%~1` q"l0%EdKi Kd}sX?_oP$a҉bUyӟx}T_ Ck^7ҏ]NAx܇:0n DZc*5;!濈?qu&h3~tb[Zx%F6M8/2 ڠa#-R5 %H sf!^+킬c1f2HV&E*>Ez\4 wDCVRs1z;kdv~ػquh{>=X/MIA7xxe0_Pۋ. xf1g5h,9hA'eLJ=}w{ݛc807-)Xr?c~^PKe] PK@7proguard/classfile/util/ClassReferenceInitializer.classZ |TՕ$ofx!d d&(C$%5Hy 8X?WRŶXIu]]vw붴]ݺݭ=73//o&~8͹Ϲ{-7㸂noy] |_ /?H  ?p矸S~~淓Ow~foo$l.Ŀ_yoxǃwk] ߺw? ]xoDž?sŏ?@!} vEN~RܤCnfr yMOuQ&SJC4MSBto<~:{K3b" gSt0}t.t\hG*j  UZT'ł\"H *t-]E]Ԡ*L ] Z*VJ{DgU4׷6f ^*u nW$eڗL45J2Ebݒ)D$*;T2ޓ+ 6gMkZ,:wY)f9/6S?VX4$m{v#<7aPi)1QEkM&̵E[Mq%jc5#Z4Lh]kDb۴872ry-6<dyDoZ%C$aU{-h!YS$pG2!veÁԠeM(jY=WMTir7D"[t;:FvkMXS"0ZBuja㬻u{hG.u%#9չAqlv lTOG<Ԛ#?K23Z[2O *QWrcQw؍[TVܦvAm 5ZR }P+i6U*tJC+xUA4oTh05Y- ]ˇWUë ]_=IvSC*@Qu(UN ýjv3),PIUFM*EgՐ.q6n]|*(R/L '}"D&>%*%O$%zՂI}OЇUIڭ-$k J{/*sB ݪmtUNڧ]٪IM -tBt}TT!0}LGT8=cBO گ }ROi W2gTzJ4>!|F ωNWJ_\rי& =%r*}֪,}YR7G'QkVJy䊢>*do\{fZf>_<3Q3MJ%FxR7muUyz >|7tZ72aFn٘FT˧+1b602 ƪb7 JA<rɕk: )jN7IXdA2eeHF$#_q@` 9DY/ïn-·LԪj^ M6܉+7^&F9]6714,jŅOiS; ºe0CEy>67z]v(Hl7_k7zas7C.温#m`޽iDD5fghSrA8|NRTˁ֍S OT}_m,%7o}YQb{to$WLlc*x:.r{Nˇ-gHQjflZ؅"j{筸M>o7wϽw1A<~85(QC{pp? wK(8ьTl1 0k([*j2IU,42 1 1t[G JL$ 0O CpsEf&e(ǔ@jEى2vyBƒx(7J <2݊Qe0>f(+PfH[*9̇X<疝)-8*`Σx̐!KٮE2}nAV*^,^dϢg'?RBY9'uQ[N_!m|^d9E QP@u)(p,TpxBoQ2?j$o<9[2_B-pz^~) |1@ྀ:1+x9sF"U,lPrXbsxR| x}}x5wy}х$~ҟħ \?(,_ƌr)xi9BB4Z;6 m8dt{l'[uJU8P&ڛ7sEp@9" `&^)>22^}hj1PT/G'TTf6hK=A\vp+n3js>'Au,sUnca|!LUf,d%Cf<ְ^D2\eX鴜9!.dȄ*EĜm㍫W7Z51JPXgX*:n\nL<c`X[A`]Ϝq4?Ȇw6ZA ͜~^:g) qf6A1vswO2ws~ XžÜ Cb |D0mE(ZqU^Fڇt7s__,ڇh3ڃ&orJKo\h&ф'n>βQLbKNl![SFA~!v˜CunΒs8B= t5b$!9] B$#هq\ڄ)7p0)cJƴ4Ð7ś5^/7V+ۖ[BM7/{ww!th<ά1f3 Mުr^mQz_(ݶ-ڶyaSЄZo i'd-YeئUpZg dZp96.e;)4o-|y`Ni ٶj|편UƬ;~ Q ME93ȫ((㶊ad(uw" /X:Oc?'vnҝeʐpm Sd0}K|~7>z,FFrv)CV=): $ GBihD2 B!yg!#@a\uOOxùvы%Dq=@IiMJIz%,e'{{q+ *H)yF0­ O 12\BhGkt=Do{Qԅuz8^aT)"F~PKBpPK@%proguard/classfile/LibraryClass.classW pTWfw{ E ݄)V -GS^(77a1]v7ЊRi}VmRZ3S[;v:Vgt;8sG67a2sw`>^ uIY)>'] {!7(xP_ G<2G!/q|~UǤ=8&q'd{$Nʵ$))NIr ѿN˯ooJ rg] (hVA-Xӧ&D ǒ‰}j"^JZw{զ>5Ԟ# 1-* GZG jOUS9{Z_ӳZch5p5D_KJm:xO@ Odq+,H-4Ի7'HOt6tւIi-H8D^?C2Zm@ߢvq$?2NzWK.>X\6\=~kڥj -i#$3`-ڜnQ{ɜn/듴"{ge0/6k=ư1fj(nT~|K3d*LwkZ$q"_c%ǧ*6[c}ZIf~O8ңY`J ]Vۧ#.)?h4 &FG?]a5Tp}}'JIq&[SZ2ibK H"FѾ[hiHjA9gzڴq7׷\t9Mͦ?f*S̙QAS M&W_Zbv(0vOuԽZ:Md6 T[ZbLb5I>i/\ƥY.O 4.׾7ʝ+ 9QEƄId4Uq=сxP["ci\`V*7(hƍ Hq+(naƢxԏc>~r=bGwi. PTKD5 դ&ƴRp$aKqxօ qqQGCX S*GTA,tE9}IKR܌E.|ׅ)x(A]˯+FPA ZKjݹk'j # t l~W̿x[,!m/~WqyU"1 אArgIȄU9 (TQ` _V^eDmAʤP5BX 3B%)TLRM PG߈&Z36!9.9BLf7矪Bߗ7*+h*/f9Q5͕GGԬq7or:ͣmyA:i/KChcE\Y![tpɘԁR~.C,G,AXRbz4Ql ŷvt!v"$;D?Q-1ĝԾ;fӡ%fv8.3qsf"FCOqD< xU( <xFmH9/k'Ke[ٜ2[Ɉǹ nqlkӜGTA)xiIJ`v+0kU6~y˔dyM2% &20pzkwjw"Hטv;?F)==s"l3?$c¼nfH ůP ޢ·9o9$:Gw>)tb!2_-r[VTxFWCoB\*b{0i^)f:Lhn[YQ|ڙ=t0X|^k0Ֆ؞=kBuiEc5)^D*w|b5,8SN+V0`cI ʼrrlيmsץeSE(ᾁ2]-EM:ħm4r>zkoMi}>V]+p[K?)\A8V/0)uQ~o| OQ]@q0|TK+/9Hj$#4%9j'&zxOW4,04YN Ӎv8:0;kH%# Lvp.'äQoޞ]O%+8zx@W&;A6!3hԴhqGi4.? HK_Γ:o|EzX*!Ćsh ܥ$L PKPK@7proguard/classfile/visitor/ExceptionHandlerFilter.classRNAP Z (jb=QQLI -,91āqԎLj@Ż)W ye(|T ѼPX֛ aZq *Px7j:9VȏFJz%^\0xy]R;'Pz'6!Q EZ}~]Tࢄ ט+wpm\Eሷ2ÄC}ѣO_oQ60}wM c%DU#ֹjf$Q Qly`^c7;@[:{ZӰ.Sc^!'4DPM|n^lOϘ$gXP1xAQG wAPK 47PK@5proguard/classfile/visitor/ExceptionRangeFilter.classR[OAn^ZJ)V,hR˾@ԦѤ  M:dmv+xg}g&}9gs})$0GZx fH≉9&2#CUo"X!)歝'(5H dAæzox J1}WPJ;B} Tnr3 tCW|کDvď JRH[ø xfayg.CV#;zHXY~ *'ݛ QkM.14g霦=Ĝ3Ȓ klt޾gg٫}{ Y@:en yI{EQO拆#b_?բq&uY̡JީA{PK PK@5proguard/classfile/visitor/DotClassClassVisitor.classTn@=iJBhýBZ *ЈH E9NE<T@Qs3i)Oproguard/classfile/visitor/ExceptionExcludedOffsetFilter.classRN@6qpI iRBNXB EЛco"׎5B<g*?BXVݙf,P1؋ Eb8rQec* ZRxnp p[ށ|VCӷ 1%nRJnw 5e P4>4}{6go 7Yq8JRu<=Md~lTڣ{^[|SDEO=6 yljÄ^d5䠩&5PdXLI _#t1Ccy-Zφ!]&vVwJ1*k ň6t1bNw}''Jz~ ;H3/D0yRyo5d咢_"uz*)7d Q+EPK]ӹxPK@3proguard/classfile/visitor/NamedMethodVisitor.class]OQ~'|-eĐxUPtX6[I= F̼ϙ_Ǯ<^'<晋Xs5/l8x)PJdjsy!LIft=p#5gXUQLt&'Ϻlp4YK|K':{+~)F:im͞NjH% lէ'kr浴;F35=I&Tma덎T%nz޷z(cӃ{q֞-\2;7wal)U0cVݤ9b *naNjUܩjwU,V{^ǒ *x0,x1ƻŢ +yX !Ref"0si۽ГfѴ4_Ofbqϥ`3gZTr vdK)gXϧ8Co Y-WoY+ F6jLa#İKczHgǹu'xUJ]13! e!u֕^WyLʼn9&3|I$yԔ>T=m#+ aCMҿc"FaR0 .bXu,TB^N=x :R 2tc>Z,ڹe*|g(T7j$_e&49'UD*6Qm; v4۰]I|/{M#<ڎ0QWv|!R5Cjwݠc YCT 1IYE%y33O04'4I!ۊfTU`H Ǘ^`I:;ժ%+1t3BT} z ͚W1,aJr qZg7.24- GeBDc ʚ[ M̽=lB1\[󆊶=nvNv.F̒\bF @ibQ~2H(-3'UYfLOfRQbQ%^jZKS݀@sa ԱRQAA?'1/]?)+5XX4+P$PKm PK@1proguard/classfile/visitor/ExceptionCounter.classQ]KA=fYOA=e.SAHC!:ȶ#묄KP=Q]Tas9wΝ &$haB2CSQX!'&YW-?8n\^pקL#t}L#$ٗ=-Uڊ| U'a|﷥/χڬʉת5ĵi?_zjDBOxw}4]>9!akFѤ*t& <8gnWx;jlX=1b9ŤMU| @Clj\#BvO$\ּz&)6(6PKyUaPK@2proguard/classfile/visitor/ClassAccessFilter.classRMo@}kqiJ(M8m8 dm%r&eT $B~? 10%{;v @,Lj̢X(ZnbIE+&U.CYPH6@V;1fwD<8Lz?6J٘DƔ2ELX9TlqɄgcVR({CQEE0ScQZ8C7B: ̪E=N*%BIK@vN(̸`ne͝@w0>R"2ȮSq}CubT[cb?\ ؤ9t~DYQqxLM:ouqjcZE{ L= oy`2PBe&wfΙge,Hb&w"s72:ͽ$ ܏\P< L EDa5f*Wo%݆cͯLNBs7| Q7kF M7VȝF., ֽ}G`⶜vojʷ&07pمVܪoBk$tR^1w*ekN-*W*c#@%Wp& "s L㺁,nhX0, <8߈׌ZY UN-&j>R*{(Z &*gvCϏR=4q{k+/f}F/RH>%}4h33.pvc\BOɻLgr+=e2QxO7e5񜓾D/Rsh9^ 96ɱMHc'>g~BW$ij])[xGWpPK|1&PK@3proguard/classfile/visitor/MemberAccessFilter.class[S@i(7@Q^% DKD83Nڮ5LH1I~_|qFd'lZ rdq̩H+1*ĘB*bB%Z&vSŭ6vEஂ) єigRah3KXnb9e.ѹ CߖmhA )Hi8 f5\EK0vԞ!N6-˹5'<))waaJ'9t 4fD#H]OB& ݤi}%<\{+]<3[A}LOtAD؁D6>pd?aJH!Qu $%ѯhޅM#"/0-#Ty4 0AV 4C zvb$ONVFzH0d A\j x2K:eF[0D %N M,m(Gҧ?\6Lr8lPK-HkPK@1proguard/classfile/visitor/AllMethodVisitor.class]KPG\TfT$M]il刃Aw!](}HҪP"B /`j h)CeSH1(<#AAq D9OPKiPK@5proguard/classfile/visitor/SimilarMemberVisitor.classkOQߣUX[- ^Zo%ӚònY. ԴMYb)ٝ3̜PE/mpaNs)/JkoT;)*ZЎE,Xe+XQ*oVe@'T5C{V7< @ m9݌x 9qEμȈqLd<&;e趼\%7a\o'nk?s^/t$"V|iK")+ {?_Щ/H\=qwLJ2_xajru5,5嘻ٕ;ȳUxRA/'Mo JLC"!y?y݁1l8Ї~؁A)CR`aF U[lKÎ]Pd*[j{c蒻d{>Fh734i@jOQ ʚ44H[)FUk"*4&8X7 sy*(!zEwG){^Nٮ,ۡ.[j]-I)Ԯ"""lVDj)®ۋPP$Sq^>ذ6luxmʳ R&yW+Pe(P @ǙhGB78IR}>wHyP LAk itΪ`A4y1sp9&,]7PK#PK@3proguard/classfile/visitor/LibraryClassFilter.classJ@I/i/mzʍ7WEI;)i"Ӵc ēiaN2? AY82Q1q`}> LFbhT8s5ruQ],n/!2d/e +V}k1`H‘`(e nSO)i䎬j_F{.ѾWѤF}8WCq-#TeJEBu&|mPabFE`(.σ{M0bmh zcSj_4I)`9`N H 4ɣED[rU1x"v%+RրKR˿PKHPK@6proguard/classfile/visitor/VariableMemberVisitor.classoPϥ@Gױs:JǨ|01)l /ƘjJYf}2[ٍ s|O?}jzYh(rCRq[ź C`tNpnf}wvжZu=:Zw[ {(5;~=@ZGeӘ*A }'̵F_ݪxm'g=;Rc Q$|«R"0ymvalwxHO O$Ar ;p8q21,yuqIe,븂wh <ױ^4V(`L{e') L:ϧ"u1k#O%FXGF/~\#̍/PCa-#MvP]_PKhqPK@0proguard/classfile/visitor/AllFieldVisitor.class[KAy)TJn/R"d(|]GY]]>Vz"e109yx}P8r aY 2V&a]B 4+;ݰȓ r^WbQ<hц0ݹsT/!WVkRpt26#!aK6 [3aB;ڵP}ђ_hᏏ`Pn4]8$ڋ~45QHҩ"B 0Y49t(8@ E"KM!='\>"7&;&O_4rBiP)^PK%iPK@0proguard/classfile/visitor/MemberCollector.classRn@=cqRhm' BO<Iw=wܯ>}Ǝ֪0q k5\U)t]5-6 fS14z{y&/c â=s*Lb7 D,TfOãWByؽ89O|o4@x݀wfEʺGy2/j\Qa%m5Xca2g H$Z¶W&ZY$DxS ΌR99+k6lOH?uz"q,Be(e:Q>0q1|LB>ѮNzp@Rvw؀ZXE.y,l{ 6?B{Oetz`U'Խ :hjႆ)dgjxY>]yDbPKwcPK@1proguard/classfile/visitor/AllMemberVisitor.classN@R 'T<ܨƄxD}) .)BcxH|(Eh}x}CJ4C$c+nXpg JX.a! ˢ#fPKm۪wuԄɵ^W=ap3 U %]wVkҲfUbH4hITlݾx|cum B`?zOW @ƌM[+FXCvBb QWN3V]40'x.`<fS0 v[v|P sn4WL>@V_|ѝRP-Ҥ(b.?bYgc`y/` ⇄~L PKF埥PK@2proguard/classfile/visitor/NamedFieldVisitor.classN@McC9%8 7D*$RڊD'8H},kP J{3ch~ `.dZ̚.^`6t@!]%Pi]K2IP 4rWuʜV:Ci `pc\d$7u_oG8E҉:Wَ)gd=$4dMƼtHmt& ձ-pѱVqtC=XYGv5 /1N{ގ~ۃG ÓְnWV?vKw7fhe9$WϺ9Kܯ?lBbe4{Y7'rqO #*grzA.W#^*atrFI@Ӡ2ťHsT7ce ,Fb`C1ᩁgxn& U71a:&[e~cggK1*mcMAb;*gj>Sc-ʄA _%LR4s:xƩ$ PJW֔TIc'pU-m4ccvkh=5t~KVu4P{Ƥ[(*hHuEj2G[G$n}8ޢ* PaM`|Ezcszc{JZ b41z2bbICDȘ I÷S;P";Ic PK`a3PK@.proguard/classfile/visitor/MemberVisitor.classK 0j}NsbW>mF E0L|xh dRN%fY7.\xl'XLƤH$ц0Ȼ"Zn%O-=M>Z'%0eATZ/PKPK@8proguard/classfile/visitor/MemberClassAccessFilter.class[S@ۖFZ"R)W@Tj(75-K))|I_|r\벊+uU5\ `P 麷p[ w,$,aft30B%lEZgddI7Dޭ0Ή\ZXzAC+y}+ϥA!5e$򋂡6b(Nki"G9IJ܈.Eaϲ=C1a|.šYo켔;Ry)wu~HdIJ-yrNv.0S#ܬVwcZQ(PVKmE8ach8#q6RhGqF8 1q L*xS 9f0`190pq_U4GG743H!rP2#rC(+R]CISɛ]W^H)ںw{!FsX"IaP.j5I\$ Gk9FclmMEwInm9vՠOfLjWZVsJg1Rxc s!5R'dn9aRi#̌iꥤ龯g'Jc>ӳ6 Z t94؋j#h ǡF%9@`U~?ֵH!'E0yRCQ2JQ:"8Q&)JٓR+)3D#<-%%*yr垶~p#;_l5 >P u?#\N}XC]i'R=9H'>DPK;PPK@2proguard/classfile/visitor/BottomClassFilter.class[KQ2YFr—ftu8 #נmg$dob5@{^@ĊXubv!bSĖ8Tm*NEGnԻ VAojrʥToC.5708KFMcX,mR5~M,䆤Ҳ0TKF˺4PUR-iT15o(=Em ^D$$`WB!I aDȂLH2rSikUM9-dpk.VQftq=3t(@f^2ϔo3@@NBdވ;qO378hcN"S_5ɟ_$K XPKqx'1PK@3proguard/classfile/visitor/ClassVersionFilter.classRmO`=ڭMއ Y5%&K ly.b&,D?QtKD#{s@i0X0jcO)X73 <x a+nU~sNDUe?3v#qN؍@QF//$!l^o*7=>uJtvpOGFoFkłxqW:sD KLUBQi;hn]#%Medc)RIs ýKLva"tm"5%,)91.gĕ$Y PK޴PK@.proguard/classfile/visitor/MemberCounter.classRKK@mWQ=)UA)x3i׺%mdO^EG_Uvafv`@  Rb1Xa5m0c g!m4 krya16w*d D_85aJCUZ ZVmא-ih*Q#:wnl +OH*ѐ=y& EuQ,uF4H0h$Rdz^2zmOXϥ>w5}8ԄvNBF+>=0UӘ!}DT} @NF 'UV IELmbo'< fMU#bh`PK {PK@3proguard/classfile/visitor/MultiMemberVisitor.class[OAa =c"@X)(IFض+.ٶd%kkDnM% m#)xof3|?`7h-i>!nE3FHfԍ17gfWRt|-[DB-V,l`hfYWO?3b hϓ[VqYhJWG+|m@בX\Za(+VI/e1ΰ$uhHlvP*[ei;) Ut:O 9jNL:NIp n]y~]$|C(OKvNU^ͩ(OW(F/U,[Y}ΐmp~lƑljۚnDsC@v㶊 Qq*pE T\5i6O2z>Jl=/d_e[;@xTW"!>oY%y;h: 8sGc<^8 C!>p1…~>AtPxM>. b2HY$EJB/ {PҮuR©C]ǚ?*cZ?fjŰ(0(:CIUŠt|BpighS"G1d7K{~p+x_?"3"9a/5{u :O/Ku F|x&yMߍPKPK@-proguard/classfile/visitor/ClassCleaner.classYYpU= 3tlA YDAv 1h"`0Й`LQTPPYq\ A,K,O,ӲMw̄ĤRfw=֜ԧK 0 yPYŠլ[~jg+HMDLBBgEBV܃{%tb^x@<(a#6bG%[Dl]""v%bD<-`- .$ P 굘zcY՗+Quh XWJ[uTI$L)o'CR#03hQ5l3qZ蝾Pg-ЪXgu<0!Iu{ՄMdȢ4j3ǧAnƟ=> EVP Cך OMQQ,h&c8w],\p8Yc'hްnh4Bw9kP J<<9eCA// %AiwmUZbFl~`8:q`v"](8{jbqCqgO yQsS-KZNTCսUl苀:J'Jk%5}s#Z{ec\E^RR>vwqlQMlx{u9NL@VKb{msj"1&!!DIȅshҀms{horY9Jwk=(pms>\ٹVjj3hb]eqp~u/ނ*]W\AobZ`8*VzjbUaٙ7#1jo|f>UPd\RwagX/xI+"؇tp!7d2mxWa'<*☌e 'eb'd|~|*3贌B!#yLZ4ԨGi63Y-/``J}SZ,ߔ@BffK;Ya@^RjY#\-{y骲v`mQ+s,%V,ǣ510s~gJ+>ehfdL5ƷN_hw6̜{R3'uw*ęvXaq3r}ڡN.7/˲?Q]MQ8~\u/zfݢ{uca¹~;w\{ 5L[X':*)Uqv_})c/]#)5!h!ؖ|S],36KwwpH1:(*hklfړhv^Mcm߶=NpՑ6ZJNMv9)M@~B6zvM EВV5Y1 a<.Lߓ0S0T#kx3XvB{2C5*GٴSV~>`VXdŐ.b"$d! #p5JPE-*1,9EV\TuTGLSM3LIUCNwY.L}fe޾yڅu+yl<)i&,ΪF[r%tLr+j-):LdX * YY~y{Iבu>9e&Ra@ !cc3,aM̠ Ȓє+*a+%c4z%/ЍA]M*,>pEnsnYq4>b7t/AS_%k ebwr!Cd78JcdyO&; pbYn@0$zPY4F0, P)#ԣ}EΡ_u f,Tu8;j=9XnLx7®#A~"i jnFSvr n>FN d]_/M|&J\Aa0Yx} S̥r$ QQ(&BAhPK#ɥ#PK@4proguard/classfile/visitor/ExceptClassesFilter.classRMo@N Bb >=9RJv*?G.\rATpf "B/y}v 7S84avipZgl1ocA #_e;40ZZ_{u|4ΒV0ZJ0v*}& !prš V.ՠ)vjR#1eRߊi XG5WC51n+f$03sXx&~꨺fsw_H;⬃82up98` â@y ii77GMYgjI78)a_.ڄ ??愶b<18OYar ]0?0$H4xXGp}bi[da>#ah|vu%F9$I[<&Oq v`D k^;T V!nv &'>ez`NPK:PK@2proguard/classfile/visitor/NamedClassVisitor.classRN@="R.V^xBM|Ԑ`x/%%_&~eFH0d윙9oj8SN ؍MA(8TpĠ9=wGA`4GaПa#\kZW  zs`Om˳ՎB K^sGuzymeC]Aw[a G  A1l{A`:- -Z8C-AM4H+8pSM}׉*iK 㑋bH㸣HȽ`tP? z,}"=VDy Y.)W02dVg(E%dɖƠ"<~ *g*3d: rUu.oPKxDjPK@5proguard/classfile/visitor/VariableClassVisitor.classRJ@=K1m߫Vk "bEoXVj+V}4hRsfN&  tLR6ՇL1cVY(Z-/j^ KkY-5,:~B=Yu-MmKTD}!Z3Dբ`D;n\3;~ - %B2ч`'iaKDdŌ51E?dÌݗ=1_y %6;RSmn^e5wh$/m2AEGu+Ƕ΍ trd6[P.d[M\(’eXڈ\QpVa]L*Q  0.!&&$ s!QB'ԯ3nTI&UJMHSF+e⎔z(tA)FJ(D9;hS&r/EzguyF O2@ SPK؋x#PPK@;proguard/classfile/visitor/MethodImplementationFilter.classJ@m롞O5U *EP»]u%id|C^>8iTU3_fgftu ` 1F4jӐdhwX*3{2WҙU Tk>vyC01C,CGVAWx&Ow5X;»p ;ZPw7(+kAӿPt=թؑC\E{- p+܀q:4LĔNti6ЍJÆf +{Ҷra;4hb909zWH mGNSs -0Mz錓e"B`f[hS,`!E",][&W{s n!{B,Ua lTH? [DP6y{ȎPK~PK@0proguard/classfile/visitor/AllClassVisitor.classQN@=[ڵ\Dƒ EhLODM4%KKxI|(t1HAvv̜33;oaBe TLl2`ʋ㮌eF 8 /:p/p^H=cX9L.Njfջ v Ŏ dѝS4E߄b* #) 2]~Ni$̹9oJb%aIe +V51LuxeMJz+VߖMؽ޵pu7Zan!+cΏ/+bn3{eB悼ݩ4~58 ( &aSݸd^w$gy$@7"aBb&eҁ.Go:ءA/ڮh&剤hHq(p2B9L:& !`PKbPK@7proguard/classfile/visitor/ReferencedClassVisitor.classXYxU.-KVtȎRZP LiH&u2.".,((nlƟm2b')쐱OxxvG؋12+ 2g8pk<ka 4bQ ޖhu 4]3I(-0jZʐ_[HA5*  Z2I(tQh`(FkZ[]r$,l6M(=f4={gi:{Zæ*]͕Czx 3 MoJpWw;f\_6&,L,X(A_K[u%Vjjŕ6bvwy.<0i,"&N+q"cw 4M+TsSovRqڇ6-'mE3dC]!W ?byr=I7w"BZqoC~51rgX+ICbjlwٞbyݨq ^lI9ּt\xRQLzԶ#ڧpO%mw3|G(vJ}K_aw#u6 ).fB=qK;sZxE-`oDo_`3m"7SJ8't"Po'+LC0Dc9;n)O5gUp->%7_KꏪęKpsհ/E3\I0法o0N'.Сު'&D $b2`*0 ŠEQ\r^z+FrEH%u$Nr0lAv:fp c E6$+H.*b9ZgUejtI9d]\9\NUa-P|Q,#(- llg)(x2[sbA ,l"&ż9DJt@@|,H<&f4 ($ i#V܅) yN$M qBvdi*i3d`d>@Is7ERHMJJiֆ9G(!PJ KJ3܉9N{4&&߉9EӤY)ᄜ`Βff2)LdH'" %Ҭou"PWISGi0(pYz+x8F91?Q?>ܟ 3ډ0z΂PKH`  PK@@proguard/classfile/visitor/ExceptionHandlerConstantVisitor.classS]OA=ӯۅb*(tVLH v!Lml ?xX Zwν̹w|q @ 62(ddPa J3}:+/;aeÈ-xs  UW 1d^K%ʽ3%HԎT])= h0@m}EH@3|yP=~mTdW#Ƅ͡wG =: }-cы\QrwO<@ŒY<^8}ؾ;&bv/{<aX㪮钕>^G{6u5J/|:R&m149PπDm:'hs0w Ȏ#IC ˄|AmP,Ck:Er5]LE~vO@*4"H:Ak(g OPKSPK@:proguard/classfile/visitor/ConcreteClassDownTraveler.classROPn;W6* -4QD !j r%%݌ Fx??A=-&,f{󝞞XBøCcyc"GAh29+ysiP=Ubq:GcCcB^ŵ>کUIuT[EۤET]B^'?PKJKPK@@proguard/classfile/visitor/ImplementingClassConstantFilter.classSJP=/ƶ:ZBPQ( EAŅؼʓ4TO/Et҅%D+(Qùù==TMCCW Ao}O" 4 3ʅ+sVMc-^HjJ(AUtuN4W\rĭm m˯Y 0ڲ'oWC>G&^)I6OJo:C%#@r-t<"Fw;%we n"E?QϜh&:Qv6PK*PK@-proguard/classfile/visitor/ClassCounter.classPMK@}MVAA{hKA Jt-[DIEP8If޾73mX*!e +V-~1N #sv$Qi ,~PKH>JPK@-proguard/classfile/visitor/ClassPrinter.class\x5$fckpB3!'%"l{I!Jz{/^NwlB>V6{"G+gXԏ_isJǾ }Jk}op!SR~`cj7?(Oƙ9r<}אSxJwx'D5ޅR$_FBwHxEzQx_F: "b/ |{^%/ 2^N W|0E4̇ K>T|8j?w(ݕ2wh?R0N|H9k|H &i|O)US" 3,9|+POR~y?S|7 z"'z$a)fl|#_Kxc&G<ƛ5~y~Ke~_N?ip??h~4~OI{OS)rEYE5~ `p/YIU~~!(/0\ ~e4~uh~ n~~ Enȭ~]k 6h|{)/? !0`hQ?F5D?IO(xL~ϟj9}^/5_~-_ohM?7Kok/4A?''Tis#Ͽ5ƿA?O$Y ~`hQoew?!@/D;l e/&EW!k/Q(!MtD_)4K}Om|O}b['v>Q|'J}AjgU3AšPtaD<]8AqhK"M 5& xs B2d $C$Z&BH,ʀ0hK$I@ o\tkM Yҳؓ%4ILCMC-()͘ +(!؊N,˳Ȣdњh"07u`gi,bH:U2]Xta `M%P"~Me#HcIl@ͦ8 S NFhZFrlhilIxh)ROIĢXh]m*;VhW$X7&o(~oՅ ixJf*۴TcS9l~#cfMLk3H=%Rm)<&UPܳr Y$[d &%ɽj:[*1e!HWJή2)HfGDcE$p^LBft^f 36K$fC^[^Fn13ׅ'bAd[G;[o7rG6vt,;7EJʜh %`_ 8!ZkP s&cfikx.o`goĢp"RyY %rqP9ξ5 ek ʹP[6JFFO"IPwH973%SC6+~-㑆H\FVd'J\V)mPK[rᖮK&ѤA 5 #D^Kx2K'0ncU.e]LF&h4f؇&!_en ) T~&ג(WV()َB:kCoO; N #P8Dı-S dc&!̙mnC_m7ЃmMdw M_.Ao)36nG/HJJ@6^Cܕ[9P<([@ro٤}[2C3g-@glY!MΙ8>&@-,>]@ۖOܗmrw--[o݆P 8*H66*БYhK8)p .Dg2"oZ6w? yt*٤mҶ"k6(ͦi [~S,ǎՂMl~t'#jr_v[i1*J(Am ֚ Yiw!9[\tl&+3d`ٔ6 禆튈Zn [Wں' eq%%>{KII$[[-NqOb NŶ7cf[ f[f]H9 bɄjkح ,P;Ia)ag$ch/.x] Z]ڀ[WO뢂VCDacL9t6{,]Ɇp\guQ)vd8M -AY.*]73?],ZSCc κ-bCu1L #0M'E RbKK1XS(6A^08 %1]J\څcM"h=HoݬKf-X2@S!Aպ/&0a(Xz"QN4]ѷY#&Q'ɔ;rI-SvN%Z1Mϕt麘!J)L]u1GvT+\[}QiDs)u?2&kA )}>@4V/QGPF.$g5/Hw.)y!= :G.07؃MR;A˰>Hj9>`11]"b+KoEbTCмHͺ8$  t=HIjVR]D@v湜;mW(cId?8$9DCxN~8\gQL'*z.G 5j2O8'U4X bCplZ؉M>q.N"Ş,N4F4#SuqnRGuqsð@Yz8Au94!;sSyRy=0h]qp:O瓈@fXID[%ޕX %[٬H\̠,Hnm]64f6 $KtqeFri[\FI` ]w)W+l?fFWUjivK p mE S+ZN\`:Aw^ieʥQ6uqYBt ?[[uq]eP*H}.^t+p.^5ܘ]kr#u2+ .GeFwQ]y:{o-%EOwi7'{-x(#'>Ň̟BQGa eX/Y2 ?&1.>%14%EZ0KHԏu񹜉4l ~o);6|~5D#AŪG.i'$,CC5&4cu_]^t+uAPqF5]g {C*b? ҾQă24VΌ457F"zniWr'JuUļi*߸4oɺ3 Y-p:݊=+DƕQY-q1i]d6~8-GhQY>fP .S+κe H%f9(8wLV"k"=dcY]YF=whFQ=YBeW*b3#'/iћCgi)אkj$L:P&DQ k[V7bfv,qRIů QSJ1ɪ=qs MF7]R7ulw02aw44K[O\ >p=\{0(f v[#+yMÞ/eIdXBYH&fW_fdHVMemE&Жr4'go"U eJdU4{fQy4ڪQcl_3wNQh]xr&.*+EI[Z\qLt4MAf/yh.ryz:Z-Eh.%{En$\-uH,ȃ9:M6g0v}]g=▮:w@ǠttğuЉCg45kSZ(6@;3_Kev a+1{ ckf6Y2Ugc6@ ߖ>&JU9E`;7h{``~CU%`Ġ//sї. U. 釘): `B\KNzl0Dp l?ha!H0$Yb'2v ,gg v.V¡lp{dS8} Dz8~yO8p N4l j6 m;/fCնglsmlsDma6QGmsxm^gQ}djؑ~TՖ?R#|#*q gk|:&G%5w Z(lsКCk:X+;X ? \Ŋj6ap-q$̀فp [ vv!ElǣXl@1$8K.`t6#' `b"LJ0eO63' {,GOb,6;'I`J!0eKq8V8N6.[ a'sUl1eoONIm]LٗUǑ.{ǵ0Z|s%a@)Ï(Oa(|9p̀ w=?bl*=]3bJ#7R:R^w;#w.]®ˍ8`1eˉ]] .V`w@ΘRU._.mQ|ooSjODmijR؍m)mB:$g(bf E8Rd&lY)&}iEF*vBc8#ЏFF֤ji{"_~Ze]t9@6VTb7 ; h6Bg8Vˈ(J*P%b%15`CiCRPg >Gv`s 6ƚq~5ߤZ-}˪óᒙdhizzLC۸۸xE~j㲷vُ*QyH=䏢-(O+=)5Nz1V=6c=lj0e);H_{Q݋i7'x[dNRv: fg`elKaUNtM'e덋~lW.R]ANvrABd ͩS FZ;֭ӽn@݌Zv+j W0v:PaqaЙF묕ЉR1*މU xB߇0=TG#pvF3{9?)Gsr9'#gsr ;6g۞RyedVuضobqxvH9)-_ i-]db D4p1]r[6B̗h3_5 g`I ܅. KR2^e(wAyҠڢZcP]EuB;?D~Iw4svp*!)TUr]p&EyeByG(]^#x7= \x7*2Wx}oxA=CƚK)- VŘyn (%0B5/ܳٹoWk38 P1vnnu p}f ^p Eq8sc+=Q<6;@o>=E,c\rۋ,U8>=e}L}>/0/R^UF 97bkB(s/a4М 4$jnjn9jnjp77eA6fG<6>1Q5cn? uVx ?Fb5BAv.{=a8OZѾN)>-g e;Ur\χ؋y|8ԕ2XK歃gs1_ 8jQ=T*vk/9]( (ߍ{ Vq}-~L_n/ }E] *jBe+jԬW^vFF.*P׉g+Kp֣:`=nzz|l.!~/,87u^ _B [ެnO?ZVj.jCV5c^GMb^bVJGF3hY*бb:>u| gA%wep. KnT<Im5Cr"Q})ÕdYuE+?A+ snBڴJ0?o){n%ב9~br]ya?sUA~ÁĜ lˆ`ѿ/3GpAZvW+|]JP*PQ @Lb%'VaKe%aJn ^zDMZ¤>hK!$#|dYdeC~YGd_c+.hj0RlN sߐ@ߢ';ψ "DNKnT 0{]PZ60;t=<z+SzB/cWH%xJ"=Ut#+a(Lh_n ';}tPK \M#PK@3proguard/classfile/visitor/SimpleClassPrinter.classV[WW 2@#h-hUB "PoH,.5N88ɄU}K@_s] v=J.U}s&_fbQ|U TwyW۲L@F ,H“}Vwd sGLPYz=m{~Rz-#Lg輟An8,bVgԆnz6jaUnd_>W^U&!}r_VUD97sN!!_j[\ж]^pZ`+F`5->3~)-a_.}1)˂Q@H&hw<=#BR%=p'=Khb% }9d J={'^?|a` a$Ӕ= ǟ&)`N|i>=UΪ; cq&꟩_HT1oϲ8T WҺsPKΫHG PK@6proguard/classfile/visitor/MultiClassPoolVisitor.classS]OQ=vR~1FS$ZMM5,J,d?Hb|Gb_M' uҴ!&}عΜ9sٟu,B\1ssE$ENU\K Q܈&ÅrYRkխZҬU 0^-,.qamjҶ͖ okN^<<+C %a[؊a*/3L Ko;YΏVMipa)?2фnG;Rw$'`ܹ}@@#Pf7=cvIDZBRHHEAAu$Qp RϕBf_mzz>C\-iG r>SZph*d "A{-q'bStʸW 64dE!.y$rtO! 2Ӕ0$iJ/Sd{ Hg!|B'6Ģ$}rf i9m>`/m չWP@ ~ꄢGU.S]kNxl1͹w>ĎnJ|E-Pk\^#PKQ_kPK@3proguard/classfile/visitor/ClassVersionSetter.classRMo@}1qҚ~@K"¢VE$Kk 5#~b vfwͼ7oh(f2n+s:X3P<6㞎: f?XD!2X!^.3Ti"'ҎEP#r{р+ (r+H"y)O32M{Gԗ7VcrI_~oiQ*PV3˶jbK<L\EUGӄ g~8ta‡\*袎-l3lCH8ߌ  {'04.mq~`l5Vkc(FkP0`XY!20,u,u#ZtڀF@wjld,ܦfKӂW Nm xQh!C*.eq}23hQ'WU徢t2q-cn gh9 () Z!7Mqڎ'Nȓ2Pc7?&FҠ "uj\;;#ǀM:ko` U 5 u& 8J2g"%|%z}_tƵΚ{N&eNhRų2-p꣛y~v)e1ؠkECPåx'Y @"L譛?(|dQ$@. ,.FOe2DjyTIqY (ND1u"+| 4 yNYŕ CC4A^S*PKkgM PK@2proguard/classfile/visitor/ExceptClassFilter.class]OAEX?j$CY1FWhnY &U^QwWZ͙w9's{@ !&0?Ŕ>E0Lqu^Wg^ŕdL]vWWټ( XttnJ_*/N6vr~ݼ@n(dioӚR,{DiyVWs惵Դ?޴~jKl?͔tD,`a<,`o(+[M{vwNPUte:W}N+0ǿ3/cN5դ@1 3L5Dx x %5Kٴ.?V 0f0! x$gX:(SdlEW PK 0@PK@/proguard/classfile/visitor/ClassCollector.classQN@=ӂRDA|pe) ՝cbH\]`0qW@ -DDctQB4sgϯub# JyaK6:ǎ#!6 +%Cv2M Mx&uypt%!Et=6 fk \@}!M4~HI]9аaK$Ӻ~`/J,ϝ"Fc)?ݟLL/,,Pu*Iط!5Ҩ>-N)~Fw:@]?nYddue\~VPD]QQpYyrf6N-pAYqdD =|ޗsޛ`jjI]T+0T TϐCɩ]L<S{R|15szފk4j= 572jwT(T{̗F&l#r tyc1;>CVƗ=;R 6AXtr`X;xB'1 hѢ,]cU\y@tA%e( HaҨ3C/PKdHPK@?proguard/classfile/visitor/ImplementedClassConstantFilter.classSJP=7ƶ~?ZYB+ *.Vܤ"~!( .(qmA.;3̙WN]qhLOKI1aHð\ټ[E<+^TMiS67(v{Ɛ.盎*<Ồa)*e\ş0bj^7f.w!Vt-N T+\6y!*cm># I@Ú264ljbmv˺ ϕ f^7=[cwVj"C$:;bN.۫3n3$z*ze7|ݮN~9e(I! av{.+(>}PyU4-V䌆!'*/ݞlPL <. wv6c4f !i`)˜k0Xcwnoz IG!ݫc9FLFD>E:d ڙ {Fv4d%G , tYa>!˿"P:<(U짪H_bЫTl.aS+FPKd9PK@1proguard/classfile/visitor/ClassPoolVisitor.class;o>=NvvvFFE ĢdpZfN>\f#Wp~iQrPA.2*H/+,A1eZ@sRK@b`L lPK% PK@7proguard/classfile/visitor/ClassHierarchyTraveler.classRMo@͗1M@H۴hB N@ BFM? ?x5ƇyٙyOvĄ,`CCMæ- M<@C <2m8 }| PLH2P'B3V:P14#5<su$'df/ /@{ O=v6rᱠ@|BuX:yzzYM9uVXXyG&{)H/O/p hZp¢% vb1óO|p|rτ2l9VlC_vͨh?=O«=3=E 7GYߞnY ŴJ%2VW鯃 T7o`v5F^c\](|! m uMP>*hisP%GQnD _a\ƚb*7gč#>SD*3X PKiBOPK@7proguard/classfile/visitor/ImplementedClassFilter.classN1EgR IP\S@TT"To 9)RiE| *Q/9>:r6xD?&0e5`cl{6ga‚E.P֊l Lt[cK{N, Z -;RY^*(P>~³yCDQ ^^T2qgWRS;sbf*zvĥFKWeIEWXʡ޹ %p b²:1 l;'~TVCg:*`fW>ʠAuGWsGݹb5 Ñ9Ñ?M)3\m1a׮a^Q,."7ݽ%8^K rfng(>/͞|<{`X3v PKxƿPK@proguard/classfile/Method.class;o>=Nv6vvvFҢT̜TFnԒIJDFɂĢ4}Fļt}\sRX$+PK[{ qPK@%proguard/classfile/ProgramField.classTKoQ.L/*ZEmDw*!֔4ƺ֌ L]Kܸ6QpPdHN2wιgǯqGe!! VnUuXqCFaFͰ{l؆Ukrh6N ]iv6tf_n9MgU¨68CρXfpm,AVWS2YƑ'҉6;-Kp~WsɴK.8U .{9@m)=醴eF=81T`V 24YTD^[*Pq[1e; #ey 6I-pbW9 1osRnM.Cw02d&a}Hg/?:!L/3EhHΑr҆:GR? Nx /"ֈHF|Z< $>ȺK5 o(0J)<"K#%JOkRLjx(-d1@~'`"NpD <#"b |Q@KS>V*}EkIaPKrAMPK@%proguard/classfile/LibraryField.classRMK@}ƶoXk(D/i-+1m+уG(qvPkݷoޛ@iUa,qLdS60c`CVǺzͽЪiɝBr-=~(TkaEբjD Y&h"%9 1ޗVax%̶:^7N= á$2l&hGsG}iO1u"5=җ Iڛ*?"֝Iv[0f N*;e#dCaf0+ԲXGn="rs #PK'PK@"proguard/classfile/ClassPool.classT[sE=lv:%`MİET.Fb & 4a`5;2)-oś/>hBVY<g_ (|w[9c8^!ǫ&^I&N)k6FzC-MsxKYgLme-xGaZS1)g0ʶdaxgeQ-0*7N$" κT~VE%鮊MH_ٖepb:uu[-󴹳SPLWn:[2ޟsۢ_\ \r\PQlɖ= q+Rvnp岬z {Ve,buE^]`0 D!Zmyz[gmoӴs=FLb+N-˳:f;99L2NkՕ18`cE 1ipc&:U\6q3ǐ0!U\nM|!PH""2/adwJwdf4ئe9)IiaZG ։6:Z?VIvC$_ 3=bd&ݕ+m(A6O ː~)뭖MuA}-ah+mmr*TX/!}nZQ~v._EH08R#Me& I=KGϚsV~ӈ`#MSXDc0?_nM%R|M)Qoh7գR RS_X6CƉkhn4~qBx?PK[7PK@%proguard/classfile/ProgramClass.classX xTd IH HdH0PŠH@ A$H*H^@2gAZi`[U邭T"hѺԥ[֥us{fKL{s=j(gl,=L2&%e})>2vI_n =^&x<!I<~'~/`5ɿd2{.#* Shh0o 15[w C1%'Pl^w$W#muj42u4xڪEs:Վ7^[b%GZ냡iWI#a9'X֤ζ k"j"r]ZleR̡@Pͺ4M5Wcr#0ƒkLLWg[EB Fp)(J]u3VZ9`lzb׬p&7/ǻVhENx;Xb ٘dD"|WOHV =Zx 6%Ռa~*+bl$H`F'iV?az PuQO7d- 90fj[[3eՃ 9'8S6TRO{1-= ,x gD;.-#7ۃ6Z̰Ѵ3X2DM'#`l:A_l ["jueO 0z)H>]Vb&P|Ypvju,3&#҈LXʳd0LIcZb$p[ҬqIuǫ'gs[QvMi^:|jˋ?NPf@71ƯcpPm=Ir 8؁{ %RDp+BEd YX[R^nRW*=.y.ΓT2gZ%+WX5 cg\]Ef{㭷g%fl-=zS[S6sL Po)u-?jԣhʨfwBlBD:atp/ QR5CxQJpyg"􀛢c~u!+y Ѹ%0Ň{$^th.'')ӧV`)Z VSRkh.4ƚ!;@ы,AhYKv"0%}(,FSSXD;1"Ї s:p8k/̮2Lt%a7,۽گ#{vK ,裲{ ב5rH;H&C/Oٽnǥ=n^ mwiw>HvgO&U ڃڂ:u:>LHH[MK2DQQ')g#d|Kƹبgm6>|F=59́Ŕ/{89hhЦHRÉt%i>7*sv$7zqz馌yӕw.r]/rnK>$WRjwՋɜCHUL"w=k;U䊖cu5].Bn=Q+a'1GlBq kq؈NGD/.7͸Z܂ĭ[ ߵl^c w+'r֪*<݁r񭤋|]{h۶a4v߳K/y )*ϠH˜m<ƈ0#_"֦D$@ċEmxfn+ aB bĵQG{;5B{{ %M?2Ѧ_ L#)t'+Lw(K }h:pk)n}Dn}Bn}Dn}J34 t xhr;\4s6uᑟnSMTBE#FjӀLpDLEZ5zZE#PDmG3?r@[bua \ΰ>3rLs2}! Rh@c Ocn~JIwQeZl QvPKOgf PK@proguard/classfile/Clazz.classUmS@lyW@ET;F΀e^0iI.G9n6%Йɳ^ Yx7Yx+`t4oٲ 6 eY4-%`(l#Y(Vg9uP ʋF4զ8Z@-r7ʩjtݓ =BuZ0<ǖ0-}? k;nSzdfZT)JF Z MuVE\<9Y/ c܃szFCVNB:[}%vrmr4Wږ욀w))ZiI̅r;J7]+]]/OY⠵q2S>|K^6}?"tMKy3%X1s)TMʴ:{[謭tҰtɿe׌Uux5VQ=dud48P9KɎjUw~ ?t\.`Spc:ђJ.(`.zԘ/[/Nێ'U3 r{T[=T&5yʕ OЃ/d,a/csO8Ċ댣c0N8S0Mxn22e>oyKx3a>bȸĸ ExLS9 xI kS8APK/`dPK@.proguard/classfile/constant/LongConstant.classQJP=Cj*4J7E-D1HLJ.MхG7m-҅.ygE IL1#bVm7i AMg˅*Clv4 Bϧ[ d iq׼0t䪪5\KҰ훒jpǹ T6xZr-5uGw-Tjx,VCnbU7y)3 _~ҎlӴ;.yz$?= GAUS>` JQ\H N\Y|A ulP&m{l[ܡmXZ=He怐aDhX'("J^[U7 d7PK`9PK@/proguard/classfile/constant/ClassConstant.classSAoA}Kw --Z[AV٤h4&m$!lE/ek,KcC xNhSJ[V.'ԨuNn")mFHi:!&5Q2_-P2&+ewӯ@|]eWɑ7d+`hˉhbkPKePK@0proguard/classfile/constant/DoubleConstant.classRJP=iV<(5u؈Aqg%Ѕ$.?J<Xą.3 2`04:0 ˍS@Tma;Ji&8DV< ML̤KM)>*3Y=^a7Iut/ʆ-=ҲrŖ[!|M˳|-WD-oO5]+l|%,r40Ij?=f"1;{O#.| rT 7/H 3t5?[9?k3/(i &vM6-m<i,# }5i&F&ǢQASХlRpvibJv7yn,Q#2U, T|HIWS7 ZaOt lR <cJxLt8¸vPx/l0~c'| mߕ*P EZ }cO1ͅTNO4nFKZ[\.+` ^=weQK KQ]=u>Pd|FPKgǐPK@0proguard/classfile/constant/StringConstant.classT]kA=MôGZjXmR,Z[liXI7e)%">X%ٌM@½3w=e@"`%0VEXA" ]2QdSWa0ZMױZѮSVdt!w]Bl6KN2QC :k3LwCj0O̒irFp۲-JFe-ѹoԩ*V3f ׸ʐOIDN.dy߬y閂f]7cTv5m8p,{O/aLOOn,OOk ߱qiԝ40aS*ic6DCK*ɠ#Vǁ{QVЕC}ݸGtɠMDޕ/v9gXD~~0䠗J+ )3;76K1 ߦ|zEuu'G}Ɩi;:üdZ!&1#;GAO{ X IT }(&q[נAUGGT%ٲ%, _]bnQ>wiS.IM:4 i$GH#YL{PKRPK@4proguard/classfile/constant/MethodTypeConstant.classRRP=)M#Aj h)N3Lg aMH1ZNvor3:.?)N)]{Ϲܓ7&(vsX+;%TqWǺ{]WN0$ :ځ F/w{y };ֺ(vZʼb%P?y&շ{vJȃc}f/y2y>)TYRS'nwZOaD(b;$fVq N F~SwK7aȗZh?2lSI3QiB55cpY/؜E8^@֜$o0;'W0ijf59e+o\ ot:_5\'ķ6hi"ar4 3+qPK ,"PK@-proguard/classfile/constant/RefConstant.classS]oA=+,Elie5ĆM}4[ei1&4|(e[,$}9wι9?xBH ȄEN-ˋ*VwC20(Bu:e?02C[0k?s0k:7Q嵒3,Uf̚j+&Wl!2'dHTAJgVS׊njMʄ* Lt9Fc7] !`ȧ'_'SyjjS3eFg1iZmaUTVTmQ#Fw5U fЅs7^jK3WƌYx e+"SUQd< .STiu 4怶0{昲8b؛WқG & ّL#YD1@qڥ(2/6a"Q)E%o'.RQa7*uOHS)-C91F^4xK^ /xG2?^ LS%|y0 $6d"eװLǩ0p944>~m{p?PK$clPK@6proguard/classfile/constant/MethodHandleConstant.classSMo@I I ~RJ[HCs +"z`Hȱ#HT([JipreYT0[Y(p;M6vUp> kWk30k ́4ݶ5yKӵ;1}fڡۺ%:'N72 3ȥCٜno:.oK!6.#%Yw#Po쒼Zn#A? |mG֧I3beiaZ 3Kڱ<nxވG,w腾_8b 1쪰* *ȩ# ME]Qex0E ۳$紥iX2sIhk‰vxs٧I:ޅ @ӊܣ 9Zћk*~}h9H{Hbz2ՂkSOHvz|e"\LʓԷ7p3n-a8_3$|p¥.jlF.&+Aw(Pv!#c2!gZ_PKx]-PK@5proguard/classfile/constant/NameAndTypeConstant.classRn@=k'6 i@[Jo8%Zq()*xck`:/x >B:&C_fgϜ9;_2T,A4cC&Tl͠Ż>?v;~d`xqC;F0Hq{c٨2Cet=GnpNGfTEzX0jϲa M; exV5~ڏ&FT)"WsC?Yc/ȝNɽ%^UƁ>TjS¥ ((uvysTUh=D av7Ͻs̅&_rmλ5Z &KLME,&K IXGfB=e:+n.B2WN! Tܣx= ! XLVA<-S QR7p$}^JYD]ʗүI !Wq-o|!l K[9=S˩yyAZQq/6Pig(ȺicBVPK8, PK@Cproguard/classfile/constant/visitor/ExceptClassConstantFilter.classSN@= M <ʣxJ[jڪ"X`7qhc{_ ,|TkCPUlxs3W. oc< &0i` /Џ:ueȊ[tTAۂ!Wr۲ʗnkl wՖ |wB7-;HGX*k̪އSt#Г8 [ פgka!MpnbT^=$DE_O,lԽз7M3[E'JU̙00`3&^ᵎoD ? PIǪvǑ;R4oq ~3h$dPUyB >;#6=6hhSd)MD.r3R"5Zsbb1bXD`Ttt3!C_Z|^ wdt?c_(;h7PKPK@<proguard/classfile/constant/visitor/AllConstantVisitor.classRJ@=XRJ7hTE(EOXI?Kp?JIWHKsΜ+"6UAK* `UA!ۖr˭ Gd8trt;έ0 mz}V,;a9prBeaPnn^7 I*J.{ ;Sϙ}iE%w?J'9TR7.!U2/-QDYQl@e81=GVS eLCF` P(U6-W )qMw$ 7 {*9P`#cR] .!,)rtB'2oaHҴS\ՄL~PKooPK@Gproguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.classUkS@=VBC!*}PR$<"P*UTf@fihtMhtB)6{sw&ƃhI曫z7ja8A:Eo,ޏ{꺭ΔΕi{tm~aP1B+qAMKCGc 5e7i&/Lj}ۉXDZ4 YG?o{|6E[8q1i7bD+^QڇWl؏E蹵M#$h9Y1T :G ZBazaPKs|a&PK@9proguard/classfile/constant/visitor/ConstantVisitor.classN@OAQͻntCnLXr1Aeb2|(c96B3}әs 9e$Oձ+:}j>D `1A}8<1#ŌA3I13<S83f-PK`˯PK@;proguard/classfile/constant/visitor/MethodrefTraveler.classS[KAfͺ5ziۇn ҀZA}ܝ#0 ,>gIa9s ` o0(fQ1g㙍 M}#P#CٖQh>mL-&|T(ݠUrRha4!C-؍G#E񔵩O{,@gg{ГHNZ/\J0H.usL4Y: +Xpo7S[ xq$/-%Rq1dJ><*x*о@0:=л*0S C#sEZkO 4*90YIi2v0Jѥ]%X9S#,Y<<ʎS%BBqO Xf'9)W)3Ak OPK$'PK@;proguard/classfile/constant/visitor/ConstantTagFilter.classSNA=RbŊBMmM7kD ۡ\v-< _}D0_ڂF4ڗ{{;gf>t+E3fNy& #EkPX'tC*j'],a\i ek2CTTgYl EQ`ߒ4ժΦ ĦKȭY$ `Ob]} qwGSD2n]a` F1pK.c" 鈘tB_7RT;Wm):ѥ!tcЊ ]~[%]qd'$N!l+l,-y1FF~f>Rfe{Y$UKDqZB1٧xFfLյ<ˇorW{9{틙{FVlvyG *u?,H|Rvc1&fNYS}PKΎPK@*proguard/classfile/constant/Constant.class}QmKP~\[.2할+A HA߯:&sm_UP}5)Tbܳs=zđYdb_ŁC:P.l?VbP.ω2z @0;'"r;ᵩ%&Ãޙ=\Cc^q/2Rk(X^_g.*-OK:U fa g^L15jk&Sgɟ|JۑAł8'}UI3%BJ 9zPL%l@zZXNJAzWH2Zސ' PKwSbPK@<proguard/classfile/constant/InterfaceMethodrefConstant.classSn@='N&ܚJ-T\(j$K-%}kORW:r M!x(Ĭk(B$33gΎg|`+EJy\pMu 7JX@5Z _Ky_ <(v=ϛ3 ~,Chjֿ"ӷ٧+!o0kQ$U:G~v?'qRe/9*']ڥ0BY?'BE 7q’ۨ[yܳB& LKi QܣxCcz!2SH% φ!P2)98LĻy(u3OBĻ:[6g 0camU{q ~0F^Ȏ;רd|Yaxy}|9{9>;At` rxJŜP0$x=+#V\CREJD,o:EdxN$%$9yK{ON]K^ObD|h9묑-^Ƹ*\I M&:.[n^*8s&>8&m5'fуhDB3ӣ H{^wO kaj.ޝToڍr), xEɥe'k=36vG3uJ:+ɧL&t<3'K.q1KDi WS"6BH F3(ҵyK5&$SLKtd|OB'5ŅLWt$+ճ)f|ne +ː ʴT0f2L>']sulmݕ-2?{9œ(8/XF'TR>쐥a5_w]9J9|ġ?J:CW77)׭G]{+ x9t_݄ɉ ́Q0f?V1#.5M<*ކ'{ޚc3] hQރ'p V!h~p6=~]YSDh+=[MlE]YPW_"z?RAՐZ՗UpD60XԮvY}}|oV r$ec>kŃ1ǧH3`?- 5FTx[X ؝ o;%qzҽ+d5Ya)[G0C!J\n6]i&n m(sDԕߢfmu{obDqM߭)1<_ M4FyB|΍G^,:^9R"0c_PK>~ PK@3proguard/classfile/constant/MethodrefConstant.classSN@CPhI@p hFx`Goⅇ>B5*.fw90) =xB% K&KbA]_cP k tvfp#:iRWZ<p*MnMQ*7s;B_jCuTiMS|$MiKv]T۷0 Ѣ6"O7n*O#1aф$#,y2E 4f%u3:PhăF*OҘ'cCXeHG%V:a^ OPd1 PK#PK@2proguard/classfile/constant/FieldrefConstant.classSN@=' .I. H%@ }ȕ#F- |:kEiҙݙgfg_VFޥİ 1\$&/c_҇cx5Cn9 8;^\-m3ˆS/.TUofF[n3Op|n-ʕq3DՒeW-a8}d|\C i 0-= f0Ĝ"zeXE?|ԂՐRsLQ?U]ll(!} fErnCx|0||Ea{$h(WiW &k+ZP7 ӈ<D*ds;(rq}VCao#b @jiQ=b;1$ _/tk!8C>7wB,=uF(߮EF<~2ԭaєWF8]*A)Oio+NUV)".n=Z+۠UU=T&k`2VL6jb K7֗ Eu0;rndHC%}ƒ0J?S󡋚 fG햣`t 1ihd+DFlL/u/W. FR \yp& * XRq U|e+XVpG縫 E:T U&k* f  * LfxE3JEJޣHg6uisx (,U&-߳}oЕg H]>P/%-xj.u۴DSkv5Rм7F k-Kbm7kR@ceѪCsؽkpx65o&b uȝk|)3 ` 2T!,ЏLYe,*Qn)2ȸ0P55~9{u2t\}P+aˆ2D׌3HjCԨ e?q*UL4{u㥾fTM]j Vi5v]ͪKgZ'a*"p["ꎨYXAʆytZԒm=[ kU) b.Cf:цei-1(qcsi,*80VrLbcK3H1 ɴ˦V-nW*80b5gU2j?MvT=_IQ) bd)dӜtC" e W?{/?DFjА0w/"yim<6" 0%6! } c?ґ_u @1G6=ڔ1 y0ԏD'dPkqvkXKj1-D?xnkG'&9OϹ~ 98XHaYa] , QѰ2V>GM*c!e;0Sn|6W }ג ۑo{ow#^};=v/G`GƇFGn;CAgJӒ^Me3cAgC{v[zҊWFNsWǓ5q{Ӊ*Nݶ P86tlȱm]1ˁTIs/{雞e0Q%#oHDeuf^O:ߤDʘ+:ӓb3O qk Sa'?bD ۣ/KO -K=F%w@@EҲ'E"YMh+C)zӭjL CV-qQNSd^0дtR i_n-עB3 B6mϱ {PKW\L PK@2proguard/io/ManifestRewriter$SplitLineWriter.class}RnP=ױq[S76 ZAXT YTT@"`C D.*6!0I 3g^uj@n*N o^#+8,ZAq0o0G⇕{ܧ|u.l{̖x7ۏw=~m<ETPrDvYk~D*ђҶ$`n ZQgZuo7Em/E ttPcE`Xaa={|rcAtNxnQE s+!#ƐC˯q>Y۶ #E8$!<|Mv2R!MʧN#E5t&*Dc5oh.:;H>rEa$9eݧC'xho;CE|.#N &T zR\|*.214K1Lǘױst]GcD7z.!KtvQC*87PKys2FPK@%proguard/io/DataEntryObfuscator.classToU={7:$qӤ%ZƁҔ:!8):є(]&ڬ(DH *q q@8k*Bz@B aNe޼7z3/QRЍ~/ 2 K [p Z .*  ˂K(p ^kGd~A+TЁ1ڂ7񖌔e\fJZ)K \if>nK zǓ CkE˭hE1yA_* Yz)Nzk6nX3\swW/=50<>C 3HruOng9eK$Lzla+9^Q1Aɛn+#폐lfU]ѵj՜f~Tу^qFsSFD91"i3U12U;*(]}7U|[ vJQZnGk7Uh <zG=s(]QPQĒ ]2V,4M~/FSeNLvۀ4ݶ08Q r[CG0>w%n%'Eܒf^P`*lMrħW"vӋ<ZIֲ*L93x(d|>txtQ:ʌXJZݭU*ܠ6 izr3D&}M.uȫnP ٿ)~ȼQE pM(61IJg<6 $:;[`$gxh'\D%xi͟e#AZyBHBv )قkn@[=JIH"z0ld^نL;7 h&_znFtoIRk`:M w6N0$+ o= ZF&X<[G8w|=B$:cxց_ѕ\$/^b݃t!]uH0[ejp /j,ntjڒp #X*Cܗ3wIW/|KˁؿPKo PK@)proguard/io/FilteredDataEntryReader.classRMo@}k;1MJ[HF)D*mU*ؕ )HD8rG!:Ђh́gf훷3o?I̻(bȨnEc.p%"$,"PT:QNI;TI?[3Z91lawn7rsV 8w@0[W=_0~_YS j\P <1% yL ,.~JA)h3C`>?sHwa:kxS&EflTM\1+8K[i3lCNZ Huo`c4 S]/+J]z ༇+3%pv*m) #P K/P#Jz U8`E\U_>ۑ|Z./"iVaEA]oqDM/O<&8>g^J.4I TJ )!UzN}^rW!pPK^2[PK@!proguard/io/DataEntryWriter.classuJ@Դӊ^ 7)\ZnKa2j^>8Q,' |9gW8 1 RF̱Mp5Z}|43bBx;sjKqB UYIj)kY=VbcLSBܦpՃvnFtkN.wkvbyX! ?srSdQr.o"zB MG}) q"}}wpPK&PK@!proguard/io/DirectoryFilter.classJ@DӛƍR5)N/BEݴdD3eH>C' a?;zŖ%=4|XXbú {bvڃ0QO^_$C!qhSJR'SQ!${@s"wI{7~^YWhHCg.PKmN PK@!proguard/io/DataEntryFilter.class;o>=NvvvFԂbF) Ģ|}ĒD׼Jk(FҢT̜TF_ZX U;D #H~Nb^RVjr ##00203X @ PK`PK@proguard/io/NameFilter.classSN@} &Lw&aw "@Hpk%U1KzU?E@:t0a@Cl @+R\؈Qc+ }.U^KU*[nZ|uȼ3Z)$ms':'E3cw^![?3Keul|䶼`w,$HZ׊׾v 12L8&1Ş&æcYjjձDt5|Δio$`FK4\/01L$xKgHG0=_NW|1FҴ uli)-dYUψh= Nv!@cz͵LHam"Hivg;GncyPKjJfsPK@#proguard/io/DataEntryRewriter.classUSe-faBZe7Z[C-*Bmbt)3:duohbeG|//K.-w~络?öw˸ c\tuoȘPЅ dP%H(bJ4(xWb5w:7<y_ƂEق^*vAc˺ck֜Y`dݟlZ;%`*Ц״3Z.scKĤm0}s5 dm! "e0}30fnAهYVtM*ɸ)L`n-T[|}h.3mp6bt+ .e'ˮ`Vtb]* 09UQSLTpW&,62p@g(o{1&`?iMolSqN Jտp<M+K:=%~DT%uGրu ff6f^w\ &nՋEfw\۳^pEt;ǬαS vLd^ Pٴ 0 ał/$lCJ{0!yLx%0="衃|D`&e@V˺ ve0Jc$uGH8C"Uo~do8sxxJE.ĕpR.dһV eR E5.H?Q1EզqWhQU U}Bx.zWK+Ov08?DP4 Updy?H*">i7 eh/я b #X&H@ y6hjkw}Mڀ?ˆ#XCCw vC/ 42E&ЯЈO{&ir(dQ9axzHnz>%Z">- Y|Mۖ: PPK>!TPK@"proguard/io/DataEntryRenamer.classT[OA]\](R". ^B[Em%elFo&IOL ">嚆f̊Ϝ%λrzOł} !*>h"iqKÇ-wZpi0QUSa*Ey)ufx`xYW,)h,LٮP639{LcMAg9BΩDvŴ4c9Ê ]$>giO8cDʜͭELڢLe ˌikCAO*ŤaS) mj=jfD:oܬw?Syǹoh2%ƀUY85͉(yYHhqܴi=2NG@ǀEvc:ױ8g^J4=WHF*"D*~1, ~ϝK_VuCu[RDJ8# uqX*W$dVc JK9$C1>G*xQOuQG_BwEVu(M5Y;댘]523S0T\c kFv  }Cj3^8Ivky;PEwn\<Ț2)v@IQ:t-8YS[.t{lβs'$&D \hsUڏ D o)o$o B)x !}4^G+_»8JHghD+g*5 ^C0oѼ m[m$y,O=c F&2q7c1 28K׸)C}Nͳ.n_p6/ܥYO7 t{!_ R(ё BGph =-x$n#h!'LM)#X Y|/K%D~E&-h ՜v=Ó Wd& ]YOE9>G/F7Nj/!`Yڅ=G"M.r٭|_ql>E/cS?PKE+ PK@proguard/io/ClassRewriter.class}UYWYnhTt\: cP\hE!؞Љn'_f~s499|a~v 𐺹UUZn>Ƞ`>hHI82 81yWp'9N)k[NsK6$8+EN~yIqQ .IqYj89f80TFcV2-Z5rӮU'be1f,~u6a3BZvzse: XfMʂ(LK̹k%a4JU҄laFtXy"Y}+)=csCfUbǑWq8 *cxI Xblcm~F{. X|$lհ*%6ewuU*q[\wU}ݞ]:ƚ{"^b:K*  Z/ Ube9_z*V?|H푀n0uٟA_$gðKO~m* oӐj6Dû2dMFk3רr.D.9hӾGZ'fpy>ut"Oi/iEpXϲ0޹d87z}1&bXE7DPq܋I1"C] *j1qv)Z*.3SC*N)KBTgUeewDlA˴ KOhȌ3w(Ns̈ j'z(a ;Rѩ)#BҤۖvm8aYާKرMCRP2`uUF]iQY36cYei1fU̅urU+M W3է8eotm?,̓ ڢ81#FobjİIt-oe^Imom;:NmF#o:P^|ؑ"sTVqx2'WZ2b,+|G4aNSH]:JU"hx"/[IjxOi4<5<5SCXTeS+16fX*ix5D W񦆷pAcؾ`^NE o㒆DZCN=3" rR$iWo[fkGS+έv @QFLB4Xe,vqvaN8'YϚ]c$.c^Τ-߅͟]A[m -TY+ |E4_ 7gdq,uF37S9@a1>C_PD hQ(soJ?bZ _ı>0 fP4@4<4@4KCFm(5@-:R5jr ̠: o0ob$V %QĪ-gQ^Qˏ9 `MDU@F !lQҨs]8`2C0+ʹy 9*IKkG e}5a@f Ibu ^A sr9XG-I 9A.@YRj[ 8Eg*ym%e^wW'9?ʀх0Q 6y4J) ,STXF'2X_`f|g1Z$bcTy~r.ͺ@*zk2IA` -4N!1u^l |[BRQ͂X)`eD 0r&?τ|q -#ѾEC.R ġz2̢Y;UT5ټNOs.PK;A PK@"proguard/io/RenamedDataEntry.classuSmSQ=eS÷45 2K+4 M3m+2C$N5G5 γ1Q" 8dH!Μ!)[mYJ4EJ}"<\`Q0 ' D.K]Rc~"$"riD_bIr2,pP`^Sm\>q7M:oD>#&B,ou,Z[xC\a `?PKDCPK@'proguard/io/DataEntryParentFilter.class}QNP=V*ڒИø"jq7[Rqc1p2NM=㜙m XZ ȧcCǦ-B#"qG׏dH4az{? $=ߋ;LE/O7-^V=h %4kq ödEsJ?שĝ0ahbI%eTL!Tgj~=kd;" FPxB+qBL*$ >s^o)F-moy9W(lVP-h鰗ǝ&rJm0M}*=VPK"g O;PK@proguard/io/JarReader.class}RNa]vz= #\@H %0&xm4Knl >GIIķEZW\?Xƪ(bQ1kㆼU,hPEܔ[*nXRq06=j{aK\7ݶa9 !r߲-!a>w.27](. V=jg9˻Nm'$o(ԑ@^GӄY05X=իٽqECYt0ӐWqyB2g@H!1f JB8'N%wc?Q:wAG/o`F3 <4I. huCbVr. F%_XB=B,qy(`IN-"z^ a4_ Sx)Խb4ąDCX0@|]}3c&ckLRX*[Y c7q5Fnb[(}R|~PK2PK@'proguard/io/ParentDataEntryWriter.class}RMo@}81q܄RJIJiGI쪾p TERHg\vY#p #~bvfvvyϏ(VWfz ` w-ܳpP*hJʤG;}C($#khaPEZe "V3DPuP`7YAM7Q%/1pANgIXQKUwgJX!yn&T͌К'9^@mw. z`|϶Y Y8k\q\N3[`<[x:3kzt lek2L~ፑ'lQa?ڄg+` Y>/hjX PKPK@)proguard/io/FilteredDataEntryWriter.classSMSP=M M#P@|#Te V ~̠04UGn\% ymp{_}s{?`UC t,DZ4bXr W`-\5LREJŊ`LY۞TsK5+7љ^HX}vB6{v2dߺSqzVY`-*T~Z2#AϪ϶|{؞ʭ- hr[MxkAI/p DG81W_KAC Qx;J5PK`|iPK@&proguard/io/DataEntryClassWriter.classTR[];& HD12*J./p3R> d'̤&{P٪cRT~_c{0ꈕޓ^ݻ{#ql8N `T1t .%q\\UpM\W07)5S JvwdfTƽfUbN}3tMa}Z 'jSLhXqg )/<;nZ%@f!691]lU7bnVHӳm-]:S1u@-*Yn}|Lu->gIn>ߡhmj8k8 iX@a H7mʋ~FŴƲp-|+aKԓq O5,cӂ%O!D% `0ÎtJ[d=x_҈͗|Kxnِ&4+/\lJH6@"ID HOeR ҟɳoG6#ɎGa1INpB:i k!^h &N Mt-)2?&cg-(bM]Hś8D@=x15kQc %G*@JjIOX]8HNi<樖y#藧Gd^uz~PKQlPK@proguard/io/ZipDataEntry.class}TRP]P+ /xKS "*xZܽd()i'Mc|A3:Q봡R >ts{kϏ_Fq\ %IUGq 1\ 7%LJ[1wch%1-O$ci3 f DJk9@O01czo'٥Y7e6g kVq3Nxen lݣGdvlvHâ9T .nXGcW-w\/E[޼SL'ov]]+e!-P[Ϯ/m,*6&g<H ŲLNf%b;^W7gٲcn7*Q1]EzU@~ (x dT<#Y1b*b*✂'*Bߗ{W,WTZ"0|(ٔ[їo&BK#©8*dS|f)e[ȧW>K< GZ֭ga5JoN>T]4t; %I3)rω#>H$n8G~LPKE%5PK@proguard/io/ClassFilter.classRMO@}[BE@#\=xxBbL ))џ婉$q%! {};fe?>4!UykIkAAQC %*6 %AC:me-sΎ M`6XsG@..$ֺ 5dIci< ,:ba,orSosۺQ$- ٖf'(GB3#*m٨nRkw][`AKߴ Z[+ !2MWY"nZ#>Ȼp VABfp,K ^>cGVSdʹPKHXPK@proguard/io/FileDataEntry.classmSRA=C KrT,D%FP,&n6|_bI*_,lBHb{ft?0*: פ&⦊[ݕ{r7%2⾂T4㡊&nYSrIIH'Xi59ڜ2٭L!SU"Ht$J'8=GUZ[:p^ P;dM~ Oy cc5k)ÔB3VXc6~ UCg4Su_0`wS!jK$olAkY0@-oH ˸Flvލci2-h=k=vNv.FF) Ģ|}ĒD׼Jk0F.׊Ԃbvn ?8(9-3'A6hRj^VbY"#4V J@sRKB@Şp@g@4L PK>PK@2proguard/io/ManifestRewriter$SplitLineReader.class}RMOQ=3ҡci+&c*JlڇN11!qcR\DKERP1q1w9^ t|/Ӌa@@hX({v[4@jemM2kv֓@p)8ބ@wru Ibj-Ŝ81le}U7<eLMʒ3APr9|)$S[,Vܬruɲ ŌDm p-ީnwb)x MrYzv8>3sGG?ȗ !A ܼ8}G0mڇ'>N<;b+F+`_MG*tߩ!dC?3*cF -.}(7UЁjg[ b XF +ﲸ p0<氎lM=-߇xA3157MU뛵S~6*y^<ͿMl1hV[6~TD3s6xAmb/v{Qً~Z8s_PKiPK@proguard/io/ClassReader.classVSU]Hذ%MiKH miIAQ^-/ b{.t, ~_s+3odr=;sǿ? _hGo5W"%c@ *BxQ  ^R aXZ99cr4VW1IS*+tqFj!̆9 7mFAV|"a1%ХXVpK`Z ,М[#9s1*e|^jJF9rۦn.ٺ!6dٹY\ ,8އa\םY,׊d%Ӫ ;ct. >HCn wg ؂3DWMp=gR\Ί]Z]G׉B؝|k肩JjxBR<4I WXX&]*xK=lhxP&wuUYZ\`uKd1olD9ẙ/!|#|LN'>g>p~vYep3ېY'JQgE>_v_9ipe_j wvޝQv;YuәV%ʘ_ : PV:UHvjoӮʧН;T"bhF?oRP0#|ͱR!Hɮx,, ۜSKRr\4%j[X =%%y7[w+م\KX-pHX835.7IDQu]&7ܹb>$ZL:#CВO g}}|QuY#6J1{eNB^<ډ%;w[}gq>`@a'^Lw<;RtGj4V ϒ|轊hb,ѼMT&Nm"6LDGIBj\(.#+hAC,&v>w B3ۨIoжuf5݁H`LMW?GHCj .Bf:Q"8Jﰈh'и&9 n!Rp[\$rw!܅՟"D@OD|DdT&죌vi):5&1]R"l[gA4V<ڻVM)K_:f@BGp%p/wvInIX< raHXG<&qu k6u4u70&pPz%Wm >P†>ԩk36G@\HZx?W'n֌:2Eq+#}*-٬`UzC4cUa$&L԰#F b`3Ty(h GFAkӓmq#3kz1haK'I:"q=6jܳii'VFWqz)d8]G>;(ì1[jЈdEON>dpgV+• Wd IoB] ғSUT/hNk -TݰP1}b7[#N>ݟ*\KQ=ə`+ 8)4҅##E%Q[1T!^^:2XS{2{ceY0sFydT=f(&Ya"gC:F9+cC1C)Mh㗱QDjߛ]L-r!D5RHEŔ%Y~(BԷܹX_WP+$6 '&n&?mg"!֩'q6ؕiƼ!vs7y-@֎W.*WsɛisO/i|ʸ9geM[/߬g.JC n]+As鉰.a& zZEc`]Ԅ"n)wjerǐW;afh0v~(BH҈ ʍ1;; mJ'Oqyht 8]I[prWE$(a朮)DHS$0-ar zYnVЌA3(yy!9]VҾr҂pS*QSǃ#^W#(sVϓ?e4D7)AP}QVqVWB_*m5͕˓:k}7*߂QŜ.ep(rCt >-C"`J%FP>+|-_y4 oITzD mPGn 1*^dQOE&ra3ӰDYy(Yˣ8%n(#X4+^pd0B)昲1T [DL*mgSc&Łbn-=q\k[l%,XvWU6#B'bTIIێvM/]TPV<=Ƴۋ4:8=sqvcN|f8X9`58KV_~|ö[4ۃ0~b ;s+ʾo/v7yb6PKMY˺W PK@"proguard/io/ManifestRewriter.classJ@mcxn=^ԶXv$UX^|JM*b? L11m"Y8ϱ0z**G^*>u8߳E p.ESv]|ۖ冎Q,Gڕor"N跻T֯=)u_ۤjz'N-ҳc̃B:noCend,Xf(ŋ\k^3fifط^HL 9p|%t$/KgҵЪP@ Ez:@d HԊ$_aԈ Տo!mL }LTA =A:`1PK܄PK@proguard/io/DataEntryPump.class;o>=vNv.FĒD׼bF Ģ|}\ePjbJjf#kErjAIf~^1;7_Zꖙ 4Z/+,A   %9yIY% `!ROUl L y فl&PKPK@$proguard/SubclassedClassFilter.classKKQw4L{?pBڄ&h%nZћL댐*0-[UJj9sޟ_8 X0 X62VuH0:oNq[!]eRk. kBNqvSeI*NSy [Kn)2 0hEǖ\(4\jy"N~ %V*( nĺ0&tlĖft$MDc+XuެY ;\C o62hg+SrJw`8=F#ds 4p,}vO\:A)RHS5C.!LZ A ~yU1~/DY5}PK<3<'PK@.proguard/preverify/CodeSubroutineInliner.classX |S6Mn/IY+@' hitMn۫i%7@QQ7Cs@7 S+S6qltn{mvw&)Gzι~~'Oȣq*`+H(X` '6C?ya^]pM\kܸV{^UTv:Wn|w2|7a7>&ܬLqq2ۘ,lV^;U|TqnxnH{yp*i&~'S}ƃAT4!vyh EZa^=«}<|^ 1f/*/+ 857\, V kEWYJ~@UWˆz/4=bEfB OzRF"mhE@! X\h +eMx,ɜf9"F2m3lٱDULu%b)ۊB&E[z$14FYIɻ`wlUfX{B+66U@hX5ߊZRU'PFRąFWv*rf_1PMcƣ1B$QfyiG;J=P3h7چMȹ$IQaSUXy.o^ycTBbVD$t8Fr-Lž(ag(зUiMo=#ӎ#q+bDlT3| eKˌuKp1m b%e+4UHаk4UjўT`䫸'4|VF q3d3%jY'hOMlP𤆧 <+ӘBeMM]Ch<[x% 8.G;LxN|W}?%5> ?`'@gv, L?B}.w ^d&C +.mY`ĥ]Q!D" Yl8I<ڢLGd! hA~PKv͌ؽTp+4- όvٻ8B -YHw-F'o,roMcԱ4$u: 5IdaYkV]妝JD2Qftq@>eT#i\E|+Pb@~chb[b!#q,Ns|E0U!١uTJRṜ 32jFqP?P"#8}TNe~)ȴtN'Ų&"np(360VY T=iDŽ},KpL=Q`Rk7eXv(sVEWQGN6K.Tc.r%X*ni]ͭܣVyU:C6PCIJAKgc=P=piRljIT iP0tZTM!GL: .92Qr?tĉ> Y*J8Ә)-nPh4=dz1wpNtd*ݩ~gIR#{҄^Ewqd~Q TUD'Oa:z xlwJ>!IW~b]C7,pyVZ'`^R2@Ut{7h'B24_uƜKwU@Hd^90*CCG`]xҘ/Hك8c0_i xQDf /.SZ~:+D"}wAi9A+-:/sB'Ͽsut%'#5*|:b&!j4 SD#Ah*qipbN)]2_ Ѽ؍{tS^, 9tΠGxd,55A yW} d4oE kvPztnM|$+fV@}Od8P !C N(Tyuɫ[%eX+aTQ20Zdc*hƫ BАa"&147jh Sd*CP8]3T$L]4MTl*^Pq5J7QR (TLf 7@ h$GkY ģd(!d^0d4Niţ)Xr'c&+'N5%|~9-3JA'qji0QQ2͸ i! N&[„$Z+Nմ-[]T24HZ1=μ*]Tgp)%Rmd^kQmsIHXqbf|RTCWpn?#fkw<˜G][qae?Q*a3&:G9t.aښ=ff܌ǣm[YyF;8p} <iT{喏-,ߠ4O6i@& iGnRTTgd,Ҩj$l*Шɢ90AC(?Q QhFKB ϘA;5Oht15k"e\Cح Z)n7/W] _*ZiFkhB4V+ԦqAcxD37O-h6*9YId݆.rjt uyɞ%+6|BB0Lx1dgݕhxPALjWC-  ]Q:5PTFW纅43E-tBitAwjtq /y7ٸW6>Oix{4O8c0aw:H2zDDEʥpy`5vV㠛zT=qlϰvf䚢)^maU8ǍdaٺrY˧Tp+ؙ{܃4bz%Bc4%IhQvy>;64Xۜ$%ŤgCdžr.U,6K!׵a~gWLKx)Nc6ұlzR0aN$=cMzpf-T`5up1+Ӷvw fEaYMHJL.L4gE<~i9zKVx;'5'jnNYۖ]mt܀A ]-(/|!Q ,~<{ ʪ}zpJF"ت <)C c8Mtz/>և4%>U^ʳ-LUWWCZ:Ka bQkΪpY<3Ew:4zQtlRu.h"bՇnx>+3땻Ti8™+VՏj{~26e rQϑ{ 0Oצiji> pyPi솫|׭1a6&;Y2-V 2j|ņbBjumFq?.=*ۋo[ |&uLMBtA,IÅE}IWa+SSZ=YӌQ7jѬpn( 1-F%TV[w|VY. wZa.][a([4 [Q2kevn[?R t 5@XKALvAt%xaYI,mXAYWoF݂~C>CgVI9Fѷ)z -%6p ;:0^ե|o.͐iEE띏 t=߼SnL I*kj`?z!{+ w?Ch@G[l/eC?I0znڋRϺ}Mhgue\Al>\EIq#U[X-ҋÈ8'VP u#FU^Uqɪ>MwM~Wr]jя؀|kͺֽn]y cFl+=~ =Ԙlo={Cpjuxud lh+ԡ{FI9(g8XkC=zaxNiÉ&uq蘀-Iɸq:nrӱQ3]ǹx1:W;. r4h2#Xۋ}i;yFW2y/կLއ‚ NSJwΩ_]N";bu(s$Fp\* 4J~.lRi^x&^?G#NɿPKD>(PK@*proguard/preverify/SubroutineInliner.classSmoA~W}bmrӪƈė&EMjHq,tYID?8 Zў?<3;| lG69\pIGYqECNU tL+US iDZ Ha]CAɐr|%ڡ{ K{C[66ԎDa%C79kGo8˭^;LtS!0KRn="pa-"cOtEQmj(Ġ`N@]ʃY9EDA EZǕ:OhGR$jJsS[6 ҿq%`.jDSk{me;CX؇ayiYDE$Q".ʪsx'`>F4y}}T LjxBl,RJ˔ ӍQd=6S+PK@t,ZPK@$proguard/preverify/Preverifier.classSnQ [ XkmJ\zH%EhHe9i}¤$>eXY1ٙ9͜_(bG 㼆uQu\E  .%pWt :j؊#SC!i{nK{2vYYLg?1eUcU&g.;lpj8{n|2 lv[᥊<x=igBA$s)Zշ ,``6CrEW8rP4P5s 8U󚵑a'$})$y 8v |()z&pݠW:m% jeH'|.zHbĤbXnqm!U|nٶy@' Pv_AV!և SWj,Oƿ~[Md44EH_dȎ_`93"gIh[1@+87yb}4f#D `TǎH /f` ۘ]d 9:OPK3̆/[PK@"proguard/ConfigurationWriter.classX |T?f¼ /! @-d","Ò+N&/a`2faѺժZۊKvbjݠuڽjV?$~_~{s<,wsyHq{Ћ<PUy\-ˉdpe>FTtg\+'3 opٜep,q<[v7xPxa๲q'YE"b9\bRY4L* O22xk n?e2Vu!z?-s0`FY)|,6|Ae!ep]o9l1{dfp\ISoy;ee92kge>e@Ps,/%ťb9/PJ9F/Zz@_z,Wd 7 7-rk2:ηɭŪDm9R^7!gwu+]n2|eGN|O."e1 ~dCxX,51 |Hc ?1"S2LsQDx ?HFgex ~A6_%~eڠ7d7⡧U7&wE~/ ev_`\! lZ-ozn? ~-&s-[6672ٸzKp{>vշ&h;g*Oñ%m ۃ kY%SK. GELksfjuXLVVS݊ GY3d$ñhbfs*ٓJB0+ح)+"h~Sex+w7ĢT<(Qke0ޜfvF Ҍ`r7R{nHp"`4͑i\VF9vDoQiN3͂Y{T#f{!ļm+ M>;\~XIY;"9Di1^㯱cC/xph0Ej v[{p*C7JVDZrq^Fܖ%{}suڑDi, Ei!-v$ V J`o-?Mۤ|Sl[6W CF J h;Iл&'8f n]@bk'#ᐃXcf#9r%I7>d O;q+B#X(}$&.+i'|حT}";cP#6d%г JjB12#*L%]Fb>`Gk;|N܂\p6E2c#g~*"͇c vC"Lw#Ħժ@@ +R+.ro"L5iL%p[l я,eȮfl oG8$nQrZ?JTzPF RY ݊Gb'xE TJERV#:BA+(K88eO|,Dd'9lB!8U.HDrƫr;MTR+l,<~RBGm'.sTB.zQB%΋Mud,i.AQvC0 f͚e*v:J,ǃcŨ8Cb- 5&"Q<6M;- &P't̮2{VbG89s- "e}W I[ڙC?zFȟ+uk16@L7i lJb-lG|0cM5; 91yi?F$5:@xUN?^VۘVrnpYOC;njMΚAf[`^5YیL$F3;,uCYeee%K+9aSrp<68 Uf`npF4 bUi:gL!$ 2E-|F6zt§?FASaL]t_nzSդc R)]7'YwZpC(KV[,.@s>7ZQCx,gؠy uIh!8*/gI C~rbC(גD,nYQŽpQ'"X, `QvMЬdz~OD4AyJ~+Β͙Ś& 6HģI C!,8_?g+qk o$}飑C%7˹ؾ[`*Qu>-~e)yG{Gc˛5cFrzUwc&&KAݩ9;Ӱ3ffפi[X}z:М'`gz"44| -PC'ZS-wZ@r.Ω>iyW\mk6iKtVJ+uЈ}ZCm6ۈ35@gihm"A6ء-@M]6k( h@inF}R`z|mⲩ{%ۼ~=I1 !L:ii:EXG1jqt%NN:@ :aY-@=ޡ 0]Et.zR^Nq }7AWp>ϻJ |+]wҵ|]їt=?C_WtE{}Y)U&ӷȊ%B|p!"ɝ[0U ю@v/(]{]C}Us(s g<uܲq~?]Y\({qq(s!S{w;`.=>hȆDwQ{fjaat<҅] \G&vܽJޣmP;T"iiVeZK!DAXyq#Uk>ص\hr=K0hzeH FuJ~v~U{hPE|h| ?susuRVd}niAb ]&Ct*XtChn?FDع.̋EuᴴJO%_~rM^5f=z:ʁ8TPTţas|WOQ$mǑw NK%, Z<Ociͭ2ZWUxp{?0h?pe+T˯l-?i$tx7tG?Ф)jhӆ)ʽ?S CԦ*ȥ*TUSj 4R5jCm㠶PzB-γ#?sSmgkQ Hj=yUF%j%MPi9LT|dY TIV؅^_K3hd]k bpFL2Y4Cmz%2lW;) =/Aʹ_XKj`< / L L@tL):niS?buŕC*JE\ʣ68 W×WePuՠ^\M5h@Up1ynVWP&i=.fYb✟WZJ,KIK.)Ki /-JNu)H,*NuHN-(a`e` E饉E) :EN&F1@SҌ@Uk;F Hr10sB+A2lZUEpPKyl,PK@proguard/Targeter.class}UYSU.[MC$]ee$%,ftX pg{M Q_jOV7-XꃕWnr|~@ 긂f\D&y4 %L&&^. g5,|M'Hd>ڢ;,0c袋 ] D:hUGn$hLҮu4=;`=ߣP6OG H}MvF6AcaiShZi};U_=-qV1L? 1@ }T5THqO4 nBF4*PKDphPK@!proguard/ArgumentWordReader.class}TRA=C+P.7QZZ.WԲ«X,*L۽WXъp:hG4{)sEUຎtc@à ;u4cH]ri{7;36Tls-;5(PmI5Cmy &z"sR.nr6Yf$`˼MJe|Bf=˱5Ը0\OVq2ERIR/:97!"Ҍm&nB8{N $aܫWUy#=Ř2&!ЖuTta4x8繆8(6 UE~[}# _c{ri/$)Fb޺ j yi{RzB_w 0f?U}O#oOCo5PcwMg@o-V?~6E0/ L=wR6Z%f U4Hk bSkL! E PKz/HPK@ proguard/UpToDateChecker$1.class;o>=vvv.FҢT̜TFЂ|ĒT"IJDFʼԒdvnFĢ}4* *^*d7&o1;X6өo14](WN TmlN 'O{m x83y,ݞ\Î$LxHPGKɲ+z!a* *|LĬ[yO9ܥG5FxI&IPNiFR%IC㼣Z:t&#ޫE%SSv3u[XET'oͮXkRi Uc5}9N=%V=M9TyҫTĬC^] &%1A$pPp3I$&>d3;z]IZݦr*%z6_٪wI`v崊iM u+[*#Ó+fdKGnN9t ];&XT*dg@?e$$ppe9:NVY(, \+ =殁QT(|Iv zb$fhKig>AZBHÍcÑbq2!}x<1Ȏ)nTg6# 0UEoUi;P%WkFFךݙ)'c3)_yg)"zw8d GIGbN-ap )8ELnF$&ußX;8zcu½ctQn^Vd9udб#ɛI^creL6ybђþ‡d 1@y48t_|Y#ιz zE ͦO_8ө9TF_=ih&|OL8:i`Nj |=\1HwuvRmJq-hB]@+ocp3iSgFfr3f_(o _Tdlu f% tgၫucCdBz%aT A 2*S\95wXm#iZ#<Ǚ<,0^: )?Ө>]Ө>JDirw<$QTl'L&Y./|z]݅Hy^?M߁9CAj\T )Rc&>W1 vyO5|Wzn'*n؋E{Q픽8۩{q"7+U2,sv#v//ec5: M&$ZIS̃~y0Ӳl.v/^xx{1fAQ7}8Z?/Տ}@cU=@(nf,nC3sے>z'(#t[n+݉iOP4ɃDM wb^0P-eʃwv})rߋH:ގ2 !cbFG2lr좹~=Z,E>#6q։RIt`،[ĕ;M<8_ ;PGr>Wqh\훃k|ַFj W8zBvݘW eHCXO!˂`[#4'P `q`'gAInR/©Į0iinQxK`+P8"t94P[Ceh`3]||fDh؉ӑbYN^:iZ AQ/#V`*{acc8OT=HʊWp^&Ig! ?x[d4LLP(Sk _Hձ:R>56S,Tkke! xQej~OR \.{H9yXsmeSb dzO(ӠX f`)=lUb6nHʇPK/d:7 PK@proguard/Initializer.classX |guYhkmo|ؒu#>#+ JF#ifvֶBL $`PbqI)`{1j mR(=hR $@)iIߛ]2n?~}/:Z܁w{T} >~ xPGPPu4!!?:ft£:fQ*>1\|B| :OT<#/=򴎕ST9f=Ć{N+mfNV͓}j1ixѨUMfgK)ncXƤLKSjbed-!/o21N!mOfqVũVZJ*c lµ'EŔ9ERŠj3pa5d͛魩 39ݔ! .qH0S4N!YMdPZ0uQJWi#Leh*11Q/)pөLF6`ċ+h0 yƘW4Y:N1M3JcيdsT|!ٌ0t {R-rL*q4E@.M` 0I%2̌j v< 3ͻb_}^=2^z\ 32E1NzT JÌ f sLz~p/-wj ];ܜ&AJ}Qy7ǧtL76O"rp=IȤQ^DcAIy(9`d:;ı ͛–/Fcq+m%b +daf\&pxs_m 67o]9*$H~-Tҽ` B*h۩6uO23O5v=]!Jdaɸ]G2L5E~TG)M(E0ŗF,'2]]%۱GlIrS({ qŸW7:9.wq0R_p^Z%6aZC3ôօi=mF++UyC?.7i3h\ A}?UXMT6yʶ[9w`wO0_50Υ;,Fvi28,3@Yl2%W̆kPkUYnl[{ j[Śc휓3 OE̮Oڷdˮ F~p)TםWuRܮƘLSZX sQ] /b|һ)\[몺U9 *m;0?kNB]4fL _]Iي'nͤ&ȯ%b$B1>G/ W?by 6I^jĔ{kVUo$/Sjnʧf:pSԴ%xT3=#ǧ]TJ޹ʻ(` vfX[Yԃ3>G !e5=mt GBS5/|w%/Jt7Xhl>/eAkiHԧDr{m>UZX;p'6VrO]x G m9P[it]ƈb9Sۘq5/!@HM@|SBMj2m0P3ǠIazo LR'8`FNQ A" C7gN`rpYs -LY\6PKQ-{F s/*7EˑFL%Z+xO;v:^`e_ vP+_6xxU]Ӯ=_YҮbhq/|yPƁrD<_oz~0B}]`$鰆u! n!L"7"r<(!KMS:ٺ&~A4;F5 ~ _F`&m#Jo#-g3?AYܽ4f=Y%L^Pv2I׊zOs_3MqIܠImGfPhY*P!@,[0m!ܻŽ` CϦy;ܧiN?nA"@CyDǴ |\ Ξ;(An^vS!d AɇW fHw W:.$E$ކPK1wPK@proguard/InputReader.classWwW\lh",&QZ)&*bЅb$Cvgy>KB- jimVUf7!<͹w>;oO*6ZlD[=qQÇy}J(0jы S*j!y~*fcA9y *apT̆"Q}1ǁ8󠂏X㸏p(<\Dq$x-|2TV YyxDQ<cq|}U| _VKSю<<WSq؟ंgel3mKຮcm Ԭ1-[+ y9;bvV 2-{Edi]@&gnc۹+sو@Fئ+033 3VM.7>jid}Mɮ~5gX<Ǵ'+Lu-~@Wڠ;n}'#7\A!h4܆<8%0;Np[.qMVMW7ܢm_0Kݳu 3f߰n[R=o;R_lZ{ ]ai ) =I{fuXyIG75| k6^`hxgc B *Y &H# ̫^By"8a4|4s-tMv29ҕV $ }*Ҕ3{5|ؔ͝>jV65y=[I蒞}| ? CU}R0.glǑ/7[F^fuΣ"E/q_ycPO8F.Zr=Ӊ =ǙΚlԦ ] ̠/+E)q6%ks&kj^Ze{z 9IK}/%a a2Ay9?3.k1*Uߢ-9&xf'' WQZqצ]]9עxK5w4S ?i;D e'Az93[@] ~@?_kwo5hs}7I _#dG^譽{i'̜; O`jttlv^nQF*T0mdK*ElAz!;8#L#N29DA^:Jm^ Tf۶z^]a,aRw 藕"f@br`Cp_w.Vw&wuU_ 05ʠ9;/ȝ۷5F @jλ|7!=y\{EWUZuzxDR /TdzM-])?ԅ u >~E}s'lpUb|69Dӓka}Tc 1g%Sf,ᘼ]S^PJ3; ߕp8Ae>rS =wb3wЪSEƦ0L EtTL_3-J-&iқRKeq|CELE,.ƐD"LEm, SкCʴ2(mQHNJVݘ)"t6'G17T_=y"+E,(baG^x:xE 7v9ܹT*-F9%(XaKjF2z$YRSN`G TXqL؉hNz| Li84#+4AXXMb91 OİX'!ab?pD<QNf8I,SOc< DžFQh+hhؔbˆ`C%s `cb'$]MWhMJ=m0\FO9*]m@pW Y{֬)2xW5EV]_)\{*dIB&>ey=gc,Lp1j8A (0.^] /_΢S<;PK ~VPK@%proguard/ConfigurationConstants.classw`^eqxۉĮrM$ty`4M{4mmW{ݦJ#xPVUm1vvjcsKakB0󕂥g ې=p5!;%0Jy tZ&kJڰT8vOeKi߭ݕVjoFrͲ+= [g} IK})lfJ}[fF &fەԉʬQ BVy-RعC{|Xa{OwGખ͚{23F~b&*lgq&G,>dd >tubzw' OB,NLK6'}v\,R6KΑŞV~:n( jQA&j}VaX镼Y ɠz"R)]L#ky]-Pt+MMltcX~Aa"<"br }~ ͠ˈ"mtsb~TR3g6:<[YSK/בf7(go(l̈0Gt%%:ZouW dbQ'ӆNM\6 KS~GazF+e]w˘,ɺa4b,8U Y%V*#J ZA~EKJ}v?G8n)RIۑQR#Ow9#e=m5OqxҴ{~LaFyDtVzLSy-}Gs_3T_Nr {)f45RN*ovat ~xЅ;\CE 7B1^a[dt r̘J ?DZLzeF/ϚVzIȉEa_`*,`P]s؂n SR~RYQ׶G$;קJDwO.b@1rh4 2DO zIΓ>d = ׬^6hW7*Zp?b\cRY*7vTd4TsFj &YnKOƃnhƤ49`Xcvhx'ǫ-<Mj$";A5QXA5 wIt" pDVLJ>A[Wi5u⭪ϩV9bjnSmryd>pOƢ8Wƅc:b›U[QiԶS=tFINp9~wZUTa0hx&66XU70XrduaQ<ƭaTkta)ݹNec|&mnQxe"v( *R%^C*rD}EQ[=c*4s^sWKۖ&'%r[ElJ1N-z*8[h\ísdmw4 g2{fdGAY/ܽd\z!DTs>{ v7SH[q]ި`WF<ډ <ykD{1y ~?sOUR66F%| oo$|x-Ax'xs CN _Kx΄>E`Ề/&|W|ߋ!|_%GR _OS`p=NvvvFւĢTFC IJDļt̼tkMĢҒobIrFj5#Wp~iQr[fAlȸ"=Y RCT02 OJM.acd`d`bFFfH21PKPK@#proguard/util/SettableMatcher.class}PMO@}B+ *CgR?SCo ljIiMh(,9pؙٙ7'.v-YA * 4Ml6`Nދ?dil2@fQ=,J"yΠ;[E: 5?JU>bXS!RVETL0eh:?r/IX{;b <H7!R*8F +6j2 {sX %ޒAq@+@OS:tWb%[_<#_v)`*bjnkͲ$tBڣ]ӂ)u6~PK(1PK@"proguard/util/FileNameParser.classUSU&lLkD FhHijH$KfSC;o>1Ӈ/<8 ksbٙsr=u=x 2."*!&Á1F$|,txxȅ+2qUOx̓O1%a eƌ n ?1 _p+%n|u _#5%epK’ zUf`.4^ҍJN3W\Vj։OS#5VVزet(ebC5 ,/VdU ˵thZіC3 .}@a=%ᎂe08a u3)*"=e!+គ킾zs kyJx70xG+6ʪж SZ5UP+XGQBI qם![mӁP%013 eTmp[yͰ(֭܆۝QyRKj*Z*gjE߮U\0dhSoo ^=l"H&O9U|I5oP"YJPAZZgg *-k֪U3KO.M;tYuKPUj j(ua,BjjTЪqۋfUs[mq \*Wyo0rBdrtvpGk'oR+pFE) @2Iqgx%ax(*V_هf& 6 e|p|Є yһ(GM(sDZJ?a}#.T1a({'6rf}m oI{nG<;LvONļcmܸ͆2AVBń&ֱfb &ax *[Ǽ- VC~(@?e*bLo;32!(XEғ5)2 !~rѷlv[5Y%C%,̐Mo Ѫ%ΥRFnu2տܶn OٸRNZ[䧑/[1*ȨAQ Ȫ6CƱ́J&htxeHe39o$\nBgw96 %su}I]ב0Go.Oai(3Vx"ij]Hlq c,H+Gf4Q>e%Z!IYӭ?=D~LE}XPKQePK@#proguard/util/ClassNameParser.classVSW]au+ Z5lA!]  VƂjmv3t7Q;Sg:~L/ܙIMW`97s=>|qS2*сN x\D +/cNp# \wRtזdli TODOea `PĐ$ 1$ax a:)#|~F-xcqN!ÍqQ p`+060Hpxg"g<KNyA&LmX f5liř6 ϸ%7!ۊ%'}́ք7k>ÎN&jmv%ggfq{S^Êq_J #dsGxF!IGbP*kE720xhaV訽 [$}E cz>S14d6wy%VQ`YyE\AIn_4 BprJAuC0s1<-#V%Jgi.jlܰ\L23X*(x3 쬂Y\qE!%'cۮ2*NW{p:ðcջ 7ѩi3j34+e@N=:V˜$deJͣ Uxh֭7o1tl^ g9c+z"Awc)| 也(|mezcl6Tv-ıi ڥH$-|}OSY.22i>'ɕ$M&_$+JeC&2X"* p;XtH9TEڅET5Ot.9-Ze[BkO/m+5PԪÙWX0v/䨮&sПxsQ9hy H cshH xo`{9>jYT 6ۨYD] 욇zw%E$t=؃88~c\G0lDq 1|J} 5oq0Yn&tM/<(e4Ҝ 1v,SZCQB!Z**2[RCы xǟTATC>@2Ԥ9HV!\G'fK٤=.!'FZl!Η8XtT~{S CZ<G#h3Wi~W!=NvvvFĒbFQ IJDļt̼tk(FҢT̜TF!/XSH#tAQ~zibQ~iIf>FIY%l L b1I&6PK` PK@)proguard/util/VariableStringMatcher.class}RRQ=wf1+ &HQy P,d$&`p+l2.Xł+Ծh)6o=}=@Kn4cȅ& s0au7rPw "cRƔi6-+XV3%a3Б6J5卂/z!ceXǴcg=ҬTV7m)kf:R\d2Bƾ^`p.REka,ی RZFA\'us]K("k,z7vHN+d FiPT/wbL ^gC3 ^L0/ 7MA;Pp 2f-12cA" |3 f V[zbD1i=?:wC ژ3E/[|xȠZFkfpqNwɒ]KkAf͠A6K۹<5K լ׶Y]&! 8`j ABTUHW¡v;p~$@0~ ?L"Tq"imWF$'Hp1꫟;ՐWzrpgC3? o**"%|hgs$Ya,c!ܧX*^)bdcn'z"p mJgdQt:U ,PK6ZGPK@proguard/util/ListUtil.classUSWdae[ZHBcI6Q[A"XKBX?NyC_0ZBqZm;o3n$3̽';q>'v㦄'wKq ;p_A LJ$a ]HxG1#N$Sr1 qƃq~~փ "10rG0ΰu#niS:iJYmT/hfQ4r3 9]LaىH$ff ZwnhYaVAKM$|"섬f8M*hh#N4metb';\M8 2>E2[dA`4<]-cc`V9"'#]DA%\g1.Veg2W(!ˉQy˸2)*fl҇2/N&8k"7(ZF*Q]o)f V9=EC752X7p_PCRMjlU[}",a'rp2Z mt5R}he.ryg6Khr_pQTWQUoAMVZR~M-| T}(;|Ƿ /L(o oPKٗiB PK@proguard/util/NotMatcher.class}PN@=--DIFM07& Lp~?ƍ𣌷@ܰ3sgBB& J(.)"yndL$ q;MԬObN.; UrJsV28ƒPPPWp&qwӝA{ܡ^~#y2z%o+c0mC`:ʄNtBui9QBY7AwyHoyղ gc+kw{y+g6c:{o\纺x?- X\PK'PK@proguard/util/NameParser.classT_sU]vaaJ$ T4Z7BUkPL,JhLb4!YlegY}/[/yv2L?Oc<R9{<05$L ")!R H 㪊0*|xG5!A$zƏBϪংsž#; "|"[ r >a0-0H:mT8C0oZЪfj Ig|cjUMiUg&Ө jfhyp˻ܙuôzqS拦(,u,9S"Zx!_bn(TCK 0n8 Ѱ4ˢʩ"B5kXDENw0«flX/5l`K60/} 6vGy0-ꢹlL%Q0r^.5"vsut] y /rqv'Gfyp(& f< 'pY/f\s3Lf;I~uhQcdf#LܨSaܪ0LO8x[GdPla,sop ;y6 oue^s2E^14LdEI3&I_wq$]ߠB&ׁgRA$ڐc%i;K6BJ<w8ZGt Y>xaD~hC Z/CNowqDH?=!\A蛦69-" zRx)^ H$CKim1A]O`IDs8/aϟp_I%(ǧi.=|= . dk:&~wp;%>[([`?ar0PK(PK@#proguard/util/ConstantMatcher.class]PN@jT8Զ/$PܶeSKJk-ODcj0zf&Of?>1p`F=6mhA.<՗[sI4MQƛ7]3'L4O}6pfEbyV7ZPJ⢅ 6aj:tB76ZX%;A8M*7o)`tWP0|ak ;2ݨv3ǝb~_GuPKK tPK@proguard/util/ListParser.classVSUݼ6Y@B)T Ih>P^RP4`%Ydw7v:S?_g/ f'?BHdܽ<~wroC~ yЁa#8'5y.\'\\0!Bě&EH|}KD-. 0U""1ͷ3\e т!7uލw(, xOD'8U."nϕa d,q󘀸 aꪖuC3z:x(k. kHTswaS5lV,PRU_BL}%!JH5;%CoxS.";,>ɭ% A P%⚄>&! Cg8ZgT1\3 S]zEHzGoٞY ycMI5ٛ2Gn$IY*k]1 5y%mvU'#஄{_N+SJQS NֻC8򰒷wě\^>C?CNk1%cR>Jo1Lcw6Ǜz`hS)yVm 'vFf-?V49I2k'{{S&{pҺxRq T@f ø0؊r*l SIt*" 3)"3Eܿ I~n3=[J Ụ|[0PcubUv<2Et9vmNc hr-@ a\LOa/ 7_`{B;$ka' {,%<?=w@e~d5qgS-8'@\6aoul= w3n &jr8TTڰo ? s)6Ju;tD'PIg1Og",жa 886H֙K9FZyPB-<UH}98?q֨įߔ֯&6qo#F"y- ,#g? opM'v_ l%xag9D牕#<@ u/n[T8;T{ؠ# I9b,hO0e2е+h"^>WӊO\ Ka>U2zSPK;o6¤PK@proguard/util/AndMatcher.class}RNPm+Z-"(JL4Abhԋ jbL<0hj S[/DbQ}6^fgwg&/@ 4XJa9y *U(X%$vعu=z.t(V3 <߽>!q^xB8.<9ٰ;Ѡvό:1'ˍ`[}w !FA9ĺqw5CÚ$R: dqB&jNH(O˕6IഐnYaUb^82W|$sw)La,1n6s;6RqBnY %tm3h|o` 4<6Oϰṁm4%S }z"j>]] ǡ(V ~H؅LXjx-:C!sy2"pQ~C̈́H'u6&*Cڄl"Rviۢ7f~(Xy9DX.h:K*#<(PnqU\ "?{wt!NV*AKz3zBGp+!1DMvwPKɉnaCPK@%proguard/DataEntryReaderFactory.classUWe}d&ڔ)6U,EhAd!I'U?q.#縄sܹvލ{3<0}w1w~_[1t C7[ o3pZ5U'㺌~H1Ȃ7d @0 ([F%IP¸֯muHA-&eQ(2>aȘ0 SA+fX*%aV%2-P zIS*aei4DM1ћqaH@*3IFʤ:9;*v2֓6!ÙuuV6Tg\i6r3n*^dJV<Q>l6,.A>~1d6*aN'Hg0drf38 ܓp_NjafƴU,fΠl\4]|`I6ʚnĤ@ESxJ;m&#4?Pg*@sq}[r:X4ƼޑةaUdM\o_1|MG$V;仛7]81` {.:f&oe33=I=a8 8ێSsTbCfZoݞ#.5[۫l-Mζ c{޽$&Y;Ԁ.t;$=nwOL/Lo0(sdqjVKW < z9>J2ەi!Kw8C} Ubx\w)I\&^:PK^tPK@!proguard/ClassSpecification.classT[oU6z8qnig()$4$ ĕc{RR }[T%@8QT ~AFnl Kg|g|g?17"1)bJij"NxN"%ⴉ>8c 3Ŝx^y^ :u,8ם[йp~ۅ[V'5M;t&T*sy{y }{BمBѵ\|hdvdslN![n8gG.|6]r2:^U7_U\ڽkŦ\!H\)f}!Wp+Ny^3\(UWK4)o& o7zC#gT`0,:BU3%_Ti΂'=vqn咓a7{ͮy18>LX՝i`rƙh~1b((1ŠqHaHGE cTģ:}Yxrx"࿌(DO℆#NfJŲdg72NI9 S39' b>sr8gGҔT:.){HaO>t;2I@@ohŔYR_+ qt.+e1YT)S~1"uHD8K9MvEŎ']6!` BV"TCJkЭ^a%"V"RYa7$j 1|.|4L Y'8O1c*N#]Ĭh{}1FV6w_||x!#?3/D8^>,6YIbT:n)Wq~M8h]<4- QB}ø) YJm* :Pp0BH^ժM<:7Xw=ɢ<&-ԣIOL[{Xh=#V]Winp0V+]}AzG{M"NiSuy$f.Z9vɾtq̎Ѧ&Z7z-٣OU^MFEJVMgcV:-PЯcǓvXVc$1JY|*>)TmXWg*BmUEpq ^-Vt{wzڵChBCEsҢXp)=/j?:r^÷, ~ pۇr~r$B0H0DyRI:AzI#$ N>FI%D\1 ]qh(u{W /3n7noqX,.šM1 œ`_PKT6PK@"proguard/ConfigurationParser.class:xTUffHBD0`H(5R Hf̄bڻGaIbb[]׵ke-K}ow=sO?kÏpĉC0d;p7:'8':'9d'tST'r49Og:,<ΑxI̓Yx|Q._2'J|ǿH|7$7%Ƿ$Ƿ%ߓ>?~ C'?╏%~?/xįxZ7<~+;$ G~I<[/<*7wK^x/FR B G!lN7IaQ8~rJэ.+=u8F%R,X>b+X)WURIQ/O)VK(_5Re&iv mI"Rx8b( <;Qx ֿ?p@p}`r]/]MZhPsZu_ܤ6icfm<f;"zQՐWɜ }ukgzI#t?4!(Tf}M 9mLڟ4SfW󃭡:p>qśĬ)DpVbp0D!Dmműb=nIF,n#]xp x: G;DԅcpFIqK܁k)yf`tmN#zxVQHk` iVQpsx"j_ą%x;}(&KZgH6Z .hsB$;W+hI5_x?q,L?jg?nvF>_=e.qv,U8#n#n>;excQj$Tk]!5]M3|ƍސocNƱaaf tRXڛ͒}%#eO[|>&CuS!s8Q1L[" jj+m0Y1bkn^μgf%|I)-ܚu Esz΋C0Fvy|wBǿ: xΨ9%lR6O}k3E)nr5P,f?ć.OJV#X8N!$JqWa:g.,NQ_[IΙu:9e7Y+<=xʅbK|-!-y *RE=,j 6I~,Vƴƕ ;<̽GGV|Ͽ~?;Ŀ]6Bwiyd1RLGJN י} %~!- ē;9f_Bfu3#jFR|Y/kS@%lP(1V"6!ɡw)벵2r(ڔk/L$p´8f"ZINqs=I8qgAE y07ʝKHq˱fF˴MB{^Y?u)xxWQlq+ :Kօ˱o鬑->8~DŽFbK\7Ln3)$,+([|V~'Y MQP~yb!O0-mDw/\,ًOf;مKX *f?Dfa4]$ٺP0@uAʊsH_U!=g7:rg{ֱ8EZg7H) wu)B;{Dd|j]؄662ҋPѥ MsiQzJKHH2W9*Џ$fUl ah2Bo4h5a$rSxpivF+cQ˥940@.HmX~7օSpK+沥 $Dj_Y$^ZoJyuBb5}˻^UԳMIKA, /sQ^6N/ 1"gw=3f&P1ڵ j̭n* O}\U2_9Uy;[aJ/rܴna{Q;9[le6dJs+uOkb V68ZfJ^TjO䤶bh)&9mv4Uh|ZTbLw*ɾYbu]]lLQPuIj5^7{˩^m*kIȵSun!=}"J8.xZ؎5D$eMӝM&#Vc;[x9<V秊#թNoqM`xdnvrNN5C$(FܽA!u?Jl5 SH0$)Hࣕǚ zU˦5{7[3X_rViaMo6^7aXn!3 "| J1 .NNO.ĦlTGX=ЄRzV̟>w [1ksM#Jxj^~bE}O<懌}$'ܺ*li:wD tĞu)Ub֑RV+\< n\pRֳTƦ( A".9Z8iy4y0oAR.?g|JX' TrNrY?oÜ{M5n"=}:Zl_^ MV_1NU^ f*P>vxLeKdT!KY8A\1ӧ<3^5+Dq :I *Co2j\RҼfFa38u1qŒ8\`VkQL0- D 8- vs,9Hςr. PanԃPvcTaY0," ä0tφO֤aP *:KehX,?yG ZIJ )(7Q:rd*9v(hF!C-k7QYQ 逢6eo9hgQ_*PХZk~{zlTÝ;)s2tAtJL Ewe\aDwb\|Ytw_;%pqe;\eᘚH%?'(WC)<`XjbhKLnˠ.W p86l؂kZ\Q3> 'wM"n~]wk`xo][pO5<jCv'kOCb!/| njoS?],rK*LrD%FnL- τ A1g!S4|턛Ȟn0nQTv­KbTJ:ZC-qiwlQVkmEzLVwHf?6ʏ3[:6=àd['-{3mCB0%ia;/p/ܤm6r;ss?)D2CĆڸ[\4kIG.`C1Ɠ3M0a-8NALp{H-=KTq|c;)Nd;JS,Gtl퀇 zg˰`_E`c.X8 \F~v: 8GǛk9xZlKg Ds 1O-ΉW&?+'R\FYTS@igҳҐ΍#=#Iӈ}jt<+& /! zU![H,RI L(|n<5;onx(;7ޝ =MS[#'&Fwwɝtє Ɍ̐#sr%[x6^a:/?GMO7M,qbI)ax|HQd2"Yw-0P|RnWLg7VMn7UQnJJ*YS]e*;V90>@I<."tЅ W0$2d)gIieHgUcyDEVg2T)m|ۄ(S^$;hE2aۨ! (CT@aP*+'=bi𮨆\Q,_1_,CM G'B(6b^&+x8C\K%q9Sl_)nn]aM,e (MY/+i.r)pKiZm4Aق$͢hqo"{Do͙- ;s½4Eh䚗_i50M*O49i{m͑t$͓|=i$GCyE|SulN dXLbtf7(=D_`|7b$O̮8f` {IEaJ'qG1G04ni4:+ 8ŋc#Y\5Lh[VøȡH.+MItV)T]U-_#fG}:dEv~S.zbr)[tvUMo.*ʴCYEIr - bM RyC(3 d_\}l8CZ\:OՊf͍jCkeϵ6wkcE6IkS@mՊ\q6Oі㵥bL'Vzq(C-(ZFviZvikii㴫ymvII;GE\M>]{~N 8ҥ<ڥYn܅6Qʵ\i s@wR^)ȩj[nexbv9P̝1 BɁ:<ωI"n bFCɕ'qya\'A?!>Czi_@+} õpg8BhCbr^ zh!)z/8Cp^ nئ{> G!>*MMW`@_fX \iak($f6v xPcUI+HWC^ZBNj,:u-]P7{O( yK04wb]ڎEU:mQy}b}N9[́UX X/Ej87M(% Н.F {!_b0YoYz3,pGߘ":OTnڇ%L:Y[Z(a)2dsZ/tࠦaRAw _AwzR7$Ly+!P>Yc?rtK#jl'FpP2o-i)eb*<;UDZbS0^rZ: ?c,enY [v_n.bkpmT!ӦݥM(`A%뀉;p\7|++;v+*;n+(M K<[4V]WK Joeg vnw m߃()g6[rm}#lʿMU\#M޴0ED> " <"RD$bI|[̡v%;k*w%Xю$a֎Yˣqjji}]Лt+TcTT\VŶJ86ن@ѼClHFFX!tx/PK\x 5EPK@"proguard/MemberSpecification.classRKOP=vZ5<|Lg`C$!᥃,0&v:u(vL\ccذ1:04GmAt{~|폟X@@ 7+ẄnJ%9 Q`( ?p7v#S]lb;MȮگrjz~"9FN yP-,u xޫ]k2S//2FvBG kW ;vM!֨q}pm΅'߲-\]ٯ[`AA'k*X=bX0eT+23fXthfi+cc{ v5#6X.&IY܌9dILGKFΙ*Ad}bQC?^Ұ !qs^y + 6U-^ 5 Cاu½!M\5 :^" )HTR K eE\.k.aXo5W?`X4=-s;ϘIfjʕ*6}/;^>f;`K1=\Qp'gEAD*W|CM^ǽ ӎIG>5\TNa(3F)39딒Ӱ崔@HTRS\RеWu IԻrqPT VOF[o=6g4]-3}%ꨙy%6o ]k=knM; ,LKw-g_w87g\qKnhl]wO=ڌ:) b6UĶxYau mnz@:'$$\"[F&c}h4EFA-5M B)bZGkk>|)Uv<2e6y)/tq\29—Axiy*z*n|{c*NG :~^ :pFYף77;.((K:qIeW0C@aڵ|YR jUurD}4dcWE9}{D~p=N]Xu#h tȨ:ΈY\Pq %F9\q7; ,n*y Hߥf>ȽNAlyK 83F%%:AiĥQz=M.6X@d6Au<JnW†ѝ]`ʹ,J_=wwKurfj_b5= ?IcW=l|K}GQu\GʤwHy 4 K)#U!l5Bh0D؃0("Ő'~XL.Osx>;{0 < E$*.9\*zңmSt4Kzl2|DԸRW1]F(YAm[o+ٳT_L BWQv } < (2ʘ-H?#y:PKh4PK@proguard/ant/ProGuardTask.classX xT>7$dc 0H! DM /3w&fB삥.ں@]MښDKZ[]vjkV{o&3L>ssvDJ, v:⣏h}4@Х<> } O2&S>t"@t P ]᧫(c}ѵ>\舟>Ͽ_Cǝ,u=dWF&_e5&_g FģLV&Lؓqv&w0`r'䞙mG0;L{L|?@zO?a?=~~GK\g֟>~%CKkVw*_ǤٽZZeSخ&1NOǵDP-MO mݣS5}kX *3n fKڣ\ᤚNo -p=2cȨjɘl۫ez:LjѤ6hp4 Z2\Jۮ tzT& X1mkYSM`3y/XJ;YF&&oI}ec)=ŵ6dD-(F\H>x,rL9]Lr8ϙSDD>8>"VFb%$X>i$u5Vi3VLMkfeAj1YNid,!ڐT-K"x!M C[ŭWI]rbj@7lk'z1CrL;N@#ZeLs)i &};کiǙMnLQ=T#y@FtI~:޷T<<®'ɘ#fo˙YՈmWͽJlHF&M~M ~CUw{ "ڋxj`eO*A?ҟ3nClԍD#햮'v5mwgd,/ +>-ZpsB֐ uv ,Ii+1Uc!=n8b-1/ UoSyB5zQw6Si3jQ K }>e^a<y x0B`$ʘ`RΤE*E"b"&̛ţ)bX$W<7>G GQP)o+<:} ƭS#Q5,.xPTrGh-nxlTO͖d9S?6S4 +&đ ۉ>{>0Q?uT+v#%%" 8NҜdb1! 4nT.]v)uVE_ Fr]Q Rϳaԋn,\%ةYS"ۈu(P[tMw)81rB#u9grd2.`} ˵iITza_b&\7μNNN1Z `l-V ƙ`hrֆ08兝׽.lub8EA?-OpAq"BeՈ.T/΢. \S06BH8a>F F{08J>1B9͹^{yEvi,ug}T!1:7- aF88mc*B2PK PK@+proguard/ant/KeepSpecificationElement.classSmOA~r TRQ01]sw/Be=3ϼ__C]ӑĸKqWuRÔt4(a)ʹ :p3 ]q]_-3ConVCYx(=+J.JWK mff!CwNbV) BRZnic4s{ Bds2 epEH5G5_O罚ou⦟ QW-wa3*0p75209pa{KYٿbgAD4ЍJ)1|QKXfj C/Ďkԭw➰*0Bu23!I L6x4YCjHL:]a0gm5;(94d7+y[Id,,5^]HERcPOf)#KғS]SL56= Ҵ3Z`pd2I1ub1dަH@|ףiRi0:a'_ëF>Ibz+X# q J=rF>#հ# SBF淟o9!g&$oPKD~PK@ proguard/ant/FilterElement.classS[OAl,r"^EQhjMlՄaw(fwj_`|3Gnf99ߜ͙_}tLhHಆILi^`VuiLͪ1$vlG !YpfTo"]][1teu %f}[U ZUa$"jJ1Jv [aYu͜?)衈bMA[JH' W.:0#*uRPt՚ܷ J>Xq*Vt}ExjwkopsW "06UzpMI00%SrA0ɞh>I3Uȩ􅜻|+,*a%sKg#ӷ7!͉hEc]N*~/a}@ku^ s)VYM,N8ԮEpb,OE2Q`Diqt!NY}v!C q%WGf8>=%Z1霗F71dQhlєn)6)rcǵXXg.jGTgK_*!ǐPK^^lPK@$proguard/ant/ConfigurationTask.classWkxU~d~kzВdClI4M[i6(LdvvmPDb+Zo{nJ+E@/ G}|3dwv)̙=ͼ,Ɵ¸t@`oFy>*1in"'Uۤ];J)i>Ɲ-8K0/8|%ݫ2/_c!"W8Fюu|#!R(>/G;Js(50K}`󤃅Җ4xR(YÔ7ncJVU9*j&]g2&8V*v;6fxt]Ƒr&"O~Ӊɽ=;*[.im3;bf|crR>o%TUq*a]0wMqw"iX>6LϾJ];kܮ3<;hm=JXi_hIXnA֢n|ߓ@x=/'1gon1S{ XµeXn| <+c؃a+{NҜeݱXbjQ΅Zv-?rc;hѻ/~Kko,39ic%cf5qHT/Bs2Nljɾt0SC|'o2-Ns+g_b̤WݨLYLOĻkjd>2-tJrH%)oR)nn喂-ZJYO+;Y>g,*ߥ**M 8/;uљ3<Wbz1~yaeFg`Vxu? eńm71=mZIL>:8+%!1kpD+EEI۳1c(QAtyP(fCE1dxf U(҃*T*RZU jU+ƃjTZUP I#$.Kz#s3@x!Jj۔ʐor/lRϋe)52vRF5 :Z.ŦFxiU{Ußh_goU]NDnȭ5A%2심EfѵlHsd򝻛Z=t0fjQ<'zemv9RfԎEy>dC! :(pyxȫX|G1c<F2z F3:1>f֓@8o6Y;=Ǵ2[ uPud S137SYu9#'mgݨayQo0'h]O9A듞5mXKx`7'}/SޖvlV'MKzedI夕gx};-6vٴK;7t|bA6ңo[Ɗ48 sddI)SU=RWg{/wN_4s`u北qi睔,~Qͤ/r@Z^#+(xBÓKm[GS2癶%p$I-HrְmvaX>f'63 >9%ZN.MMl:뵝b핮kdh0V_1gQPjgV"P;~Õ~_9~xskJRtXApf1#'S46f3v@t=.}ߔL}K5ۥ~e'ݕE6+ͧe^,h5gSn$6nȳRY*O*풎^?KXh"Y󞙍') v0:epUHLsb)Cu:}_g0Hk˽y~oTK6lް~$Tӏ j'4kܟ7͛&\BiVˉ55AkB7ӨuӨaG/shPR@!< P{ZP$IYa "QCXՉ`$X0!|(N(󸐙 FQ^4~"Dvk"QDGpuxI$.`i\**k*I|'"u(Hp(w9+(Ø{ky3Z;D(j+/`U1ǫ}k}㸏[ p*'&}ƭ)V&{p{Bl8.xwj`vAW/A3l;%,7e#3O8ʷ͒PK#-3ϚIkJWY/8V:cn3?Lj]=\f`Rq/ә6LʂD0o:mX8XJBzQsUٙlOOXtHXak3S]"Z*B5EΪFu+w$WH:{ ^]ic47ΏJ6R牤-[rI]}2ltחKݖ'EutK. ^T}?C Vs}أe?yv;h]vb)⼄QqAǏ؍踈K:jx鸌+:S:zH9^~gu24?q/x I۸g9,[J[I a6ҢXf#[}vFMGlK;$FFHq'I tjUֻ0<,i궓\L:IFo4eR 5ޥ{t\ڍt7혹a#;5"d.Q*͈xf||^3.LkB7 V9=CGMut:<7κ.#aim>2sNǰ9j&) yz4SOsԴd dlT{6i>fz]p%Awp} X-s./7G^XYoIᖖsǜtWͣʴ&jӬZ3]AO 媔߭AmCLi5򽙜vhK1rNm^]V"3 x/,^׋:&_1 !R5wp[ pG ,aNzr@IR XdB$| ܖp{G2"NnzKrO&EcyX_jMPkoE}bWPYu=|V3uQYKq?I.bq/> 6'KC %⿎ڈ?T_D8R?["$E}]-IY_r *0J)M"P}p0zp"+XYcUJ74-#-ړ$=3P4,]X,l؊8%Wa:W5,~ q s9/_]~i)?JQqrTOs|Rʟ!RYr@IWS"Mʻ} ^ze|;U u~ר۰`uruoRUQ;</Byq?H*\ǵ)4&&X;W^D~+ǡG4aHͩݾT tRjmdNf֑TkI7n)эe_VbbS %¡%">:oH c2F*='O\sT%ZViWO^,3P7_ :Ω8 ) pIYKr^~j0bH·5bD\bTŵ*ihT'0b\aI9I9R1o3RJqCM qA- RVf8h k_0yεO-pS0ԏK[RڒP=ly.,!|Ѳ-q2u!4d8CewgbI7]ym#.zb{8&1G&/e -!于qJѭ=#.:G R zur(c-6obwf oQGKÜI8yGsp S-pבENż :gh+1P;zov\21CP犂2N+8-b‰q;CAc+AY♙eQX+,XaQ ܒ̩\I x:N(3رmѩ֗Wax;`+{A:Dݨ帘ghzʵ9wgm1_\Cyn. _89.iQe7 |,&P߮"R|RBD!_6-OJ&#Jp%Ab?1g,R8a1Ei 6FU8e9n ėzjcpy\$~oKy|^1y)Xf|B@^ I<j|i%Dy?Dgz58PK;wPK@-proguard/ant/MemberSpecificationElement.classV[w-kcp8! @&`CM&FGxF-!&ͅ4%riӖTO~hZCoC}f䛐0{wfٷ3 UqqP11㤄< >.Ʉ$%yT3* P 9ryɅ8%K9lRbvW$I8.iIxB'9 or\x2p<xEf)|!9rΘ223g9~p70ubtYsIbj%m+`hMo9I"<q2ޘipc.CW:2X ,;3bAĄܛE`ݧyNI)3X|;'e-qcr}P=a3*'Q$;MLޡ(K$,y )e 5NQS ?5P+925RSʞ5EI@ 4j7  A}SMg8Em9egLQx)0OTrrdA#0ljL8Cb͝;E?[tbHiu8kXeRgIE\`ؕEoit4,H=~azXU"%*:fhB2}Q> { 5)I}4i ~TSƕ,f96ߠM*`DCgOK`rTMF>pgS&l^r 뉰`Y·[V&dSUdSOa衫xENzzks>u<&/&Y ÃDDa$ʮBH3hbm/V 6?#^C7K~%&%Kd,=H)sPS hYe}g؝aMtĪYNvTH2Idb͟R9(ɮlO0gnrL_,OSS}Ǔg -jcBRj!T^#x_5\&' a6\$c o8Fx#u !:lJ٬KO?`!C#zbk#E*.|Hj#֏zol4hcPKk Q PK@proguard/WordReader.classVklS188Pn:6ȶG!PI!mGcpc$9{ +et]Y E5yXS ݤ ڤi4M4iҾMd{c>l|q&Uah쐞6TRMMe =5p"CZj:;Cn `*͕^EӳL>=g^V obr1N&gj}H}:QoJs\ 'jkNɦYpMd:~͌ز.I%TOMp-t3\Ѯ tSjusg,?enr'ɥtΈk|Olae/2e<>{}2VQ};]6l༌o6Ɉ1;2E;U:QrSS!xɋ2j <^4q0u$gch*mdd]aa(pT RSz|T6Д%qeK "rLɓZ<{ˑ&x|F5]R\HnԸZn33j^>UuU4 *z5z·_߮a*;zR -ږ RʕH-Q3cZbΦ N㮛FЃ4 Tʳ8՝w8|ś #ݴйDYt/Bzv{6V߆\^>YwU(izOq[l̊+C+iaޒ bӮqۛj/)qBZ'$t_OI "-JgR>\-.6־!V'-bh?rvXUXmY-R!yEKg'ՒHEKwubR.b"VX\ҁDaoOOmװ|RDLE\|w3L+nsG%5$Qv5(GkilKK +YeK8]ɡ mu`BZl-ZI@­ _ik}s,VZ.,2>5apٛ{~ us %g-ܲl'ΕU+Eꐃ9i܃3؄s4DEE8,:@-|w!g#&V^\H38~!'Bç"__|&>SN$W:_#4HnJ$$+%d=HCԞ4G*eyWolv:J xD+dц5n4[Zi(W=Yپo`c*tSњ\b{2-BϮ}L:mj‰^z7:%G1wgêr(U=1BqQṠ+bo&'|n*ߎD;iI]c*?GѪhQ=y<|ʏu'pFVw;?PHutU (<ǝPKtz!W PK@5proguard/obfuscate/MemberObfuscator$MyFixedName.classRNP= @IhL þ-R-i_i1qa\Vw;] FVDNĺ- /3dBUWڮmca)C7]0+Vadq\ՆI1õٳ-muB]/󘤶5u^5ZZo*a&vĐ^WDAV]\YluظW;-񀗨&+Cq Mʰ?gн:f1 f%!cHɓ).0ti/V4Ck؀PK;>~PK@*proguard/obfuscate/SimpleNameFactory.classU[WUI2!B Mihc0BS,RV!E- 8kڗ[_xĺ\>7I%d|>'sϿy C!ZY\aU]cqn =mn, ,n`$V0Aawˊ !°E) CCɫI RBc=LAYєZQkMf^YY5geb#Vq wea De iV߲bMB߲-oPOKŝ #- ENY]-Z1!K$dM&8ѶX;ifs>\g`阳TȧԱfvf<]Kp|?)9t nJ\*:⼊0УtU,X [XU6dQJҒpUdeapЭ cɊhgٙaF^y OTcU 3fo2 ZV)Z%VFT\D7Q쎄]lםU"*@Pđ(rň Z)7M6ifS⠱Hh}.kMzPfE5=֠4YD9^ M&6 3}to|j&I8 ?:h^DY~]606b6!%ѿӤh -H?N…W UHz[1 | %}#.JxJA,WHC*aa<<[-DӅ-G-B.1@QcA OPסm жphC܆*s7w3e80KKm't&ջSSSh, 77h-A%3"=yЌ7Omn-/Q?EGlh8!Ѱ@% }rh8򈢀[X'4ѴtD 7?!0&9-tR G` /tbBA:BA7xLL7K6a#ѫ~E@K#Yyʹ@IKS!yF|f"!ګ<ԌH:ii% I$^T1C }|> NȸD'8aU;|vbwD@9P{e'y&PK3?PK@%proguard/obfuscate/ClassRenamer.class[SP 1(-m roH)hCڞb44G[8:ăqOJ[cl?ୌӈDLaa2H)d!uܐq2pK¸ L)6mLK]LI'ᾄf$2Mݹ3;p|SE3?2IBKЩ Npkӌ3Yۃyz'g>WpQ]~@G|xM4 :B(Z0h$E.O ohEȗiE zHA(BD"p: PO=N|(}DzB{8#zD #LUđh?FHQC`hK$wQ_KBm LI  EhS~J5u8 i \#_PKehTi5PK@8proguard/obfuscate/ClassObfuscator$MyKeepCollector.classUmSW~nɒvۂ&B hip kMfgگ~ C?3Kf`26{yy<}ϟF1a i IHKq)J.I1!R[a`InxW5䰢!Ctlevf"Vkm89Hyvwk(vŴML|DA7ÉinU8wEftK1vHԕ&Mۦ%2>^N?`V;6 5%Qk. F2z:]Z63ڶp>yVni3+qR\iy&> *nqF5uT|w,ΩQǗJ&Fŷ{x{h%j'{,'^GF:9}Xl8~!FC0.vD-~>} 9Qc+/S}y%ZaڮplL#̀͟c+^h4Dv=zhC\-Ҡ]ww۱sZu~crf'&iwvZ>y ". FJ1cKgPC1kI=}Uy%~X|* B,$"FNt ɇ`agdqAy>|UIK1zAlLV:֒'MtьMEEsSy*jir9Gstmٟ5m梄ó`bcO ^E4JKKb5LLDz9!8<>63$eۤ$鋍/{G; ~ !5m oփSlz96Aiz6ۻE|FyAzz@=V;{ Lsŵ@JC 4{tp/ZcJHn;CK%}x*P)* ~j@doPK~)9PK@$proguard/obfuscate/NameFactory.classM=0]wB0TbOãjU8"%P`c#%Gy w&|ɛQY͖Vz2˶wʣTVGajt3Is>O:Cݱ0,pGCD.!>GPKJ PK@.proguard/obfuscate/DictionaryNameFactory.classUsSU,nL ȦI!ڦE B[[rܦқxs-+: # SAh '|pƿ;I7CU^sη|9uG*PvC ^PNhSq. ݒc$+ч~IE$G혊id"]հ͘Jԇ굍TnSTXh,ԭD߱M+t=i >(j*k @q풆E<%P| O˫؋a Ob@ZzܰyaЖ7l,4R $Y**0^u\ Y7[x=RB<5h+㗑#c~s24VJ} pb2ܜPpE{ngO43vƈ7wKpJ:WENlBȦOV™X.2D>3sθa9in3O 86+ez:mX@:x̰I9A.2eY94@-ҹ[E 'YX2a{2y.e┠3qIhĽTvhbjZ ߓ[E@IS3Z.ކ|@|p=⾉/ ;Q+Z9rG:lBb/rr Aݳpp3 oiey(á9wQAٙC~뺆&' TŚhVد*f+(~\˂wC ^<պ0sy_ǦjRA]|ݭfE.~' 9O?VIQGUj俳똻Pkci`Ht|1|n,+YgIYKz ÖݚöP۹ aE}QʞU+]и7y9 6yjEы|[PKcrv& PK@0proguard/obfuscate/MemberNameConflictFixer.classWSW=eeP\ f,`4Š&xDLݷ˘0&DsX|-VĤ*O*ov$~?7Bݵ Gh !☌!'cOqLD/%Ap$g2Ja#e+!2.h2###+p (C,H0%XFhaw6w}q۰n0C};[u-_#}1F1:֌kI'lt|QCsn™ Im(Bۃ\hda缶UfEbZO7u"VkUV&( Z κ1ckY#/t A<P<}z=/,deʞ|uz)O {}a _^@ YE;{tɀVݖ3ۣOp]Ԗ=ImhWЁ] n[Aޗ1TPĘqpL⊂qU 5񖄷wxkhfcȥ+xK!`?`شP1-WtJU!nJ#|L)5'F|O|&pB)R?U3u4W (ϪFhE[Eʔ㢎 Mн`FQuG kI"'+ /||o|)IJOrIb*63Oʽz2CuLԀBsWXgh_}$\ acoqjeKZ/=9Gx/%)%2U49jm6'>EF;./&OCoo H/|KYՑtdۊP"6/X 1܊j6>eCɒ^rkhGݙOЀ25㕮в*3dqNh^W"2E]Jhٵ״JT97ܲ;y[zޕղkjG2>Jˁ۝1joC=+3,VA֐=^vnvFႢbbĂ̼tFu IJDļt"5fB[fjN \7Q#AjojIF>’x,xzRbҢT̜TFQ02(]^XVZXAaRVjr ##0020300iV60adL \PK ^)PK@(proguard/obfuscate/ClassObfuscator.classX xTdf^2ya`2 B($@L^0󆭵*v[*% 1u5ZkmZ[]seW8νgϽx@Tanfr N&|C4␂[=+xp6&3ɝ._t1:*8쁗L;bS>qDq͎<<'=}7~ij<1',֍*/?gs҃=8q.No ~K߳U)I ,.֣!-c^PH@ajjW ;ָm4cAԫVAӈ4-Ck34Lc\!d_l(A4b lɗҔi֛Q#jmfz^cQ-l#E۵]ZUH ZR^-KP({E0b f pK`B2 "F3E+5nJKacTo14hL@Ls2G`:2?em]A[N5Nn,^F0 KYBn1BzlDB5c?snM Q3kfclu @ݠ5he.#fATk BKa +L7Iݪo_ݎ6$ZT"uOs.ElV4X* CnEln8e#f D/Y4SdIJ=o,ק*MRF1S kާAK*CtҮ1=G8WnWrfc׳ԬhoYfk$LZgd sQ N͵Ŧjxm( <,e/\(p.ҡuHβ{fnjxLVʇ=CJ3ߏ{gcӳ5%ņ~,95@̳>WIY [E ZU\q&5CWq TюPM](XȞ6Ve0d ّ:/ҢGU`Oo-R)?Lz1~W_ۃQE313/0s ŘD`)LrE-b5j(t)l(@wLı7`>K\>| P(ixb&[Cɂ?p *;m/|-%wQ$w k'h(D. >Pވ\|}pv[NN^^FnqN(~eC ie7XWeĿ Џ*X؏X+>T@߅l2"g,qvbYgJ]^Wf/wbNǒ$ӵ's1r`8N{x<3Q_g4}X/7+.;/[FG7\*vW%bWv~T+L.O^k `Iv_dZ˸+ځ>WTP*n_tƍ n| !p2 wC#&[.ldP25A`J&xL=BTq$JL:qSu8 R Г9遱.t`sZpr1EL"*t^u2zMFΎBV %EzQ$ x絸Β*#S`5G$vzKbe*Z#'@ G$'H G0(&YQI'ħ,R=hd].Y3 9FsXPhbH07~@Ot^:Vt0p_5%(! ԐӐgHE!JzkZûC4Zpl!Lva#sk:Clm tYv^Oyy!by]i2 (CqB2Hz5̮%xe@*/ˆǽc.!ʇɕ_"SҺFSIz!oaK 9>&MBf_Sc݁*yf^Z7o"Q}9S#g\ƕHxA Bs~PKT(SPK@&proguard/obfuscate/MappingKeeper.classVYU.Y4LئAd2%,F 3"(B' I:;,VUVUneVI VC|'C,dTϽ{sHV` }H*~< ^Pp%Qb<*8;$E/ ְ1"$RbrbL8^ 'ĉuJi&x]xC9 oJ8 æTbF%p93 +YʏW̒+ 1?c$dX$ 7KsaW/>-ehF@U$mU{(I+d\5OL8(?}vV~lC~%l6s5k伏Ӱ2aU+>dHEG8/JP@42*8r*b薐WqK*.JlB[GH=qI]E%ui%Ӝe^vtֻTXP\zt+HXz2Hᨨ⪊k¯*n`R[*;d1D\1E7Um wTŻ**>=SR/AoԦUļ1φa,}gK{%`` &rY|f (7j)}{1aRAs]2\o/Lįk@}o_ȣ_x\軷9,ꨔem)J^ᒭ~}Qeǚ:0z7bư Q/m6wFE4DDu3tFt63KYMd8c猫a[1+b-;"gA.C_t-4bFWLډLc QO NcU~~~,'z<; ǰ KƨMm\ xoB3O!B:!Ï&I5=TiMڤ5:AYj N"}b F`$ nx (<۩o %*vR>I|LS#h?OH^ jx*)!ʏ FH w<M!)B<N7DcSеuì40K 0GDP`R aT_S,G.wPK,>I PK@+proguard/obfuscate/SpecialNameFactory.classS]Sa~^@E 3ʏC%MLI"ei^qe~HӍ7]TS8L]9yҔbϻ9yyϷCRFn(id8JD]b\ 0)Ĕn ,tڍqaV(dcA¢[ mJ4Hb' ,zRuk]-TZucj2]i+J9ZzNi!C`GޑF{C b´#pcrtl`g8ɵ" fw>ZP'C7] ?Y0\&2#a }?Bvh_Aras B$ Ѐ*JP6!m>k۠;CUu jUton kFt.!y~PKō#PK@)proguard/obfuscate/MemberObfuscator.classVSU$da@KbWjJ--j-&,]vM 񩎣3;0>8bg}3>g7nv 9{=o"(p r1a\je1҈8/W*F! c ńxH0%2>KōnbF[>0+aNmHfeT[Iu3(i]mn3Ru|0R,Zܶ pK7ռfy6Za86QbY)3[(9mAb >Y^r놚IRl1V2\H.Ķs"ウ᠟^jqx`PCuod>>CXPm?#{ǩ=v Oe+G5QA T Tp AL.CPNw@<6 r+((Hᬂw𮄢aQ=acI9+0`R2/aj/LBI}DIsBZ54) HӖ((Wc8 qL4C.lc>C2 Ew1Trgow~Yit^POeyΩMa_Z tfT^X:fhY۫Sg,ޛVwh LQ5,wW'"(kOeg~rg`i9@JH.KvΌ} j_Mۖ FܥR3|+%7(EmbkзM, .>: !XkDrD:B?!I D/0p -!m/}kHV"E&{O!AmkUB_XC{4şB?EĕM( M48O`- VR4DU `so7Ѷ0Z8It:U&EPK$Z)shN"'3Lb>. xA=}.PK4mPK@#proguard/obfuscate/NameMarker.classWmSU~6n@)Q@ZjiyJjxDj$7t!즛 |gǏpq3?Qgn6!, T'79=?`_KcTeIx5<0.`[Txh 3xd>¬9̇E b)e,6F\"cX&ⱈO4j NY&9jlfƲΓҶZTC_7ɼR, 艤 d()F6L95> MiC1v}>UPqZeӣ8pZ=̧:O'r}ٴCrǔOhiNRN{{JpI85Ν4fpIXdxcZN_bY\U'­V40s8/n2V9eRCSJ֚,&:l{礪,iI/6Z ٢UMf l(ۊx]m#3㉌;qD|!CAZDFFLFLĺPel`SD^4: "0Pa(a[siGĮ=|)+c:\z:W*f::}*j>njNeuݶsu=#>jߊ,wqcgV W< hq5'2VweijN#7mkZ{)b]+JZܮI̬j H/ev'(>*@$7rӡFWib>2Խ(Yr#INxBDz-, eX=}!<ww~Z\UNԱ[ҹD ~mjaR=,IWm7='o?ޤl6\E;ѵA}fY} 7xnI$k hXu@hXÐ0Bַ`V0't&.M/<$u3dy7<Y̑EX"2Yxakd!k G ogC-/#P, t^O[!8GO8X!.;$}ȱp0z+@QGJI۴z UGfj! -FjA;%E8jE}OJ#y] `#[_㓦t~B#~*_iel PK=5PK@#proguard/obfuscate/MapCleaner.classmQMK@}ƤU^RTTzߦ[YIW"zZvvͼ7/m(aÁZزmc.91C$& /VTkZ_g:Pj }>A B*&|"M8s $tZ(O|y4J@P&m=Ӄ6`2,xnQ9'!b/PKDPK@.proguard/obfuscate/MultiMappingProcessor.classn@c'1HCv"EDT $RiP9 8gy.\ P8xN<0B9 K33xvz`,$\ k9bSu Vϭ}k ;/[CG߫xWQеBҞ9ǐ~ `Iz6rO?:.Eֆ5\+)uf*5WB{FScK ՠדm;|M)l#/OЎЙn,Tö `ykXg<ʴΙ n.p n=9 ^C>n#u +3Ț_g>Ҏa:) ҚHtPj\'.ޡP*!x[q׏KDWWCPЛt&MPU/{ }Ocp#1fOSS@ESF`he&r-MrYԸ&jiMC1 }~L>yRFX PK+PK@,proguard/obfuscate/ParameterNameMarker.class͕KSPMS4RQjAGgԅDCIR]KBG7n8~~ЈS88ν|+$~8A aGDLEta@Q$=RqlyliN*R0`mja3 競Uq*q SKS p-;Y]c=0Y)kCgިBA7xZpROܤnt_}U, `o^ijJV/$]AW[xBXe/*ew[mʜE*ٞZK;.kY n=k\Yi4z;zz ok1L*Jβp'Sj=$g,eWrjlVDY;FVvƥŲ觿[T2}d%Sa-< PGyͲ!ja׍e&j.}B!= tiDQEW@dyD~&3]ybo~ץ^y r]EGu36XH8|3Dq9:sjuznnUpn kqVܻ{p ["2[ \pmui#, $KH|"|fGmPKn PK@,proguard/obfuscate/NameFactoryResetter.classKO@RPhЅn| +F iȐBʹL4FЅAt:|w~~a@+Iıul(dH @4j°|TnoUtȳ/qɰp%ҿf8(e>n3nG0dr(Z%RrcI:(>;#-@JGQOs6E5ݑEC w/T<$iXԱ6 AÞyc3-0[{Z0Ag1$Tpi Lqi1'aКU/ОbHӺLGRHr%Ngho18#sJ)d͜sAJPK:aPK@+proguard/obfuscate/NumericNameFactory.classmPMO@}R (A#@Ƌ DOnڔ@kF2NшQfe̛yx}ĖydbUUk FńGac8gȜ}P脑&#O3 1 ŐDur[y=%(8dzq"} SY}˻feDĺ l28H컱w}_P ='W;5)I4Cޞ vzH,]V.o"h8`0؄)Y#\)ݣ)u'hZxAbP? #%^)j(}PKDIPK@&proguard/obfuscate/MappingReader.classVsUf7l4e TEBE%@ E)Tq@6$ L^$`GyCg|q|տg;٤q2wN~ :UЍ6.I~䬑˛$A6 2 Gupa"ѵoZ ۀh$?Z( ?p-UQ=>x28({KǺ!hߣ{R0 3%Ӆ2.zeB֑ҭ?C7nUeWM l+aH Fx<e, t)ciˮGD+@u<=0Iz*VxչF'It=y}X6vf!cgrD0]1' eߠ Gipt.dc^;%x$,huM Ij=lKt. ˋ==AM s+t%N46,v~[[M|i)Q RB+)4An&ZPAO[zܣIRztͮW+afYs\0D!km)AIY539xU\Pu՗pRwVyZW|Z/#ݩװFD {lV[إ6h*ֆ[Mlh\AYkEBUsUӵɘ|L)>|N<@+!(KHSwW ~pH7 ?Nܠ (w PK _H PK@#proguard/obfuscate/Obfuscator.classX |[uK'v^N"HBBĎBB; vµtm)u8 @ecBC(k}1J@Iv[=mڝޫ+پVLYw=s>/V$4$6U(^S g4s I9( |^< |_%_8`.M/ |I .%\`1&p^xK7~S V5Q7-$]{V}?C]= #I}?VgSY._)AUȯ;Q>ߖ?/rW{o?Rp@wPp? [O~`@%T@#T EAB jPaO K RcfA4Wq|GAh; jQp'-@B ^$(6.Qp/]*hA)TPD22PoZkB >̹C+|hEZMk j#4&Pz`fZ }ɎjBt6mn#\hAKOjtVSԌ`!B;% &]W% QtFot=6V*Q?rRg Kw9ў#q#wHLٯf4*2imuк]IC故uuB$"Dzh,jQM˭M!݈)-;ɛZ]jHX| wڕԬf*Dmk5:3^M .LGf$fHb릩XfMjMc:Qi]K[C#\@5M#=)ڣgəcea].с:h'DyF*])E.尞tܧyQRuvg2 nf>X!mhIޒweWnQtpu/pYZA~` &QOVV˛T#cBSfUwn!{%D Vs9Ԥ=]!c}i}0\l{/D7Q_i?aUW2jv^>5&kEFtP.Q.CCZ>f{dĊOTf3DK2ب:fh@V?Y)aʢǸZF&2-6z6b.""oٵ=$#*x1ScdճH`xv\%a`cBhLR몵nh{:1Dž2չL̶y}^9#TcJp5`LF&.`a0]eQi0D $r4SПej4$ͱJ|3Ueh ˌa[e92IӵuBݺ˥b75C5Ԍ<kkcߙ'RwCb9Te2R{Ö]Up+IyLjNOl7;ݙ>aΨ3R]"Yf)MM"l`7լY݉{~^S9CFyѝe7^:y&>=a8ۍt3kưYhޒ !IqAw}zJ$̮t㽃G|QyX}RWcfIJBs2Q]|s_Zyg!y^ %=\kcBU _x>ښ&1,y+~V}JۗΩjSs7fޜfnꋊ2K^zU.jN阘'KH5sL2áYZ%0bwB_dUϙC޲b~^ [{tL~B6=˧-==''~J|zxK}Lέ 'WYϔyX3]z!kny~MZEjjǃ-7ؠ3E1*mCd8$Gw.R;(x9jsʵ8kӈ\_/*VIege8MucNK]64GәYvՓn%&4dPLSv12 ڢ{{s>파&; co V)jEfCu%WGuQn-Eg.<7ymX:a牞зOqL gt紇9-O/pX]:%L.j&'zFB}"6Z3LߓFoKO 4%cAVnYpO5S{S-;l '$N5iW|x8fU^m)/1^BÛ}sJSӺVrʥy ;-p89VYźe.bpK/@Y(a1ceLDzpcwVXvL<滙ⱐaZpo xVHm6, 2p\j\1M`"Vp}5뫩" mǃmtS9~ot򙩈vt[P‘"kr⒙:b6vgj4JzV6>S<, ϒť٣4⒛P\M).FRZD./d w<"F8QY^;a]x_x6>`7cao'K}E| Iwsylv*)3L``3,gC!>\/K6BvGv<%qvham a;mx 0>8;q6<A') mT5c^ڊhHw-g(YL PK%PK@*proguard/obfuscate/ClassObfuscator$1.class;o>=vvv.FҢT̜TFbĒ"IJDFʼԒdvnFĢ|T}4* L rШbTvL "o}&R% HĜ&?3°QvP Od~\H٩ L0ɫQKI}ME?m"M<6bi']k5چbZi JkmY#pxħ$t=>sI|^AIE/H%I^Re/WT|Uū**⢊ TqIŷT\VmQ]kI|/+}vDQՇPvEgT~p&?( 6Fs5 :dC֨b{- 'U("ܯ@\H,3X@зOF]$We[вݠ1˵jzLAIo4KRT)VAc* hyqĖATۺ;rLGpLJZCq(B `/|x,/FBs+ꦖ2 ?Ĥ [*Gٶ,":~$X.? ]N~k(N$qUhE_0#@ȥ&#F[#Fpo9Fwy 79׋$ 3B/Kwyp[YL1 B/eƈ V1rlw=_Ĕr& SVPca989 ߵB{T8Yc-d524ذ\CTreXxKIh!#}J7B{|h-Nw5*X<|*Kğ@jyOßqS_WI("7\8"et 6y@x1Bs咢qvQ<y rE',_/MњzG۠t\EjDǯԕUEY+"+JCϊl 6d(ja. `WP- w⮍~\k<5n^^Զ1q}ͷH7noӭpߢv6.UZYrQ^`?-}i n‹Hհu Y~ ղˤeW#X5׷+)ꥭ҆脼y)vsD}AYBC}U*V̇<ƗjEx^Z ZA iK*+b+yuD˔4W],9*L5\Ur4Zvȟ ENFG9 " s7oKs|Πw c3&Am/%3A^m kvO4^q0; 6Jh A#%ݢo.aK3V.%:wo+ 60vѡ4 {هa^q/"܇gp?_pMe_K>9|[5gE$fKxVg)xg}zw>py:kb =LWIT\:x}>#XC370+hA34q7> U(8t#DNȄ(üjhDFE$Up͝f4rmBas 4FM jN݌_}`%=3 lZ-r:kWjхL7LuWY[,s[C[%`\3#eNJ #QnbF!ݙCѬo2ճTf_RcujUQW,G֘ꮑu^\U])eVB Mrr&Ӌ̑q+۸#a!h4O+Ԃ5FgЂhѶ2PZ}Peo# EЀI7B 9c,IClWTPK 1+WPKX}:proguard/wtk/default.proWo0~_a?`i+ &V؀ă\Sol']sNuIFöw}FH4c0ä/P)0a@h Y |Me K4G4)Ĝj ESʹML&lbZ9^O9ywQMВ-?2bYL*gUm$ѣgbJmechEafAUM>qF|$NBTauUW[m #OuYYV+Ff-5P* [АDTQd e:bsYb8;6)R$.aY 9ӓ'a畃#U}1Gsdory; <P T`)5-Pg_Als٭܁l~|w!wKj'&uL/~c {}c5US<8+0)_2~Yv ğ[tܥ#Y '+0 @7BIm `!a.(^ cږ^#IlW;b"ښ<\ǀq }n$!e-qC R;g 5.w0Y`Cs|rzaE`JtL眅KXo!]+XF^ 5ݿy.OoWoyf UX6?y|Ԙrlpس41>;n':_PKc0PK@%proguard/wtk/ProGuardObfuscator.classV[oU^{I:IZkN)m$88vȭ85{IRJ) ^"xB+";? IyDd|g߿ G2zpIBZa% ޖqd͐!ఄmF%#!#c2:.Ɇ1ΣsaeL=0%ᔳnJx_)dtc,9|(# %1E 56A2Wx `L:\Yᡂ/]t]L [2j8[Ք㙩%VM1sɰ-L730\f/%ڠ}B&w3-;wMLfw7uqTP%5f#֣[{QImPtOb7_k`.x"ۺ|Tbm;7F`[{mb{s J%jD b{6T̞:{u6+Si㚫/p%\fh&O6nҐ0?u= ){.+Q$Ǚhez8hQ2-4N3DBZԔᐈ~N4s 裵^T$yN*k@xJH $ٗ&TO#d_N0 $(䭯@@:WG0CzptD:d5ܧAQ FЮC:: ,b@8|/6=3tؑ@T O ֠XAeUH.p ~jS**YLݨ:QD0Fxg@|~mD0<2XF4R4@4:G5rJPKPK@3proguard/optimize/evaluation/LivenessAnalyzer.classW}l|;B)\hP+bAQ+XQO\TZuЉn(: e,[Fe[3Mp:,Y2dY6skW[ 1޾/}=|' t/-^zD{mB !{s oL=HCȽ–d)d_]떹xz-Bz|[V!#^&ߑz('xO y~BuXG<9YF\ߔio֓[T\"J6R[ZDp%"l3Szz\Cd +>Tmdv2ҡxW(N͙46aĴTň]7ي )1G/QF=ݖNcw QLDp7ȁ2^a"ݦ% qp{p';_;ؓɆCWxjqxLF8pZ%ZWڤ( H3O?XuyJҍ|׼*9y kd*HtzyڵY-L2lHeaZ[O.߫ujKʜ*q[T܀UNԩa`;YTbJ!lP"إ%@2lU{>WpBkx]AxC&4CW NxSLpZT-3gjiRaXN{OP9dF,h-&!)s-䮟&(y~6(c .i6DDqx4'xmlf+/=`m;,3mS5ۓF+KqRгg"K}o+MŭXKe-_v1~>.L֭Hޚ2wpmoUͥWSα٨nF1#ϟtph9?31 e]MGczn+d2-}%Sǣ[qN(6&.'2 –wkx2Kʊˈ7Ev5q-Vu`C-WazI7\vծZfɟ[ra Dܪ@ۇarccZ&?Ka8A8WΩF8|oK.-$R_f.Ԙ .\,k|BC 9KҮg{8OT1Jf)6`*(_k))Zz1'7 Cr{*f@:GWN5L7N5k*' (<ƫ`1+S2MTTxbY8ȫ3`˔:lJG;{ -\fEYB#m\Ls7:_71 [X? q6ZLi)P=A<˼Dn:N[lsH$Iۙމm[7qHwLJcZCXkR".ҏ+%Yr z^,xB14̥(JzJyp|!\ {XٜfG1=ȳ۱Rr{1%Ubq *Ҕ׺}Jtu{<bFxΞuǗ݇#Cb>=2z)B`7>:wG9WI Wq^QL_ڇ@h+-bfc}^RxLt!;C4m9Jkp|1'7bNF5Jzu4 <ʇkuIPu%[Ip3ϧS r5`M@-_cYXķ+*F`BRߙܚŽGw9QզWj]> 7.pGy̢O>tcIQ.FDܗo*a_c#̲9PfsjWT掘/PK PK@7proguard/optimize/evaluation/EvaluationSimplifier.classZ xTu{yIhlZ=1BH#fFOhF̌ؼ}w7`nPIvqm&m4N&iLyh$ b}s]=Ͻ'*U M[.\75|Å4 V)ޕ- t; 7d^:^O?dX]'ȅO\ƿ_c1'74&p?svdY|K)[_I@+~#[)>hXŵ?ߟg jeEH%)&}. 43]S0gk4LiFBGt)[8dBL-`PFIh1V\TL]tM`i L.B%.*2(U5>rkTB4ZQ;M]4f QTOH^q.W7] t*.F=@+4&i ں*_FjY5xBN7{[YX'0wwU5, B"E,l7| 83@5T44;j1DaƮQh^9XpgԒҕp5ƒFٻ1=%'@^ n/HL-I%tasgJuԪSv)hDC-O{`yfo3`$B[UwdHiJo/S%?EN9SfmHur2,n揞V2˲:lt>^ouVW@EclEuf);RV'FBAFۃ!oth=Z4hx=h5F7cA _զq}#`>P _EH ƴ#N۔;;>b|!CS}uVI 8TB|W&4I/kNvӸyG\ϸB]aid/Lż~#\ɻK8Fn-E7aƟTq;H|"ɚ;q[q~DUlZd+>S4jtN H[4w=FKYYqb?V{5v[G%:-e|#)nb;m]2Ë;ֿykt:kԤS3<~N+œaPUtɐ&ΰZ5Vu+."Sf)C$-WB<#~䥍:E'Z5jө:m:CSxR3R<+sR<y:>-O2ELXzxBBԩE;:EX^:EK:mi']%tN.. i\IWitNp/`?aPbP }wH^K~N2nt«:,~|t ݪE6];ĉ;uvt7hN}:%k=>~Huzqa&/ESFO3+sD7_oܠ^#E:A:D:ıpX0yz e'~PʌCӇ X8(KC) Z4 <4-R1 N@Wpۑ%F sӣ!η13aBWpJYƈN$nwfp`gva)F$m3R1su|h0mvFĈ[?洣Yg~PT'qw"kUŧ+~)@c4Z &r$1%ɫtZfI0S0,YrcJQe~<$_ް  utvEMvoyGaZ +RmL!^jEbNib~3ibM+8M#ke(wYC]s8iq%#Z#.$miky9 6C  {9f 9ye专Nvs/FW~D7̧JD | O::t_(Heޮ@4䤿eY7XvQR-֗Tg%ukNN \ Wjh%/)?ELzn&+zMʯ{XݍíR\VB^/ǺKBG9۞]SzipUj/2UV~eSB8 N.`kd43^k+((NU\f Jc|jE Y=؏a91 gzԈܑ1_F؝E Y s*R`F+.BG cb+Lv4'= Oʖ7em^?##lt@ AlghLW@8mORg܎Q.,&w^BYyJNTSTYel8\X9NHX{-y +L>>-%iP9Աѣseׇot]l)a'GO?%ǟ|Á~|U픴(LL+z01^AA^=^w.U"G#c ^sێR3CǙc~%z[g{N$g鳜B?lbSOpnyLs3-fZҺhyY|mZd16kgbi 6hI6lbڴ̶ܦSmZaSS^w>-`F.jvbF9}=ךnӒmvҺٷn|a?|NqƒJIMiy(j)4i2)O,ӷ;NԠ-43h Z̧XL&,M&|N\jGm:0B%>'m, )I =ɎvB5fL0y[Q/xUgEUbUcGZ5>%\V- Y%ȦK9n_t5hkyUtVMh[`JxPŀ!m/jcX[d@jL#2'?mO#O~I+YN3'g{NNsᲷzyyhhи*'Ps;cXҋ1, az/A\ ORS5I':Z M14wjn+zqSz{{ŴtsUױބ` ]\C]01Ϝg 'dGr28^(te v93+k/rM3כHޘds-eC ;sJrJsr_wU1>әܽΗf?>N}7#G<3yxGgץ6S >?}~<TŃle(V9J * X,\kUUYne-W.b`Weqy@5- j99x;h?H jЋbXg/0+\'gv!pXF)w`۔Ky7(p^Wz.WcO`]X_ 8 |WX!~㔷X oKXiFo櫫%4Q>YA9G(Tr^L%ՖCr>a9?f9rA[#6#ܿ|g庩#̮o!؇,2;M<*^{#Cf.yS+DwTQ4zz $+mCݘdWِ\jۑ) 7;fa:jKMȾԆΖE*^pQ|'"A!DW-vŰ5%!ՎKJXfS^˶)o)rEMhM WbGSg BG_镌Ȓ;miyu3ѐh`-1APOC]E䎌܊܆q.r;K 9>ܠO>F 1tфkAlG'HQ&&x]8 WW0`P~'e亢m-5;1V^y1,32QVgSa^!tH0аa)u# xǬ.4m|fA/h ii)91Wfα )pc.]1zd,Zѝ9m,vg #ⵌ B#-252ٴ~ٵ]@V"96eGz}Al 15uk f&R.@h1eP㦩cO ,֟:tŊ7vB4d%Wmַ4hͰѬ*F0b &TLbJK+8eL+QqqқY9o[|Bg4'BS=5<i7+a6Sp ot/%z.5;' mޒ_)+(~gh('Q?J<4_ ٤|>O UsOiXT}ɃԨ|ygtߙ&.7!fܷ@Lr<"wAL=hh/@cxmv&sP<<׍Z]7m݁KC\P_Yqo[ȒhQ*gfgŶ.x4~OpQzCt :.XydH2-%pX'7i·dGZ/tSdO/zKGQ^tPAE0)Zg]qo"A1'T)K-#D VXrܰ=A"H>+p<^BHț05F\G AW:qJ O"۟~P]6Ѹ /JqQg[ g?G&`o.DuBL8\lȗeLdyI?PKn3ť1 PK@5proguard/optimize/evaluation/EvaluationShrinker.class; xT̼73y$0El$H@( )!@@ CHF'3qfPZ7bEkMZ*;]Zk}m.?7L /s9{} ixlঙn4n6rM7^nN n|ܴs&M7gr&M9wrog9`,nffۢs8W2p8`\E[ ^|NmK=Ƚ<ѣ,1_/f878C5+|ͧϸ\/R+ ~\BZaLMW}|€? 5sbf-0k'li~oyxހ<Rkꂁf-ʪjw:OӮ`ٔEU KW7,]Qkh=JSKME:Z"BrCm}C]ݲ+zu!!vYu%_MËp#Lݦ @m-$"(7EA1{a֯Z 86e+UC!Ƞ[. jI)}rUSUCDÚ Ղjf*eLfZGkHWd-IV5Xd$dGJ5 5+mq5Bi54 kx8Y7lմհ(FAR&F:xms8Y(zZ)6u+!o8@Q4giG0 6soBo?b&p0l~AKK| z& G*{۽[BMfiu1$##AΐEڸQk/lӚ)#(ev&s5Ck_ַ~7e-LFtlʣ00mW6 iBP$:C^Q@Iƨ@ z7tol<ǯ&& & >c" jZ( v-fm֮6Zed>u_K1hO 1J-6n iaJV'xɆHZXI[k ac@kH ]Qc#TcJ-qy"Q&w=-d^-;@=j"w;3"{~knu5S3{قz@z Lg"M\ObՇIXД怟&"vdʴјD(Bׁɀb9WPeTAOKo zm\ʭi0X͊2iZ0\j3ײF`8:hnYGniu*1(3u_};%6YNhwgKROUH[1͔Zs<!LL4e>FM3'WpDl5C| {FǼZ.48refbRƊNgf=8k eDx1=RXk ELC&'kl1N(>'8<<4efH\ōc5.M֯^aMv5Xˇ/QO.Uƚ3ʬYЀf6P\PQ0gCK%Go5&6oj"9sˎڠfx?}Qf K\K8D8t㉡jcGxW^K"y#*6r"p`׼1fQG VTű(LUU=J*3XM9R*N)*N17y '*o[*F'B r o[GBށwNW/)pⱾ|P|[z"Q/Wd7LϹ/*AX,y;VY`}Ưi ~msWkqi` :ĺBBc8O$.r.iտ 7TV[:)~KscKgk$P$T%IJBudaGS$"!MCֹrUI}>BmU:E.PJi="v^TŪD:I&ɒ[N!cTNSٓLgOtf@GΰW?>֗ YcEh7H<KrDjJ(]4iSBp.3@a)hv~m3t0`r.QB- yMTV-\K}&f o ^~eN|O E$d 3D5UjL޸K5k 7"ihyOZ[i&ŞfZ ?4YTq ]̹a3CZp`UyH 9`"R ƈ6O#^`űו]:zQ>˂V/?gxCʣ~2,Lkxl?5Qfrn<c<魼7sXn"k[)O|hHJjC2#p}iq03\Z4\x*, PAL4Al!jZB7Md  %xȺ@DPZCL+p=eqS%.+έ^;HNiM-fqR<|݁afΒv楴+}|0~~gA0y qvMuIlQ7a *a"\ -C Fx»&Gi{MO5?%35| 9ML^0 G&G ~,f'~?E&M3?k#&ߘ / ~M~%f}4 c-o[}}>ߏcK~ tύƗ.KM.$_B=}0q/d"kؿu@RS}m} VŽ"{ 90~LM&IL=pS0m0]=G@~c^(wRO|fH{P:PdxزJy{ ÝD^ڿJH{pȅ P4@ mo'xB8.nKOc,>?\~U@{ZÝ_3{ P>>MVH'=tyNB.3V3zi6P)WEThudA[x)tT` n$`d@>)yV|VJį] [-o6#X{]nq{`g0$ςVC^ # qRWX8ʭ$[TwS I_xJ`} '!zZT$ ZAeT +iLbiԙmlsVTOYiVk5:dY߀|[$d:dIk; M0ub ȱ~%x /CE`eH0NVa.SIS(8&FUΦ},cy !.ȑ'$y1NF`p6N:_i!Iǔ\FrHa@9BLqʥrpȳ`\\piQa͕kHa)VSrDKڴ l<䵐!#`r,tZ)F&޼*,٬?,87L m:RJnU(9cN"o9P&DB] .nlȺʃ j i7鯐JOM&-RlVȽD p|9W[ {5@|u4*b6.v u(uUlUQ@B`Lkb9V_c#*KCZ/ξOײ2fZItYTyϴ%<ٔd ~G)p I QhȓBNP#u&? >q蒟p,tÝp2<,OY5:* o{G(̔?8C bOGĹF oL}j …}pQHob6t%4bciSO=Dv =Tm IgL% RɐL!^c1UD66kƝ*:MbKR{RHPޑ0t:ff6Qy6VJ ޭILENUT[|(IR0~>s"S? kR8>$ RfP6KiIU|$$NJ<͐&"Ǒh1$M#y%y$bwɻdpPV9}L_:QsIWj$Bq `!g0Z\*NhGrIb|{؀:9TELD?}`8%i2ŝ-|PR6 PnM0EPK[nP.^WelJ*A8H_)' |F{6d'ҨUĐL%*JX#ڏ>tbiiĖXf45.27♥*{wl&@}.S}+Y|NQŒľlx<&|t͝]ľ`.f` fƽ <`wED3xb|F'YhG,LZzbEXe7-S,N $51<).ބ$xA28Dy:"1)דXXBM,6r,K@HLRK.34 4Sk"9\9y{X*\gcZoF\ )1Z<5:ZKDh$u eͧE rX񴟝5Lqd q'ωȤeܽc/oefffDVƋFg0PG)pPK>HGLPK@3proguard/optimize/evaluation/TracedBranchUnit.classQJA=mږB=DFB I/Y=SM 3sOB}@Ѳsg瞙WUS#`IAFA6\ #!Zܹb5<[0[a#68u|Zw ϵe =;Cm}۴HG Nx!]l*ԅ8Jhv}{IMVH y:Vd؝iy@vPbV߅f:K'+>po6˹~4 5"4VV=ӂކ0>InO5eUŞ.+#6FduC<"3T0]pmrBh"=䱏mCb,LZPK 50bIPK@8proguard/optimize/evaluation/StoringInvocationUnit.classV[oE=\psД&C[nMIIIq6I Mi8:ȗHDB/ @5y( qf^M/wffoFaxщ^tႇqa. 3%L1%\-7E{EUa&"̬0s^\uan3/̂0nt㖄t&Ҧu-&ZZ$2u5i-_Y29e)#?p^7̸z*ϪXXଚѓFXzZña1MBKD7ڲZTu $|i-c3Pis_Z+67fI#QLx^[c5pҌf5uX"s'MaƑ%! kRVWlyeG&l tBjy|&=eiM|gMs.$(sC>݈ɨ&kuCUЇaѭG^tp[BWP(;UU85ƒ;x_]S+P BW$bNГ}QmtNҤ֣W.i|S ?)1sV*׍dnL%3^_Ug7ءX(-B%!T%R*@CG*g-E= $o$q&e)TerZ8N( B&䐳*Ph^%<?zԉ:^(fk͐D}_' Ȳ g~HxkNF2`sŶ#0@6}ې6\Es8.hde 7[ >A9/@pXsh/7"cDO9"%="'b/ᔅ8l`ODy ~wڇ/X9Cb :w/K! [!6ӵ e)EfRc( nm i6x@4}&T<`_ 30VODFeg_ϗ&yk9Wtߐ[/3j?gG1g{<Od}̔Yj!-mA?q;]&v_!r}:N?l6wؑ?%_9g۱PK>NPK@Fproguard/optimize/evaluation/PartialEvaluator$MyInstructionBlock.classTMo@}8q운@ iIRpLUZmvH$J|]hDaf޼{f}}<&r(+3 M *f b0<틘afu? Su\~F= 8S?[ B1FV,d-@&UOWfmA_;a|Uqц2n}Ǫ%}'Oto¨P ,y"+ ŵf'Q)?T_YVG9Q;dsGe#EwiRY0W:~Α' Srr^#r(2 '\%q{1Z^$"ʑPK8vL WPK@Tproguard/optimize/evaluation/EvaluationShrinker$MyVariableInitializationMarker.classUmOA~r_BX0N p=dZ1]!mCh3A/6wd$6bԀL!Vv }a͆#+RѩbL7tLcS:1cs kQG´D3./dT?eֶ%6Ud{8`G ֊-D2ClD?X o1ka _2%Z垗)'晉j$J3)ӼWg,)s-%ːO<d_%k,;˿C-IPIv1?'${{ {F*>oPO!1!I"iGǎ&]GCtdEBi ƕoU'D]~mtL23?^.F}w:TPK8^ƔPK@3proguard/optimize/evaluation/PartialEvaluator.classZ |T{/y6$!AC jIB!Ha vn!ړZkkW-h+P5% xgzԻZ{o6Vgwof~3G>߳D\'@D:).4R\HT.)% M! ]@ ~  )[: - GPxtH" <4F:E(va,FK{L*8Q10A]TB\4Y0J]88X'Ge. *Pi($LP!R@0Kl5Ni 4WU+ 0_N@P4X(؅F:UDm)HoN2(-r'WK+]Dz>2lqj{L)[FzMzgx!'ㅥ.CҮ^ .Mg6qҹ oI#69{:y}w|"]#PDY>lNb^"R.:] 5/T }aBv톚@=*[MgRfTW.E% y[;|*?I7/_80Ԛڅ˫U]XPS7oyUy LF֤yu|NȬhX^[0ny e!*f[,Za: m m [:U%>KLEqӘ?6d", 9e}UU>ʐ7д.oL.)K!JB뚛>KuӢ{Ieޕp9bcoy|Ei:3CTQL]Es/DHأ->vol*|o};˨,eOYX5ʪ73qY[tLR*aSe-Q?3U"QIlqaJ|V_IeL&$:B3k%֒V丩'YjEÖKd|:֬Dv́UZdqk{C~ok5 ME]_ڧE"=_:Kīf?SuӒ}FDMb8⫎x}upa=/I?lJ55pify-W'z,m 2cUx.'~.fM |VVYb"/Qj9|HxpG/Ttc0l3&B=@ގdZ=; w 0.h^Ӡ_^}Mt/GO3C&_8< A==|@Ac=NO{i.kг(w9pfsP.((L,A/oIG/?uA?zb=ouq@c9زK|H$i-*I̭Ͱ@^tA3 ޔ[27zs4YIسZ8'à¸$hMUy2]zϠtР?S nc>!OEӏgyXAÿd)#!WD]wkKM7JR55ؓ9 ZU?Ȗ75"=xɨ¹dmk t|2>SVd~+4)'y\pRؗu>V%|Q$+7pSf)Nu+ptQA™")6eV-J5sh [W|iȳI**\4ql;hi_-i816~Y#gl xO {?Sߚ |rڂmEr ѓ'M"$ANq0}Ō#.Sid*K+ %%'Wy>jm:v/37n`\ȓ@_~ļ258Uoh\.=&~dEJ\50T!Ŝ\2Y$%`3V;|,+~7;Xta8X@U/6N؅=Z AyyJфL=xOP<Ս)Oʘ'10}3s 'N夠RPJT4zODυb OIy; 1} R7y(1 UAjd,dq(1&7ɉg#r' -imZQ",3|*~gWneǶU[a2f_Ds>/D3|_Y1|>; /^~-Y܊_;,';9Kɱ$barMDFi>,'))rn_dޟ9EU$E.WZdw_5)rNdE可 y0^6rT5u򌒅tuaVb8\ŒCbD$S{0_TރSb$2$+L0&&sb<"Q7귢5Cmn軱P"+3)sU=*q'(^fn3ጳcz/1sJ e`IÝZr;w@w;$'p;'Ӷ^|,}ckKp{=)=8Ӳ,ycԓҍӹvj 838ˌ8enc+bv*Ϲ1ΣkU^܋,克cӬ`ⴉڊ^ it;{-7XF7VzRi =guyEY$S$";=b~ 'n+ϒ|WϔllJoJHY}w]n֔g@Ytޖ{Đsw#΋K'1⸏X( tx:mEnU.1Vˆw`'=2 MR-R2 Imi!wv5&Eil,19laCLT.Dr1)`Sle+(Wa Sfz\܀)w><܏W>R"Uy2gɭ-SA+Jc:C.TMʧb(LUU2RՕBu2AW,uD4cu]uY-U)w}ʃjZ^V.RQsyj@=*tUڦQjP=eZgFu};6qsq;U; 2G/5b}*F^K"Ӯ7p)H ^z)rQnGz53Z R+Z^,>R4 '_:S=ad[3Ώ#rL 9Q 9Q 93ibbZYFQ9ʵGy(#S)#ZiaWiT@:ךɍCʳbHL6u4|_ 'éގj*=މ^lRŏqWn!<>#xU}OK-OR4MWwL96SrAۋݚ;]dcyj:2a9=g끷22X1RcO?/+Vd<.|,EoS'̷ti#.8=.u4ӓ&%MIep ۱nؤ%2%{̹<7gg9IÓƹb}bY3͝۝aa_+XC1u`.1?)Rth2p -sX AAVh\Zmjym>Xk_˞a/9D|;Qg?y@4g? y֣@$ЉnH櫻q-+ޞpa!v',Efsq"yQ\N-fyU؈m FhK1F; e(NIrTk+PXkrUA ZM-igZء z6n\<8o2?m+xKz[R܁4HE2!s@GލK69x{oƶW$Yf .]bJjWm;j_wlǩ5,|eD#W"ⷴ,5Lwl"nb3\lE2lZ fqet-NZZ˲tdrˬ5ƞp|11oD*L(mk/&h0E{wL3'`ygbeiC{ :s{l)&ZnPKNL8PK@4proguard/optimize/evaluation/VariableOptimizer.classWklWn1~4IcMi%IqۛII'ޱ3aΚ8mCC)u@\ GҢ"DAP $$@ 7>UTǹ{_Khd x$d.~) INIbJrZʿKDI$yw~ْd!I#$. K͔=Gx q}(ɇ$yR|X|D > xZZDvTg ֮]m\&{Iݧ̴@qƶnɸa 46%lOYɁnB}q=7Fh( ݴv@i2F:IC3ɔmg1Dm&9RPacPO@1CtjjX7TP Ŕ/w)Ūi'魍iN Zj7Bh]~Ĥ5+ضeTZ~΅8z^4TP.stKVðO%co`&dG ,$|$K]æ|NccBǗ%R%&o±b~œ.yE,KZRɳFDayA5mmmxNKx*.*+ TC :\5r.EI &V)[ fI̊E2/ ["K$s-F2SKm뉁P'xٰ؞h̄mXL,Cb EAWlcۍĀ} ;:&93^=+ⷠm=>[K% ߒNv;-JLČ3|dCLS<=V^f:"){e-jn>ocL7$l"$% (srr>3m}FL>k.M|6ø0ގ2Y/iYKY紬}l)ۂV}IK**1 qy' 8ӭ|s ) _ۃX|ង]/$| L(Xl`$(pӡtl MrW@r,^qR2aPag_6Lcup)6:X|.!@f(8:n[aZKZV\a+w G($\ADh?PLc(s;a8#1~?鋚o \铫P!JJ~:ٹ* 9pf ~x`2 #MdßA<qב',xqxy7Ŝ'0=o2;UY~-{MH%2g:qh1̕>e~q8'$? 5WΆGJPjưп3㍅}ﲴy'ofix ~w؄1?V̟_s;]ܸ ڔ9jˊ@m΂2 GA^'ƌ\)-w+cN6/#xЄ$/9=QJݮ[sCL(]5FQTsp f6R~@N(<#n riCkaQE$i\ R$G9IEnvO i֒%uk3"?!:lMWlE؆Nzvb;<[O.J U9k` -_j~&Qfx`4Mxن {4O:=vxn,[Ρ+QKGP@#綊>|S/NPKvK\#PK@Mproguard/optimize/evaluation/EvaluationShrinker$MyStackConsistencyFixer.classX{xuݽ;,۲%#lcC5`epD caY^펤W}ؖMI8P& :NJͣ &&PM)IH_sfYK~=3;{Ιz #}>.?걛g1?#$C4dTdU}^>~v#?~1>.)~q'w'~,n w3OxY?(9*8*>ϊTbz<<0C<%Ǽ+mںh&b۶Nn^<k_Fjgmb ("FKr3P$ӳIelQ*xW_3yh[:@'P* 'ttpV]F8C'ꉏ,jZ:~Z4` o+Ss+ɛIGړp.~ kGiWiC/o~uC2 eH݋Gzt0L~1 @mRx^^ u=mG;yeR A8ar!nE,8(i?ii6NBv'U9#9Y9l``]|o3nւEƜW &_` jamG("qP#OoExu ^4&^pR}fPt-4h+fĦç Y@0+(080f.xUO?z~r׿E=\z!:=KI7JE8.K𤜁,"r.ޕU\ ZLU\։+dX(rB+jy WZt<,E\/clV1$Q..1*wgdXC븏Yy ߓOG)oM ޑ )~!OYX _BAYSҟf$m_|G$o.eso|?:5VEW;]t-k9]u]j+T;RWNbɊ$MMMN8;*JqȅJ)(Pcr+:6+3ЮD2 r ~xT{5BF(̓%TPtۂb MN [nb41%&%Dȃ PPle>jБ'xq" N4'ܖ!,ӽC:L/6Cid~Z7m#u,5I:e)?Z(~_X\K4thp& nK89Qxlc ~BUi˶xe Dܝ 8lL1`3E 6E;3%ZY%`0:b^\s̻\BR 3?ie-R6eg7f/ْ7I_~i| àD!u!9!|94^ʡʡNʡC;()vbBbP.m\]R17!Ρ .&^)(oS bJ֘xޖv 8<+K7v;˴uC[V6.﷉ WWTJx.7HnS7Cֶw$3!)ܹ{8ES+ps#X s0 Qa>&m.DžC;0KO )a>-g[{0^a>/~a /<(C98/ p_—`b~DGs?D9n> 'A<ڮ2Lotu}M56+mJlޣGw(CZ}Dٵ6}ǒsL]4jMCSͮh{ܢezJYR90-,0ik S:*RRijJ)ZGqMLNEs5ƴԯAjX1R?.g~ѬRZ C=;RѤ6hj}3ؕ-̈ vOR*8-af'q\Q=n*٢DU@5,35f$#vPq\L%ܳNYx8QC@J?}_Z}uhD)-FKQO?g K[6|de;[h2dѰiQ Mtx80qݕ-BE2ʃQSLv NšXHFUnQKWY+lo-$gc0K|q cX6mT W5UyyN0m02K_ w 0q4R%1-1ߐݵe#v'= =-LJK;v'fuf M7GHjӑI~ؠP-1l1ƢnOX8ޏp+M밞c6rlU̱-jq{*nVq{-uv\ϡ#vуG/tъVLvɑ@N]/8~r `LJqn~LGpT(BKttC%O8~sW*//9~_3S^kT^W!9› z--Z^vQluU zC[6NAO(}ř/oXˬ:T5zE94 y n 9a(hlʚG_jqy ʭ0X PTW8bNoZudkmde>Q);Us= G v0HH.-bWLp (Dd<)DEDt1i֊\wEivxhFxbrNnM"Iz1 W:hwl.kLSԓFz3:ŻkFתЉHGmq\, 0b0ګPG*E`ʧ14JxQT60* EKe䡝ՍکZb7gV%rۍʶSW%bލ۩uDupvωc<͒uvj;Qד>XnTR^=BStKR^ W,ώ ̐1nuŦٱ bn []vl/a2k]|;vaNXG].猝g&ЉcG"0G: C *׋xyӼGٝO{Zf8$m3$!]BM'im=%9:)/PKXg gPK@4proguard/optimize/OptimizationInfoMemberFilter.classKo@uiix<%u.AE.)*'نrJ@P9AVmA;3=׷P,fqCMܚV);4)0?PǠǞY^px(lnQc7d~$?aW&߶~Pr{a1WV&υ`i1.o ـr8n< kY'"5hWka % qIA]A44\ Xah- (U rFsĻ>CebW7Ւcg=OQS_bfjaUY:2*4ntL{ di#G_g>Ҋ"d7PlR!dTOUk(qЄǴ)yiL%xFc% h%K{`& xM7xKޫoPKR|hPK@/proguard/optimize/ConstantParameterFilter.classSKSA&daY%CԼ* UyUofcmvSȁ^\pJ=x稽*Pu%=;.Cn:eôHKƫ*MYciKa"sRrʂcEb-__m,]Q:aQaE?r*84PچXaiN׹nѮ⎎"" EcS:͐mV|Y¸ I_ZƆ,#E)τ\FC")$ljBr=0 /˘'%zLPKmntPK@"proguard/optimize/KeepMarker.classTRA=lQT@I@V"&UpD%I&[m6T/V~efB,vf9==׷!Ë)2e*؉̊;b5煊%,H'>+K0ŎMi#u7uftsu 1w*7Z*GH^=xdh͜V.3ȨieWk9!a*)C3޴rjňs^[,#Z|U$2^x薑umu\krLVṊ'Nj##(msetG-ܖ@C,*. K aYA+ cUšut1Է:yTŒ\Ca7 j>s;sN5VL=VM-ӦY2,5_u7h0~yܴB0o|DEET g핷rTˀ?Rk_) gDO9ě|2MƷH$c u nNU5u7B3#-I1`Shv)T!}K\P )MkD_':JtѝMaHr8!#msrtWm"kr3\gp^s@8o fp3< Cl y.:;x0q^ :{@W}14hv`7PK{#)gPK@!proguard/optimize/Optimizer.classz xTZLrNN&&LCKps F&2'a$ɄɄ*U*%hZj*#^ZkmU֯ڋj̙939?ϓ]{ǟY~b 砚mΓ< x;ew%bHl c7Ov!{$dc/p{%''^ ~ /I5 / Ju /2 I /WHM * fa@keded FI>PM\7x KrķDU7&"~[;DSYjKxL*.[{DW:.Ȱ~r>(C">,d}2lz|Du ^<.bTds !7 eh6?!C ;S">-C&C'/gedede8_e. rdp1X?R|]ğp!d8۽./d)<Kky=op=wl<)p/ G.E Gʻ2_"/]w"^?p/>> 2<ex$qg"_EX^87p;~"-q'\/dx?/^U)+W-]b s3wtPqgdɔr?dn0&E+c"s&8 qXb&⦐3" ]]\al vi{doex؞`gwGsO8qVbFvP3#2QicAJ=jݑFأ4IU[DyAR.L*WO﮿#4U,`O0 *ۥ z:Ǹ8t4H -۪7S$eC4)qP]jXd1Ch,E"NMbd 9 K~6 DZWGˎ[΂;:Cwh^ 7(tN(.iCع" %u$Pav;WQ41MjVJL5' K;i0\- 9F C[QX>yj ŻS*X tat1]5zZÓy.Hl0%xjD4JHYkY/߀QyMmV/uSl2u5wY3UeiiR|Qÿ]--cUk56ECl``u n4zj́4{Qjm_KKDh~5zJo9jxojL;rO@g\ h+kT4z DFyvǾf޹ƙ4+szYO|;mg7C6 9Z)UIol깖ZqG8=r胷Bi GVUM|'\i|q37ODjTqPܛW$N] ' ։Zec٭;;l\KC㪚VSC'&FLoV]oG$hc;G6q5aiT;3}HIӹwqh尾Z#oV_!6 qtQ{ziO8%X1Ma-9FjKOI76&c= ooytC*^> EzKڕPzo~6j:{i۾dn\ēb=G|+Q<])!K77 ҤF4t+̖x ͚~:jOaba]~`=9Ÿ':$ չ)֒Y*eÞ; >bn; "u57ez"|s+d?Xo'\n} DBH*oA4;[zg[Tq|Vׯvw8ǯ^USz<1a;}ήdWq?]-kZv]O%ȓUC{uv7q%v7v3~;;ʾeu4ƈ8oV`u]aߺ߽d<: 5&E}c:C%v˗&ZM~'u!sD(ߤA}`w"8,o#%؉6PҪGʒ?;v<=^}cSj3;;cZS4iuR4{VBiw.~_]o A4u8$f mWI15HU:t%:_$J3FC{0l&aV R%(?h$hVyPSq_b74M=E#V'E? Q,:J2ʠii;@1Ԋ2n:xz <)FNm/ؘBtQ/(b$qڎME(J{0'G>q%No"!(^rkgd#mL,߭sa]kNšFF7ɷFMTIҍ!PbF1y♟4!&δՀֽľYyc ,lFD7_?7öa(`ҍǢ d-?٧vY;5Ji? J N}+)/,Xi}2.lxX+is"Z8e팴kN>CI}3:BLer󛃶lHq EZ*(aX w/Z^r Y~aa!;E& sβN (s=P B@lidH{aw7UhVca:3uV3J7`iiSLA8#S<̪j6i7r Cr0{MN9M&3bp;YE"2OcGnW?Hi7f~i@rC_1S٧E5CΦHH!D(-d/2[?F!❸[ o`'vB41ohk;mwv E7ɞ!R$qd ,̡hg.sp.18bq F/ ~IB$ď"~Mď!~/",_Lď%~2_aK61_i'O&cO%~F|/%O' ėhgĻ@'{gܔgSa33q>JsAt`/d>*݈q=gyv-3/t*ELC^7پ(أ+? {|(׻#NA(Щ cNeN]B\Q:r)Pt*SvHr\bu9T1N]:5()1A \:5嘤SNcNStj1UFtJq9Juj1]\:UrXcNs9\:5~f+K bALDQ9 &j  (9Ḓi.e1 091 |03 bGJdA,6%1G:9# 9@P1YE"esQN\T,qVK̙aI iV( uaJ,!fiP*K,\V,;g͌Ku}OYzUT M2 j$|i4y}И*\ BѬ׾hDmMQF[KtMh?u^4TV+BǠ]i|ݧDa;}0*O)9zWbTxd'5БN*)B7g8Nv}|R1(D!Tw"s+Js y> μ(ON}I7U?n3K07B2% t O\S($-FZjZ3LL2Av|8/,)3Q,FkCo=Rr'a2- WD $3WU|N^MEhsУem|k}(\7L*6AnHN~n< 1M>eqtXM7pyƙLŗ8Jlhy}zUlO9WzWswݾ| %w4}DݯUQ2Axy}Gz'q"(< }'*Ce|@Tp$Ue0|0|,WQ 3Ng/0YWM>'!,XMi$&s}z'OcEjQ[V|S-'G`>GPYPO$7_>#R/Sh\)QwB^$G)gFrSFQHxEQ0-&EQsFE6U*jRRDb2ge Vkb2gJ)Жr^ J[VM*|&,7|!WB7fW`p/b/8p͎mNbe86mqm9VVB&\jۆn\el:/p׸!>6pb$c.XgEk e35WM-xGxOPgHf>>'3+erj|5 ̫Wo2?dG_3Ŀg~g~r7l[$-F4JHKXauR3k0|!MgN.=:W.',"}.dMgfYvMݐjeY;bDzcddf}y {I^r=BޔUvR>ޕ[CiU<ѾHXk_.4=(4 B}޾_`?(쇅kM#fm- [Džm'9aJP ; O.? !!Dr 9u]ž녽9'}9p^\pAn?jGo ~)|-opq^pI^P8wK~.\OPXn|U8H"~ WfZ6@J%6Y:8m&AxTY@e>tr Et׹rZ ?V˳d N~8'8F Q@GLH::t$ui1D) c Y"JeG1َ(q4QBicpLLic #S)u:QZ(tc:3(Ueq̤~x(C@v~9PK ryMPK@0proguard/optimize/peephole/MethodFinalizer.classTRA=MB DYd! D1VTAaL&4Ng&ŃߐťG(IŰ<{=sUxѧ T8U<Đp:Tp#a!݈GCT1 >6$ϥ.,aLb,dK ݲvjlAU p[Qk5#žep x!<"ϗJ ʌo>$UJ+b$w D](.+U Z(irj‛=}_Ё.2 D 6LhxੂI SVS0f5< sx=tPg-r4Cyq@0CaVEh3gTrtcP^sX9RU,4ܲ<"ߕtXS{8)NSà 0C2kHv8t e)|Vg2#>12^R'Zh9'xP oPMv\B8p>M'\_ck`[&}57PK_PK@/proguard/optimize/peephole/ClassFinalizer.classS]kA=fi֏Vc&AQ+ " Liv]H!T}Q%YC1`v=s__Xm q=OэuT [xW)PK7}PK@2proguard/optimize/peephole/PeepholeOptimizer.classUmOA~=kˁo$M s[#0%2A:33<ן}0:.wd)qW{:1}<БŤN 9 y L)=i;\UNdפ=n8 ^$3 8 D)|?T0cԚ@82)|oK0`Hk% ' jrvr!0QăMT/.r-U콽tI31׸,xp_~'{60a% \F+7u0m`5<209!΅01L)=bmj"w?w1OqF^"]h̋7fջ/roGj3EF!Kz,x>4\t^#_c5Ћ?}l3jbMA:IA\%9DqZ'H,?J65:H>qp=c#t$f!HHH:yG0ZGn"& l} E8c#JCt,C;DO!UiSQYS/>tW8M7ׅ[PKVoPK@<proguard/optimize/peephole/UnreachableExceptionRemover.classVWUd&C%2VL)5bXmXG&f4L&W,<Ǎ]Yq!n ~҅;-F.w?}wo 1\i0 'rq.:Gpr/'{1);yR f$JHKx!d9YӍcZl9o-Uӱlmݬiv.j5o8Rs\41ů:vMt?1{mP0&鷣=EftR pdAH[9, Ҋa/i+EwV5p  JȘ2DV[(#ybxA۸,ኌX% d,?ݨF`Q !!U5,RhM#5Ot]ԛלA}`8lgQv#^&jFS``كrPUGiP9>t){n҅g6VsN!Sשxf#{whxĻI>B/6NCSs/ =Mσ 4J`UI0}*}O3D!b•?ِ7Q:<[QRB ":~zA "`BytK!:bEG]H15uvoip) qC5P'lGFGc!auEGz^$xE bk}>W]?JJߴ9ޢY>3 Ql"٧ݰeǟޔ7)(-*BbJ *ap~Y;{=isޥq0t#v\1ե@Y8 Bgq2v0ac"ݝnN ɣq9s{ KT֚ wӔa95%;.t >ZyafN}$>tgGpQ>XbF ֲCP$Wh0=\ğf+1gHұV7ێL.9y?0nNDlȆpzJhtiWD,kɵ65&SuˏDҍs;BVq4λT4n®, @Nǰ` ũ8kt: /k=(1Ia hvzS 9O4[U ƅB6(v hE 5Dr }P,TkVmt |p\B_);}BEp`C l`֎UPI e;0E* ,Y 0Lc™XXz6K걙ЈHb7q#̼{q s:P>R4:BV~K'ML~'+/+?`;F"X.8 vBeYzfT?E< Cu-ai2&x>^jUO7[YҀ r T1tB`m{Ys HKFv360OX]f|.+kirNIcr+&vPxSF?zЊr1@C͙L6 RfPshJLUS1͓)VO[;W}0]t'i"K.g1.(EXY|m.YL9rXle "RrffW kEV.V9a)>jZaX 1b=.睑/h|[tCt=#z ҭLי45frO2iĢEI4k\w{7ä3" Ů myxK7y)mò9yy: } *=O!ꓛPK ,PK@3proguard/optimize/peephole/BranchTargetFinder.classXyxT7kB P F $$L&/a`2̰6- ڒmŵaQ)Zkť~mђޛK2C_>s9lso^9 $sqg*q_᠗9{9j98iqp?7oEk.-Kk8x9xGslڎٱ<<'s{ 98r|F4{|\Пy^E ^e ^jLeX3C~M,O`$)(0`0z}^7{ W7ֻVj[Ndx ƚK.H2fEYr0Dl/w7pAkp[%N-*5@ no-'1 WT{kW|a)=иklxݭo3ExW{nEWWp7la %±h}PgZ8=lcD8*A9= h;QLJd)ȥ}qp"w Ǔݒɰ0)e) J@fɆ,Z3vq&'.m`i`;(o򨉵KdÛj`[DA"Fj7Np|6pg8#8HGuGBU*{ܽ-$usNH uh{;=) '% ^4CR")GNr| "%;?>{L̺]9-"-\9޳ n a~.:38+u2-Y l 'BGxmKy* 3t6IkPAu#1~~.5=юþ>ާgA=i(YZLuCMڢQ|I SC&} ĒrH X ohFk?3iEo%~%mZD"8r`?Z]bb9=;"?Zۇ,Hğ81wfb-W*9(;]얤 1J0gH24pGXjo#--*PN-ܦ$u'm+ƴ;k)'AJ=Rv&jYn`$z:Z<ixʍ2X(K`8Y/_r+ڹ(冎FQڜ F3ܡmBt4gP!Ot Wol)‘OW=#sEquVmCP|ex)UXMS[6::kexm}ѯv#$R*6&_sΨuh9qulrm糼 ٪@%ˆy p!0 /X4KtĿKR«u2ktx-n^GrpuJup_E:.5UeN}UJm\^Y~SCA=`Dg4V99 xa40&Ĕ2>ZSi#8 ʊIEf.-'% bp(ά8&b*jKd fҔUl3lbbWܐsjb֬r geGpcVrwܔUniV Fr4 \z >L+-m$h(("u`4cHv@g ƲzɐW v+5Ajo$g܉t;`" h I|T#bnalфJ?0AGF\E=Nf'5Lf܆s1? C9m&t9g9.#O ;Fz6LhF31؍Sǐ3tssjޏ:^N!L(I69mê@QNa= Ph;^L$ns5ӪS-MsfvA:LrFж]V\[`b/pV%O㵹ԏ v'*n)v:!\L<+Z6˓{ctYQfDǺMȵ[7v[w5l0 `c.Laa&NY}g]:~Rt17:f˱̃xyqq,kċl d-x$k?M3.fe16mfSY9Vv!z]n`Fb^&ۈk?zn_F;qV{VZMF:UQP2ͶCp t>"9=@q2۞dEl bJ?#Z*{"{yP^+u->y<5*=Շd77mg|e״^fbpBnR)BH5ܯT홴 7[;<>\,c>F ;v 6#$݃/h[Q4.ɼpACt2^AR‡T a֠Lh-qfb&>qRR2´OTu`ϷboicT6.0sCݡ+1,뼛akh;gcR)Kف} M5Hjdw=!q}Mua5̟Wna"rZDu9ؠ(]~]4.t>XCD~ r"8eNQ@J`U,F*}vNco֜6ޡPK&eQPK@Eproguard/optimize/peephole/RetargetedInnerClassAttributeRemover.classVWU=2ɐ0@G? BӒ@S)D-j;L^`d&g2+{t.\Ȳs8.=l ]x\꿣73$|$7~oG66ч~AA@<.h;BD. r9! 2TbT5c21!=mZ62; gA35|\X֜'Nۊ^[dZ*1QVl\:§k:j<mK_,n)٬ג[w;mrҶ C'`pfI7&lfŜ;rz>=8Fd//'q'36ÍC<?&mkZXhfͲ ]4`LsW4 +vDdPM#51` 2n)1`(#+`AƧ >]dEh W+IE[/<^伸lRIԀ]||V/zNyq&鞭 W4=-J6ZǨX|䠱QNT.*Vdi**pip`4UMEe.sj;}}Lt{ࣖ>" GW}^p8c8WqI]xiuZI\wexT }2`h7oG[g:괶ZV g Q?#`~14GuLKB^ &x}ޢ1mpU F4joD;hE+} }0N40v:*Br':@")_R%aP ۄ Ģ HkPcEl߿iɞ! KhL١~\Di7B(kf8&p)zs&`I/|n$sD$7_ևSnFȹwА@K'Đ좓f(u3) _D} }o" K됄jv7@BwiwIko=X`y]2dS$<9*CK6qB P3ո-+5i϶dBTDqhnoQ zAeGkE +ex 9f?'-a.4C Af|^S{$"ḁ%aJ{1˛ $@A6D3vkҖ5H-8USPlU8C.)}k{$<9clKŗV b؊gSƹ_/9 "ƥJJҼ'mz|83JS8c >pㆁF a\DŽqm o` w =;J \!yf [k2KZrNj .Vմ3wxۇ:`R?nV$(G_B PE>YuUPH;ͭ&{uA`j3}q1t5|TEc= _ԔIUz o64UazS\8=];S-K7E}8H?LðVIU~.hub}4[{$dpf=& i9^EG "V]FTT}{ҙetn $ PD1}'&=s먊BZE'aD?5iElf ]h^Gs/ѝ_"V mO2d4%d_Wޤp,Hd3JYCoO5* ڿA0nIN}P*01GyjG>"c, N/PKnΉAPK@.proguard/optimize/peephole/ClassMerger$1.classM 0_]x"< =ACͅPbԍK{xlwK&>̙s9s{ι㿮NXS,O&c>6->hb1&jG31vq-93n[D3݌t0pb!3O%QblD"E`mۨ"2ە`Tͦ ,i(M$0~SCZD3uÚ氡D#H[ nmJ}8鞾x .C {w)FjnBLLaSӎ{u2흶`5U_ ;Sh%t7N_@vZH39WmUsyZHR]JWf wѣUKI#Bv8fh|jꁻMa.J+{Mw;HHyAŠTF=29,m]7U5Qkz[E^aK6fɎU~uRtnVLw*~XrP9HX C͌*\B .rFj,+EpA }IH+SB ֡^Bu{^IxG$3rggڙ8C蘄5X+8NHxx`d=6AG*C8QS [pP@/c$`U:9dW|m]1.XjD5Y7Y}1{2C߫ [7IMxTMRVlvET?δ7Y$T ӫvF⸤T4AA@ fDEZfMih(_T INB}k) ̣wze| yC){DW 19(e9l!;di8-3Q#;` r8u0+>ayYe{-xJQz s:eAvtRKq9Q~ME) 3@w)RralFz5^{8xYˢ+9^ < c:;yz lgؖY(rY 2{D6uDr!= 61ff99#I N'e8h<]$BO?o- ;ӘIgˊj[+A\ؒn,}@Ӛ#.&ގ"#fQJ7Q)_ߡD{q2*!?Au|/-$dO?-B,vMx-X.=aK'CGg_%$m'Wiheypyu2_O}$/W _iߥX_hdw/P]\D1;8oñhuPK=OPK@4proguard/optimize/peephole/ReachableCodeMarker.classW]LUai E?b[[aO -Ei]KAZ݁vYZj141X0FfLc|4F˲Cs=;9{gUxՃhpch4c}Bbq@HqHGpT4Bch1!b!;=xOzMMA]B?k(CO[$Ih|:[F,mD ^Mh1D_n%@1/0l,NX4i.m7c U#ZlEV?qLE$}3$Ѳ)Ef^ˠݮ(%G; i4h0 d-o2%z[ }U=1 o~ c,̓ķifnRY sKs:WN>X { R 1yFYyBT܇*Jp+0TIأb֫OATE *ag*؍= , 1)uإഊA)A!!=x+xAŋ8%/gqNBe:ҫu?cYbP%E ˈ$/fChcݾ`:f3_zEʌ>gpzo5-HM'` OL뤴#谫UOy4$!~;uPCV_Z~(vKoXiGEuzzh/J{,h5 w"ן'b`s%Z4M܉j>%d%QGCBd.B9^-d:Z([|9GskzRex~ 7?vͺ"&>Wk+K7rHe#? d|&_B85g?}h@֕Jf zs.+(*}8M>E GQQݵ3 d&9D=8Ù-ؚWc[MI-%-O-un\+ye5Uǒ|97os](gk@  3pf=S0z3;3ښ*O@$ GіIxYtaϋb`:B7 f)̉:Hy{] yŊi.uk<6):2(b-kI4/~ N}MLչD{e]$UrSlw< b\c(d0WVqm.jl)w/ߤ$ %풓+PK3 $JPK@+proguard/optimize/peephole/NopRemover.class͔[OAC][V -Qh,>&QbL|vnD>-L@>2Y.̞oTp'$.•$5\On*1=aqKmlsh8BzڝΦp#ܛPee`M)֪%a՛LuD[ȇ   r0WE^ ,A"H6/?3|K;;}'s9}]1YjOী"t]|`Eȩu/ P;^m޶ `L \@ZG2*,Eϗ%vsoy-PJ2M+pC,87hcx~3:l4~ TTi8@8$ SX ^.^Wq oPKO0QPK@4proguard/optimize/peephole/VerticalClassMerger.classSn@=chSzII\B8?!JBZ&لEvlp+H |bT%B9sΌg|<0QӭUm6u7p-6{=G~_dG1Cj(GPN!á@9x)~0lPFb5cNO g uC2HFNf}ܔ#q{]^K[X+1R]$1P͖x,ub[Z&jcnumv,Xh6Xa9GBo|6'ɻjZPuzđt)S=gU݃g?}Jw֌1,,/9h ƪ z.I3Mx^ UA<]*'35"{$3t3i↗^Ge;ܘx'ǸxLvXGFZuxw,d*U=xTIe'c)NIx帋];͵0‡)rgTh).αyVHX>q d+y<W$|I—&'DT iZRF22xL`D2ޓVPTMV5 FDO[$<' Wߧ'4-ӮLk)g?I1#zcR7ZºGK< TctoܬvEI %5ՠJg7Жo_Cnd0yҍv7Պ&0FziF$R #w КZ Rq˜jRy)rpƱ[$V/ٸcmLs9B1Ae1Mu"v,i'BSL4 55i*|AfkZ3'slF2Yh-Hs4c\XVQc@.E[=\r{7Ӡl+<k[a n qWRܦ|-c(jO:Sףb eWEg@b=FČdr^\T5ba|C 50BdvQ1t?~uZG܇FRu?>l(ژŨC}T ՞b=}L^*A~?-xH܋g0=,V#b8&y;E8~bh2i>3aPEPK'QM rPK@3proguard/optimize/peephole/GotoReturnReplacer.classUKOQ.-3t; @.ri6>`)+c|Hțk;;9S v}cQ*I:uL)Ut鸊n=q }*븁~Qb`Sb){JC:134dRX<[K+zJ=&fR9Ľ/GP{O"C%QUCAPNz&B  , m>DQDpgHEz(ān?HYNůyطxJrS n@}ǕUW^lZC__OAekzkk}r]3 ޛ{|ԕ e546Q`fzNqSB5х,0 Gxx?~PK "PK@,proguard/optimize/peephole/ClassMerger.classY |K`9 F1GB %0I9&MwV$MҤi`M-iۻMmnȾof$K,}f_>2Utsx^ |)/hFEKb%,>Ƨ[gEw s AQAɍ/ ?+|Y~E}Uu7+MĒs} E?kbcD4?DROKW Uo`3~+~'_2s Onܣv/ `7 9%2InJeRL&Ur7RTʨ<ܰ(4CeLhTyN)ͥy2WGUxB5T+B" b!Z"3Te2˴\A\lTjin<4djTp+5 VY2iLd֐1‚ v ōA7"p_52dQko AByk$kxJvEF+k~=nE# -lJқ0) K6hPTK bgmYAq=ڧtK'0Z?j&J3oeNZKy}BqMF؈o!,oVWNl7zgBhGCL*h-VL6aV$Մ # w'`[3߆iQ= A<8~_-VNj͉j£iZ8CY=0=6G&NyZ >i}< &XS > Rf@;ۂ5~-#| kۄOhC&ČI=5[ :6#rh1=ޓoR0 P S#h@aȩ2:Dʈ.!5^o[V *ލx'J_>AK$7}1%<@+Cz֝`D3u6ȴA0{;5[}}"MyL7U xeu _,5m~ZUFeApTנ &JvRLTM*TNTC{eڧR{TO2P>ҍW(JM^1bYS*>8= #y!`_D$hdZ&}IąŮ+;O^ enì-tk MGCRx`:R٭(KJ}ԯæه&·)ڠxṋx 9S]L]4'Ze%BM1"11iA>VRA3MHA4D'TRL36%)Ymة )pt0`nQ\ D9UVN 8!DLNhN4q'g0sSK. hu*BSe,N@4rJ(*JtV\Y"iwT.ڛs˫H"lJ\`i7oҢ9iZpܴ%cC-tuNÞō MKf<*+$M˖MY sBV" ~z'xsI[͙ǭe̘aE,a]1>"2D _kk5ISV 2 YTe]ñ>@|fYըJ 0N}61Jd<$B3}onT a| &[4M{s) 0a2Cknc<;^OUN q,vZ?oZHh-t0| @:qn%Fl7KyGDqP?̳o#\?E ۣ^::skZڀEj U,ٖ+-|2r|5Sx4AO6l 7vs#r P/ycKew}XW4SfŲK\ms4IH*Oղ]t)Ȍ]yl"1=kbU%#ZS^4,~3kɍ'^]a~/.b݁bE)V*.B7Ug*3=+'O*ͼm8]<.ݵ8JJd~)2isC[ە5 MF3kKU ybj^g5"zĵ|/;qJ0>0~xW%{ć%ĻxUS=\pr_R t 0 F>\/ y3"\^Exk.B^;x !s׳8E8bxl{ B9:^)EcPgp(f.D()fG1wĚ1ɬo e:Q-LZggt̽|&$YjI_B93>Kڤt&c`0a+"u٤r Pwyv̳8 %#/ڪhF$)YS *)K #X 3ǟ3a.{})Khb̫V&1ZP^sÂI>t 5ڤF$oAnSZsLӛG$I2ǵi$U칋XU~ۢca_㷀M6qư$ϕ– N<(b3^ [j=SanA ;q5NavSEe yPؚ]{+lw $VBAz:=_ ר~G'$Hm4_G5Z(%KZ! #I}{8fct<DgG tCLuc1^tFc L?¡N_%Un|xHQ7b)KXC㙍ZX79b#%0!, i, d D \Bc Пw0~_~D|nC%݉9t7Vӽϓxgn^6#IVy} ]H‡mnpciw,&9wT;єB8% IhʼnG'[&yM4s]\y[F0˒SlzwPzbwޜ]Fh;-CJO8))<%"S'&<_u,jsc#sLcEi;p!+v&M3ES-_xZ~ dOg$ ${*#/6r9 bʖSvszyk7$M >jkJ^NnLtB.TTR l Zj ^<;~fp-i$T2iʥ%HK1[\%zά>5@\79ܿPKV߇#PK@>proguard/optimize/peephole/InstructionSequenceReplacer$1.class= 1Zx k a$fx(1joc{`A,CN WKm0Z*ZEl {#A%W\ls*C0 ;|G}e?d)Z #+]!Xo"adof$j^< tu_PK]oPK@=proguard/optimize/peephole/InstructionSequencesReplacer.classUnQ.03RQ+AҍYVP!: 5fhn\n |@=3TB;u3;3_Sf1}0\ # \Qpab#W˥GV ߪetj r~[ͯK^` a g3[/lkfJ7v{S<KWmWwe z0j9bG<m0+fUΚ0*͛±lscި1C(L^rwܮj <ʑdW}l_Gƌns} rSe24m;0CbׄGĀݶD"b2y5!{4Gq{ sy5:`w}\A{$dH>"A(N=&ؿ$kd&PF .1Yo1錢J13BT%VPګ߁Ty-w?3~ hd^KxCi/PKN6@CPK@7proguard/optimize/peephole/UnreachableCodeRemover.classVsU6ͦҴ()*IyjPM Sm.(/Ae ~qh:ʌ~㹛4}13ssy폟~ dDJFdԣ8N'0 _z# aH)f0,&hcbfo5,Ή|d\%o 20.Tf&drʈtWpUBABQ!dh=1Kj;<^Ona#rmm6l/1;k GҖm<Ϊ8z:YT>js- v^ Cv͛٧]ݺ\9.y6& <-L GL~]Dy˨(Ayќ+ڤ%]kW{kMɩ`+P[qc,P S= ',@gSϸ<mڱy'yD (p1lW0BobBgK,ʿc &q]”>rQ; rЪB7@9|%|DUx1WpPp$|V)(  |UR; 5zAыVAys_`ܡ4/ E )C$zRV=AĪ@F/fY2tX*g۴R1w"T[|9 ffXThtHq/w2n-SW.H5L78IKX$ w-G%z;bPȹyJdG >7tgDm08^\7IwݫlZ]׺HS7vzQ$f$I.zc/,1a:4Aid&,#922#h&UOCMKѺ^ʹOEpaGNNs Q`hE~Rqι)ԋD`q{5Y t O` .dߟLWL|L- {? VHY?U|/:Kp}6ЎR6ІL0{ >Wq40a ƈ# {51밞!+ U4ϔ5µΈB޿nMHB^╜pP rjbre)d0E&黳١^>d]ŸȐ󾠚*KįzvhtI\&뙉LK>]i_}D㈍ ZԹO*tXI2N_@M,s2VCw/ V?B95T"Ah"b"kv@.Efϗ($> 8A,J˳'I}|;ҩdT3jFS}їPM "Ƈ뜁f6ާŵ4<{¸`*jXT7R2&UhV0 < grcI^![mGz5`WPKю7PK@.proguard/optimize/peephole/MethodInliner.classZ |յ$G6!,!LB[DE/df֥.uIVAdFZ֪mT|}W[_{f2I& ^?˹{gw8(Rq(gi$!V/*2ο*TE7QVEKR^?PE&tO* *&/*@QTI$MigQ:QF)DRP)TdDS1F9(A9 *Pr-$(T1NLGϻ T& d'@.Fht Ut*CZ;]RL"iM\*S3*ULE#͔ e9 )U+c󤨐b,{JL:S|FLƯ̤*:OxbP .E,7ZVdqʰ*]Hu"]pȠ>sA%TeX!*jEYdB.IV`rE򨸁*']XivPZU|*m;A LB ֯_[PWP`m5kjXLZ8ƕu+j%㬽fdzI_PSrl""Qw o^@|pX\H}kyֈ/F_ů6́a%v޾U/ ׅvw[#f_/1+v m21j`'+Ѱo}{T5U´hk[oB}ͷMkUBfcxs֚-=$|ƉHu t&hs4ڑ;drYQwEV4VT2(n3Pxf0wG8u)&{I"z=.ZEt5D=uGur=2Y遖h+a( 9=K%n{=24j EndTJ~w 'Zlfor}~}IssDgbZKPZ¹(jjj`>:iho[WB`,DrB 5Eoۖ -AĠogQqThua=z3Y޷ͪ=1vd 'jLڑ?! N}m!qI`v[ WYӏ鎯)Kb;̾rl``GۣK8>aqrweCMR ֝肩Ɏk.D|KrqaaJz1SM &!=lLmhG9V9V$`{أ/I7W4pLpH8% QǜicH4<''hxOq05`񀆇).<8Do݁}mz+5D V-!PͭVa<(l3v^6V>zYrLa #*4vWXXxN]NWhxht%mRFg`^5\  T+玓fT7bQ1Fn$[h3Fvht] Zitt h߶E}A(>XǘA74B$2bB7it3:4tsA#noix^`/m k80t;ݡН}p`'E /Ȥը:5: !JkӀۿbkH a$lo~ڮB;]?iNv=Bj%xL>NO(BOi4=C9UawӚ=XIw> D8cR;Fyz5z^ $_{BUzEפ8$uސa.!(F?4яFO5>߰im!;SpaVP{C)DQbug44)~чtom-RP*7Ruw>Rc~%Z4)_uO5s&gYFU4x_!]Rot_&gsNļy'|!.H:U4>l[#Qy )_ ƫ8N_Hz~NEuMPH+I0d ^OvE$㞥t$QL|}!C㆚N(2'D\=Aw!gs "qfrTS#ffþ ]ױg}'!, v?2@%L͟Ĉl!"T+q%FA/֕g^FNNz< 儝giB%b$932r%}V4%n)IObdE%*9^o-mc/5WZj>Ѣ*i7E|Bϋnrfq 0gucn pBd,YR9I  ybw)y-#O)Yro<)kщk ejŁC@Z}l4񣘗G |@^oM;)j8cuR\OkF83R2ی>g-gOk1x5 }5`3/0kzG8 a&â]5cJGQj3~}# Pr(!M # I#0wfh K׏~IMe75YfTWZ(%_4Gf kidӚp/3g3 I$'Fj Rc>\w[ľ!w8>9ɸwŽo.܍{0 piYxpۆ"_y//=FӪwa~u3Q? O~n1gƺ6yp17Vykת_/uz/q2NG:tM8z@`ǥS/h5bMi< XՋ5=w#Tf&7ndqSnds3sMFkb7F&uc 8.EW0gUA5xsZ|\{W\g}Z'?#'$kz._!8U\2#e}0^L`^'Od>C!'séqN3qxM?:"irt] ,ab9sUbwsr=i?C:gz!{%YиaCkV0`.[Bm^CG?_LK:EyN<*~sqe͂EN\3]3nÐuY?/;ػ`OF*C5WI.AdIHVه\-%qİ, k3%QkK0Jxك vk#u@\؅=ۉi5AỸqFX `Wؘs(DzOe3F\wFgijd%:lo1;;|/s) \|V:0Ɩ+b&XJPrK8:ZnKӹ\V37Xwѧ*E>]v`^x.]oEII̓gvwz?&"Psh3ΣmXF۱F~f57sy7EUo4tI z't7ԁӨGO,;i #"Sϲ(br{΀Y Uie+]\iCb.sG@kjL8 B4~!1Ё \9tenS΂tn5fR iIc!0QBPNc=s,d_17E/~:]2ҫGo[.>ڻxo>}B;R2(.!>fD4*Kb;)w*nq%ŜSUl&NI$Ov3C{1MI8̐PPى݉ mCv`1W ->s[ _l3lII9hNͧsvoGjiuv=ׯ k8؃o73P\blbVɶefgQM7-q^\:\?UFa6{9 PK#i,PK@Hproguard/optimize/peephole/ClassMerger$FieldOptimizationInfoCopier.classSMo@}q↴ R6DD*qtMc[ 3V +? 15%xgr{D<`m7m~p>DhzàkBea }baV=CyVp!;OQImP†M7A"W/͖60c5wDWα<;fv4NZ .G)zE=M0[f.l9۳['Uv߭5^^2g%pzz]͠[B@Z!Osm ȉ̓MˠCv jSΡlSEO(|C;C3z /cf/қ"5ۤ^ew;-b)P2 PK!PK@6proguard/optimize/peephole/HorizontalClassMerger.classTNA=C[]˧HѢ"[ڂh"1!$ jvZlw7۪ D2Ygf=޹3gobbwMb6E{k39)M$a04 j(`@@@!f"vIsC!T]lP5Nz]QaL| _wx@boʫ7mIG[nsUC"wt?`{U0-]٨+YJDrbi,a.+E7' 5K <ܐ;cG*}-FY Kizn`aRwEM(ڢ5+q_qyAbvwGE|eC/ޣt;xck唴ݔ]pbڵrvvsδ@pgOמ>q@;펚٢34|#M G*Uޓ{yO9ɪ>Fm8g4Ѷ=)p*P2s)!Й8`4B4 ` Aþ ?6h/ `i"fN lDC3a>ʜ;䶝J O3X/ 1.(H*|~_3. .o]@Iwѵ!.u0iC}'wY*KF|(>d#}cBؠ}>c!LW *d\@m#15ßTJSETHFcӶ u6*$RPW]^"McX &\8Nk( U +ꪱ$V !H`aPp}<,bȰxP!֥+JJ`KK4($\ۺdŊKj/4YR\ItY!%,`di JkݼDVTZ]ee]S\^ʴDZ33 3˗0LAE*.ZƬ3h%3btJf7f3/iBI,%̓ue+KV&*$(//$˸61J7[54VqXqXqXꦍ UvFmЦZlXvmniݭ5qlԚ:6 7iYY 2YPIY\Nm}B9{]j[TW*ta*ra5[ Wê]pBXhD!e[WST!y6ں*o+切.SUJV{([:ouJ`d֡C@X'I5t waou卍(jDLyF!-QkͰCM[RolĬ1+S01ZY' 32i;62̆Vf6fq#}fs4A7*nv[PPLф.Z)rRTT7 Tk'*AuB e뤯O!<*uZt+ENn&QIFpҭu;2/: bNB m5[77ՔevpĦ{GUH*C&yB2~5- h898&22dsagfCd"=#0s3h lSFQpa%Z$<ƅ8 .īIS Iѽ3i-;jYy*Y\4{,8+M ,Wr=t7$N[y8M]M,o`㋳_2xdyIxdxIWxdxV$Yq׸mBjvC V˹-uC#mCmGt ;SB~{HuGrxWHaKԬF:{ kk0mFU*a`ŶJFpuO0l$ :az˨Տdž{ASFvAKmm݅C=ݫ4CuuGnhvQp#b*fPxT&Ir *5A P@CPIў#=CLy 5 ыimb+ӕҒF[i ݛF}!\L)uؠ K!r}jKRXk>{;{b]C} 0oѴZ thkf%2Z-;6ĵ5o0 L>kzچ fP50[|BnlM,t '96R"7ͱ#q6JoífP^tbВw<:dpWQ/ <#E7l{SIpj> cë7b6sSvХ'NA^ qWIsd ^emp0Iyg*jJZ%5A[NPݱqQƚ%151E1U1e͋Tߥ0\U~O}頭"ƞ2ѦRamGN,Qxf~5%0UHӈj8`Iän`c=CituEbVXlP,>VفO[z#1xK (d{WU|bvpPCաmE@6`u:yrn5?X#cl0,s$Bp6`-qpB.36} 6 >2 氿-hUMD3M)}mҿj*ke-~mx jGo<ͱv= V0ov-y;tXH>'_'D o | +>?BX7?#1࿍w{>?D?Ags?/W 7-G?'" ?/F? o~*jbELNpp`aS!<p:#g"<pg#8<x2SOEx|L xs <|^".\/ K^ᕀ^x5kEx@pՀkx#µ7!:7Gކp#&ށNn{ x­#w! 0+>>D0!FxQ> '>4g?Y~y/%"?_/~W@M@_A*~\G|A.C_z|aXoGWzGO#aT"O~ S?c??O3h|!`_P~_F__A뿂 ZX++hW`W__A뿂 ZX++hW`W__A뿂 ZX++hW`WOOahS΃:O{vda;N3;(ځ3|f |?"0 dY$Y*?D@YG$n}1 <&AIk7I}>&) GS)ɸh:\<$I/Xd%˒xK~H p69Onikdc̭@KkѼLk.'Ə)I%AtC2uф@RIpB0/ seE4zH%2b"F!:ٷd<}`%u$ _2LQÖ#jT$JH;-Jrkd]&%uۤ>zwɅȽ{GяɯȟD?!~Jo+I/OO)/џ+KSEAT:{ 9Jޜh|Df56': ˮC캀]zJuk--l"B@):*QXG:J2DGtTt(CGuZeh:xU(KG5::&NG:Qhht4YG;t41Ǥ<"M{LZ#XLښ푍 A-0`!x f=&͑H&`!s A=5 \P`p#nN |FӜyKۙ\iNzD6$ $ڷ0߆e:.Wִl.zPPqc n쪠A*ʶX,Ęr,E[ҀV a EC@gS6 ]k5N*uC\&Wҡq422 ;UfrE+.T >ˣy^qk -q`#r#p7t0mv|"5]D"c7: N2$S$hurws4NIW&erpO'H#HW{z%EX%l6ыu;bɥ{Irɲ 2y ʥ_.=K%%]bZs/iNjq/|r_.t_H-xd[rɵxX\:HEq/r9/CKW.^\^BǚZ6ɦhfp o%j~qgsNܙq2q 䥜7םW-'(r/_r~k <Ƀw5~Ù'[w°\xSʑfӞFiSJi کH˦=]NG6vR{#2gnrCٳq̲s$F>w&>yG.}õlvz0G]U<΢Y`Fjöw #H{Ħ"hEGm{cHM{kŞs͡MqV|E.n5Ѳ[-V(n'ln'mʝnʧl176.736ni7fqxLsgm>nϊN7!4ϹFnٟݗ`Meߵyަ#7hOi&䢄V8Kue$?\5$7Jh8m>=%V2;\xNo"!e1q@5Sq'Ϗ/'gN^НXMbr;wַu* ؏=, C^M|# lAڂXD-6?֣;񟃳ݕ\$Ҍ~PJ6[xq+QQߓSWQ_kd>]ptV@ν#nQqۏɸ?sMqۏ˸?s?~|֤\}Mνy۟ĤSC8Nw$ e,)I'mSJ~Iba5:GSrԒLzӞ9!G{ǔOCZ}{CUUEVU)![Ξ- gfvܫ ಆ~\I] W0\&4L<}L gsFzgU|bN}%(}/e5Ȉap̒)xeO'6a4 %Zp<;IR$*¦eѵCv\剛uc $:۫՛A豜}ŒtB&u yM4LN,wr;t]]l 'Uro~;Fi@ަssΒPÚ~˰`O!~V5D m|ңe^'3Ν>ȯ-&IC(.0I{lbfP({|)3EK*ոj@(3 : OBN)7cC¦H W e5N3W 38+gZ% 0p(eIJq.et.m,WҮXxD_ƟU3(ˢ Tg9P,CeGtgh-%cԟO?TD6J-^|a`,Agǚ=wtX`"@بtF*sɏ* A>OЊzEx%+Fb{Ẃ".unR)؉@g|VKHfW4|(YH-]R3E/%YeB9qOz4oIݗQR@X4п$g ./~Q&9p"~zsD)vA}{d"0Ic?uSh ZQWOtþ4R)F@o> )=<'_qAi.Wh i]qoaOH*w!Z-܎@Oũ:z' >Eӂ F(+aa[$ BhcG  M6O+TBb*cToR񻇯 6 9ỦxOwm;h쑞!oiIq㿧q^uD|yt1o-\oPK@NPK@7proguard/optimize/BootstrapMethodArgumentShrinker.classTKSP.m[""*QQRq(ZEQtљB4M:y0ƍ?nٸv|-;IQ;Ǘ2`?Bۍ_Nq qgi9a$ tCȈȊqNĈ !W 1X xb!˜-E7K*i*bMeZ\+rkE/p'~f˶l%U6͊l^Ȗe(Kų>pN=.Y]9+keuʹdwR3ul9m__P\.uۙV==m T Q{np:+pZzwg|fsTF>0e^ wH;eoG8(^Vћ"륛9G$Pt 2Mg74LߐH!m!Jog$Nұo, FлTL^@grHLX{~ў`,*2w^ t,q=v:LjmB(i!,n|Ej3>(20-PP߻ZR(UIU-a&O:UgKvR{kS.\zXP @N832r;13́ KFzQ9Irꞻ2i`-,hϏnD $J@*]%$daؙ3̙3_ֱh@B7001i3::fLlHQ rJM-FVu:rYЎIwamoj9ׂa8/kY- uɋ}䜤RO_eQqu/ڙƅT8^ ǢgB7Ɯ!:M, eb1q$RE+AX]" 1OƪZ:+2,92fWQ?֫ *u[l߶)I;\!E>0$? l44# μ@{"!J6JޒaAQHlseoQ4,Ei=<FPK&PK@Bproguard/optimize/TailRecursionSimplifier$MyRecursionChecker.classUNQna( .U@ KLLhk: xV$鯿?~(w50_$h)8+K 3fhKnY=lql:dJeqI#x≎x⹎`x [miܣu:3 mVd]N5%8̙ ;P;ָnG r4tSeqLMҘj/g8q.ayI"I14mlm)Q^19jqL˹|$$~h=](_! $oCߢSJĿ!zz4)H8IƑp^E 6/O%N=;)☗LU.a+]мcC^<>Hr)`BN<ąEJxN\iA#pZc05칗 0lhJ)K5^5*IT۵!S4mfr4pBMF9Yܠ_7t_lJ56:\[JL^ {xf% -,+5}E2^lmF2E6tN^O*U͚FrNlU.}PA.ڍ(jQ)uFHZ V#&5Uv1S7>@uEĮdZt|]vxY7GBw 8+38'-$<'$|yc\)I| $Ju\dY0[#$f{ pYxF7{qXa$\ŋ orK|KKxY4-; fiKODZ "&ONhFz\3m"^=|_«(5?#Hᢄyxzbw <@29a,_֞'Czt }DZբȰVΛUDzF5k/R ^s0h]7ٿ¢s6l<|qxX~sB#PT(6ubB3(VIrQ[MEV=cjj,cPWmW1Vuj[#泒,~P{dVeƮ(Skdoί:,/`nF\ff6kꖢpc!cزBFI7NXoS/xւ`5O2>0Q@)Ȗ h )0D W0!(u~R:fϖX iۓKk&.]MA}!a|1ѓRGvմK_ZQ ۋ=|KY=s=}TKM'2k[)lIW$%, l=?@ ι{ɧ~{hn1IkFw̓fwH4p߿y"Q‘)oIm-4KݿȓB98;<\1gXq4·9|s)[qUx!ç ÆJPijccSLPҶ+ )< 9DfP9YTpG`7Qʇ`htdԎ ݨA/v~ (714L$.j\NSq<}]@? 6Ol2j*!`xՋR3R0W ldyDur^M}%΃wW2uVux61NZ'bei8Q#*8Pp;( uWx_LT9캌|B{ᅩj){OT\gh&vsw~,^qX/{d*dnڱwYu`g + vL4F-uex*y ,Rc5uNig aDf_ 4 F8v.HاD>>A`ؼ56>Q+?0Yٖ@Z.(6|nooS;{:?H퟈&ZCD|h7-l3zv Cj@irNȖS2p7%yg:ٷz]э2D˘@V*.aR}SʘŮzw|)چ!Fx㖺UopX+kvm͜RFdKqCg-Wַ vI\1$(86:kEM+_X7_*U{]s;1t՛^ܢ2pw^M# D 4V5u$=eޥ|S #7m0F^ }D&?5$ًH`3d/1HYb|GtZSt+)!䌦Wcb! sdķ!h@_!IF('N3v[$>l9G\X@E2tVB^:ʽFzI?Ws|\PKpX-PK@1proguard/optimize/info/BackwardBranchMarker.classTMOa~~-] ʗmEDkLClRAmf 1䅋#G:nK(n^fvgygf_~H`ZF3~21B ! "&!.aD(C /q)w83CkE5}W5Sz.U,Y(1ΔMcV|2JZrNWwwSN4k7UKfYe.~JR~wBDd+Y=il+}F 8V 8~ lǍjNXsl$>u ˴ WA+1` t?wt.g OrNS$cE;_ HzI?A PgDaMxNiǨI ʡL'am#@ K]>2!~9՘W5yzۃPKdŽPK@Cproguard/optimize/info/StaticInitializerContainingClassMarker.classSMo@}/ -|Չ*R zsMXp֑D .P8pBHM*̬gy;;W[uTr9ಎsc\M͚u 1j!o ( ]!A/"HڕoZ$ 5QwŁ㧡CѨ-&\G ň +~$'d2%w&!ގϟT}5fImc&=hܣ(Ir5#Wu Zj Cl`@ޞljb:Т-eu0.ȑ7m3g?7h1'*ۄCM?,W(vk4OrC X Ziy?ѳyLta'PK.2ְ  PK@8proguard/optimize/info/ExceptionInstructionChecker.class͕OQƿZ"UQPQZ"`HO3ګә2tJ7ƝkuAMčn\?zf8"Uq&{HŠ+1(;Vp@A^8[p컓4J* Ғ@?5'ں!:--R3Y5gatɱoUTGhZ.id4hl꺎U\ZN/46hʮS<řXw,Ȳt'ź&TJib46}b7%wT(jD?i c3vь+ڞZM V8#G18 8 j"lڥ(< y;mR W\iY楡yiD6jk[AU͓, QG8J%ͿĹSr頗Oۨz5L}*;詛(QFt5'-mA0gm8M6-qi$V!H$"RV_+̏5f̓!)0syyyy9Üe^g1MfYb{L({#D6K^7Fv!xĹ\\4̣$_PKUePK@.proguard/optimize/info/CaughtClassFilter.classJ@Mijj=LR1xcśWm۵nm٦}CP<\>8IE)K?`+tL`Y#1c,yu.[]Q^U .n-dS }-x,ʦ8j7JBRtP)!ưڷvoNXeIqu/ڛƩVeq ޮ^a_&X01CǢ%,H"e" ƻeCv+C*yj3 ;;@Cn1 }AٝN޾2DЗ I/(Bqd9 䞠=0Jvr Q:ro.{A ZQ M`6C*~/Ka PKY͉ PK@/proguard/optimize/info/AccessMethodMarker.classWsUl#@4 ZQ@X(MMimjEalҥnl"Xqpg>iNJG}S?M6 `ٛs}{< )pxqуKleL `WD1z02DldA$NnTwVDaS!NJkJUȕzLIj<%;rʹ̼pt&k)b1ۭreT'_cMq@[32U}ix,&g2rfNWr![+}M-JU)i#bo4Crܚ‚cšbUY?uKI"EgpGBD+<#%b  iБaȲula°Q㎈<$]C6e1_&-m(kA -dűΖf %ZP)%EV=\V<0_T |Eq*uN/}M75R>@cdOЯzrl pxl#<^CO @q]4R p|퇿HMflA;,@ baAC42T?I!`'w^#{d6IpJC*H>U~B+rx8s]Ghxi?U >#|g/m:KvK*wMoH[#;H<;4Up;=*wx"8ʿPK(F8PK@5proguard/optimize/info/InstantiationClassFilter.classJPVchnHFPP=Sۤ}CP\.|JDRJ`,?sy}{~e:#ĄILE1i1#`VuϤ+=G1dK-\U q!ºZ]E-iKoa57=c:U+I[eNyADcXS&@KvqUEIԾz$cEZ+n"y:L,bD q $nN˓M/?I/j5]uQ}n!W~~'E瞈ts,`t7 It\!$;L^}{ݒGȎP-Fb}rO.Dù;h'5imyo~"%_;PKk&'PK@+proguard/optimize/info/DotClassFilter.classNAaTw-a0LxQE D[ i4aq9>f\JLRZ+ E:Fa8&"ǤgtLё`0 UhdCbHe/SnrUDIVz{ Y.jg*c9E0uqԬ:*E}䄤RW_ʼOGS @z#O 70 s&`bQÈ1,p.]Ymazɱ 1D=)e8_aǭ1ޤ:kegH]@v{;u:!潒'@dȳ=vC A"EEQZ\c~DPO~&ؠ}nR7"~]0PK6dPK@3proguard/optimize/info/MethodInvocationMarker.classUKSP.DBx < VZ;SqFq&&LHaop/p¥ xn4<XVnMss??~}GT1aIipU5H3*X n(`\Cma g!P9'LT\c}@ .5d82skZ|(+ ۙK+;-KIBKe"!(%?Uȭ.!\-Lr2 UnAqcf{e q,Q$MAٖ USX17al>Hiаx (LE.ka,q* ͱ[ղ U >+vzAy~W niHᶂ;&1`ZCwd4t㲂{f0+_Z5`a"ZsDQlɦ^CQH.ZA"k`v∉;=|GV<僽6@GgF7 j~P2 U1{3m|*?OB> ihM ^aYqjm,閡8h/wʔrY\фfߪ`rzqA^茏>_`=w6}Ƚ{߿6$K"^Є-8!> K7$\5#F1&ao$p7%$1ɡ$´q3|#"9 ]&2-e'mRnWԪf2 &Lc騱f9}Sc6k*F!o3oE P,0n5צ %ͼ.eI[-Ϫ5mY32gu91&5S9[ U*u@fixc: E bQ6MN hs*z`uA**j*SUWdaJ3FLiqW2xQej*e2\x.x dF2"X!EK2R|NАXqr@.>Ved9JNFY [F2E-N%+Eⷊ2&HITk/YMzTG\,>TT OK@'^It*kmٙƻ=Ъl~eLMs=x~ ` e!T2o+*͓ʶ=q A)a0\<$Iy"ce.$?h "J\Z2_lOmr]x>Dtc{:LT-^'QVR (H|Dhb9CtF}H#y;w!/wآhvw-ƼAoѓ?=;tDŽ d|v|F9%+\Ϳ&FtX)x>bx'"пC.#%?~p>;G#d)?PKzQ PK@1proguard/optimize/info/ParameterUsageMarker.classX]pWY{eNiSY#i$ubZЮ~ݕ iJ -u3aa CừOEN!39wu99s}wRЇIPd9 r S |R/_L#)DSScV̝V`9(xiQEdGT`VǼOYPp䳂|N|^//e|YW$9uiJš\ֲ= Όf>raL-ۺ ˒L҇穬9sfn6Xn629=\6vNaH5A+tnΥ$ W&Ӛei= PP=aL>U(z>]mӘ\D=w!VVU@j<WIpv^W^Wd"76Njr3c;q{xC-ZY/c kTٜ0ذ8'q)gKNx@zy'U 0B\ȯ \?reUs{Ё8,C8g#.DRDhѶ ,_@h=e'10 h낺. N dߋ8DWEqvrqcMu^@@ +ZEn^F k0N܇ |QCF> 0wc|Gq<ˋxP A|݂wK (UkJ^#cvC/fkbwB:); iEBfb–=5f\{fEl*ސB%ܲ_W,sk-吼!-El+ 3BC"|~]`Heb= v:w?pAabevDXt)bG4"+8>/SA[´ٹ獺+1F*w?hyu⌐WmcEP$$I2QƙWFp`RI_Ng]{pSuڛC΄s07PK劬ePK@1proguard/optimize/info/CatchExceptionMarker.classSMo@}q뚖BjJD* zsMđ W.\T8rG!fҒfgv@E󸺀 p] (M 4d5foOC69ò%zEЭs]w(_j]UJOIv`{Mؾ7k=Vf9%(dȭ"o|ˎ.>TZK '|jw戱͂Mø/]R _֭$.w`&Koz| ;z}rXzȼU3bBFS|jK4i}m:& \Ĕi50K:.ǂ7 D3x/t,7 \UX2bUG亪+,;2ռ\""vdVZuc{WͰV_u~R>umf VfꐬF*ZCO >gYc_Of2b}6{nF5t'-dQ͜u ݿ\lEe esekr6:%TOvBjS9~@:8ϾgAGjG'Sql-%PIR/" (OPոOH!=xe|TaBxq㡮OP)8Ʊq|:$tы1 m W6l)݃^ȣ|GC9I,fcIa%,e#|vW`.txxrc;+9 #Oُ* Gn{sL#q7=6 x}BdU4-{h =vQ݈YD_78վf}3C F0wI8N[n ϏԼv+PKCG PK@.proguard/optimize/info/CaughtClassMarker.classOAǿC]X+P~VMj/ML4`8pNmw- O p"ăGQ7jZw?޾߾B΁ :uxb#k㩍g WҗQ!V8d`/>t5>Zԩ eɚaȐ+x4\u-ȖpGٷ~$RQXgBUy9bNvZ18AW,w"V$f$‚Ia]HY ŸA'mO\ :~ݯ5EO )P w~_ 26Dtǫw2esYh$ `4xmqZi^)K+j6 I #S|gJXn05D#`a- ~.}5-xImPۻXa[bc_S )[ҿPKU"PK@Dproguard/optimize/info/PackageVisibleMemberInvokingClassMarker.classSWƟCkiP_*$jKԔh@ ;N2[.#h;Mg^:>$@(ys{{0Mi\IO|b7iawIu0Oqͤ(ng\27 |a`nXeMҭ:nذ@leMW4dcٹGɢ-NVW7wHAľ8Ah@q?8nڞ *oJ8b> :oZ7BQ4>zcaE;:J?ѯIu~72<ͺȰ{;2ذ;v]>"a6省},`nyM*Kc8߹k#}4f ܶP S|;Jba Xp?ca켽udqk^ 3Y^3t-gw G⠃of]'RPI3o^Ct)r}OxVUGe.ki\9 ۣ?wuYdud԰|fUA\vxn^g>CwUmtߗ4)'X)Yfg;̟!.v~D{NKtRiÅ#)t9 D.Ie0L1>i~gP#4CҊ!D*G? Qm$i)"]'hMrc\lC R+y}3s$^Buo0o K|\ !`WqRyJ8ٻqU<2=:MΟ FW$ES#=Y{ PKDnPK@2proguard/optimize/info/ClassOptimizationInfo.classsUǿ7dmMKnVV@ap@tfntnP_/>^xgdtW(I%\6!ߓsϹ=`8"9."oeE{d'qJ䴉^G F_+,xA4tPܜ;žzGW"' GPp[ ͵Npyt?tזV0-wPnVh;Z]"+^ӭqmcBgҕk |*X|b[pW vfÌ޾Mwm|W/W\lhLUf;̚d}v䭱.R/&n0r1p:xM(XWv^Z'Vu=,`vKdDdT$2&2. _d&p 8wvJZKKnoĠ{,Uu>X>}CJ忔4ܵ#m)c-%F}Mm~ e!%1D2"YS$sQg`W~kD0rJ3qmS8*2qTr_;Rҳ1t2:O}]贎>Kݛ6t{D_`d$m32O3謎)%:Nݟ6uG*#chSG蜎nx":kꢫ_5#PI@jo;Hw!7|Qud;2Mt :FGNN#E'K'ۑ)c1;2mtrtr=|?Q?"~§XjdEOXc )p{|0 춟`XaúC=įu?4PKUVPK@Cproguard/optimize/info/StaticInitializerContainingClassFilter.classYK@Vi}[zT})B=@o4-[D`CP<~(q)*Rdaؙ\;oA8F1asa *U,XfM+k6:\֌.l˸"pwV%f1±N:%/x&K"@(c5OEUry':ڹۑu(yD n%Kqjiyj#TXCJG q $rמhQ(C8u.COaiզez !c.͞`Xuw%Ru*-Cmd$'HAh'\=i QQ#Cl4>Ws3Bw=@ɿ ;M3vJ_7?%H>Y'IW0 PK\\PK@2proguard/optimize/info/InstanceofClassMarker.classUKSA,-OEGDAD !h+(Ofa7P¿͛/VYe3.rҳ}=)ф iF0 & "p)͔4 40aFd)К c;C=nOX9ɛ-ɬc '13F.gWdgp]Gl]XqMxEYDBPTnW)6,@0%D! 5 6 ȩ<*ʟێ0ÈgJLu[ZQW;5,ib%h[ ;m_*k;So=CG+4긋90ᾎ(4<б%ᡎM %v@iڎx.07LdCf3"-xjSV&wwZ&(RNiZ ;CVC-S l杸RλDQsZ8GC<~ y/IkJ5uRp~G/./]lUPKYçzPK@Fproguard/optimize/info/PackageVisibleMemberContainingClassMarker.classTKoQ.P(U^e F%$MQP#pk $ƍ-.\GZH ݜs<{ϙ_!\ **T\R$Cؐ)-)n+`SAJA!HX}O%a1Lnz_2 aH*݆^0N "U.QIyXqJ|FNIn[!,gCfu'di QaΫFw!,rbXհy v4⮆{jX}c2vm1ະυSk1ESqmݜ9ut93ϺPzw:w=h9P4"e6 [Sdj5m'3!7ソn_L+lLVp=79)S`HO*]!m\e4i䈑\i&o`_L2$WzZ&>ZfO?r63D|Ĩ9:n&".nRn :V/]nbcR%HJ%r$wģE<^CyJN^k©e>\PK-j,PK@+proguard/optimize/info/DotClassMarker.classUKSAb>$b?7+)f:f4_.66Vc>ϝx-f:B_WBKV6P2 5_[F4iuE\ÄILi>:.[ô$fG2=[9Gl VA Ėf.#OY?붊a)sGKtK^f x`)#GN?.Y9S=Elm!it4GՏ _lֱsa<鶪= m6_6Ϛꋻhʭ/~*f1tӜRgʫ$N/FC=*eLL.V2d.`=JX aG|#%xCdZ*Ztg*bK2a* 凈_ 2diPKZ5jPK@2proguard/optimize/info/FieldOptimizationInfo.classWs-,qeR'D4iMHl'cSO_+G't2$ilӤy!ii0zM3w{w!h{㻧Љ+c4638wq$zG ;gQ`ZY~ #"xzKl/&/y^ J%&6fZj4ऌS t!fQgE/xYThﱾTzdph\ϕT+ӪQRm=o&N$ B'umT[%O FlmfVMg%t鰄z8$Ԭ{5+Zj M05Mjx'(ya*JuSHx4 1n$>ӧ #>&!g~ aqv,2/~Z$us2*,ǫ qc+q1VLn]Z5/l-9a K5fmGAs 3k_Is3`5/x*<Қi)Tʶ-}]aBydň̽%UAeS?qFjUË#괚4T3&A3׽xm Aqk_zR ">fSB'G.l+ v`$KxjL$d0*sylUu `@N;[2m)Ļ 2>P!>R@X9W .(| [R1 S+M =*5?{KV3&PnO# >ǟ$=ϸįϕuSTй !㟡.KhP֍>U0Ⱦz)^^6}SRS&>C5#ᧁU}w,US'VM&7{DQFU,!-AG4u -al%#b%sHz1qǪ.mV̊ZTlHS%xJH{NRTBX=MWiU U5Xk?okc=. 5c# J9DpplW0\ Ir"V%cF?(~ӟ 'h O=hGih9ffҧ֟ӻCx|R!&ং[ f)]a=`pf #zRin9 슒ⅽddeF} U4ffzN+"ǣsZYk#㸤Y)e$!^ŒN`Qm0"& rk܃@0)XͩB)X0'}2~JMܓ 1 BZ%#=%.wJ*f ŖlF(4ʦ Lu.Աoyj*zЫ`^,ETİྊXVUıbOzU!i0ȋ}VFY>eK䢛"_̉-\ .Q4ZqZAX-kځU۞rMϊQKV$ߑ/I]N =*X^\ya1^gV֕u8 àɳgJ5رM 7 |vu$/,=iɗ~.B7H G3?FO+gW:B:*!; lrٰQ ~ۅ:ɛ'y1R 26 s|mmNV^ lF {:H7 l< :D{O `ʿMq^g\e/PKёPK@9proguard/optimize/info/MemberOptimizationInfoSetter.classS]OQ=.  T @YB0ԘB|[کn>/|GfM!mbxs̜sf?vi"0kb&h`s/2B:T9j0uM:k5(\ns"Ns8ZNPuvE␄. yQ]ݬxJ%Ȗ)jk~lֽ iM7Xøe +xi`^YXdž^_rB`U'Tn.יjxKmw=~bN|T3^'eC*Iv~w !DM\8PxL*-IboAs Fi*d5"Vݺ)'fb纬&z LBƶŦo!qp[4 z#IL ܇ @}*oPK%qPK@3proguard/optimize/info/MethodOptimizationInfo.classV]lWzc:vSu$-i4ㄸIwǛIֳfgmҒ:м*Ax@TT OLhnrQ;7l+.1uaft=S.CUX1Ʋ:kY>Ѷg/}K ]{e?$ӛBxcCt(qA=AtH[lGA?Rs'E' o=u}zwk?Ɔ" u8`W)66El=|yOɅ`S3>O?Y}#bq_˺,W>@\onA.^ ^owroCA.תXu-rB 9߷sʏxOĘ ݌S>}a??1]L5#i?h0ǼwO$Џ|"7K~,cnY">tftfC-3-kLp-k+EYD9P n*̯Xl(:axGU1F4xZ 8PT,SL/r0fIEq!BIVhBI鲾Z1C1u+CV qH ގ9ͤh$>nT'ʽJRcيQX^ 2.d s\@uά*MbbEz{w[\VqM6+A㌣D&dYYl׊zQ'SIM?V^7e pH=yHIHV7ΙmECV dE(VpMBy 6(H0P):np3"⑄ؒ 7/%2>q``T1㴊 V\ѰW%bRE^bJ ZisbXxE7ߟ/xn,'_P\R1ኼi{lS3^4\Ɣ#c-2Tu(dՉVVO^jqrBA〕g=o53( '9exk=XW?js6z5`y]銉 Ȕa3ZSXF @=|;|#kXF AvOg G;XEtFޜp Z>>5857&-읂u6CL$oŷg ;Ǫd5U [i-ה ,_KUFF> Gڨ+'j1_+xSKQpWd ^ R<^Z+?*e֌eS{` 6pŸfdegc ղN5E%fZqTb-ݩ& M#h ,YLPg_n (QuSqDH0W0{GBFY ̡7c ^`0%XV~$~kBq+s++o,sfsj1Tx u$BHmvb[\YSc"K(o~ [4= , 7Q(, )X[KR.犅GDa2KJBE()pgrlb>|d>"o?F8% Kσ$$5]O .?dr3ƪ F5$1'4¸ 1ѐ]SqO}#p+jCm"%j.m*M 98 D}O,؄ HķiQplJ2e5J=瑦1=+Xmh(ׂ0PLjV׿⯒z?Sdq .PK DPK@1proguard/optimize/TailRecursionSimplifier$1.class= @-< A8 M$x(qZ cz< .J4;%zIc+)L,y(lL/>q-a^"m=DEYK.W~Okc.*5ʤfqRf+1qi]w'PK{PK@)proguard/optimize/ParameterShrinker.classU[oE&lF7^(-YZ!I)jbDebO)jw Q@R+M'٤N839?` :ՐqҊdtd(ts kJ]PyEq  ˋs ÑBnDaX <^K%U/ǐ)^^ͪ-m$Cu+>^Bڄ(\bhY }%鈫-}e0z@(r> O.˜Qd' djAB[E"Xic>BzbV ]o@xO:o&_aD84 $1lyaEᒁ)\P00 "x%jN3nkl5a !!V m,-/C+ԶD:p}^ #ꯋ`7PRf8Dw-]dH(#iW=ьr=%uj͝U4:5F/LUgm^!'\AmipL:`Hk(]QAw*\EUjVM12 a,i<9e s=7~/h.Gt'ii9p&. .=U7J2/03l^8BՉ#PdG<(@WWD>@bw P z}XG1C6Lj`Bzm[E ?6壹Baz>fFj>zq3>Ef,uS7w03M??{-HI'B>7U-`]gwÌ;;BbI!z"},S5ʦLUvg Q['Q wOg/?m|7G|G/gy?PKaط[PK@1proguard/optimize/DuplicateInitializerFixer.classWwSEY^䉲H(Jŀh -DZC^0M[ .o;FSPxт "襯F\J]"c-|؍+\zl}R \_y'~\˛w=Ǽ!(Go"2P;5b'n7r!/r &: >0Xv Y0k}aF<3L%g*YKuQA { gæthj&LMjޫ=?h)z&*1elK꯮]^ZGgTN-nҭJ$rf{Pjg:ꂔŹ`4 J(6,-7foda{]pBTF 5s?Ԁg!x}G)LVd[nܮޖM(2klؤTUEUo[YΖW[zZx_oZZ1՚ /ߩR$%ip!.0QHIvw KðTq)0GJn0CY.>5>  ⲇ#c ::Ԍ`;;϶"WxB“')<-!, 8 9驤fHS9zFF;>UԊ$Ks=|F !cbL:NlIJiiHCE87G]E>bPDvቹ2Mxa]_KvZZݎVsHN]q4X f__7C4Ye{8E̎yIG$98pc3y Y|G ]\jƕhVA ЋRD5뱖VaWYhj!` (5ǩ 4aDȥe"dm3yڵrqá#l89~Ax#~O4"aU-\N0ӼzsVqt,$[v6cX$~H#.gsͥ΅'b3s<6 &LIdއ4 {~8U/W_I’ư>Ļc,91y17t.yhpp҈C`ªlw|I?XB|KGIwh~JwJ[e;X9J9|)/L|=ɔۗHLov;;PKiPK@/proguard/optimize/TailRecursionSimplifier.classXWdvgw2%RWyl6 K,!A)dv]ggV-VZJ6Ղ&hhm}ԊVmZ~Wϝll^T>ɜ{̹{9{^+X^lDT"IF. :9;&B !rxa^K%a,ŰZxZ+$H@;l>E)J椙J+f4Y: L 9Q^vp-_MDeiKOt')Re>T-jBX>mI$-[Ѣw'zn aʖbviN͊% |$aI7⺡E= ͺ[[ ךv;4s'Ζ0 Gg9s6ah JQۛ_p.!:K}wܷk̺7M1 ٚ.Z8=n8ᰪ%9L0 O-;N[G1nLb7$URUk2y~-r{[z +YJs$Ҧ5|/oC!Eƽh {9eړ0l8iO}^Fvh@!^u2[ďdd/)~&e\qeG_ǀ E\qWedxkFoeqd|0&LPcc"+{m+4q9مwd 3"2tpWn!4+Җ@!j(}=IHwk2dޗO|P5j[SĸR:c_fN(;7LiC(qnbXgMWdotscfS*&A̢֨sQ`҄0vj+])hRR5]O8z^f5kF2puh]M[3S6祸 I (m|ڈo"3 ["%Ԍhҡ@xs$U% kyϔJ 8Y+ӥ;T-A͉DTM;FD$2{F\)!z*iޠg2Ÿ[pfjj ?uMtusq"TWt̴3* +JW#웪XjU$l?r,7vy3U66-zNk0Gi|˾a/W!PꥫeF\yǠ[cۃyucwgS̭YO&b3X+t=] %Ģ~ /.UvKU^C!=t;QpɾD|0ެ/+B( AhkAlxCeFЌV an[Vm^&U~E /=60O\v BCpg07AqEYy(qӸy7qo+2}T=UıX !؀4y0y(1t >UV覶O ̟h'1O*Og FüW?:{z.SS  y>_`Q{/v}KjĀ؏qz|/8ww8K++2 G<63m> ZfHp|"i[X" s`F-jEvPb"(xQP'q% [xo*"zRU!>uB<@nq\Iv᮶Џ9YIAP|MtϿh|D=U8`!P NS F˨ SH!^ŚqᶊAF~V<TH H-2\>e7|ݶKh&ǝ;\F 9)zο+eSY1=T|HQ6\&ވHCX/Al B?^ Hr!_MaN GGrl*XpO@Gv2kCfOqE`m|12kg,A}0X?(۲BpL;H.Mbp~$3&i~L3ez_Fv~M`m.E="Jp\FveI=  n&L ~FxT`q~NW2Nrf36%ꏨ} )PS0M iտ%̩>3f~77J09]*zIlFӸ%m.Rk5YwvU1{zD>v+1*3E)ჭ=tWB@tp/;bjzDCAz:~}i.?!˧qP(tfP@e5N](sM|ʡ D u%2T>r)bjnx[$3ȝctէ Ϗ(ՈhUbz}ZApP4iY%ֵkޟ'f6"-G 5׫%~&쉬Id1ťHh- ݸ3A'răQ[3$5P"CQk/mnʰn_ҬFA1qڈ(^]g}F8#0͎Qj$ sIa5(_4RQj3 `O 1nWV]<£ve'1 P:-N}&<ȇu{ F0 5Fqcf1Z&gr#)L^j I:zހ!>i(ك0f~@X[K,3! dV}>sɟv!Cu0'}!߇!>xM D-b؇ aˌr2ɑ:q z9|vDLІC^$̋z0͉%pr܋/T6]DZ 5iCOl*g2C {YH|wJQYdTeҐzM7ِh&3ƎȆh<'23] O@[X?f' NGLԤaB@ES̽RF_ I&`u\`[5"OӚf t8ʔME(kIƌ+BjLcΟ֩ _+n u %6OfM?FN,}'{@wS!t0ٴJG% A VIS_ jke%EzvR`u#+'QZMVP^0fb1>в%f}]+烲cJDc j;*jNQLÇXShib8S6/R.SD qa?(.ow.C5J//b=D˦^-til -.bzlUg9l:9"9l!Pt})Ŀ6@In\NAc?PK- PK@proguard/LineWordReader.class}R]oQ=ҥmQuZE탵5셬],?K &>2ΰ;3̹?"sX-6U*0(/rpO$6ٗerT@—-}Ge:Yw\Ho@ʖ݆tsm-0E%u=]bYӖ;ؾgK3[M!#tH8*%𯙲mֽŠW7^Q[^oHA Ô=g.3xa lkxtgfS\pGhx'|zJ&Eiuَzoiqf"z*ZXEcV+=/ʗ:%cVYeI ΈjV0 #XIgq HedM>F>]@7N)NJ1p|8TĻ#ȍo2H 5‰!n_?CS5Jmu,=hhLqy54>s Z[ PK0#PK@ META-INF/PK@$`c=META-INF/MANIFEST.MFPK@v8 %proguard/DataEntryWriterFactory.classPK@% proguard/ClassPathEntry.classPK@5. & proguard/shrink/InnerUsageMarker.classPK@`: 'rproguard/shrink/ShortestUsageMark.classPK@etia Aproguard/shrink/ShortestUsageMarker$MyRecursiveCauseChecker.classPK@l{*proguard/shrink/InterfaceUsageMarker.classPK@h+*~proguard/shrink/ShortestUsagePrinter.classPK@V0{6  )"proguard/shrink/ShortestUsageMarker.classPK@3 E+-(proguard/shrink/AnnotationUsageMarker.classPK@6Q_&M0proguard/shrink/UsedMemberFilter.classPK@#2proguard/shrink/UsageMarker$1.classPK@δnA3proguard/shrink/UsageMarker$MyPossiblyUsedMemberUsageMarker.classPK@ꔟ#=6proguard/shrink/UsageMarker$MyNonEmptyMethodUsageMarker.classPK@;Pj%t9proguard/shrink/UsedClassFilter.classPK@??P%8;proguard/shrink/UsageMarker$MyInterfaceUsageMarker.classPK@;+=proguard/shrink/ShortestUsageMarker$1.classPK@ob&">>proguard/shrink/UsageMarker$MyBootStrapMethodUsageMarker.classPK@ɂ.?5uBproguard/shrink/ClassShrinker$SignatureShrinker.classPK@m‡ &#Gproguard/shrink/ClassShrinker.classPK@[y "Qproguard/shrink/UsagePrinter.classPK@Z4%Wproguard/shrink/ClassShrinker$1.classPK@:/znWproguard/shrink/Shrinker.classPK@8O!_proguard/shrink/UsageMarker.classPK@c֣~L62uproguard/evaluation/value/IdentifiedValueFactory.classPK@:5xproguard/evaluation/value/ConvertedIntegerValue.classPK@S۴4izproguard/evaluation/value/ConvertedDoubleValue.classPK@a1|proguard/evaluation/value/UnknownFloatValue.classPK@2proguard/evaluation/value/ConvertedByteValue.classPK@Ԁ/A 0 proguard/evaluation/value/UnknownLongValue.classPK@y5proguard/evaluation/value/IdentifiedDoubleValue.classPK@\a 3"proguard/evaluation/value/UnknownIntegerValue.classPK@D/)proguard/evaluation/value/ComparisonValue.classPK@Bjg4proguard/evaluation/value/CompositeDoubleValue.classPK@K<.proguard/evaluation/value/Category1Value.classPK@mde2proguard/evaluation/value/NegatedDoubleValue.classPK@jpZ01Sproguard/evaluation/value/SpecificLongValue.classPK@9} *proguard/evaluation/value/FloatValue.classPK@4proguard/evaluation/value/IdentifiedFloatValue.classPK@:vub3\proguard/evaluation/value/ParticularLongValue.classPK@wC?C)proguard/evaluation/value/LongValue.classPK@5>6~3proguard/evaluation/value/ConvertedFloatValue.classPK@m#c.. proguard/evaluation/value/Category2Value.classPK@I;q ,Qproguard/evaluation/value/IntegerValue.classPK@3proguard/evaluation/value/NegatedIntegerValue.classPK@GvŸ +proguard/evaluation/value/DoubleValue.classPK@bձd2#proguard/evaluation/value/UnknownDoubleValue.classPK@*,4proguard/evaluation/value/ValueFactory.classPK@WT7 ~.proguard/evaluation/value/ReferenceValue.classPK@{ 4proguard/evaluation/value/ParticularFloatValue.classPK@wz57 2proguard/evaluation/value/SpecificFloatValue.classPK@6#7Jproguard/evaluation/value/ConvertedCharacterValue.classPK@BԃQ}6proguard/evaluation/value/ParticularIntegerValue.classPK@W 3[proguard/evaluation/value/CompositeFloatValue.classPK@ %iproguard/evaluation/value/Value.classPK@u1proguard/evaluation/value/NegatedFloatValue.classPK@Ĥ_t 6proguard/evaluation/value/InstructionOffsetValue.classPK@Kc0proguard/evaluation/value/NegatedLongValue.classPK@x3proguard/evaluation/value/IdentifiedLongValue.classPK@s0 5proguard/evaluation/value/ParticularDoubleValue.classPK@!J3proguard/evaluation/value/ConvertedShortValue.classPK@leE 3 proguard/evaluation/value/SpecificDoubleValue.classPK@5_proguard/evaluation/value/CompositeIntegerValue.classPK@ $z2proguard/evaluation/value/ConvertedLongValue.classPK@2Y0 4 proguard/evaluation/value/SpecificValueFactory.classPK@ݎkBNH4proguard/evaluation/value/SpecificIntegerValue.classPK@s6Sproguard/evaluation/value/IdentifiedIntegerValue.classPK@#2proguard/evaluation/value/CompositeLongValue.classPK@|#81proguard/evaluation/value/IdentifiedReferenceValue.classPK@)'(zproguard/evaluation/value/TopValue.classPK@GOƗg%!proguard/evaluation/TracedStack.classPK@^D؉)(proguard/evaluation/TracedVariables.classPK@r!)s-proguard/evaluation/BasicBranchUnit.classPK@W{y3_0proguard/evaluation/ClassConstantValueFactory.classPK@|kmd0(M2proguard/evaluation/InvocationUnit.classPK@ξt$3proguard/evaluation/BranchUnit.classPK@ȹ .4proguard/evaluation/ConstantValueFactory.classPK@ݽbR#R9proguard/evaluation/Variables.classPK@m'[?#Aproguard/evaluation/Processor.classPK@ C o0Xproguard/evaluation/Stack.classPK@ph -aproguard/evaluation/BasicInvocationUnit.classPK@Sv kproguard/ProGuard.classPK@ Q&xproguard/classfile/LibraryMember.classPK@ɞeT 6{proguard/classfile/instruction/SimpleInstruction.classPK@Y=NW6Kproguard/classfile/instruction/SwitchInstruction.classPK@C(+9proguard/classfile/instruction/InstructionConstants.classPK@ W?aproguard/classfile/instruction/visitor/InstructionCounter.classPK@ko D%proguard/classfile/instruction/visitor/MultiInstructionVisitor.classPK@M -?proguard/classfile/instruction/visitor/InstructionVisitor.classPK@Bproguard/classfile/instruction/visitor/AllInstructionVisitor.classPK@)wG;proguard/classfile/instruction/TableSwitchInstruction.classPK@% 6{proguard/classfile/instruction/BranchInstruction.classPK@&5d8proguard/classfile/instruction/ConstantInstruction.classPK@_Z<kproguard/classfile/instruction/LookUpSwitchInstruction.classPK@ 4/proguard/classfile/instruction/InstructionUtil.classPK@|xu58sproguard/classfile/instruction/VariableInstruction.classPK@9 0Nproguard/classfile/instruction/Instruction.classPK@Uj 7sproguard/classfile/instruction/InstructionFactory.classPK@d\;proguard/classfile/attribute/EnclosingMethodAttribute.classPK@E䳁y;proguard/classfile/attribute/LineNumberTableAttribute.classPK@I76proguard/classfile/attribute/BootstrapMethodInfo.classPK@H\\6{proguard/classfile/attribute/SourceFileAttribute.classPK@{Y5;proguard/classfile/attribute/SyntheticAttribute.classPK@ 3 proguard/classfile/attribute/UnknownAttribute.classPK@=MC3Zproguard/classfile/attribute/InnerClassesInfo.classPK@w[Bproguard/classfile/attribute/LocalVariableTypeTableAttribute.classPK@e8/0proguard/classfile/attribute/CodeAttribute.classPK@J<"proguard/classfile/attribute/BootstrapMethodsAttribute.classPK@k9proguard/classfile/attribute/ConstantValueAttribute.classPK@XHs+>zproguard/classfile/attribute/visitor/AllAttributeVisitor.classPK@&xv+Bproguard/classfile/attribute/visitor/InnerClassesInfoVisitor.classPK@tb Hproguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.classPK@fAEproguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.classPK@![" @proguard/classfile/attribute/visitor/MultiAttributeVisitor.classPK@U['>nproguard/classfile/attribute/visitor/AttributeNameFilter.classPK@.)MbBproguard/classfile/attribute/visitor/AllExceptionInfoVisitor.classPK@kn_Eproguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.classPK@AUG <{proguard/classfile/attribute/visitor/StackSizeComputer.classPK@AķN?proguard/classfile/attribute/visitor/ExceptionInfoVisitor.classPK@϶nG#proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.classPK@E(#BVproguard/classfile/attribute/visitor/NonEmptyAttributeFilter.classPK@o;proguard/classfile/attribute/visitor/AttributeVisitor.classPK@͖^CNproguard/classfile/attribute/visitor/LocalVariableInfoVisitor.classPK@ ŭ&$B{proguard/classfile/attribute/visitor/RequiredAttributeFilter.classPK@PR@&proguard/classfile/attribute/visitor/LineNumberInfoVisitor.classPK@bp-55'proguard/classfile/attribute/SignatureAttribute.classPK@e@;fZ4V*proguard/classfile/attribute/LocalVariableInfo.classPK@ 8-proguard/classfile/attribute/InnerClassesAttribute.classPK@eQ?g/proguard/classfile/attribute/annotation/ArrayElementValue.classPK@b ;F1proguard/classfile/attribute/annotation/EnumConstantElementValue.classPK@}P4proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.classPK@=*86proguard/classfile/attribute/annotation/Annotation.classPK@H4R:proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.classPK@kChY7<proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.classPK@}%̿&H&>proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.classPK@'j[e@proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.classPK@B>e JXBproguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.classPK@[>b5I5Eproguard/classfile/attribute/annotation/visitor/ElementValueVisitor.classPK@z̙vGFproguard/classfile/attribute/annotation/visitor/AnnotationVisitor.classPK@X^dJGproguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.classPK@05\O6Kproguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.classPK@ ZKrMproguard/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.classPK@$ʋDOproguard/classfile/attribute/annotation/AnnotationElementValue.classPK@BQproguard/classfile/attribute/annotation/ConstantElementValue.classPK@!~sKTproguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.classPK@Fauj:Vproguard/classfile/attribute/annotation/ElementValue.classPK@#?zYproguard/classfile/attribute/annotation/ClassElementValue.classPK@߂=B \proguard/classfile/attribute/annotation/AnnotationsAttribute.classPK@pa08^proguard/classfile/attribute/LocalVariableTypeInfo.classPK@;]5waproguard/classfile/attribute/SourceDirAttribute.classPK@d@S&,7cproguard/classfile/attribute/Attribute.classPK@Sg+>fproguard/classfile/attribute/LocalVariableTableAttribute.classPK@ra6`iproguard/classfile/attribute/ExceptionsAttribute.classPK@ct0kproguard/classfile/attribute/ExceptionInfo.classPK@^D%nproguard/classfile/attribute/preverification/StackMapAttribute.classPK@v@+:pproguard/classfile/attribute/preverification/TopType.classPK@ڧ=-@Isproguard/classfile/attribute/preverification/SameZeroFrame.classPK@l[+ @uproguard/classfile/attribute/preverification/MoreZeroFrame.classPK@sq>}zproguard/classfile/attribute/preverification/IntegerType.classPK@$$5?|proguard/classfile/attribute/preverification/SameOneFrame.classPK@~j1Hzproguard/classfile/attribute/preverification/UninitializedThisType.classPK@ :BD Jproguard/classfile/attribute/preverification/VerificationTypeFactory.classPK@dIproguard/classfile/attribute/preverification/StackMapTableAttribute.classPK@wR.<proguard/classfile/attribute/preverification/FloatType.classPK@v4E <؋proguard/classfile/attribute/preverification/FullFrame.classPK@S.@proguard/classfile/attribute/preverification/LessZeroFrame.classPK@q'=@proguard/classfile/attribute/preverification/DoubleType.classPK@((^@proguard/classfile/attribute/preverification/StackMapFrame.classPK@ ]OR/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.classPK@iOproguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.classPK@Ģ;proguard/classfile/attribute/preverification/NullType.classPK@j&!Cproguard/classfile/attribute/preverification/VerificationType.classPK@@;proguard/classfile/attribute/preverification/LongType.classPK@GDYproguard/classfile/attribute/preverification/UninitializedType.classPK@!v(=proguard/classfile/attribute/preverification/ObjectType.classPK@vw1proguard/classfile/attribute/LineNumberInfo.classPK@B6qproguard/classfile/attribute/DeprecatedAttribute.classPK@O:'Xproguard/classfile/ClassConstants.classPK@>[tproguard/classfile/Field.classPK@ 6Bproguard/classfile/io/ProgramClassWriter$AttributeBodyWriter.classPK@S~p3Aproguard/classfile/io/ProgramClassWriter$ConstantBodyWriter.classPK@b+y!_p.Tproguard/classfile/io/ProgramClassReader.classPK@a-)proguard/classfile/io/RuntimeDataOutput.classPK@SN .proguard/classfile/io/LibraryClassReader.classPK@[ Eproguard/classfile/io/ProgramClassWriter$ElementValueBodyWriter.classPK@] . proguard/classfile/io/ProgramClassWriter.classPK@N0proguard/classfile/io/ProgramClassWriter$1.classPK@J\Fproguard/classfile/io/ProgramClassWriter$StackMapFrameBodyWriter.classPK@},proguard/classfile/io/RuntimeDataInput.classPK@hkI|proguard/classfile/io/ProgramClassWriter$VerificationTypeBodyWriter.classPK@[#m & proguard/classfile/ProgramMember.classPK@gM$3%proguard/classfile/editor/VariableSizeUpdater.classPK@ȓ`C3(proguard/classfile/editor/CodeAttributeEditor.classPK@1;5-=proguard/classfile/editor/ConstantAdder.classPK@^!|M0ZEproguard/classfile/editor/InstructionAdder.classPK@ s04Hproguard/classfile/editor/StackSizeUpdater.classPK@]9Z;5PJproguard/classfile/editor/CodeAttributeComposer.classPK@F\;\^proguard/classfile/editor/CodeAttributeEditorResetter.classPK@WE0 1f`proguard/classfile/editor/BridgeMethodFixer.classPK@o =+dproguard/classfile/editor/AccessFixer.classPK@$Ejproguard/classfile/editor/LocalVariableTypeTableAttributeEditor.classPK@A:AT:mproguard/classfile/editor/LocalVariableTypeInfoAdder.classPK@N`g-oproguard/classfile/editor/SubclassAdder.classPK@BwCqproguard/classfile/editor/AccessFixer$MyReferencedClassFinder.classPK@8z/tproguard/classfile/editor/VariableCleaner.classPK@N/u I2zproguard/classfile/editor/ConstantPoolEditor.classPK@F .Oproguard/classfile/editor/VariableEditor.classPK@Y5proguard/classfile/editor/MethodInvocationFixer.classPK@X6PI /proguard/classfile/editor/AnnotationAdder.classPK@.tt1proguard/classfile/editor/InstructionWriter.classPK@JcBCproguard/classfile/editor/ParameterAnnotationsAttributeEditor.classPK@42eO4sproguard/classfile/editor/ConstantPoolRemapper.classPK@vE/3:proguard/classfile/editor/ClassReferenceFixer.classPK@>\-Aproguard/classfile/editor/LocalVariableTableAttributeEditor.classPK@f$ &4 proguard/classfile/editor/MemberReferenceFixer.classPK@; f 3Cproguard/classfile/editor/ElementValuesEditor.classPK@5proguard/classfile/editor/NamedAttributeDeleter.classPK@LiK2proguard/classfile/editor/ExceptionInfoAdder.classPK@%3Xproguard/classfile/editor/LineNumberInfoAdder.classPK@ڼ:$ Hproguard/classfile/editor/CodeAttributeEditor$CompositeInstruction.classPK@~Z D 3/proguard/classfile/editor/NameAndTypeShrinker.classPK@⡋6proguard/classfile/editor/LocalVariableInfoAdder.classPK@. -4,proguard/classfile/editor/Utf8Shrinker.classPK@@5a7Iproguard/classfile/editor/InnerClassesAccessFixer.classPK@Nk:+1proguard/classfile/editor/ClassEditor.classPK@ ſ.proguard/classfile/editor/InterfaceAdder.classPK@kG4proguard/classfile/editor/ConstantPoolShrinker.classPK@55proguard/classfile/editor/CodeAttributeEditor$1.classPK@ &21proguard/classfile/editor/ElementValueAdder.classPK@}T'2Fproguard/classfile/editor/ComparableConstant.classPK@iyZ1proguard/classfile/editor/ClassMemberSorter.classPK@O>/H!proguard/classfile/editor/InterfaceSorter.classPK@c0E&proguard/classfile/editor/VariableRemapper.classPK@ha/5+proguard/classfile/editor/SubclassToAdder.classPK@@Mt2,proguard/classfile/editor/ConstantPoolSorter.classPK@\@o 0=1proguard/classfile/editor/AttributesEditor.classPK@)~: 6proguard/classfile/editor/AnnotationsAttributeEditor.classPK@t5.?8proguard/classfile/editor/ExceptionAdder.classPK@5 L>:proguard/classfile/editor/LineNumberTableAttributeEditor.classPK@{q&9<proguard/classfile/editor/ExceptionsAttributeEditor.classPK@ dp+>proguard/classfile/editor/MemberAdder.classPK@"Ӣ-QFproguard/classfile/editor/AccessFixer$1.classPK@;d/NGproguard/classfile/editor/AttributeSorter.classPK@Җ_2Jproguard/classfile/editor/ClassElementSorter.classPK@|Y 3.Lproguard/classfile/editor/AttributeAdder.classPK@2Wx0Zproguard/classfile/editor/InterfacesEditor.classPK@]proguard/classfile/Member.classPK@I($_proguard/classfile/VisitorAccepter.classPK@J(`proguard/classfile/util/AccessUtil.classPK@c# {(8Lbproguard/classfile/util/InstructionSequenceMatcher.classPK@H&?-qproguard/classfile/util/MemberFinder$MemberFoundException.classPK@xu6 *rproguard/classfile/util/MemberFinder.classPK@lJu 8Gwproguard/classfile/util/DescriptorClassEnumeration.classPK@ l !>|proguard/classfile/util/DynamicClassReferenceInitializer.classPK@5 |53proguard/classfile/util/ExternalTypeEnumeration.classPK@|TwKI%'proguard/classfile/util/ClassUtil.classPK@ӇB&Z/?proguard/classfile/util/SimplifiedVisitor.classPK@z+K:ޭproguard/classfile/util/ClassSubHierarchyInitializer.classPK@']; <proguard/classfile/util/ClassSuperHierarchyInitializer.classPK@sD5proguard/classfile/util/InternalTypeEnumeration.classPK@%a@);?proguard/classfile/util/DynamicMemberReferenceInitializer.classPK@kt),proguard/classfile/util/WarningPrinter.classPK@ʐ,proguard/classfile/util/MemberFinder$1.classPK@2 4\?8proguard/classfile/util/StringReferenceInitializer.classPK@_ *proguard/classfile/util/MethodLinker.classPK@e] *Xproguard/classfile/util/StringSharer.classPK@67 proguard/classfile/util/ClassReferenceInitializer.classPK@Bp&Gproguard/classfile/ProgramMethod.classPK@ % proguard/classfile/LibraryClass.classPK@߃^v5,proguard/classfile/visitor/MemberToClassVisitor.classPK@e|%S/proguard/classfile/visitor/SubclassFilter.classPK@=proguard/classfile/visitor/MethodImplementationTraveler.classPK@ 477 proguard/classfile/visitor/ExceptionHandlerFilter.classPK@ 5? proguard/classfile/visitor/ExceptionRangeFilter.classPK@9o(`:5l proguard/classfile/visitor/DotClassClassVisitor.classPK@]ӹx>/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.classPK@\3Tproguard/classfile/visitor/NamedMethodVisitor.classPK@M91kproguard/classfile/visitor/MemberNameFilter.classPK@Jcf1proguard/classfile/visitor/SubclassTraveler.classPK@~Ah6cproguard/classfile/visitor/ExceptionOffsetFilter.classPK@m -tproguard/classfile/visitor/ClassVisitor.classPK@yUa1rproguard/classfile/visitor/ExceptionCounter.classPK@F(t< 2&proguard/classfile/visitor/ClassAccessFilter.classPK@|1&4proguard/classfile/visitor/ClassPresenceFilter.classPK@-Hk3!proguard/classfile/visitor/MemberAccessFilter.classPK@i1C$proguard/classfile/visitor/AllMethodVisitor.classPK@#5 &proguard/classfile/visitor/SimilarMemberVisitor.classPK@H3g)proguard/classfile/visitor/LibraryClassFilter.classPK@<96+proguard/classfile/visitor/VariableMemberVisitor.classPK@hq2w-proguard/classfile/visitor/MultiClassVisitor.classPK@%i0Z0proguard/classfile/visitor/AllFieldVisitor.classPK@wc0!2proguard/classfile/visitor/MemberCollector.classPK@F埥1U4proguard/classfile/visitor/AllMemberVisitor.classPK@,0|246proguard/classfile/visitor/NamedFieldVisitor.classPK@`a30I8proguard/classfile/visitor/ClassNameFilter.classPK@.B;proguard/classfile/visitor/MemberVisitor.classPK@;P8t<proguard/classfile/visitor/MemberClassAccessFilter.classPK@qx'12*@proguard/classfile/visitor/BottomClassFilter.classPK@޴3Bproguard/classfile/visitor/ClassVersionFilter.classPK@ {.IDproguard/classfile/visitor/MemberCounter.classPK@3 Fproguard/classfile/visitor/MultiMemberVisitor.classPK@#ɥ#-_Iproguard/classfile/visitor/ClassCleaner.classPK@:4pQproguard/classfile/visitor/ExceptClassesFilter.classPK@xDj2Sproguard/classfile/visitor/NamedClassVisitor.classPK@C5Uproguard/classfile/visitor/VariableClassVisitor.classPK@؋x#P7Wproguard/classfile/visitor/MemberDescriptorFilter.classPK@~;Zproguard/classfile/visitor/MethodImplementationFilter.classPK@2ݪ:G0\proguard/classfile/visitor/AllClassVisitor.classPK@!;<90^proguard/classfile/visitor/ClassPoolFiller.classPK@b4(`proguard/classfile/visitor/LibraryMemberFilter.classPK@H`  7bproguard/classfile/visitor/ReferencedClassVisitor.classPK@S@iproguard/classfile/visitor/ExceptionHandlerConstantVisitor.classPK@JK:kproguard/classfile/visitor/ConcreteClassDownTraveler.classPK@*@%nproguard/classfile/visitor/ImplementingClassConstantFilter.classPK@H>J-Npproguard/classfile/visitor/ClassCounter.classPK@ \M#-qproguard/classfile/visitor/ClassPrinter.classPK@ΫHG 3proguard/classfile/visitor/SimpleClassPrinter.classPK@Q_k6proguard/classfile/visitor/MultiClassPoolVisitor.classPK@Zz~3proguard/classfile/visitor/ClassVersionSetter.classPK@kgM 8proguard/classfile/visitor/ReferencedMemberVisitor.classPK@ 0@2dproguard/classfile/visitor/ExceptClassFilter.classPK@'RM/gproguard/classfile/visitor/ClassCollector.classPK@dH3proguard/classfile/visitor/ProgramClassFilter.classPK@ z?proguard/classfile/visitor/ImplementedClassConstantFilter.classPK@d94proguard/classfile/visitor/ProgramMemberFilter.classPK@% 1ժproguard/classfile/visitor/ClassPoolVisitor.classPK@iBO7proguard/classfile/visitor/ClassHierarchyTraveler.classPK@xƿ7 proguard/classfile/visitor/ImplementedClassFilter.classPK@[{ q.proguard/classfile/Method.classPK@rAM%proguard/classfile/ProgramField.classPK@'%proguard/classfile/LibraryField.classPK@[7"proguard/classfile/ClassPool.classPK@Ogf %proguard/classfile/ProgramClass.classPK@/`dnproguard/classfile/Clazz.classPK@`9.^proguard/classfile/constant/LongConstant.classPK@e/Gproguard/classfile/constant/ClassConstant.classPK@s_]B0proguard/classfile/constant/DoubleConstant.classPK@gǐ7proguard/classfile/constant/InvokeDynamicConstant.classPK@R0proguard/classfile/constant/StringConstant.classPK@ ,"4proguard/classfile/constant/MethodTypeConstant.classPK@$cl-"proguard/classfile/constant/RefConstant.classPK@x]-6proguard/classfile/constant/MethodHandleConstant.classPK@8, 5qproguard/classfile/constant/NameAndTypeConstant.classPK@Cproguard/classfile/constant/visitor/ExceptClassConstantFilter.classPK@oo<;proguard/classfile/constant/visitor/AllConstantVisitor.classPK@s|a&Gproguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.classPK@`˯9<proguard/classfile/constant/visitor/ConstantVisitor.classPK@$';Kproguard/classfile/constant/visitor/MethodrefTraveler.classPK@Ύ;nproguard/classfile/constant/visitor/ConstantTagFilter.classPK@wSb*proguard/classfile/constant/Constant.classPK@EnA<nproguard/classfile/constant/InterfaceMethodrefConstant.classPK@;'=/proguard/classfile/constant/FloatConstant.classPK@O?1proguard/classfile/constant/IntegerConstant.classPK@>~ .proguard/classfile/constant/Utf8Constant.classPK@#3^proguard/classfile/constant/MethodrefConstant.classPK@Vaz2proguard/classfile/constant/FieldrefConstant.classPK@x&proguard/classfile/LibraryMethod.classPK@'Wproguard/UpToDateChecker.classPK@fz+proguard/ClassPath.classPK@W\L  proguard/FileWordReader.classPK@ys2F2P proguard/io/ManifestRewriter$SplitLineWriter.classPK@o %proguard/io/DataEntryObfuscator.classPK@{:)<proguard/io/FilteredDataEntryReader.classPK@Nereproguard/io/DataEntry.classPK@*proguard/io/DataEntryDirectoryFilter.classPK@~Npq% proguard/io/DataEntryNameFilter.classPK@^2[*proguard/io/CascadingDataEntryWriter.classPK@&!=proguard/io/DataEntryWriter.classPK@_!)'!yproguard/io/DirectoryFilter.classPK@mN proguard/io/DirectoryPump.classPK@`!u!proguard/io/DataEntryFilter.classPK@jJfsI"proguard/io/NameFilter.classPK@>!T#J$proguard/io/DataEntryRewriter.classPK@ l#"(proguard/io/DataEntryRenamer.classPK@E+ !',proguard/io/DirectoryWriter.classPK@=XV1proguard/io/ClassRewriter.classPK@;A 4proguard/io/JarWriter.classPK@DC":proguard/io/RenamedDataEntry.classPK@"g O;'D=proguard/io/DataEntryParentFilter.classPK@2>proguard/io/JarReader.classPK@'EAproguard/io/ParentDataEntryWriter.classPK@`|i)Cproguard/io/FilteredDataEntryWriter.classPK@Ql&XFproguard/io/DataEntryClassWriter.classPK@E%5Iproguard/io/ZipDataEntry.classPK@HXnMproguard/io/ClassFilter.classPK@d_Oproguard/io/FileDataEntry.classPK@>!qRproguard/io/DataEntryReader.classPK@i2bSproguard/io/ManifestRewriter$SplitLineReader.classPK@mV +Vproguard/io/ClassReader.classPK@m KP[proguard/io/Finisher.classPK@MY˺W !+\proguard/io/DataEntryCopier.classPK@܄"4cproguard/io/ManifestRewriter.classPK@eproguard/io/DataEntryPump.classPK@<3<'$eproguard/SubclassedClassFilter.classPK@'8BF` G.gproguard/preverify/CodeSubroutineInliner.classPK@D>((rproguard/preverify/CodePreverifier.classPK@@t,Z*proguard/preverify/SubroutineInliner.classPK@3̆/[$+proguard/preverify/Preverifier.classPK@lw Q +"proguard/ConfigurationWriter.classPK@yl,Mproguard/ParseException.classPK@Dphrproguard/Targeter.classPK@z/H!proguard/ArgumentWordReader.classPK@afS pproguard/UpToDateChecker$1.classPK@/d:7 Xproguard/OutputWriter.classPK@<.9#"سproguard/Initializer.classPK@1w6Yproguard/UpToDateChecker$ModificationTimeChecker.classPK@ ~VTproguard/InputReader.classPK@ %sproguard/ConfigurationConstants.classPK@ proguard/util/StringParser.classPK@(1#}proguard/util/SettableMatcher.classPK@/q"proguard/util/FileNameParser.classPK@"  &Vproguard/util/FixedStringMatcher.classPK@Qe$fproguard/util/ExtensionMatcher.classPK@Y*aV #Cproguard/util/ClassNameParser.classPK@` !proguard/util/StringMatcher.classPK@ϣ)proguard/util/VariableStringMatcher.classPK@6ZGproguard/util/OrMatcher.classPK@ٗiB proguard/util/ListUtil.classPK@'proguard/util/NotMatcher.classPK@(Wproguard/util/NameParser.classPK@K t#?proguard/util/ConstantMatcher.classPK@Zproguard/util/ListParser.classPK@ &proguard/util/EmptyStringMatcher.classPK@;o6¤proguard/util/ListMatcher.classPK@0hGproguard/util/AndMatcher.classPK@ɉnaC$sproguard/DuplicateClassPrinter.classPK@^t%proguard/DataEntryReaderFactory.classPK@ɽX! proguard/ClassSpecification.classPK@T6vproguard/Configuration.classPK@\x 5E"proguard/ConfigurationParser.classPK@ehe "5proguard/MemberSpecification.classPK@%x -Q8proguard/FullyQualifiedClassNameChecker.classPK@h4%i?proguard/KeepClassMemberChecker.classPK@ Bproguard/ant/ProGuardTask.classPK@D~+Mproguard/ant/KeepSpecificationElement.classPK@^^l Pproguard/ant/FilterElement.classPK@êj -$Sproguard/ant/ConfigurationTask.classPK@M~; #]proguard/ant/ClassPathElement.classPK@x,_dproguard/ant/ClassSpecificationElement.classPK(\@k w7ilproguard/ant/task.propertiesPK@;w'mproguard/ant/ConfigurationElement.classPK@k Q -@rproguard/ant/MemberSpecificationElement.classPK@tz!W yproguard/WordReader.classPK@;>~5 proguard/obfuscate/MemberObfuscator$MyFixedName.classPK@\*Mi*proguard/obfuscate/SimpleNameFactory.classPK@3?)proguard/obfuscate/MemberNameFilter.classPK@ehTi5%proguard/obfuscate/ClassRenamer.classPK@9ۙ<8ώproguard/obfuscate/ClassObfuscator$MyKeepCollector.classPK@Uv 'Βproguard/obfuscate/MappingPrinter.classPK@~)9*proguard/obfuscate/AttributeShrinker.classPK@J $*proguard/obfuscate/NameFactory.classPK@crv& .proguard/obfuscate/DictionaryNameFactory.classPK@x%2 0proguard/obfuscate/MemberNameConflictFixer.classPK@ ^))proguard/obfuscate/MappingProcessor.classPK@ꐿ (proguard/obfuscate/ClassObfuscator.classPK@|Zj90)proguard/obfuscate/MemberSpecialNameFilter.classPK@*proguard/obfuscate/MemberNameCleaner.classPK@T(S*proguard/obfuscate/SourceFileRenamer.classPK@,>I &Iproguard/obfuscate/MappingKeeper.classPK@ō#+proguard/obfuscate/SpecialNameFactory.classPK@HGL8YOproguard/optimize/evaluation/LoadingInvocationUnit.classPK@ 50bI3 Sproguard/optimize/evaluation/TracedBranchUnit.classPK@>N8Tproguard/optimize/evaluation/StoringInvocationUnit.classPK@8vL WFYproguard/optimize/evaluation/PartialEvaluator$MyInstructionBlock.classPK@8^ƔTZ\proguard/optimize/evaluation/EvaluationShrinker$MyVariableInitializationMarker.classPK@NL83p_proguard/optimize/evaluation/PartialEvaluator.classPK@vK\#4kvproguard/optimize/evaluation/VariableOptimizer.classPK@ M)proguard/optimize/evaluation/EvaluationShrinker$MyStackConsistencyFixer.classPK@R5bproguard/optimize/evaluation/PartialEvaluator$1.classPK@i7jproguard/optimize/evaluation/EvaluationShrinker$1.classPK@zg!*uproguard/optimize/ChangedCodePrinter.classPK@Xg g,proguard/optimize/ConstantMemberFilter.classPK@R|h4proguard/optimize/OptimizationInfoMemberFilter.classPK@mnt/cproguard/optimize/ConstantParameterFilter.classPK@{#)g"4proguard/optimize/KeepMarker.classPK@ ryM!Yproguard/optimize/Optimizer.classPK@_0proguard/optimize/peephole/MethodFinalizer.classPK@7}/proguard/optimize/peephole/ClassFinalizer.classPK@Vo2'proguard/optimize/peephole/PeepholeOptimizer.classPK@P$s < proguard/optimize/peephole/UnreachableExceptionRemover.classPK@ ,3proguard/optimize/peephole/TargetClassChanger.classPK@5; Y3proguard/optimize/peephole/BranchTargetFinder.classPK@&eQ1proguard/optimize/peephole/MemberPrivatizer.classPK@{Ϛ EPproguard/optimize/peephole/RetargetedInnerClassAttributeRemover.classPK@nΉA1]proguard/optimize/peephole/VariableShrinker.classPK@.Eproguard/optimize/peephole/ClassMerger$1.classPK@=O7Cproguard/optimize/peephole/GotoCommonCodeReplacer.classPK@3 $J4proguard/optimize/peephole/ReachableCodeMarker.classPK@O0Q+} proguard/optimize/peephole/NopRemover.classPK@^?Z4' proguard/optimize/peephole/VerticalClassMerger.classPK@'QM r\ proguard/optimize/peephole/InstructionSequenceReplacer$MyReplacementInstructionFactory.classPK@ "3 proguard/optimize/peephole/GotoReturnReplacer.classPK@V߇#, proguard/optimize/peephole/ClassMerger.classPK@]o>v" proguard/optimize/peephole/InstructionSequenceReplacer$1.classPK@N6@C=# proguard/optimize/peephole/InstructionSequencesReplacer.classPK@Y&m 7:& proguard/optimize/peephole/UnreachableCodeRemover.classPK@ю71+ proguard/optimize/peephole/GotoGotoReplacer.classPK@#i,.[/ proguard/optimize/peephole/MethodInliner.classPK@!HLB proguard/optimize/peephole/ClassMerger$FieldOptimizationInfoCopier.classPK@î[6D proguard/optimize/peephole/HorizontalClassMerger.classPK@KX<G proguard/optimize/peephole/InstructionSequenceReplacer.classPK@-#=N proguard/optimize/peephole/InstructionSequenceConstants.classPK@Y3]r proguard/optimize/MemberDescriptorSpecializer.classPK@)=y(v proguard/optimize/KeptMemberFilter.classPK@@N;x proguard/optimize/DuplicateInitializerInvocationFixer.classPK@,,07~ proguard/optimize/BootstrapMethodArgumentShrinker.classPK@զ, proguard/optimize/WriteOnlyFieldFilter.classPK@&' proguard/optimize/KeptClassFilter.classPK@ż"OB proguard/optimize/TailRecursionSimplifier$MyRecursionChecker.classPK@{8J0 proguard/optimize/MethodDescriptorShrinker.classPK@r (3 proguard/optimize/MethodStaticizer.classPK@r2 proguard/optimize/info/InstanceofClassFilter.classPK@pX-0 proguard/optimize/info/VariableUsageMarker.classPK@dŽ1 proguard/optimize/info/BackwardBranchMarker.classPK@.2ְ  C proguard/optimize/info/StaticInitializerContainingClassMarker.classPK@Ue83 proguard/optimize/info/ExceptionInstructionChecker.classPK@Y͉ .+ proguard/optimize/info/CaughtClassFilter.classPK@(F8/ proguard/optimize/info/AccessMethodMarker.classPK@k&'5 proguard/optimize/info/InstantiationClassFilter.classPK@6d+ proguard/optimize/info/DotClassFilter.classPK@xd42e 3y proguard/optimize/info/MethodInvocationMarker.classPK@zQ 3 proguard/optimize/info/SideEffectMethodMarker.classPK@劬e13 proguard/optimize/info/ParameterUsageMarker.classPK@LqN1 proguard/optimize/info/CatchExceptionMarker.classPK@CG 1r proguard/optimize/info/ReadWriteFieldMarker.classPK@U". proguard/optimize/info/CaughtClassMarker.classPK@DnD6 proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.classPK@UV2 proguard/optimize/info/ClassOptimizationInfo.classPK@\\C proguard/optimize/info/StaticInitializerContainingClassFilter.classPK@pn2 proguard/optimize/info/InstanceofClassMarker.classPK@Yçz5h proguard/optimize/info/NoSideEffectMethodMarker.classPK@-j,F proguard/optimize/info/PackageVisibleMemberContainingClassMarker.classPK@Z5j+ proguard/optimize/info/DotClassMarker.classPK@s 2 proguard/optimize/info/FieldOptimizationInfo.classPK@ё5{ proguard/optimize/info/InstantiationClassMarker.classPK@%q9 proguard/optimize/info/MemberOptimizationInfoSetter.classPK@!M"3 proguard/optimize/info/MethodOptimizationInfo.classPK@/0: 3V proguard/optimize/info/NonPrivateMemberMarker.classPK@=ƈf8 proguard/optimize/info/ClassOptimizationInfoSetter.classPK@|Fvs9N proguard/optimize/info/SideEffectInstructionChecker.classPK@ D2 proguard/optimize/info/SuperInvocationMarker.classPK@{1E proguard/optimize/TailRecursionSimplifier$1.classPK@aط[)L proguard/optimize/ParameterShrinker.classPK@i1Z proguard/optimize/DuplicateInitializerFixer.classPK@4A / proguard/optimize/TailRecursionSimplifier.classPK@z* 2/' proguard/ClassSpecificationVisitorFactory.classPK@- $" proguard/DescriptorKeepChecker.classPK@0#( proguard/LineWordReader.classPK;;n6+ proguard4.8/bin/0000775000175000017500000000000011760503005012330 5ustar ericericproguard4.8/bin/retrace.bat0000644000175000017500000000070611503377032014452 0ustar ericeric@ECHO OFF REM Start-up script for Retrace -- companion tool for ProGuard, free class file REM shrinker, optimizer, obfuscator, and preverifier for Java bytecode. REM REM Note: when passing file names containing spaces to this script, REM you'll have to add escaped quotes around them, e.g. REM "\"C:/My Directory/My File.txt\"" IF EXIST "%PROGUARD_HOME%" GOTO home SET PROGUARD_HOME=.. :home java -jar "%PROGUARD_HOME%"\lib\retrace.jar %* proguard4.8/bin/proguardgui.sh0000755000175000017500000000113011627751764015233 0ustar ericeric#!/bin/sh # # Start-up script for the GUI of ProGuard -- free class file shrinker, # optimizer, obfuscator, and preverifier for Java bytecode. # # Note: when passing file names containing spaces to this script, # you'll have to add escaped quotes around them, e.g. # "\"/My Directory/My File.txt\"" PROGUARD_HOME=`dirname "$0"`/.. # On Linux, Java 1.6.0_24 and higher hang when starting the GUI: # http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7027598 # We're using the -D option as a workaround. java -DsuppressSwingDropSupport=true -jar $PROGUARD_HOME/lib/proguardgui.jar "$@" proguard4.8/bin/proguard.bat0000644000175000017500000000065311503376767014667 0ustar ericeric@ECHO OFF REM Start-up script for ProGuard -- free class file shrinker, optimizer, REM obfuscator, and preverifier for Java bytecode. REM REM Note: when passing file names containing spaces to this script, REM you'll have to add escaped quotes around them, e.g. REM "\"C:/My Directory/My File.txt\"" IF EXIST "%PROGUARD_HOME%" GOTO home SET PROGUARD_HOME=.. :home java -jar "%PROGUARD_HOME%"\lib\proguard.jar %* proguard4.8/bin/proguard.sh0000755000175000017500000000057511614343140014517 0ustar ericeric#!/bin/sh # # Start-up script for ProGuard -- free class file shrinker, optimizer, # obfuscator, and preverifier for Java bytecode. # # Note: when passing file names containing spaces to this script, # you'll have to add escaped quotes around them, e.g. # "\"/My Directory/My File.txt\"" PROGUARD_HOME=`dirname "$0"`/.. java -jar $PROGUARD_HOME/lib/proguard.jar "$@" proguard4.8/bin/retrace.sh0000755000175000017500000000063011614343200014306 0ustar ericeric#!/bin/sh # # Start-up script for Retrace -- companion tool for ProGuard, free class file # shrinker, optimizer, obfuscator, and preverifier for Java bytecode. # # Note: when passing file names containing spaces to this script, # you'll have to add escaped quotes around them, e.g. # "\"/My Directory/My File.txt\"" PROGUARD_HOME=`dirname "$0"`/.. java -jar $PROGUARD_HOME/lib/retrace.jar "$@" proguard4.8/bin/proguardgui.bat0000644000175000017500000000067111503377016015360 0ustar ericeric@ECHO OFF REM Start-up script for the GUI of ProGuard -- free class file shrinker, REM optimizer, obfuscator, and preverifier for Java bytecode. REM REM Note: when passing file names containing spaces to this script, REM you'll have to add escaped quotes around them, e.g. REM "\"C:/My Directory/My File.txt\"" IF EXIST "%PROGUARD_HOME%" GOTO home SET PROGUARD_HOME=.. :home java -jar "%PROGUARD_HOME%"\lib\proguardgui.jar %* proguard4.8/README0000644000175000017500000000170311760503005012437 0ustar ericericProGuard, Java class file shrinker, optimizer, obfuscator, and preverifier ========================================================================== This distribution contains the following directories: - bin : simple wrapper scripts to run ProGuard, its GUI, and ReTrace - lib : the main jars, compiled and ready to use with "java -jar ...." - docs : the complete documentation, licenses, etc. in html format - examples : some example configuration files - src : the source code - build : various alternative build scripts The best place to start is docs/index.html Example ======= If you want to give ProGuard a spin right away, try processing the ProGuard jar itself: cd examples java -jar ../lib/proguard.jar @proguard.pro The resulting proguard_out.jar contains the same application, but it's a lot smaller. Enjoy! http://proguard.sourceforge.net/ Copyright (c) 2002-2012 Eric Lafortune (eric@graphics.cornell.edu)