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