ClassBands.java

  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. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.List;
  23. import java.util.stream.Collectors;
  24. import java.util.stream.Stream;

  25. import org.apache.commons.compress.harmony.pack200.Codec;
  26. import org.apache.commons.compress.harmony.pack200.Pack200Exception;
  27. import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
  28. import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
  29. import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
  30. import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
  31. import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
  32. import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantValueAttribute;
  33. import org.apache.commons.compress.harmony.unpack200.bytecode.DeprecatedAttribute;
  34. import org.apache.commons.compress.harmony.unpack200.bytecode.EnclosingMethodAttribute;
  35. import org.apache.commons.compress.harmony.unpack200.bytecode.ExceptionsAttribute;
  36. import org.apache.commons.compress.harmony.unpack200.bytecode.LineNumberTableAttribute;
  37. import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTableAttribute;
  38. import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTypeTableAttribute;
  39. import org.apache.commons.compress.harmony.unpack200.bytecode.SignatureAttribute;
  40. import org.apache.commons.compress.harmony.unpack200.bytecode.SourceFileAttribute;

  41. /**
  42.  * Class Bands
  43.  */
  44. public class ClassBands extends BandSet {

  45.     private int[] classFieldCount;

  46.     private long[] classFlags;

  47.     private long[] classAccessFlags; // Access flags for writing to the class
  48.     // file

  49.     private int[][] classInterfacesInts;

  50.     private int[] classMethodCount;

  51.     private int[] classSuperInts;

  52.     private String[] classThis;

  53.     private int[] classThisInts;

  54.     private ArrayList<Attribute>[] classAttributes;

  55.     private int[] classVersionMajor;

  56.     private int[] classVersionMinor;

  57.     private IcTuple[][] icLocal;

  58.     private List<Attribute>[] codeAttributes;

  59.     private int[] codeHandlerCount;

  60.     private int[] codeMaxNALocals;

  61.     private int[] codeMaxStack;

  62.     private ArrayList<Attribute>[][] fieldAttributes;

  63.     private String[][] fieldDescr;

  64.     private int[][] fieldDescrInts;

  65.     private long[][] fieldFlags;

  66.     private long[][] fieldAccessFlags;

  67.     private ArrayList<Attribute>[][] methodAttributes;

  68.     private String[][] methodDescr;

  69.     private int[][] methodDescrInts;

  70.     private long[][] methodFlags;

  71.     private long[][] methodAccessFlags;

  72.     private final AttributeLayoutMap attrMap;

  73.     private final CpBands cpBands;

  74.     private final SegmentOptions options;

  75.     private final int classCount;

  76.     private int[] methodAttrCalls;

  77.     private int[][] codeHandlerStartP;

  78.     private int[][] codeHandlerEndPO;

  79.     private int[][] codeHandlerCatchPO;

  80.     private int[][] codeHandlerClassRCN;

  81.     private boolean[] codeHasAttributes;

  82.     /**
  83.      * @param segment TODO
  84.      */
  85.     public ClassBands(final Segment segment) {
  86.         super(segment);
  87.         this.attrMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
  88.         this.cpBands = segment.getCpBands();
  89.         this.classCount = header.getClassCount();
  90.         this.options = header.getOptions();

  91.     }

  92.     private int getCallCount(final int[][] methodAttrIndexes, final long[][] flags, final int context) {
  93.         int callCount = 0;
  94.         for (final int[] element : methodAttrIndexes) {
  95.             for (final int index : element) {
  96.                 final AttributeLayout layout = attrMap.getAttributeLayout(index, context);
  97.                 callCount += layout.numBackwardsCallables();
  98.             }
  99.         }
  100.         int layoutsUsed = 0;
  101.         for (final long[] flag : flags) {
  102.             for (final long element : flag) {
  103.                 layoutsUsed |= element;
  104.             }
  105.         }
  106.         for (int i = 0; i < 26; i++) {
  107.             if ((layoutsUsed & 1 << i) != 0) {
  108.                 final AttributeLayout layout = attrMap.getAttributeLayout(i, context);
  109.                 callCount += layout.numBackwardsCallables();
  110.             }
  111.         }
  112.         return callCount;
  113.     }

  114.     public ArrayList<Attribute>[] getClassAttributes() {
  115.         return classAttributes;
  116.     }

  117.     public int[] getClassFieldCount() {
  118.         return classFieldCount;
  119.     }

  120.     public long[] getClassFlags() {
  121.         if (classAccessFlags == null) {
  122.             long mask = 0x7FFF;
  123.             for (int i = 0; i < 16; i++) {
  124.                 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS);
  125.                 if (layout != null && !layout.isDefaultLayout()) {
  126.                     mask &= ~(1 << i);
  127.                 }
  128.             }
  129.             classAccessFlags = new long[classFlags.length];
  130.             for (int i = 0; i < classFlags.length; i++) {
  131.                 classAccessFlags[i] = classFlags[i] & mask;
  132.             }
  133.         }
  134.         return classAccessFlags;
  135.     }

  136.     public int[][] getClassInterfacesInts() {
  137.         return classInterfacesInts;
  138.     }

  139.     public int[] getClassMethodCount() {
  140.         return classMethodCount;
  141.     }

  142.     public int[] getClassSuperInts() {
  143.         return classSuperInts;
  144.     }

  145.     public int[] getClassThisInts() {
  146.         return classThisInts;
  147.     }

  148.     /**
  149.      * 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
  150.      * class in the segment
  151.      *
  152.      * @return Class file major version numbers, or null if none specified
  153.      */
  154.     public int[] getClassVersionMajor() {
  155.         return classVersionMajor;
  156.     }

  157.     /**
  158.      * 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
  159.      * class in the segment
  160.      *
  161.      * @return Class file minor version numbers, or null if none specified
  162.      */
  163.     public int[] getClassVersionMinor() {
  164.         return classVersionMinor;
  165.     }

  166.     public int[][] getCodeHandlerCatchPO() {
  167.         return codeHandlerCatchPO;
  168.     }

  169.     public int[][] getCodeHandlerClassRCN() {
  170.         return codeHandlerClassRCN;
  171.     }

  172.     public int[] getCodeHandlerCount() {
  173.         return codeHandlerCount;
  174.     }

  175.     public int[][] getCodeHandlerEndPO() {
  176.         return codeHandlerEndPO;
  177.     }

  178.     public int[][] getCodeHandlerStartP() {
  179.         return codeHandlerStartP;
  180.     }

  181.     public boolean[] getCodeHasAttributes() {
  182.         return codeHasAttributes;
  183.     }

  184.     public int[] getCodeMaxNALocals() {
  185.         return codeMaxNALocals;
  186.     }

  187.     public int[] getCodeMaxStack() {
  188.         return codeMaxStack;
  189.     }

  190.     public ArrayList<Attribute>[][] getFieldAttributes() {
  191.         return fieldAttributes;
  192.     }

  193.     public int[][] getFieldDescrInts() {
  194.         return fieldDescrInts;
  195.     }

  196.     public long[][] getFieldFlags() {
  197.         if (fieldAccessFlags == null) {
  198.             long mask = 0x7FFF;
  199.             for (int i = 0; i < 16; i++) {
  200.                 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD);
  201.                 if (layout != null && !layout.isDefaultLayout()) {
  202.                     mask &= ~(1 << i);
  203.                 }
  204.             }
  205.             fieldAccessFlags = new long[fieldFlags.length][];
  206.             for (int i = 0; i < fieldFlags.length; i++) {
  207.                 fieldAccessFlags[i] = new long[fieldFlags[i].length];
  208.                 for (int j = 0; j < fieldFlags[i].length; j++) {
  209.                     fieldAccessFlags[i][j] = fieldFlags[i][j] & mask;
  210.                 }
  211.             }
  212.         }
  213.         return fieldAccessFlags;
  214.     }

  215.     public IcTuple[][] getIcLocal() {
  216.         return icLocal;
  217.     }

  218.     public ArrayList<Attribute>[][] getMethodAttributes() {
  219.         return methodAttributes;
  220.     }

  221.     public String[][] getMethodDescr() {
  222.         return methodDescr;
  223.     }

  224.     public int[][] getMethodDescrInts() {
  225.         return methodDescrInts;
  226.     }

  227.     public long[][] getMethodFlags() {
  228.         if (methodAccessFlags == null) {
  229.             long mask = 0x7FFF;
  230.             for (int i = 0; i < 16; i++) {
  231.                 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD);
  232.                 if (layout != null && !layout.isDefaultLayout()) {
  233.                     mask &= ~(1 << i);
  234.                 }
  235.             }
  236.             methodAccessFlags = new long[methodFlags.length][];
  237.             for (int i = 0; i < methodFlags.length; i++) {
  238.                 methodAccessFlags[i] = new long[methodFlags[i].length];
  239.                 for (int j = 0; j < methodFlags[i].length; j++) {
  240.                     methodAccessFlags[i][j] = methodFlags[i][j] & mask;
  241.                 }
  242.             }
  243.         }
  244.         return methodAccessFlags;
  245.     }

  246.     /**
  247.      * Gets an ArrayList of ArrayLists which hold the code attributes corresponding to all classes in order.
  248.      *
  249.      * If a class doesn't have any attributes, the corresponding element in this list will be an empty ArrayList.
  250.      *
  251.      * @return ArrayList
  252.      */
  253.     public ArrayList<List<Attribute>> getOrderedCodeAttributes() {
  254.         return Stream.of(codeAttributes).map(ArrayList::new).collect(Collectors.toCollection(ArrayList::new));
  255.     }

  256.     public long[] getRawClassFlags() {
  257.         return classFlags;
  258.     }

  259.     private void parseClassAttrBands(final InputStream in) throws IOException, Pack200Exception {
  260.         final String[] cpUTF8 = cpBands.getCpUTF8();
  261.         final String[] cpClass = cpBands.getCpClass();

  262.         // Prepare empty attribute lists
  263.         classAttributes = new ArrayList[classCount];
  264.         Arrays.setAll(classAttributes, i -> new ArrayList<>());

  265.         classFlags = parseFlags("class_flags", in, classCount, Codec.UNSIGNED5, options.hasClassFlagsHi());
  266.         final int classAttrCount = SegmentUtils.countBit16(classFlags);
  267.         final int[] classAttrCounts = decodeBandInt("class_attr_count", in, Codec.UNSIGNED5, classAttrCount);
  268.         final int[][] classAttrIndexes = decodeBandInt("class_attr_indexes", in, Codec.UNSIGNED5, classAttrCounts);
  269.         final int callCount = getCallCount(classAttrIndexes, new long[][] { classFlags }, AttributeLayout.CONTEXT_CLASS);
  270.         final int[] classAttrCalls = decodeBandInt("class_attr_calls", in, Codec.UNSIGNED5, callCount);

  271.         final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_CLASS);

  272.         final AttributeLayout sourceFileLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE, AttributeLayout.CONTEXT_CLASS);
  273.         final int sourceFileCount = SegmentUtils.countMatches(classFlags, sourceFileLayout);
  274.         final int[] classSourceFile = decodeBandInt("class_SourceFile_RUN", in, Codec.UNSIGNED5, sourceFileCount);

  275.         final AttributeLayout enclosingMethodLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ENCLOSING_METHOD, AttributeLayout.CONTEXT_CLASS);
  276.         final int enclosingMethodCount = SegmentUtils.countMatches(classFlags, enclosingMethodLayout);
  277.         final int[] enclosingMethodRC = decodeBandInt("class_EnclosingMethod_RC", in, Codec.UNSIGNED5, enclosingMethodCount);
  278.         final int[] enclosingMethodRDN = decodeBandInt("class_EnclosingMethod_RDN", in, Codec.UNSIGNED5, enclosingMethodCount);

  279.         final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_CLASS);
  280.         final int signatureCount = SegmentUtils.countMatches(classFlags, signatureLayout);
  281.         final int[] classSignature = decodeBandInt("class_Signature_RS", in, Codec.UNSIGNED5, signatureCount);

  282.         final int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls);

  283.         final AttributeLayout innerClassLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_INNER_CLASSES, AttributeLayout.CONTEXT_CLASS);
  284.         final int innerClassCount = SegmentUtils.countMatches(classFlags, innerClassLayout);
  285.         final int[] classInnerClassesN = decodeBandInt("class_InnerClasses_N", in, Codec.UNSIGNED5, innerClassCount);
  286.         final int[][] classInnerClassesRC = decodeBandInt("class_InnerClasses_RC", in, Codec.UNSIGNED5, classInnerClassesN);
  287.         final int[][] classInnerClassesF = decodeBandInt("class_InnerClasses_F", in, Codec.UNSIGNED5, classInnerClassesN);
  288.         int flagsCount = 0;
  289.         for (final int[] element : classInnerClassesF) {
  290.             for (final int element2 : element) {
  291.                 if (element2 != 0) {
  292.                     flagsCount++;
  293.                 }
  294.             }
  295.         }
  296.         final int[] classInnerClassesOuterRCN = decodeBandInt("class_InnerClasses_outer_RCN", in, Codec.UNSIGNED5, flagsCount);
  297.         final int[] classInnerClassesNameRUN = decodeBandInt("class_InnerClasses_name_RUN", in, Codec.UNSIGNED5, flagsCount);

  298.         final AttributeLayout versionLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION, AttributeLayout.CONTEXT_CLASS);
  299.         final int versionCount = SegmentUtils.countMatches(classFlags, versionLayout);
  300.         final int[] classFileVersionMinorH = decodeBandInt("class_file_version_minor_H", in, Codec.UNSIGNED5, versionCount);
  301.         final int[] classFileVersionMajorH = decodeBandInt("class_file_version_major_H", in, Codec.UNSIGNED5, versionCount);
  302.         if (versionCount > 0) {
  303.             classVersionMajor = new int[classCount];
  304.             classVersionMinor = new int[classCount];
  305.         }
  306.         final int defaultVersionMajor = header.getDefaultClassMajorVersion();
  307.         final int defaultVersionMinor = header.getDefaultClassMinorVersion();

  308.         // Parse non-predefined attribute bands
  309.         int backwardsCallIndex = backwardsCallsUsed;
  310.         final int limit = options.hasClassFlagsHi() ? 62 : 31;
  311.         final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
  312.         final int[] counts = new int[limit + 1];
  313.         final List<Attribute>[] otherAttributes = new List[limit + 1];
  314.         for (int i = 0; i < limit; i++) {
  315.             final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS);
  316.             if (layout != null && !layout.isDefaultLayout()) {
  317.                 otherLayouts[i] = layout;
  318.                 counts[i] = SegmentUtils.countMatches(classFlags, layout);
  319.             }
  320.         }
  321.         for (int i = 0; i < counts.length; i++) {
  322.             if (counts[i] > 0) {
  323.                 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
  324.                 otherAttributes[i] = bands.parseAttributes(in, counts[i]);
  325.                 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
  326.                 if (numBackwardsCallables > 0) {
  327.                     final int[] backwardsCalls = new int[numBackwardsCallables];
  328.                     System.arraycopy(classAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
  329.                     bands.setBackwardsCalls(backwardsCalls);
  330.                     backwardsCallIndex += numBackwardsCallables;
  331.                 }
  332.             }
  333.         }

  334.         // Now process the attribute bands we have parsed
  335.         int sourceFileIndex = 0;
  336.         int enclosingMethodIndex = 0;
  337.         int signatureIndex = 0;
  338.         int innerClassIndex = 0;
  339.         int innerClassC2NIndex = 0;
  340.         int versionIndex = 0;
  341.         icLocal = new IcTuple[classCount][];
  342.         for (int i = 0; i < classCount; i++) {
  343.             final long flag = classFlags[i];
  344.             if (deprecatedLayout.matches(classFlags[i])) {
  345.                 classAttributes[i].add(new DeprecatedAttribute());
  346.             }
  347.             if (sourceFileLayout.matches(flag)) {
  348.                 final long result = classSourceFile[sourceFileIndex];
  349.                 ClassFileEntry value = sourceFileLayout.getValue(result, cpBands.getConstantPool());
  350.                 if (value == null) {
  351.                     // Remove package prefix
  352.                     String className = classThis[i].substring(classThis[i].lastIndexOf('/') + 1);
  353.                     className = className.substring(className.lastIndexOf('.') + 1);

  354.                     // Remove mangled nested class names
  355.                     final char[] chars = className.toCharArray();
  356.                     int index = -1;
  357.                     for (int j = 0; j < chars.length; j++) {
  358.                         if (chars[j] <= 0x2D) {
  359.                             index = j;
  360.                             break;
  361.                         }
  362.                     }
  363.                     if (index > -1) {
  364.                         className = className.substring(0, index);
  365.                     }
  366.                     // Add .java to the end
  367.                     value = cpBands.cpUTF8Value(className + ".java", true);
  368.                 }
  369.                 classAttributes[i].add(new SourceFileAttribute((CPUTF8) value));
  370.                 sourceFileIndex++;
  371.             }
  372.             if (enclosingMethodLayout.matches(flag)) {
  373.                 final CPClass theClass = cpBands.cpClassValue(enclosingMethodRC[enclosingMethodIndex]);
  374.                 CPNameAndType theMethod = null;
  375.                 if (enclosingMethodRDN[enclosingMethodIndex] != 0) {
  376.                     theMethod = cpBands.cpNameAndTypeValue(enclosingMethodRDN[enclosingMethodIndex] - 1);
  377.                 }
  378.                 classAttributes[i].add(new EnclosingMethodAttribute(theClass, theMethod));
  379.                 enclosingMethodIndex++;
  380.             }
  381.             if (signatureLayout.matches(flag)) {
  382.                 final long result = classSignature[signatureIndex];
  383.                 final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, cpBands.getConstantPool());
  384.                 classAttributes[i].add(new SignatureAttribute(value));
  385.                 signatureIndex++;
  386.             }
  387.             if (innerClassLayout.matches(flag)) {
  388.                 // Just create the tuples for now because the attributes are
  389.                 // decided at the end when creating class constant pools
  390.                 icLocal[i] = new IcTuple[classInnerClassesN[innerClassIndex]];
  391.                 for (int j = 0; j < icLocal[i].length; j++) {
  392.                     final int icTupleCIndex = classInnerClassesRC[innerClassIndex][j];
  393.                     int icTupleC2Index = -1;
  394.                     int icTupleNIndex = -1;

  395.                     final String icTupleC = cpClass[icTupleCIndex];
  396.                     int icTupleF = classInnerClassesF[innerClassIndex][j];
  397.                     String icTupleC2 = null;
  398.                     String icTupleN = null;

  399.                     if (icTupleF != 0) {
  400.                         icTupleC2Index = classInnerClassesOuterRCN[innerClassC2NIndex];
  401.                         icTupleNIndex = classInnerClassesNameRUN[innerClassC2NIndex];
  402.                         icTupleC2 = cpClass[icTupleC2Index];
  403.                         icTupleN = cpUTF8[icTupleNIndex];
  404.                         innerClassC2NIndex++;
  405.                     } else {
  406.                         // Get from icBands
  407.                         final IcBands icBands = segment.getIcBands();
  408.                         final IcTuple[] icAll = icBands.getIcTuples();
  409.                         for (final IcTuple element : icAll) {
  410.                             if (element.getC().equals(icTupleC)) {
  411.                                 icTupleF = element.getF();
  412.                                 icTupleC2 = element.getC2();
  413.                                 icTupleN = element.getN();
  414.                                 break;
  415.                             }
  416.                         }
  417.                     }

  418.                     final IcTuple icTuple = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN, icTupleCIndex, icTupleC2Index, icTupleNIndex, j);
  419.                     icLocal[i][j] = icTuple;
  420.                 }
  421.                 innerClassIndex++;
  422.             }
  423.             if (versionLayout.matches(flag)) {
  424.                 classVersionMajor[i] = classFileVersionMajorH[versionIndex];
  425.                 classVersionMinor[i] = classFileVersionMinorH[versionIndex];
  426.                 versionIndex++;
  427.             } else if (classVersionMajor != null) {
  428.                 // Fill in with defaults
  429.                 classVersionMajor[i] = defaultVersionMajor;
  430.                 classVersionMinor[i] = defaultVersionMinor;
  431.             }
  432.             // Non-predefined attributes
  433.             for (int j = 0; j < otherLayouts.length; j++) {
  434.                 if (otherLayouts[j] != null && otherLayouts[j].matches(flag)) {
  435.                     // Add the next attribute
  436.                     classAttributes[i].add(otherAttributes[j].get(0));
  437.                     otherAttributes[j].remove(0);
  438.                 }
  439.             }
  440.         }
  441.     }

  442.     /**
  443.      * Parse the class metadata bands and return the number of backwards callables.
  444.      *
  445.      * @param in             TODO
  446.      * @param classAttrCalls TODO
  447.      * @return the number of backwards callables.
  448.      * @throws Pack200Exception TODO
  449.      * @throws IOException      If an I/O error occurs.
  450.      */
  451.     private int parseClassMetadataBands(final InputStream in, final int[] classAttrCalls) throws Pack200Exception, IOException {
  452.         int numBackwardsCalls = 0;
  453.         final String[] RxA = { "RVA", "RIA" };

  454.         final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS);
  455.         final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS);
  456.         final int rvaCount = SegmentUtils.countMatches(classFlags, rvaLayout);
  457.         final int riaCount = SegmentUtils.countMatches(classFlags, riaLayout);
  458.         final int[] RxACount = { rvaCount, riaCount };
  459.         final int[] backwardsCalls = { 0, 0 };
  460.         if (rvaCount > 0) {
  461.             numBackwardsCalls++;
  462.             backwardsCalls[0] = classAttrCalls[0];
  463.             if (riaCount > 0) {
  464.                 numBackwardsCalls++;
  465.                 backwardsCalls[1] = classAttrCalls[1];
  466.             }
  467.         } else if (riaCount > 0) {
  468.             numBackwardsCalls++;
  469.             backwardsCalls[1] = classAttrCalls[0];
  470.         }
  471.         final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, RxACount, backwardsCalls, "class");
  472.         final List<Attribute> rvaAttributes = mbgs[0].getAttributes();
  473.         final List<Attribute> riaAttributes = mbgs[1].getAttributes();
  474.         int rvaAttributesIndex = 0;
  475.         int riaAttributesIndex = 0;
  476.         for (int i = 0; i < classFlags.length; i++) {
  477.             if (rvaLayout.matches(classFlags[i])) {
  478.                 classAttributes[i].add(rvaAttributes.get(rvaAttributesIndex++));
  479.             }
  480.             if (riaLayout.matches(classFlags[i])) {
  481.                 classAttributes[i].add(riaAttributes.get(riaAttributesIndex++));
  482.             }
  483.         }
  484.         return numBackwardsCalls;
  485.     }

  486.     private void parseCodeAttrBands(final InputStream in, final int codeFlagsCount) throws IOException, Pack200Exception {
  487.         final long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount, Codec.UNSIGNED5, segment.getSegmentHeader().getOptions().hasCodeFlagsHi());
  488.         final int codeAttrCount = SegmentUtils.countBit16(codeFlags);
  489.         final int[] codeAttrCounts = decodeBandInt("code_attr_count", in, Codec.UNSIGNED5, codeAttrCount);
  490.         final int[][] codeAttrIndexes = decodeBandInt("code_attr_indexes", in, Codec.UNSIGNED5, codeAttrCounts);
  491.         int callCount = 0;
  492.         for (final int[] element : codeAttrIndexes) {
  493.             for (final int index : element) {
  494.                 final AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_CODE);
  495.                 callCount += layout.numBackwardsCallables();
  496.             }
  497.         }
  498.         final int[] codeAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5, callCount);

  499.         final AttributeLayout lineNumberTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE);
  500.         final int lineNumberTableCount = SegmentUtils.countMatches(codeFlags, lineNumberTableLayout);
  501.         final int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in, Codec.UNSIGNED5, lineNumberTableCount);
  502.         final int[][] lineNumberTableBciP = decodeBandInt("code_LineNumberTable_bci_P", in, Codec.BCI5, lineNumberTableN);
  503.         final int[][] lineNumberTableLine = decodeBandInt("code_LineNumberTable_line", in, Codec.UNSIGNED5, lineNumberTableN);

  504.         final AttributeLayout localVariableTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE,
  505.                 AttributeLayout.CONTEXT_CODE);
  506.         final AttributeLayout localVariableTypeTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE,
  507.                 AttributeLayout.CONTEXT_CODE);

  508.         final int lengthLocalVariableNBand = SegmentUtils.countMatches(codeFlags, localVariableTableLayout);
  509.         final int[] localVariableTableN = decodeBandInt("code_LocalVariableTable_N", in, Codec.UNSIGNED5, lengthLocalVariableNBand);
  510.         final int[][] localVariableTableBciP = decodeBandInt("code_LocalVariableTable_bci_P", in, Codec.BCI5, localVariableTableN);
  511.         final int[][] localVariableTableSpanO = decodeBandInt("code_LocalVariableTable_span_O", in, Codec.BRANCH5, localVariableTableN);
  512.         final CPUTF8[][] localVariableTableNameRU = parseCPUTF8References("code_LocalVariableTable_name_RU", in, Codec.UNSIGNED5, localVariableTableN);
  513.         final CPUTF8[][] localVariableTableTypeRS = parseCPSignatureReferences("code_LocalVariableTable_type_RS", in, Codec.UNSIGNED5, localVariableTableN);
  514.         final int[][] localVariableTableSlot = decodeBandInt("code_LocalVariableTable_slot", in, Codec.UNSIGNED5, localVariableTableN);

  515.         final int lengthLocalVariableTypeTableNBand = SegmentUtils.countMatches(codeFlags, localVariableTypeTableLayout);
  516.         final int[] localVariableTypeTableN = decodeBandInt("code_LocalVariableTypeTable_N", in, Codec.UNSIGNED5, lengthLocalVariableTypeTableNBand);
  517.         final int[][] localVariableTypeTableBciP = decodeBandInt("code_LocalVariableTypeTable_bci_P", in, Codec.BCI5, localVariableTypeTableN);
  518.         final int[][] localVariableTypeTableSpanO = decodeBandInt("code_LocalVariableTypeTable_span_O", in, Codec.BRANCH5, localVariableTypeTableN);
  519.         final CPUTF8[][] localVariableTypeTableNameRU = parseCPUTF8References("code_LocalVariableTypeTable_name_RU", in, Codec.UNSIGNED5,
  520.                 localVariableTypeTableN);
  521.         final CPUTF8[][] localVariableTypeTableTypeRS = parseCPSignatureReferences("code_LocalVariableTypeTable_type_RS", in, Codec.UNSIGNED5,
  522.                 localVariableTypeTableN);
  523.         final int[][] localVariableTypeTableSlot = decodeBandInt("code_LocalVariableTypeTable_slot", in, Codec.UNSIGNED5, localVariableTypeTableN);

  524.         // Parse non-predefined attribute bands
  525.         int backwardsCallIndex = 0;
  526.         final int limit = options.hasCodeFlagsHi() ? 62 : 31;
  527.         final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
  528.         final int[] counts = new int[limit + 1];
  529.         final List<Attribute>[] otherAttributes = new List[limit + 1];
  530.         for (int i = 0; i < limit; i++) {
  531.             final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CODE);
  532.             if (layout != null && !layout.isDefaultLayout()) {
  533.                 otherLayouts[i] = layout;
  534.                 counts[i] = SegmentUtils.countMatches(codeFlags, layout);
  535.             }
  536.         }
  537.         for (int i = 0; i < counts.length; i++) {
  538.             if (counts[i] > 0) {
  539.                 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
  540.                 otherAttributes[i] = bands.parseAttributes(in, counts[i]);
  541.                 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
  542.                 if (numBackwardsCallables > 0) {
  543.                     final int[] backwardsCalls = new int[numBackwardsCallables];
  544.                     System.arraycopy(codeAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
  545.                     bands.setBackwardsCalls(backwardsCalls);
  546.                     backwardsCallIndex += numBackwardsCallables;
  547.                 }
  548.             }
  549.         }

  550.         int lineNumberIndex = 0;
  551.         int lvtIndex = 0;
  552.         int lvttIndex = 0;
  553.         for (int i = 0; i < codeFlagsCount; i++) {
  554.             if (lineNumberTableLayout.matches(codeFlags[i])) {
  555.                 final LineNumberTableAttribute lnta = new LineNumberTableAttribute(lineNumberTableN[lineNumberIndex], lineNumberTableBciP[lineNumberIndex],
  556.                         lineNumberTableLine[lineNumberIndex]);
  557.                 lineNumberIndex++;
  558.                 codeAttributes[i].add(lnta);
  559.             }
  560.             if (localVariableTableLayout.matches(codeFlags[i])) {
  561.                 final LocalVariableTableAttribute lvta = new LocalVariableTableAttribute(localVariableTableN[lvtIndex], localVariableTableBciP[lvtIndex],
  562.                         localVariableTableSpanO[lvtIndex], localVariableTableNameRU[lvtIndex], localVariableTableTypeRS[lvtIndex],
  563.                         localVariableTableSlot[lvtIndex]);
  564.                 lvtIndex++;
  565.                 codeAttributes[i].add(lvta);
  566.             }
  567.             if (localVariableTypeTableLayout.matches(codeFlags[i])) {
  568.                 final LocalVariableTypeTableAttribute lvtta = new LocalVariableTypeTableAttribute(localVariableTypeTableN[lvttIndex],
  569.                         localVariableTypeTableBciP[lvttIndex], localVariableTypeTableSpanO[lvttIndex], localVariableTypeTableNameRU[lvttIndex],
  570.                         localVariableTypeTableTypeRS[lvttIndex], localVariableTypeTableSlot[lvttIndex]);
  571.                 lvttIndex++;
  572.                 codeAttributes[i].add(lvtta);
  573.             }
  574.             // Non-predefined attributes
  575.             for (int j = 0; j < otherLayouts.length; j++) {
  576.                 if (otherLayouts[j] != null && otherLayouts[j].matches(codeFlags[i])) {
  577.                     // Add the next attribute
  578.                     codeAttributes[i].add(otherAttributes[j].get(0));
  579.                     otherAttributes[j].remove(0);
  580.                 }
  581.             }
  582.         }

  583.     }

  584.     private void parseCodeBands(final InputStream in) throws Pack200Exception, IOException {
  585.         final AttributeLayout layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD);

  586.         final int codeCount = SegmentUtils.countMatches(methodFlags, layout);
  587.         final int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1, codeCount);

  588.         final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags();
  589.         if (!allCodeHasFlags) {
  590.             codeHasAttributes = new boolean[codeCount];
  591.         }
  592.         int codeSpecialHeader = 0;
  593.         for (int i = 0; i < codeCount; i++) {
  594.             if (codeHeaders[i] == 0) {
  595.                 codeSpecialHeader++;
  596.                 if (!allCodeHasFlags) {
  597.                     codeHasAttributes[i] = true;
  598.                 }
  599.             }
  600.         }
  601.         final int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in, Codec.UNSIGNED5, codeSpecialHeader);
  602.         final int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in, Codec.UNSIGNED5, codeSpecialHeader);
  603.         final int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count", in, Codec.UNSIGNED5, codeSpecialHeader);

  604.         codeMaxStack = new int[codeCount];
  605.         codeMaxNALocals = new int[codeCount];
  606.         codeHandlerCount = new int[codeCount];
  607.         int special = 0;
  608.         for (int i = 0; i < codeCount; i++) {
  609.             final int header = 0xff & codeHeaders[i];
  610.             if (header < 0) {
  611.                 throw new IllegalStateException("Shouldn't get here");
  612.             }
  613.             if (header == 0) {
  614.                 codeMaxStack[i] = codeMaxStackSpecials[special];
  615.                 codeMaxNALocals[i] = codeMaxNALocalsSpecials[special];
  616.                 codeHandlerCount[i] = codeHandlerCountSpecials[special];
  617.                 special++;
  618.             } else if (header <= 144) {
  619.                 codeMaxStack[i] = (header - 1) % 12;
  620.                 codeMaxNALocals[i] = (header - 1) / 12;
  621.                 codeHandlerCount[i] = 0;
  622.             } else if (header <= 208) {
  623.                 codeMaxStack[i] = (header - 145) % 8;
  624.                 codeMaxNALocals[i] = (header - 145) / 8;
  625.                 codeHandlerCount[i] = 1;
  626.             } else if (header <= 255) {
  627.                 codeMaxStack[i] = (header - 209) % 7;
  628.                 codeMaxNALocals[i] = (header - 209) / 7;
  629.                 codeHandlerCount[i] = 2;
  630.             } else {
  631.                 throw new IllegalStateException("Shouldn't get here either");
  632.             }
  633.         }
  634.         codeHandlerStartP = decodeBandInt("code_handler_start_P", in, Codec.BCI5, codeHandlerCount);
  635.         codeHandlerEndPO = decodeBandInt("code_handler_end_PO", in, Codec.BRANCH5, codeHandlerCount);
  636.         codeHandlerCatchPO = decodeBandInt("code_handler_catch_PO", in, Codec.BRANCH5, codeHandlerCount);
  637.         codeHandlerClassRCN = decodeBandInt("code_handler_class_RCN", in, Codec.UNSIGNED5, codeHandlerCount);

  638.         final int codeFlagsCount = allCodeHasFlags ? codeCount : codeSpecialHeader;

  639.         codeAttributes = new List[codeFlagsCount];
  640.         Arrays.setAll(codeAttributes, i -> new ArrayList<>());
  641.         parseCodeAttrBands(in, codeFlagsCount);
  642.     }

  643.     private void parseFieldAttrBands(final InputStream in) throws IOException, Pack200Exception {
  644.         fieldFlags = parseFlags("field_flags", in, classFieldCount, Codec.UNSIGNED5, options.hasFieldFlagsHi());
  645.         final int fieldAttrCount = SegmentUtils.countBit16(fieldFlags);
  646.         final int[] fieldAttrCounts = decodeBandInt("field_attr_count", in, Codec.UNSIGNED5, fieldAttrCount);
  647.         final int[][] fieldAttrIndexes = decodeBandInt("field_attr_indexes", in, Codec.UNSIGNED5, fieldAttrCounts);
  648.         final int callCount = getCallCount(fieldAttrIndexes, fieldFlags, AttributeLayout.CONTEXT_FIELD);
  649.         final int[] fieldAttrCalls = decodeBandInt("field_attr_calls", in, Codec.UNSIGNED5, callCount);

  650.         // Assign empty field attributes
  651.         fieldAttributes = new ArrayList[classCount][];
  652.         for (int i = 0; i < classCount; i++) {
  653.             fieldAttributes[i] = new ArrayList[fieldFlags[i].length];
  654.             for (int j = 0; j < fieldFlags[i].length; j++) {
  655.                 fieldAttributes[i][j] = new ArrayList<>();
  656.             }
  657.         }

  658.         final AttributeLayout constantValueLayout = attrMap.getAttributeLayout("ConstantValue", AttributeLayout.CONTEXT_FIELD);
  659.         final int constantCount = SegmentUtils.countMatches(fieldFlags, constantValueLayout);
  660.         final int[] field_constantValue_KQ = decodeBandInt("field_ConstantValue_KQ", in, Codec.UNSIGNED5, constantCount);
  661.         int constantValueIndex = 0;

  662.         final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_FIELD);
  663.         final int signatureCount = SegmentUtils.countMatches(fieldFlags, signatureLayout);
  664.         final int[] fieldSignatureRS = decodeBandInt("field_Signature_RS", in, Codec.UNSIGNED5, signatureCount);
  665.         int signatureIndex = 0;

  666.         final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_FIELD);

  667.         for (int i = 0; i < classCount; i++) {
  668.             for (int j = 0; j < fieldFlags[i].length; j++) {
  669.                 final long flag = fieldFlags[i][j];
  670.                 if (deprecatedLayout.matches(flag)) {
  671.                     fieldAttributes[i][j].add(new DeprecatedAttribute());
  672.                 }
  673.                 if (constantValueLayout.matches(flag)) {
  674.                     // we've got a value to read
  675.                     final long result = field_constantValue_KQ[constantValueIndex];
  676.                     final String desc = fieldDescr[i][j];
  677.                     final int colon = desc.indexOf(':');
  678.                     String type = desc.substring(colon + 1);
  679.                     if (type.equals("B") || type.equals("S") || type.equals("C") || type.equals("Z")) {
  680.                         type = "I";
  681.                     }
  682.                     final ClassFileEntry value = constantValueLayout.getValue(result, type, cpBands.getConstantPool());
  683.                     fieldAttributes[i][j].add(new ConstantValueAttribute(value));
  684.                     constantValueIndex++;
  685.                 }
  686.                 if (signatureLayout.matches(flag)) {
  687.                     // we've got a signature attribute
  688.                     final long result = fieldSignatureRS[signatureIndex];
  689.                     final String desc = fieldDescr[i][j];
  690.                     final int colon = desc.indexOf(':');
  691.                     final String type = desc.substring(colon + 1);
  692.                     final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, type, cpBands.getConstantPool());
  693.                     fieldAttributes[i][j].add(new SignatureAttribute(value));
  694.                     signatureIndex++;
  695.                 }
  696.             }
  697.         }

  698.         // Parse non-predefined attribute bands
  699.         int backwardsCallIndex = parseFieldMetadataBands(in, fieldAttrCalls);
  700.         final int limit = options.hasFieldFlagsHi() ? 62 : 31;
  701.         final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
  702.         final int[] counts = new int[limit + 1];
  703.         final List<Attribute>[] otherAttributes = new List[limit + 1];
  704.         for (int i = 0; i < limit; i++) {
  705.             final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD);
  706.             if (layout != null && !layout.isDefaultLayout()) {
  707.                 otherLayouts[i] = layout;
  708.                 counts[i] = SegmentUtils.countMatches(fieldFlags, layout);
  709.             }
  710.         }
  711.         for (int i = 0; i < counts.length; i++) {
  712.             if (counts[i] > 0) {
  713.                 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
  714.                 otherAttributes[i] = bands.parseAttributes(in, counts[i]);
  715.                 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
  716.                 if (numBackwardsCallables > 0) {
  717.                     final int[] backwardsCalls = new int[numBackwardsCallables];
  718.                     System.arraycopy(fieldAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
  719.                     bands.setBackwardsCalls(backwardsCalls);
  720.                     backwardsCallIndex += numBackwardsCallables;
  721.                 }
  722.             }
  723.         }

  724.         // Non-predefined attributes
  725.         for (int i = 0; i < classCount; i++) {
  726.             for (int j = 0; j < fieldFlags[i].length; j++) {
  727.                 final long flag = fieldFlags[i][j];
  728.                 int othersAddedAtStart = 0;
  729.                 for (int k = 0; k < otherLayouts.length; k++) {
  730.                     if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) {
  731.                         // Add the next attribute
  732.                         if (otherLayouts[k].getIndex() < 15) {
  733.                             fieldAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0));
  734.                         } else {
  735.                             fieldAttributes[i][j].add(otherAttributes[k].get(0));
  736.                         }
  737.                         otherAttributes[k].remove(0);
  738.                     }
  739.                 }
  740.             }
  741.         }
  742.     }

  743.     private void parseFieldBands(final InputStream in) throws IOException, Pack200Exception {
  744.         fieldDescrInts = decodeBandInt("field_descr", in, Codec.DELTA5, classFieldCount);
  745.         fieldDescr = getReferences(fieldDescrInts, cpBands.getCpDescriptor());
  746.         parseFieldAttrBands(in);
  747.     }

  748.     private int parseFieldMetadataBands(final InputStream in, final int[] fieldAttrCalls) throws Pack200Exception, IOException {
  749.         int backwardsCallsUsed = 0;
  750.         final String[] RxA = { "RVA", "RIA" };

  751.         final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD);
  752.         final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD);

  753.         final int rvaCount = SegmentUtils.countMatches(fieldFlags, rvaLayout);
  754.         final int riaCount = SegmentUtils.countMatches(fieldFlags, riaLayout);
  755.         final int[] RxACount = { rvaCount, riaCount };
  756.         final int[] backwardsCalls = { 0, 0 };
  757.         if (rvaCount > 0) {
  758.             backwardsCalls[0] = fieldAttrCalls[0];
  759.             backwardsCallsUsed++;
  760.             if (riaCount > 0) {
  761.                 backwardsCalls[1] = fieldAttrCalls[1];
  762.                 backwardsCallsUsed++;
  763.             }
  764.         } else if (riaCount > 0) {
  765.             backwardsCalls[1] = fieldAttrCalls[0];
  766.             backwardsCallsUsed++;
  767.         }
  768.         final MetadataBandGroup[] mb = parseMetadata(in, RxA, RxACount, backwardsCalls, "field");
  769.         final List<Attribute> rvaAttributes = mb[0].getAttributes();
  770.         final List<Attribute> riaAttributes = mb[1].getAttributes();
  771.         int rvaAttributesIndex = 0;
  772.         int riaAttributesIndex = 0;
  773.         for (int i = 0; i < fieldFlags.length; i++) {
  774.             for (int j = 0; j < fieldFlags[i].length; j++) {
  775.                 if (rvaLayout.matches(fieldFlags[i][j])) {
  776.                     fieldAttributes[i][j].add(rvaAttributes.get(rvaAttributesIndex++));
  777.                 }
  778.                 if (riaLayout.matches(fieldFlags[i][j])) {
  779.                     fieldAttributes[i][j].add(riaAttributes.get(riaAttributesIndex++));
  780.                 }
  781.             }
  782.         }
  783.         return backwardsCallsUsed;
  784.     }

  785.     private MetadataBandGroup[] parseMetadata(final InputStream in, final String[] RxA, final int[] RxACount, final int[] backwardsCallCounts,
  786.             final String contextName) throws IOException, Pack200Exception {
  787.         final MetadataBandGroup[] mbg = new MetadataBandGroup[RxA.length];
  788.         for (int i = 0; i < RxA.length; i++) {
  789.             mbg[i] = new MetadataBandGroup(RxA[i], cpBands);
  790.             final String rxa = RxA[i];
  791.             if (rxa.indexOf('P') >= 0) {
  792.                 mbg[i].param_NB = decodeBandInt(contextName + "_" + rxa + "_param_NB", in, Codec.BYTE1, RxACount[i]);
  793.             }
  794.             int pairCount = 0;
  795.             if (!rxa.equals("AD")) {
  796.                 mbg[i].anno_N = decodeBandInt(contextName + "_" + rxa + "_anno_N", in, Codec.UNSIGNED5, RxACount[i]);
  797.                 mbg[i].type_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_type_RS", in, Codec.UNSIGNED5, mbg[i].anno_N);
  798.                 mbg[i].pair_N = decodeBandInt(contextName + "_" + rxa + "_pair_N", in, Codec.UNSIGNED5, mbg[i].anno_N);
  799.                 for (final int[] element : mbg[i].pair_N) {
  800.                     for (final int element2 : element) {
  801.                         pairCount += element2;
  802.                     }
  803.                 }

  804.                 mbg[i].name_RU = parseCPUTF8References(contextName + "_" + rxa + "_name_RU", in, Codec.UNSIGNED5, pairCount);
  805.             } else {
  806.                 pairCount = RxACount[i];
  807.             }
  808.             mbg[i].T = decodeBandInt(contextName + "_" + rxa + "_T", in, Codec.BYTE1, pairCount + backwardsCallCounts[i]);
  809.             int ICount = 0, DCount = 0, FCount = 0, JCount = 0, cCount = 0, eCount = 0, sCount = 0, arrayCount = 0, atCount = 0;
  810.             for (final int element : mbg[i].T) {
  811.                 final char c = (char) element;
  812.                 switch (c) {
  813.                 case 'B':
  814.                 case 'C':
  815.                 case 'I':
  816.                 case 'S':
  817.                 case 'Z':
  818.                     ICount++;
  819.                     break;
  820.                 case 'D':
  821.                     DCount++;
  822.                     break;
  823.                 case 'F':
  824.                     FCount++;
  825.                     break;
  826.                 case 'J':
  827.                     JCount++;
  828.                     break;
  829.                 case 'c':
  830.                     cCount++;
  831.                     break;
  832.                 case 'e':
  833.                     eCount++;
  834.                     break;
  835.                 case 's':
  836.                     sCount++;
  837.                     break;
  838.                 case '[':
  839.                     arrayCount++;
  840.                     break;
  841.                 case '@':
  842.                     atCount++;
  843.                     break;
  844.                 }
  845.             }
  846.             mbg[i].caseI_KI = parseCPIntReferences(contextName + "_" + rxa + "_caseI_KI", in, Codec.UNSIGNED5, ICount);
  847.             mbg[i].caseD_KD = parseCPDoubleReferences(contextName + "_" + rxa + "_caseD_KD", in, Codec.UNSIGNED5, DCount);
  848.             mbg[i].caseF_KF = parseCPFloatReferences(contextName + "_" + rxa + "_caseF_KF", in, Codec.UNSIGNED5, FCount);
  849.             mbg[i].caseJ_KJ = parseCPLongReferences(contextName + "_" + rxa + "_caseJ_KJ", in, Codec.UNSIGNED5, JCount);
  850.             mbg[i].casec_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_casec_RS", in, Codec.UNSIGNED5, cCount);
  851.             mbg[i].caseet_RS = parseReferences(contextName + "_" + rxa + "_caseet_RS", in, Codec.UNSIGNED5, eCount, cpBands.getCpSignature());
  852.             mbg[i].caseec_RU = parseReferences(contextName + "_" + rxa + "_caseec_RU", in, Codec.UNSIGNED5, eCount, cpBands.getCpUTF8());
  853.             mbg[i].cases_RU = parseCPUTF8References(contextName + "_" + rxa + "_cases_RU", in, Codec.UNSIGNED5, sCount);
  854.             mbg[i].casearray_N = decodeBandInt(contextName + "_" + rxa + "_casearray_N", in, Codec.UNSIGNED5, arrayCount);
  855.             mbg[i].nesttype_RS = parseCPUTF8References(contextName + "_" + rxa + "_nesttype_RS", in, Codec.UNSIGNED5, atCount);
  856.             mbg[i].nestpair_N = decodeBandInt(contextName + "_" + rxa + "_nestpair_N", in, Codec.UNSIGNED5, atCount);
  857.             int nestPairCount = 0;
  858.             for (final int element : mbg[i].nestpair_N) {
  859.                 nestPairCount += element;
  860.             }
  861.             mbg[i].nestname_RU = parseCPUTF8References(contextName + "_" + rxa + "_nestname_RU", in, Codec.UNSIGNED5, nestPairCount);
  862.         }
  863.         return mbg;
  864.     }

  865.     private void parseMethodAttrBands(final InputStream in) throws IOException, Pack200Exception {
  866.         methodFlags = parseFlags("method_flags", in, classMethodCount, Codec.UNSIGNED5, options.hasMethodFlagsHi());
  867.         final int methodAttrCount = SegmentUtils.countBit16(methodFlags);
  868.         final int[] methodAttrCounts = decodeBandInt("method_attr_count", in, Codec.UNSIGNED5, methodAttrCount);
  869.         final int[][] methodAttrIndexes = decodeBandInt("method_attr_indexes", in, Codec.UNSIGNED5, methodAttrCounts);
  870.         final int callCount = getCallCount(methodAttrIndexes, methodFlags, AttributeLayout.CONTEXT_METHOD);
  871.         methodAttrCalls = decodeBandInt("method_attr_calls", in, Codec.UNSIGNED5, callCount);

  872.         // assign empty method attributes
  873.         methodAttributes = new ArrayList[classCount][];
  874.         for (int i = 0; i < classCount; i++) {
  875.             methodAttributes[i] = new ArrayList[methodFlags[i].length];
  876.             for (int j = 0; j < methodFlags[i].length; j++) {
  877.                 methodAttributes[i][j] = new ArrayList<>();
  878.             }
  879.         }

  880.         // Parse method exceptions attributes
  881.         final AttributeLayout methodExceptionsLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS, AttributeLayout.CONTEXT_METHOD);
  882.         final int count = SegmentUtils.countMatches(methodFlags, methodExceptionsLayout);
  883.         final int[] numExceptions = decodeBandInt("method_Exceptions_n", in, Codec.UNSIGNED5, count);
  884.         final int[][] methodExceptionsRS = decodeBandInt("method_Exceptions_RC", in, Codec.UNSIGNED5, numExceptions);

  885.         // Parse method signature attributes
  886.         final AttributeLayout methodSignatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_METHOD);
  887.         final int count1 = SegmentUtils.countMatches(methodFlags, methodSignatureLayout);
  888.         final int[] methodSignatureRS = decodeBandInt("method_signature_RS", in, Codec.UNSIGNED5, count1);

  889.         final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_METHOD);

  890.         // Add attributes to the attribute arrays
  891.         int methodExceptionsIndex = 0;
  892.         int methodSignatureIndex = 0;
  893.         for (int i = 0; i < methodAttributes.length; i++) {
  894.             for (int j = 0; j < methodAttributes[i].length; j++) {
  895.                 final long flag = methodFlags[i][j];
  896.                 if (methodExceptionsLayout.matches(flag)) {
  897.                     final int n = numExceptions[methodExceptionsIndex];
  898.                     final int[] exceptions = methodExceptionsRS[methodExceptionsIndex];
  899.                     final CPClass[] exceptionClasses = new CPClass[n];
  900.                     for (int k = 0; k < n; k++) {
  901.                         exceptionClasses[k] = cpBands.cpClassValue(exceptions[k]);
  902.                     }
  903.                     methodAttributes[i][j].add(new ExceptionsAttribute(exceptionClasses));
  904.                     methodExceptionsIndex++;
  905.                 }
  906.                 if (methodSignatureLayout.matches(flag)) {
  907.                     // We've got a signature attribute
  908.                     final long result = methodSignatureRS[methodSignatureIndex];
  909.                     final String desc = methodDescr[i][j];
  910.                     final int colon = desc.indexOf(':');
  911.                     String type = desc.substring(colon + 1);
  912.                     // TODO Got to get better at this ... in any case, it should
  913.                     // be e.g. KIB or KIH
  914.                     if (type.equals("B") || type.equals("H")) {
  915.                         type = "I";
  916.                     }
  917.                     final CPUTF8 value = (CPUTF8) methodSignatureLayout.getValue(result, type, cpBands.getConstantPool());
  918.                     methodAttributes[i][j].add(new SignatureAttribute(value));
  919.                     methodSignatureIndex++;
  920.                 }
  921.                 if (deprecatedLayout.matches(flag)) {
  922.                     methodAttributes[i][j].add(new DeprecatedAttribute());
  923.                 }
  924.             }
  925.         }

  926.         // Parse non-predefined attribute bands
  927.         int backwardsCallIndex = parseMethodMetadataBands(in, methodAttrCalls);
  928.         final int limit = options.hasMethodFlagsHi() ? 62 : 31;
  929.         final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
  930.         final int[] counts = new int[limit + 1];
  931.         for (int i = 0; i < limit; i++) {
  932.             final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD);
  933.             if (layout != null && !layout.isDefaultLayout()) {
  934.                 otherLayouts[i] = layout;
  935.                 counts[i] = SegmentUtils.countMatches(methodFlags, layout);
  936.             }
  937.         }
  938.         final List<Attribute>[] otherAttributes = new List[limit + 1];
  939.         for (int i = 0; i < counts.length; i++) {
  940.             if (counts[i] > 0) {
  941.                 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
  942.                 otherAttributes[i] = bands.parseAttributes(in, counts[i]);
  943.                 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
  944.                 if (numBackwardsCallables > 0) {
  945.                     final int[] backwardsCalls = new int[numBackwardsCallables];
  946.                     System.arraycopy(methodAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
  947.                     bands.setBackwardsCalls(backwardsCalls);
  948.                     backwardsCallIndex += numBackwardsCallables;
  949.                 }
  950.             }
  951.         }

  952.         // Non-predefined attributes
  953.         for (int i = 0; i < methodAttributes.length; i++) {
  954.             for (int j = 0; j < methodAttributes[i].length; j++) {
  955.                 final long flag = methodFlags[i][j];
  956.                 int othersAddedAtStart = 0;
  957.                 for (int k = 0; k < otherLayouts.length; k++) {
  958.                     if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) {
  959.                         // Add the next attribute
  960.                         if (otherLayouts[k].getIndex() < 15) {
  961.                             methodAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0));
  962.                         } else {
  963.                             methodAttributes[i][j].add(otherAttributes[k].get(0));
  964.                         }
  965.                         otherAttributes[k].remove(0);
  966.                     }
  967.                 }
  968.             }
  969.         }
  970.     }

  971.     private void parseMethodBands(final InputStream in) throws IOException, Pack200Exception {
  972.         methodDescrInts = decodeBandInt("method_descr", in, Codec.MDELTA5, classMethodCount);
  973.         methodDescr = getReferences(methodDescrInts, cpBands.getCpDescriptor());
  974.         parseMethodAttrBands(in);
  975.     }

  976.     private int parseMethodMetadataBands(final InputStream in, final int[] methodAttrCalls) throws Pack200Exception, IOException {
  977.         int backwardsCallsUsed = 0;
  978.         final String[] RxA = { "RVA", "RIA", "RVPA", "RIPA", "AD" };
  979.         final int[] rxaCounts = { 0, 0, 0, 0, 0 };

  980.         final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
  981.         final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
  982.         final AttributeLayout rvpaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
  983.                 AttributeLayout.CONTEXT_METHOD);
  984.         final AttributeLayout ripaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,
  985.                 AttributeLayout.CONTEXT_METHOD);
  986.         final AttributeLayout adLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT, AttributeLayout.CONTEXT_METHOD);
  987.         final AttributeLayout[] rxaLayouts = { rvaLayout, riaLayout, rvpaLayout, ripaLayout, adLayout };

  988.         Arrays.setAll(rxaCounts, i -> SegmentUtils.countMatches(methodFlags, rxaLayouts[i]));
  989.         final int[] backwardsCalls = new int[5];
  990.         int methodAttrIndex = 0;
  991.         for (int i = 0; i < backwardsCalls.length; i++) {
  992.             if (rxaCounts[i] > 0) {
  993.                 backwardsCallsUsed++;
  994.                 backwardsCalls[i] = methodAttrCalls[methodAttrIndex];
  995.                 methodAttrIndex++;
  996.             } else {
  997.                 backwardsCalls[i] = 0;
  998.             }
  999.         }
  1000.         final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, rxaCounts, backwardsCalls, "method");
  1001.         final List<Attribute>[] attributeLists = new List[RxA.length];
  1002.         final int[] attributeListIndexes = new int[RxA.length];
  1003.         for (int i = 0; i < mbgs.length; i++) {
  1004.             attributeLists[i] = mbgs[i].getAttributes();
  1005.             attributeListIndexes[i] = 0;
  1006.         }
  1007.         for (int i = 0; i < methodFlags.length; i++) {
  1008.             for (int j = 0; j < methodFlags[i].length; j++) {
  1009.                 for (int k = 0; k < rxaLayouts.length; k++) {
  1010.                     if (rxaLayouts[k].matches(methodFlags[i][j])) {
  1011.                         methodAttributes[i][j].add(attributeLists[k].get(attributeListIndexes[k]++));
  1012.                     }
  1013.                 }
  1014.             }
  1015.         }
  1016.         return backwardsCallsUsed;
  1017.     }

  1018.     /*
  1019.      * (non-Javadoc)
  1020.      *
  1021.      * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream)
  1022.      */
  1023.     @Override
  1024.     public void read(final InputStream in) throws IOException, Pack200Exception {
  1025.         final int classCount = header.getClassCount();
  1026.         classThisInts = decodeBandInt("class_this", in, Codec.DELTA5, classCount);
  1027.         classThis = getReferences(classThisInts, cpBands.getCpClass());
  1028.         classSuperInts = decodeBandInt("class_super", in, Codec.DELTA5, classCount);
  1029.         final int[] classInterfaceLengths = decodeBandInt("class_interface_count", in, Codec.DELTA5, classCount);
  1030.         classInterfacesInts = decodeBandInt("class_interface", in, Codec.DELTA5, classInterfaceLengths);
  1031.         classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5, classCount);
  1032.         classMethodCount = decodeBandInt("class_method_count", in, Codec.DELTA5, classCount);
  1033.         parseFieldBands(in);
  1034.         parseMethodBands(in);
  1035.         parseClassAttrBands(in);
  1036.         parseCodeBands(in);

  1037.     }

  1038.     @Override
  1039.     public void unpack() {

  1040.     }

  1041. }