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