Home | History | Annotate | Download | only in bytecode
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.bytecode;
     17 
     18 import java.io.DataInputStream;
     19 import java.io.DataOutputStream;
     20 import java.io.ByteArrayOutputStream;
     21 import java.io.PrintWriter;
     22 import java.io.IOException;
     23 import java.util.HashMap;
     24 import java.util.HashSet;
     25 import java.util.Map;
     26 import java.util.Set;
     27 
     28 import javassist.CtClass;
     29 
     30 /**
     31  * Constant pool table.
     32  */
     33 public final class ConstPool {
     34     LongVector items;
     35     int numOfItems;
     36     HashMap classes;
     37     HashMap strings;
     38     ConstInfo[] constInfoCache;
     39     int[] constInfoIndexCache;
     40     int thisClassInfo;
     41 
     42     private static final int CACHE_SIZE = 32;
     43 
     44     /**
     45      * A hash function for CACHE_SIZE
     46      */
     47     private static int hashFunc(int a, int b) {
     48         int h = -2128831035;
     49         final int prime = 16777619;
     50         h = (h ^ (a & 0xff)) * prime;
     51         h = (h ^ (b & 0xff)) * prime;
     52 
     53         // changing the hash key size from 32bit to 5bit
     54         h = (h >> 5) ^ (h & 0x1f);
     55         return h & 0x1f;    // 0..31
     56     }
     57 
     58     /**
     59      * <code>CONSTANT_Class</code>
     60      */
     61     public static final int CONST_Class = ClassInfo.tag;
     62 
     63     /**
     64      * <code>CONSTANT_Fieldref</code>
     65      */
     66     public static final int CONST_Fieldref = FieldrefInfo.tag;
     67 
     68     /**
     69      * <code>CONSTANT_Methodref</code>
     70      */
     71     public static final int CONST_Methodref = MethodrefInfo.tag;
     72 
     73     /**
     74      * <code>CONSTANT_InterfaceMethodref</code>
     75      */
     76     public static final int CONST_InterfaceMethodref
     77                                         = InterfaceMethodrefInfo.tag;
     78 
     79     /**
     80      * <code>CONSTANT_String</code>
     81      */
     82     public static final int CONST_String = StringInfo.tag;
     83 
     84     /**
     85      * <code>CONSTANT_Integer</code>
     86      */
     87     public static final int CONST_Integer = IntegerInfo.tag;
     88 
     89     /**
     90      * <code>CONSTANT_Float</code>
     91      */
     92     public static final int CONST_Float = FloatInfo.tag;
     93 
     94     /**
     95      * <code>CONSTANT_Long</code>
     96      */
     97     public static final int CONST_Long = LongInfo.tag;
     98 
     99     /**
    100      * <code>CONSTANT_Double</code>
    101      */
    102     public static final int CONST_Double = DoubleInfo.tag;
    103 
    104     /**
    105      * <code>CONSTANT_NameAndType</code>
    106      */
    107     public static final int CONST_NameAndType = NameAndTypeInfo.tag;
    108 
    109     /**
    110      * <code>CONSTANT_Utf8</code>
    111      */
    112     public static final int CONST_Utf8 = Utf8Info.tag;
    113 
    114     /**
    115      * Represents the class using this constant pool table.
    116      */
    117     public static final CtClass THIS = null;
    118 
    119     /**
    120      * Constructs a constant pool table.
    121      *
    122      * @param thisclass         the name of the class using this constant
    123      *                          pool table
    124      */
    125     public ConstPool(String thisclass) {
    126         items = new LongVector();
    127         numOfItems = 0;
    128         addItem(null);          // index 0 is reserved by the JVM.
    129         classes = new HashMap();
    130         strings = new HashMap();
    131         constInfoCache = new ConstInfo[CACHE_SIZE];
    132         constInfoIndexCache = new int[CACHE_SIZE];
    133         thisClassInfo = addClassInfo(thisclass);
    134     }
    135 
    136     /**
    137      * Constructs a constant pool table from the given byte stream.
    138      *
    139      * @param in        byte stream.
    140      */
    141     public ConstPool(DataInputStream in) throws IOException {
    142         classes = new HashMap();
    143         strings = new HashMap();
    144         constInfoCache = new ConstInfo[CACHE_SIZE];
    145         constInfoIndexCache = new int[CACHE_SIZE];
    146         thisClassInfo = 0;
    147         /* read() initializes items and numOfItems, and do addItem(null).
    148          */
    149         read(in);
    150     }
    151 
    152     void prune() {
    153         classes = new HashMap();
    154         strings = new HashMap();
    155         constInfoCache = new ConstInfo[CACHE_SIZE];
    156         constInfoIndexCache = new int[CACHE_SIZE];
    157     }
    158 
    159     /**
    160      * Returns the number of entries in this table.
    161      */
    162     public int getSize() {
    163         return numOfItems;
    164     }
    165 
    166     /**
    167      * Returns the name of the class using this constant pool table.
    168      */
    169     public String getClassName() {
    170         return getClassInfo(thisClassInfo);
    171     }
    172 
    173     /**
    174      * Returns the index of <code>CONSTANT_Class_info</code> structure
    175      * specifying the class using this constant pool table.
    176      */
    177     public int getThisClassInfo() {
    178         return thisClassInfo;
    179     }
    180 
    181     void setThisClassInfo(int i) {
    182         thisClassInfo = i;
    183     }
    184 
    185     ConstInfo getItem(int n) {
    186         return items.elementAt(n);
    187     }
    188 
    189     /**
    190      * Returns the <code>tag</code> field of the constant pool table
    191      * entry at the given index.
    192      */
    193     public int getTag(int index) {
    194         return getItem(index).getTag();
    195     }
    196 
    197     /**
    198      * Reads <code>CONSTANT_Class_info</code> structure
    199      * at the given index.
    200      *
    201      * @return  a fully-qualified class or interface name specified
    202      *          by <code>name_index</code>.  If the type is an array
    203      *          type, this method returns an encoded name like
    204      *          <code>[java.lang.Object;</code> (note that the separators
    205      *          are not slashes but dots).
    206      * @see javassist.ClassPool#getCtClass(String)
    207      */
    208     public String getClassInfo(int index) {
    209         ClassInfo c = (ClassInfo)getItem(index);
    210         if (c == null)
    211             return null;
    212         else
    213             return Descriptor.toJavaName(getUtf8Info(c.name));
    214     }
    215 
    216     /**
    217      * Reads the <code>name_index</code> field of the
    218      * <code>CONSTANT_NameAndType_info</code> structure
    219      * at the given index.
    220      */
    221     public int getNameAndTypeName(int index) {
    222         NameAndTypeInfo ntinfo = (NameAndTypeInfo)getItem(index);
    223         return ntinfo.memberName;
    224     }
    225 
    226     /**
    227      * Reads the <code>descriptor_index</code> field of the
    228      * <code>CONSTANT_NameAndType_info</code> structure
    229      * at the given index.
    230      */
    231     public int getNameAndTypeDescriptor(int index) {
    232         NameAndTypeInfo ntinfo = (NameAndTypeInfo)getItem(index);
    233         return ntinfo.typeDescriptor;
    234     }
    235 
    236     /**
    237      * Reads the <code>class_index</code> field of the
    238      * <code>CONSTANT_Fieldref_info</code>,
    239      * <code>CONSTANT_Methodref_info</code>,
    240      * or <code>CONSTANT_Interfaceref_info</code>,
    241      * structure at the given index.
    242      *
    243      * @since 3.6
    244      */
    245     public int getMemberClass(int index) {
    246         MemberrefInfo minfo = (MemberrefInfo)getItem(index);
    247         return minfo.classIndex;
    248     }
    249 
    250     /**
    251      * Reads the <code>name_and_type_index</code> field of the
    252      * <code>CONSTANT_Fieldref_info</code>,
    253      * <code>CONSTANT_Methodref_info</code>,
    254      * or <code>CONSTANT_Interfaceref_info</code>,
    255      * structure at the given index.
    256      *
    257      * @since 3.6
    258      */
    259     public int getMemberNameAndType(int index) {
    260         MemberrefInfo minfo = (MemberrefInfo)getItem(index);
    261         return minfo.nameAndTypeIndex;
    262     }
    263 
    264     /**
    265      * Reads the <code>class_index</code> field of the
    266      * <code>CONSTANT_Fieldref_info</code> structure
    267      * at the given index.
    268      */
    269     public int getFieldrefClass(int index) {
    270         FieldrefInfo finfo = (FieldrefInfo)getItem(index);
    271         return finfo.classIndex;
    272     }
    273 
    274     /**
    275      * Reads the <code>class_index</code> field of the
    276      * <code>CONSTANT_Fieldref_info</code> structure
    277      * at the given index.
    278      *
    279      * @return the name of the class at that <code>class_index</code>.
    280      */
    281     public String getFieldrefClassName(int index) {
    282         FieldrefInfo f = (FieldrefInfo)getItem(index);
    283         if (f == null)
    284             return null;
    285         else
    286             return getClassInfo(f.classIndex);
    287     }
    288 
    289     /**
    290      * Reads the <code>name_and_type_index</code> field of the
    291      * <code>CONSTANT_Fieldref_info</code> structure
    292      * at the given index.
    293      */
    294     public int getFieldrefNameAndType(int index) {
    295         FieldrefInfo finfo = (FieldrefInfo)getItem(index);
    296         return finfo.nameAndTypeIndex;
    297     }
    298 
    299     /**
    300      * Reads the <code>name_index</code> field of the
    301      * <code>CONSTANT_NameAndType_info</code> structure
    302      * indirectly specified by the given index.
    303      *
    304      * @param index     an index to a <code>CONSTANT_Fieldref_info</code>.
    305      * @return  the name of the field.
    306      */
    307     public String getFieldrefName(int index) {
    308         FieldrefInfo f = (FieldrefInfo)getItem(index);
    309         if (f == null)
    310             return null;
    311         else {
    312             NameAndTypeInfo n = (NameAndTypeInfo)getItem(f.nameAndTypeIndex);
    313             if(n == null)
    314                 return null;
    315             else
    316                 return getUtf8Info(n.memberName);
    317         }
    318     }
    319 
    320     /**
    321      * Reads the <code>descriptor_index</code> field of the
    322      * <code>CONSTANT_NameAndType_info</code> structure
    323      * indirectly specified by the given index.
    324      *
    325      * @param index     an index to a <code>CONSTANT_Fieldref_info</code>.
    326      * @return  the type descriptor of the field.
    327      */
    328     public String getFieldrefType(int index) {
    329         FieldrefInfo f = (FieldrefInfo)getItem(index);
    330         if (f == null)
    331             return null;
    332         else {
    333             NameAndTypeInfo n = (NameAndTypeInfo)getItem(f.nameAndTypeIndex);
    334             if(n == null)
    335                 return null;
    336             else
    337                 return getUtf8Info(n.typeDescriptor);
    338         }
    339     }
    340 
    341     /**
    342      * Reads the <code>class_index</code> field of the
    343      * <code>CONSTANT_Methodref_info</code> structure
    344      * at the given index.
    345      */
    346     public int getMethodrefClass(int index) {
    347         MethodrefInfo minfo = (MethodrefInfo)getItem(index);
    348         return minfo.classIndex;
    349     }
    350 
    351     /**
    352      * Reads the <code>class_index</code> field of the
    353      * <code>CONSTANT_Methodref_info</code> structure
    354      * at the given index.
    355      *
    356      * @return the name of the class at that <code>class_index</code>.
    357      */
    358     public String getMethodrefClassName(int index) {
    359         MethodrefInfo minfo = (MethodrefInfo)getItem(index);
    360         if (minfo == null)
    361             return null;
    362         else
    363             return getClassInfo(minfo.classIndex);
    364     }
    365 
    366     /**
    367      * Reads the <code>name_and_type_index</code> field of the
    368      * <code>CONSTANT_Methodref_info</code> structure
    369      * at the given index.
    370      */
    371     public int getMethodrefNameAndType(int index) {
    372         MethodrefInfo minfo = (MethodrefInfo)getItem(index);
    373         return minfo.nameAndTypeIndex;
    374     }
    375 
    376     /**
    377      * Reads the <code>name_index</code> field of the
    378      * <code>CONSTANT_NameAndType_info</code> structure
    379      * indirectly specified by the given index.
    380      *
    381      * @param index     an index to a <code>CONSTANT_Methodref_info</code>.
    382      * @return  the name of the method.
    383      */
    384     public String getMethodrefName(int index) {
    385         MethodrefInfo minfo = (MethodrefInfo)getItem(index);
    386         if (minfo == null)
    387             return null;
    388         else {
    389             NameAndTypeInfo n
    390                 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
    391             if(n == null)
    392                 return null;
    393             else
    394                 return getUtf8Info(n.memberName);
    395         }
    396     }
    397 
    398     /**
    399      * Reads the <code>descriptor_index</code> field of the
    400      * <code>CONSTANT_NameAndType_info</code> structure
    401      * indirectly specified by the given index.
    402      *
    403      * @param index     an index to a <code>CONSTANT_Methodref_info</code>.
    404      * @return  the descriptor of the method.
    405      */
    406     public String getMethodrefType(int index) {
    407         MethodrefInfo minfo = (MethodrefInfo)getItem(index);
    408         if (minfo == null)
    409             return null;
    410         else {
    411             NameAndTypeInfo n
    412                 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
    413             if(n == null)
    414                 return null;
    415             else
    416                 return getUtf8Info(n.typeDescriptor);
    417         }
    418     }
    419 
    420     /**
    421      * Reads the <code>class_index</code> field of the
    422      * <code>CONSTANT_InterfaceMethodref_info</code> structure
    423      * at the given index.
    424      */
    425     public int getInterfaceMethodrefClass(int index) {
    426         InterfaceMethodrefInfo minfo
    427             = (InterfaceMethodrefInfo)getItem(index);
    428         return minfo.classIndex;
    429     }
    430 
    431     /**
    432      * Reads the <code>class_index</code> field of the
    433      * <code>CONSTANT_InterfaceMethodref_info</code> structure
    434      * at the given index.
    435      *
    436      * @return the name of the class at that <code>class_index</code>.
    437      */
    438     public String getInterfaceMethodrefClassName(int index) {
    439         InterfaceMethodrefInfo minfo
    440             = (InterfaceMethodrefInfo)getItem(index);
    441         return getClassInfo(minfo.classIndex);
    442     }
    443 
    444     /**
    445      * Reads the <code>name_and_type_index</code> field of the
    446      * <code>CONSTANT_InterfaceMethodref_info</code> structure
    447      * at the given index.
    448      */
    449     public int getInterfaceMethodrefNameAndType(int index) {
    450         InterfaceMethodrefInfo minfo
    451             = (InterfaceMethodrefInfo)getItem(index);
    452         return minfo.nameAndTypeIndex;
    453     }
    454 
    455     /**
    456      * Reads the <code>name_index</code> field of the
    457      * <code>CONSTANT_NameAndType_info</code> structure
    458      * indirectly specified by the given index.
    459      *
    460      * @param index     an index to
    461      *                  a <code>CONSTANT_InterfaceMethodref_info</code>.
    462      * @return  the name of the method.
    463      */
    464     public String getInterfaceMethodrefName(int index) {
    465         InterfaceMethodrefInfo minfo
    466             = (InterfaceMethodrefInfo)getItem(index);
    467         if (minfo == null)
    468             return null;
    469         else {
    470             NameAndTypeInfo n
    471                 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
    472             if(n == null)
    473                 return null;
    474             else
    475                 return getUtf8Info(n.memberName);
    476         }
    477     }
    478 
    479     /**
    480      * Reads the <code>descriptor_index</code> field of the
    481      * <code>CONSTANT_NameAndType_info</code> structure
    482      * indirectly specified by the given index.
    483      *
    484      * @param index     an index to
    485      *                  a <code>CONSTANT_InterfaceMethodref_info</code>.
    486      * @return  the descriptor of the method.
    487      */
    488     public String getInterfaceMethodrefType(int index) {
    489         InterfaceMethodrefInfo minfo
    490             = (InterfaceMethodrefInfo)getItem(index);
    491         if (minfo == null)
    492             return null;
    493         else {
    494             NameAndTypeInfo n
    495                 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
    496             if(n == null)
    497                 return null;
    498             else
    499                 return getUtf8Info(n.typeDescriptor);
    500         }
    501     }
    502     /**
    503      * Reads <code>CONSTANT_Integer_info</code>, <code>_Float_info</code>,
    504      * <code>_Long_info</code>, <code>_Double_info</code>, or
    505      * <code>_String_info</code> structure.
    506      * These are used with the LDC instruction.
    507      *
    508      * @return a <code>String</code> value or a wrapped primitive-type
    509      * value.
    510      */
    511     public Object getLdcValue(int index) {
    512         ConstInfo constInfo = this.getItem(index);
    513         Object value = null;
    514         if (constInfo instanceof StringInfo)
    515             value = this.getStringInfo(index);
    516         else if (constInfo instanceof FloatInfo)
    517             value = new Float(getFloatInfo(index));
    518         else if (constInfo instanceof IntegerInfo)
    519             value = new Integer(getIntegerInfo(index));
    520         else if (constInfo instanceof LongInfo)
    521             value = new Long(getLongInfo(index));
    522         else if (constInfo instanceof DoubleInfo)
    523             value = new Double(getDoubleInfo(index));
    524         else
    525             value = null;
    526 
    527         return value;
    528     }
    529 
    530     /**
    531      * Reads <code>CONSTANT_Integer_info</code> structure
    532      * at the given index.
    533      *
    534      * @return the value specified by this entry.
    535      */
    536     public int getIntegerInfo(int index) {
    537         IntegerInfo i = (IntegerInfo)getItem(index);
    538         return i.value;
    539     }
    540 
    541     /**
    542      * Reads <code>CONSTANT_Float_info</code> structure
    543      * at the given index.
    544      *
    545      * @return the value specified by this entry.
    546      */
    547     public float getFloatInfo(int index) {
    548         FloatInfo i = (FloatInfo)getItem(index);
    549         return i.value;
    550     }
    551 
    552     /**
    553      * Reads <code>CONSTANT_Long_info</code> structure
    554      * at the given index.
    555      *
    556      * @return the value specified by this entry.
    557      */
    558     public long getLongInfo(int index) {
    559         LongInfo i = (LongInfo)getItem(index);
    560         return i.value;
    561     }
    562 
    563     /**
    564      * Reads <code>CONSTANT_Double_info</code> structure
    565      * at the given index.
    566      *
    567      * @return the value specified by this entry.
    568      */
    569     public double getDoubleInfo(int index) {
    570         DoubleInfo i = (DoubleInfo)getItem(index);
    571         return i.value;
    572     }
    573 
    574     /**
    575      * Reads <code>CONSTANT_String_info</code> structure
    576      * at the given index.
    577      *
    578      * @return the string specified by <code>string_index</code>.
    579      */
    580     public String getStringInfo(int index) {
    581         StringInfo si = (StringInfo)getItem(index);
    582         return getUtf8Info(si.string);
    583     }
    584 
    585     /**
    586      * Reads <code>CONSTANT_utf8_info</code> structure
    587      * at the given index.
    588      *
    589      * @return the string specified by this entry.
    590      */
    591     public String getUtf8Info(int index) {
    592         Utf8Info utf = (Utf8Info)getItem(index);
    593         return utf.string;
    594     }
    595 
    596     /**
    597      * Determines whether <code>CONSTANT_Methodref_info</code>
    598      * structure at the given index represents the constructor
    599      * of the given class.
    600      *
    601      * @return          the <code>descriptor_index</code> specifying
    602      *                  the type descriptor of the that constructor.
    603      *                  If it is not that constructor,
    604      *                  <code>isConstructor()</code> returns 0.
    605      */
    606     public int isConstructor(String classname, int index) {
    607         return isMember(classname, MethodInfo.nameInit, index);
    608     }
    609 
    610     /**
    611      * Determines whether <code>CONSTANT_Methodref_info</code>,
    612      * <code>CONSTANT_Fieldref_info</code>, or
    613      * <code>CONSTANT_InterfaceMethodref_info</code> structure
    614      * at the given index represents the member with the specified
    615      * name and declaring class.
    616      *
    617      * @param classname         the class declaring the member
    618      * @param membername        the member name
    619      * @param index             the index into the constant pool table
    620      *
    621      * @return          the <code>descriptor_index</code> specifying
    622      *                  the type descriptor of that member.
    623      *                  If it is not that member,
    624      *                  <code>isMember()</code> returns 0.
    625      */
    626     public int isMember(String classname, String membername, int index) {
    627         MemberrefInfo minfo = (MemberrefInfo)getItem(index);
    628         if (getClassInfo(minfo.classIndex).equals(classname)) {
    629             NameAndTypeInfo ntinfo
    630                 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
    631             if (getUtf8Info(ntinfo.memberName).equals(membername))
    632                 return ntinfo.typeDescriptor;
    633         }
    634 
    635         return 0;       // false
    636     }
    637 
    638     /**
    639      * Determines whether <code>CONSTANT_Methodref_info</code>,
    640      * <code>CONSTANT_Fieldref_info</code>, or
    641      * <code>CONSTANT_InterfaceMethodref_info</code> structure
    642      * at the given index has the name and the descriptor
    643      * given as the arguments.
    644      *
    645      * @param membername        the member name
    646      * @param desc              the descriptor of the member.
    647      * @param index             the index into the constant pool table
    648      *
    649      * @return          the name of the target class specified by
    650      *                  the <code>..._info</code> structure
    651      *                  at <code>index</code>.
    652      *                  Otherwise, null if that structure does not
    653      *                  match the given member name and descriptor.
    654      */
    655     public String eqMember(String membername, String desc, int index) {
    656         MemberrefInfo minfo = (MemberrefInfo)getItem(index);
    657         NameAndTypeInfo ntinfo
    658                 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
    659         if (getUtf8Info(ntinfo.memberName).equals(membername)
    660             && getUtf8Info(ntinfo.typeDescriptor).equals(desc))
    661             return getClassInfo(minfo.classIndex);
    662         else
    663             return null;       // false
    664     }
    665 
    666     private int addItem(ConstInfo info) {
    667         items.addElement(info);
    668         return numOfItems++;
    669     }
    670 
    671     /**
    672      * Copies the n-th item in this ConstPool object into the destination
    673      * ConstPool object.
    674      * The class names that the item refers to are renamed according
    675      * to the given map.
    676      *
    677      * @param n                 the <i>n</i>-th item
    678      * @param dest              destination constant pool table
    679      * @param classnames        the map or null.
    680      * @return the index of the copied item into the destination ClassPool.
    681      */
    682     public int copy(int n, ConstPool dest, Map classnames) {
    683         if (n == 0)
    684             return 0;
    685 
    686         ConstInfo info = getItem(n);
    687         return info.copy(this, dest, classnames);
    688     }
    689 
    690     int addConstInfoPadding() {
    691         return addItem(new ConstInfoPadding());
    692     }
    693 
    694     /**
    695      * Adds a new <code>CONSTANT_Class_info</code> structure.
    696      *
    697      * <p>This also adds a <code>CONSTANT_Utf8_info</code> structure
    698      * for storing the class name.
    699      *
    700      * @return          the index of the added entry.
    701      */
    702     public int addClassInfo(CtClass c) {
    703         if (c == THIS)
    704             return thisClassInfo;
    705         else if (!c.isArray())
    706             return addClassInfo(c.getName());
    707         else {
    708             // an array type is recorded in the hashtable with
    709             // the key "[L<classname>;" instead of "<classname>".
    710             //
    711             // note: toJvmName(toJvmName(c)) is equal to toJvmName(c).
    712 
    713             return addClassInfo(Descriptor.toJvmName(c));
    714         }
    715     }
    716 
    717     /**
    718      * Adds a new <code>CONSTANT_Class_info</code> structure.
    719      *
    720      * <p>This also adds a <code>CONSTANT_Utf8_info</code> structure
    721      * for storing the class name.
    722      *
    723      * @param qname     a fully-qualified class name
    724      *                  (or the JVM-internal representation of that name).
    725      * @return          the index of the added entry.
    726      */
    727     public int addClassInfo(String qname) {
    728         ClassInfo info = (ClassInfo)classes.get(qname);
    729         if (info != null)
    730             return info.index;
    731         else {
    732             int utf8 = addUtf8Info(Descriptor.toJvmName(qname));
    733             info = new ClassInfo(utf8, numOfItems);
    734             classes.put(qname, info);
    735             return addItem(info);
    736         }
    737     }
    738 
    739     /**
    740      * Adds a new <code>CONSTANT_NameAndType_info</code> structure.
    741      *
    742      * <p>This also adds <code>CONSTANT_Utf8_info</code> structures.
    743      *
    744      * @param name      <code>name_index</code>
    745      * @param type      <code>descriptor_index</code>
    746      * @return          the index of the added entry.
    747      */
    748     public int addNameAndTypeInfo(String name, String type) {
    749         return addNameAndTypeInfo(addUtf8Info(name), addUtf8Info(type));
    750     }
    751 
    752     /**
    753      * Adds a new <code>CONSTANT_NameAndType_info</code> structure.
    754      *
    755      * @param name      <code>name_index</code>
    756      * @param type      <code>descriptor_index</code>
    757      * @return          the index of the added entry.
    758      */
    759     public int addNameAndTypeInfo(int name, int type) {
    760         int h = hashFunc(name, type);
    761         ConstInfo ci = constInfoCache[h];
    762         if (ci != null && ci instanceof NameAndTypeInfo && ci.hashCheck(name, type))
    763             return constInfoIndexCache[h];
    764         else {
    765             NameAndTypeInfo item = new NameAndTypeInfo(name, type);
    766             constInfoCache[h] = item;
    767             int i = addItem(item);
    768             constInfoIndexCache[h] = i;
    769             return i;
    770         }
    771     }
    772 
    773     /**
    774      * Adds a new <code>CONSTANT_Fieldref_info</code> structure.
    775      *
    776      * <p>This also adds a new <code>CONSTANT_NameAndType_info</code>
    777      * structure.
    778      *
    779      * @param classInfo         <code>class_index</code>
    780      * @param name              <code>name_index</code>
    781      *                          of <code>CONSTANT_NameAndType_info</code>.
    782      * @param type              <code>descriptor_index</code>
    783      *                          of <code>CONSTANT_NameAndType_info</code>.
    784      * @return          the index of the added entry.
    785      */
    786     public int addFieldrefInfo(int classInfo, String name, String type) {
    787         int nt = addNameAndTypeInfo(name, type);
    788         return addFieldrefInfo(classInfo, nt);
    789     }
    790 
    791     /**
    792      * Adds a new <code>CONSTANT_Fieldref_info</code> structure.
    793      *
    794      * @param classInfo         <code>class_index</code>
    795      * @param nameAndTypeInfo   <code>name_and_type_index</code>.
    796      * @return          the index of the added entry.
    797      */
    798     public int addFieldrefInfo(int classInfo, int nameAndTypeInfo) {
    799         int h = hashFunc(classInfo, nameAndTypeInfo);
    800         ConstInfo ci = constInfoCache[h];
    801         if (ci != null && ci instanceof FieldrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo))
    802             return constInfoIndexCache[h];
    803         else {
    804             FieldrefInfo item = new FieldrefInfo(classInfo, nameAndTypeInfo);
    805             constInfoCache[h] = item;
    806             int i = addItem(item);
    807             constInfoIndexCache[h] = i;
    808             return i;
    809         }
    810     }
    811 
    812     /**
    813      * Adds a new <code>CONSTANT_Methodref_info</code> structure.
    814      *
    815      * <p>This also adds a new <code>CONSTANT_NameAndType_info</code>
    816      * structure.
    817      *
    818      * @param classInfo         <code>class_index</code>
    819      * @param name              <code>name_index</code>
    820      *                          of <code>CONSTANT_NameAndType_info</code>.
    821      * @param type              <code>descriptor_index</code>
    822      *                          of <code>CONSTANT_NameAndType_info</code>.
    823      * @return          the index of the added entry.
    824      */
    825     public int addMethodrefInfo(int classInfo, String name, String type) {
    826         int nt = addNameAndTypeInfo(name, type);
    827         return addMethodrefInfo(classInfo, nt);
    828     }
    829 
    830     /**
    831      * Adds a new <code>CONSTANT_Methodref_info</code> structure.
    832      *
    833      * @param classInfo         <code>class_index</code>
    834      * @param nameAndTypeInfo   <code>name_and_type_index</code>.
    835      * @return          the index of the added entry.
    836      */
    837     public int addMethodrefInfo(int classInfo, int nameAndTypeInfo) {
    838         int h = hashFunc(classInfo, nameAndTypeInfo);
    839         ConstInfo ci = constInfoCache[h];
    840         if (ci != null && ci instanceof MethodrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo))
    841             return constInfoIndexCache[h];
    842         else {
    843             MethodrefInfo item = new MethodrefInfo(classInfo, nameAndTypeInfo);
    844             constInfoCache[h] = item;
    845             int i = addItem(item);
    846             constInfoIndexCache[h] = i;
    847             return i;
    848         }
    849     }
    850 
    851     /**
    852      * Adds a new <code>CONSTANT_InterfaceMethodref_info</code>
    853      * structure.
    854      *
    855      * <p>This also adds a new <code>CONSTANT_NameAndType_info</code>
    856      * structure.
    857      *
    858      * @param classInfo         <code>class_index</code>
    859      * @param name              <code>name_index</code>
    860      *                          of <code>CONSTANT_NameAndType_info</code>.
    861      * @param type              <code>descriptor_index</code>
    862      *                          of <code>CONSTANT_NameAndType_info</code>.
    863      * @return          the index of the added entry.
    864      */
    865     public int addInterfaceMethodrefInfo(int classInfo, String name,
    866                                          String type) {
    867         int nt = addNameAndTypeInfo(name, type);
    868         return addInterfaceMethodrefInfo(classInfo, nt);
    869     }
    870 
    871     /**
    872      * Adds a new <code>CONSTANT_InterfaceMethodref_info</code>
    873      * structure.
    874      *
    875      * @param classInfo         <code>class_index</code>
    876      * @param nameAndTypeInfo   <code>name_and_type_index</code>.
    877      * @return          the index of the added entry.
    878      */
    879     public int addInterfaceMethodrefInfo(int classInfo,
    880                                          int nameAndTypeInfo) {
    881         int h = hashFunc(classInfo, nameAndTypeInfo);
    882         ConstInfo ci = constInfoCache[h];
    883         if (ci != null && ci instanceof InterfaceMethodrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo))
    884             return constInfoIndexCache[h];
    885         else {
    886             InterfaceMethodrefInfo item =new InterfaceMethodrefInfo(classInfo, nameAndTypeInfo);
    887             constInfoCache[h] = item;
    888             int i = addItem(item);
    889             constInfoIndexCache[h] = i;
    890             return i;
    891         }
    892     }
    893 
    894     /**
    895      * Adds a new <code>CONSTANT_String_info</code>
    896      * structure.
    897      *
    898      * <p>This also adds a new <code>CONSTANT_Utf8_info</code>
    899      * structure.
    900      *
    901      * @return          the index of the added entry.
    902      */
    903     public int addStringInfo(String str) {
    904         return addItem(new StringInfo(addUtf8Info(str)));
    905     }
    906 
    907     /**
    908      * Adds a new <code>CONSTANT_Integer_info</code>
    909      * structure.
    910      *
    911      * @return          the index of the added entry.
    912      */
    913     public int addIntegerInfo(int i) {
    914         return addItem(new IntegerInfo(i));
    915     }
    916 
    917     /**
    918      * Adds a new <code>CONSTANT_Float_info</code>
    919      * structure.
    920      *
    921      * @return          the index of the added entry.
    922      */
    923     public int addFloatInfo(float f) {
    924         return addItem(new FloatInfo(f));
    925     }
    926 
    927     /**
    928      * Adds a new <code>CONSTANT_Long_info</code>
    929      * structure.
    930      *
    931      * @return          the index of the added entry.
    932      */
    933     public int addLongInfo(long l) {
    934         int i = addItem(new LongInfo(l));
    935         addItem(new ConstInfoPadding());
    936         return i;
    937     }
    938 
    939     /**
    940      * Adds a new <code>CONSTANT_Double_info</code>
    941      * structure.
    942      *
    943      * @return          the index of the added entry.
    944      */
    945     public int addDoubleInfo(double d) {
    946         int i = addItem(new DoubleInfo(d));
    947         addItem(new ConstInfoPadding());
    948         return i;
    949     }
    950 
    951     /**
    952      * Adds a new <code>CONSTANT_Utf8_info</code>
    953      * structure.
    954      *
    955      * <p>If the given utf8 string has been already recorded in the
    956      * table, then this method does not add a new entry to avoid adding
    957      * a duplicated entry.
    958      * Instead, it returns the index of the entry already recorded.
    959      *
    960      * @return          the index of the added entry.
    961      */
    962     public int addUtf8Info(String utf8) {
    963         Utf8Info info = (Utf8Info)strings.get(utf8);
    964         if (info != null)
    965             return info.index;
    966         else {
    967             info = new Utf8Info(utf8, numOfItems);
    968             strings.put(utf8, info);
    969             return addItem(info);
    970         }
    971     }
    972 
    973     /**
    974      * Get all the class names.
    975      *
    976      * @return a set of class names
    977      */
    978     public Set getClassNames()
    979     {
    980         HashSet result = new HashSet();
    981         LongVector v = items;
    982         int size = numOfItems;
    983         for (int i = 1; i < size; ++i) {
    984             String className = v.elementAt(i).getClassName(this);
    985             if (className != null)
    986                result.add(className);
    987         }
    988         return result;
    989     }
    990 
    991     /**
    992      * Replaces all occurrences of a class name.
    993      *
    994      * @param oldName           the replaced name (JVM-internal representation).
    995      * @param newName           the substituted name (JVM-internal representation).
    996      */
    997     public void renameClass(String oldName, String newName) {
    998         LongVector v = items;
    999         int size = numOfItems;
   1000         classes = new HashMap(classes.size() * 2);
   1001         for (int i = 1; i < size; ++i) {
   1002             ConstInfo ci = v.elementAt(i);
   1003             ci.renameClass(this, oldName, newName);
   1004             ci.makeHashtable(this);
   1005         }
   1006     }
   1007 
   1008     /**
   1009      * Replaces all occurrences of class names.
   1010      *
   1011      * @param classnames        specifies pairs of replaced and substituted
   1012      *                          name.
   1013      */
   1014     public void renameClass(Map classnames) {
   1015         LongVector v = items;
   1016         int size = numOfItems;
   1017         classes = new HashMap(classes.size() * 2);
   1018         for (int i = 1; i < size; ++i) {
   1019             ConstInfo ci = v.elementAt(i);
   1020             ci.renameClass(this, classnames);
   1021             ci.makeHashtable(this);
   1022         }
   1023     }
   1024 
   1025     private void read(DataInputStream in) throws IOException {
   1026         int n = in.readUnsignedShort();
   1027 
   1028         items = new LongVector(n);
   1029         numOfItems = 0;
   1030         addItem(null);          // index 0 is reserved by the JVM.
   1031 
   1032         while (--n > 0) {       // index 0 is reserved by JVM
   1033             int tag = readOne(in);
   1034             if ((tag == LongInfo.tag) || (tag == DoubleInfo.tag)) {
   1035                 addItem(new ConstInfoPadding());
   1036                 --n;
   1037             }
   1038         }
   1039 
   1040         int i = 1;
   1041         while (true) {
   1042             ConstInfo info = items.elementAt(i++);
   1043             if (info == null)
   1044                 break;
   1045             else
   1046                 info.makeHashtable(this);
   1047         }
   1048     }
   1049 
   1050     private int readOne(DataInputStream in) throws IOException {
   1051         ConstInfo info;
   1052         int tag = in.readUnsignedByte();
   1053         switch (tag) {
   1054         case Utf8Info.tag :                     // 1
   1055             info = new Utf8Info(in, numOfItems);
   1056             strings.put(((Utf8Info)info).string, info);
   1057             break;
   1058         case IntegerInfo.tag :                  // 3
   1059             info = new IntegerInfo(in);
   1060             break;
   1061         case FloatInfo.tag :                    // 4
   1062             info = new FloatInfo(in);
   1063             break;
   1064         case LongInfo.tag :                     // 5
   1065             info = new LongInfo(in);
   1066             break;
   1067         case DoubleInfo.tag :                   // 6
   1068             info = new DoubleInfo(in);
   1069             break;
   1070         case ClassInfo.tag :                    // 7
   1071             info = new ClassInfo(in, numOfItems);
   1072             // classes.put(<classname>, info);
   1073             break;
   1074         case StringInfo.tag :                   // 8
   1075             info = new StringInfo(in);
   1076             break;
   1077         case FieldrefInfo.tag :                 // 9
   1078             info = new FieldrefInfo(in);
   1079             break;
   1080         case MethodrefInfo.tag :                // 10
   1081             info = new MethodrefInfo(in);
   1082             break;
   1083         case InterfaceMethodrefInfo.tag :       // 11
   1084             info = new InterfaceMethodrefInfo(in);
   1085             break;
   1086         case NameAndTypeInfo.tag :              // 12
   1087             info = new NameAndTypeInfo(in);
   1088             break;
   1089         default :
   1090             throw new IOException("invalid constant type: " + tag);
   1091         }
   1092 
   1093         addItem(info);
   1094         return tag;
   1095     }
   1096 
   1097     /**
   1098      * Writes the contents of the constant pool table.
   1099      */
   1100     public void write(DataOutputStream out) throws IOException {
   1101         out.writeShort(numOfItems);
   1102         LongVector v = items;
   1103         int size = numOfItems;
   1104         for (int i = 1; i < size; ++i)
   1105             v.elementAt(i).write(out);
   1106     }
   1107 
   1108     /**
   1109      * Prints the contents of the constant pool table.
   1110      */
   1111     public void print() {
   1112         print(new PrintWriter(System.out, true));
   1113     }
   1114 
   1115     /**
   1116      * Prints the contents of the constant pool table.
   1117      */
   1118     public void print(PrintWriter out) {
   1119         int size = numOfItems;
   1120         for (int i = 1; i < size; ++i) {
   1121             out.print(i);
   1122             out.print(" ");
   1123             items.elementAt(i).print(out);
   1124         }
   1125     }
   1126 }
   1127 
   1128 abstract class ConstInfo {
   1129     public abstract int getTag();
   1130 
   1131     public String getClassName(ConstPool cp) { return null; }
   1132     public void renameClass(ConstPool cp, String oldName, String newName) {}
   1133     public void renameClass(ConstPool cp, Map classnames) {}
   1134     public abstract int copy(ConstPool src, ConstPool dest, Map classnames);
   1135                         // ** classnames is a mapping between JVM names.
   1136 
   1137     public abstract void write(DataOutputStream out) throws IOException;
   1138     public abstract void print(PrintWriter out);
   1139 
   1140     void makeHashtable(ConstPool cp) {}     // called after read() finishes in ConstPool.
   1141 
   1142     boolean hashCheck(int a, int b) { return false; }
   1143 
   1144     public String toString() {
   1145         ByteArrayOutputStream bout = new ByteArrayOutputStream();
   1146         PrintWriter out = new PrintWriter(bout);
   1147         print(out);
   1148         return bout.toString();
   1149     }
   1150 }
   1151 
   1152 /* padding following DoubleInfo or LongInfo.
   1153  */
   1154 class ConstInfoPadding extends ConstInfo {
   1155     public int getTag() { return 0; }
   1156 
   1157     public int copy(ConstPool src, ConstPool dest, Map map) {
   1158         return dest.addConstInfoPadding();
   1159     }
   1160 
   1161     public void write(DataOutputStream out) throws IOException {}
   1162 
   1163     public void print(PrintWriter out) {
   1164         out.println("padding");
   1165     }
   1166 }
   1167 
   1168 class ClassInfo extends ConstInfo {
   1169     static final int tag = 7;
   1170     int name;
   1171     int index;
   1172 
   1173     public ClassInfo(int className, int i) {
   1174         name = className;
   1175         index = i;
   1176     }
   1177 
   1178     public ClassInfo(DataInputStream in, int i) throws IOException {
   1179         name = in.readUnsignedShort();
   1180         index = i;
   1181     }
   1182 
   1183     public int getTag() { return tag; }
   1184 
   1185     public String getClassName(ConstPool cp) {
   1186         return cp.getUtf8Info(name);
   1187     };
   1188 
   1189     public void renameClass(ConstPool cp, String oldName, String newName) {
   1190         String nameStr = cp.getUtf8Info(name);
   1191         if (nameStr.equals(oldName))
   1192             name = cp.addUtf8Info(newName);
   1193         else if (nameStr.charAt(0) == '[') {
   1194             String nameStr2 = Descriptor.rename(nameStr, oldName, newName);
   1195             if (nameStr != nameStr2)
   1196                 name = cp.addUtf8Info(nameStr2);
   1197         }
   1198     }
   1199 
   1200     public void renameClass(ConstPool cp, Map map) {
   1201         String oldName = cp.getUtf8Info(name);
   1202         if (oldName.charAt(0) == '[') {
   1203             String newName = Descriptor.rename(oldName, map);
   1204             if (oldName != newName)
   1205                 name = cp.addUtf8Info(newName);
   1206         }
   1207         else {
   1208             String newName = (String)map.get(oldName);
   1209             if (newName != null && !newName.equals(oldName))
   1210                 name = cp.addUtf8Info(newName);
   1211         }
   1212     }
   1213 
   1214     public int copy(ConstPool src, ConstPool dest, Map map) {
   1215         String classname = src.getUtf8Info(name);
   1216         if (map != null) {
   1217             String newname = (String)map.get(classname);
   1218             if (newname != null)
   1219                 classname = newname;
   1220         }
   1221 
   1222         return dest.addClassInfo(classname);
   1223     }
   1224 
   1225     public void write(DataOutputStream out) throws IOException {
   1226         out.writeByte(tag);
   1227         out.writeShort(name);
   1228     }
   1229 
   1230     public void print(PrintWriter out) {
   1231         out.print("Class #");
   1232         out.println(name);
   1233     }
   1234 
   1235     void makeHashtable(ConstPool cp) {
   1236         String name = Descriptor.toJavaName(getClassName(cp));
   1237         cp.classes.put(name, this);
   1238     }
   1239 }
   1240 
   1241 class NameAndTypeInfo extends ConstInfo {
   1242     static final int tag = 12;
   1243     int memberName;
   1244     int typeDescriptor;
   1245 
   1246     public NameAndTypeInfo(int name, int type) {
   1247         memberName = name;
   1248         typeDescriptor = type;
   1249     }
   1250 
   1251     public NameAndTypeInfo(DataInputStream in) throws IOException {
   1252         memberName = in.readUnsignedShort();
   1253         typeDescriptor = in.readUnsignedShort();
   1254     }
   1255 
   1256     boolean hashCheck(int a, int b) { return a == memberName && b == typeDescriptor; }
   1257 
   1258     public int getTag() { return tag; }
   1259 
   1260     public void renameClass(ConstPool cp, String oldName, String newName) {
   1261         String type = cp.getUtf8Info(typeDescriptor);
   1262         String type2 = Descriptor.rename(type, oldName, newName);
   1263         if (type != type2)
   1264             typeDescriptor = cp.addUtf8Info(type2);
   1265     }
   1266 
   1267     public void renameClass(ConstPool cp, Map map) {
   1268         String type = cp.getUtf8Info(typeDescriptor);
   1269         String type2 = Descriptor.rename(type, map);
   1270         if (type != type2)
   1271             typeDescriptor = cp.addUtf8Info(type2);
   1272     }
   1273 
   1274     public int copy(ConstPool src, ConstPool dest, Map map) {
   1275         String mname = src.getUtf8Info(memberName);
   1276         String tdesc = src.getUtf8Info(typeDescriptor);
   1277         tdesc = Descriptor.rename(tdesc, map);
   1278         return dest.addNameAndTypeInfo(dest.addUtf8Info(mname),
   1279                                        dest.addUtf8Info(tdesc));
   1280     }
   1281 
   1282     public void write(DataOutputStream out) throws IOException {
   1283         out.writeByte(tag);
   1284         out.writeShort(memberName);
   1285         out.writeShort(typeDescriptor);
   1286     }
   1287 
   1288     public void print(PrintWriter out) {
   1289         out.print("NameAndType #");
   1290         out.print(memberName);
   1291         out.print(", type #");
   1292         out.println(typeDescriptor);
   1293     }
   1294 }
   1295 
   1296 abstract class MemberrefInfo extends ConstInfo {
   1297     int classIndex;
   1298     int nameAndTypeIndex;
   1299 
   1300     public MemberrefInfo(int cindex, int ntindex) {
   1301         classIndex = cindex;
   1302         nameAndTypeIndex = ntindex;
   1303     }
   1304 
   1305     public MemberrefInfo(DataInputStream in) throws IOException {
   1306         classIndex = in.readUnsignedShort();
   1307         nameAndTypeIndex = in.readUnsignedShort();
   1308     }
   1309 
   1310     public int copy(ConstPool src, ConstPool dest, Map map) {
   1311         int classIndex2 = src.getItem(classIndex).copy(src, dest, map);
   1312         int ntIndex2 = src.getItem(nameAndTypeIndex).copy(src, dest, map);
   1313         return copy2(dest, classIndex2, ntIndex2);
   1314     }
   1315 
   1316     boolean hashCheck(int a, int b) { return a == classIndex && b == nameAndTypeIndex; }
   1317 
   1318     abstract protected int copy2(ConstPool dest, int cindex, int ntindex);
   1319 
   1320     public void write(DataOutputStream out) throws IOException {
   1321         out.writeByte(getTag());
   1322         out.writeShort(classIndex);
   1323         out.writeShort(nameAndTypeIndex);
   1324     }
   1325 
   1326     public void print(PrintWriter out) {
   1327         out.print(getTagName() + " #");
   1328         out.print(classIndex);
   1329         out.print(", name&type #");
   1330         out.println(nameAndTypeIndex);
   1331     }
   1332 
   1333     public abstract String getTagName();
   1334 }
   1335 
   1336 class FieldrefInfo extends MemberrefInfo {
   1337     static final int tag = 9;
   1338 
   1339     public FieldrefInfo(int cindex, int ntindex) {
   1340         super(cindex, ntindex);
   1341     }
   1342 
   1343     public FieldrefInfo(DataInputStream in) throws IOException {
   1344         super(in);
   1345     }
   1346 
   1347     public int getTag() { return tag; }
   1348 
   1349     public String getTagName() { return "Field"; }
   1350 
   1351     protected int copy2(ConstPool dest, int cindex, int ntindex) {
   1352         return dest.addFieldrefInfo(cindex, ntindex);
   1353     }
   1354 }
   1355 
   1356 class MethodrefInfo extends MemberrefInfo {
   1357     static final int tag = 10;
   1358 
   1359     public MethodrefInfo(int cindex, int ntindex) {
   1360         super(cindex, ntindex);
   1361     }
   1362 
   1363     public MethodrefInfo(DataInputStream in) throws IOException {
   1364         super(in);
   1365     }
   1366 
   1367     public int getTag() { return tag; }
   1368 
   1369     public String getTagName() { return "Method"; }
   1370 
   1371     protected int copy2(ConstPool dest, int cindex, int ntindex) {
   1372         return dest.addMethodrefInfo(cindex, ntindex);
   1373     }
   1374 }
   1375 
   1376 class InterfaceMethodrefInfo extends MemberrefInfo {
   1377     static final int tag = 11;
   1378 
   1379     public InterfaceMethodrefInfo(int cindex, int ntindex) {
   1380         super(cindex, ntindex);
   1381     }
   1382 
   1383     public InterfaceMethodrefInfo(DataInputStream in) throws IOException {
   1384         super(in);
   1385     }
   1386 
   1387     public int getTag() { return tag; }
   1388 
   1389     public String getTagName() { return "Interface"; }
   1390 
   1391     protected int copy2(ConstPool dest, int cindex, int ntindex) {
   1392         return dest.addInterfaceMethodrefInfo(cindex, ntindex);
   1393     }
   1394 }
   1395 
   1396 class StringInfo extends ConstInfo {
   1397     static final int tag = 8;
   1398     int string;
   1399 
   1400     public StringInfo(int str) {
   1401         string = str;
   1402     }
   1403 
   1404     public StringInfo(DataInputStream in) throws IOException {
   1405         string = in.readUnsignedShort();
   1406     }
   1407 
   1408     public int getTag() { return tag; }
   1409 
   1410     public int copy(ConstPool src, ConstPool dest, Map map) {
   1411         return dest.addStringInfo(src.getUtf8Info(string));
   1412     }
   1413 
   1414     public void write(DataOutputStream out) throws IOException {
   1415         out.writeByte(tag);
   1416         out.writeShort(string);
   1417     }
   1418 
   1419     public void print(PrintWriter out) {
   1420         out.print("String #");
   1421         out.println(string);
   1422     }
   1423 }
   1424 
   1425 class IntegerInfo extends ConstInfo {
   1426     static final int tag = 3;
   1427     int value;
   1428 
   1429     public IntegerInfo(int i) {
   1430         value = i;
   1431     }
   1432 
   1433     public IntegerInfo(DataInputStream in) throws IOException {
   1434         value = in.readInt();
   1435     }
   1436 
   1437     public int getTag() { return tag; }
   1438 
   1439     public int copy(ConstPool src, ConstPool dest, Map map) {
   1440         return dest.addIntegerInfo(value);
   1441     }
   1442 
   1443     public void write(DataOutputStream out) throws IOException {
   1444         out.writeByte(tag);
   1445         out.writeInt(value);
   1446     }
   1447 
   1448     public void print(PrintWriter out) {
   1449         out.print("Integer ");
   1450         out.println(value);
   1451     }
   1452 }
   1453 
   1454 class FloatInfo extends ConstInfo {
   1455     static final int tag = 4;
   1456     float value;
   1457 
   1458     public FloatInfo(float f) {
   1459         value = f;
   1460     }
   1461 
   1462     public FloatInfo(DataInputStream in) throws IOException {
   1463         value = in.readFloat();
   1464     }
   1465 
   1466     public int getTag() { return tag; }
   1467 
   1468     public int copy(ConstPool src, ConstPool dest, Map map) {
   1469         return dest.addFloatInfo(value);
   1470     }
   1471 
   1472     public void write(DataOutputStream out) throws IOException {
   1473         out.writeByte(tag);
   1474         out.writeFloat(value);
   1475     }
   1476 
   1477     public void print(PrintWriter out) {
   1478         out.print("Float ");
   1479         out.println(value);
   1480     }
   1481 }
   1482 
   1483 class LongInfo extends ConstInfo {
   1484     static final int tag = 5;
   1485     long value;
   1486 
   1487     public LongInfo(long l) {
   1488         value = l;
   1489     }
   1490 
   1491     public LongInfo(DataInputStream in) throws IOException {
   1492         value = in.readLong();
   1493     }
   1494 
   1495     public int getTag() { return tag; }
   1496 
   1497     public int copy(ConstPool src, ConstPool dest, Map map) {
   1498         return dest.addLongInfo(value);
   1499     }
   1500 
   1501     public void write(DataOutputStream out) throws IOException {
   1502         out.writeByte(tag);
   1503         out.writeLong(value);
   1504     }
   1505 
   1506     public void print(PrintWriter out) {
   1507         out.print("Long ");
   1508         out.println(value);
   1509     }
   1510 }
   1511 
   1512 class DoubleInfo extends ConstInfo {
   1513     static final int tag = 6;
   1514     double value;
   1515 
   1516     public DoubleInfo(double d) {
   1517         value = d;
   1518     }
   1519 
   1520     public DoubleInfo(DataInputStream in) throws IOException {
   1521         value = in.readDouble();
   1522     }
   1523 
   1524     public int getTag() { return tag; }
   1525 
   1526     public int copy(ConstPool src, ConstPool dest, Map map) {
   1527         return dest.addDoubleInfo(value);
   1528     }
   1529 
   1530     public void write(DataOutputStream out) throws IOException {
   1531         out.writeByte(tag);
   1532         out.writeDouble(value);
   1533     }
   1534 
   1535     public void print(PrintWriter out) {
   1536         out.print("Double ");
   1537         out.println(value);
   1538     }
   1539 }
   1540 
   1541 class Utf8Info extends ConstInfo {
   1542     static final int tag = 1;
   1543     String string;
   1544     int index;
   1545 
   1546     public Utf8Info(String utf8, int i) {
   1547         string = utf8;
   1548         index = i;
   1549     }
   1550 
   1551     public Utf8Info(DataInputStream in, int i) throws IOException {
   1552         string = in.readUTF();
   1553         index = i;
   1554     }
   1555 
   1556     public int getTag() { return tag; }
   1557 
   1558     public int copy(ConstPool src, ConstPool dest, Map map) {
   1559         return dest.addUtf8Info(string);
   1560     }
   1561 
   1562     public void write(DataOutputStream out) throws IOException {
   1563         out.writeByte(tag);
   1564         out.writeUTF(string);
   1565     }
   1566 
   1567     public void print(PrintWriter out) {
   1568         out.print("UTF8 \"");
   1569         out.print(string);
   1570         out.println("\"");
   1571     }
   1572 }
   1573