| /* |
| * 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.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 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 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; |
| } |
| } |