1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.DataOutputStream;
21 import java.io.IOException;
22 import java.io.Serializable;
23 import org.apache.bcel.Constants;
24
25 /***
26 * This class represents the constant pool, i.e., a table of constants, of
27 * a parsed classfile. It may contain null references, due to the JVM
28 * specification that skips an entry after an 8-byte constant (double,
29 * long) entry. Those interested in generating constant pools
30 * programatically should see <a href="../generic/ConstantPoolGen.html">
31 * ConstantPoolGen</a>.
32
33 * @version $Id: ConstantPool.java 386056 2006-03-15 11:31:56Z tcurdt $
34 * @see Constant
35 * @see org.apache.bcel.generic.ConstantPoolGen
36 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
37 */
38 public class ConstantPool implements Cloneable, Node, Serializable {
39
40 private int constant_pool_count;
41 private Constant[] constant_pool;
42
43
44 /***
45 * @param constant_pool Array of constants
46 */
47 public ConstantPool(Constant[] constant_pool) {
48 setConstantPool(constant_pool);
49 }
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 byte tag;
61 constant_pool_count = file.readUnsignedShort();
62 constant_pool = new Constant[constant_pool_count];
63
64
65
66 for (int i = 1; i < constant_pool_count; i++) {
67 constant_pool[i] = Constant.readConstant(file);
68
69
70
71
72
73
74
75 tag = constant_pool[i].getTag();
76 if ((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long)) {
77 i++;
78 }
79 }
80 }
81
82
83 /***
84 * Called by objects that are traversing the nodes of the tree implicitely
85 * defined by the contents of a Java class. I.e., the hierarchy of methods,
86 * fields, attributes, etc. spawns a tree of objects.
87 *
88 * @param v Visitor object
89 */
90 public void accept( Visitor v ) {
91 v.visitConstantPool(this);
92 }
93
94
95 /***
96 * Resolve constant to a string representation.
97 *
98 * @param c Constant to be printed
99 * @return String representation
100 */
101 public String constantToString( Constant c ) throws ClassFormatException {
102 String str;
103 int i;
104 byte tag = c.getTag();
105 switch (tag) {
106 case Constants.CONSTANT_Class:
107 i = ((ConstantClass) c).getNameIndex();
108 c = getConstant(i, Constants.CONSTANT_Utf8);
109 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
110 break;
111 case Constants.CONSTANT_String:
112 i = ((ConstantString) c).getStringIndex();
113 c = getConstant(i, Constants.CONSTANT_Utf8);
114 str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
115 break;
116 case Constants.CONSTANT_Utf8:
117 str = ((ConstantUtf8) c).getBytes();
118 break;
119 case Constants.CONSTANT_Double:
120 str = "" + ((ConstantDouble) c).getBytes();
121 break;
122 case Constants.CONSTANT_Float:
123 str = "" + ((ConstantFloat) c).getBytes();
124 break;
125 case Constants.CONSTANT_Long:
126 str = "" + ((ConstantLong) c).getBytes();
127 break;
128 case Constants.CONSTANT_Integer:
129 str = "" + ((ConstantInteger) c).getBytes();
130 break;
131 case Constants.CONSTANT_NameAndType:
132 str = (constantToString(((ConstantNameAndType) c).getNameIndex(),
133 Constants.CONSTANT_Utf8)
134 + " " + constantToString(((ConstantNameAndType) c).getSignatureIndex(),
135 Constants.CONSTANT_Utf8));
136 break;
137 case Constants.CONSTANT_InterfaceMethodref:
138 case Constants.CONSTANT_Methodref:
139 case Constants.CONSTANT_Fieldref:
140 str = (constantToString(((ConstantCP) c).getClassIndex(), Constants.CONSTANT_Class)
141 + "." + constantToString(((ConstantCP) c).getNameAndTypeIndex(),
142 Constants.CONSTANT_NameAndType));
143 break;
144 default:
145 throw new RuntimeException("Unknown constant type " + tag);
146 }
147 return str;
148 }
149
150
151 private static final String escape( String str ) {
152 int len = str.length();
153 StringBuffer buf = new StringBuffer(len + 5);
154 char[] ch = str.toCharArray();
155 for (int i = 0; i < len; i++) {
156 switch (ch[i]) {
157 case '\n':
158 buf.append("//n");
159 break;
160 case '\r':
161 buf.append("//r");
162 break;
163 case '\t':
164 buf.append("//t");
165 break;
166 case '\b':
167 buf.append("//b");
168 break;
169 case '"':
170 buf.append("//\"");
171 break;
172 default:
173 buf.append(ch[i]);
174 }
175 }
176 return buf.toString();
177 }
178
179
180 /***
181 * Retrieve constant at `index' from constant pool and resolve it to
182 * a string representation.
183 *
184 * @param index of constant in constant pool
185 * @param tag expected type
186 * @return String representation
187 */
188 public String constantToString( int index, byte tag ) throws ClassFormatException {
189 Constant c = getConstant(index, tag);
190 return constantToString(c);
191 }
192
193
194 /***
195 * Dump constant pool to file stream in binary format.
196 *
197 * @param file Output file stream
198 * @throws IOException
199 */
200 public void dump( DataOutputStream file ) throws IOException {
201 file.writeShort(constant_pool_count);
202 for (int i = 1; i < constant_pool_count; i++) {
203 if (constant_pool[i] != null) {
204 constant_pool[i].dump(file);
205 }
206 }
207 }
208
209
210 /***
211 * Get constant from constant pool.
212 *
213 * @param index Index in constant pool
214 * @return Constant value
215 * @see Constant
216 */
217 public Constant getConstant( int index ) {
218 if (index >= constant_pool.length || index < 0) {
219 throw new ClassFormatException("Invalid constant pool reference: " + index
220 + ". Constant pool size is: " + constant_pool.length);
221 }
222 return constant_pool[index];
223 }
224
225
226 /***
227 * Get constant from constant pool and check whether it has the
228 * expected type.
229 *
230 * @param index Index in constant pool
231 * @param tag Tag of expected constant, i.e., its type
232 * @return Constant value
233 * @see Constant
234 * @throws ClassFormatException
235 */
236 public Constant getConstant( int index, byte tag ) throws ClassFormatException {
237 Constant c;
238 c = getConstant(index);
239 if (c == null) {
240 throw new ClassFormatException("Constant pool at index " + index + " is null.");
241 }
242 if (c.getTag() != tag) {
243 throw new ClassFormatException("Expected class `" + Constants.CONSTANT_NAMES[tag]
244 + "' at index " + index + " and got " + c);
245 }
246 return c;
247 }
248
249
250 /***
251 * @return Array of constants.
252 * @see Constant
253 */
254 public Constant[] getConstantPool() {
255 return constant_pool;
256 }
257
258
259 /***
260 * Get string from constant pool and bypass the indirection of
261 * `ConstantClass' and `ConstantString' objects. I.e. these classes have
262 * an index field that points to another entry of the constant pool of
263 * type `ConstantUtf8' which contains the real data.
264 *
265 * @param index Index in constant pool
266 * @param tag Tag of expected constant, either ConstantClass or ConstantString
267 * @return Contents of string reference
268 * @see ConstantClass
269 * @see ConstantString
270 * @throws ClassFormatException
271 */
272 public String getConstantString( int index, byte tag ) throws ClassFormatException {
273 Constant c;
274 int i;
275 c = getConstant(index, tag);
276
277
278
279
280
281
282
283 switch (tag) {
284 case Constants.CONSTANT_Class:
285 i = ((ConstantClass) c).getNameIndex();
286 break;
287 case Constants.CONSTANT_String:
288 i = ((ConstantString) c).getStringIndex();
289 break;
290 default:
291 throw new RuntimeException("getConstantString called with illegal tag " + tag);
292 }
293
294 c = getConstant(i, Constants.CONSTANT_Utf8);
295 return ((ConstantUtf8) c).getBytes();
296 }
297
298
299 /***
300 * @return Length of constant pool.
301 */
302 public int getLength() {
303 return constant_pool_count;
304 }
305
306
307 /***
308 * @param constant Constant to set
309 */
310 public void setConstant( int index, Constant constant ) {
311 constant_pool[index] = constant;
312 }
313
314
315 /***
316 * @param constant_pool
317 */
318 public void setConstantPool( Constant[] constant_pool ) {
319 this.constant_pool = constant_pool;
320 constant_pool_count = (constant_pool == null) ? 0 : constant_pool.length;
321 }
322
323
324 /***
325 * @return String representation.
326 */
327 public String toString() {
328 StringBuffer buf = new StringBuffer();
329 for (int i = 1; i < constant_pool_count; i++) {
330 buf.append(i).append(")").append(constant_pool[i]).append("\n");
331 }
332 return buf.toString();
333 }
334
335
336 /***
337 * @return deep copy of this constant pool
338 */
339 public ConstantPool copy() {
340 ConstantPool c = null;
341 try {
342 c = (ConstantPool) clone();
343 c.constant_pool = new Constant[constant_pool_count];
344 for (int i = 1; i < constant_pool_count; i++) {
345 if (constant_pool[i] != null) {
346 c.constant_pool[i] = constant_pool[i].copy();
347 }
348 }
349 } catch (CloneNotSupportedException e) {
350 }
351 return c;
352 }
353 }