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:44:01 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 Constants, 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 == CONSTANT_Double) || (tag == 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 CONSTANT_Class: 
00097       i   = ((ConstantClass)c).getNameIndex();
00098       c   = getConstant(i, CONSTANT_Utf8);
00099       str = Utility.compactClassName(((ConstantUtf8)c).getBytes(), false);
00100       break;
00101 
00102     case CONSTANT_String:
00103       i   = ((ConstantString)c).getStringIndex();
00104       c   = getConstant(i, CONSTANT_Utf8);
00105       str = "\"" + escape(((ConstantUtf8)c).getBytes()) + "\"";
00106       break;
00107 
00108     case CONSTANT_Utf8:    str = ((ConstantUtf8)c).getBytes();         break;
00109     case CONSTANT_Double:  str = "" + ((ConstantDouble)c).getBytes();  break;
00110     case CONSTANT_Float:   str = "" + ((ConstantFloat)c).getBytes();   break;
00111     case CONSTANT_Long:    str = "" + ((ConstantLong)c).getBytes();    break;
00112     case CONSTANT_Integer: str = "" + ((ConstantInteger)c).getBytes(); break;
00113 
00114     case CONSTANT_NameAndType:
00115       str = (constantToString(((ConstantNameAndType)c).getNameIndex(),
00116                   CONSTANT_Utf8) + " " +
00117          constantToString(((ConstantNameAndType)c).getSignatureIndex(),
00118                   CONSTANT_Utf8));
00119       break;
00120 
00121     case CONSTANT_InterfaceMethodref: case CONSTANT_Methodref: case CONSTANT_Fieldref:
00122       str = (constantToString(((ConstantCP)c).getClassIndex(),
00123                   CONSTANT_Class) + "." + 
00124          constantToString(((ConstantCP)c).getNameAndTypeIndex(),
00125                   CONSTANT_NameAndType));        
00126       break;
00127 
00128     default: // Never reached
00129       throw new RuntimeException("Unknown constant type " + tag);
00130     }
00131     
00132     return str;
00133   }  
00134   /**
00135    * @return deep copy of this constant pool
00136    */
00137   public ConstantPool copy() {
00138     ConstantPool c = null;
00139 
00140     try {
00141       c = (ConstantPool)clone();
00142     } catch(CloneNotSupportedException e) {}
00143 
00144     c.constant_pool = new Constant[constant_pool_count];
00145 
00146     for(int i=1; i < constant_pool_count; i++) {
00147       if(constant_pool[i] != null)
00148     c.constant_pool[i] = constant_pool[i].copy();
00149     }
00150 
00151     return c;
00152   }  
00153   /** 
00154    * Dump constant pool to file stream in binary format.
00155    *
00156    * @param file Output file stream
00157    * @throw IOException
00158    */
00159   public void dump(DataOutputStream file) throws IOException
00160   {
00161     file.writeShort(constant_pool_count);
00162 
00163     for(int i=1; i < constant_pool_count; i++)
00164       if(constant_pool[i] != null)
00165     constant_pool[i].dump(file);
00166   }  
00167   private static final String escape(String str) {
00168     int          len = str.length();
00169     StringBuffer buf = new StringBuffer(len + 5);
00170     char[]       ch  = str.toCharArray();
00171 
00172     for(int i=0; i < len; i++) {
00173       switch(ch[i]) {
00174       case '\n' : buf.append("\\n"); break;
00175       case '\r' : buf.append("\\r"); break;
00176       case '\t' : buf.append("\\t"); break;
00177       case '\b' : buf.append("\\b"); break;
00178       case '"'  : buf.append("\\\""); break;
00179       default: buf.append(ch[i]);
00180       }
00181     }
00182 
00183     return buf.toString();
00184   }  
00185   /**
00186    * Get constant from constant pool.
00187    *
00188    * @param  index Index in constant pool
00189    * @return Constant value
00190    * @see    Constant
00191    */
00192   public Constant getConstant(int index) {
00193     return constant_pool[index];
00194   }  
00195   /**
00196    * Get constant from constant pool and check whether it has the
00197    * expected type.
00198    *
00199    * @param  index Index in constant pool
00200    * @param  tag Tag of expected constant, i.e. its type
00201    * @return Constant value
00202    * @see    Constant
00203    * @throw  ClassFormatError
00204    */
00205   public Constant getConstant(int index, byte tag)
00206        throws ClassFormatError
00207   {
00208     Constant c;
00209 
00210     c = constant_pool[index];
00211 
00212     if(c == null)
00213       throw new ClassFormatError("Constant pool at index " + index + " is null.");
00214 
00215     if(c.getTag() == tag)
00216       return c;
00217     else
00218       throw new ClassFormatError("Expected class `" + CONSTANT_NAMES[tag] + 
00219                  "' at index " + index + " and got " + c);
00220   }  
00221   /**
00222    * @return Array of constants.
00223    * @see    Constant
00224    */
00225   public Constant[] getConstantPool() { return constant_pool;  }  
00226   /**
00227    * Get string from constant pool and bypass the indirection of 
00228    * `ConstantClass' and `ConstantString' objects. I.e. these classes have
00229    * an index field that points to another entry of the constant pool of
00230    * type `ConstantUtf8' which contains the real data.
00231    *
00232    * @param  index Index in constant pool
00233    * @param  tag Tag of expected constant, either ConstantClass or ConstantString
00234    * @return Contents of string reference
00235    * @see    ConstantClass
00236    * @see    ConstantString
00237    * @throw  ClassFormatError
00238    */
00239   public String getConstantString(int index, byte tag) 
00240        throws ClassFormatError
00241   {
00242     Constant c;
00243     int    i;
00244     String   s;
00245 
00246     c = getConstant(index, tag);
00247 
00248     /* This switch() is not that elegant, since the two classes have the
00249      * same contents, they just differ in the name of the index
00250      * field variable.
00251      * But we want to stick to the JVM naming conventions closely though
00252      * we could have solved these more elegantly by using the same
00253      * variable name or by subclassing.
00254      */
00255     switch(tag) {
00256     case CONSTANT_Class:  i = ((ConstantClass)c).getNameIndex();    break;
00257     case CONSTANT_String: i = ((ConstantString)c).getStringIndex(); break;
00258     default:              throw new RuntimeException("getConstantString" +
00259                              "called with illegal tag " +
00260                              tag);
00261     }
00262 
00263     // Finally get the string from the constant pool
00264     c = getConstant(i, 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:58 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001