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 int bcParsed = 0;
213
214 final List<Boolean> switchIsTableSwitch = new ArrayList<>();
215 wideByteCodes = new ArrayList<>();
216 for (int c = 0; c < classCount; c++) {
217 final int numberOfMethods = methodFlags[c].length;
218 methodByteCodePacked[c] = new byte[numberOfMethods][];
219 for (int m = 0; m < numberOfMethods; m++) {
220 final long methodFlag = methodFlags[c][m];
221 if (!abstractModifier.matches(methodFlag) && !nativeModifier.matches(methodFlag)) {
222 final ByteArrayOutputStream codeBytes = new ByteArrayOutputStream();
223 byte code;
224 while ((code = (byte) (0xff & in.read())) != -1) {
225 codeBytes.write(code);
226 }
227 methodByteCodePacked[c][m] = codeBytes.toByteArray();
228 bcParsed += methodByteCodePacked[c][m].length;
229 final int[] codes = new int[methodByteCodePacked[c][m].length];
230 for (int i = 0; i < codes.length; i++) {
231 codes[i] = methodByteCodePacked[c][m][i] & 0xff;
232 }
233 for (int i = 0; i < methodByteCodePacked[c][m].length; i++) {
234 final int codePacked = 0xff & methodByteCodePacked[c][m][i];
235 switch (codePacked) {
236 case 16:
237 case 188:
238 bcByteCount++;
239 break;
240 case 17:
241 bcShortCount++;
242 break;
243 case 18:
244 case 19:
245 bcStringRefCount++;
246 break;
247 case 234:
248 case 237:
249 bcIntRefCount++;
250 break;
251 case 235:
252 case 238:
253 bcFloatRefCount++;
254 break;
255 case 197:
256 bcByteCount++;
257
258 case 233:
259 case 236:
260 case 187:
261 case 189:
262 case 192:
263 case 193:
264 bcClassRefCount++;
265 break;
266 case 20:
267 bcLongRefCount++;
268 break;
269 case 239:
270 bcDoubleRefCount++;
271 break;
272 case 169:
273 bcLocalCount++;
274 break;
275 case 167:
276 case 168:
277 case 200:
278 case 201:
279 bcLabelCount++;
280 break;
281 case 170:
282 switchIsTableSwitch.add(Boolean.TRUE);
283 bcCaseCountCount++;
284 bcLabelCount++;
285 break;
286 case 171:
287 switchIsTableSwitch.add(Boolean.FALSE);
288 bcCaseCountCount++;
289 bcLabelCount++;
290 break;
291 case 178:
292 case 179:
293 case 180:
294 case 181:
295 bcFieldRefCount++;
296 break;
297 case 182:
298 case 183:
299 case 184:
300 bcMethodRefCount++;
301 break;
302 case 185:
303 bcIMethodRefCount++;
304 break;
305 case 202:
306 case 203:
307 case 204:
308 case 205:
309 case 209:
310 case 210:
311 case 211:
312 case 212:
313 bcThisFieldCount++;
314 break;
315 case 206:
316 case 207:
317 case 208:
318 case 213:
319 case 214:
320 case 215:
321 bcThisMethodCount++;
322 break;
323 case 216:
324 case 217:
325 case 218:
326 case 219:
327 case 223:
328 case 224:
329 case 225:
330 case 226:
331 bcSuperFieldCount++;
332 break;
333 case 220:
334 case 221:
335 case 222:
336 case 227:
337 case 228:
338 case 229:
339 bcSuperMethodCount++;
340 break;
341 case 132:
342 bcLocalCount++;
343 bcByteCount++;
344 break;
345 case 196:
346 final int nextInstruction = 0xff & methodByteCodePacked[c][m][i + 1];
347 wideByteCodes.add(Integer.valueOf(nextInstruction));
348 if (nextInstruction == 132) {
349 bcLocalCount++;
350 bcShortCount++;
351 } else if (endsWithLoad(nextInstruction) || endsWithStore(nextInstruction) || nextInstruction == 169) {
352 bcLocalCount++;
353 } else {
354 segment.log(Segment.LOG_LEVEL_VERBOSE, "Found unhandled " + ByteCode.getByteCode(nextInstruction));
355 }
356 i++;
357 break;
358 case 230:
359 case 231:
360 case 232:
361 bcInitRefCount++;
362 break;
363 case 253:
364 bcEscRefCount++;
365 break;
366 case 254:
367 bcEscCount++;
368 break;
369 default:
370 if (endsWithLoad(codePacked) || endsWithStore(codePacked)) {
371 bcLocalCount++;
372 } else if (startsWithIf(codePacked)) {
373 bcLabelCount++;
374 }
375 }
376 }
377 }
378 }
379 }
380
381 bcCaseCount = decodeBandInt("bc_case_count", in, Codec.UNSIGNED5, bcCaseCountCount);
382 int bcCaseValueCount = 0;
383 for (int i = 0; i < bcCaseCount.length; i++) {
384 final boolean isTableSwitch = switchIsTableSwitch.get(i).booleanValue();
385 if (isTableSwitch) {
386 bcCaseValueCount += 1;
387 } else {
388 bcCaseValueCount += bcCaseCount[i];
389 }
390 }
391 bcCaseValue = decodeBandInt("bc_case_value", in, Codec.DELTA5, bcCaseValueCount);
392
393
394
395 for (int index = 0; index < bcCaseCountCount; index++) {
396 bcLabelCount += bcCaseCount[index];
397 }
398 bcByte = decodeBandInt("bc_byte", in, Codec.BYTE1, bcByteCount);
399 bcShort = decodeBandInt("bc_short", in, Codec.DELTA5, bcShortCount);
400 bcLocal = decodeBandInt("bc_local", in, Codec.UNSIGNED5, bcLocalCount);
401 bcLabel = decodeBandInt("bc_label", in, Codec.BRANCH5, bcLabelCount);
402 bcIntRef = decodeBandInt("bc_intref", in, Codec.DELTA5, bcIntRefCount);
403 bcFloatRef = decodeBandInt("bc_floatref", in, Codec.DELTA5, bcFloatRefCount);
404 bcLongRef = decodeBandInt("bc_longref", in, Codec.DELTA5, bcLongRefCount);
405 bcDoubleRef = decodeBandInt("bc_doubleref", in, Codec.DELTA5, bcDoubleRefCount);
406 bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5, bcStringRefCount);
407 bcClassRef = decodeBandInt("bc_classref", in, Codec.UNSIGNED5, bcClassRefCount);
408 bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5, bcFieldRefCount);
409 bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5, bcMethodRefCount);
410 bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5, bcIMethodRefCount);
411 bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5, bcThisFieldCount);
412 bcSuperField = decodeBandInt("bc_superfield", in, Codec.UNSIGNED5, bcSuperFieldCount);
413 bcThisMethod = decodeBandInt("bc_thismethod", in, Codec.UNSIGNED5, bcThisMethodCount);
414 bcSuperMethod = decodeBandInt("bc_supermethod", in, Codec.UNSIGNED5, bcSuperMethodCount);
415 bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5, bcInitRefCount);
416 bcEscRef = decodeBandInt("bc_escref", in, Codec.UNSIGNED5, bcEscRefCount);
417 bcEscRefSize = decodeBandInt("bc_escrefsize", in, Codec.UNSIGNED5, bcEscRefCount);
418 bcEscSize = decodeBandInt("bc_escsize", in, Codec.UNSIGNED5, bcEscCount);
419 bcEscByte = decodeBandInt("bc_escbyte", in, Codec.BYTE1, bcEscSize);
420 }
421
422 private boolean startsWithIf(final int codePacked) {
423 return codePacked >= 153 && codePacked <= 166 || codePacked == 198 || codePacked == 199;
424 }
425
426 @Override
427 public void unpack() throws Pack200Exception {
428 final int classCount = header.getClassCount();
429 final long[][] methodFlags = segment.getClassBands().getMethodFlags();
430 final int[] codeMaxNALocals = segment.getClassBands().getCodeMaxNALocals();
431 final int[] codeMaxStack = segment.getClassBands().getCodeMaxStack();
432 final ArrayList<Attribute>[][] methodAttributes = segment.getClassBands().getMethodAttributes();
433 final String[][] methodDescr = segment.getClassBands().getMethodDescr();
434
435 final AttributeLayoutMap attributeDefinitionMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
436
437 final AttributeLayout abstractModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_ABSTRACT, AttributeLayout.CONTEXT_METHOD);
438 final AttributeLayout nativeModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_NATIVE, AttributeLayout.CONTEXT_METHOD);
439 final AttributeLayout staticModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_STATIC, AttributeLayout.CONTEXT_METHOD);
440
441 final int[] wideByteCodeArray = new int[wideByteCodes.size()];
442 for (int index = 0; index < wideByteCodeArray.length; index++) {
443 wideByteCodeArray[index] = wideByteCodes.get(index).intValue();
444 }
445 final OperandManager operandManager = new OperandManager(bcCaseCount, bcCaseValue, bcByte, bcShort, bcLocal, bcLabel, bcIntRef, bcFloatRef, bcLongRef,
446 bcDoubleRef, bcStringRef, bcClassRef, bcFieldRef, bcMethodRef, bcIMethodRef, bcThisField, bcSuperField, bcThisMethod, bcSuperMethod, bcInitRef,
447 wideByteCodeArray);
448 operandManager.setSegment(segment);
449
450 int i = 0;
451 final ArrayList<List<Attribute>> orderedCodeAttributes = segment.getClassBands().getOrderedCodeAttributes();
452 int codeAttributeIndex = 0;
453
454
455 final int[] handlerCount = segment.getClassBands().getCodeHandlerCount();
456 final int[][] handlerStartPCs = segment.getClassBands().getCodeHandlerStartP();
457 final int[][] handlerEndPCs = segment.getClassBands().getCodeHandlerEndPO();
458 final int[][] handlerCatchPCs = segment.getClassBands().getCodeHandlerCatchPO();
459 final int[][] handlerClassTypes = segment.getClassBands().getCodeHandlerClassRCN();
460
461 final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags();
462 final boolean[] codeHasFlags = segment.getClassBands().getCodeHasAttributes();
463
464 for (int c = 0; c < classCount; c++) {
465 final int numberOfMethods = methodFlags[c].length;
466 for (int m = 0; m < numberOfMethods; m++) {
467 final long methodFlag = methodFlags[c][m];
468 if (!abstractModifier.matches(methodFlag) && !nativeModifier.matches(methodFlag)) {
469 final int maxStack = codeMaxStack[i];
470 int maxLocal = codeMaxNALocals[i];
471 if (!staticModifier.matches(methodFlag)) {
472 maxLocal++;
473 }
474
475 maxLocal += SegmentUtils.countInvokeInterfaceArgs(methodDescr[c][m]);
476 final String[] cpClass = segment.getCpBands().getCpClass();
477 operandManager.setCurrentClass(cpClass[segment.getClassBands().getClassThisInts()[c]]);
478 operandManager.setSuperClass(cpClass[segment.getClassBands().getClassSuperInts()[c]]);
479 final List<ExceptionTableEntry> exceptionTable = new ArrayList<>();
480 if (handlerCount != null) {
481 for (int j = 0; j < handlerCount[i]; j++) {
482 final int handlerClass = handlerClassTypes[i][j] - 1;
483 CPClass cpHandlerClass = null;
484 if (handlerClass != -1) {
485
486
487
488 cpHandlerClass = segment.getCpBands().cpClassValue(handlerClass);
489 }
490 final ExceptionTableEntry entry = new ExceptionTableEntry(handlerStartPCs[i][j], handlerEndPCs[i][j], handlerCatchPCs[i][j],
491 cpHandlerClass);
492 exceptionTable.add(entry);
493 }
494 }
495 final CodeAttribute codeAttr = new CodeAttribute(maxStack, maxLocal, methodByteCodePacked[c][m], segment, operandManager, exceptionTable);
496 final List<Attribute> methodAttributesList = methodAttributes[c][m];
497
498 int indexForCodeAttr = 0;
499 for (final Attribute attribute : methodAttributesList) {
500 if (!(attribute instanceof NewAttribute) || ((NewAttribute) attribute).getLayoutIndex() >= 15) {
501 break;
502 }
503 indexForCodeAttr++;
504 }
505 methodAttributesList.add(indexForCodeAttr, codeAttr);
506 codeAttr.renumber(codeAttr.byteCodeOffsets);
507 List<Attribute> currentAttributes;
508 if (allCodeHasFlags) {
509 currentAttributes = orderedCodeAttributes.get(i);
510 } else if (codeHasFlags[i]) {
511 currentAttributes = orderedCodeAttributes.get(codeAttributeIndex);
512 codeAttributeIndex++;
513 } else {
514 currentAttributes = Collections.EMPTY_LIST;
515 }
516 for (final Attribute currentAttribute : currentAttributes) {
517 codeAttr.addAttribute(currentAttribute);
518
519 if (currentAttribute.hasBCIRenumbering()) {
520 ((BCIRenumberedAttribute) currentAttribute).renumber(codeAttr.byteCodeOffsets);
521 }
522 }
523 i++;
524 }
525 }
526 }
527 }
528 }