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.constant.*;
     25 
     26 /**
     27  * This class can add constant pool entries to a given class.
     28  *
     29  * @author Eric Lafortune
     30  */
     31 public class ConstantPoolEditor
     32 {
     33     private static final boolean DEBUG = false;
     34 
     35     private ProgramClass targetClass;
     36 
     37 
     38     /**
     39      * Creates a new ConstantPoolEditor that will edit constants in the given
     40      * target class.
     41      */
     42     public ConstantPoolEditor(ProgramClass targetClass)
     43     {
     44         this.targetClass = targetClass;
     45     }
     46 
     47 
     48     /**
     49      * Finds or creates a IntegerConstant constant pool entry with the given
     50      * value.
     51      * @return the constant pool index of the Utf8Constant.
     52      */
     53     public int addIntegerConstant(int value)
     54     {
     55         int        constantPoolCount = targetClass.u2constantPoolCount;
     56         Constant[] constantPool      = targetClass.constantPool;
     57 
     58         // Check if the entry already exists.
     59         for (int index = 1; index < constantPoolCount; index++)
     60         {
     61             Constant constant = constantPool[index];
     62 
     63             if (constant != null &&
     64                 constant.getTag() == ClassConstants.CONSTANT_Integer)
     65             {
     66                 IntegerConstant integerConstant = (IntegerConstant)constant;
     67                 if (integerConstant.getValue() == value)
     68                 {
     69                     return index;
     70                 }
     71             }
     72         }
     73 
     74         return addConstant(new IntegerConstant(value));
     75     }
     76 
     77 
     78     /**
     79      * Finds or creates a LongConstant constant pool entry with the given value.
     80      * @return the constant pool index of the LongConstant.
     81      */
     82     public int addLongConstant(long value)
     83     {
     84         int        constantPoolCount = targetClass.u2constantPoolCount;
     85         Constant[] constantPool      = targetClass.constantPool;
     86 
     87         // Check if the entry already exists.
     88         for (int index = 1; index < constantPoolCount; index++)
     89         {
     90             Constant constant = constantPool[index];
     91 
     92             if (constant != null &&
     93                 constant.getTag() == ClassConstants.CONSTANT_Long)
     94             {
     95                 LongConstant longConstant = (LongConstant)constant;
     96                 if (longConstant.getValue() == value)
     97                 {
     98                     return index;
     99                 }
    100             }
    101         }
    102 
    103         return addConstant(new LongConstant(value));
    104     }
    105 
    106 
    107     /**
    108      * Finds or creates a FloatConstant constant pool entry with the given
    109      * value.
    110      * @return the constant pool index of the FloatConstant.
    111      */
    112     public int addFloatConstant(float value)
    113     {
    114         int        constantPoolCount = targetClass.u2constantPoolCount;
    115         Constant[] constantPool      = targetClass.constantPool;
    116 
    117         // Check if the entry already exists.
    118         for (int index = 1; index < constantPoolCount; index++)
    119         {
    120             Constant constant = constantPool[index];
    121 
    122             if (constant != null &&
    123                 constant.getTag() == ClassConstants.CONSTANT_Float)
    124             {
    125                 FloatConstant floatConstant = (FloatConstant)constant;
    126                 if (floatConstant.getValue() == value)
    127                 {
    128                     return index;
    129                 }
    130             }
    131         }
    132 
    133         return addConstant(new FloatConstant(value));
    134     }
    135 
    136 
    137     /**
    138      * Finds or creates a DoubleConstant constant pool entry with the given
    139      * value.
    140      * @return the constant pool index of the DoubleConstant.
    141      */
    142     public int addDoubleConstant(double value)
    143     {
    144         int        constantPoolCount = targetClass.u2constantPoolCount;
    145         Constant[] constantPool      = targetClass.constantPool;
    146 
    147         // Check if the entry already exists.
    148         for (int index = 1; index < constantPoolCount; index++)
    149         {
    150             Constant constant = constantPool[index];
    151 
    152             if (constant != null &&
    153                 constant.getTag() == ClassConstants.CONSTANT_Double)
    154             {
    155                 DoubleConstant doubleConstant = (DoubleConstant)constant;
    156                 if (doubleConstant.getValue() == value)
    157                 {
    158                     return index;
    159                 }
    160             }
    161         }
    162 
    163         return addConstant(new DoubleConstant(value));
    164     }
    165 
    166 
    167     /**
    168      * Finds or creates a StringConstant constant pool entry with the given
    169      * value.
    170      * @return the constant pool index of the StringConstant.
    171      */
    172     public int addStringConstant(String string,
    173                                  Clazz  referencedClass,
    174                                  Member referencedMember)
    175     {
    176         int        constantPoolCount = targetClass.u2constantPoolCount;
    177         Constant[] constantPool      = targetClass.constantPool;
    178 
    179         // Check if the entry already exists.
    180         for (int index = 1; index < constantPoolCount; index++)
    181         {
    182             Constant constant = constantPool[index];
    183 
    184             if (constant != null &&
    185                 constant.getTag() == ClassConstants.CONSTANT_String)
    186             {
    187                 StringConstant stringConstant = (StringConstant)constant;
    188                 if (stringConstant.getString(targetClass).equals(string))
    189                 {
    190                     return index;
    191                 }
    192             }
    193         }
    194 
    195         return addConstant(new StringConstant(addUtf8Constant(string),
    196                                               referencedClass,
    197                                               referencedMember));
    198     }
    199 
    200 
    201     /**
    202      * Finds or creates a FieldrefConstant constant pool entry for the given
    203      * class and field.
    204      * @return the constant pool index of the FieldrefConstant.
    205      */
    206     public int addFieldrefConstant(Clazz  referencedClass,
    207                                    Member referencedMember)
    208     {
    209         return addFieldrefConstant(referencedClass.getName(),
    210                                    referencedMember.getName(referencedClass),
    211                                    referencedMember.getDescriptor(referencedClass),
    212                                    referencedClass,
    213                                    referencedMember);
    214     }
    215 
    216 
    217     /**
    218      * Finds or creates a FieldrefConstant constant pool entry with the given
    219      * class name, field name, and descriptor.
    220      * @return the constant pool index of the FieldrefConstant.
    221      */
    222     public int addFieldrefConstant(String className,
    223                                    String name,
    224                                    String descriptor,
    225                                    Clazz  referencedClass,
    226                                    Member referencedMember)
    227     {
    228         return addFieldrefConstant(className,
    229                                    addNameAndTypeConstant(name, descriptor),
    230                                    referencedClass,
    231                                    referencedMember);
    232     }
    233 
    234 
    235     /**
    236      * Finds or creates a FieldrefConstant constant pool entry with the given
    237      * class name, field name, and descriptor.
    238      * @return the constant pool index of the FieldrefConstant.
    239      */
    240     public int addFieldrefConstant(String className,
    241                                    int    nameAndTypeIndex,
    242                                    Clazz  referencedClass,
    243                                    Member referencedMember)
    244     {
    245         return addFieldrefConstant(addClassConstant(className, referencedClass),
    246                                    nameAndTypeIndex,
    247                                    referencedClass,
    248                                    referencedMember);
    249     }
    250 
    251 
    252     /**
    253      * Finds or creates a FieldrefConstant constant pool entry with the given
    254      * class constant pool entry index, field name, and descriptor.
    255      * @return the constant pool index of the FieldrefConstant.
    256      */
    257     public int addFieldrefConstant(int    classIndex,
    258                                    String name,
    259                                    String descriptor,
    260                                    Clazz  referencedClass,
    261                                    Member referencedMember)
    262     {
    263         return addFieldrefConstant(classIndex,
    264                                    addNameAndTypeConstant(name, descriptor),
    265                                    referencedClass,
    266                                    referencedMember);
    267     }
    268 
    269 
    270     /**
    271      * Finds or creates a FieldrefConstant constant pool entry with the given
    272      * class constant pool entry index and name and type constant pool entry
    273      * index.
    274      * @return the constant pool index of the FieldrefConstant.
    275      */
    276     public int addFieldrefConstant(int    classIndex,
    277                                    int    nameAndTypeIndex,
    278                                    Clazz  referencedClass,
    279                                    Member referencedMember)
    280     {
    281         int        constantPoolCount = targetClass.u2constantPoolCount;
    282         Constant[] constantPool      = targetClass.constantPool;
    283 
    284         // Check if the entry already exists.
    285         for (int index = 1; index < constantPoolCount; index++)
    286         {
    287             Constant constant = constantPool[index];
    288 
    289             if (constant != null &&
    290                 constant.getTag() == ClassConstants.CONSTANT_Fieldref)
    291             {
    292                 FieldrefConstant fieldrefConstant = (FieldrefConstant)constant;
    293                 if (fieldrefConstant.u2classIndex         == classIndex &&
    294                     fieldrefConstant.u2nameAndTypeIndex   == nameAndTypeIndex)
    295                 {
    296                     return index;
    297                 }
    298             }
    299         }
    300 
    301         return addConstant(new FieldrefConstant(classIndex,
    302                                                 nameAndTypeIndex,
    303                                                 referencedClass,
    304                                                 referencedMember));
    305     }
    306 
    307 
    308     /**
    309      * Finds or creates a InterfaceMethodrefConstant constant pool entry with the
    310      * given class name, method name, and descriptor.
    311      * @return the constant pool index of the InterfaceMethodrefConstant.
    312      */
    313     public int addInterfaceMethodrefConstant(String className,
    314                                              String name,
    315                                              String descriptor,
    316                                              Clazz  referencedClass,
    317                                              Member referencedMember)
    318     {
    319         return addInterfaceMethodrefConstant(className,
    320                                              addNameAndTypeConstant(name, descriptor),
    321                                              referencedClass,
    322                                              referencedMember);
    323     }
    324 
    325 
    326     /**
    327      * Finds or creates a InterfaceMethodrefConstant constant pool entry with the
    328      * given class name, method name, and descriptor.
    329      * @return the constant pool index of the InterfaceMethodrefConstant.
    330      */
    331     public int addInterfaceMethodrefConstant(String className,
    332                                              int    nameAndTypeIndex,
    333                                              Clazz  referencedClass,
    334                                              Member referencedMember)
    335     {
    336         return addInterfaceMethodrefConstant(addClassConstant(className, referencedClass),
    337                                              nameAndTypeIndex,
    338                                              referencedClass,
    339                                              referencedMember);
    340     }
    341 
    342 
    343     /**
    344      * Finds or creates a InterfaceMethodrefConstant constant pool entry for the
    345      * given class and method.
    346      * @return the constant pool index of the InterfaceMethodrefConstant.
    347      */
    348     public int addInterfaceMethodrefConstant(Clazz  referencedClass,
    349                                              Member referencedMember)
    350     {
    351         return addInterfaceMethodrefConstant(referencedClass.getName(),
    352                                              referencedMember.getName(referencedClass),
    353                                              referencedMember.getDescriptor(referencedClass),
    354                                              referencedClass,
    355                                              referencedMember);
    356     }
    357 
    358 
    359     /**
    360      * Finds or creates a InterfaceMethodrefConstant constant pool entry with the
    361      * given class constant pool entry index, method name, and descriptor.
    362      * @return the constant pool index of the InterfaceMethodrefConstant.
    363      */
    364     public int addInterfaceMethodrefConstant(int    classIndex,
    365                                              String name,
    366                                              String descriptor,
    367                                              Clazz  referencedClass,
    368                                              Member referencedMember)
    369     {
    370         return addInterfaceMethodrefConstant(classIndex,
    371                                              addNameAndTypeConstant(name, descriptor),
    372                                              referencedClass,
    373                                              referencedMember);
    374     }
    375 
    376 
    377     /**
    378      * Finds or creates a InterfaceMethodrefConstant constant pool entry with the
    379      * given class constant pool entry index and name and type constant pool
    380      * entry index.
    381      * @return the constant pool index of the InterfaceMethodrefConstant.
    382      */
    383     public int addInterfaceMethodrefConstant(int    classIndex,
    384                                              int    nameAndTypeIndex,
    385                                              Clazz  referencedClass,
    386                                              Member referencedMember)
    387     {
    388         int        constantPoolCount = targetClass.u2constantPoolCount;
    389         Constant[] constantPool      = targetClass.constantPool;
    390 
    391         // Check if the entry already exists.
    392         for (int index = 1; index < constantPoolCount; index++)
    393         {
    394             Constant constant = constantPool[index];
    395 
    396             if (constant != null &&
    397                             constant.getTag() == ClassConstants.CONSTANT_InterfaceMethodref)
    398             {
    399                 InterfaceMethodrefConstant methodrefConstant = (InterfaceMethodrefConstant)constant;
    400                 if (methodrefConstant.u2classIndex       == classIndex &&
    401                     methodrefConstant.u2nameAndTypeIndex == nameAndTypeIndex)
    402                 {
    403                     return index;
    404                 }
    405             }
    406         }
    407 
    408         return addConstant(new InterfaceMethodrefConstant(classIndex,
    409                                                           nameAndTypeIndex,
    410                                                           referencedClass,
    411                                                           referencedMember));
    412     }
    413 
    414 
    415     /**
    416      * Finds or creates a MethodrefConstant constant pool entry for the given
    417      * class and method.
    418      * @return the constant pool index of the MethodrefConstant.
    419      */
    420     public int addMethodrefConstant(Clazz  referencedClass,
    421                                     Member referencedMember)
    422     {
    423         return addMethodrefConstant(referencedClass.getName(),
    424                                     referencedMember.getName(referencedClass),
    425                                     referencedMember.getDescriptor(referencedClass),
    426                                     referencedClass,
    427                                     referencedMember);
    428     }
    429 
    430 
    431     /**
    432      * Finds or creates a MethodrefConstant constant pool entry with the given
    433      * class name, method name, and descriptor.
    434      * @return the constant pool index of the MethodrefConstant.
    435      */
    436     public int addMethodrefConstant(String className,
    437                                     String name,
    438                                     String descriptor,
    439                                     Clazz  referencedClass,
    440                                     Member referencedMember)
    441     {
    442         return addMethodrefConstant(className,
    443                                     addNameAndTypeConstant(name, descriptor),
    444                                     referencedClass,
    445                                     referencedMember);
    446     }
    447 
    448 
    449     /**
    450      * Finds or creates a MethodrefConstant constant pool entry with the given
    451      * class name, method name, and descriptor.
    452      * @return the constant pool index of the MethodrefConstant.
    453      */
    454     public int addMethodrefConstant(String className,
    455                                     int    nameAndTypeIndex,
    456                                     Clazz  referencedClass,
    457                                     Member referencedMember)
    458     {
    459         return addMethodrefConstant(addClassConstant(className, referencedClass),
    460                                     nameAndTypeIndex,
    461                                     referencedClass,
    462                                     referencedMember);
    463     }
    464 
    465 
    466     /**
    467      * Finds or creates a MethodrefConstant constant pool entry with the given
    468      * class constant pool entry index, method name, and descriptor.
    469      * @return the constant pool index of the MethodrefConstant.
    470      */
    471     public int addMethodrefConstant(int    classIndex,
    472                                     String name,
    473                                     String descriptor,
    474                                     Clazz  referencedClass,
    475                                     Member referencedMember)
    476     {
    477         return addMethodrefConstant(classIndex,
    478                                     addNameAndTypeConstant(name, descriptor),
    479                                     referencedClass,
    480                                     referencedMember);
    481     }
    482 
    483 
    484     /**
    485      * Finds or creates a MethodrefConstant constant pool entry with the given
    486      * class constant pool entry index and name and type constant pool entry
    487      * index.
    488      * @return the constant pool index of the MethodrefConstant.
    489      */
    490     public int addMethodrefConstant(int    classIndex,
    491                                     int    nameAndTypeIndex,
    492                                     Clazz  referencedClass,
    493                                     Member referencedMember)
    494     {
    495         int        constantPoolCount = targetClass.u2constantPoolCount;
    496         Constant[] constantPool      = targetClass.constantPool;
    497 
    498         // Check if the entry already exists.
    499         for (int index = 1; index < constantPoolCount; index++)
    500         {
    501             Constant constant = constantPool[index];
    502 
    503             if (constant != null &&
    504                 constant.getTag() == ClassConstants.CONSTANT_Methodref)
    505             {
    506                 MethodrefConstant methodrefConstant = (MethodrefConstant)constant;
    507                 if (methodrefConstant.u2classIndex       == classIndex &&
    508                     methodrefConstant.u2nameAndTypeIndex == nameAndTypeIndex)
    509                 {
    510                     return index;
    511                 }
    512             }
    513         }
    514 
    515         return addConstant(new MethodrefConstant(classIndex,
    516                                                  nameAndTypeIndex,
    517                                                  referencedClass,
    518                                                  referencedMember));
    519     }
    520 
    521 
    522     /**
    523      * Finds or creates a ClassConstant constant pool entry for the given class.
    524      * @return the constant pool index of the ClassConstant.
    525      */
    526     public int addClassConstant(Clazz referencedClass)
    527     {
    528         return addClassConstant(referencedClass.getName(),
    529                                 referencedClass);
    530     }
    531 
    532 
    533     /**
    534      * Finds or creates a ClassConstant constant pool entry with the given name.
    535      * @return the constant pool index of the ClassConstant.
    536      */
    537     public int addClassConstant(String name,
    538                                 Clazz  referencedClass)
    539     {
    540         int        constantPoolCount = targetClass.u2constantPoolCount;
    541         Constant[] constantPool      = targetClass.constantPool;
    542 
    543         // Check if the entry already exists.
    544         for (int index = 1; index < constantPoolCount; index++)
    545         {
    546             Constant constant = constantPool[index];
    547 
    548             if (constant != null &&
    549                 constant.getTag() == ClassConstants.CONSTANT_Class)
    550             {
    551                 ClassConstant classConstant = (ClassConstant)constant;
    552                 if (classConstant.getName(targetClass).equals(name))
    553                 {
    554                     return index;
    555                 }
    556             }
    557         }
    558 
    559         int nameIndex = addUtf8Constant(name);
    560 
    561         return addConstant(new ClassConstant(nameIndex, referencedClass));
    562     }
    563 
    564 
    565     /**
    566      * Finds or creates a NameAndTypeConstant constant pool entry with the given
    567      * name and type.
    568      * @return the constant pool index of the NameAndTypeConstant.
    569      */
    570     public int addNameAndTypeConstant(String name,
    571                                       String type)
    572     {
    573         int        constantPoolCount = targetClass.u2constantPoolCount;
    574         Constant[] constantPool      = targetClass.constantPool;
    575 
    576         // Check if the entry already exists.
    577         for (int index = 1; index < constantPoolCount; index++)
    578         {
    579             Constant constant = constantPool[index];
    580 
    581             if (constant != null &&
    582                 constant.getTag() == ClassConstants.CONSTANT_NameAndType)
    583             {
    584                 NameAndTypeConstant nameAndTypeConstant = (NameAndTypeConstant)constant;
    585                 if (nameAndTypeConstant.getName(targetClass).equals(name) &&
    586                     nameAndTypeConstant.getType(targetClass).equals(type))
    587                 {
    588                     return index;
    589                 }
    590             }
    591         }
    592 
    593         return addConstant(new NameAndTypeConstant(addUtf8Constant(name),
    594                                                    addUtf8Constant(type)));
    595     }
    596 
    597 
    598     /**
    599      * Finds or creates a Utf8Constant constant pool entry for the given string.
    600      * @return the constant pool index of the Utf8Constant.
    601      */
    602     public int addUtf8Constant(String string)
    603     {
    604         int        constantPoolCount = targetClass.u2constantPoolCount;
    605         Constant[] constantPool      = targetClass.constantPool;
    606 
    607         // Check if the entry already exists.
    608         for (int index = 1; index < constantPoolCount; index++)
    609         {
    610             Constant constant = constantPool[index];
    611 
    612             if (constant != null &&
    613                 constant.getTag() == ClassConstants.CONSTANT_Utf8)
    614             {
    615                 Utf8Constant utf8Constant = (Utf8Constant)constant;
    616                 if (utf8Constant.getString().equals(string))
    617                 {
    618                     return index;
    619                 }
    620             }
    621         }
    622 
    623         return addConstant(new Utf8Constant(string));
    624     }
    625 
    626 
    627     /**
    628      * Adds a given constant pool entry to the end of the constant pool/
    629      * @return the constant pool index for the added entry.
    630      */
    631     public int addConstant(Constant constant)
    632     {
    633         int        constantPoolCount = targetClass.u2constantPoolCount;
    634         Constant[] constantPool      = targetClass.constantPool;
    635 
    636         // Make sure there is enough space for another constant pool entry.
    637         if (constantPool.length < constantPoolCount+2)
    638         {
    639             targetClass.constantPool = new Constant[constantPoolCount+2];
    640             System.arraycopy(constantPool, 0,
    641                              targetClass.constantPool, 0,
    642                              constantPoolCount);
    643             constantPool = targetClass.constantPool;
    644         }
    645 
    646         if (DEBUG)
    647         {
    648             System.out.println(targetClass.getName()+": adding ["+constant.getClass().getName()+"] at index "+targetClass.u2constantPoolCount);
    649         }
    650 
    651         // Create a new Utf8Constant for the given string.
    652         constantPool[targetClass.u2constantPoolCount++] = constant;
    653 
    654         // Long constants and double constants take up two entries in the
    655         // constant pool.
    656         int tag = constant.getTag();
    657         if (tag == ClassConstants.CONSTANT_Long ||
    658             tag == ClassConstants.CONSTANT_Double)
    659         {
    660             constantPool[targetClass.u2constantPoolCount++] = null;
    661         }
    662 
    663         return constantPoolCount;
    664     }
    665 }
    666