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