private void parseClassAttrBands()

in modules/pack200/src/main/java/org/apache/harmony/unpack200/ClassBands.java [479:725]


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

        // Prepare empty attribute lists
        classAttributes = new ArrayList[classCount];
        for (int i = 0; i < classCount; i++) {
            classAttributes[i] = new ArrayList();
        }

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

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

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

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

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

        int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls);

        AttributeLayout innerClassLayout = attrMap.getAttributeLayout(
                AttributeLayout.ATTRIBUTE_INNER_CLASSES,
                AttributeLayout.CONTEXT_CLASS);
        int innerClassCount = SegmentUtils.countMatches(classFlags,
                innerClassLayout);
        int[] classInnerClassesN = decodeBandInt("class_InnerClasses_N", in,
                Codec.UNSIGNED5, innerClassCount);
        int[][] classInnerClassesRC = decodeBandInt("class_InnerClasses_RC",
                in, Codec.UNSIGNED5, classInnerClassesN);
        int[][] classInnerClassesF = decodeBandInt("class_InnerClasses_F", in,
                Codec.UNSIGNED5, classInnerClassesN);
        int flagsCount = 0;
        for (int i = 0; i < classInnerClassesF.length; i++) {
            for (int j = 0; j < classInnerClassesF[i].length; j++) {
                if (classInnerClassesF[i][j] != 0) {
                    flagsCount++;
                }
            }
        }
        int[] classInnerClassesOuterRCN = decodeBandInt(
                "class_InnerClasses_outer_RCN", in, Codec.UNSIGNED5, flagsCount);
        int[] classInnerClassesNameRUN = decodeBandInt(
                "class_InnerClasses_name_RUN", in, Codec.UNSIGNED5, flagsCount);

        AttributeLayout versionLayout = attrMap.getAttributeLayout(
                AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION,
                AttributeLayout.CONTEXT_CLASS);
        int versionCount = SegmentUtils.countMatches(classFlags, versionLayout);
        int[] classFileVersionMinorH = decodeBandInt(
                "class_file_version_minor_H", in, Codec.UNSIGNED5, versionCount);
        int[] classFileVersionMajorH = decodeBandInt(
                "class_file_version_major_H", in, Codec.UNSIGNED5, versionCount);
        if (versionCount > 0) {
            classVersionMajor = new int[classCount];
            classVersionMinor = new int[classCount];
        }
        int defaultVersionMajor = header.getDefaultClassMajorVersion();
        int defaultVersionMinor = header.getDefaultClassMinorVersion();

        // Parse non-predefined attribute bands
        int backwardsCallIndex = backwardsCallsUsed;
        int limit = options.hasClassFlagsHi() ? 62 : 31;
        AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
        int[] counts = new int[limit + 1];
        List[] otherAttributes = new List[limit + 1];
        for (int i = 0; i < limit; i++) {
            AttributeLayout layout = attrMap.getAttributeLayout(i,
                    AttributeLayout.CONTEXT_CLASS);
            if (layout != null && !(layout.isDefaultLayout())) {
                otherLayouts[i] = layout;
                counts[i] = SegmentUtils.countMatches(classFlags, layout);
            }
        }
        for (int i = 0; i < counts.length; i++) {
            if (counts[i] > 0) {
                NewAttributeBands bands = attrMap
                        .getAttributeBands(otherLayouts[i]);
                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
                int numBackwardsCallables = otherLayouts[i]
                        .numBackwardsCallables();
                if (numBackwardsCallables > 0) {
                    int[] backwardsCalls = new int[numBackwardsCallables];
                    System.arraycopy(classAttrCalls, backwardsCallIndex,
                            backwardsCalls, 0, numBackwardsCallables);
                    bands.setBackwardsCalls(backwardsCalls);
                    backwardsCallIndex += numBackwardsCallables;
                }
            }
        }

        // Now process the attribute bands we have parsed
        int sourceFileIndex = 0;
        int enclosingMethodIndex = 0;
        int signatureIndex = 0;
        int innerClassIndex = 0;
        int innerClassC2NIndex = 0;
        int versionIndex = 0;
        icLocal = new IcTuple[classCount][];
        for (int i = 0; i < classCount; i++) {
            long flag = classFlags[i];
            if (deprecatedLayout.matches(classFlags[i])) {
                classAttributes[i].add(new DeprecatedAttribute());
            }
            if (sourceFileLayout.matches(flag)) {
                long result = classSourceFile[sourceFileIndex];
                ClassFileEntry value = sourceFileLayout.getValue(result,
                        cpBands.getConstantPool());
                if (value == null) {
                    // Remove package prefix
                    String className = classThis[i].substring(classThis[i]
                            .lastIndexOf('/') + 1);
                    className = className
                            .substring(className.lastIndexOf('.') + 1);

                    // Remove mangled nested class names
                    char[] chars = className.toCharArray();
                    int index = -1;
                    for (int j = 0; j < chars.length; j++) {
                        if (chars[j] <= 0x2D) {
                            index = j;
                            break;
                        }
                    }
                    if (index > -1) {
                        className = className.substring(0, index);
                    }
                    // Add .java to the end
                    value = cpBands.cpUTF8Value(className + ".java", true);
                }
                classAttributes[i].add(new SourceFileAttribute((CPUTF8)value));
                sourceFileIndex++;
            }
            if (enclosingMethodLayout.matches(flag)) {
                CPClass theClass = cpBands
                        .cpClassValue(enclosingMethodRC[enclosingMethodIndex]);
                CPNameAndType theMethod = null;
                if(enclosingMethodRDN[enclosingMethodIndex] != 0) {
                    theMethod = cpBands
                            .cpNameAndTypeValue(enclosingMethodRDN[enclosingMethodIndex] - 1);
                }
                classAttributes[i].add(new EnclosingMethodAttribute(theClass,
                        theMethod));
                enclosingMethodIndex++;
            }
            if (signatureLayout.matches(flag)) {
                long result = classSignature[signatureIndex];
                CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, cpBands
                        .getConstantPool());
                classAttributes[i].add(new SignatureAttribute(value));
                signatureIndex++;
            }
            if (innerClassLayout.matches(flag)) {
                // Just create the tuples for now because the attributes are
                // decided at the end when creating class constant pools
                icLocal[i] = new IcTuple[classInnerClassesN[innerClassIndex]];
                for (int j = 0; j < icLocal[i].length; j++) {
                    int icTupleCIndex = classInnerClassesRC[innerClassIndex][j];
                    int icTupleC2Index = -1;
                    int icTupleNIndex = -1;

                    String icTupleC = cpClass[icTupleCIndex];
                    int icTupleF = classInnerClassesF[innerClassIndex][j];
                    String icTupleC2 = null;
                    String icTupleN = null;

                    if (icTupleF != 0) {
                        icTupleC2Index = classInnerClassesOuterRCN[innerClassC2NIndex];
                        icTupleNIndex = classInnerClassesNameRUN[innerClassC2NIndex];
                        icTupleC2 = cpClass[icTupleC2Index];
                        icTupleN = cpUTF8[icTupleNIndex];
                        innerClassC2NIndex++;
                    } else {
                        // Get from icBands
                        IcBands icBands = segment.getIcBands();
                        IcTuple[] icAll = icBands.getIcTuples();
                        for (int k = 0; k < icAll.length; k++) {
                            if (icAll[k].getC().equals(icTupleC)) {
                                icTupleF = icAll[k].getF();
                                icTupleC2 = icAll[k].getC2();
                                icTupleN = icAll[k].getN();
                                break;
                            }
                        }
                    }

                    IcTuple icTuple = new IcTuple(icTupleC, icTupleF,
                            icTupleC2, icTupleN, icTupleCIndex, icTupleC2Index, icTupleNIndex, j);
                    icLocal[i][j] = icTuple;
                }
                innerClassIndex++;
            }
            if (versionLayout.matches(flag)) {
                classVersionMajor[i] = classFileVersionMajorH[versionIndex];
                classVersionMinor[i] = classFileVersionMinorH[versionIndex];
                versionIndex++;
            } else if (classVersionMajor != null) {
                // Fill in with defaults
                classVersionMajor[i] = defaultVersionMajor;
                classVersionMinor[i] = defaultVersionMinor;
            }
            // Non-predefined attributes
            for (int j = 0; j < otherLayouts.length; j++) {
                if (otherLayouts[j] != null && otherLayouts[j].matches(flag)) {
                    // Add the next attribute
                    classAttributes[i].add(otherAttributes[j].get(0));
                    otherAttributes[j].remove(0);
                }
            }
        }
    }