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