1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.harmony.unpack200;
20
21 import org.apache.commons.compress.harmony.pack200.Codec;
22 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
23 import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
24 import org.apache.commons.lang3.StringUtils;
25
26
27
28
29 public class AttributeLayout implements IMatcher {
30
31
32
33
34 public static final String ACC_ABSTRACT = "ACC_ABSTRACT";
35
36
37
38
39 public static final String ACC_ANNOTATION = "ACC_ANNOTATION";
40
41
42
43
44 public static final String ACC_ENUM = "ACC_ENUM";
45
46
47
48
49 public static final String ACC_FINAL = "ACC_FINAL";
50
51
52
53
54 public static final String ACC_INTERFACE = "ACC_INTERFACE";
55
56
57
58
59 public static final String ACC_NATIVE = "ACC_NATIVE";
60
61
62
63
64 public static final String ACC_PRIVATE = "ACC_PRIVATE";
65
66
67
68
69 public static final String ACC_PROTECTED = "ACC_PROTECTED";
70
71
72
73
74 public static final String ACC_PUBLIC = "ACC_PUBLIC";
75
76
77
78
79 public static final String ACC_STATIC = "ACC_STATIC";
80
81
82
83
84 public static final String ACC_STRICT = "ACC_STRICT";
85
86
87
88
89 public static final String ACC_SYNCHRONIZED = "ACC_SYNCHRONIZED";
90
91
92
93
94 public static final String ACC_SYNTHETIC = "ACC_SYNTHETIC";
95
96
97
98
99 public static final String ACC_TRANSIENT = "ACC_TRANSIENT";
100
101
102
103
104 public static final String ACC_VOLATILE = "ACC_VOLATILE";
105
106
107
108
109 public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault";
110
111
112
113
114 public static final String ATTRIBUTE_CLASS_FILE_VERSION = "class-file version";
115
116
117
118
119 public static final String ATTRIBUTE_CODE = "Code";
120
121
122
123
124 public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue";
125
126
127
128
129 public static final String ATTRIBUTE_DEPRECATED = "Deprecated";
130
131
132
133
134 public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod";
135
136
137
138
139 public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions";
140
141
142
143
144 public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses";
145
146
147
148
149 public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable";
150
151
152
153
154 public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
155
156
157
158
159 public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
160
161
162
163
164 public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
165
166
167
168
169 public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations";
170
171
172
173
174 public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
175
176
177
178
179 public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
180
181
182
183
184 public static final String ATTRIBUTE_SIGNATURE = "Signature";
185
186
187
188
189 public static final String ATTRIBUTE_SOURCE_FILE = "SourceFile";
190
191
192
193
194 public static final int CONTEXT_CLASS = 0;
195
196
197
198
199 public static final int CONTEXT_CODE = 3;
200
201
202
203
204 public static final int CONTEXT_FIELD = 1;
205
206
207
208
209 public static final int CONTEXT_METHOD = 2;
210
211
212
213
214 public static final String[] contextNames = { "Class", "Field", "Method",
215 "Code", };
216
217 private static ClassFileEntry getValue(final String layout, long longIndex, final SegmentConstantPool pool) throws Pack200Exception {
218 if (layout.startsWith("R")) {
219
220 if (layout.indexOf('N') != -1) {
221 longIndex--;
222 }
223 if (layout.startsWith("RU")) {
224 return pool.getValue(SegmentConstantPool.UTF_8, longIndex);
225 }
226 if (layout.startsWith("RS")) {
227 return pool.getValue(SegmentConstantPool.SIGNATURE, longIndex);
228 }
229 } else if (layout.startsWith("K")) {
230 final char type = layout.charAt(1);
231 switch (type) {
232 case 'S':
233 return pool.getValue(SegmentConstantPool.CP_STRING, longIndex);
234 case 'I':
235 case 'C':
236 return pool.getValue(SegmentConstantPool.CP_INT, longIndex);
237 case 'F':
238 return pool.getValue(SegmentConstantPool.CP_FLOAT, longIndex);
239 case 'J':
240 return pool.getValue(SegmentConstantPool.CP_LONG, longIndex);
241 case 'D':
242 return pool.getValue(SegmentConstantPool.CP_DOUBLE, longIndex);
243 }
244 }
245 throw new Pack200Exception("Unknown layout encoding: " + layout);
246 }
247
248 private final int context;
249
250 private final int index;
251
252 private final String layout;
253
254 private long mask;
255
256 private final String name;
257 private final boolean isDefault;
258 private int backwardsCallCount;
259
260
261
262
263
264
265
266
267
268
269
270
271 public AttributeLayout(final String name, final int context, final String layout, final int index) throws Pack200Exception {
272 this(name, context, layout, index, true);
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287 public AttributeLayout(final String name, final int context, final String layout, final int index, final boolean isDefault) throws Pack200Exception {
288 this.index = index;
289 this.context = context;
290 if (index >= 0) {
291 this.mask = 1L << index;
292 } else {
293 this.mask = 0;
294 }
295 if (context != CONTEXT_CLASS && context != CONTEXT_CODE && context != CONTEXT_FIELD && context != CONTEXT_METHOD) {
296 throw new Pack200Exception("Attribute context out of range: " + context);
297 }
298 if (layout == null) {
299 throw new Pack200Exception("Cannot have a null layout");
300 }
301 if (StringUtils.isEmpty(name)) {
302 throw new Pack200Exception("Cannot have an unnamed layout");
303 }
304 this.name = name;
305 this.layout = layout;
306 this.isDefault = isDefault;
307 }
308
309
310
311
312
313
314 public Codec getCodec() {
315 if (layout.indexOf('O') >= 0) {
316 return Codec.BRANCH5;
317 }
318 if (layout.indexOf('P') >= 0) {
319 return Codec.BCI5;
320 }
321 if (layout.indexOf('S') >= 0 && !layout.contains("KS")
322 && !layout.contains("RS")) {
323 return Codec.SIGNED5;
324 }
325 if (layout.indexOf('B') >= 0) {
326 return Codec.BYTE1;
327 }
328 return Codec.UNSIGNED5;
329 }
330
331
332
333
334
335
336 public int getContext() {
337 return context;
338 }
339
340
341
342
343
344
345 public int getIndex() {
346 return index;
347 }
348
349
350
351
352
353
354 public String getLayout() {
355 return layout;
356 }
357
358
359
360
361
362
363 public String getName() {
364 return name;
365 }
366
367
368
369
370
371
372
373
374
375 public ClassFileEntry getValue(final long longIndex, final SegmentConstantPool pool) throws Pack200Exception {
376 return getValue(layout, longIndex, pool);
377 }
378
379
380
381
382
383
384
385
386
387
388 public ClassFileEntry getValue(final long longIndex, final String type, final SegmentConstantPool pool) throws Pack200Exception {
389
390
391
392 if (!layout.startsWith("KQ")) {
393 return getValue(layout, longIndex, pool);
394 }
395 if (type.equals("Ljava/lang/String;")) {
396 return getValue("KS", longIndex, pool);
397 }
398 return getValue("K" + type + layout.substring(2), longIndex,
399 pool);
400 }
401
402 @Override
403 public int hashCode() {
404 final int prime = 31;
405 int r = 1;
406 if (name != null) {
407 r = r * prime + name.hashCode();
408 }
409 if (layout != null) {
410 r = r * prime + layout.hashCode();
411 }
412 r = r * prime + index;
413 r = r * prime + context;
414 return r;
415 }
416
417
418
419
420
421
422 public boolean isDefaultLayout() {
423 return isDefault;
424 }
425
426
427
428
429
430
431 @Override
432 public boolean matches(final long value) {
433 return (value & mask) != 0;
434 }
435
436
437
438
439
440
441 public int numBackwardsCallables() {
442 if ("*".equals(layout)) {
443 return 1;
444 }
445 return backwardsCallCount;
446 }
447
448
449
450
451
452
453 public void setBackwardsCallCount(final int backwardsCallCount) {
454 this.backwardsCallCount = backwardsCallCount;
455 }
456
457 @Override
458 public String toString() {
459 return contextNames[context] + ": " + name;
460 }
461
462 }