View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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   * Class Bands
48   */
49  public class ClassBands extends BandSet {
50  
51      private int[] classFieldCount;
52  
53      private long[] classFlags;
54  
55      private long[] classAccessFlags; // Access flags for writing to the class
56      // file
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      * @param segment TODO
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      * Returns null if all classes should use the default major and minor version or an array of integers containing the major version numberss to use for each
202      * class in the segment
203      *
204      * @return Class file major version numbers, or null if none specified
205      */
206     public int[] getClassVersionMajor() {
207         return classVersionMajor;
208     }
209 
210     /**
211      * Returns null if all classes should use the default major and minor version or an array of integers containing the minor version numberss to use for each
212      * class in the segment
213      *
214      * @return Class file minor version numbers, or null if none specified
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      * Gets an ArrayList of ArrayLists which hold the code attributes corresponding to all classes in order.
318      *
319      * If a class doesn't have any attributes, the corresponding element in this list will be an empty ArrayList.
320      *
321      * @return ArrayList
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         // Prepare empty attribute lists
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         // Parse non-predefined attribute bands
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         // Now process the attribute bands we have parsed
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                     // Remove package prefix
435                     String className = classThis[i].substring(classThis[i].lastIndexOf('/') + 1);
436                     className = className.substring(className.lastIndexOf('.') + 1);
437 
438                     // Remove mangled nested class names
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                     // Add .java to the end
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                 // Just create the tuples for now because the attributes are
473                 // decided at the end when creating class constant pools
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                         // Get from icBands
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                 // Fill in with defaults
516                 classVersionMajor[i] = defaultVersionMajor;
517                 classVersionMinor[i] = defaultVersionMinor;
518             }
519             // Non-predefined attributes
520             for (int j = 0; j < otherLayouts.length; j++) {
521                 if (otherLayouts[j] != null && otherLayouts[j].matches(flag)) {
522                     // Add the next attribute
523                     classAttributes[i].add(otherAttributes[j].get(0));
524                     otherAttributes[j].remove(0);
525                 }
526             }
527         }
528     }
529 
530     /**
531      * Parse the class metadata bands and return the number of backwards callables.
532      *
533      * @param in             TODO
534      * @param classAttrCalls TODO
535      * @return the number of backwards callables.
536      * @throws Pack200Exception If a Pack200 semantic error occurs.
537      * @throws IOException      If an I/O error occurs.
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         // Parse non-predefined attribute bands
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             // Non-predefined attributes
671             for (int j = 0; j < otherLayouts.length; j++) {
672                 if (otherLayouts[j] != null && otherLayouts[j].matches(codeFlags[i])) {
673                     // Add the next attribute
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         // Assign empty field attributes
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                     // we've got a value to read
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                     // we've got a signature attribute
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         // Parse non-predefined attribute bands
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         // Non-predefined attributes
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                         // Add the next attribute
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         // assign empty method attributes
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         // Parse method exceptions attributes
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         // Parse method signature attributes
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         // Add attributes to the attribute arrays
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                     // We've got a signature attribute
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                     // TODO Got to get better at this ... in any case, it should
1044                     // be for example KIB or KIH
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         // Parse non-predefined attribute bands
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         // Non-predefined attributes
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                         // Add the next attribute
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      * (non-Javadoc)
1158      *
1159      * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream)
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 }