1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.bcel.classfile;
20
21 import java.io.DataInput;
22 import java.io.DataOutputStream;
23 import java.io.IOException;
24 import java.util.Arrays;
25 import java.util.Iterator;
26
27 import org.apache.bcel.Const;
28
29
30
31
32
33
34
35
36
37 public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
38
39 private static String escape(final String str) {
40 final int len = str.length();
41 final StringBuilder buf = new StringBuilder(len + 5);
42 final char[] ch = str.toCharArray();
43 for (int i = 0; i < len; i++) {
44 switch (ch[i]) {
45 case '\n':
46 buf.append("\\n");
47 break;
48 case '\r':
49 buf.append("\\r");
50 break;
51 case '\t':
52 buf.append("\\t");
53 break;
54 case '\b':
55 buf.append("\\b");
56 break;
57 case '"':
58 buf.append("\\\"");
59 break;
60 default:
61 buf.append(ch[i]);
62 }
63 }
64 return buf.toString();
65 }
66
67 private Constant[] constantPool;
68
69
70
71
72 public ConstantPool(final Constant[] constantPool) {
73 setConstantPool(constantPool);
74 }
75
76
77
78
79
80
81
82 public ConstantPool(final DataInput input) throws IOException {
83 byte tag;
84 final int constantPoolCount = input.readUnsignedShort();
85 constantPool = new Constant[constantPoolCount];
86
87
88
89
90 for (int i = 1; i < constantPoolCount; i++) {
91 constantPool[i] = Constant.readConstant(input);
92
93
94
95
96
97
98 tag = constantPool[i].getTag();
99 if (tag == Const.CONSTANT_Double || tag == Const.CONSTANT_Long) {
100 i++;
101 }
102 }
103 }
104
105
106
107
108
109
110
111 @Override
112 public void accept(final Visitor v) {
113 v.visitConstantPool(this);
114 }
115
116
117
118
119
120
121
122
123 public String constantToString(Constant c) throws IllegalArgumentException {
124 final String str;
125 final int i;
126 final byte tag = c.getTag();
127 switch (tag) {
128 case Const.CONSTANT_Class:
129 i = ((ConstantClass) c).getNameIndex();
130 c = getConstantUtf8(i);
131 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
132 break;
133 case Const.CONSTANT_String:
134 i = ((ConstantString) c).getStringIndex();
135 c = getConstantUtf8(i);
136 str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
137 break;
138 case Const.CONSTANT_Utf8:
139 str = ((ConstantUtf8) c).getBytes();
140 break;
141 case Const.CONSTANT_Double:
142 str = String.valueOf(((ConstantDouble) c).getBytes());
143 break;
144 case Const.CONSTANT_Float:
145 str = String.valueOf(((ConstantFloat) c).getBytes());
146 break;
147 case Const.CONSTANT_Long:
148 str = String.valueOf(((ConstantLong) c).getBytes());
149 break;
150 case Const.CONSTANT_Integer:
151 str = String.valueOf(((ConstantInteger) c).getBytes());
152 break;
153 case Const.CONSTANT_NameAndType:
154 str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " "
155 + constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8);
156 break;
157 case Const.CONSTANT_InterfaceMethodref:
158 case Const.CONSTANT_Methodref:
159 case Const.CONSTANT_Fieldref:
160 str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "."
161 + constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
162 break;
163 case Const.CONSTANT_MethodHandle:
164
165
166 final ConstantMethodHandle cmh = (ConstantMethodHandle) c;
167 str = Const.getMethodHandleName(cmh.getReferenceKind()) + " "
168 + constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag());
169 break;
170 case Const.CONSTANT_MethodType:
171 final ConstantMethodType cmt = (ConstantMethodType) c;
172 str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8);
173 break;
174 case Const.CONSTANT_InvokeDynamic:
175 final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c;
176 str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
177 break;
178 case Const.CONSTANT_Dynamic:
179 final ConstantDynamic cd = (ConstantDynamic) c;
180 str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
181 break;
182 case Const.CONSTANT_Module:
183 i = ((ConstantModule) c).getNameIndex();
184 c = getConstantUtf8(i);
185 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
186 break;
187 case Const.CONSTANT_Package:
188 i = ((ConstantPackage) c).getNameIndex();
189 c = getConstantUtf8(i);
190 str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
191 break;
192 default:
193 throw new IllegalArgumentException("Unknown constant type " + tag);
194 }
195 return str;
196 }
197
198
199
200
201
202
203
204
205 public String constantToString(final int index, final byte tag) {
206 return constantToString(getConstant(index, tag));
207 }
208
209
210
211
212 public ConstantPool copy() {
213 ConstantPool c = null;
214 try {
215 c = (ConstantPool) clone();
216 c.constantPool = new Constant[constantPool.length];
217 for (int i = 1; i < constantPool.length; i++) {
218 if (constantPool[i] != null) {
219 c.constantPool[i] = constantPool[i].copy();
220 }
221 }
222 } catch (final CloneNotSupportedException e) {
223
224 }
225 return c;
226 }
227
228
229
230
231
232
233
234 public void dump(final DataOutputStream file) throws IOException {
235
236
237
238
239 final int size = Math.min(constantPool.length, Const.MAX_CP_ENTRIES);
240
241 file.writeShort(size);
242 for (int i = 1; i < size; i++) {
243 if (constantPool[i] != null) {
244 constantPool[i].dump(file);
245 }
246 }
247 }
248
249
250
251
252
253
254
255
256
257 @SuppressWarnings("unchecked")
258 public <T extends Constant> T getConstant(final int index) throws ClassFormatException {
259 return (T) getConstant(index, Constant.class);
260 }
261
262
263
264
265
266
267
268
269
270
271 @SuppressWarnings("unchecked")
272 public <T extends Constant> T getConstant(final int index, final byte tag) throws ClassFormatException {
273 return (T) getConstant(index, tag, Constant.class);
274 }
275
276
277
278
279
280
281
282
283
284
285
286 public <T extends Constant> T getConstant(final int index, final byte tag, final Class<T> castTo) throws ClassFormatException {
287 final T c = getConstant(index);
288 if (c == null || c.getTag() != tag) {
289 throw new ClassFormatException("Expected class '" + Const.getConstantName(tag) + "' at index " + index + " and got " + c);
290 }
291 return c;
292 }
293
294
295
296
297
298
299
300
301
302
303
304
305 public <T extends Constant> T getConstant(final int index, final Class<T> castTo) throws ClassFormatException {
306 if (index >= constantPool.length || index < 1) {
307 throw new ClassFormatException("Invalid constant pool reference using index: " + index + ". Constant pool size is: " + constantPool.length);
308 }
309 if (constantPool[index] != null && !castTo.isAssignableFrom(constantPool[index].getClass())) {
310 throw new ClassFormatException("Invalid constant pool reference at index: " + index +
311 ". Expected " + castTo + " but was " + constantPool[index].getClass());
312 }
313 if (index > 1) {
314 final Constant prev = constantPool[index - 1];
315 if (prev != null && (prev.getTag() == Const.CONSTANT_Double || prev.getTag() == Const.CONSTANT_Long)) {
316 throw new ClassFormatException("Constant pool at index " + index + " is invalid. The index is unused due to the preceeding "
317 + Const.getConstantName(prev.getTag()) + ".");
318 }
319 }
320
321 final T c = castTo.cast(constantPool[index]);
322 if (c == null) {
323 throw new ClassFormatException("Constant pool at index " + index + " is null.");
324 }
325 return c;
326 }
327
328
329
330
331
332
333
334
335
336 public ConstantInteger getConstantInteger(final int index) {
337 return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class);
338 }
339
340
341
342
343
344 public Constant[] getConstantPool() {
345 return constantPool;
346 }
347
348
349
350
351
352
353
354
355
356
357
358
359 public String getConstantString(final int index, final byte tag) throws IllegalArgumentException {
360 final int i;
361
362
363
364
365
366 switch (tag) {
367 case Const.CONSTANT_Class:
368 i = getConstant(index, ConstantClass.class).getNameIndex();
369 break;
370 case Const.CONSTANT_String:
371 i = getConstant(index, ConstantString.class).getStringIndex();
372 break;
373 case Const.CONSTANT_Module:
374 i = getConstant(index, ConstantModule.class).getNameIndex();
375 break;
376 case Const.CONSTANT_Package:
377 i = getConstant(index, ConstantPackage.class).getNameIndex();
378 break;
379 case Const.CONSTANT_Utf8:
380 return getConstantUtf8(index).getBytes();
381 default:
382 throw new IllegalArgumentException("getConstantString called with illegal tag " + tag);
383 }
384
385 return getConstantUtf8(i).getBytes();
386 }
387
388
389
390
391
392
393
394
395
396 public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException {
397 return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class);
398 }
399
400
401
402
403 public int getLength() {
404 return constantPool.length;
405 }
406
407 @Override
408 public Iterator<Constant> iterator() {
409 return Arrays.stream(constantPool).iterator();
410 }
411
412
413
414
415 public void setConstant(final int index, final Constant constant) {
416 constantPool[index] = constant;
417 }
418
419
420
421
422 public void setConstantPool(final Constant[] constantPool) {
423 this.constantPool = constantPool != null ? constantPool : Constant.EMPTY_ARRAY;
424 }
425
426
427
428
429 @Override
430 public String toString() {
431 final StringBuilder buf = new StringBuilder();
432 for (int i = 1; i < constantPool.length; i++) {
433 buf.append(i).append(")").append(constantPool[i]).append("\n");
434 }
435 return buf.toString();
436 }
437 }