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