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