proguard.classfile.editor.AttributesEditor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of proguard-core Show documentation
Show all versions of proguard-core Show documentation
ProGuardCORE is a free library to read, analyze, modify, and write Java class files.
/*
* ProGuardCORE -- library to process Java bytecode.
*
* Copyright (c) 2002-2020 Guardsquare NV
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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;
}
/** Finds the specified attribute in the target. */
public Attribute findAttribute(String attributeName) {
// What's the target?
return targetAttribute != null
? findAttribute(
targetAttribute.u2attributesCount, targetAttribute.attributes, attributeName)
: targetMember != null
? findAttribute(targetMember.u2attributesCount, targetMember.attributes, attributeName)
: findAttribute(targetClass.u2attributesCount, targetClass.attributes, attributeName);
}
/** 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 to 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 =
findAttributeIndex(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 = findAttributeIndex(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 findAttributeIndex(
int attributesCount, Attribute[] attributes, String attributeName) {
for (int index = 0; index < attributesCount; index++) {
Attribute attribute = attributes[index];
if (attribute.getAttributeName(targetClass).equals(attributeName)) {
return index;
}
}
return -1;
}
/** Finds the attribute with the given name in the given array of attributes. */
private Attribute findAttribute(
int attributesCount, Attribute[] attributes, String attributeName) {
for (int index = 0; index < attributesCount; index++) {
Attribute attribute = attributes[index];
if (attribute.getAttributeName(targetClass).equals(attributeName)) {
return attribute;
}
}
return null;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy