private ClassFile buildClassFile()

in src/main/java/org/apache/commons/compress/harmony/unpack200/Segment.java [138:314]


    private ClassFile buildClassFile(final int classNum) {
        final ClassFile classFile = new ClassFile();
        final int[] major = classBands.getClassVersionMajor();
        final int[] minor = classBands.getClassVersionMinor();
        if (major != null) {
            classFile.major = major[classNum];
            classFile.minor = minor[classNum];
        } else {
            classFile.major = header.getDefaultClassMajorVersion();
            classFile.minor = header.getDefaultClassMinorVersion();
        }
        // build constant pool
        final ClassConstantPool cp = classFile.pool;
        final int fullNameIndexInCpClass = classBands.getClassThisInts()[classNum];
        final String fullName = cpBands.getCpClass()[fullNameIndexInCpClass];
        // SourceFile attribute
        int i = fullName.lastIndexOf("/") + 1; // if lastIndexOf==-1, then
        // -1+1=0, so str.substring(0)
        // == str

        // Get the source file attribute
        final List<Attribute> classAttributes = classBands.getClassAttributes()[classNum];
        SourceFileAttribute sourceFileAttribute = null;
        for (final Attribute classAttribute : classAttributes) {
            if (classAttribute.isSourceFileAttribute()) {
                sourceFileAttribute = (SourceFileAttribute) classAttribute;
            }
        }

        if (sourceFileAttribute == null) {
            // If we don't have a source file attribute yet, we need
            // to infer it from the class.
            final AttributeLayout SOURCE_FILE = attrDefinitionBands.getAttributeDefinitionMap().getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE,
                    AttributeLayout.CONTEXT_CLASS);
            if (SOURCE_FILE.matches(classBands.getRawClassFlags()[classNum])) {
                int firstDollar = -1;
                for (int index = 0; index < fullName.length(); index++) {
                    if (fullName.charAt(index) <= '$') {
                        firstDollar = index;
                    }
                }
                final String fileName;
                if (firstDollar > -1 && i <= firstDollar) {
                    fileName = fullName.substring(i, firstDollar) + ".java";
                } else {
                    fileName = fullName.substring(i) + ".java";
                }
                sourceFileAttribute = new SourceFileAttribute(cpBands.cpUTF8Value(fileName, false));
                classFile.attributes = new Attribute[] { (Attribute) cp.add(sourceFileAttribute) };
            } else {
                classFile.attributes = new Attribute[] {};
            }
        } else {
            classFile.attributes = new Attribute[] { (Attribute) cp.add(sourceFileAttribute) };
        }

        // If we see any class attributes, add them to the class's attributes
        // that will
        // be written out. Keep SourceFileAttributes out since we just
        // did them above.
        final List<Attribute> classAttributesWithoutSourceFileAttribute = new ArrayList<>(classAttributes.size());
        for (int index = 0; index < classAttributes.size(); index++) {
            final Attribute attrib = classAttributes.get(index);
            if (!attrib.isSourceFileAttribute()) {
                classAttributesWithoutSourceFileAttribute.add(attrib);
            }
        }
        final Attribute[] originalAttributes = classFile.attributes;
        classFile.attributes = new Attribute[originalAttributes.length + classAttributesWithoutSourceFileAttribute.size()];
        System.arraycopy(originalAttributes, 0, classFile.attributes, 0, originalAttributes.length);
        for (int index = 0; index < classAttributesWithoutSourceFileAttribute.size(); index++) {
            final Attribute attrib = classAttributesWithoutSourceFileAttribute.get(index);
            cp.add(attrib);
            classFile.attributes[originalAttributes.length + index] = attrib;
        }

        // this/superclass
        final ClassFileEntry cfThis = cp.add(cpBands.cpClassValue(fullNameIndexInCpClass));
        final ClassFileEntry cfSuper = cp.add(cpBands.cpClassValue(classBands.getClassSuperInts()[classNum]));
        // add interfaces
        final ClassFileEntry[] cfInterfaces = new ClassFileEntry[classBands.getClassInterfacesInts()[classNum].length];
        for (i = 0; i < cfInterfaces.length; i++) {
            cfInterfaces[i] = cp.add(cpBands.cpClassValue(classBands.getClassInterfacesInts()[classNum][i]));
        }
        // add fields
        final ClassFileEntry[] cfFields = new ClassFileEntry[classBands.getClassFieldCount()[classNum]];
        // fieldDescr and fieldFlags used to create this
        for (i = 0; i < cfFields.length; i++) {
            final int descriptorIndex = classBands.getFieldDescrInts()[classNum][i];
            final int nameIndex = cpBands.getCpDescriptorNameInts()[descriptorIndex];
            final int typeIndex = cpBands.getCpDescriptorTypeInts()[descriptorIndex];
            final CPUTF8 name = cpBands.cpUTF8Value(nameIndex);
            final CPUTF8 descriptor = cpBands.cpSignatureValue(typeIndex);
            cfFields[i] = cp.add(new CPField(name, descriptor, classBands.getFieldFlags()[classNum][i], classBands.getFieldAttributes()[classNum][i]));
        }
        // add methods
        final ClassFileEntry[] cfMethods = new ClassFileEntry[classBands.getClassMethodCount()[classNum]];
        // methodDescr and methodFlags used to create this
        for (i = 0; i < cfMethods.length; i++) {
            final int descriptorIndex = classBands.getMethodDescrInts()[classNum][i];
            final int nameIndex = cpBands.getCpDescriptorNameInts()[descriptorIndex];
            final int typeIndex = cpBands.getCpDescriptorTypeInts()[descriptorIndex];
            final CPUTF8 name = cpBands.cpUTF8Value(nameIndex);
            final CPUTF8 descriptor = cpBands.cpSignatureValue(typeIndex);
            cfMethods[i] = cp.add(new CPMethod(name, descriptor, classBands.getMethodFlags()[classNum][i], classBands.getMethodAttributes()[classNum][i]));
        }
        cp.addNestedEntries();

        // add inner class attribute (if required)
        boolean addInnerClassesAttr = false;
        final IcTuple[] icLocal = getClassBands().getIcLocal()[classNum];
        final boolean icLocalSent = icLocal != null;
        final InnerClassesAttribute innerClassesAttribute = new InnerClassesAttribute("InnerClasses");
        final IcTuple[] icRelevant = getIcBands().getRelevantIcTuples(fullName, cp);
        final List<IcTuple> ic_stored = computeIcStored(icLocal, icRelevant);
        for (final IcTuple icStored : ic_stored) {
            final int innerClassIndex = icStored.thisClassIndex();
            final int outerClassIndex = icStored.outerClassIndex();
            final int simpleClassNameIndex = icStored.simpleClassNameIndex();

            final String innerClassString = icStored.thisClassString();
            final String outerClassString = icStored.outerClassString();
            final String simpleClassName = icStored.simpleClassName();

            CPUTF8 innerName = null;
            CPClass outerClass = null;

            final CPClass innerClass = innerClassIndex != -1 ? cpBands.cpClassValue(innerClassIndex) : cpBands.cpClassValue(innerClassString);
            if (!icStored.isAnonymous()) {
                innerName = simpleClassNameIndex != -1 ? cpBands.cpUTF8Value(simpleClassNameIndex) : cpBands.cpUTF8Value(simpleClassName);
            }

            if (icStored.isMember()) {
                outerClass = outerClassIndex != -1 ? cpBands.cpClassValue(outerClassIndex) : cpBands.cpClassValue(outerClassString);
            }
            final int flags = icStored.F;
            innerClassesAttribute.addInnerClassesEntry(innerClass, outerClass, innerName, flags);
            addInnerClassesAttr = true;
        }
        // If ic_local is sent, and it's empty, don't add
        // the inner classes attribute.
        if (icLocalSent && icLocal.length == 0) {
            addInnerClassesAttr = false;
        }

        // If ic_local is not sent and ic_relevant is empty,
        // don't add the inner class attribute.
        if (!icLocalSent && icRelevant.length == 0) {
            addInnerClassesAttr = false;
        }

        if (addInnerClassesAttr) {
            // Need to add the InnerClasses attribute to the
            // existing classFile attributes.
            final Attribute[] originalAttrs = classFile.attributes;
            final Attribute[] newAttrs = new Attribute[originalAttrs.length + 1];
            System.arraycopy(originalAttrs, 0, newAttrs, 0, originalAttrs.length);
            newAttrs[newAttrs.length - 1] = innerClassesAttribute;
            classFile.attributes = newAttrs;
            cp.addWithNestedEntries(innerClassesAttribute);
        }
        // sort CP according to cp_All
        cp.resolve(this);
        // NOTE the indexOf is only valid after the cp.resolve()
        // build up remainder of file
        classFile.accessFlags = (int) classBands.getClassFlags()[classNum];
        classFile.thisClass = cp.indexOf(cfThis);
        classFile.superClass = cp.indexOf(cfSuper);
        // TODO placate format of file for writing purposes
        classFile.interfaces = new int[cfInterfaces.length];
        for (i = 0; i < cfInterfaces.length; i++) {
            classFile.interfaces[i] = cp.indexOf(cfInterfaces[i]);
        }
        classFile.fields = cfFields;
        classFile.methods = cfMethods;
        return classFile;
    }