All Downloads are FREE. Search and download functionalities are using the official Maven repository.

proguard.classfile.editor.AttributesEditor Maven / Gradle / Ivy

/*
 * 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