    001/*
    002 *  Licensed to the Apache Software Foundation (ASF) under one or more
    003 *  contributor license agreements.  See the NOTICE file distributed with
    004 *  this work for additional information regarding copyright ownership.
    005 *  The ASF licenses this file to You under the Apache License, Version 2.0
    006 *  (the "License"); you may not use this file except in compliance with
    007 *  the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 */
    017package org.apache.commons.compress.harmony.unpack200;
    018
    019import java.io.IOException;
    020import java.io.InputStream;
    021import java.util.ArrayList;
    022import java.util.Arrays;
    023import java.util.List;
    024import java.util.stream.Collectors;
    025import java.util.stream.Stream;
    026
    027import org.apache.commons.compress.harmony.pack200.Codec;
    028import org.apache.commons.compress.harmony.pack200.Pack200Exception;
    029import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
    030import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
    031import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
    032import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
    033import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
    034import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantValueAttribute;
    035import org.apache.commons.compress.harmony.unpack200.bytecode.DeprecatedAttribute;
    036import org.apache.commons.compress.harmony.unpack200.bytecode.EnclosingMethodAttribute;
    037import org.apache.commons.compress.harmony.unpack200.bytecode.ExceptionsAttribute;
    038import org.apache.commons.compress.harmony.unpack200.bytecode.LineNumberTableAttribute;
    039import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTableAttribute;
    040import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTypeTableAttribute;
    041import org.apache.commons.compress.harmony.unpack200.bytecode.SignatureAttribute;
    042import org.apache.commons.compress.harmony.unpack200.bytecode.SourceFileAttribute;
    043
    044/**
    045 * Class Bands
    046 */
    047public class ClassBands extends BandSet {
    048
    049    private int[] classFieldCount;
    050
    051    private long[] classFlags;
    052
    053    private long[] classAccessFlags; // Access flags for writing to the class
    054    // file
    055
    056    private int[][] classInterfacesInts;
    057
    058    private int[] classMethodCount;
    059
    060    private int[] classSuperInts;
    061
    062    private String[] classThis;
    063
    064    private int[] classThisInts;
    065
    066    private ArrayList<Attribute>[] classAttributes;
    067
    068    private int[] classVersionMajor;
    069
    070    private int[] classVersionMinor;
    071
    072    private IcTuple[][] icLocal;
    073
    074    private List<Attribute>[] codeAttributes;
    075
    076    private int[] codeHandlerCount;
    077
    078    private int[] codeMaxNALocals;
    079
    080    private int[] codeMaxStack;
    081
    082    private ArrayList<Attribute>[][] fieldAttributes;
    083
    084    private String[][] fieldDescr;
    085
    086    private int[][] fieldDescrInts;
    087
    088    private long[][] fieldFlags;
    089
    090    private long[][] fieldAccessFlags;
    091
    092    private ArrayList<Attribute>[][] methodAttributes;
    093
    094    private String[][] methodDescr;
    095
    096    private int[][] methodDescrInts;
    097
    098    private long[][] methodFlags;
    099
    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}