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