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