View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.classfile;
    18
    19  import java.io.DataInputStream;
    20  import java.io.DataOutputStream;
    21  import java.io.IOException;
    22  import java.io.Serializable;
    23  import org.apache.bcel.Constants;
    24
    25  /***
    26   * This class represents the constant pool, i.e., a table of constants, of
    27   * a parsed classfile. It may contain null references, due to the JVM
    28   * specification that skips an entry after an 8-byte constant (double,
    29   * long) entry.  Those interested in generating constant pools
    30   * programatically should see <a href="../generic/ConstantPoolGen.html">
    31   * ConstantPoolGen</a>.
    32
    33   * @version $Id: ConstantPool.java 386056 2006-03-15 11:31:56Z tcurdt $
    34   * @see     Constant
    35   * @see     org.apache.bcel.generic.ConstantPoolGen
    36   * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    37   */
    38  public class ConstantPool implements Cloneable, Node, Serializable {
    39
    40      private int constant_pool_count;
    41      private Constant[] constant_pool;
    42
    43
    44      /***
    45       * @param constant_pool Array of constants
    46       */
    47      public ConstantPool(Constant[] constant_pool) {
    48          setConstantPool(constant_pool);
    49      }
    50
    51
    52      /***
    53       * Read constants from given file stream.
    54       *
    55       * @param file Input stream
    56       * @throws IOException
    57       * @throws ClassFormatException
    58       */
    59      ConstantPool(DataInputStream file) throws IOException, ClassFormatException {
    60          byte tag;
    61          constant_pool_count = file.readUnsignedShort();
    62          constant_pool = new Constant[constant_pool_count];
    63          /* constant_pool[0] is unused by the compiler and may be used freely
    64           * by the implementation.
    65           */
    66          for (int i = 1; i < constant_pool_count; i++) {
    67              constant_pool[i] = Constant.readConstant(file);
    68              /* Quote from the JVM specification:
    69               * "All eight byte constants take up two spots in the constant pool.
    70               * If this is the n'th byte in the constant pool, then the next item
    71               * will be numbered n+2"
    72               *
    73               * Thus we have to increment the index counter.
    74               */
    75              tag = constant_pool[i].getTag();
    76              if ((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long)) {
    77                  i++;
    78              }
    79          }
    80      }
    81
    82
    83      /***
    84       * Called by objects that are traversing the nodes of the tree implicitely
    85       * defined by the contents of a Java class. I.e., the hierarchy of methods,
    86       * fields, attributes, etc. spawns a tree of objects.
    87       *
    88       * @param v Visitor object
    89       */
    90      public void accept( Visitor v ) {
    91          v.visitConstantPool(this);
    92      }
    93
    94
    95      /***
    96       * Resolve constant to a string representation.
    97       *
    98       * @param  c Constant to be printed
    99       * @return String representation
    100      */
    101     public String constantToString( Constant c ) throws ClassFormatException {
    102         String str;
    103         int i;
    104         byte tag = c.getTag();
    105         switch (tag) {
    106             case Constants.CONSTANT_Class:
    107                 i = ((ConstantClass) c).getNameIndex();
    108                 c = getConstant(i, Constants.CONSTANT_Utf8);
    109                 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
    110                 break;
    111             case Constants.CONSTANT_String:
    112                 i = ((ConstantString) c).getStringIndex();
    113                 c = getConstant(i, Constants.CONSTANT_Utf8);
    114                 str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
    115                 break;
    116             case Constants.CONSTANT_Utf8:
    117                 str = ((ConstantUtf8) c).getBytes();
    118                 break;
    119             case Constants.CONSTANT_Double:
    120                 str = "" + ((ConstantDouble) c).getBytes();
    121                 break;
    122             case Constants.CONSTANT_Float:
    123                 str = "" + ((ConstantFloat) c).getBytes();
    124                 break;
    125             case Constants.CONSTANT_Long:
    126                 str = "" + ((ConstantLong) c).getBytes();
    127                 break;
    128             case Constants.CONSTANT_Integer:
    129                 str = "" + ((ConstantInteger) c).getBytes();
    130                 break;
    131             case Constants.CONSTANT_NameAndType:
    132                 str = (constantToString(((ConstantNameAndType) c).getNameIndex(),
    133                         Constants.CONSTANT_Utf8)
    134                         + " " + constantToString(((ConstantNameAndType) c).getSignatureIndex(),
    135                         Constants.CONSTANT_Utf8));
    136                 break;
    137             case Constants.CONSTANT_InterfaceMethodref:
    138             case Constants.CONSTANT_Methodref:
    139             case Constants.CONSTANT_Fieldref:
    140                 str = (constantToString(((ConstantCP) c).getClassIndex(), Constants.CONSTANT_Class)
    141                         + "." + constantToString(((ConstantCP) c).getNameAndTypeIndex(),
    142                         Constants.CONSTANT_NameAndType));
    143                 break;
    144             default: // Never reached
    145                 throw new RuntimeException("Unknown constant type " + tag);
    146         }
    147         return str;
    148     }
    149
    150
    151     private static final String escape( String str ) {
    152         int len = str.length();
    153         StringBuffer buf = new StringBuffer(len + 5);
    154         char[] ch = str.toCharArray();
    155         for (int i = 0; i < len; i++) {
    156             switch (ch[i]) {
    157                 case '\n':
    158                     buf.append("//n");
    159                     break;
    160                 case '\r':
    161                     buf.append("//r");
    162                     break;
    163                 case '\t':
    164                     buf.append("//t");
    165                     break;
    166                 case '\b':
    167                     buf.append("//b");
    168                     break;
    169                 case '"':
    170                     buf.append("//\"");
    171                     break;
    172                 default:
    173                     buf.append(ch[i]);
    174             }
    175         }
    176         return buf.toString();
    177     }
    178
    179
    180     /***
    181      * Retrieve constant at `index' from constant pool and resolve it to
    182      * a string representation.
    183      *
    184      * @param  index of constant in constant pool
    185      * @param  tag expected type
    186      * @return String representation
    187      */
    188     public String constantToString( int index, byte tag ) throws ClassFormatException {
    189         Constant c = getConstant(index, tag);
    190         return constantToString(c);
    191     }
    192
    193
    194     /***
    195      * Dump constant pool to file stream in binary format.
    196      *
    197      * @param file Output file stream
    198      * @throws IOException
    199      */
    200     public void dump( DataOutputStream file ) throws IOException {
    201         file.writeShort(constant_pool_count);
    202         for (int i = 1; i < constant_pool_count; i++) {
    203             if (constant_pool[i] != null) {
    204                 constant_pool[i].dump(file);
    205             }
    206         }
    207     }
    208
    209
    210     /***
    211      * Get constant from constant pool.
    212      *
    213      * @param  index Index in constant pool
    214      * @return Constant value
    215      * @see    Constant
    216      */
    217     public Constant getConstant( int index ) {
    218         if (index >= constant_pool.length || index < 0) {
    219             throw new ClassFormatException("Invalid constant pool reference: " + index
    220                     + ". Constant pool size is: " + constant_pool.length);
    221         }
    222         return constant_pool[index];
    223     }
    224
    225
    226     /***
    227      * Get constant from constant pool and check whether it has the
    228      * expected type.
    229      *
    230      * @param  index Index in constant pool
    231      * @param  tag Tag of expected constant, i.e., its type
    232      * @return Constant value
    233      * @see    Constant
    234      * @throws  ClassFormatException
    235      */
    236     public Constant getConstant( int index, byte tag ) throws ClassFormatException {
    237         Constant c;
    238         c = getConstant(index);
    239         if (c == null) {
    240             throw new ClassFormatException("Constant pool at index " + index + " is null.");
    241         }
    242         if (c.getTag() != tag) {
    243             throw new ClassFormatException("Expected class `" + Constants.CONSTANT_NAMES[tag]
    244                     + "' at index " + index + " and got " + c);
    245         }
    246         return c;
    247     }
    248
    249
    250     /***
    251      * @return Array of constants.
    252      * @see    Constant
    253      */
    254     public Constant[] getConstantPool() {
    255         return constant_pool;
    256     }
    257
    258
    259     /***
    260      * Get string from constant pool and bypass the indirection of
    261      * `ConstantClass' and `ConstantString' objects. I.e. these classes have
    262      * an index field that points to another entry of the constant pool of
    263      * type `ConstantUtf8' which contains the real data.
    264      *
    265      * @param  index Index in constant pool
    266      * @param  tag Tag of expected constant, either ConstantClass or ConstantString
    267      * @return Contents of string reference
    268      * @see    ConstantClass
    269      * @see    ConstantString
    270      * @throws  ClassFormatException
    271      */
    272     public String getConstantString( int index, byte tag ) throws ClassFormatException {
    273         Constant c;
    274         int i;
    275         c = getConstant(index, tag);
    276         /* This switch() is not that elegant, since the two classes have the
    277          * same contents, they just differ in the name of the index
    278          * field variable.
    279          * But we want to stick to the JVM naming conventions closely though
    280          * we could have solved these more elegantly by using the same
    281          * variable name or by subclassing.
    282          */
    283         switch (tag) {
    284             case Constants.CONSTANT_Class:
    285                 i = ((ConstantClass) c).getNameIndex();
    286                 break;
    287             case Constants.CONSTANT_String:
    288                 i = ((ConstantString) c).getStringIndex();
    289                 break;
    290             default:
    291                 throw new RuntimeException("getConstantString called with illegal tag " + tag);
    292         }
    293         // Finally get the string from the constant pool
    294         c = getConstant(i, Constants.CONSTANT_Utf8);
    295         return ((ConstantUtf8) c).getBytes();
    296     }
    297
    298
    299     /***
    300      * @return Length of constant pool.
    301      */
    302     public int getLength() {
    303         return constant_pool_count;
    304     }
    305
    306
    307     /***
    308      * @param constant Constant to set
    309      */
    310     public void setConstant( int index, Constant constant ) {
    311         constant_pool[index] = constant;
    312     }
    313
    314
    315     /***
    316      * @param constant_pool
    317      */
    318     public void setConstantPool( Constant[] constant_pool ) {
    319         this.constant_pool = constant_pool;
    320         constant_pool_count = (constant_pool == null) ? 0 : constant_pool.length;
    321     }
    322
    323
    324     /***
    325      * @return String representation.
    326      */
    327     public String toString() {
    328         StringBuffer buf = new StringBuffer();
    329         for (int i = 1; i < constant_pool_count; i++) {
    330             buf.append(i).append(")").append(constant_pool[i]).append("\n");
    331         }
    332         return buf.toString();
    333     }
    334
    335
    336     /***
    337      * @return deep copy of this constant pool
    338      */
    339     public ConstantPool copy() {
    340         ConstantPool c = null;
    341         try {
    342             c = (ConstantPool) clone();
    343             c.constant_pool = new Constant[constant_pool_count];
    344             for (int i = 1; i < constant_pool_count; i++) {
    345                 if (constant_pool[i] != null) {
    346                     c.constant_pool[i] = constant_pool[i].copy();
    347                 }
    348             }
    349         } catch (CloneNotSupportedException e) {
    350         }
    351         return c;
    352     }
    353 }