diff options
Diffstat (limited to 'src/proguard/classfile/editor/MemberAdder.java')
-rw-r--r-- | src/proguard/classfile/editor/MemberAdder.java | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/proguard/classfile/editor/MemberAdder.java b/src/proguard/classfile/editor/MemberAdder.java new file mode 100644 index 0000000..5f939bb --- /dev/null +++ b/src/proguard/classfile/editor/MemberAdder.java @@ -0,0 +1,257 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with 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 ConstantVisitor adds all class members that it visits to the given + * target class. + * + * @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 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. + */ +// * @param addFields specifies whether fields should be added, or fused +// * with the present fields. + public MemberAdder(ProgramClass targetClass)//), +// boolean addFields) + { + this.targetClass = targetClass; +// this.addFields = addFields; + + 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); + } + + + 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); + } + + + // 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())); + } +} |