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 default:
195
196 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
197 }
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212 public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException {
213 return readAttribute((DataInput) dataInputStream, constantPool);
214 }
215
216
217
218
219
220
221 public static void removeAttributeReader(final String name) {
222 READERS.remove(name);
223 }
224
225
226
227
228 @java.lang.Deprecated
229 protected int name_index;
230
231
232
233
234 @java.lang.Deprecated
235 protected int length;
236
237
238
239
240 @java.lang.Deprecated
241 protected byte tag;
242
243
244
245
246 @java.lang.Deprecated
247 protected ConstantPool constant_pool;
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) {
266 this.tag = tag;
267 this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index");
268 this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length");
269 this.constant_pool = constantPool;
270 }
271
272
273
274
275
276
277
278 @Override
279 public abstract void accept(Visitor v);
280
281
282
283
284
285
286 @Override
287 public Object clone() {
288 Attribute attr = null;
289 try {
290 attr = (Attribute) super.clone();
291 } catch (final CloneNotSupportedException e) {
292 throw new UnsupportedOperationException("Clone Not Supported", e);
293 }
294 return attr;
295 }
296
297
298
299
300
301 public abstract Attribute copy(ConstantPool constantPool);
302
303
304
305
306
307
308
309 public void dump(final DataOutputStream file) throws IOException {
310 file.writeShort(name_index);
311 file.writeInt(length);
312 }
313
314
315
316
317
318 public final ConstantPool getConstantPool() {
319 return constant_pool;
320 }
321
322
323
324
325 public final int getLength() {
326 return length;
327 }
328
329
330
331
332
333 public String getName() {
334 return constant_pool.getConstantUtf8(name_index).getBytes();
335 }
336
337
338
339
340 public final int getNameIndex() {
341 return name_index;
342 }
343
344
345
346
347 public final byte getTag() {
348 return tag;
349 }
350
351
352
353
354
355 public final void setConstantPool(final ConstantPool constantPool) {
356 this.constant_pool = constantPool;
357 }
358
359
360
361
362 public final void setLength(final int length) {
363 this.length = length;
364 }
365
366
367
368
369 public final void setNameIndex(final int nameIndex) {
370 this.name_index = nameIndex;
371 }
372
373
374
375
376 @Override
377 public String toString() {
378 return Const.getAttributeName(tag);
379 }
380 }