Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

ConstantPool.java

00001 package de.fub.bytecode.classfile;
00002 
00003 import  de.fub.bytecode.Constants;
00004 import  java.io.*;
00005 
00006 /**
00007  * This class represents the constant pool, i.e., a table of constants.
00008  * It may contain null references, due to the JVM specification that skips
00009  * an entry after an 8-byte constant (double, long) entry.
00010  *
00011  * @version $Id: ConstantPool.java,v 1.1.1.1 2002/01/24 03:41:37 pserver Exp $
00012  * @see     Constant
00013  * @author <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00014  */
00015 public class ConstantPool implements Cloneable {
00016   private int        constant_pool_count;
00017   private Constant[] constant_pool;
00018 
00019   /**
00020    * @param constant_pool Array of constants
00021    */
00022   public ConstantPool(Constant[] constant_pool)
00023   {
00024     setConstantPool(constant_pool);
00025   }  
00026   /**
00027    * Read constants from given file stream.
00028    *
00029    * @param file Input stream
00030    * @throw IOException
00031    * @throw ClassFormatError
00032    */
00033   ConstantPool(DataInputStream file) throws IOException, ClassFormatError
00034   {
00035     byte tag;
00036 
00037     constant_pool_count = file.readUnsignedShort();
00038     constant_pool       = new Constant[constant_pool_count];
00039 
00040     /* constant_pool[0] is unused by the compiler and may be used freely
00041      * by the implementation.
00042      */
00043     for(int i=1; i < constant_pool_count; i++) {
00044       constant_pool[i] = Constant.readConstant(file);
00045       
00046       /* Quote from the JVM specification:
00047        * "All eight byte constants take up two spots in the constant pool.
00048        * If this is the n'th byte in the constant pool, then the next item
00049        * will be numbered n+2"
00050        * 
00051        * Thus we have to increment the index counter.
00052        */
00053       tag = constant_pool[i].getTag();
00054       if((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long))
00055     i++;
00056     }
00057   }  
00058   /**
00059    * Called by objects that are traversing the nodes of the tree implicitely
00060    * defined by the contents of a Java class. I.e., the hierarchy of methods,
00061    * fields, attributes, etc. spawns a tree of objects.
00062    *
00063    * @param v Visitor object
00064    */
00065   public void accept(Visitor v) {
00066     v.visitConstantPool(this);
00067   }  
00068   /**
00069    * Retrieve constant at `index' from constant pool and resolve it to
00070    * a string representation.
00071    *
00072    * @param  index of constant in constant pool
00073    * @param  tag expected type
00074    * @return String representation
00075    */
00076   public String constantToString(int index, byte tag) 
00077        throws ClassFormatError
00078   {
00079     Constant c = getConstant(index, tag);
00080     return constantToString(c);
00081   }  
00082   /**
00083    * Resolve constant to a string representation.
00084    *
00085    * @param  constant Constant to be printed
00086    * @return String representation
00087    */
00088   public String constantToString(Constant c)
00089        throws ClassFormatError  
00090   {
00091     String   str;
00092     int      i;
00093     byte     tag = c.getTag();
00094 
00095     switch(tag) {
00096     case Constants.CONSTANT_Class: 
00097       i   = ((ConstantClass)c).getNameIndex();
00098       c   = getConstant(i, Constants.CONSTANT_Utf8);
00099       str = Utility.compactClassName(((ConstantUtf8)c).getBytes(), false);
00100       break;
00101 
00102     case Constants.CONSTANT_String:
00103       i   = ((ConstantString)c).getStringIndex();
00104       c   = getConstant(i, Constants.CONSTANT_Utf8);
00105       str = "\"" + escape(((ConstantUtf8)c).getBytes()) + "\"";
00106       break;
00107 
00108     case Constants.CONSTANT_Utf8:    str = ((ConstantUtf8)c).getBytes();         break;
00109     case Constants.CONSTANT_Double:  str = "" + ((ConstantDouble)c).getBytes();  break;
00110     case Constants.CONSTANT_Float:   str = "" + ((ConstantFloat)c).getBytes();   break;
00111     case Constants.CONSTANT_Long:    str = "" + ((ConstantLong)c).getBytes();    break;
00112     case Constants.CONSTANT_Integer: str = "" + ((ConstantInteger)c).getBytes(); break;
00113 
00114     case Constants.CONSTANT_NameAndType:
00115       str = (constantToString(((ConstantNameAndType)c).getNameIndex(),
00116                   Constants.CONSTANT_Utf8) + " " +
00117          constantToString(((ConstantNameAndType)c).getSignatureIndex(),
00118                   Constants.CONSTANT_Utf8));
00119       break;
00120 
00121     case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref:
00122     case Constants.CONSTANT_Fieldref:
00123       str = (constantToString(((ConstantCP)c).getClassIndex(),
00124                   Constants.CONSTANT_Class) +   "." + 
00125          constantToString(((ConstantCP)c).getNameAndTypeIndex(),
00126                   Constants.CONSTANT_NameAndType));      
00127       break;
00128 
00129     default: // Never reached
00130       throw new RuntimeException("Unknown constant type " + tag);
00131     }
00132     
00133     return str;
00134   }  
00135   /**
00136    * @return deep copy of this constant pool
00137    */
00138   public ConstantPool copy() {
00139     ConstantPool c = null;
00140 
00141     try {
00142       c = (ConstantPool)clone();
00143     } catch(CloneNotSupportedException e) {}
00144 
00145     c.constant_pool = new Constant[constant_pool_count];
00146 
00147     for(int i=1; i < constant_pool_count; i++) {
00148       if(constant_pool[i] != null)
00149     c.constant_pool[i] = constant_pool[i].copy();
00150     }
00151 
00152     return c;
00153   }  
00154   /** 
00155    * Dump constant pool to file stream in binary format.
00156    *
00157    * @param file Output file stream
00158    * @throw IOException
00159    */
00160   public void dump(DataOutputStream file) throws IOException
00161   {
00162     file.writeShort(constant_pool_count);
00163 
00164     for(int i=1; i < constant_pool_count; i++)
00165       if(constant_pool[i] != null)
00166     constant_pool[i].dump(file);
00167   }  
00168   private static final String escape(String str) {
00169     int          len = str.length();
00170     StringBuffer buf = new StringBuffer(len + 5);
00171     char[]       ch  = str.toCharArray();
00172 
00173     for(int i=0; i < len; i++) {
00174       switch(ch[i]) {
00175       case '\n' : buf.append("\\n"); break;
00176       case '\r' : buf.append("\\r"); break;
00177       case '\t' : buf.append("\\t"); break;
00178       case '\b' : buf.append("\\b"); break;
00179       case '"'  : buf.append("\\\""); break;
00180       default: buf.append(ch[i]);
00181       }
00182     }
00183 
00184     return buf.toString();
00185   }  
00186   /**
00187    * Get constant from constant pool.
00188    *
00189    * @param  index Index in constant pool
00190    * @return Constant value
00191    * @see    Constant
00192    */
00193   public Constant getConstant(int index) {
00194     return constant_pool[index];
00195   }  
00196   /**
00197    * Get constant from constant pool and check whether it has the
00198    * expected type.
00199    *
00200    * @param  index Index in constant pool
00201    * @param  tag Tag of expected constant, i.e., its type
00202    * @return Constant value
00203    * @see    Constant
00204    * @throw  ClassFormatError
00205    */
00206   public Constant getConstant(int index, byte tag)
00207        throws ClassFormatError
00208   {
00209     Constant c;
00210 
00211     c = constant_pool[index];
00212 
00213     if(c == null)
00214       throw new ClassFormatError("Constant pool at index " + index + " is null.");
00215 
00216     if(c.getTag() == tag)
00217       return c;
00218     else
00219       throw new ClassFormatError("Expected class `" + Constants.CONSTANT_NAMES[tag] + 
00220                  "' at index " + index + " and got " + c);
00221   }  
00222   /**
00223    * @return Array of constants.
00224    * @see    Constant
00225    */
00226   public Constant[] getConstantPool() { return constant_pool;  }  
00227   /**
00228    * Get string from constant pool and bypass the indirection of 
00229    * `ConstantClass' and `ConstantString' objects. I.e. these classes have
00230    * an index field that points to another entry of the constant pool of
00231    * type `ConstantUtf8' which contains the real data.
00232    *
00233    * @param  index Index in constant pool
00234    * @param  tag Tag of expected constant, either ConstantClass or ConstantString
00235    * @return Contents of string reference
00236    * @see    ConstantClass
00237    * @see    ConstantString
00238    * @throw  ClassFormatError
00239    */
00240   public String getConstantString(int index, byte tag) 
00241        throws ClassFormatError
00242   {
00243     Constant c;
00244     int    i;
00245     String   s;
00246 
00247     c = getConstant(index, tag);
00248 
00249     /* This switch() is not that elegant, since the two classes have the
00250      * same contents, they just differ in the name of the index
00251      * field variable.
00252      * But we want to stick to the JVM naming conventions closely though
00253      * we could have solved these more elegantly by using the same
00254      * variable name or by subclassing.
00255      */
00256     switch(tag) {
00257     case Constants.CONSTANT_Class:  i = ((ConstantClass)c).getNameIndex();    break;
00258     case Constants.CONSTANT_String: i = ((ConstantString)c).getStringIndex(); break;
00259     default:
00260       throw new RuntimeException("getConstantString called with illegal tag " + tag);
00261     }
00262 
00263     // Finally get the string from the constant pool
00264     c = getConstant(i, Constants.CONSTANT_Utf8);
00265     return ((ConstantUtf8)c).getBytes();
00266   }  
00267   /**
00268    * @return Length of constant pool.
00269    */
00270   public int getLength()
00271   {
00272     return constant_pool_count;
00273   }  
00274   /**
00275    * @param constant Constant to set
00276    */
00277   public void setConstant(int index, Constant constant) {
00278     constant_pool[index] = constant;
00279   }  
00280   /**
00281    * @param constant_pool
00282    */
00283   public void setConstantPool(Constant[] constant_pool) {
00284     this.constant_pool = constant_pool;
00285     constant_pool_count = (constant_pool == null)? 0 : constant_pool.length;
00286   }  
00287   /**
00288    * @return String representation.
00289    */
00290   public String toString() {
00291     StringBuffer buf = new StringBuffer();
00292 
00293     for(int i=1; i < constant_pool_count; i++)
00294       buf.append(i + ")" + constant_pool[i] + "\n");
00295 
00296     return buf.toString();
00297   }  
00298 }

Generated at Thu Feb 7 06:42:59 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001