Fork of Apache Harmony's Pack200 implementation
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pack200/src/main/java/org/apache/harmony/unpack200/ClassBands.java

1418 lines
60 KiB

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.harmony.unpack200;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.harmony.pack200.Codec;
import org.apache.harmony.pack200.Pack200Exception;
import org.apache.harmony.unpack200.bytecode.Attribute;
import org.apache.harmony.unpack200.bytecode.CPClass;
import org.apache.harmony.unpack200.bytecode.CPNameAndType;
import org.apache.harmony.unpack200.bytecode.CPUTF8;
import org.apache.harmony.unpack200.bytecode.ClassFileEntry;
import org.apache.harmony.unpack200.bytecode.ConstantValueAttribute;
import org.apache.harmony.unpack200.bytecode.DeprecatedAttribute;
import org.apache.harmony.unpack200.bytecode.EnclosingMethodAttribute;
import org.apache.harmony.unpack200.bytecode.ExceptionsAttribute;
import org.apache.harmony.unpack200.bytecode.LineNumberTableAttribute;
import org.apache.harmony.unpack200.bytecode.LocalVariableTableAttribute;
import org.apache.harmony.unpack200.bytecode.LocalVariableTypeTableAttribute;
import org.apache.harmony.unpack200.bytecode.SignatureAttribute;
import org.apache.harmony.unpack200.bytecode.SourceFileAttribute;
/**
* Class Bands
*/
public class ClassBands extends BandSet {
private int[] classFieldCount;
private long[] classFlags;
private long[] classAccessFlags; // Access flags for writing to the class
// file
private int[][] classInterfacesInts;
private int[] classMethodCount;
private int[] classSuperInts;
private String[] classThis;
private int[] classThisInts;
private ArrayList[] classAttributes;
private int[] classVersionMajor;
private int[] classVersionMinor;
private IcTuple[][] icLocal;
private List[] codeAttributes;
private int[] codeHandlerCount;
private int[] codeMaxNALocals;
private int[] codeMaxStack;
private ArrayList[][] fieldAttributes;
private String[][] fieldDescr;
private int[][] fieldDescrInts;
private long[][] fieldFlags;
private long[][] fieldAccessFlags;
private ArrayList[][] methodAttributes;
private String[][] methodDescr;
private int[][] methodDescrInts;
private long[][] methodFlags;
private long[][] methodAccessFlags;
private final AttributeLayoutMap attrMap;
private final CpBands cpBands;
private final SegmentOptions options;
private final int classCount;
private int[] methodAttrCalls;
private int[][] codeHandlerStartP;
private int[][] codeHandlerEndPO;
private int[][] codeHandlerCatchPO;
private int[][] codeHandlerClassRCN;
private boolean [] codeHasAttributes;
/**
* @param segment
*/
public ClassBands(Segment segment) {
super(segment);
this.attrMap = segment.getAttrDefinitionBands()
.getAttributeDefinitionMap();
this.cpBands = segment.getCpBands();
this.classCount = header.getClassCount();
this.options = header.getOptions();
}
/*
* (non-Javadoc)
*
* @see org.apache.harmony.unpack200.BandSet#unpack(java.io.InputStream)
*/
public void read(InputStream in) throws IOException, Pack200Exception {
int classCount = header.getClassCount();
classThisInts = decodeBandInt("class_this", in, Codec.DELTA5, classCount);
classThis = getReferences(classThisInts, cpBands.getCpClass());
classSuperInts = decodeBandInt("class_super", in, Codec.DELTA5,
classCount);
int[] classInterfaceLengths = decodeBandInt("class_interface_count",
in, Codec.DELTA5, classCount);
classInterfacesInts = decodeBandInt("class_interface", in, Codec.DELTA5,
classInterfaceLengths);
classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5,
classCount);
classMethodCount = decodeBandInt("class_method_count", in,
Codec.DELTA5, classCount);
parseFieldBands(in);
parseMethodBands(in);
parseClassAttrBands(in);
parseCodeBands(in);
}
public void unpack() {
}
private void parseFieldBands(InputStream in) throws IOException,
Pack200Exception {
fieldDescrInts = decodeBandInt("field_descr", in, Codec.DELTA5,
classFieldCount);
fieldDescr = getReferences(fieldDescrInts, cpBands.getCpDescriptor());
parseFieldAttrBands(in);
}
private void parseFieldAttrBands(InputStream in) throws IOException,
Pack200Exception {
fieldFlags = parseFlags("field_flags", in, classFieldCount,
Codec.UNSIGNED5, options.hasFieldFlagsHi());
int fieldAttrCount = SegmentUtils.countBit16(fieldFlags);
int[] fieldAttrCounts = decodeBandInt("field_attr_count", in,
Codec.UNSIGNED5, fieldAttrCount);
int[][] fieldAttrIndexes = decodeBandInt("field_attr_indexes", in,
Codec.UNSIGNED5, fieldAttrCounts);
int callCount = getCallCount(fieldAttrIndexes, fieldFlags,
AttributeLayout.CONTEXT_FIELD);
int[] fieldAttrCalls = decodeBandInt("field_attr_calls", in,
Codec.UNSIGNED5, callCount);
// Assign empty field attributes
fieldAttributes = new ArrayList[classCount][];
for (int i = 0; i < classCount; i++) {
fieldAttributes[i] = new ArrayList[fieldFlags[i].length];
for (int j = 0; j < fieldFlags[i].length; j++) {
fieldAttributes[i][j] = new ArrayList();
}
}
AttributeLayout constantValueLayout = attrMap.getAttributeLayout(
"ConstantValue", AttributeLayout.CONTEXT_FIELD);
int constantCount = SegmentUtils.countMatches(fieldFlags,
constantValueLayout);
int[] field_constantValue_KQ = decodeBandInt("field_ConstantValue_KQ",
in, Codec.UNSIGNED5, constantCount);
int constantValueIndex = 0;
AttributeLayout signatureLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_SIGNATURE,
AttributeLayout.CONTEXT_FIELD);
int signatureCount = SegmentUtils.countMatches(fieldFlags,
signatureLayout);
int[] fieldSignatureRS = decodeBandInt("field_Signature_RS", in,
Codec.UNSIGNED5, signatureCount);
int signatureIndex = 0;
AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_DEPRECATED,
AttributeLayout.CONTEXT_FIELD);
for (int i = 0; i < classCount; i++) {
for (int j = 0; j < fieldFlags[i].length; j++) {
long flag = fieldFlags[i][j];
if (deprecatedLayout.matches(flag)) {
fieldAttributes[i][j].add(new DeprecatedAttribute());
}
if (constantValueLayout.matches(flag)) {
// we've got a value to read
long result = field_constantValue_KQ[constantValueIndex];
String desc = fieldDescr[i][j];
int colon = desc.indexOf(':');
String type = desc.substring(colon + 1);
if (type.equals("B") || type.equals("S")
|| type.equals("C") || type.equals("Z"))
type = "I";
ClassFileEntry value = constantValueLayout.getValue(result,
type, cpBands.getConstantPool());
fieldAttributes[i][j]
.add(new ConstantValueAttribute(value));
constantValueIndex++;
}
if (signatureLayout.matches(flag)) {
// we've got a signature attribute
long result = fieldSignatureRS[signatureIndex];
String desc = fieldDescr[i][j];
int colon = desc.indexOf(':');
String type = desc.substring(colon + 1);
CPUTF8 value = (CPUTF8) signatureLayout.getValue(result,
type, cpBands.getConstantPool());
fieldAttributes[i][j].add(new SignatureAttribute(value));
signatureIndex++;
}
}
}
int backwardsCallsUsed = parseFieldMetadataBands(in, fieldAttrCalls);
// Parse non-predefined attribute bands
int backwardsCallIndex = backwardsCallsUsed;
int limit = options.hasFieldFlagsHi() ? 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_FIELD);
if (layout != null && !(layout.isDefaultLayout())) {
otherLayouts[i] = layout;
counts[i] = SegmentUtils.countMatches(fieldFlags, 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(fieldAttrCalls, backwardsCallIndex,
backwardsCalls, 0, numBackwardsCallables);
bands.setBackwardsCalls(backwardsCalls);
backwardsCallIndex += numBackwardsCallables;
}
}
}
// Non-predefined attributes
for (int i = 0; i < classCount; i++) {
for (int j = 0; j < fieldFlags[i].length; j++) {
long flag = fieldFlags[i][j];
int othersAddedAtStart = 0;
for (int k = 0; k < otherLayouts.length; k++) {
if (otherLayouts[k] != null
&& otherLayouts[k].matches(flag)) {
// Add the next attribute
if(otherLayouts[k].getIndex()<15) {
fieldAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0));
} else {
fieldAttributes[i][j].add(otherAttributes[k].get(0));
}
otherAttributes[k].remove(0);
}
}
}
}
}
private void parseMethodBands(InputStream in) throws IOException,
Pack200Exception {
methodDescrInts = decodeBandInt("method_descr", in, Codec.MDELTA5,
classMethodCount);
methodDescr = getReferences(methodDescrInts, cpBands.getCpDescriptor());
parseMethodAttrBands(in);
}
private void parseMethodAttrBands(InputStream in) throws IOException,
Pack200Exception {
methodFlags = parseFlags("method_flags", in, classMethodCount,
Codec.UNSIGNED5, options.hasMethodFlagsHi());
int methodAttrCount = SegmentUtils.countBit16(methodFlags);
int[] methodAttrCounts = decodeBandInt("method_attr_count", in,
Codec.UNSIGNED5, methodAttrCount);
int[][] methodAttrIndexes = decodeBandInt("method_attr_indexes", in,
Codec.UNSIGNED5, methodAttrCounts);
int callCount = getCallCount(methodAttrIndexes, methodFlags,
AttributeLayout.CONTEXT_METHOD);
methodAttrCalls = decodeBandInt("method_attr_calls", in, Codec.UNSIGNED5,
callCount);
// assign empty method attributes
methodAttributes = new ArrayList[classCount][];
for (int i = 0; i < classCount; i++) {
methodAttributes[i] = new ArrayList[methodFlags[i].length];
for (int j = 0; j < methodFlags[i].length; j++) {
methodAttributes[i][j] = new ArrayList();
}
}
// Parse method exceptions attributes
AttributeLayout methodExceptionsLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_EXCEPTIONS,
AttributeLayout.CONTEXT_METHOD);
int count = SegmentUtils.countMatches(methodFlags,
methodExceptionsLayout);
int[] numExceptions = decodeBandInt("method_Exceptions_n", in,
Codec.UNSIGNED5, count);
int[][] methodExceptionsRS = decodeBandInt("method_Exceptions_RC",
in, Codec.UNSIGNED5, numExceptions);
// Parse method signature attributes
AttributeLayout methodSignatureLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_SIGNATURE,
AttributeLayout.CONTEXT_METHOD);
int count1 = SegmentUtils.countMatches(methodFlags,
methodSignatureLayout);
int[] methodSignatureRS = decodeBandInt("method_signature_RS", in,
Codec.UNSIGNED5, count1);
AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_DEPRECATED,
AttributeLayout.CONTEXT_METHOD);
// Add attributes to the attribute arrays
int methodExceptionsIndex = 0;
int methodSignatureIndex = 0;
for (int i = 0; i < methodAttributes.length; i++) {
for (int j = 0; j < methodAttributes[i].length; j++) {
long flag = methodFlags[i][j];
if (methodExceptionsLayout.matches(flag)) {
int n = numExceptions[methodExceptionsIndex];
int[] exceptions = methodExceptionsRS[methodExceptionsIndex];
CPClass[] exceptionClasses = new CPClass[n];
for (int k = 0; k < n; k++) {
exceptionClasses[k] = cpBands
.cpClassValue(exceptions[k]);
}
methodAttributes[i][j].add(new ExceptionsAttribute(
exceptionClasses));
methodExceptionsIndex++;
}
if (methodSignatureLayout.matches(flag)) {
// We've got a signature attribute
long result = methodSignatureRS[methodSignatureIndex];
String desc = methodDescr[i][j];
int colon = desc.indexOf(':');
String type = desc.substring(colon + 1);
// TODO Got to get better at this ... in any case, it should
// be e.g. KIB or KIH
if (type.equals("B") || type.equals("H"))
type = "I";
CPUTF8 value = (CPUTF8) methodSignatureLayout.getValue(
result, type, cpBands.getConstantPool());
methodAttributes[i][j]
.add(new SignatureAttribute(value));
methodSignatureIndex++;
}
if (deprecatedLayout.matches(flag)) {
methodAttributes[i][j].add(new DeprecatedAttribute());
}
}
}
// Parse method metadata bands
int backwardsCallsUsed = parseMethodMetadataBands(in, methodAttrCalls);
// Parse non-predefined attribute bands
int backwardsCallIndex = backwardsCallsUsed;
int limit = options.hasMethodFlagsHi() ? 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_METHOD);
if (layout != null && !(layout.isDefaultLayout())) {
otherLayouts[i] = layout;
counts[i] = SegmentUtils.countMatches(methodFlags, 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(methodAttrCalls, backwardsCallIndex,
backwardsCalls, 0, numBackwardsCallables);
bands.setBackwardsCalls(backwardsCalls);
backwardsCallIndex += numBackwardsCallables;
}
}
}
// Non-predefined attributes
for (int i = 0; i < methodAttributes.length; i++) {
for (int j = 0; j < methodAttributes[i].length; j++) {
long flag = methodFlags[i][j];
int othersAddedAtStart = 0;
for (int k = 0; k < otherLayouts.length; k++) {
if (otherLayouts[k] != null
&& otherLayouts[k].matches(flag)) {
// Add the next attribute
if(otherLayouts[k].getIndex() < 15) {
methodAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0));
} else {
methodAttributes[i][j].add(otherAttributes[k].get(0));
}
otherAttributes[k].remove(0);
}
}
}
}
}
private int getCallCount(int[][] methodAttrIndexes, long[][] flags,
int context) throws Pack200Exception {
int callCount = 0;
for (int i = 0; i < methodAttrIndexes.length; i++) {
for (int j = 0; j < methodAttrIndexes[i].length; j++) {
int index = methodAttrIndexes[i][j];
AttributeLayout layout = attrMap.getAttributeLayout(index,
context);
callCount += layout.numBackwardsCallables();
}
}
int layoutsUsed = 0;
for (int i = 0; i < flags.length; i++) {
for (int j = 0; j < flags[i].length; j++) {
layoutsUsed |= flags[i][j];
}
}
for (int i = 0; i < 26; i++) {
if ((layoutsUsed & 1 << i) != 0) {
AttributeLayout layout = attrMap.getAttributeLayout(i, context);
callCount += layout.numBackwardsCallables();
}
}
return callCount;
}
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);
}
}
}
}
private void parseCodeBands(InputStream in) throws Pack200Exception,
IOException {
AttributeLayout layout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD);
int codeCount = SegmentUtils.countMatches(methodFlags, layout);
int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1,
codeCount);
boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags();
if(!allCodeHasFlags) {
codeHasAttributes = new boolean[codeCount];
}
int codeSpecialHeader = 0;
for (int i = 0; i < codeCount; i++) {
if (codeHeaders[i] == 0) {
codeSpecialHeader++;
if(!allCodeHasFlags) {
codeHasAttributes[i] = true;
}
}
}
int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in,
Codec.UNSIGNED5, codeSpecialHeader);
int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in,
Codec.UNSIGNED5, codeSpecialHeader);
int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count",
in, Codec.UNSIGNED5, codeSpecialHeader);
codeMaxStack = new int[codeCount];
codeMaxNALocals = new int[codeCount];
codeHandlerCount = new int[codeCount];
int special = 0;
for (int i = 0; i < codeCount; i++) {
int header = 0xff & codeHeaders[i];
if (header < 0) {
throw new IllegalStateException("Shouldn't get here");
} else if (header == 0) {
codeMaxStack[i] = codeMaxStackSpecials[special];
codeMaxNALocals[i] = codeMaxNALocalsSpecials[special];
codeHandlerCount[i] = codeHandlerCountSpecials[special];
special++;
} else if (header <= 144) {
codeMaxStack[i] = (header - 1) % 12;
codeMaxNALocals[i] = (header - 1) / 12;
codeHandlerCount[i] = 0;
} else if (header <= 208) {
codeMaxStack[i] = (header - 145) % 8;
codeMaxNALocals[i] = (header - 145) / 8;
codeHandlerCount[i] = 1;
} else if (header <= 255) {
codeMaxStack[i] = (header - 209) % 7;
codeMaxNALocals[i] = (header - 209) / 7;
codeHandlerCount[i] = 2;
} else {
throw new IllegalStateException("Shouldn't get here either");
}
}
codeHandlerStartP = decodeBandInt("code_handler_start_P", in,
Codec.BCI5, codeHandlerCount);
codeHandlerEndPO = decodeBandInt("code_handler_end_PO", in,
Codec.BRANCH5, codeHandlerCount);
codeHandlerCatchPO = decodeBandInt("code_handler_catch_PO", in,
Codec.BRANCH5, codeHandlerCount);
codeHandlerClassRCN = decodeBandInt(
"code_handler_class_RCN", in, Codec.UNSIGNED5, codeHandlerCount);
int codeFlagsCount = allCodeHasFlags ? codeCount : codeSpecialHeader;
codeAttributes = new List[codeFlagsCount];
for (int i = 0; i < codeAttributes.length; i++) {
codeAttributes[i] = new ArrayList();
}
parseCodeAttrBands(in, codeFlagsCount);
}
private void parseCodeAttrBands(InputStream in, int codeFlagsCount)
throws IOException, Pack200Exception {
long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount,
Codec.UNSIGNED5, segment.getSegmentHeader().getOptions()
.hasCodeFlagsHi());
int codeAttrCount = SegmentUtils.countBit16(codeFlags);
int[] codeAttrCounts = decodeBandInt("code_attr_count", in,
Codec.UNSIGNED5, codeAttrCount);
int[][] codeAttrIndexes = decodeBandInt("code_attr_indexes", in,
Codec.UNSIGNED5, codeAttrCounts);
int callCount = 0;
for (int i = 0; i < codeAttrIndexes.length; i++) {
for (int j = 0; j < codeAttrIndexes[i].length; j++) {
int index = codeAttrIndexes[i][j];
AttributeLayout layout = attrMap.getAttributeLayout(index,
AttributeLayout.CONTEXT_CODE);
callCount += layout.numBackwardsCallables();
}
}
int[] codeAttrCalls = decodeBandInt("code_attr_calls", in,
Codec.UNSIGNED5, callCount);
AttributeLayout lineNumberTableLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE,
AttributeLayout.CONTEXT_CODE);
int lineNumberTableCount = SegmentUtils.countMatches(codeFlags,
lineNumberTableLayout);
int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in,
Codec.UNSIGNED5, lineNumberTableCount);
int[][] lineNumberTableBciP = decodeBandInt(
"code_LineNumberTable_bci_P", in, Codec.BCI5, lineNumberTableN);
int[][] lineNumberTableLine = decodeBandInt(
"code_LineNumberTable_line", in, Codec.UNSIGNED5,
lineNumberTableN);
AttributeLayout localVariableTableLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE,
AttributeLayout.CONTEXT_CODE);
AttributeLayout localVariableTypeTableLayout = attrMap
.getAttributeLayout(
AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE,
AttributeLayout.CONTEXT_CODE);
int lengthLocalVariableNBand = SegmentUtils.countMatches(codeFlags,
localVariableTableLayout);
int[] localVariableTableN = decodeBandInt("code_LocalVariableTable_N",
in, Codec.UNSIGNED5, lengthLocalVariableNBand);
int[][] localVariableTableBciP = decodeBandInt(
"code_LocalVariableTable_bci_P", in, Codec.BCI5,
localVariableTableN);
int[][] localVariableTableSpanO = decodeBandInt(
"code_LocalVariableTable_span_O", in, Codec.BRANCH5,
localVariableTableN);
CPUTF8[][] localVariableTableNameRU = parseCPUTF8References(
"code_LocalVariableTable_name_RU", in, Codec.UNSIGNED5,
localVariableTableN);
CPUTF8[][] localVariableTableTypeRS = parseCPSignatureReferences(
"code_LocalVariableTable_type_RS", in, Codec.UNSIGNED5,
localVariableTableN);
int[][] localVariableTableSlot = decodeBandInt(
"code_LocalVariableTable_slot", in, Codec.UNSIGNED5,
localVariableTableN);
int lengthLocalVariableTypeTableNBand = SegmentUtils.countMatches(
codeFlags, localVariableTypeTableLayout);
int[] localVariableTypeTableN = decodeBandInt(
"code_LocalVariableTypeTable_N", in, Codec.UNSIGNED5,
lengthLocalVariableTypeTableNBand);
int[][] localVariableTypeTableBciP = decodeBandInt(
"code_LocalVariableTypeTable_bci_P", in, Codec.BCI5,
localVariableTypeTableN);
int[][] localVariableTypeTableSpanO = decodeBandInt(
"code_LocalVariableTypeTable_span_O", in, Codec.BRANCH5,
localVariableTypeTableN);
CPUTF8[][] localVariableTypeTableNameRU = parseCPUTF8References(
"code_LocalVariableTypeTable_name_RU", in, Codec.UNSIGNED5,
localVariableTypeTableN);
CPUTF8[][] localVariableTypeTableTypeRS = parseCPSignatureReferences(
"code_LocalVariableTypeTable_type_RS", in, Codec.UNSIGNED5,
localVariableTypeTableN);
int[][] localVariableTypeTableSlot = decodeBandInt(
"code_LocalVariableTypeTable_slot", in, Codec.UNSIGNED5,
localVariableTypeTableN);
// Parse non-predefined attribute bands
int backwardsCallIndex = 0;
int limit = options.hasCodeFlagsHi() ? 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_CODE);
if (layout != null && !(layout.isDefaultLayout())) {
otherLayouts[i] = layout;
counts[i] = SegmentUtils.countMatches(codeFlags, 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(codeAttrCalls, backwardsCallIndex,
backwardsCalls, 0, numBackwardsCallables);
bands.setBackwardsCalls(backwardsCalls);
backwardsCallIndex += numBackwardsCallables;
}
}
}
int lineNumberIndex = 0;
int lvtIndex = 0;
int lvttIndex = 0;
for (int i = 0; i < codeFlagsCount; i++) {
if (lineNumberTableLayout.matches(codeFlags[i])) {
LineNumberTableAttribute lnta = new LineNumberTableAttribute(
lineNumberTableN[lineNumberIndex],
lineNumberTableBciP[lineNumberIndex],
lineNumberTableLine[lineNumberIndex]);
lineNumberIndex++;
codeAttributes[i].add(lnta);
}
if (localVariableTableLayout.matches(codeFlags[i])) {
LocalVariableTableAttribute lvta = new LocalVariableTableAttribute(
localVariableTableN[lvtIndex],
localVariableTableBciP[lvtIndex],
localVariableTableSpanO[lvtIndex],
localVariableTableNameRU[lvtIndex],
localVariableTableTypeRS[lvtIndex],
localVariableTableSlot[lvtIndex]);
lvtIndex++;
codeAttributes[i].add(lvta);
}
if (localVariableTypeTableLayout.matches(codeFlags[i])) {
LocalVariableTypeTableAttribute lvtta = new LocalVariableTypeTableAttribute(
localVariableTypeTableN[lvttIndex],
localVariableTypeTableBciP[lvttIndex],
localVariableTypeTableSpanO[lvttIndex],
localVariableTypeTableNameRU[lvttIndex],
localVariableTypeTableTypeRS[lvttIndex],
localVariableTypeTableSlot[lvttIndex]);
lvttIndex++;
codeAttributes[i].add(lvtta);
}
// Non-predefined attributes
for (int j = 0; j < otherLayouts.length; j++) {
if (otherLayouts[j] != null
&& otherLayouts[j].matches(codeFlags[i])) {
// Add the next attribute
codeAttributes[i].add(otherAttributes[j].get(0));
otherAttributes[j].remove(0);
}
}
}
}
private int parseFieldMetadataBands(InputStream in, int[] fieldAttrCalls)
throws Pack200Exception, IOException {
int backwardsCallsUsed = 0;
String[] RxA = new String[] { "RVA", "RIA" };
AttributeLayout rvaLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS,
AttributeLayout.CONTEXT_FIELD);
AttributeLayout riaLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS,
AttributeLayout.CONTEXT_FIELD);
int rvaCount = SegmentUtils.countMatches(fieldFlags, rvaLayout);
int riaCount = SegmentUtils.countMatches(fieldFlags, riaLayout);
int[] RxACount = new int[] { rvaCount, riaCount };
int[] backwardsCalls = new int[] { 0, 0 };
if (rvaCount > 0) {
backwardsCalls[0] = fieldAttrCalls[0];
backwardsCallsUsed++;
if (riaCount > 0) {
backwardsCalls[1] = fieldAttrCalls[1];
backwardsCallsUsed++;
}
} else if (riaCount > 0) {
backwardsCalls[1] = fieldAttrCalls[0];
backwardsCallsUsed++;
}
MetadataBandGroup[] mb = parseMetadata(in, RxA, RxACount,
backwardsCalls, "field");
List rvaAttributes = mb[0].getAttributes();
List riaAttributes = mb[1].getAttributes();
int rvaAttributesIndex = 0;
int riaAttributesIndex = 0;
for (int i = 0; i < fieldFlags.length; i++) {
for (int j = 0; j < fieldFlags[i].length; j++) {
if (rvaLayout.matches(fieldFlags[i][j])) {
fieldAttributes[i][j].add(rvaAttributes.get(rvaAttributesIndex++));
}
if (riaLayout.matches(fieldFlags[i][j])) {
fieldAttributes[i][j].add(riaAttributes.get(riaAttributesIndex++));
}
}
}
return backwardsCallsUsed;
}
private MetadataBandGroup[] parseMetadata(InputStream in, String[] RxA,
int[] RxACount, int[] backwardsCallCounts, String contextName)
throws IOException, Pack200Exception {
MetadataBandGroup[] mbg = new MetadataBandGroup[RxA.length];
for (int i = 0; i < RxA.length; i++) {
mbg[i] = new MetadataBandGroup(RxA[i], cpBands);
String rxa = RxA[i];
if (rxa.indexOf('P') >= 0) {
mbg[i].param_NB = decodeBandInt(contextName + "_" + rxa
+ "_param_NB", in, Codec.BYTE1, RxACount[i]);
}
int pairCount = 0;
if (!rxa.equals("AD")) {
mbg[i].anno_N = decodeBandInt(contextName + "_" + rxa
+ "_anno_N", in, Codec.UNSIGNED5, RxACount[i]);
mbg[i].type_RS = parseCPSignatureReferences(contextName
+ "_" + rxa + "_type_RS", in, Codec.UNSIGNED5,
mbg[i].anno_N);
mbg[i].pair_N = decodeBandInt(contextName + "_" + rxa
+ "_pair_N", in, Codec.UNSIGNED5, mbg[i].anno_N);
for (int j = 0; j < mbg[i].pair_N.length; j++) {
for (int k = 0; k < mbg[i].pair_N[j].length; k++) {
pairCount += mbg[i].pair_N[j][k];
}
}
mbg[i].name_RU = parseCPUTF8References(contextName
+ "_" + rxa + "_name_RU", in, Codec.UNSIGNED5,
pairCount);
}
mbg[i].T = decodeBandInt(contextName + "_" + rxa + "_T", in,
Codec.BYTE1, pairCount + backwardsCallCounts[i]);
int ICount = 0, DCount = 0, FCount = 0, JCount = 0, cCount = 0, eCount = 0, sCount = 0, arrayCount = 0, atCount = 0;
for (int j = 0; j < mbg[i].T.length; j++) {
char c = (char) mbg[i].T[j];
switch (c) {
case 'B':
case 'C':
case 'I':
case 'S':
case 'Z':
ICount++;
break;
case 'D':
DCount++;
break;
case 'F':
FCount++;
break;
case 'J':
JCount++;
break;
case 'c':
cCount++;
break;
case 'e':
eCount++;
break;
case 's':
sCount++;
break;
case '[':
arrayCount++;
break;
case '@':
atCount++;
break;
}
}
mbg[i].caseI_KI = parseCPIntReferences(contextName + "_" + rxa
+ "_caseI_KI", in, Codec.UNSIGNED5, ICount);
mbg[i].caseD_KD = parseCPDoubleReferences(contextName + "_" + rxa
+ "_caseD_KD", in, Codec.UNSIGNED5, DCount);
mbg[i].caseF_KF = parseCPFloatReferences(contextName + "_" + rxa
+ "_caseF_KF", in, Codec.UNSIGNED5, FCount);
mbg[i].caseJ_KJ = parseCPLongReferences(contextName + "_" + rxa
+ "_caseJ_KJ", in, Codec.UNSIGNED5, JCount);
mbg[i].casec_RS = parseCPUTF8References(contextName + "_" + rxa
+ "_casec_RS", in, Codec.UNSIGNED5, cCount);
mbg[i].caseet_RS = parseReferences(contextName + "_" + rxa
+ "_caseet_RS", in, Codec.UNSIGNED5, eCount, cpBands
.getCpSignature());
mbg[i].caseec_RU = parseReferences(contextName + "_" + rxa
+ "_caseec_RU", in, Codec.UNSIGNED5, eCount, cpBands
.getCpUTF8());
mbg[i].cases_RU = parseCPUTF8References(contextName + "_" + rxa
+ "_cases_RU", in, Codec.UNSIGNED5, sCount);
mbg[i].casearray_N = decodeBandInt(contextName + "_" + rxa
+ "_casearray_N", in, Codec.UNSIGNED5, arrayCount);
mbg[i].nesttype_RS = parseCPUTF8References(contextName + "_" + rxa
+ "_nesttype_RS", in, Codec.UNSIGNED5, atCount);
mbg[i].nestpair_N = decodeBandInt(contextName + "_" + rxa
+ "_nestpair_N", in, Codec.UNSIGNED5, atCount);
int nestPairCount = 0;
for (int j = 0; j < mbg[i].nestpair_N.length; j++) {
nestPairCount += mbg[i].nestpair_N[j];
}
mbg[i].nestname_RU = parseCPUTF8References(contextName + "_" + rxa
+ "_nestname_RU", in, Codec.UNSIGNED5, nestPairCount);
}
return mbg;
}
private int parseMethodMetadataBands(InputStream in, int[] methodAttrCalls)
throws Pack200Exception, IOException {
int backwardsCallsUsed = 0;
String[] RxA = new String[] { "RVA", "RIA", "RVPA", "RIPA", "AD" };
int[] rxaCounts = new int[] { 0, 0, 0, 0, 0 };
int[] backwardsCalls = new int[5];
int methodAttrIndex = 0;
for (int i = 0; i < backwardsCalls.length; i++) {
if (rxaCounts[i] > 0) {
backwardsCallsUsed++;
backwardsCalls[i] = methodAttrCalls[methodAttrIndex];
methodAttrIndex++;
} else {
backwardsCalls[i] = 0;
}
}
AttributeLayout rvaLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS,
AttributeLayout.CONTEXT_METHOD);
AttributeLayout riaLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS,
AttributeLayout.CONTEXT_METHOD);
AttributeLayout rvpaLayout = attrMap
.getAttributeLayout(
AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
AttributeLayout.CONTEXT_METHOD);
AttributeLayout ripaLayout = attrMap
.getAttributeLayout(
AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,
AttributeLayout.CONTEXT_METHOD);
AttributeLayout adLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT,
AttributeLayout.CONTEXT_METHOD);
AttributeLayout[] rxaLayouts = new AttributeLayout[] { rvaLayout,
riaLayout, rvpaLayout, ripaLayout, adLayout };
for (int i = 0; i < rxaLayouts.length; i++) {
rxaCounts[i] = SegmentUtils
.countMatches(methodFlags, rxaLayouts[i]);
}
MetadataBandGroup[] mbgs = parseMetadata(in, RxA, rxaCounts,
backwardsCalls, "method");
List[] attributeLists = new List[RxA.length];
int[] attributeListIndexes = new int[RxA.length];
for (int i = 0; i < mbgs.length; i++) {
attributeLists[i] = mbgs[i].getAttributes();
attributeListIndexes[i] = 0;
}
for (int i = 0; i < methodFlags.length; i++) {
for (int j = 0; j < methodFlags[i].length; j++) {
for (int k = 0; k < rxaLayouts.length; k++) {
if (rxaLayouts[k].matches(methodFlags[i][j])) {
methodAttributes[i][j]
.add(attributeLists[k].get(attributeListIndexes[k]++));
}
}
}
}
return backwardsCallsUsed;
}
/**
* Parse the class metadata bands and return the number of backwards
* callables
*
* @param in
* @param classAttrCalls
* @return
* @throws Pack200Exception
* @throws IOException
*/
private int parseClassMetadataBands(InputStream in, int[] classAttrCalls)
throws Pack200Exception, IOException {
int numBackwardsCalls = 0;
String[] RxA = new String[] { "RVA", "RIA" };
AttributeLayout rvaLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS,
AttributeLayout.CONTEXT_CLASS);
AttributeLayout riaLayout = attrMap.getAttributeLayout(
AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS,
AttributeLayout.CONTEXT_CLASS);
int rvaCount = SegmentUtils.countMatches(classFlags, rvaLayout);
int riaCount = SegmentUtils.countMatches(classFlags, riaLayout);
int[] RxACount = new int[] { rvaCount, riaCount };
int[] backwardsCalls = new int[] { 0, 0 };
if (rvaCount > 0) {
numBackwardsCalls++;
backwardsCalls[0] = classAttrCalls[0];
if (riaCount > 0) {
numBackwardsCalls++;
backwardsCalls[1] = classAttrCalls[1];
}
} else if (riaCount > 0) {
numBackwardsCalls++;
backwardsCalls[1] = classAttrCalls[0];
}
MetadataBandGroup[] mbgs = parseMetadata(in, RxA, RxACount,
backwardsCalls, "class");
List rvaAttributes = mbgs[0].getAttributes();
List riaAttributes = mbgs[1].getAttributes();
int rvaAttributesIndex = 0;
int riaAttributesIndex = 0;
for (int i = 0; i < classFlags.length; i++) {
if (rvaLayout.matches(classFlags[i])) {
classAttributes[i].add(rvaAttributes.get(rvaAttributesIndex++));
}
if (riaLayout.matches(classFlags[i])) {
classAttributes[i].add(riaAttributes.get(riaAttributesIndex++));
}
}
return numBackwardsCalls;
}
public ArrayList[] getClassAttributes() {
return classAttributes;
}
public int[] getClassFieldCount() {
return classFieldCount;
}
public long[] getRawClassFlags() {
return classFlags;
}
public long[] getClassFlags() throws Pack200Exception {
if (classAccessFlags == null) {
long mask = 0x7FFF;
for (int i = 0; i < 16; i++) {
AttributeLayout layout = attrMap.getAttributeLayout(i,
AttributeLayout.CONTEXT_CLASS);
if (layout != null && !layout.isDefaultLayout()) {
mask &= ~(1 << i);
}
}
classAccessFlags = new long[classFlags.length];
for (int i = 0; i < classFlags.length; i++) {
classAccessFlags[i] = classFlags[i] & mask;
}
}
return classAccessFlags;
}
public int[][] getClassInterfacesInts() {
return classInterfacesInts;
}
public int[] getClassMethodCount() {
return classMethodCount;
}
public int[] getClassSuperInts() {
return classSuperInts;
}
public int[] getClassThisInts() {
return classThisInts;
}
public int[] getCodeMaxNALocals() {
return codeMaxNALocals;
}
public int[] getCodeMaxStack() {
return codeMaxStack;
}
public ArrayList[][] getFieldAttributes() {
return fieldAttributes;
}
public int[][] getFieldDescrInts() {
return fieldDescrInts;
}
public int[][] getMethodDescrInts() {
return methodDescrInts;
}
public long[][] getFieldFlags() throws Pack200Exception {
if (fieldAccessFlags == null) {
long mask = 0x7FFF;
for (int i = 0; i < 16; i++) {
AttributeLayout layout = attrMap.getAttributeLayout(i,
AttributeLayout.CONTEXT_FIELD);
if (layout != null && !layout.isDefaultLayout()) {
mask &= ~(1 << i);
}
}
fieldAccessFlags = new long[fieldFlags.length][];
for (int i = 0; i < fieldFlags.length; i++) {
fieldAccessFlags[i] = new long[fieldFlags[i].length];
for (int j = 0; j < fieldFlags[i].length; j++) {
fieldAccessFlags[i][j] = fieldFlags[i][j] & mask;
}
}
}
return fieldAccessFlags;
}
/**
* Answer an ArrayList of ArrayLists which hold the code attributes
* corresponding to all classes in order.
*
* If a class doesn't have any attributes, the corresponding element in this
* list will be an empty ArrayList.
*
* @return ArrayList
*/
public ArrayList getOrderedCodeAttributes() {
ArrayList orderedAttributeList = new ArrayList(codeAttributes.length);
for (int classIndex = 0; classIndex < codeAttributes.length; classIndex++) {
ArrayList currentAttributes = new ArrayList(codeAttributes[classIndex].size());
for (int attributeIndex = 0; attributeIndex < codeAttributes[classIndex]
.size(); attributeIndex++) {
Attribute attribute = (Attribute) codeAttributes[classIndex]
.get(attributeIndex);
currentAttributes.add(attribute);
}
orderedAttributeList.add(currentAttributes);
}
return orderedAttributeList;
}
public ArrayList[][] getMethodAttributes() {
return methodAttributes;
}
public String[][] getMethodDescr() {
return methodDescr;
}
public long[][] getMethodFlags() throws Pack200Exception {
if (methodAccessFlags == null) {
long mask = 0x7FFF;
for (int i = 0; i < 16; i++) {
AttributeLayout layout = attrMap.getAttributeLayout(i,
AttributeLayout.CONTEXT_METHOD);
if (layout != null && !layout.isDefaultLayout()) {
mask &= ~(1 << i);
}
}
methodAccessFlags = new long[methodFlags.length][];
for (int i = 0; i < methodFlags.length; i++) {
methodAccessFlags[i] = new long[methodFlags[i].length];
for (int j = 0; j < methodFlags[i].length; j++) {
methodAccessFlags[i][j] = methodFlags[i][j] & mask;
}
}
}
return methodAccessFlags;
}
/**
* Returns null if all classes should use the default major and minor
* version or an array of integers containing the major version numberss to
* use for each class in the segment
*
* @return Class file major version numbers, or null if none specified
*/
public int[] getClassVersionMajor() {
return classVersionMajor;
}
/**
* Returns null if all classes should use the default major and minor
* version or an array of integers containing the minor version numberss to
* use for each class in the segment
*
* @return Class file minor version numbers, or null if none specified
*/
public int[] getClassVersionMinor() {
return classVersionMinor;
}
public int[] getCodeHandlerCount() {
return codeHandlerCount;
}
public int[][] getCodeHandlerCatchPO() {
return codeHandlerCatchPO;
}
public int[][] getCodeHandlerClassRCN() {
return codeHandlerClassRCN;
}
public int[][] getCodeHandlerEndPO() {
return codeHandlerEndPO;
}
public int[][] getCodeHandlerStartP() {
return codeHandlerStartP;
}
public IcTuple[][] getIcLocal() {
return icLocal;
}
public boolean[] getCodeHasAttributes() {
return codeHasAttributes;
}
}