ClassBands.java
- /*
- * 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.commons.compress.harmony.unpack200;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
- import org.apache.commons.compress.harmony.pack200.Codec;
- import org.apache.commons.compress.harmony.pack200.Pack200Exception;
- import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
- import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
- import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
- import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
- import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
- import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantValueAttribute;
- import org.apache.commons.compress.harmony.unpack200.bytecode.DeprecatedAttribute;
- import org.apache.commons.compress.harmony.unpack200.bytecode.EnclosingMethodAttribute;
- import org.apache.commons.compress.harmony.unpack200.bytecode.ExceptionsAttribute;
- import org.apache.commons.compress.harmony.unpack200.bytecode.LineNumberTableAttribute;
- import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTableAttribute;
- import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTypeTableAttribute;
- import org.apache.commons.compress.harmony.unpack200.bytecode.SignatureAttribute;
- import org.apache.commons.compress.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<Attribute>[] classAttributes;
- private int[] classVersionMajor;
- private int[] classVersionMinor;
- private IcTuple[][] icLocal;
- private List<Attribute>[] codeAttributes;
- private int[] codeHandlerCount;
- private int[] codeMaxNALocals;
- private int[] codeMaxStack;
- private ArrayList<Attribute>[][] fieldAttributes;
- private String[][] fieldDescr;
- private int[][] fieldDescrInts;
- private long[][] fieldFlags;
- private long[][] fieldAccessFlags;
- private ArrayList<Attribute>[][] 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 TODO
- */
- public ClassBands(final Segment segment) {
- super(segment);
- this.attrMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
- this.cpBands = segment.getCpBands();
- this.classCount = header.getClassCount();
- this.options = header.getOptions();
- }
- private int getCallCount(final int[][] methodAttrIndexes, final long[][] flags, final int context) {
- int callCount = 0;
- for (final int[] element : methodAttrIndexes) {
- for (final int index : element) {
- final AttributeLayout layout = attrMap.getAttributeLayout(index, context);
- callCount += layout.numBackwardsCallables();
- }
- }
- int layoutsUsed = 0;
- for (final long[] flag : flags) {
- for (final long element : flag) {
- layoutsUsed |= element;
- }
- }
- for (int i = 0; i < 26; i++) {
- if ((layoutsUsed & 1 << i) != 0) {
- final AttributeLayout layout = attrMap.getAttributeLayout(i, context);
- callCount += layout.numBackwardsCallables();
- }
- }
- return callCount;
- }
- public ArrayList<Attribute>[] getClassAttributes() {
- return classAttributes;
- }
- public int[] getClassFieldCount() {
- return classFieldCount;
- }
- public long[] getClassFlags() {
- if (classAccessFlags == null) {
- long mask = 0x7FFF;
- for (int i = 0; i < 16; i++) {
- final 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;
- }
- /**
- * 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[][] getCodeHandlerCatchPO() {
- return codeHandlerCatchPO;
- }
- public int[][] getCodeHandlerClassRCN() {
- return codeHandlerClassRCN;
- }
- public int[] getCodeHandlerCount() {
- return codeHandlerCount;
- }
- public int[][] getCodeHandlerEndPO() {
- return codeHandlerEndPO;
- }
- public int[][] getCodeHandlerStartP() {
- return codeHandlerStartP;
- }
- public boolean[] getCodeHasAttributes() {
- return codeHasAttributes;
- }
- public int[] getCodeMaxNALocals() {
- return codeMaxNALocals;
- }
- public int[] getCodeMaxStack() {
- return codeMaxStack;
- }
- public ArrayList<Attribute>[][] getFieldAttributes() {
- return fieldAttributes;
- }
- public int[][] getFieldDescrInts() {
- return fieldDescrInts;
- }
- public long[][] getFieldFlags() {
- if (fieldAccessFlags == null) {
- long mask = 0x7FFF;
- for (int i = 0; i < 16; i++) {
- final 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;
- }
- public IcTuple[][] getIcLocal() {
- return icLocal;
- }
- public ArrayList<Attribute>[][] getMethodAttributes() {
- return methodAttributes;
- }
- public String[][] getMethodDescr() {
- return methodDescr;
- }
- public int[][] getMethodDescrInts() {
- return methodDescrInts;
- }
- public long[][] getMethodFlags() {
- if (methodAccessFlags == null) {
- long mask = 0x7FFF;
- for (int i = 0; i < 16; i++) {
- final 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;
- }
- /**
- * Gets 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<List<Attribute>> getOrderedCodeAttributes() {
- return Stream.of(codeAttributes).map(ArrayList::new).collect(Collectors.toCollection(ArrayList::new));
- }
- public long[] getRawClassFlags() {
- return classFlags;
- }
- private void parseClassAttrBands(final InputStream in) throws IOException, Pack200Exception {
- final String[] cpUTF8 = cpBands.getCpUTF8();
- final String[] cpClass = cpBands.getCpClass();
- // Prepare empty attribute lists
- classAttributes = new ArrayList[classCount];
- Arrays.setAll(classAttributes, i -> new ArrayList<>());
- classFlags = parseFlags("class_flags", in, classCount, Codec.UNSIGNED5, options.hasClassFlagsHi());
- final int classAttrCount = SegmentUtils.countBit16(classFlags);
- final int[] classAttrCounts = decodeBandInt("class_attr_count", in, Codec.UNSIGNED5, classAttrCount);
- final int[][] classAttrIndexes = decodeBandInt("class_attr_indexes", in, Codec.UNSIGNED5, classAttrCounts);
- final int callCount = getCallCount(classAttrIndexes, new long[][] { classFlags }, AttributeLayout.CONTEXT_CLASS);
- final int[] classAttrCalls = decodeBandInt("class_attr_calls", in, Codec.UNSIGNED5, callCount);
- final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_CLASS);
- final AttributeLayout sourceFileLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE, AttributeLayout.CONTEXT_CLASS);
- final int sourceFileCount = SegmentUtils.countMatches(classFlags, sourceFileLayout);
- final int[] classSourceFile = decodeBandInt("class_SourceFile_RUN", in, Codec.UNSIGNED5, sourceFileCount);
- final AttributeLayout enclosingMethodLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ENCLOSING_METHOD, AttributeLayout.CONTEXT_CLASS);
- final int enclosingMethodCount = SegmentUtils.countMatches(classFlags, enclosingMethodLayout);
- final int[] enclosingMethodRC = decodeBandInt("class_EnclosingMethod_RC", in, Codec.UNSIGNED5, enclosingMethodCount);
- final int[] enclosingMethodRDN = decodeBandInt("class_EnclosingMethod_RDN", in, Codec.UNSIGNED5, enclosingMethodCount);
- final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_CLASS);
- final int signatureCount = SegmentUtils.countMatches(classFlags, signatureLayout);
- final int[] classSignature = decodeBandInt("class_Signature_RS", in, Codec.UNSIGNED5, signatureCount);
- final int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls);
- final AttributeLayout innerClassLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_INNER_CLASSES, AttributeLayout.CONTEXT_CLASS);
- final int innerClassCount = SegmentUtils.countMatches(classFlags, innerClassLayout);
- final int[] classInnerClassesN = decodeBandInt("class_InnerClasses_N", in, Codec.UNSIGNED5, innerClassCount);
- final int[][] classInnerClassesRC = decodeBandInt("class_InnerClasses_RC", in, Codec.UNSIGNED5, classInnerClassesN);
- final int[][] classInnerClassesF = decodeBandInt("class_InnerClasses_F", in, Codec.UNSIGNED5, classInnerClassesN);
- int flagsCount = 0;
- for (final int[] element : classInnerClassesF) {
- for (final int element2 : element) {
- if (element2 != 0) {
- flagsCount++;
- }
- }
- }
- final int[] classInnerClassesOuterRCN = decodeBandInt("class_InnerClasses_outer_RCN", in, Codec.UNSIGNED5, flagsCount);
- final int[] classInnerClassesNameRUN = decodeBandInt("class_InnerClasses_name_RUN", in, Codec.UNSIGNED5, flagsCount);
- final AttributeLayout versionLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION, AttributeLayout.CONTEXT_CLASS);
- final int versionCount = SegmentUtils.countMatches(classFlags, versionLayout);
- final int[] classFileVersionMinorH = decodeBandInt("class_file_version_minor_H", in, Codec.UNSIGNED5, versionCount);
- final int[] classFileVersionMajorH = decodeBandInt("class_file_version_major_H", in, Codec.UNSIGNED5, versionCount);
- if (versionCount > 0) {
- classVersionMajor = new int[classCount];
- classVersionMinor = new int[classCount];
- }
- final int defaultVersionMajor = header.getDefaultClassMajorVersion();
- final int defaultVersionMinor = header.getDefaultClassMinorVersion();
- // Parse non-predefined attribute bands
- int backwardsCallIndex = backwardsCallsUsed;
- final int limit = options.hasClassFlagsHi() ? 62 : 31;
- final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
- final int[] counts = new int[limit + 1];
- final List<Attribute>[] otherAttributes = new List[limit + 1];
- for (int i = 0; i < limit; i++) {
- final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS);
- if (layout != null && !layout.isDefaultLayout()) {
- otherLayouts[i] = layout;
- counts[i] = SegmentUtils.countMatches(classFlags, layout);
- }
- }
- for (int i = 0; i < counts.length; i++) {
- if (counts[i] > 0) {
- final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
- otherAttributes[i] = bands.parseAttributes(in, counts[i]);
- final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
- if (numBackwardsCallables > 0) {
- final int[] backwardsCalls = new int[numBackwardsCallables];
- System.arraycopy(classAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
- bands.setBackwardsCalls(backwardsCalls);
- backwardsCallIndex += numBackwardsCallables;
- }
- }
- }
- // Now process the attribute bands we have parsed
- int sourceFileIndex = 0;
- int enclosingMethodIndex = 0;
- int signatureIndex = 0;
- int innerClassIndex = 0;
- int innerClassC2NIndex = 0;
- int versionIndex = 0;
- icLocal = new IcTuple[classCount][];
- for (int i = 0; i < classCount; i++) {
- final long flag = classFlags[i];
- if (deprecatedLayout.matches(classFlags[i])) {
- classAttributes[i].add(new DeprecatedAttribute());
- }
- if (sourceFileLayout.matches(flag)) {
- final long result = classSourceFile[sourceFileIndex];
- ClassFileEntry value = sourceFileLayout.getValue(result, cpBands.getConstantPool());
- if (value == null) {
- // Remove package prefix
- String className = classThis[i].substring(classThis[i].lastIndexOf('/') + 1);
- className = className.substring(className.lastIndexOf('.') + 1);
- // Remove mangled nested class names
- final char[] chars = className.toCharArray();
- int index = -1;
- for (int j = 0; j < chars.length; j++) {
- if (chars[j] <= 0x2D) {
- index = j;
- break;
- }
- }
- if (index > -1) {
- className = className.substring(0, index);
- }
- // Add .java to the end
- value = cpBands.cpUTF8Value(className + ".java", true);
- }
- classAttributes[i].add(new SourceFileAttribute((CPUTF8) value));
- sourceFileIndex++;
- }
- if (enclosingMethodLayout.matches(flag)) {
- final CPClass theClass = cpBands.cpClassValue(enclosingMethodRC[enclosingMethodIndex]);
- CPNameAndType theMethod = null;
- if (enclosingMethodRDN[enclosingMethodIndex] != 0) {
- theMethod = cpBands.cpNameAndTypeValue(enclosingMethodRDN[enclosingMethodIndex] - 1);
- }
- classAttributes[i].add(new EnclosingMethodAttribute(theClass, theMethod));
- enclosingMethodIndex++;
- }
- if (signatureLayout.matches(flag)) {
- final long result = classSignature[signatureIndex];
- final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, cpBands.getConstantPool());
- classAttributes[i].add(new SignatureAttribute(value));
- signatureIndex++;
- }
- if (innerClassLayout.matches(flag)) {
- // Just create the tuples for now because the attributes are
- // decided at the end when creating class constant pools
- icLocal[i] = new IcTuple[classInnerClassesN[innerClassIndex]];
- for (int j = 0; j < icLocal[i].length; j++) {
- final int icTupleCIndex = classInnerClassesRC[innerClassIndex][j];
- int icTupleC2Index = -1;
- int icTupleNIndex = -1;
- final String icTupleC = cpClass[icTupleCIndex];
- int icTupleF = classInnerClassesF[innerClassIndex][j];
- String icTupleC2 = null;
- String icTupleN = null;
- if (icTupleF != 0) {
- icTupleC2Index = classInnerClassesOuterRCN[innerClassC2NIndex];
- icTupleNIndex = classInnerClassesNameRUN[innerClassC2NIndex];
- icTupleC2 = cpClass[icTupleC2Index];
- icTupleN = cpUTF8[icTupleNIndex];
- innerClassC2NIndex++;
- } else {
- // Get from icBands
- final IcBands icBands = segment.getIcBands();
- final IcTuple[] icAll = icBands.getIcTuples();
- for (final IcTuple element : icAll) {
- if (element.getC().equals(icTupleC)) {
- icTupleF = element.getF();
- icTupleC2 = element.getC2();
- icTupleN = element.getN();
- break;
- }
- }
- }
- final IcTuple icTuple = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN, icTupleCIndex, icTupleC2Index, icTupleNIndex, j);
- icLocal[i][j] = icTuple;
- }
- innerClassIndex++;
- }
- if (versionLayout.matches(flag)) {
- classVersionMajor[i] = classFileVersionMajorH[versionIndex];
- classVersionMinor[i] = classFileVersionMinorH[versionIndex];
- versionIndex++;
- } else if (classVersionMajor != null) {
- // Fill in with defaults
- classVersionMajor[i] = defaultVersionMajor;
- classVersionMinor[i] = defaultVersionMinor;
- }
- // Non-predefined attributes
- for (int j = 0; j < otherLayouts.length; j++) {
- if (otherLayouts[j] != null && otherLayouts[j].matches(flag)) {
- // Add the next attribute
- classAttributes[i].add(otherAttributes[j].get(0));
- otherAttributes[j].remove(0);
- }
- }
- }
- }
- /**
- * Parse the class metadata bands and return the number of backwards callables.
- *
- * @param in TODO
- * @param classAttrCalls TODO
- * @return the number of backwards callables.
- * @throws Pack200Exception TODO
- * @throws IOException If an I/O error occurs.
- */
- private int parseClassMetadataBands(final InputStream in, final int[] classAttrCalls) throws Pack200Exception, IOException {
- int numBackwardsCalls = 0;
- final String[] RxA = { "RVA", "RIA" };
- final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS);
- final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS);
- final int rvaCount = SegmentUtils.countMatches(classFlags, rvaLayout);
- final int riaCount = SegmentUtils.countMatches(classFlags, riaLayout);
- final int[] RxACount = { rvaCount, riaCount };
- final int[] backwardsCalls = { 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];
- }
- final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, RxACount, backwardsCalls, "class");
- final List<Attribute> rvaAttributes = mbgs[0].getAttributes();
- final List<Attribute> 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;
- }
- private void parseCodeAttrBands(final InputStream in, final int codeFlagsCount) throws IOException, Pack200Exception {
- final long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount, Codec.UNSIGNED5, segment.getSegmentHeader().getOptions().hasCodeFlagsHi());
- final int codeAttrCount = SegmentUtils.countBit16(codeFlags);
- final int[] codeAttrCounts = decodeBandInt("code_attr_count", in, Codec.UNSIGNED5, codeAttrCount);
- final int[][] codeAttrIndexes = decodeBandInt("code_attr_indexes", in, Codec.UNSIGNED5, codeAttrCounts);
- int callCount = 0;
- for (final int[] element : codeAttrIndexes) {
- for (final int index : element) {
- final AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_CODE);
- callCount += layout.numBackwardsCallables();
- }
- }
- final int[] codeAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5, callCount);
- final AttributeLayout lineNumberTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE);
- final int lineNumberTableCount = SegmentUtils.countMatches(codeFlags, lineNumberTableLayout);
- final int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in, Codec.UNSIGNED5, lineNumberTableCount);
- final int[][] lineNumberTableBciP = decodeBandInt("code_LineNumberTable_bci_P", in, Codec.BCI5, lineNumberTableN);
- final int[][] lineNumberTableLine = decodeBandInt("code_LineNumberTable_line", in, Codec.UNSIGNED5, lineNumberTableN);
- final AttributeLayout localVariableTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE,
- AttributeLayout.CONTEXT_CODE);
- final AttributeLayout localVariableTypeTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE,
- AttributeLayout.CONTEXT_CODE);
- final int lengthLocalVariableNBand = SegmentUtils.countMatches(codeFlags, localVariableTableLayout);
- final int[] localVariableTableN = decodeBandInt("code_LocalVariableTable_N", in, Codec.UNSIGNED5, lengthLocalVariableNBand);
- final int[][] localVariableTableBciP = decodeBandInt("code_LocalVariableTable_bci_P", in, Codec.BCI5, localVariableTableN);
- final int[][] localVariableTableSpanO = decodeBandInt("code_LocalVariableTable_span_O", in, Codec.BRANCH5, localVariableTableN);
- final CPUTF8[][] localVariableTableNameRU = parseCPUTF8References("code_LocalVariableTable_name_RU", in, Codec.UNSIGNED5, localVariableTableN);
- final CPUTF8[][] localVariableTableTypeRS = parseCPSignatureReferences("code_LocalVariableTable_type_RS", in, Codec.UNSIGNED5, localVariableTableN);
- final int[][] localVariableTableSlot = decodeBandInt("code_LocalVariableTable_slot", in, Codec.UNSIGNED5, localVariableTableN);
- final int lengthLocalVariableTypeTableNBand = SegmentUtils.countMatches(codeFlags, localVariableTypeTableLayout);
- final int[] localVariableTypeTableN = decodeBandInt("code_LocalVariableTypeTable_N", in, Codec.UNSIGNED5, lengthLocalVariableTypeTableNBand);
- final int[][] localVariableTypeTableBciP = decodeBandInt("code_LocalVariableTypeTable_bci_P", in, Codec.BCI5, localVariableTypeTableN);
- final int[][] localVariableTypeTableSpanO = decodeBandInt("code_LocalVariableTypeTable_span_O", in, Codec.BRANCH5, localVariableTypeTableN);
- final CPUTF8[][] localVariableTypeTableNameRU = parseCPUTF8References("code_LocalVariableTypeTable_name_RU", in, Codec.UNSIGNED5,
- localVariableTypeTableN);
- final CPUTF8[][] localVariableTypeTableTypeRS = parseCPSignatureReferences("code_LocalVariableTypeTable_type_RS", in, Codec.UNSIGNED5,
- localVariableTypeTableN);
- final int[][] localVariableTypeTableSlot = decodeBandInt("code_LocalVariableTypeTable_slot", in, Codec.UNSIGNED5, localVariableTypeTableN);
- // Parse non-predefined attribute bands
- int backwardsCallIndex = 0;
- final int limit = options.hasCodeFlagsHi() ? 62 : 31;
- final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
- final int[] counts = new int[limit + 1];
- final List<Attribute>[] otherAttributes = new List[limit + 1];
- for (int i = 0; i < limit; i++) {
- final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_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) {
- final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
- otherAttributes[i] = bands.parseAttributes(in, counts[i]);
- final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
- if (numBackwardsCallables > 0) {
- final int[] backwardsCalls = new int[numBackwardsCallables];
- System.arraycopy(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])) {
- final LineNumberTableAttribute lnta = new LineNumberTableAttribute(lineNumberTableN[lineNumberIndex], lineNumberTableBciP[lineNumberIndex],
- lineNumberTableLine[lineNumberIndex]);
- lineNumberIndex++;
- codeAttributes[i].add(lnta);
- }
- if (localVariableTableLayout.matches(codeFlags[i])) {
- final 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])) {
- final 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 void parseCodeBands(final InputStream in) throws Pack200Exception, IOException {
- final AttributeLayout layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD);
- final int codeCount = SegmentUtils.countMatches(methodFlags, layout);
- final int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1, codeCount);
- final 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;
- }
- }
- }
- final int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in, Codec.UNSIGNED5, codeSpecialHeader);
- final int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in, Codec.UNSIGNED5, codeSpecialHeader);
- final 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++) {
- final int header = 0xff & codeHeaders[i];
- if (header < 0) {
- throw new IllegalStateException("Shouldn't get here");
- }
- 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);
- final int codeFlagsCount = allCodeHasFlags ? codeCount : codeSpecialHeader;
- codeAttributes = new List[codeFlagsCount];
- Arrays.setAll(codeAttributes, i -> new ArrayList<>());
- parseCodeAttrBands(in, codeFlagsCount);
- }
- private void parseFieldAttrBands(final InputStream in) throws IOException, Pack200Exception {
- fieldFlags = parseFlags("field_flags", in, classFieldCount, Codec.UNSIGNED5, options.hasFieldFlagsHi());
- final int fieldAttrCount = SegmentUtils.countBit16(fieldFlags);
- final int[] fieldAttrCounts = decodeBandInt("field_attr_count", in, Codec.UNSIGNED5, fieldAttrCount);
- final int[][] fieldAttrIndexes = decodeBandInt("field_attr_indexes", in, Codec.UNSIGNED5, fieldAttrCounts);
- final int callCount = getCallCount(fieldAttrIndexes, fieldFlags, AttributeLayout.CONTEXT_FIELD);
- final 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<>();
- }
- }
- final AttributeLayout constantValueLayout = attrMap.getAttributeLayout("ConstantValue", AttributeLayout.CONTEXT_FIELD);
- final int constantCount = SegmentUtils.countMatches(fieldFlags, constantValueLayout);
- final int[] field_constantValue_KQ = decodeBandInt("field_ConstantValue_KQ", in, Codec.UNSIGNED5, constantCount);
- int constantValueIndex = 0;
- final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_FIELD);
- final int signatureCount = SegmentUtils.countMatches(fieldFlags, signatureLayout);
- final int[] fieldSignatureRS = decodeBandInt("field_Signature_RS", in, Codec.UNSIGNED5, signatureCount);
- int signatureIndex = 0;
- final 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++) {
- final 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
- final long result = field_constantValue_KQ[constantValueIndex];
- final String desc = fieldDescr[i][j];
- final 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";
- }
- final 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
- final long result = fieldSignatureRS[signatureIndex];
- final String desc = fieldDescr[i][j];
- final int colon = desc.indexOf(':');
- final String type = desc.substring(colon + 1);
- final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, type, cpBands.getConstantPool());
- fieldAttributes[i][j].add(new SignatureAttribute(value));
- signatureIndex++;
- }
- }
- }
- // Parse non-predefined attribute bands
- int backwardsCallIndex = parseFieldMetadataBands(in, fieldAttrCalls);
- final int limit = options.hasFieldFlagsHi() ? 62 : 31;
- final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
- final int[] counts = new int[limit + 1];
- final List<Attribute>[] otherAttributes = new List[limit + 1];
- for (int i = 0; i < limit; i++) {
- final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_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) {
- final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
- otherAttributes[i] = bands.parseAttributes(in, counts[i]);
- final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
- if (numBackwardsCallables > 0) {
- final int[] backwardsCalls = new int[numBackwardsCallables];
- System.arraycopy(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++) {
- final 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 parseFieldBands(final InputStream in) throws IOException, Pack200Exception {
- fieldDescrInts = decodeBandInt("field_descr", in, Codec.DELTA5, classFieldCount);
- fieldDescr = getReferences(fieldDescrInts, cpBands.getCpDescriptor());
- parseFieldAttrBands(in);
- }
- private int parseFieldMetadataBands(final InputStream in, final int[] fieldAttrCalls) throws Pack200Exception, IOException {
- int backwardsCallsUsed = 0;
- final String[] RxA = { "RVA", "RIA" };
- final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD);
- final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD);
- final int rvaCount = SegmentUtils.countMatches(fieldFlags, rvaLayout);
- final int riaCount = SegmentUtils.countMatches(fieldFlags, riaLayout);
- final int[] RxACount = { rvaCount, riaCount };
- final int[] backwardsCalls = { 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++;
- }
- final MetadataBandGroup[] mb = parseMetadata(in, RxA, RxACount, backwardsCalls, "field");
- final List<Attribute> rvaAttributes = mb[0].getAttributes();
- final List<Attribute> 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(final InputStream in, final String[] RxA, final int[] RxACount, final int[] backwardsCallCounts,
- final String contextName) throws IOException, Pack200Exception {
- final MetadataBandGroup[] mbg = new MetadataBandGroup[RxA.length];
- for (int i = 0; i < RxA.length; i++) {
- mbg[i] = new MetadataBandGroup(RxA[i], cpBands);
- final 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 (final int[] element : mbg[i].pair_N) {
- for (final int element2 : element) {
- pairCount += element2;
- }
- }
- mbg[i].name_RU = parseCPUTF8References(contextName + "_" + rxa + "_name_RU", in, Codec.UNSIGNED5, pairCount);
- } else {
- pairCount = RxACount[i];
- }
- 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 (final int element : mbg[i].T) {
- final char c = (char) element;
- 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 = parseCPSignatureReferences(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 (final int element : mbg[i].nestpair_N) {
- nestPairCount += element;
- }
- mbg[i].nestname_RU = parseCPUTF8References(contextName + "_" + rxa + "_nestname_RU", in, Codec.UNSIGNED5, nestPairCount);
- }
- return mbg;
- }
- private void parseMethodAttrBands(final InputStream in) throws IOException, Pack200Exception {
- methodFlags = parseFlags("method_flags", in, classMethodCount, Codec.UNSIGNED5, options.hasMethodFlagsHi());
- final int methodAttrCount = SegmentUtils.countBit16(methodFlags);
- final int[] methodAttrCounts = decodeBandInt("method_attr_count", in, Codec.UNSIGNED5, methodAttrCount);
- final int[][] methodAttrIndexes = decodeBandInt("method_attr_indexes", in, Codec.UNSIGNED5, methodAttrCounts);
- final 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
- final AttributeLayout methodExceptionsLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS, AttributeLayout.CONTEXT_METHOD);
- final int count = SegmentUtils.countMatches(methodFlags, methodExceptionsLayout);
- final int[] numExceptions = decodeBandInt("method_Exceptions_n", in, Codec.UNSIGNED5, count);
- final int[][] methodExceptionsRS = decodeBandInt("method_Exceptions_RC", in, Codec.UNSIGNED5, numExceptions);
- // Parse method signature attributes
- final AttributeLayout methodSignatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_METHOD);
- final int count1 = SegmentUtils.countMatches(methodFlags, methodSignatureLayout);
- final int[] methodSignatureRS = decodeBandInt("method_signature_RS", in, Codec.UNSIGNED5, count1);
- final 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++) {
- final long flag = methodFlags[i][j];
- if (methodExceptionsLayout.matches(flag)) {
- final int n = numExceptions[methodExceptionsIndex];
- final int[] exceptions = methodExceptionsRS[methodExceptionsIndex];
- final 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
- final long result = methodSignatureRS[methodSignatureIndex];
- final String desc = methodDescr[i][j];
- final 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";
- }
- final 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 non-predefined attribute bands
- int backwardsCallIndex = parseMethodMetadataBands(in, methodAttrCalls);
- final int limit = options.hasMethodFlagsHi() ? 62 : 31;
- final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
- final int[] counts = new int[limit + 1];
- for (int i = 0; i < limit; i++) {
- final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD);
- if (layout != null && !layout.isDefaultLayout()) {
- otherLayouts[i] = layout;
- counts[i] = SegmentUtils.countMatches(methodFlags, layout);
- }
- }
- final List<Attribute>[] otherAttributes = new List[limit + 1];
- for (int i = 0; i < counts.length; i++) {
- if (counts[i] > 0) {
- final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
- otherAttributes[i] = bands.parseAttributes(in, counts[i]);
- final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
- if (numBackwardsCallables > 0) {
- final int[] backwardsCalls = new int[numBackwardsCallables];
- System.arraycopy(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++) {
- final 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 void parseMethodBands(final InputStream in) throws IOException, Pack200Exception {
- methodDescrInts = decodeBandInt("method_descr", in, Codec.MDELTA5, classMethodCount);
- methodDescr = getReferences(methodDescrInts, cpBands.getCpDescriptor());
- parseMethodAttrBands(in);
- }
- private int parseMethodMetadataBands(final InputStream in, final int[] methodAttrCalls) throws Pack200Exception, IOException {
- int backwardsCallsUsed = 0;
- final String[] RxA = { "RVA", "RIA", "RVPA", "RIPA", "AD" };
- final int[] rxaCounts = { 0, 0, 0, 0, 0 };
- final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
- final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
- final AttributeLayout rvpaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
- AttributeLayout.CONTEXT_METHOD);
- final AttributeLayout ripaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS,
- AttributeLayout.CONTEXT_METHOD);
- final AttributeLayout adLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT, AttributeLayout.CONTEXT_METHOD);
- final AttributeLayout[] rxaLayouts = { rvaLayout, riaLayout, rvpaLayout, ripaLayout, adLayout };
- Arrays.setAll(rxaCounts, i -> SegmentUtils.countMatches(methodFlags, rxaLayouts[i]));
- final 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;
- }
- }
- final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, rxaCounts, backwardsCalls, "method");
- final List<Attribute>[] attributeLists = new List[RxA.length];
- final 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;
- }
- /*
- * (non-Javadoc)
- *
- * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream)
- */
- @Override
- public void read(final InputStream in) throws IOException, Pack200Exception {
- final 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);
- final 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);
- }
- @Override
- public void unpack() {
- }
- }