| /* |
| * ProGuard -- shrinking, optimization, obfuscation, and preverification |
| * of Java bytecode. |
| * |
| * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| package proguard.classfile.editor; |
| |
| import proguard.classfile.ProgramClass; |
| 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; |
| } |
| } |