private void parseClassAttrBands()

in src/main/java/org/apache/commons/compress/harmony/unpack200/ClassBands.java [331:528]


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

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

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

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

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

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

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

        final int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls);

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

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

        // Parse non-predefined attribute bands
        int backwardsCallIndex = backwardsCallsUsed;
        final int limit = options.hasClassFlagsHi() ? 62 : 31;
        final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
        final int[] counts = new int[limit + 1];
        final List<Attribute>[] otherAttributes = new List[limit + 1];
        for (int i = 0; i < limit; i++) {
            final 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) {
                final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
                final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
                if (numBackwardsCallables > 0) {
                    final 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++) {
            final long flag = classFlags[i];
            if (deprecatedLayout.matches(classFlags[i])) {
                classAttributes[i].add(new DeprecatedAttribute());
            }
            if (sourceFileLayout.matches(flag)) {
                final 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
                    final 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)) {
                final 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)) {
                final long result = classSignature[signatureIndex];
                final 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++) {
                    final int icTupleCIndex = classInnerClassesRC[innerClassIndex][j];
                    int icTupleC2Index = -1;
                    int icTupleNIndex = -1;

                    final 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
                        final IcBands icBands = segment.getIcBands();
                        final IcTuple[] icAll = icBands.getIcTuples();
                        for (final IcTuple element : icAll) {
                            if (element.getC().equals(icTupleC)) {
                                icTupleF = element.getF();
                                icTupleC2 = element.getC2();
                                icTupleN = element.getN();
                                break;
                            }
                        }
                    }

                    final 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);
                }
            }
        }
    }