18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.bcel.internal.classfile; 23 24 import java.io.DataInput; 25 import java.io.DataOutputStream; 26 import java.io.IOException; 27 28 import com.sun.org.apache.bcel.internal.Const; 29 30 /** 31 * This class represents the constant pool, i.e., a table of constants, of 32 * a parsed classfile. It may contain null references, due to the JVM 33 * specification that skips an entry after an 8-byte constant (double, 34 * long) entry. Those interested in generating constant pools 35 * programatically should see <a href="../generic/ConstantPoolGen.html"> 36 * ConstantPoolGen</a>. 37 38 * @version $Id$ 39 * @see Constant 40 * @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen 41 */ 42 public class ConstantPool implements Cloneable, Node { 43 44 private Constant[] constant_pool; 45 46 47 /** 48 * @param constant_pool Array of constants 49 */ 50 public ConstantPool(final Constant[] constant_pool) { 51 this.constant_pool = constant_pool; 52 } 53 54 55 /** 56 * Read constants from given input stream. 57 * 58 * @param input Input stream 59 * @throws IOException 60 * @throws ClassFormatException 61 */ 62 public ConstantPool(final DataInput input) throws IOException, ClassFormatException { 63 byte tag; 64 final int constant_pool_count = input.readUnsignedShort(); 65 constant_pool = new Constant[constant_pool_count]; 66 /* constant_pool[0] is unused by the compiler and may be used freely 67 * by the implementation. 68 */ 69 for (int i = 1; i < constant_pool_count; i++) { 70 constant_pool[i] = Constant.readConstant(input); 71 /* Quote from the JVM specification: 72 * "All eight byte constants take up two spots in the constant pool. 73 * If this is the n'th byte in the constant pool, then the next item 74 * will be numbered n+2" 75 * 76 * Thus we have to increment the index counter. 77 */ 78 tag = constant_pool[i].getTag(); 79 if ((tag == Const.CONSTANT_Double) || (tag == Const.CONSTANT_Long)) { 80 i++; 81 } 82 } 83 } 84 85 86 /** 87 * Called by objects that are traversing the nodes of the tree implicitely 88 * defined by the contents of a Java class. I.e., the hierarchy of methods, 89 * fields, attributes, etc. spawns a tree of objects. 90 * 91 * @param v Visitor object 92 */ 93 @Override 94 public void accept( final Visitor v ) { 95 v.visitConstantPool(this); 96 } 97 98 99 /** 100 * Resolve constant to a string representation. 101 * 102 * @param c Constant to be printed 103 * @return String representation 104 */ 105 public String constantToString( Constant c ) throws ClassFormatException { 106 String str; 107 int i; 108 final byte tag = c.getTag(); 109 switch (tag) { 110 case Const.CONSTANT_Class: 111 i = ((ConstantClass) c).getNameIndex(); 112 c = getConstant(i, Const.CONSTANT_Utf8); 113 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); 114 break; 115 case Const.CONSTANT_String: 116 i = ((ConstantString) c).getStringIndex(); 117 c = getConstant(i, Const.CONSTANT_Utf8); 118 str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\""; 119 break; 120 case Const.CONSTANT_Utf8: 146 Const.CONSTANT_NameAndType); 147 break; 148 case Const.CONSTANT_MethodHandle: 149 // Note that the ReferenceIndex may point to a Fieldref, Methodref or 150 // InterfaceMethodref - so we need to peek ahead to get the actual type. 151 final ConstantMethodHandle cmh = (ConstantMethodHandle) c; 152 str = Const.getMethodHandleName(cmh.getReferenceKind()) 153 + " " + constantToString(cmh.getReferenceIndex(), 154 getConstant(cmh.getReferenceIndex()).getTag()); 155 break; 156 case Const.CONSTANT_MethodType: 157 final ConstantMethodType cmt = (ConstantMethodType) c; 158 str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8); 159 break; 160 case Const.CONSTANT_InvokeDynamic: 161 final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c; 162 str = cid.getBootstrapMethodAttrIndex() 163 + ":" + constantToString(cid.getNameAndTypeIndex(), 164 Const.CONSTANT_NameAndType); 165 break; 166 default: // Never reached 167 throw new RuntimeException("Unknown constant type " + tag); 168 } 169 return str; 170 } 171 172 173 private static String escape( final String str ) { 174 final int len = str.length(); 175 final StringBuilder buf = new StringBuilder(len + 5); 176 final char[] ch = str.toCharArray(); 177 for (int i = 0; i < len; i++) { 178 switch (ch[i]) { 179 case '\n': 180 buf.append("\\n"); 181 break; 182 case '\r': 183 buf.append("\\r"); 184 break; 185 case '\t': 186 buf.append("\\t"); 187 break; 188 case '\b': 189 buf.append("\\b"); 190 break; 191 case '"': 192 buf.append("\\\""); 193 break; 194 default: 195 buf.append(ch[i]); 196 } 197 } 198 return buf.toString(); 199 } 200 201 202 /** 203 * Retrieve constant at `index' from constant pool and resolve it to 204 * a string representation. 205 * 206 * @param index of constant in constant pool 207 * @param tag expected type 208 * @return String representation 209 */ 210 public String constantToString( final int index, final byte tag ) throws ClassFormatException { 211 final Constant c = getConstant(index, tag); 212 return constantToString(c); 213 } 214 215 216 /** 217 * Dump constant pool to file stream in binary format. 218 * 219 * @param file Output file stream 220 * @throws IOException 221 */ 222 public void dump( final DataOutputStream file ) throws IOException { 223 file.writeShort(constant_pool.length); 224 for (int i = 1; i < constant_pool.length; i++) { 225 if (constant_pool[i] != null) { 226 constant_pool[i].dump(file); 227 } 228 } 229 } 230 231 232 /** 233 * Get constant from constant pool. 234 * 235 * @param index Index in constant pool 236 * @return Constant value 237 * @see Constant 238 */ 239 public Constant getConstant( final int index ) { 240 if (index >= constant_pool.length || index < 0) { 241 throw new ClassFormatException("Invalid constant pool reference: " + index 242 + ". Constant pool size is: " + constant_pool.length); 243 } 244 return constant_pool[index]; 245 } 246 247 248 /** 249 * Get constant from constant pool and check whether it has the 250 * expected type. 251 * 252 * @param index Index in constant pool 253 * @param tag Tag of expected constant, i.e., its type 254 * @return Constant value 255 * @see Constant 256 * @throws ClassFormatException 257 */ 258 public Constant getConstant( final int index, final byte tag ) throws ClassFormatException { 259 Constant c; 260 c = getConstant(index); 261 if (c == null) { 262 throw new ClassFormatException("Constant pool at index " + index + " is null."); 263 } 264 if (c.getTag() != tag) { 265 throw new ClassFormatException("Expected class `" + Const.getConstantName(tag) 266 + "' at index " + index + " and got " + c); 267 } 268 return c; 269 } 270 271 272 /** 273 * @return Array of constants. 274 * @see Constant 275 */ 276 public Constant[] getConstantPool() { 277 return constant_pool; 278 } 279 280 281 /** 282 * Get string from constant pool and bypass the indirection of 283 * `ConstantClass' and `ConstantString' objects. I.e. these classes have 284 * an index field that points to another entry of the constant pool of 285 * type `ConstantUtf8' which contains the real data. 286 * 287 * @param index Index in constant pool 288 * @param tag Tag of expected constant, either ConstantClass or ConstantString 289 * @return Contents of string reference 290 * @see ConstantClass 291 * @see ConstantString 292 * @throws ClassFormatException 293 */ 294 public String getConstantString( final int index, final byte tag ) throws ClassFormatException { 295 Constant c; 296 int i; 297 c = getConstant(index, tag); 298 /* This switch() is not that elegant, since the two classes have the 299 * same contents, they just differ in the name of the index 300 * field variable. 301 * But we want to stick to the JVM naming conventions closely though 302 * we could have solved these more elegantly by using the same 303 * variable name or by subclassing. 304 */ 305 switch (tag) { 306 case Const.CONSTANT_Class: 307 i = ((ConstantClass) c).getNameIndex(); 308 break; 309 case Const.CONSTANT_String: 310 i = ((ConstantString) c).getStringIndex(); 311 break; 312 default: 313 throw new RuntimeException("getConstantString called with illegal tag " + tag); 314 } 315 // Finally get the string from the constant pool 316 c = getConstant(i, Const.CONSTANT_Utf8); 317 return ((ConstantUtf8) c).getBytes(); 318 } 319 320 321 /** 322 * @return Length of constant pool. 323 */ 324 public int getLength() { 325 return constant_pool == null ? 0 : constant_pool.length; 326 } 327 328 329 /** 330 * @param constant Constant to set | 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.bcel.internal.classfile; 23 24 import java.io.DataInput; 25 import java.io.DataOutputStream; 26 import java.io.IOException; 27 28 import com.sun.org.apache.bcel.internal.Const; 29 30 /** 31 * This class represents the constant pool, i.e., a table of constants, of 32 * a parsed classfile. It may contain null references, due to the JVM 33 * specification that skips an entry after an 8-byte constant (double, 34 * long) entry. Those interested in generating constant pools 35 * programatically should see <a href="../generic/ConstantPoolGen.html"> 36 * ConstantPoolGen</a>. 37 38 * @see Constant 39 * @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen 40 */ 41 public class ConstantPool implements Cloneable, Node { 42 43 private Constant[] constant_pool; 44 45 /** 46 * @param constant_pool Array of constants 47 */ 48 public ConstantPool(final Constant[] constant_pool) { 49 this.constant_pool = constant_pool; 50 } 51 52 /** 53 * Reads constants from given input stream. 54 * 55 * @param input Input stream 56 * @throws IOException 57 * @throws ClassFormatException 58 */ 59 public ConstantPool(final DataInput input) throws IOException, ClassFormatException { 60 byte tag; 61 final int constant_pool_count = input.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(input); 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 == Const.CONSTANT_Double) || (tag == Const.CONSTANT_Long)) { 77 i++; 78 } 79 } 80 } 81 82 /** 83 * Called by objects that are traversing the nodes of the tree implicitely 84 * defined by the contents of a Java class. I.e., the hierarchy of methods, 85 * fields, attributes, etc. spawns a tree of objects. 86 * 87 * @param v Visitor object 88 */ 89 @Override 90 public void accept( final Visitor v ) { 91 v.visitConstantPool(this); 92 } 93 94 /** 95 * Resolves constant to a string representation. 96 * 97 * @param c Constant to be printed 98 * @return String representation 99 */ 100 public String constantToString( Constant c ) throws ClassFormatException { 101 String str; 102 int i; 103 final byte tag = c.getTag(); 104 switch (tag) { 105 case Const.CONSTANT_Class: 106 i = ((ConstantClass) c).getNameIndex(); 107 c = getConstant(i, Const.CONSTANT_Utf8); 108 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); 109 break; 110 case Const.CONSTANT_String: 111 i = ((ConstantString) c).getStringIndex(); 112 c = getConstant(i, Const.CONSTANT_Utf8); 113 str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\""; 114 break; 115 case Const.CONSTANT_Utf8: 141 Const.CONSTANT_NameAndType); 142 break; 143 case Const.CONSTANT_MethodHandle: 144 // Note that the ReferenceIndex may point to a Fieldref, Methodref or 145 // InterfaceMethodref - so we need to peek ahead to get the actual type. 146 final ConstantMethodHandle cmh = (ConstantMethodHandle) c; 147 str = Const.getMethodHandleName(cmh.getReferenceKind()) 148 + " " + constantToString(cmh.getReferenceIndex(), 149 getConstant(cmh.getReferenceIndex()).getTag()); 150 break; 151 case Const.CONSTANT_MethodType: 152 final ConstantMethodType cmt = (ConstantMethodType) c; 153 str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8); 154 break; 155 case Const.CONSTANT_InvokeDynamic: 156 final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c; 157 str = cid.getBootstrapMethodAttrIndex() 158 + ":" + constantToString(cid.getNameAndTypeIndex(), 159 Const.CONSTANT_NameAndType); 160 break; 161 case Const.CONSTANT_Module: 162 i = ((ConstantModule) c).getNameIndex(); 163 c = getConstant(i, Const.CONSTANT_Utf8); 164 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); 165 break; 166 case Const.CONSTANT_Package: 167 i = ((ConstantPackage) c).getNameIndex(); 168 c = getConstant(i, Const.CONSTANT_Utf8); 169 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); 170 break; 171 default: // Never reached 172 throw new RuntimeException("Unknown constant type " + tag); 173 } 174 return str; 175 } 176 177 private static String escape( final String str ) { 178 final int len = str.length(); 179 final StringBuilder buf = new StringBuilder(len + 5); 180 final char[] ch = str.toCharArray(); 181 for (int i = 0; i < len; i++) { 182 switch (ch[i]) { 183 case '\n': 184 buf.append("\\n"); 185 break; 186 case '\r': 187 buf.append("\\r"); 188 break; 189 case '\t': 190 buf.append("\\t"); 191 break; 192 case '\b': 193 buf.append("\\b"); 194 break; 195 case '"': 196 buf.append("\\\""); 197 break; 198 default: 199 buf.append(ch[i]); 200 } 201 } 202 return buf.toString(); 203 } 204 205 /** 206 * Retrieves constant at `index' from constant pool and resolve it to 207 * a string representation. 208 * 209 * @param index of constant in constant pool 210 * @param tag expected type 211 * @return String representation 212 */ 213 public String constantToString( final int index, final byte tag ) throws ClassFormatException { 214 final Constant c = getConstant(index, tag); 215 return constantToString(c); 216 } 217 218 /** 219 * Dump constant pool to file stream in binary format. 220 * 221 * @param file Output file stream 222 * @throws IOException 223 */ 224 public void dump( final DataOutputStream file ) throws IOException { 225 file.writeShort(constant_pool.length); 226 for (int i = 1; i < constant_pool.length; i++) { 227 if (constant_pool[i] != null) { 228 constant_pool[i].dump(file); 229 } 230 } 231 } 232 233 /** 234 * Gets constant from constant pool. 235 * 236 * @param index Index in constant pool 237 * @return Constant value 238 * @see Constant 239 */ 240 public Constant getConstant( final int index ) { 241 if (index >= constant_pool.length || index < 0) { 242 throw new ClassFormatException("Invalid constant pool reference: " + index 243 + ". Constant pool size is: " + constant_pool.length); 244 } 245 return constant_pool[index]; 246 } 247 248 /** 249 * Gets constant from constant pool and check whether it has the 250 * expected type. 251 * 252 * @param index Index in constant pool 253 * @param tag Tag of expected constant, i.e., its type 254 * @return Constant value 255 * @see Constant 256 * @throws ClassFormatException 257 */ 258 public Constant getConstant( final int index, final byte tag ) throws ClassFormatException { 259 Constant c; 260 c = getConstant(index); 261 if (c == null) { 262 throw new ClassFormatException("Constant pool at index " + index + " is null."); 263 } 264 if (c.getTag() != tag) { 265 throw new ClassFormatException("Expected class `" + Const.getConstantName(tag) 266 + "' at index " + index + " and got " + c); 267 } 268 return c; 269 } 270 271 /** 272 * @return Array of constants. 273 * @see Constant 274 */ 275 public Constant[] getConstantPool() { 276 return constant_pool; 277 } 278 279 /** 280 * Gets string from constant pool and bypass the indirection of 281 * `ConstantClass' and `ConstantString' objects. I.e. these classes have 282 * an index field that points to another entry of the constant pool of 283 * type `ConstantUtf8' which contains the real data. 284 * 285 * @param index Index in constant pool 286 * @param tag Tag of expected constant, either ConstantClass or ConstantString 287 * @return Contents of string reference 288 * @see ConstantClass 289 * @see ConstantString 290 * @throws ClassFormatException 291 */ 292 public String getConstantString( final int index, final byte tag ) throws ClassFormatException { 293 Constant c; 294 int i; 295 c = getConstant(index, tag); 296 /* This switch() is not that elegant, since the four classes have the 297 * same contents, they just differ in the name of the index 298 * field variable. 299 * But we want to stick to the JVM naming conventions closely though 300 * we could have solved these more elegantly by using the same 301 * variable name or by subclassing. 302 */ 303 switch (tag) { 304 case Const.CONSTANT_Class: 305 i = ((ConstantClass) c).getNameIndex(); 306 break; 307 case Const.CONSTANT_String: 308 i = ((ConstantString) c).getStringIndex(); 309 break; 310 case Const.CONSTANT_Module: 311 i = ((ConstantModule) c).getNameIndex(); 312 break; 313 case Const.CONSTANT_Package: 314 i = ((ConstantPackage) c).getNameIndex(); 315 break; 316 default: 317 throw new RuntimeException("getConstantString called with illegal tag " + tag); 318 } 319 // Finally get the string from the constant pool 320 c = getConstant(i, Const.CONSTANT_Utf8); 321 return ((ConstantUtf8) c).getBytes(); 322 } 323 324 325 /** 326 * @return Length of constant pool. 327 */ 328 public int getLength() { 329 return constant_pool == null ? 0 : constant_pool.length; 330 } 331 332 333 /** 334 * @param constant Constant to set |