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