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.DataInputStream;
21 import java.io.DataOutputStream;
22 import java.io.IOException;
23 import java.util.HashMap;
24 import java.util.Map;
25
26 import org.apache.bcel.Const;
27 import org.apache.bcel.util.Args;
28
29
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 public abstract class Attribute implements Cloneable, Node {
55
56 private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug");
57
58 private static final Map<String, Object> READERS = new HashMap<>();
59
60
61
62
63
64
65 public static final Attribute[] EMPTY_ARRAY = {};
66
67
68
69
70
71
72
73
74
75 @java.lang.Deprecated
76 public static void addAttributeReader(final String name, final AttributeReader attributeReader) {
77 READERS.put(name, attributeReader);
78 }
79
80
81
82
83
84
85
86
87 public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) {
88 READERS.put(name, unknownAttributeReader);
89 }
90
91 protected static void println(final String msg) {
92 if (debug) {
93 System.err.println(msg);
94 }
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
111 byte tag = Const.ATTR_UNKNOWN;
112
113 final int nameIndex = dataInput.readUnsignedShort();
114 final String name = constantPool.getConstantUtf8(nameIndex).getBytes();
115
116
117 final int length = dataInput.readInt();
118
119
120 for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++) {
121 if (name.equals(Const.getAttributeName(i))) {
122 tag = i;
123 break;
124 }
125 }
126
127
128 switch (tag) {
129 case Const.ATTR_UNKNOWN:
130 final Object r = READERS.get(name);
131 if (r instanceof UnknownAttributeReader) {
132 return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool);
133 }
134 return new Unknown(nameIndex, length, dataInput, constantPool);
135 case Const.ATTR_CONSTANT_VALUE:
136 return new ConstantValue(nameIndex, length, dataInput, constantPool);
137 case Const.ATTR_SOURCE_FILE:
138 return new SourceFile(nameIndex, length, dataInput, constantPool);
139 case Const.ATTR_CODE:
140 return new Code(nameIndex, length, dataInput, constantPool);
141 case Const.ATTR_EXCEPTIONS:
142 return new ExceptionTable(nameIndex, length, dataInput, constantPool);
143 case Const.ATTR_LINE_NUMBER_TABLE:
144 return new LineNumberTable(nameIndex, length, dataInput, constantPool);
145 case Const.ATTR_LOCAL_VARIABLE_TABLE:
146 return new LocalVariableTable(nameIndex, length, dataInput, constantPool);
147 case Const.ATTR_INNER_CLASSES:
148 return new InnerClasses(nameIndex, length, dataInput, constantPool);
149 case Const.ATTR_SYNTHETIC:
150 return new Synthetic(nameIndex, length, dataInput, constantPool);
151 case Const.ATTR_DEPRECATED:
152 return new Deprecated(nameIndex, length, dataInput, constantPool);
153 case Const.ATTR_PMG:
154 return new PMGClass(nameIndex, length, dataInput, constantPool);
155 case Const.ATTR_SIGNATURE:
156 return new Signature(nameIndex, length, dataInput, constantPool);
157 case Const.ATTR_STACK_MAP:
158
159
160 println("Warning: Obsolete StackMap attribute ignored.");
161 return new Unknown(nameIndex, length, dataInput, constantPool);
162 case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
163 return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool);
164 case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
165 return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool);
166 case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
167 return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
168 case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
169 return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
170 case Const.ATTR_ANNOTATION_DEFAULT:
171 return new AnnotationDefault(nameIndex, length, dataInput, constantPool);
172 case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
173 return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool);
174 case Const.ATTR_ENCLOSING_METHOD:
175 return new EnclosingMethod(nameIndex, length, dataInput, constantPool);
176 case Const.ATTR_STACK_MAP_TABLE:
177
178
179 return new StackMap(nameIndex, length, dataInput, constantPool);
180 case Const.ATTR_BOOTSTRAP_METHODS:
181 return new BootstrapMethods(nameIndex, length, dataInput, constantPool);
182 case Const.ATTR_METHOD_PARAMETERS:
183 return new MethodParameters(nameIndex, length, dataInput, constantPool);
184 case Const.ATTR_MODULE:
185 return new Module(nameIndex, length, dataInput, constantPool);
186 case Const.ATTR_MODULE_PACKAGES:
187 return new ModulePackages(nameIndex, length, dataInput, constantPool);
188 case Const.ATTR_MODULE_MAIN_CLASS:
189 return new ModuleMainClass(nameIndex, length, dataInput, constantPool);
190 case Const.ATTR_NEST_HOST:
191 return new NestHost(nameIndex, length, dataInput, constantPool);
192 case Const.ATTR_NEST_MEMBERS:
193 return new NestMembers(nameIndex, length, dataInput, constantPool);
194 case Const.ATTR_RECORD:
195 return new Record(nameIndex, length, dataInput, constantPool);
196 default:
197
198 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
199 }
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 }