Home | History | Annotate | Download | only in editor
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2009 Eric Lafortune (eric (at) graphics.cornell.edu)
      6  *
      7  * This program is free software; you can redistribute it and/or modify it
      8  * under the terms of the GNU General Public License as published by the Free
      9  * Software Foundation; either version 2 of the License, or (at your option)
     10  * any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
     15  * more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, write to the Free Software Foundation, Inc.,
     19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     20  */
     21 package proguard.classfile.editor;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 
     26 /**
     27  * This class can add and delete attributes to and from classes, fields,
     28  * methods, and code attributes. Attributes to be added must be filled out
     29  * beforehand, including their references to the constant pool. Existing
     30  * attributes of the same type are always replaced.
     31  *
     32  * @author Eric Lafortune
     33  */
     34 public class AttributesEditor
     35 {
     36     private final ProgramClass  targetClass;
     37     private final ProgramMember targetMember;
     38     private final CodeAttribute targetAttribute;
     39     private final boolean       replaceAttributes;
     40 
     41 
     42     /**
     43      * Creates a new AttributeAdder that will edit attributes in the given
     44      * target class.
     45      */
     46     public AttributesEditor(ProgramClass targetClass,
     47                             boolean      replaceAttributes)
     48     {
     49         this(targetClass, null, null, replaceAttributes);
     50     }
     51 
     52 
     53     /**
     54      * Creates a new AttributeAdder that will edit attributes in the given
     55      * target class member.
     56      */
     57     public AttributesEditor(ProgramClass  targetClass,
     58                             ProgramMember targetMember,
     59                             boolean       replaceAttributes)
     60     {
     61         this(targetClass, targetMember, null, replaceAttributes);
     62     }
     63 
     64 
     65     /**
     66      * Creates a new AttributeAdder that will edit attributes in the given
     67      * target code attribute.
     68      */
     69     public AttributesEditor(ProgramClass  targetClass,
     70                             ProgramMember targetMember,
     71                             CodeAttribute targetAttribute,
     72                             boolean       replaceAttributes)
     73     {
     74         this.targetClass       = targetClass;
     75         this.targetMember      = targetMember;
     76         this.targetAttribute   = targetAttribute;
     77         this.replaceAttributes = replaceAttributes;
     78     }
     79 
     80 
     81     /**
     82      * Adds the given attribute to the target.
     83      */
     84     public void addAttribute(Attribute attribute)
     85     {
     86         // What's the target?
     87         if (targetAttribute != null)
     88         {
     89             // Try to replace an existing attribute.
     90             if (!replaceAttributes ||
     91                 !replaceAttribute(targetAttribute.u2attributesCount,
     92                                   targetAttribute.attributes,
     93                                   attribute))
     94             {
     95                 // Otherwise append the attribute.
     96                 targetAttribute.attributes =
     97                     addAttribute(targetAttribute.u2attributesCount,
     98                                  targetAttribute.attributes,
     99                                  attribute);
    100 
    101                 targetAttribute.u2attributesCount++;
    102             }
    103         }
    104         else if (targetMember != null)
    105         {
    106             // Try to replace an existing attribute.
    107             if (!replaceAttributes ||
    108                 !replaceAttribute(targetMember.u2attributesCount,
    109                                   targetMember.attributes,
    110                                   attribute))
    111             {
    112                 // Otherwise append the attribute.
    113                 targetMember.attributes =
    114                     addAttribute(targetMember.u2attributesCount,
    115                                  targetMember.attributes,
    116                                  attribute);
    117 
    118                 targetMember.u2attributesCount++;
    119             }
    120         }
    121         else
    122         {
    123             // Try to replace an existing attribute.
    124             if (!replaceAttributes ||
    125                 !replaceAttribute(targetClass.u2attributesCount,
    126                                   targetClass.attributes,
    127                                   attribute))
    128             {
    129                 // Otherwise append the attribute.
    130                 targetClass.attributes =
    131                     addAttribute(targetClass.u2attributesCount,
    132                                  targetClass.attributes,
    133                                  attribute);
    134 
    135                 targetClass.u2attributesCount++;
    136             }
    137         }
    138     }
    139 
    140 
    141     /**
    142      * Deletes the specified attribute from the target.
    143      */
    144     public void deleteAttribute(String attributeName)
    145     {
    146         // What's the target?
    147         if (targetAttribute != null)
    148         {
    149             targetAttribute.u2attributesCount =
    150                 deleteAttribute(targetAttribute.u2attributesCount,
    151                                 targetAttribute.attributes,
    152                                 attributeName);
    153         }
    154         else if (targetMember != null)
    155         {
    156             targetMember.u2attributesCount =
    157                 deleteAttribute(targetMember.u2attributesCount,
    158                                 targetMember.attributes,
    159                                 attributeName);
    160         }
    161         else
    162         {
    163             targetClass.u2attributesCount =
    164                 deleteAttribute(targetClass.u2attributesCount,
    165                                 targetClass.attributes,
    166                                 attributeName);
    167         }
    168     }
    169 
    170 
    171     // Small utility methods.
    172 
    173     /**
    174      * Tries put the given attribute in place of an existing attribute of the
    175      * same name, returning whether it was present.
    176      */
    177     private boolean replaceAttribute(int         attributesCount,
    178                                      Attribute[] attributes,
    179                                      Attribute   attribute)
    180     {
    181         // Find the attribute with the same name.
    182         int index = findAttribute(attributesCount,
    183                                   attributes,
    184                                   attribute.getAttributeName(targetClass));
    185         if (index < 0)
    186         {
    187             return false;
    188         }
    189 
    190         attributes[index] = attribute;
    191 
    192         return true;
    193     }
    194 
    195 
    196     /**
    197      * Appends the given attribute to the given array of attributes, creating a
    198      * new array if necessary.
    199      */
    200     private Attribute[] addAttribute(int         attributesCount,
    201                                      Attribute[] attributes,
    202                                      Attribute   attribute)
    203     {
    204         // Is the array too small to contain the additional attribute?
    205         if (attributes.length <= attributesCount)
    206         {
    207             // Create a new array and copy the attributes into it.
    208             Attribute[] newAttributes = new Attribute[attributesCount + 1];
    209             System.arraycopy(attributes, 0,
    210                              newAttributes, 0,
    211                              attributesCount);
    212             attributes = newAttributes;
    213         }
    214 
    215         // Append the attribute.
    216         attributes[attributesCount] = attribute;
    217 
    218         return attributes;
    219     }
    220 
    221 
    222     /**
    223      * Deletes the attributes with the given name from the given array of
    224      * attributes, returning the new number of attributes.
    225      */
    226     private int deleteAttribute(int         attributesCount,
    227                                 Attribute[] attributes,
    228                                 String      attributeName)
    229     {
    230         // Find the attribute.
    231         int index = findAttribute(attributesCount,
    232                                   attributes,
    233                                   attributeName);
    234         if (index < 0)
    235         {
    236             return attributesCount;
    237         }
    238 
    239         // Shift the other attributes in the array.
    240         System.arraycopy(attributes, index + 1,
    241                          attributes, index,
    242                          attributesCount - index - 1);
    243 
    244         // Clear the last entry in the array.
    245         attributes[--attributesCount] = null;
    246 
    247         return attributesCount;
    248     }
    249 
    250 
    251     /**
    252      * Finds the index of the attribute with the given name in the given
    253      * array of attributes.
    254      */
    255     private int findAttribute(int         attributesCount,
    256                               Attribute[] attributes,
    257                               String      attributeName)
    258     {
    259         for (int index = 0; index < attributesCount; index++)
    260         {
    261             if (attributes[index].getAttributeName(targetClass).equals(attributeName))
    262             {
    263                 return index;
    264             }
    265         }
    266 
    267         return -1;
    268     }
    269 }
    270