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