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