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.IOException;
20 import java.io.InputStream;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24 import java.util.stream.Collectors;
25 import java.util.stream.Stream;
26
27 import org.apache.commons.compress.harmony.pack200.Codec;
28 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
29 import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
30 import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
31 import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
32 import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
33 import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
34 import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantValueAttribute;
35 import org.apache.commons.compress.harmony.unpack200.bytecode.DeprecatedAttribute;
36 import org.apache.commons.compress.harmony.unpack200.bytecode.EnclosingMethodAttribute;
37 import org.apache.commons.compress.harmony.unpack200.bytecode.ExceptionsAttribute;
38 import org.apache.commons.compress.harmony.unpack200.bytecode.LineNumberTableAttribute;
39 import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTableAttribute;
40 import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTypeTableAttribute;
41 import org.apache.commons.compress.harmony.unpack200.bytecode.SignatureAttribute;
42 import org.apache.commons.compress.harmony.unpack200.bytecode.SourceFileAttribute;
43
44
45
46
47 public class ClassBands extends BandSet {
48
49 private int[] classFieldCount;
50
51 private long[] classFlags;
52
53 private long[] classAccessFlags;
54
55
56 private int[][] classInterfacesInts;
57
58 private int[] classMethodCount;
59
60 private int[] classSuperInts;
61
62 private String[] classThis;
63
64 private int[] classThisInts;
65
66 private ArrayList<Attribute>[] classAttributes;
67
68 private int[] classVersionMajor;
69
70 private int[] classVersionMinor;
71
72 private IcTuple[][] icLocal;
73
74 private List<Attribute>[] codeAttributes;
75
76 private int[] codeHandlerCount;
77
78 private int[] codeMaxNALocals;
79
80 private int[] codeMaxStack;
81
82 private ArrayList<Attribute>[][] fieldAttributes;
83
84 private String[][] fieldDescr;
85
86 private int[][] fieldDescrInts;
87
88 private long[][] fieldFlags;
89
90 private long[][] fieldAccessFlags;
91
92 private ArrayList<Attribute>[][] methodAttributes;
93
94 private String[][] methodDescr;
95
96 private int[][] methodDescrInts;
97
98 private long[][] methodFlags;
99
100 private long[][] methodAccessFlags;
101
102 private final AttributeLayoutMap attrMap;
103
104 private final CpBands cpBands;
105
106 private final SegmentOptions options;
107
108 private final int classCount;
109
110 private int[] methodAttrCalls;
111
112 private int[][] codeHandlerStartP;
113
114 private int[][] codeHandlerEndPO;
115
116 private int[][] codeHandlerCatchPO;
117
118 private int[][] codeHandlerClassRCN;
119
120 private boolean[] codeHasAttributes;
121
122
123
124
125 public ClassBands(final Segment segment) {
126 super(segment);
127 this.attrMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
128 this.cpBands = segment.getCpBands();
129 this.classCount = header.getClassCount();
130 this.options = header.getOptions();
131
132 }
133
134 private int getCallCount(final int[][] methodAttrIndexes, final long[][] flags, final int context) {
135 int callCount = 0;
136 for (final int[] element : methodAttrIndexes) {
137 for (final int index : element) {
138 final AttributeLayout layout = attrMap.getAttributeLayout(index, context);
139 callCount += layout.numBackwardsCallables();
140 }
141 }
142 int layoutsUsed = 0;
143 for (final long[] flag : flags) {
144 for (final long element : flag) {
145 layoutsUsed |= element;
146 }
147 }
148 for (int i = 0; i < 26; i++) {
149 if ((layoutsUsed & 1 << i) != 0) {
150 final AttributeLayout layout = attrMap.getAttributeLayout(i, context);
151 callCount += layout.numBackwardsCallables();
152 }
153 }
154 return callCount;
155 }
156
157 public ArrayList<Attribute>[] getClassAttributes() {
158 return classAttributes;
159 }
160
161 public int[] getClassFieldCount() {
162 return classFieldCount;
163 }
164
165 public long[] getClassFlags() {
166 if (classAccessFlags == null) {
167 long mask = 0x7FFF;
168 for (int i = 0; i < 16; i++) {
169 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS);
170 if (layout != null && !layout.isDefaultLayout()) {
171 mask &= ~(1 << i);
172 }
173 }
174 classAccessFlags = new long[classFlags.length];
175 for (int i = 0; i < classFlags.length; i++) {
176 classAccessFlags[i] = classFlags[i] & mask;
177 }
178 }
179 return classAccessFlags;
180 }
181
182 public int[][] getClassInterfacesInts() {
183 return classInterfacesInts;
184 }
185
186 public int[] getClassMethodCount() {
187 return classMethodCount;
188 }
189
190 public int[] getClassSuperInts() {
191 return classSuperInts;
192 }
193
194 public int[] getClassThisInts() {
195 return classThisInts;
196 }
197
198
199
200
201
202
203
204 public int[] getClassVersionMajor() {
205 return classVersionMajor;
206 }
207
208
209
210
211
212
213
214 public int[] getClassVersionMinor() {
215 return classVersionMinor;
216 }
217
218 public int[][] getCodeHandlerCatchPO() {
219 return codeHandlerCatchPO;
220 }
221
222 public int[][] getCodeHandlerClassRCN() {
223 return codeHandlerClassRCN;
224 }
225
226 public int[] getCodeHandlerCount() {
227 return codeHandlerCount;
228 }
229
230 public int[][] getCodeHandlerEndPO() {
231 return codeHandlerEndPO;
232 }
233
234 public int[][] getCodeHandlerStartP() {
235 return codeHandlerStartP;
236 }
237
238 public boolean[] getCodeHasAttributes() {
239 return codeHasAttributes;
240 }
241
242 public int[] getCodeMaxNALocals() {
243 return codeMaxNALocals;
244 }
245
246 public int[] getCodeMaxStack() {
247 return codeMaxStack;
248 }
249
250 public ArrayList<Attribute>[][] getFieldAttributes() {
251 return fieldAttributes;
252 }
253
254 public int[][] getFieldDescrInts() {
255 return fieldDescrInts;
256 }
257
258 public long[][] getFieldFlags() {
259 if (fieldAccessFlags == null) {
260 long mask = 0x7FFF;
261 for (int i = 0; i < 16; i++) {
262 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD);
263 if (layout != null && !layout.isDefaultLayout()) {
264 mask &= ~(1 << i);
265 }
266 }
267 fieldAccessFlags = new long[fieldFlags.length][];
268 for (int i = 0; i < fieldFlags.length; i++) {
269 fieldAccessFlags[i] = new long[fieldFlags[i].length];
270 for (int j = 0; j < fieldFlags[i].length; j++) {
271 fieldAccessFlags[i][j] = fieldFlags[i][j] & mask;
272 }
273 }
274 }
275 return fieldAccessFlags;
276 }
277
278 public IcTuple[][] getIcLocal() {
279 return icLocal;
280 }
281
282 public ArrayList<Attribute>[][] getMethodAttributes() {
283 return methodAttributes;
284 }
285
286 public String[][] getMethodDescr() {
287 return methodDescr;
288 }
289
290 public int[][] getMethodDescrInts() {
291 return methodDescrInts;
292 }
293
294 public long[][] getMethodFlags() {
295 if (methodAccessFlags == null) {
296 long mask = 0x7FFF;
297 for (int i = 0; i < 16; i++) {
298 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD);
299 if (layout != null && !layout.isDefaultLayout()) {
300 mask &= ~(1 << i);
301 }
302 }
303 methodAccessFlags = new long[methodFlags.length][];
304 for (int i = 0; i < methodFlags.length; i++) {
305 methodAccessFlags[i] = new long[methodFlags[i].length];
306 for (int j = 0; j < methodFlags[i].length; j++) {
307 methodAccessFlags[i][j] = methodFlags[i][j] & mask;
308 }
309 }
310 }
311 return methodAccessFlags;
312 }
313
314
315
316
317
318
319
320
321 public ArrayList<List<Attribute>> getOrderedCodeAttributes() {
322 return Stream.of(codeAttributes).map(ArrayList::new).collect(Collectors.toCollection(ArrayList::new));
323 }
324
325 public long[] getRawClassFlags() {
326 return classFlags;
327 }
328
329 private void parseClassAttrBands(final InputStream in) throws IOException, Pack200Exception {
330 final String[] cpUTF8 = cpBands.getCpUTF8();
331 final String[] cpClass = cpBands.getCpClass();
332
333
334 classAttributes = new ArrayList[classCount];
335 Arrays.setAll(classAttributes, i -> new ArrayList<>());
336
337 classFlags = parseFlags("class_flags", in, classCount, Codec.UNSIGNED5, options.hasClassFlagsHi());
338 final int classAttrCount = SegmentUtils.countBit16(classFlags);
339 final int[] classAttrCounts = decodeBandInt("class_attr_count", in, Codec.UNSIGNED5, classAttrCount);
340 final int[][] classAttrIndexes = decodeBandInt("class_attr_indexes", in, Codec.UNSIGNED5, classAttrCounts);
341 final int callCount = getCallCount(classAttrIndexes, new long[][] { classFlags }, AttributeLayout.CONTEXT_CLASS);
342 final int[] classAttrCalls = decodeBandInt("class_attr_calls", in, Codec.UNSIGNED5, callCount);
343
344 final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_CLASS);
345
346 final AttributeLayout sourceFileLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE, AttributeLayout.CONTEXT_CLASS);
347 final int sourceFileCount = SegmentUtils.countMatches(classFlags, sourceFileLayout);
348 final int[] classSourceFile = decodeBandInt("class_SourceFile_RUN", in, Codec.UNSIGNED5, sourceFileCount);
349
350 final AttributeLayout enclosingMethodLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ENCLOSING_METHOD, AttributeLayout.CONTEXT_CLASS);
351 final int enclosingMethodCount = SegmentUtils.countMatches(classFlags, enclosingMethodLayout);
352 final int[] enclosingMethodRC = decodeBandInt("class_EnclosingMethod_RC", in, Codec.UNSIGNED5, enclosingMethodCount);
353 final int[] enclosingMethodRDN = decodeBandInt("class_EnclosingMethod_RDN", in, Codec.UNSIGNED5, enclosingMethodCount);
354
355 final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_CLASS);
356 final int signatureCount = SegmentUtils.countMatches(classFlags, signatureLayout);
357 final int[] classSignature = decodeBandInt("class_Signature_RS", in, Codec.UNSIGNED5, signatureCount);
358
359 final int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls);
360
361 final AttributeLayout innerClassLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_INNER_CLASSES, AttributeLayout.CONTEXT_CLASS);
362 final int innerClassCount = SegmentUtils.countMatches(classFlags, innerClassLayout);
363 final int[] classInnerClassesN = decodeBandInt("class_InnerClasses_N", in, Codec.UNSIGNED5, innerClassCount);
364 final int[][] classInnerClassesRC = decodeBandInt("class_InnerClasses_RC", in, Codec.UNSIGNED5, classInnerClassesN);
365 final int[][] classInnerClassesF = decodeBandInt("class_InnerClasses_F", in, Codec.UNSIGNED5, classInnerClassesN);
366 int flagsCount = 0;
367 for (final int[] element : classInnerClassesF) {
368 for (final int element2 : element) {
369 if (element2 != 0) {
370 flagsCount++;
371 }
372 }
373 }
374 final int[] classInnerClassesOuterRCN = decodeBandInt("class_InnerClasses_outer_RCN", in, Codec.UNSIGNED5, flagsCount);
375 final int[] classInnerClassesNameRUN = decodeBandInt("class_InnerClasses_name_RUN", in, Codec.UNSIGNED5, flagsCount);
376
377 final AttributeLayout versionLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION, AttributeLayout.CONTEXT_CLASS);
378 final int versionCount = SegmentUtils.countMatches(classFlags, versionLayout);
379 final int[] classFileVersionMinorH = decodeBandInt("class_file_version_minor_H", in, Codec.UNSIGNED5, versionCount);
380 final int[] classFileVersionMajorH = decodeBandInt("class_file_version_major_H", in, Codec.UNSIGNED5, versionCount);
381 if (versionCount > 0) {
382 classVersionMajor = new int[classCount];
383 classVersionMinor = new int[classCount];
384 }
385 final int defaultVersionMajor = header.getDefaultClassMajorVersion();
386 final int defaultVersionMinor = header.getDefaultClassMinorVersion();
387
388
389 int backwardsCallIndex = backwardsCallsUsed;
390 final int limit = options.hasClassFlagsHi() ? 62 : 31;
391 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
392 final int[] counts = new int[limit + 1];
393 final List<Attribute>[] otherAttributes = new List[limit + 1];
394 for (int i = 0; i < limit; i++) {
395 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS);
396 if (layout != null && !layout.isDefaultLayout()) {
397 otherLayouts[i] = layout;
398 counts[i] = SegmentUtils.countMatches(classFlags, layout);
399 }
400 }
401 for (int i = 0; i < counts.length; i++) {
402 if (counts[i] > 0) {
403 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
404 otherAttributes[i] = bands.parseAttributes(in, counts[i]);
405 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
406 if (numBackwardsCallables > 0) {
407 final int[] backwardsCalls = new int[numBackwardsCallables];
408 System.arraycopy(classAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
409 bands.setBackwardsCalls(backwardsCalls);
410 backwardsCallIndex += numBackwardsCallables;
411 }
412 }
413 }
414
415
416 int sourceFileIndex = 0;
417 int enclosingMethodIndex = 0;
418 int signatureIndex = 0;
419 int innerClassIndex = 0;
420 int innerClassC2NIndex = 0;
421 int versionIndex = 0;
422 icLocal = new IcTuple[classCount][];
423 for (int i = 0; i < classCount; i++) {
424 final long flag = classFlags[i];
425 if (deprecatedLayout.matches(classFlags[i])) {
426 classAttributes[i].add(new DeprecatedAttribute());
427 }
428 if (sourceFileLayout.matches(flag)) {
429 final long result = classSourceFile[sourceFileIndex];
430 ClassFileEntry value = sourceFileLayout.getValue(result, cpBands.getConstantPool());
431 if (value == null) {
432
433 String className = classThis[i].substring(classThis[i].lastIndexOf('/') + 1);
434 className = className.substring(className.lastIndexOf('.') + 1);
435
436
437 final char[] chars = className.toCharArray();
438 int index = -1;
439 for (int j = 0; j < chars.length; j++) {
440 if (chars[j] <= 0x2D) {
441 index = j;
442 break;
443 }
444 }
445 if (index > -1) {
446 className = className.substring(0, index);
447 }
448
449 value = cpBands.cpUTF8Value(className + ".java", true);
450 }
451 classAttributes[i].add(new SourceFileAttribute((CPUTF8) value));
452 sourceFileIndex++;
453 }
454 if (enclosingMethodLayout.matches(flag)) {
455 final CPClass theClass = cpBands.cpClassValue(enclosingMethodRC[enclosingMethodIndex]);
456 CPNameAndType theMethod = null;
457 if (enclosingMethodRDN[enclosingMethodIndex] != 0) {
458 theMethod = cpBands.cpNameAndTypeValue(enclosingMethodRDN[enclosingMethodIndex] - 1);
459 }
460 classAttributes[i].add(new EnclosingMethodAttribute(theClass, theMethod));
461 enclosingMethodIndex++;
462 }
463 if (signatureLayout.matches(flag)) {
464 final long result = classSignature[signatureIndex];
465 final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, cpBands.getConstantPool());
466 classAttributes[i].add(new SignatureAttribute(value));
467 signatureIndex++;
468 }
469 if (innerClassLayout.matches(flag)) {
470
471
472 icLocal[i] = new IcTuple[classInnerClassesN[innerClassIndex]];
473 for (int j = 0; j < icLocal[i].length; j++) {
474 final int icTupleCIndex = classInnerClassesRC[innerClassIndex][j];
475 int icTupleC2Index = -1;
476 int icTupleNIndex = -1;
477
478 final String icTupleC = cpClass[icTupleCIndex];
479 int icTupleF = classInnerClassesF[innerClassIndex][j];
480 String icTupleC2 = null;
481 String icTupleN = null;
482
483 if (icTupleF != 0) {
484 icTupleC2Index = classInnerClassesOuterRCN[innerClassC2NIndex];
485 icTupleNIndex = classInnerClassesNameRUN[innerClassC2NIndex];
486 icTupleC2 = cpClass[icTupleC2Index];
487 icTupleN = cpUTF8[icTupleNIndex];
488 innerClassC2NIndex++;
489 } else {
490
491 final IcBands icBands = segment.getIcBands();
492 final IcTuple[] icAll = icBands.getIcTuples();
493 for (final IcTuple element : icAll) {
494 if (element.getC().equals(icTupleC)) {
495 icTupleF = element.getF();
496 icTupleC2 = element.getC2();
497 icTupleN = element.getN();
498 break;
499 }
500 }
501 }
502
503 final IcTuple icTuple = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN, icTupleCIndex, icTupleC2Index, icTupleNIndex, j);
504 icLocal[i][j] = icTuple;
505 }
506 innerClassIndex++;
507 }
508 if (versionLayout.matches(flag)) {
509 classVersionMajor[i] = classFileVersionMajorH[versionIndex];
510 classVersionMinor[i] = classFileVersionMinorH[versionIndex];
511 versionIndex++;
512 } else if (classVersionMajor != null) {
513
514 classVersionMajor[i] = defaultVersionMajor;
515 classVersionMinor[i] = defaultVersionMinor;
516 }
517
518 for (int j = 0; j < otherLayouts.length; j++) {
519 if (otherLayouts[j] != null && otherLayouts[j].matches(flag)) {
520
521 classAttributes[i].add(otherAttributes[j].get(0));
522 otherAttributes[j].remove(0);
523 }
524 }
525 }
526 }
527
528
529
530
531
532
533
534
535
536
537 private int parseClassMetadataBands(final InputStream in, final int[] classAttrCalls) throws Pack200Exception, IOException {
538 int numBackwardsCalls = 0;
539 final String[] RxA = { "RVA", "RIA" };
540
541 final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS);
542 final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS);
543 final int rvaCount = SegmentUtils.countMatches(classFlags, rvaLayout);
544 final int riaCount = SegmentUtils.countMatches(classFlags, riaLayout);
545 final int[] RxACount = { rvaCount, riaCount };
546 final int[] backwardsCalls = { 0, 0 };
547 if (rvaCount > 0) {
548 numBackwardsCalls++;
549 backwardsCalls[0] = classAttrCalls[0];
550 if (riaCount > 0) {
551 numBackwardsCalls++;
552 backwardsCalls[1] = classAttrCalls[1];
553 }
554 } else if (riaCount > 0) {
555 numBackwardsCalls++;
556 backwardsCalls[1] = classAttrCalls[0];
557 }
558 final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, RxACount, backwardsCalls, "class");
559 final List<Attribute> rvaAttributes = mbgs[0].getAttributes();
560 final List<Attribute> riaAttributes = mbgs[1].getAttributes();
561 int rvaAttributesIndex = 0;
562 int riaAttributesIndex = 0;
563 for (int i = 0; i < classFlags.length; i++) {
564 if (rvaLayout.matches(classFlags[i])) {
565 classAttributes[i].add(rvaAttributes.get(rvaAttributesIndex++));
566 }
567 if (riaLayout.matches(classFlags[i])) {
568 classAttributes[i].add(riaAttributes.get(riaAttributesIndex++));
569 }
570 }
571 return numBackwardsCalls;
572 }
573
574 private void parseCodeAttrBands(final InputStream in, final int codeFlagsCount) throws IOException, Pack200Exception {
575 final long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount, Codec.UNSIGNED5, segment.getSegmentHeader().getOptions().hasCodeFlagsHi());
576 final int codeAttrCount = SegmentUtils.countBit16(codeFlags);
577 final int[] codeAttrCounts = decodeBandInt("code_attr_count", in, Codec.UNSIGNED5, codeAttrCount);
578 final int[][] codeAttrIndexes = decodeBandInt("code_attr_indexes", in, Codec.UNSIGNED5, codeAttrCounts);
579 int callCount = 0;
580 for (final int[] element : codeAttrIndexes) {
581 for (final int index : element) {
582 final AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_CODE);
583 callCount += layout.numBackwardsCallables();
584 }
585 }
586 final int[] codeAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5, callCount);
587
588 final AttributeLayout lineNumberTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE);
589 final int lineNumberTableCount = SegmentUtils.countMatches(codeFlags, lineNumberTableLayout);
590 final int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in, Codec.UNSIGNED5, lineNumberTableCount);
591 final int[][] lineNumberTableBciP = decodeBandInt("code_LineNumberTable_bci_P", in, Codec.BCI5, lineNumberTableN);
592 final int[][] lineNumberTableLine = decodeBandInt("code_LineNumberTable_line", in, Codec.UNSIGNED5, lineNumberTableN);
593
594 final AttributeLayout localVariableTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE,
595 AttributeLayout.CONTEXT_CODE);
596 final AttributeLayout localVariableTypeTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE,
597 AttributeLayout.CONTEXT_CODE);
598
599 final int lengthLocalVariableNBand = SegmentUtils.countMatches(codeFlags, localVariableTableLayout);
600 final int[] localVariableTableN = decodeBandInt("code_LocalVariableTable_N", in, Codec.UNSIGNED5, lengthLocalVariableNBand);
601 final int[][] localVariableTableBciP = decodeBandInt("code_LocalVariableTable_bci_P", in, Codec.BCI5, localVariableTableN);
602 final int[][] localVariableTableSpanO = decodeBandInt("code_LocalVariableTable_span_O", in, Codec.BRANCH5, localVariableTableN);
603 final CPUTF8[][] localVariableTableNameRU = parseCPUTF8References("code_LocalVariableTable_name_RU", in, Codec.UNSIGNED5, localVariableTableN);
604 final CPUTF8[][] localVariableTableTypeRS = parseCPSignatureReferences("code_LocalVariableTable_type_RS", in, Codec.UNSIGNED5, localVariableTableN);
605 final int[][] localVariableTableSlot = decodeBandInt("code_LocalVariableTable_slot", in, Codec.UNSIGNED5, localVariableTableN);
606
607 final int lengthLocalVariableTypeTableNBand = SegmentUtils.countMatches(codeFlags, localVariableTypeTableLayout);
608 final int[] localVariableTypeTableN = decodeBandInt("code_LocalVariableTypeTable_N", in, Codec.UNSIGNED5, lengthLocalVariableTypeTableNBand);
609 final int[][] localVariableTypeTableBciP = decodeBandInt("code_LocalVariableTypeTable_bci_P", in, Codec.BCI5, localVariableTypeTableN);
610 final int[][] localVariableTypeTableSpanO = decodeBandInt("code_LocalVariableTypeTable_span_O", in, Codec.BRANCH5, localVariableTypeTableN);
611 final CPUTF8[][] localVariableTypeTableNameRU = parseCPUTF8References("code_LocalVariableTypeTable_name_RU", in, Codec.UNSIGNED5,
612 localVariableTypeTableN);
613 final CPUTF8[][] localVariableTypeTableTypeRS = parseCPSignatureReferences("code_LocalVariableTypeTable_type_RS", in, Codec.UNSIGNED5,
614 localVariableTypeTableN);
615 final int[][] localVariableTypeTableSlot = decodeBandInt("code_LocalVariableTypeTable_slot", in, Codec.UNSIGNED5, localVariableTypeTableN);
616
617
618 int backwardsCallIndex = 0;
619 final int limit = options.hasCodeFlagsHi() ? 62 : 31;
620 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
621 final int[] counts = new int[limit + 1];
622 final List<Attribute>[] otherAttributes = new List[limit + 1];
623 for (int i = 0; i < limit; i++) {
624 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CODE);
625 if (layout != null && !layout.isDefaultLayout()) {
626 otherLayouts[i] = layout;
627 counts[i] = SegmentUtils.countMatches(codeFlags, layout);
628 }
629 }
630 for (int i = 0; i < counts.length; i++) {
631 if (counts[i] > 0) {
632 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
633 otherAttributes[i] = bands.parseAttributes(in, counts[i]);
634 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
635 if (numBackwardsCallables > 0) {
636 final int[] backwardsCalls = new int[numBackwardsCallables];
637 System.arraycopy(codeAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
638 bands.setBackwardsCalls(backwardsCalls);
639 backwardsCallIndex += numBackwardsCallables;
640 }
641 }
642 }
643
644 int lineNumberIndex = 0;
645 int lvtIndex = 0;
646 int lvttIndex = 0;
647 for (int i = 0; i < codeFlagsCount; i++) {
648 if (lineNumberTableLayout.matches(codeFlags[i])) {
649 final LineNumberTableAttribute lnta = new LineNumberTableAttribute(lineNumberTableN[lineNumberIndex], lineNumberTableBciP[lineNumberIndex],
650 lineNumberTableLine[lineNumberIndex]);
651 lineNumberIndex++;
652 codeAttributes[i].add(lnta);
653 }
654 if (localVariableTableLayout.matches(codeFlags[i])) {
655 final LocalVariableTableAttribute lvta = new LocalVariableTableAttribute(localVariableTableN[lvtIndex], localVariableTableBciP[lvtIndex],
656 localVariableTableSpanO[lvtIndex], localVariableTableNameRU[lvtIndex], localVariableTableTypeRS[lvtIndex],
657 localVariableTableSlot[lvtIndex]);
658 lvtIndex++;
659 codeAttributes[i].add(lvta);
660 }
661 if (localVariableTypeTableLayout.matches(codeFlags[i])) {
662 final LocalVariableTypeTableAttribute lvtta = new LocalVariableTypeTableAttribute(localVariableTypeTableN[lvttIndex],
663 localVariableTypeTableBciP[lvttIndex], localVariableTypeTableSpanO[lvttIndex], localVariableTypeTableNameRU[lvttIndex],
664 localVariableTypeTableTypeRS[lvttIndex], localVariableTypeTableSlot[lvttIndex]);
665 lvttIndex++;
666 codeAttributes[i].add(lvtta);
667 }
668
669 for (int j = 0; j < otherLayouts.length; j++) {
670 if (otherLayouts[j] != null && otherLayouts[j].matches(codeFlags[i])) {
671
672 codeAttributes[i].add(otherAttributes[j].get(0));
673 otherAttributes[j].remove(0);
674 }
675 }
676 }
677
678 }
679
680 private void parseCodeBands(final InputStream in) throws Pack200Exception, IOException {
681 final AttributeLayout layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD);
682
683 final int codeCount = SegmentUtils.countMatches(methodFlags, layout);
684 final int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1, codeCount);
685
686 final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags();
687 if (!allCodeHasFlags) {
688 codeHasAttributes = new boolean[codeCount];
689 }
690 int codeSpecialHeader = 0;
691 for (int i = 0; i < codeCount; i++) {
692 if (codeHeaders[i] == 0) {
693 codeSpecialHeader++;
694 if (!allCodeHasFlags) {
695 codeHasAttributes[i] = true;
696 }
697 }
698 }
699 final int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in, Codec.UNSIGNED5, codeSpecialHeader);
700 final int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in, Codec.UNSIGNED5, codeSpecialHeader);
701 final int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count", in, Codec.UNSIGNED5, codeSpecialHeader);
702
703 codeMaxStack = new int[codeCount];
704 codeMaxNALocals = new int[codeCount];
705 codeHandlerCount = new int[codeCount];
706 int special = 0;
707 for (int i = 0; i < codeCount; i++) {
708 final int header = 0xff & codeHeaders[i];
709 if (header < 0) {
710 throw new IllegalStateException("Shouldn't get here");
711 }
712 if (header == 0) {
713 codeMaxStack[i] = codeMaxStackSpecials[special];
714 codeMaxNALocals[i] = codeMaxNALocalsSpecials[special];
715 codeHandlerCount[i] = codeHandlerCountSpecials[special];
716 special++;
717 } else if (header <= 144) {
718 codeMaxStack[i] = (header - 1) % 12;
719 codeMaxNALocals[i] = (header - 1) / 12;
720 codeHandlerCount[i] = 0;
721 } else if (header <= 208) {
722 codeMaxStack[i] = (header - 145) % 8;
723 codeMaxNALocals[i] = (header - 145) / 8;
724 codeHandlerCount[i] = 1;
725 } else if (header <= 255) {
726 codeMaxStack[i] = (header - 209) % 7;
727 codeMaxNALocals[i] = (header - 209) / 7;
728 codeHandlerCount[i] = 2;
729 } else {
730 throw new IllegalStateException("Shouldn't get here either");
731 }
732 }
733 codeHandlerStartP = decodeBandInt("code_handler_start_P", in, Codec.BCI5, codeHandlerCount);
734 codeHandlerEndPO = decodeBandInt("code_handler_end_PO", in, Codec.BRANCH5, codeHandlerCount);
735 codeHandlerCatchPO = decodeBandInt("code_handler_catch_PO", in, Codec.BRANCH5, codeHandlerCount);
736 codeHandlerClassRCN = decodeBandInt("code_handler_class_RCN", in, Codec.UNSIGNED5, codeHandlerCount);
737
738 final int codeFlagsCount = allCodeHasFlags ? codeCount : codeSpecialHeader;
739
740 codeAttributes = new List[codeFlagsCount];
741 Arrays.setAll(codeAttributes, i -> new ArrayList<>());
742 parseCodeAttrBands(in, codeFlagsCount);
743 }
744
745 private void parseFieldAttrBands(final InputStream in) throws IOException, Pack200Exception {
746 fieldFlags = parseFlags("field_flags", in, classFieldCount, Codec.UNSIGNED5, options.hasFieldFlagsHi());
747 final int fieldAttrCount = SegmentUtils.countBit16(fieldFlags);
748 final int[] fieldAttrCounts = decodeBandInt("field_attr_count", in, Codec.UNSIGNED5, fieldAttrCount);
749 final int[][] fieldAttrIndexes = decodeBandInt("field_attr_indexes", in, Codec.UNSIGNED5, fieldAttrCounts);
750 final int callCount = getCallCount(fieldAttrIndexes, fieldFlags, AttributeLayout.CONTEXT_FIELD);
751 final int[] fieldAttrCalls = decodeBandInt("field_attr_calls", in, Codec.UNSIGNED5, callCount);
752
753
754 fieldAttributes = new ArrayList[classCount][];
755 for (int i = 0; i < classCount; i++) {
756 fieldAttributes[i] = new ArrayList[fieldFlags[i].length];
757 for (int j = 0; j < fieldFlags[i].length; j++) {
758 fieldAttributes[i][j] = new ArrayList<>();
759 }
760 }
761
762 final AttributeLayout constantValueLayout = attrMap.getAttributeLayout("ConstantValue", AttributeLayout.CONTEXT_FIELD);
763 final int constantCount = SegmentUtils.countMatches(fieldFlags, constantValueLayout);
764 final int[] field_constantValue_KQ = decodeBandInt("field_ConstantValue_KQ", in, Codec.UNSIGNED5, constantCount);
765 int constantValueIndex = 0;
766
767 final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_FIELD);
768 final int signatureCount = SegmentUtils.countMatches(fieldFlags, signatureLayout);
769 final int[] fieldSignatureRS = decodeBandInt("field_Signature_RS", in, Codec.UNSIGNED5, signatureCount);
770 int signatureIndex = 0;
771
772 final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_FIELD);
773
774 for (int i = 0; i < classCount; i++) {
775 for (int j = 0; j < fieldFlags[i].length; j++) {
776 final long flag = fieldFlags[i][j];
777 if (deprecatedLayout.matches(flag)) {
778 fieldAttributes[i][j].add(new DeprecatedAttribute());
779 }
780 if (constantValueLayout.matches(flag)) {
781
782 final long result = field_constantValue_KQ[constantValueIndex];
783 final String desc = fieldDescr[i][j];
784 final int colon = desc.indexOf(':');
785 String type = desc.substring(colon + 1);
786 if (type.equals("B") || type.equals("S") || type.equals("C") || type.equals("Z")) {
787 type = "I";
788 }
789 final ClassFileEntry value = constantValueLayout.getValue(result, type, cpBands.getConstantPool());
790 fieldAttributes[i][j].add(new ConstantValueAttribute(value));
791 constantValueIndex++;
792 }
793 if (signatureLayout.matches(flag)) {
794
795 final long result = fieldSignatureRS[signatureIndex];
796 final String desc = fieldDescr[i][j];
797 final int colon = desc.indexOf(':');
798 final String type = desc.substring(colon + 1);
799 final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, type, cpBands.getConstantPool());
800 fieldAttributes[i][j].add(new SignatureAttribute(value));
801 signatureIndex++;
802 }
803 }
804 }
805
806
807 int backwardsCallIndex = parseFieldMetadataBands(in, fieldAttrCalls);
808 final int limit = options.hasFieldFlagsHi() ? 62 : 31;
809 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
810 final int[] counts = new int[limit + 1];
811 final List<Attribute>[] otherAttributes = new List[limit + 1];
812 for (int i = 0; i < limit; i++) {
813 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD);
814 if (layout != null && !layout.isDefaultLayout()) {
815 otherLayouts[i] = layout;
816 counts[i] = SegmentUtils.countMatches(fieldFlags, layout);
817 }
818 }
819 for (int i = 0; i < counts.length; i++) {
820 if (counts[i] > 0) {
821 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
822 otherAttributes[i] = bands.parseAttributes(in, counts[i]);
823 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
824 if (numBackwardsCallables > 0) {
825 final int[] backwardsCalls = new int[numBackwardsCallables];
826 System.arraycopy(fieldAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
827 bands.setBackwardsCalls(backwardsCalls);
828 backwardsCallIndex += numBackwardsCallables;
829 }
830 }
831 }
832
833
834 for (int i = 0; i < classCount; i++) {
835 for (int j = 0; j < fieldFlags[i].length; j++) {
836 final long flag = fieldFlags[i][j];
837 int othersAddedAtStart = 0;
838 for (int k = 0; k < otherLayouts.length; k++) {
839 if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) {
840
841 if (otherLayouts[k].getIndex() < 15) {
842 fieldAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0));
843 } else {
844 fieldAttributes[i][j].add(otherAttributes[k].get(0));
845 }
846 otherAttributes[k].remove(0);
847 }
848 }
849 }
850 }
851 }
852
853 private void parseFieldBands(final InputStream in) throws IOException, Pack200Exception {
854 fieldDescrInts = decodeBandInt("field_descr", in, Codec.DELTA5, classFieldCount);
855 fieldDescr = getReferences(fieldDescrInts, cpBands.getCpDescriptor());
856 parseFieldAttrBands(in);
857 }
858
859 private int parseFieldMetadataBands(final InputStream in, final int[] fieldAttrCalls) throws Pack200Exception, IOException {
860 int backwardsCallsUsed = 0;
861 final String[] RxA = { "RVA", "RIA" };
862
863 final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD);
864 final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD);
865
866 final int rvaCount = SegmentUtils.countMatches(fieldFlags, rvaLayout);
867 final int riaCount = SegmentUtils.countMatches(fieldFlags, riaLayout);
868 final int[] RxACount = { rvaCount, riaCount };
869 final int[] backwardsCalls = { 0, 0 };
870 if (rvaCount > 0) {
871 backwardsCalls[0] = fieldAttrCalls[0];
872 backwardsCallsUsed++;
873 if (riaCount > 0) {
874 backwardsCalls[1] = fieldAttrCalls[1];
875 backwardsCallsUsed++;
876 }
877 } else if (riaCount > 0) {
878 backwardsCalls[1] = fieldAttrCalls[0];
879 backwardsCallsUsed++;
880 }
881 final MetadataBandGroup[] mb = parseMetadata(in, RxA, RxACount, backwardsCalls, "field");
882 final List<Attribute> rvaAttributes = mb[0].getAttributes();
883 final List<Attribute> riaAttributes = mb[1].getAttributes();
884 int rvaAttributesIndex = 0;
885 int riaAttributesIndex = 0;
886 for (int i = 0; i < fieldFlags.length; i++) {
887 for (int j = 0; j < fieldFlags[i].length; j++) {
888 if (rvaLayout.matches(fieldFlags[i][j])) {
889 fieldAttributes[i][j].add(rvaAttributes.get(rvaAttributesIndex++));
890 }
891 if (riaLayout.matches(fieldFlags[i][j])) {
892 fieldAttributes[i][j].add(riaAttributes.get(riaAttributesIndex++));
893 }
894 }
895 }
896 return backwardsCallsUsed;
897 }
898
899 private MetadataBandGroup[] parseMetadata(final InputStream in, final String[] RxA, final int[] RxACount, final int[] backwardsCallCounts,
900 final String contextName) throws IOException, Pack200Exception {
901 final MetadataBandGroup[] mbg = new MetadataBandGroup[RxA.length];
902 for (int i = 0; i < RxA.length; i++) {
903 mbg[i] = new MetadataBandGroup(RxA[i], cpBands);
904 final String rxa = RxA[i];
905 if (rxa.indexOf('P') >= 0) {
906 mbg[i].param_NB = decodeBandInt(contextName + "_" + rxa + "_param_NB", in, Codec.BYTE1, RxACount[i]);
907 }
908 int pairCount = 0;
909 if (!rxa.equals("AD")) {
910 mbg[i].anno_N = decodeBandInt(contextName + "_" + rxa + "_anno_N", in, Codec.UNSIGNED5, RxACount[i]);
911 mbg[i].type_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_type_RS", in, Codec.UNSIGNED5, mbg[i].anno_N);
912 mbg[i].pair_N = decodeBandInt(contextName + "_" + rxa + "_pair_N", in, Codec.UNSIGNED5, mbg[i].anno_N);
913 for (final int[] element : mbg[i].pair_N) {
914 for (final int element2 : element) {
915 pairCount += element2;
916 }
917 }
918
919 mbg[i].name_RU = parseCPUTF8References(contextName + "_" + rxa + "_name_RU", in, Codec.UNSIGNED5, pairCount);
920 } else {
921 pairCount = RxACount[i];
922 }
923 mbg[i].T = decodeBandInt(contextName + "_" + rxa + "_T", in, Codec.BYTE1, pairCount + backwardsCallCounts[i]);
924 int ICount = 0, DCount = 0, FCount = 0, JCount = 0, cCount = 0, eCount = 0, sCount = 0, arrayCount = 0, atCount = 0;
925 for (final int element : mbg[i].T) {
926 final char c = (char) element;
927 switch (c) {
928 case 'B':
929 case 'C':
930 case 'I':
931 case 'S':
932 case 'Z':
933 ICount++;
934 break;
935 case 'D':
936 DCount++;
937 break;
938 case 'F':
939 FCount++;
940 break;
941 case 'J':
942 JCount++;
943 break;
944 case 'c':
945 cCount++;
946 break;
947 case 'e':
948 eCount++;
949 break;
950 case 's':
951 sCount++;
952 break;
953 case '[':
954 arrayCount++;
955 break;
956 case '@':
957 atCount++;
958 break;
959 }
960 }
961 mbg[i].caseI_KI = parseCPIntReferences(contextName + "_" + rxa + "_caseI_KI", in, Codec.UNSIGNED5, ICount);
962 mbg[i].caseD_KD = parseCPDoubleReferences(contextName + "_" + rxa + "_caseD_KD", in, Codec.UNSIGNED5, DCount);
963 mbg[i].caseF_KF = parseCPFloatReferences(contextName + "_" + rxa + "_caseF_KF", in, Codec.UNSIGNED5, FCount);
964 mbg[i].caseJ_KJ = parseCPLongReferences(contextName + "_" + rxa + "_caseJ_KJ", in, Codec.UNSIGNED5, JCount);
965 mbg[i].casec_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_casec_RS", in, Codec.UNSIGNED5, cCount);
966 mbg[i].caseet_RS = parseReferences(contextName + "_" + rxa + "_caseet_RS", in, Codec.UNSIGNED5, eCount, cpBands.getCpSignature());
967 mbg[i].caseec_RU = parseReferences(contextName + "_" + rxa + "_caseec_RU", in, Codec.UNSIGNED5, eCount, cpBands.getCpUTF8());
968 mbg[i].cases_RU = parseCPUTF8References(contextName + "_" + rxa + "_cases_RU", in, Codec.UNSIGNED5, sCount);
969 mbg[i].casearray_N = decodeBandInt(contextName + "_" + rxa + "_casearray_N", in, Codec.UNSIGNED5, arrayCount);
970 mbg[i].nesttype_RS = parseCPUTF8References(contextName + "_" + rxa + "_nesttype_RS", in, Codec.UNSIGNED5, atCount);
971 mbg[i].nestpair_N = decodeBandInt(contextName + "_" + rxa + "_nestpair_N", in, Codec.UNSIGNED5, atCount);
972 int nestPairCount = 0;
973 for (final int element : mbg[i].nestpair_N) {
974 nestPairCount += element;
975 }
976 mbg[i].nestname_RU = parseCPUTF8References(contextName + "_" + rxa + "_nestname_RU", in, Codec.UNSIGNED5, nestPairCount);
977 }
978 return mbg;
979 }
980
981 private void parseMethodAttrBands(final InputStream in) throws IOException, Pack200Exception {
982 methodFlags = parseFlags("method_flags", in, classMethodCount, Codec.UNSIGNED5, options.hasMethodFlagsHi());
983 final int methodAttrCount = SegmentUtils.countBit16(methodFlags);
984 final int[] methodAttrCounts = decodeBandInt("method_attr_count", in, Codec.UNSIGNED5, methodAttrCount);
985 final int[][] methodAttrIndexes = decodeBandInt("method_attr_indexes", in, Codec.UNSIGNED5, methodAttrCounts);
986 final int callCount = getCallCount(methodAttrIndexes, methodFlags, AttributeLayout.CONTEXT_METHOD);
987 methodAttrCalls = decodeBandInt("method_attr_calls", in, Codec.UNSIGNED5, callCount);
988
989
990 methodAttributes = new ArrayList[classCount][];
991 for (int i = 0; i < classCount; i++) {
992 methodAttributes[i] = new ArrayList[methodFlags[i].length];
993 for (int j = 0; j < methodFlags[i].length; j++) {
994 methodAttributes[i][j] = new ArrayList<>();
995 }
996 }
997
998
999 final AttributeLayout methodExceptionsLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS, AttributeLayout.CONTEXT_METHOD);
1000 final int count = SegmentUtils.countMatches(methodFlags, methodExceptionsLayout);
1001 final int[] numExceptions = decodeBandInt("method_Exceptions_n", in, Codec.UNSIGNED5, count);
1002 final int[][] methodExceptionsRS = decodeBandInt("method_Exceptions_RC", in, Codec.UNSIGNED5, numExceptions);
1003
1004
1005 final AttributeLayout methodSignatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_METHOD);
1006 final int count1 = SegmentUtils.countMatches(methodFlags, methodSignatureLayout);
1007 final int[] methodSignatureRS = decodeBandInt("method_signature_RS", in, Codec.UNSIGNED5, count1);
1008
1009 final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_METHOD);
1010
1011
1012 int methodExceptionsIndex = 0;
1013 int methodSignatureIndex = 0;
1014 for (int i = 0; i < methodAttributes.length; i++) {
1015 for (int j = 0; j < methodAttributes[i].length; j++) {
1016 final long flag = methodFlags[i][j];
1017 if (methodExceptionsLayout.matches(flag)) {
1018 final int n = numExceptions[methodExceptionsIndex];
1019 final int[] exceptions = methodExceptionsRS[methodExceptionsIndex];
1020 final CPClass[] exceptionClasses = new CPClass[n];
1021 for (int k = 0; k < n; k++) {
1022 exceptionClasses[k] = cpBands.cpClassValue(exceptions[k]);
1023 }
1024 methodAttributes[i][j].add(new ExceptionsAttribute(exceptionClasses));
1025 methodExceptionsIndex++;
1026 }
1027 if (methodSignatureLayout.matches(flag)) {
1028
1029 final long result = methodSignatureRS[methodSignatureIndex];
1030 final String desc = methodDescr[i][j];
1031 final int colon = desc.indexOf(':');
1032 String type = desc.substring(colon + 1);
1033
1034
1035 if (type.equals("B") || type.equals("H")) {
1036 type = "I";
1037 }
1038 final CPUTF8 value = (CPUTF8) methodSignatureLayout.getValue(result, type, cpBands.getConstantPool());
1039 methodAttributes[i][j].add(new SignatureAttribute(value));
1040 methodSignatureIndex++;
1041 }
1042 if (deprecatedLayout.matches(flag)) {
1043 methodAttributes[i][j].add(new DeprecatedAttribute());
1044 }
1045 }
1046 }
1047
1048
1049 int backwardsCallIndex = parseMethodMetadataBands(in, methodAttrCalls);
1050 final int limit = options.hasMethodFlagsHi() ? 62 : 31;
1051 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
1052 final int[] counts = new int[limit + 1];
1053 for (int i = 0; i < limit; i++) {
1054 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD);
1055 if (layout != null && !layout.isDefaultLayout()) {
1056 otherLayouts[i] = layout;
1057 counts[i] = SegmentUtils.countMatches(methodFlags, layout);
1058 }
1059 }
1060 final List<Attribute>[] otherAttributes = new List[limit + 1];
1061 for (int i = 0; i < counts.length; i++) {
1062 if (counts[i] > 0) {
1063 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
1064 otherAttributes[i] = bands.parseAttributes(in, counts[i]);
1065 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
1066 if (numBackwardsCallables > 0) {
1067 final int[] backwardsCalls = new int[numBackwardsCallables];
1068 System.arraycopy(methodAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
1069 bands.setBackwardsCalls(backwardsCalls);
1070 backwardsCallIndex += numBackwardsCallables;
1071 }
1072 }
1073 }
1074
1075
1076 for (int i = 0; i < methodAttributes.length; i++) {
1077 for (int j = 0; j < methodAttributes[i].length; j++) {
1078 final long flag = methodFlags[i][j];
1079 int othersAddedAtStart = 0;
1080 for (int k = 0; k < otherLayouts.length; k++) {
1081 if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) {
1082
1083 if (otherLayouts[k].getIndex() < 15) {
1084 methodAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0));
1085 } else {
1086 methodAttributes[i][j].add(otherAttributes[k].get(0));
1087 }
1088 otherAttributes[k].remove(0);
1089 }
1090 }
1091 }
1092 }
1093 }
1094
1095 private void parseMethodBands(final InputStream in) throws IOException, Pack200Exception {
1096 methodDescrInts = decodeBandInt("method_descr", in, Codec.MDELTA5, classMethodCount);
1097 methodDescr = getReferences(methodDescrInts, cpBands.getCpDescriptor());
1098 parseMethodAttrBands(in);
1099 }
1100
1101 private int parseMethodMetadataBands(final InputStream in, final int[] methodAttrCalls) throws Pack200Exception, IOException {
1102 int backwardsCallsUsed = 0;
1103 final String[] RxA = { "RVA", "RIA", "RVPA", "RIPA", "AD" };
1104 final int[] rxaCounts = { 0, 0, 0, 0, 0 };
1105
1106 final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
1107 final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
1108 final AttributeLayout rvpaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
1109 AttributeLayout.CONTEXT_METHOD);
1110 final AttributeLayout ripaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,
1111 AttributeLayout.CONTEXT_METHOD);
1112 final AttributeLayout adLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT, AttributeLayout.CONTEXT_METHOD);
1113 final AttributeLayout[] rxaLayouts = { rvaLayout, riaLayout, rvpaLayout, ripaLayout, adLayout };
1114
1115 Arrays.setAll(rxaCounts, i -> SegmentUtils.countMatches(methodFlags, rxaLayouts[i]));
1116 final int[] backwardsCalls = new int[5];
1117 int methodAttrIndex = 0;
1118 for (int i = 0; i < backwardsCalls.length; i++) {
1119 if (rxaCounts[i] > 0) {
1120 backwardsCallsUsed++;
1121 backwardsCalls[i] = methodAttrCalls[methodAttrIndex];
1122 methodAttrIndex++;
1123 } else {
1124 backwardsCalls[i] = 0;
1125 }
1126 }
1127 final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, rxaCounts, backwardsCalls, "method");
1128 final List<Attribute>[] attributeLists = new List[RxA.length];
1129 final int[] attributeListIndexes = new int[RxA.length];
1130 for (int i = 0; i < mbgs.length; i++) {
1131 attributeLists[i] = mbgs[i].getAttributes();
1132 attributeListIndexes[i] = 0;
1133 }
1134 for (int i = 0; i < methodFlags.length; i++) {
1135 for (int j = 0; j < methodFlags[i].length; j++) {
1136 for (int k = 0; k < rxaLayouts.length; k++) {
1137 if (rxaLayouts[k].matches(methodFlags[i][j])) {
1138 methodAttributes[i][j].add(attributeLists[k].get(attributeListIndexes[k]++));
1139 }
1140 }
1141 }
1142 }
1143 return backwardsCallsUsed;
1144 }
1145
1146
1147
1148
1149
1150
1151 @Override
1152 public void read(final InputStream in) throws IOException, Pack200Exception {
1153 final int classCount = header.getClassCount();
1154 classThisInts = decodeBandInt("class_this", in, Codec.DELTA5, classCount);
1155 classThis = getReferences(classThisInts, cpBands.getCpClass());
1156 classSuperInts = decodeBandInt("class_super", in, Codec.DELTA5, classCount);
1157 final int[] classInterfaceLengths = decodeBandInt("class_interface_count", in, Codec.DELTA5, classCount);
1158 classInterfacesInts = decodeBandInt("class_interface", in, Codec.DELTA5, classInterfaceLengths);
1159 classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5, classCount);
1160 classMethodCount = decodeBandInt("class_method_count", in, Codec.DELTA5, classCount);
1161 parseFieldBands(in);
1162 parseMethodBands(in);
1163 parseClassAttrBands(in);
1164 parseCodeBands(in);
1165
1166 }
1167
1168 @Override
1169 public void unpack() {
1170
1171 }
1172
1173 }