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 java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25
26 import org.apache.commons.compress.harmony.pack200.Codec;
27 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
28 import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
29 import org.apache.commons.compress.harmony.unpack200.bytecode.BCIRenumberedAttribute;
30 import org.apache.commons.compress.harmony.unpack200.bytecode.ByteCode;
31 import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
32 import org.apache.commons.compress.harmony.unpack200.bytecode.CodeAttribute;
33 import org.apache.commons.compress.harmony.unpack200.bytecode.ExceptionTableEntry;
34 import org.apache.commons.compress.harmony.unpack200.bytecode.NewAttribute;
35 import org.apache.commons.compress.harmony.unpack200.bytecode.OperandManager;
36
37
38
39
40 public class BcBands extends BandSet {
41
42
43
44 private byte[][][] methodByteCodePacked;
45
46
47
48 private int[] bcCaseCount;
49 private int[] bcCaseValue;
50 private int[] bcByte;
51 private int[] bcLocal;
52 private int[] bcShort;
53 private int[] bcLabel;
54 private int[] bcIntRef;
55 private int[] bcFloatRef;
56 private int[] bcLongRef;
57 private int[] bcDoubleRef;
58 private int[] bcStringRef;
59 private int[] bcClassRef;
60 private int[] bcFieldRef;
61 private int[] bcMethodRef;
62 private int[] bcIMethodRef;
63 private int[] bcThisField;
64 private int[] bcSuperField;
65 private int[] bcThisMethod;
66 private int[] bcSuperMethod;
67 private int[] bcInitRef;
68 private int[] bcEscRef;
69 private int[] bcEscRefSize;
70 private int[] bcEscSize;
71 private int[][] bcEscByte;
72
73 private List<Integer> wideByteCodes;
74
75
76
77
78 public BcBands(final Segment segment) {
79 super(segment);
80 }
81
82 private boolean endsWithLoad(final int codePacked) {
83 return codePacked >= 21 && codePacked <= 25;
84 }
85
86 private boolean endsWithStore(final int codePacked) {
87 return codePacked >= 54 && codePacked <= 58;
88 }
89
90 public int[] getBcByte() {
91 return bcByte;
92 }
93
94 public int[] getBcCaseCount() {
95 return bcCaseCount;
96 }
97
98 public int[] getBcCaseValue() {
99 return bcCaseValue;
100 }
101
102 public int[] getBcClassRef() {
103 return bcClassRef;
104 }
105
106 public int[] getBcDoubleRef() {
107 return bcDoubleRef;
108 }
109
110 public int[] getBcFieldRef() {
111 return bcFieldRef;
112 }
113
114 public int[] getBcFloatRef() {
115 return bcFloatRef;
116 }
117
118 public int[] getBcIMethodRef() {
119 return bcIMethodRef;
120 }
121
122 public int[] getBcInitRef() {
123 return bcInitRef;
124 }
125
126 public int[] getBcIntRef() {
127 return bcIntRef;
128 }
129
130 public int[] getBcLabel() {
131 return bcLabel;
132 }
133
134 public int[] getBcLocal() {
135 return bcLocal;
136 }
137
138 public int[] getBcLongRef() {
139 return bcLongRef;
140 }
141
142 public int[] getBcMethodRef() {
143 return bcMethodRef;
144 }
145
146 public int[] getBcShort() {
147 return bcShort;
148 }
149
150 public int[] getBcStringRef() {
151 return bcStringRef;
152 }
153
154 public int[] getBcSuperField() {
155 return bcSuperField;
156 }
157
158 public int[] getBcSuperMethod() {
159 return bcSuperMethod;
160 }
161
162 public int[] getBcThisField() {
163 return bcThisField;
164 }
165
166 public int[] getBcThisMethod() {
167 return bcThisMethod;
168 }
169
170 public byte[][][] getMethodByteCodePacked() {
171 return methodByteCodePacked;
172 }
173
174
175
176
177
178
179 @Override
180 public void read(final InputStream in) throws IOException, Pack200Exception {
181
182 final AttributeLayoutMap attributeDefinitionMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
183 final int classCount = header.getClassCount();
184 final long[][] methodFlags = segment.getClassBands().getMethodFlags();
185
186 int bcCaseCountCount = 0;
187 int bcByteCount = 0;
188 int bcShortCount = 0;
189 int bcLocalCount = 0;
190 int bcLabelCount = 0;
191 int bcIntRefCount = 0;
192 int bcFloatRefCount = 0;
193 int bcLongRefCount = 0;
194 int bcDoubleRefCount = 0;
195 int bcStringRefCount = 0;
196 int bcClassRefCount = 0;
197 int bcFieldRefCount = 0;
198 int bcMethodRefCount = 0;
199 int bcIMethodRefCount = 0;
200 int bcThisFieldCount = 0;
201 int bcSuperFieldCount = 0;
202 int bcThisMethodCount = 0;
203 int bcSuperMethodCount = 0;
204 int bcInitRefCount = 0;
205 int bcEscCount = 0;
206 int bcEscRefCount = 0;
207
208 final AttributeLayout abstractModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_ABSTRACT, AttributeLayout.CONTEXT_METHOD);
209 final AttributeLayout nativeModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_NATIVE, AttributeLayout.CONTEXT_METHOD);
210
211 methodByteCodePacked = new byte[classCount][][];
212
213 final List<Boolean> switchIsTableSwitch = new ArrayList<>();
214 wideByteCodes = new ArrayList<>();
215 for (int c = 0; c < classCount; c++) {
216 final int numberOfMethods = methodFlags[c].length;
217 methodByteCodePacked[c] = new byte[numberOfMethods][];
218 for (int m = 0; m < numberOfMethods; m++) {
219 final long methodFlag = methodFlags[c][m];
220 if (!abstractModifier.matches(methodFlag) && !nativeModifier.matches(methodFlag)) {
221 final ByteArrayOutputStream codeBytes = new ByteArrayOutputStream();
222 byte code;
223 while ((code = (byte) (0xff & in.read())) != -1) {
224 codeBytes.write(code);
225 }
226 methodByteCodePacked[c][m] = codeBytes.toByteArray();
227 final int[] codes = new int[methodByteCodePacked[c][m].length];
228 for (int i = 0; i < codes.length; i++) {
229 codes[i] = methodByteCodePacked[c][m][i] & 0xff;
230 }
231 for (int i = 0; i < methodByteCodePacked[c][m].length; i++) {
232 final int codePacked = 0xff & methodByteCodePacked[c][m][i];
233 switch (codePacked) {
234 case 16:
235 case 188:
236 bcByteCount++;
237 break;
238 case 17:
239 bcShortCount++;
240 break;
241 case 18:
242 case 19:
243 bcStringRefCount++;
244 break;
245 case 234:
246 case 237:
247 bcIntRefCount++;
248 break;
249 case 235:
250 case 238:
251 bcFloatRefCount++;
252 break;
253 case 197:
254 bcByteCount++;
255
256 case 233:
257 case 236:
258 case 187:
259 case 189:
260 case 192:
261 case 193:
262 bcClassRefCount++;
263 break;
264 case 20:
265 bcLongRefCount++;
266 break;
267 case 239:
268 bcDoubleRefCount++;
269 break;
270 case 169:
271 bcLocalCount++;
272 break;
273 case 167:
274 case 168:
275 case 200:
276 case 201:
277 bcLabelCount++;
278 break;
279 case 170:
280 switchIsTableSwitch.add(Boolean.TRUE);
281 bcCaseCountCount++;
282 bcLabelCount++;
283 break;
284 case 171:
285 switchIsTableSwitch.add(Boolean.FALSE);
286 bcCaseCountCount++;
287 bcLabelCount++;
288 break;
289 case 178:
290 case 179:
291 case 180:
292 case 181:
293 bcFieldRefCount++;
294 break;
295 case 182:
296 case 183:
297 case 184:
298 bcMethodRefCount++;
299 break;
300 case 185:
301 bcIMethodRefCount++;
302 break;
303 case 202:
304 case 203:
305 case 204:
306 case 205:
307 case 209:
308 case 210:
309 case 211:
310 case 212:
311 bcThisFieldCount++;
312 break;
313 case 206:
314 case 207:
315 case 208:
316 case 213:
317 case 214:
318 case 215:
319 bcThisMethodCount++;
320 break;
321 case 216:
322 case 217:
323 case 218:
324 case 219:
325 case 223:
326 case 224:
327 case 225:
328 case 226:
329 bcSuperFieldCount++;
330 break;
331 case 220:
332 case 221:
333 case 222:
334 case 227:
335 case 228:
336 case 229:
337 bcSuperMethodCount++;
338 break;
339 case 132:
340 bcLocalCount++;
341 bcByteCount++;
342 break;
343 case 196:
344 final int nextInstruction = 0xff & methodByteCodePacked[c][m][i + 1];
345 wideByteCodes.add(Integer.valueOf(nextInstruction));
346 if (nextInstruction == 132) {
347 bcLocalCount++;
348 bcShortCount++;
349 } else if (endsWithLoad(nextInstruction) || endsWithStore(nextInstruction) || nextInstruction == 169) {
350 bcLocalCount++;
351 } else {
352 segment.log(Segment.LOG_LEVEL_VERBOSE, "Found unhandled " + ByteCode.getByteCode(nextInstruction));
353 }
354 i++;
355 break;
356 case 230:
357 case 231:
358 case 232:
359 bcInitRefCount++;
360 break;
361 case 253:
362 bcEscRefCount++;
363 break;
364 case 254:
365 bcEscCount++;
366 break;
367 default:
368 if (endsWithLoad(codePacked) || endsWithStore(codePacked)) {
369 bcLocalCount++;
370 } else if (startsWithIf(codePacked)) {
371 bcLabelCount++;
372 }
373 }
374 }
375 }
376 }
377 }
378
379 bcCaseCount = decodeBandInt("bc_case_count", in, Codec.UNSIGNED5, bcCaseCountCount);
380 int bcCaseValueCount = 0;
381 for (int i = 0; i < bcCaseCount.length; i++) {
382 final boolean isTableSwitch = switchIsTableSwitch.get(i).booleanValue();
383 if (isTableSwitch) {
384 bcCaseValueCount += 1;
385 } else {
386 bcCaseValueCount += bcCaseCount[i];
387 }
388 }
389 bcCaseValue = decodeBandInt("bc_case_value", in, Codec.DELTA5, bcCaseValueCount);
390
391
392
393 for (int index = 0; index < bcCaseCountCount; index++) {
394 bcLabelCount += bcCaseCount[index];
395 }
396 bcByte = decodeBandInt("bc_byte", in, Codec.BYTE1, bcByteCount);
397 bcShort = decodeBandInt("bc_short", in, Codec.DELTA5, bcShortCount);
398 bcLocal = decodeBandInt("bc_local", in, Codec.UNSIGNED5, bcLocalCount);
399 bcLabel = decodeBandInt("bc_label", in, Codec.BRANCH5, bcLabelCount);
400 bcIntRef = decodeBandInt("bc_intref", in, Codec.DELTA5, bcIntRefCount);
401 bcFloatRef = decodeBandInt("bc_floatref", in, Codec.DELTA5, bcFloatRefCount);
402 bcLongRef = decodeBandInt("bc_longref", in, Codec.DELTA5, bcLongRefCount);
403 bcDoubleRef = decodeBandInt("bc_doubleref", in, Codec.DELTA5, bcDoubleRefCount);
404 bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5, bcStringRefCount);
405 bcClassRef = decodeBandInt("bc_classref", in, Codec.UNSIGNED5, bcClassRefCount);
406 bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5, bcFieldRefCount);
407 bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5, bcMethodRefCount);
408 bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5, bcIMethodRefCount);
409 bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5, bcThisFieldCount);
410 bcSuperField = decodeBandInt("bc_superfield", in, Codec.UNSIGNED5, bcSuperFieldCount);
411 bcThisMethod = decodeBandInt("bc_thismethod", in, Codec.UNSIGNED5, bcThisMethodCount);
412 bcSuperMethod = decodeBandInt("bc_supermethod", in, Codec.UNSIGNED5, bcSuperMethodCount);
413 bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5, bcInitRefCount);
414 bcEscRef = decodeBandInt("bc_escref", in, Codec.UNSIGNED5, bcEscRefCount);
415 bcEscRefSize = decodeBandInt("bc_escrefsize", in, Codec.UNSIGNED5, bcEscRefCount);
416 bcEscSize = decodeBandInt("bc_escsize", in, Codec.UNSIGNED5, bcEscCount);
417 bcEscByte = decodeBandInt("bc_escbyte", in, Codec.BYTE1, bcEscSize);
418 }
419
420 private boolean startsWithIf(final int codePacked) {
421 return codePacked >= 153 && codePacked <= 166 || codePacked == 198 || codePacked == 199;
422 }
423
424 @Override
425 public void unpack() throws Pack200Exception {
426 final int classCount = header.getClassCount();
427 final long[][] methodFlags = segment.getClassBands().getMethodFlags();
428 final int[] codeMaxNALocals = segment.getClassBands().getCodeMaxNALocals();
429 final int[] codeMaxStack = segment.getClassBands().getCodeMaxStack();
430 final ArrayList<Attribute>[][] methodAttributes = segment.getClassBands().getMethodAttributes();
431 final String[][] methodDescr = segment.getClassBands().getMethodDescr();
432
433 final AttributeLayoutMap attributeDefinitionMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
434
435 final AttributeLayout abstractModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_ABSTRACT, AttributeLayout.CONTEXT_METHOD);
436 final AttributeLayout nativeModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_NATIVE, AttributeLayout.CONTEXT_METHOD);
437 final AttributeLayout staticModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_STATIC, AttributeLayout.CONTEXT_METHOD);
438
439 final int[] wideByteCodeArray = new int[wideByteCodes.size()];
440 for (int index = 0; index < wideByteCodeArray.length; index++) {
441 wideByteCodeArray[index] = wideByteCodes.get(index).intValue();
442 }
443 final OperandManager operandManager = new OperandManager(bcCaseCount, bcCaseValue, bcByte, bcShort, bcLocal, bcLabel, bcIntRef, bcFloatRef, bcLongRef,
444 bcDoubleRef, bcStringRef, bcClassRef, bcFieldRef, bcMethodRef, bcIMethodRef, bcThisField, bcSuperField, bcThisMethod, bcSuperMethod, bcInitRef,
445 wideByteCodeArray);
446 operandManager.setSegment(segment);
447
448 int i = 0;
449 final ArrayList<List<Attribute>> orderedCodeAttributes = segment.getClassBands().getOrderedCodeAttributes();
450 int codeAttributeIndex = 0;
451
452
453 final int[] handlerCount = segment.getClassBands().getCodeHandlerCount();
454 final int[][] handlerStartPCs = segment.getClassBands().getCodeHandlerStartP();
455 final int[][] handlerEndPCs = segment.getClassBands().getCodeHandlerEndPO();
456 final int[][] handlerCatchPCs = segment.getClassBands().getCodeHandlerCatchPO();
457 final int[][] handlerClassTypes = segment.getClassBands().getCodeHandlerClassRCN();
458
459 final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags();
460 final boolean[] codeHasFlags = segment.getClassBands().getCodeHasAttributes();
461
462 for (int c = 0; c < classCount; c++) {
463 final int numberOfMethods = methodFlags[c].length;
464 for (int m = 0; m < numberOfMethods; m++) {
465 final long methodFlag = methodFlags[c][m];
466 if (!abstractModifier.matches(methodFlag) && !nativeModifier.matches(methodFlag)) {
467 final int maxStack = codeMaxStack[i];
468 int maxLocal = codeMaxNALocals[i];
469 if (!staticModifier.matches(methodFlag)) {
470 maxLocal++;
471 }
472
473 maxLocal += SegmentUtils.countInvokeInterfaceArgs(methodDescr[c][m]);
474 final String[] cpClass = segment.getCpBands().getCpClass();
475 operandManager.setCurrentClass(cpClass[segment.getClassBands().getClassThisInts()[c]]);
476 operandManager.setSuperClass(cpClass[segment.getClassBands().getClassSuperInts()[c]]);
477 final List<ExceptionTableEntry> exceptionTable = new ArrayList<>();
478 if (handlerCount != null) {
479 for (int j = 0; j < handlerCount[i]; j++) {
480 final int handlerClass = handlerClassTypes[i][j] - 1;
481 CPClass cpHandlerClass = null;
482 if (handlerClass != -1) {
483
484
485
486 cpHandlerClass = segment.getCpBands().cpClassValue(handlerClass);
487 }
488 final ExceptionTableEntry entry = new ExceptionTableEntry(handlerStartPCs[i][j], handlerEndPCs[i][j], handlerCatchPCs[i][j],
489 cpHandlerClass);
490 exceptionTable.add(entry);
491 }
492 }
493 final CodeAttribute codeAttr = new CodeAttribute(maxStack, maxLocal, methodByteCodePacked[c][m], segment, operandManager, exceptionTable);
494 final List<Attribute> methodAttributesList = methodAttributes[c][m];
495
496 int indexForCodeAttr = 0;
497 for (final Attribute attribute : methodAttributesList) {
498 if (!(attribute instanceof NewAttribute) || ((NewAttribute) attribute).getLayoutIndex() >= 15) {
499 break;
500 }
501 indexForCodeAttr++;
502 }
503 methodAttributesList.add(indexForCodeAttr, codeAttr);
504 codeAttr.renumber(codeAttr.byteCodeOffsets);
505 List<Attribute> currentAttributes;
506 if (allCodeHasFlags) {
507 currentAttributes = orderedCodeAttributes.get(i);
508 } else if (codeHasFlags[i]) {
509 currentAttributes = orderedCodeAttributes.get(codeAttributeIndex);
510 codeAttributeIndex++;
511 } else {
512 currentAttributes = Collections.EMPTY_LIST;
513 }
514 for (final Attribute currentAttribute : currentAttributes) {
515 codeAttr.addAttribute(currentAttribute);
516
517 if (currentAttribute.hasBCIRenumbering()) {
518 ((BCIRenumberedAttribute) currentAttribute).renumber(codeAttr.byteCodeOffsets);
519 }
520 }
521 i++;
522 }
523 }
524 }
525 }
526 }