1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 package com.sun.org.apache.bcel.internal.classfile; 6 7 /* ==================================================================== 8 * The Apache Software License, Version 1.1 9 * 10 * Copyright (c) 2001 The Apache Software Foundation. All rights 11 * reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * 3. The end-user documentation included with the redistribution, 26 * if any, must include the following acknowledgment: 27 * "This product includes software developed by the 28 * Apache Software Foundation (http://www.apache.org/)." 29 * Alternately, this acknowledgment may appear in the software itself, 30 * if and wherever such third-party acknowledgments normally appear. 31 * 32 * 4. The names "Apache" and "Apache Software Foundation" and 33 * "Apache BCEL" must not be used to endorse or promote products 34 * derived from this software without prior written permission. For 35 * written permission, please contact apache@apache.org. 36 * 37 * 5. Products derived from this software may not be called "Apache", 38 * "Apache BCEL", nor may "Apache" appear in their name, without 39 * prior written permission of the Apache Software Foundation. 40 * 41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 * ==================================================================== 54 * 55 * This software consists of voluntary contributions made by many 56 * individuals on behalf of the Apache Software Foundation. For more 57 * information on the Apache Software Foundation, please see 58 * <http://www.apache.org/>. 59 */ 60 61 import com.sun.org.apache.bcel.internal.Constants; 62 import java.io.*; 63 64 /** 65 * This class represents the constant pool, i.e., a table of constants, of 66 * a parsed classfile. It may contain null references, due to the JVM 67 * specification that skips an entry after an 8-byte constant (double, 68 * long) entry. Those interested in generating constant pools 69 * programatically should see <a href="../generic/ConstantPoolGen.html"> 70 * ConstantPoolGen</a>. 71 72 * @see Constant 73 * @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen 74 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 75 */ 76 public class ConstantPool implements Cloneable, Node, Serializable { 77 private int constant_pool_count; 78 private Constant[] constant_pool; 79 80 /** 81 * @param constant_pool Array of constants 82 */ 83 public ConstantPool(Constant[] constant_pool) 84 { 85 setConstantPool(constant_pool); 86 } 87 88 /** 89 * Read constants from given file stream. 90 * 91 * @param file Input stream 92 * @throws IOException 93 * @throws ClassFormatException 94 */ 95 ConstantPool(DataInputStream file) throws IOException, ClassFormatException 96 { 97 byte tag; 98 99 constant_pool_count = file.readUnsignedShort(); 100 constant_pool = new Constant[constant_pool_count]; 101 102 /* constant_pool[0] is unused by the compiler and may be used freely 103 * by the implementation. 104 */ 105 for(int i=1; i < constant_pool_count; i++) { 106 constant_pool[i] = Constant.readConstant(file); 107 108 /* Quote from the JVM specification: 109 * "All eight byte constants take up two spots in the constant pool. 110 * If this is the n'th byte in the constant pool, then the next item 111 * will be numbered n+2" 112 * 113 * Thus we have to increment the index counter. 114 */ 115 tag = constant_pool[i].getTag(); 116 if((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long)) 117 i++; 118 } 119 } 120 121 /** 122 * Called by objects that are traversing the nodes of the tree implicitely 123 * defined by the contents of a Java class. I.e., the hierarchy of methods, 124 * fields, attributes, etc. spawns a tree of objects. 125 * 126 * @param v Visitor object 127 */ 128 public void accept(Visitor v) { 129 v.visitConstantPool(this); 130 } 131 132 /** 133 * Resolve constant to a string representation. 134 * 135 * @param constant Constant to be printed 136 * @return String representation 137 */ 138 public String constantToString(Constant c) 139 throws ClassFormatException 140 { 141 String str; 142 int i; 143 byte tag = c.getTag(); 144 145 switch(tag) { 146 case Constants.CONSTANT_Class: 147 i = ((ConstantClass)c).getNameIndex(); 148 c = getConstant(i, Constants.CONSTANT_Utf8); 149 str = Utility.compactClassName(((ConstantUtf8)c).getBytes(), false); 150 break; 151 152 case Constants.CONSTANT_String: 153 i = ((ConstantString)c).getStringIndex(); 154 c = getConstant(i, Constants.CONSTANT_Utf8); 155 str = "\"" + escape(((ConstantUtf8)c).getBytes()) + "\""; 156 break; 157 158 case Constants.CONSTANT_Utf8: str = ((ConstantUtf8)c).getBytes(); break; 159 case Constants.CONSTANT_Double: str = "" + ((ConstantDouble)c).getBytes(); break; 160 case Constants.CONSTANT_Float: str = "" + ((ConstantFloat)c).getBytes(); break; 161 case Constants.CONSTANT_Long: str = "" + ((ConstantLong)c).getBytes(); break; 162 case Constants.CONSTANT_Integer: str = "" + ((ConstantInteger)c).getBytes(); break; 163 164 case Constants.CONSTANT_NameAndType: 165 str = (constantToString(((ConstantNameAndType)c).getNameIndex(), 166 Constants.CONSTANT_Utf8) + " " + 167 constantToString(((ConstantNameAndType)c).getSignatureIndex(), 168 Constants.CONSTANT_Utf8)); 169 break; 170 171 case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref: 172 case Constants.CONSTANT_Fieldref: 173 str = (constantToString(((ConstantCP)c).getClassIndex(), 174 Constants.CONSTANT_Class) + "." + 175 constantToString(((ConstantCP)c).getNameAndTypeIndex(), 176 Constants.CONSTANT_NameAndType)); 177 break; 178 179 default: // Never reached 180 throw new RuntimeException("Unknown constant type " + tag); 181 } 182 183 return str; 184 } 185 186 private static final String escape(String str) { 187 int len = str.length(); 188 StringBuffer buf = new StringBuffer(len + 5); 189 char[] ch = str.toCharArray(); 190 191 for(int i=0; i < len; i++) { 192 switch(ch[i]) { 193 case '\n' : buf.append("\\n"); break; 194 case '\r' : buf.append("\\r"); break; 195 case '\t' : buf.append("\\t"); break; 196 case '\b' : buf.append("\\b"); break; 197 case '"' : buf.append("\\\""); break; 198 default: buf.append(ch[i]); 199 } 200 } 201 202 return buf.toString(); 203 } 204 205 206 /** 207 * Retrieve constant at `index' from constant pool and resolve it to 208 * a string representation. 209 * 210 * @param index of constant in constant pool 211 * @param tag expected type 212 * @return String representation 213 */ 214 public String constantToString(int index, byte tag) 215 throws ClassFormatException 216 { 217 Constant c = getConstant(index, tag); 218 return constantToString(c); 219 } 220 221 /** 222 * Dump constant pool to file stream in binary format. 223 * 224 * @param file Output file stream 225 * @throws IOException 226 */ 227 public void dump(DataOutputStream file) throws IOException 228 { 229 file.writeShort(constant_pool_count); 230 231 for(int i=1; i < constant_pool_count; i++) 232 if(constant_pool[i] != null) 233 constant_pool[i].dump(file); 234 } 235 236 /** 237 * Get constant from constant pool. 238 * 239 * @param index Index in constant pool 240 * @return Constant value 241 * @see Constant 242 */ 243 public Constant getConstant(int index) { 244 if (index >= constant_pool.length || index < 0) 245 throw new ClassFormatException("Invalid constant pool reference: " + 246 index + ". Constant pool size is: " + 247 constant_pool.length); 248 return constant_pool[index]; 249 } 250 251 /** 252 * Get constant from constant pool and check whether it has the 253 * expected type. 254 * 255 * @param index Index in constant pool 256 * @param tag Tag of expected constant, i.e., its type 257 * @return Constant value 258 * @see Constant 259 * @throws ClassFormatException 260 */ 261 public Constant getConstant(int index, byte tag) 262 throws ClassFormatException 263 { 264 Constant c; 265 266 c = getConstant(index); 267 268 if(c == null) 269 throw new ClassFormatException("Constant pool at index " + index + " is null."); 270 271 if(c.getTag() == tag) 272 return c; 273 else 274 throw new ClassFormatException("Expected class `" + Constants.CONSTANT_NAMES[tag] + 275 "' at index " + index + " and got " + c); 276 } 277 278 /** 279 * @return Array of constants. 280 * @see Constant 281 */ 282 public Constant[] getConstantPool() { return constant_pool; } 283 /** 284 * Get string from constant pool and bypass the indirection of 285 * `ConstantClass' and `ConstantString' objects. I.e. these classes have 286 * an index field that points to another entry of the constant pool of 287 * type `ConstantUtf8' which contains the real data. 288 * 289 * @param index Index in constant pool 290 * @param tag Tag of expected constant, either ConstantClass or ConstantString 291 * @return Contents of string reference 292 * @see ConstantClass 293 * @see ConstantString 294 * @throws ClassFormatException 295 */ 296 public String getConstantString(int index, byte tag) 297 throws ClassFormatException 298 { 299 Constant c; 300 int i; 301 302 c = getConstant(index, tag); 303 304 /* This switch() is not that elegant, since the two classes have the 305 * same contents, they just differ in the name of the index 306 * field variable. 307 * But we want to stick to the JVM naming conventions closely though 308 * we could have solved these more elegantly by using the same 309 * variable name or by subclassing. 310 */ 311 switch(tag) { 312 case Constants.CONSTANT_Class: i = ((ConstantClass)c).getNameIndex(); break; 313 case Constants.CONSTANT_String: i = ((ConstantString)c).getStringIndex(); break; 314 default: 315 throw new RuntimeException("getConstantString called with illegal tag " + tag); 316 } 317 318 // Finally get the string from the constant pool 319 c = getConstant(i, Constants.CONSTANT_Utf8); 320 return ((ConstantUtf8)c).getBytes(); 321 } 322 /** 323 * @return Length of constant pool. 324 */ 325 public int getLength() 326 { 327 return constant_pool_count; 328 } 329 330 /** 331 * @param constant Constant to set 332 */ 333 public void setConstant(int index, Constant constant) { 334 constant_pool[index] = constant; 335 } 336 337 /** 338 * @param constant_pool 339 */ 340 public void setConstantPool(Constant[] constant_pool) { 341 this.constant_pool = constant_pool; 342 constant_pool_count = (constant_pool == null)? 0 : constant_pool.length; 343 } 344 /** 345 * @return String representation. 346 */ 347 public String toString() { 348 StringBuffer buf = new StringBuffer(); 349 350 for(int i=1; i < constant_pool_count; i++) 351 buf.append(i + ")" + constant_pool[i] + "\n"); 352 353 return buf.toString(); 354 } 355 356 /** 357 * @return deep copy of this constant pool 358 */ 359 public ConstantPool copy() { 360 ConstantPool c = null; 361 362 try { 363 c = (ConstantPool)clone(); 364 } catch(CloneNotSupportedException e) {} 365 366 c.constant_pool = new Constant[constant_pool_count]; 367 368 for(int i=1; i < constant_pool_count; i++) { 369 if(constant_pool[i] != null) 370 c.constant_pool[i] = constant_pool[i].copy(); 371 } 372 373 return c; 374 } 375 }