diff options
Diffstat (limited to 'src/proguard/classfile/editor/AttributesEditor.java')
-rw-r--r-- | src/proguard/classfile/editor/AttributesEditor.java | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/proguard/classfile/editor/AttributesEditor.java b/src/proguard/classfile/editor/AttributesEditor.java new file mode 100644 index 0000000..10846cc --- /dev/null +++ b/src/proguard/classfile/editor/AttributesEditor.java @@ -0,0 +1,269 @@ +/* + * 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.*; + +/** + * 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; + } +} |