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.DataInputStream;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.util.HashMap;
26 import java.util.Map;
27
28 import org.apache.bcel.Const;
29 import org.apache.bcel.util.Args;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public abstract class Attribute implements Cloneable, Node {
57
58 private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug");
59
60 private static final Map<String, Object> READERS = new HashMap<>();
61
62
63
64
65
66
67 public static final Attribute[] EMPTY_ARRAY = {};
68
69
70
71
72
73
74
75
76
77 @java.lang.Deprecated
78 public static void addAttributeReader(final String name, final AttributeReader attributeReader) {
79 READERS.put(name, attributeReader);
80 }
81
82
83
84
85
86
87
88
89 public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) {
90 READERS.put(name, unknownAttributeReader);
91 }
92
93 protected static void println(final String msg) {
94 if (debug) {
95 System.err.println(msg);
96 }
97 }
98
99
100
101
102
103
104
105
106
107
108
109
110
111 public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
112 byte tag = Const.ATTR_UNKNOWN;
113
114 final int nameIndex = dataInput.readUnsignedShort();
115 final String name = constantPool.getConstantUtf8(nameIndex).getBytes();
116
117
118 final int length = dataInput.readInt();
119
120
121 for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++) {
122 if (name.equals(Const.getAttributeName(i))) {
123 tag = i;
124 break;
125 }
126 }
127
128
129 switch (tag) {
130 case Const.ATTR_UNKNOWN:
131 final Object r = READERS.get(name);
132 if (r instanceof UnknownAttributeReader) {
133 return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool);
134 }
135 return new Unknown(nameIndex, length, dataInput, constantPool);
136 case Const.ATTR_CONSTANT_VALUE:
137 return new ConstantValue(nameIndex, length, dataInput, constantPool);
138 case Const.ATTR_SOURCE_FILE:
139 return new SourceFile(nameIndex, length, dataInput, constantPool);
140 case Const.ATTR_CODE:
141 return new Code(nameIndex, length, dataInput, constantPool);
142 case Const.ATTR_EXCEPTIONS:
143 return new ExceptionTable(nameIndex, length, dataInput, constantPool);
144 case Const.ATTR_LINE_NUMBER_TABLE:
145 return new LineNumberTable(nameIndex, length, dataInput, constantPool);
146 case Const.ATTR_LOCAL_VARIABLE_TABLE:
147 return new LocalVariableTable(nameIndex, length, dataInput, constantPool);
148 case Const.ATTR_INNER_CLASSES:
149 return new InnerClasses(nameIndex, length, dataInput, constantPool);
150 case Const.ATTR_SYNTHETIC:
151 return new Synthetic(nameIndex, length, dataInput, constantPool);
152 case Const.ATTR_DEPRECATED:
153 return new Deprecated(nameIndex, length, dataInput, constantPool);
154 case Const.ATTR_PMG:
155 return new PMGClass(nameIndex, length, dataInput, constantPool);
156 case Const.ATTR_SIGNATURE:
157 return new Signature(nameIndex, length, dataInput, constantPool);
158 case Const.ATTR_STACK_MAP:
159
160
161 println("Warning: Obsolete StackMap attribute ignored.");
162 return new Unknown(nameIndex, length, dataInput, constantPool);
163 case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
164 return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool);
165 case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
166 return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool);
167 case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
168 return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
169 case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
170 return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
171 case Const.ATTR_ANNOTATION_DEFAULT:
172 return new AnnotationDefault(nameIndex, length, dataInput, constantPool);
173 case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
174 return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool);
175 case Const.ATTR_ENCLOSING_METHOD:
176 return new EnclosingMethod(nameIndex, length, dataInput, constantPool);
177 case Const.ATTR_STACK_MAP_TABLE:
178
179
180 return new StackMap(nameIndex, length, dataInput, constantPool);
181 case Const.ATTR_BOOTSTRAP_METHODS:
182 return new BootstrapMethods(nameIndex, length, dataInput, constantPool);
183 case Const.ATTR_METHOD_PARAMETERS:
184 return new MethodParameters(nameIndex, length, dataInput, constantPool);
185 case Const.ATTR_MODULE:
186 return new Module(nameIndex, length, dataInput, constantPool);
187 case Const.ATTR_MODULE_PACKAGES:
188 return new ModulePackages(nameIndex, length, dataInput, constantPool);
189 case Const.ATTR_MODULE_MAIN_CLASS:
190 return new ModuleMainClass(nameIndex, length, dataInput, constantPool);
191 case Const.ATTR_NEST_HOST:
192 return new NestHost(nameIndex, length, dataInput, constantPool);
193 case Const.ATTR_NEST_MEMBERS:
194 return new NestMembers(nameIndex, length, dataInput, constantPool);
195 case Const.ATTR_RECORD:
196 return new Record(nameIndex, length, dataInput, constantPool);
197 default:
198
199 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
200 }
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214 public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException {
215 return readAttribute((DataInput) dataInputStream, constantPool);
216 }
217
218
219
220
221
222
223 public static void removeAttributeReader(final String name) {
224 READERS.remove(name);
225 }
226
227
228
229
230 @java.lang.Deprecated
231 protected int name_index;
232
233
234
235
236 @java.lang.Deprecated
237 protected int length;
238
239
240
241
242 @java.lang.Deprecated
243 protected byte tag;
244
245
246
247
248 @java.lang.Deprecated
249 protected ConstantPool constant_pool;
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267 protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) {
268 this.tag = tag;
269 this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index");
270 this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length");
271 this.constant_pool = constantPool;
272 }
273
274
275
276
277
278
279
280 @Override
281 public abstract void accept(Visitor v);
282
283
284
285
286
287
288 @Override
289 public Object clone() {
290 Attribute attr = null;
291 try {
292 attr = (Attribute) super.clone();
293 } catch (final CloneNotSupportedException e) {
294 throw new UnsupportedOperationException("Clone Not Supported", e);
295 }
296 return attr;
297 }
298
299
300
301
302
303 public abstract Attribute copy(ConstantPool constantPool);
304
305
306
307
308
309
310
311 public void dump(final DataOutputStream file) throws IOException {
312 file.writeShort(name_index);
313 file.writeInt(length);
314 }
315
316
317
318
319
320 public final ConstantPool getConstantPool() {
321 return constant_pool;
322 }
323
324
325
326
327 public final int getLength() {
328 return length;
329 }
330
331
332
333
334
335 public String getName() {
336 return constant_pool.getConstantUtf8(name_index).getBytes();
337 }
338
339
340
341
342 public final int getNameIndex() {
343 return name_index;
344 }
345
346
347
348
349 public final byte getTag() {
350 return tag;
351 }
352
353
354
355
356
357 public final void setConstantPool(final ConstantPool constantPool) {
358 this.constant_pool = constantPool;
359 }
360
361
362
363
364 public final void setLength(final int length) {
365 this.length = length;
366 }
367
368
369
370
371 public final void setNameIndex(final int nameIndex) {
372 this.name_index = nameIndex;
373 }
374
375
376
377
378 @Override
379 public String toString() {
380 return Const.getAttributeName(tag);
381 }
382 }