All Downloads are FREE. Search and download functionalities are using the official Maven repository.

proguard.classfile.io.ProgramClassReader Maven / Gradle / Ivy

Go to download

ProGuardCORE is a free library to read, analyze, modify, and write Java class files.

There is a newer version: 9.1.6
Show newest version
/*
 * ProGuardCORE -- library to process Java bytecode.
 *
 * Copyright (c) 2002-2020 Guardsquare NV
 *
 * Licensed 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 proguard.classfile.io;

import java.io.DataInput;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.annotation.target.*;
import proguard.classfile.attribute.annotation.target.visitor.*;
import proguard.classfile.attribute.annotation.visitor.*;
import proguard.classfile.attribute.module.*;
import proguard.classfile.attribute.module.visitor.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.attribute.preverification.visitor.*;
import proguard.classfile.attribute.visitor.*;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.*;
import proguard.io.RuntimeDataInput;

/**
 * This {@link ClassVisitor} fills out the {@link ProgramClass} instances that it visits with data
 * from the given {@link DataInput} object.
 *
 * @author Eric Lafortune
 */
public class ProgramClassReader
    implements ClassVisitor,
        MemberVisitor,
        ConstantVisitor,
        AttributeVisitor,
        BootstrapMethodInfoVisitor,
        RecordComponentInfoVisitor,
        InnerClassesInfoVisitor,
        ExceptionInfoVisitor,
        StackMapFrameVisitor,
        VerificationTypeVisitor,
        LineNumberInfoVisitor,
        ParameterInfoVisitor,
        LocalVariableInfoVisitor,
        LocalVariableTypeInfoVisitor,
        RequiresInfoVisitor,
        ExportsInfoVisitor,
        OpensInfoVisitor,
        ProvidesInfoVisitor,
        AnnotationVisitor,
        TypeAnnotationVisitor,
        TargetInfoVisitor,
        TypePathInfoVisitor,
        LocalVariableTargetElementVisitor,
        ElementValueVisitor {
  private final RuntimeDataInput dataInput;
  private final boolean ignoreStackMapAttributes;

  /** Creates a new ProgramClassReader for reading from the given DataInput. */
  public ProgramClassReader(DataInput dataInput) {
    this(dataInput, false);
  }

  /**
   * Creates a new ProgramClassReader for reading from the given DataInput, optionally treating
   * stack map attributes as unknown attributes.
   */
  public ProgramClassReader(DataInput dataInput, boolean ignoreStackMapAttributes) {
    this.dataInput = new RuntimeDataInput(dataInput);
    this.ignoreStackMapAttributes = ignoreStackMapAttributes;
  }

  // Implementations for ClassVisitor.

  @Override
  public void visitAnyClass(Clazz clazz) {}

  @Override
  public void visitProgramClass(ProgramClass programClass) {
    // Read and check the magic number.
    int u4magic = dataInput.readInt();

    ClassUtil.checkMagicNumber(u4magic);

    // Read and check the version numbers.
    int u2minorVersion = dataInput.readUnsignedShort();
    int u2majorVersion = dataInput.readUnsignedShort();

    programClass.u4version = ClassUtil.internalClassVersion(u2majorVersion, u2minorVersion);

    ClassUtil.checkVersionNumbers(programClass.u4version);

    // Read the constant pool. Note that the first entry is not used.
    programClass.u2constantPoolCount = dataInput.readUnsignedShort();

    programClass.constantPool = new Constant[programClass.u2constantPoolCount];
    for (int index = 1; index < programClass.u2constantPoolCount; index++) {
      Constant constant = createConstant();
      constant.accept(programClass, this);
      programClass.constantPool[index] = constant;

      // Long constants and double constants take up two entries in the
      // constant pool.
      int tag = constant.getTag();
      if (tag == Constant.LONG || tag == Constant.DOUBLE) {
        programClass.constantPool[++index] = null;
      }
    }

    // Read the general class information.
    programClass.u2accessFlags = dataInput.readUnsignedShort();
    programClass.u2thisClass = dataInput.readUnsignedShort();
    programClass.u2superClass = dataInput.readUnsignedShort();

    // Read the interfaces.
    programClass.u2interfacesCount = dataInput.readUnsignedShort();
    programClass.u2interfaces = readUnsignedShorts(programClass.u2interfacesCount);

    // Read the fields.
    programClass.u2fieldsCount = dataInput.readUnsignedShort();

    programClass.fields = new ProgramField[programClass.u2fieldsCount];
    for (int index = 0; index < programClass.u2fieldsCount; index++) {
      ProgramField programField = new ProgramField();
      this.visitProgramField(programClass, programField);
      programClass.fields[index] = programField;
    }

    // Read the methods.
    programClass.u2methodsCount = dataInput.readUnsignedShort();

    programClass.methods = new ProgramMethod[programClass.u2methodsCount];
    for (int index = 0; index < programClass.u2methodsCount; index++) {
      ProgramMethod programMethod = new ProgramMethod();
      this.visitProgramMethod(programClass, programMethod);
      programClass.methods[index] = programMethod;
    }

    // Read the class attributes.
    programClass.u2attributesCount = dataInput.readUnsignedShort();

    programClass.attributes = new Attribute[programClass.u2attributesCount];
    for (int index = 0; index < programClass.u2attributesCount; index++) {
      Attribute attribute = createAttribute(programClass);
      attribute.accept(programClass, this);
      programClass.attributes[index] = attribute;
    }
  }

  // Implementations for MemberVisitor.

  public void visitProgramField(ProgramClass programClass, ProgramField programField) {
    // Read the general field information.
    programField.u2accessFlags = dataInput.readUnsignedShort();
    programField.u2nameIndex = dataInput.readUnsignedShort();
    programField.u2descriptorIndex = dataInput.readUnsignedShort();

    // Read the field attributes.
    programField.u2attributesCount = dataInput.readUnsignedShort();

    programField.attributes = new Attribute[programField.u2attributesCount];
    for (int index = 0; index < programField.u2attributesCount; index++) {
      Attribute attribute = createAttribute(programClass);
      attribute.accept(programClass, programField, this);
      programField.attributes[index] = attribute;
    }
  }

  public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) {
    // Read the general method information.
    programMethod.u2accessFlags = dataInput.readUnsignedShort();
    programMethod.u2nameIndex = dataInput.readUnsignedShort();
    programMethod.u2descriptorIndex = dataInput.readUnsignedShort();

    // Read the method attributes.
    programMethod.u2attributesCount = dataInput.readUnsignedShort();

    programMethod.attributes = new Attribute[programMethod.u2attributesCount];
    for (int index = 0; index < programMethod.u2attributesCount; index++) {
      Attribute attribute = createAttribute(programClass);
      attribute.accept(programClass, programMethod, this);
      programMethod.attributes[index] = attribute;
    }
  }

  public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {}

  // Implementations for ConstantVisitor.

  public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) {
    integerConstant.u4value = dataInput.readInt();
  }

  public void visitLongConstant(Clazz clazz, LongConstant longConstant) {
    longConstant.u8value = dataInput.readLong();
  }

  public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) {
    floatConstant.f4value = dataInput.readFloat();
  }

  public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) {
    doubleConstant.f8value = dataInput.readDouble();
  }

  public void visitPrimitiveArrayConstant(
      Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant) {
    char u2primitiveType = dataInput.readChar();
    int u4length = dataInput.readInt();

    switch (u2primitiveType) {
      case TypeConstants.BOOLEAN:
        {
          boolean[] values = new boolean[u4length];

          for (int index = 0; index < u4length; index++) {
            values[index] = dataInput.readBoolean();
          }

          primitiveArrayConstant.values = values;
          break;
        }
      case TypeConstants.BYTE:
        {
          byte[] values = new byte[u4length];
          dataInput.readFully(values);

          primitiveArrayConstant.values = values;
          break;
        }
      case TypeConstants.CHAR:
        {
          char[] values = new char[u4length];

          for (int index = 0; index < u4length; index++) {
            values[index] = dataInput.readChar();
          }

          primitiveArrayConstant.values = values;
          break;
        }
      case TypeConstants.SHORT:
        {
          short[] values = new short[u4length];

          for (int index = 0; index < u4length; index++) {
            values[index] = dataInput.readShort();
          }

          primitiveArrayConstant.values = values;
          break;
        }
      case TypeConstants.INT:
        {
          int[] values = new int[u4length];

          for (int index = 0; index < u4length; index++) {
            values[index] = dataInput.readInt();
          }

          primitiveArrayConstant.values = values;
          break;
        }
      case TypeConstants.FLOAT:
        {
          float[] values = new float[u4length];

          for (int index = 0; index < u4length; index++) {
            values[index] = dataInput.readFloat();
          }

          primitiveArrayConstant.values = values;
          break;
        }
      case TypeConstants.LONG:
        {
          long[] values = new long[u4length];

          for (int index = 0; index < u4length; index++) {
            values[index] = dataInput.readLong();
          }

          primitiveArrayConstant.values = values;
          break;
        }
      case TypeConstants.DOUBLE:
        {
          double[] values = new double[u4length];

          for (int index = 0; index < u4length; index++) {
            values[index] = dataInput.readDouble();
          }

          primitiveArrayConstant.values = values;
          break;
        }
    }
  }

  public void visitStringConstant(Clazz clazz, StringConstant stringConstant) {
    stringConstant.u2stringIndex = dataInput.readUnsignedShort();
  }

  public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) {
    int u2length = dataInput.readUnsignedShort();

    // Read the UTF-8 bytes.
    byte[] bytes = new byte[u2length];
    dataInput.readFully(bytes);
    utf8Constant.setBytes(bytes);
  }

  public void visitDynamicConstant(Clazz clazz, DynamicConstant dynamicConstant) {
    dynamicConstant.u2bootstrapMethodAttributeIndex = dataInput.readUnsignedShort();
    dynamicConstant.u2nameAndTypeIndex = dataInput.readUnsignedShort();
  }

  public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) {
    invokeDynamicConstant.u2bootstrapMethodAttributeIndex = dataInput.readUnsignedShort();
    invokeDynamicConstant.u2nameAndTypeIndex = dataInput.readUnsignedShort();
  }

  public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) {
    methodHandleConstant.u1referenceKind = dataInput.readUnsignedByte();
    methodHandleConstant.u2referenceIndex = dataInput.readUnsignedShort();
  }

  public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant) {
    moduleConstant.u2nameIndex = dataInput.readUnsignedShort();
  }

  public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant) {
    packageConstant.u2nameIndex = dataInput.readUnsignedShort();
  }

  public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) {
    refConstant.u2classIndex = dataInput.readUnsignedShort();
    refConstant.u2nameAndTypeIndex = dataInput.readUnsignedShort();
  }

  public void visitClassConstant(Clazz clazz, ClassConstant classConstant) {
    classConstant.u2nameIndex = dataInput.readUnsignedShort();
  }

  public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) {
    methodTypeConstant.u2descriptorIndex = dataInput.readUnsignedShort();
  }

  public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) {
    nameAndTypeConstant.u2nameIndex = dataInput.readUnsignedShort();
    nameAndTypeConstant.u2descriptorIndex = dataInput.readUnsignedShort();
  }

  // Implementations for AttributeVisitor.

  public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) {
    // Read the unknown information.
    byte[] info = new byte[unknownAttribute.u4attributeLength];
    dataInput.readFully(info);

    unknownAttribute.info = info;
  }

  public void visitBootstrapMethodsAttribute(
      Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) {
    // Read the bootstrap methods.
    bootstrapMethodsAttribute.u2bootstrapMethodsCount = dataInput.readUnsignedShort();

    bootstrapMethodsAttribute.bootstrapMethods =
        new BootstrapMethodInfo[bootstrapMethodsAttribute.u2bootstrapMethodsCount];
    for (int index = 0; index < bootstrapMethodsAttribute.u2bootstrapMethodsCount; index++) {
      BootstrapMethodInfo bootstrapMethodInfo = new BootstrapMethodInfo();
      visitBootstrapMethodInfo(clazz, bootstrapMethodInfo);
      bootstrapMethodsAttribute.bootstrapMethods[index] = bootstrapMethodInfo;
    }
  }

  public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) {
    sourceFileAttribute.u2sourceFileIndex = dataInput.readUnsignedShort();
  }

  public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) {
    sourceDirAttribute.u2sourceDirIndex = dataInput.readUnsignedShort();
  }

  public void visitSourceDebugExtensionAttribute(
      Clazz clazz, SourceDebugExtensionAttribute sourceDebugExtensionAttribute) {
    // Read the source debug extension information.
    byte[] info = new byte[sourceDebugExtensionAttribute.u4attributeLength];
    dataInput.readFully(info);
    sourceDebugExtensionAttribute.info = info;
  }

  public void visitRecordAttribute(Clazz clazz, RecordAttribute recordAttribute) {
    // Read the components.
    recordAttribute.u2componentsCount = dataInput.readUnsignedShort();

    recordAttribute.components = new RecordComponentInfo[recordAttribute.u2componentsCount];
    for (int index = 0; index < recordAttribute.u2componentsCount; index++) {
      RecordComponentInfo recordComponentInfo = new RecordComponentInfo();
      visitRecordComponentInfo(clazz, recordComponentInfo);
      recordAttribute.components[index] = recordComponentInfo;
    }
  }

  public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) {
    // Read the inner classes.
    innerClassesAttribute.u2classesCount = dataInput.readUnsignedShort();

    innerClassesAttribute.classes = new InnerClassesInfo[innerClassesAttribute.u2classesCount];
    for (int index = 0; index < innerClassesAttribute.u2classesCount; index++) {
      InnerClassesInfo innerClassesInfo = new InnerClassesInfo();
      visitInnerClassesInfo(clazz, innerClassesInfo);
      innerClassesAttribute.classes[index] = innerClassesInfo;
    }
  }

  public void visitEnclosingMethodAttribute(
      Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) {
    enclosingMethodAttribute.u2classIndex = dataInput.readUnsignedShort();
    enclosingMethodAttribute.u2nameAndTypeIndex = dataInput.readUnsignedShort();
  }

  public void visitNestHostAttribute(Clazz clazz, NestHostAttribute nestHostAttribute) {
    nestHostAttribute.u2hostClassIndex = dataInput.readUnsignedShort();
  }

  public void visitNestMembersAttribute(Clazz clazz, NestMembersAttribute nestMembersAttribute) {
    // Read the nest host classes.
    nestMembersAttribute.u2classesCount = dataInput.readUnsignedShort();
    nestMembersAttribute.u2classes = readUnsignedShorts(nestMembersAttribute.u2classesCount);
  }

  public void visitPermittedSubclassesAttribute(
      Clazz clazz, PermittedSubclassesAttribute permittedSubclassesAttribute) {
    // Read the nest host classes.
    permittedSubclassesAttribute.u2classesCount = dataInput.readUnsignedShort();
    permittedSubclassesAttribute.u2classes =
        readUnsignedShorts(permittedSubclassesAttribute.u2classesCount);
  }

  public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute) {
    moduleAttribute.u2moduleNameIndex = dataInput.readUnsignedShort();
    moduleAttribute.u2moduleFlags = dataInput.readUnsignedShort();
    moduleAttribute.u2moduleVersionIndex = dataInput.readUnsignedShort();

    // Read the requires.
    moduleAttribute.u2requiresCount = dataInput.readUnsignedShort();

    moduleAttribute.requires = new RequiresInfo[moduleAttribute.u2requiresCount];
    for (int index = 0; index < moduleAttribute.u2requiresCount; index++) {
      RequiresInfo requiresInfo = new RequiresInfo();
      visitRequiresInfo(clazz, requiresInfo);
      moduleAttribute.requires[index] = requiresInfo;
    }

    // Read the exports.
    moduleAttribute.u2exportsCount = dataInput.readUnsignedShort();

    moduleAttribute.exports = new ExportsInfo[moduleAttribute.u2exportsCount];
    for (int index = 0; index < moduleAttribute.u2exportsCount; index++) {
      ExportsInfo exportsInfo = new ExportsInfo();
      visitExportsInfo(clazz, exportsInfo);
      moduleAttribute.exports[index] = exportsInfo;
    }

    // Read the opens.
    moduleAttribute.u2opensCount = dataInput.readUnsignedShort();

    moduleAttribute.opens = new OpensInfo[moduleAttribute.u2opensCount];
    for (int index = 0; index < moduleAttribute.u2opensCount; index++) {
      OpensInfo opensInfo = new OpensInfo();
      visitOpensInfo(clazz, opensInfo);
      moduleAttribute.opens[index] = opensInfo;
    }

    // Read the uses.
    moduleAttribute.u2usesCount = dataInput.readUnsignedShort();
    moduleAttribute.u2uses = readUnsignedShorts(moduleAttribute.u2usesCount);

    // Read the provides.
    moduleAttribute.u2providesCount = dataInput.readUnsignedShort();

    moduleAttribute.provides = new ProvidesInfo[moduleAttribute.u2providesCount];
    for (int index = 0; index < moduleAttribute.u2providesCount; index++) {
      ProvidesInfo providesInfo = new ProvidesInfo();
      visitProvidesInfo(clazz, providesInfo);
      moduleAttribute.provides[index] = providesInfo;
    }
  }

  public void visitModuleMainClassAttribute(
      Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute) {
    moduleMainClassAttribute.u2mainClass = dataInput.readUnsignedShort();
  }

  public void visitModulePackagesAttribute(
      Clazz clazz, ModulePackagesAttribute modulePackagesAttribute) {
    // Read the packages.
    modulePackagesAttribute.u2packagesCount = dataInput.readUnsignedShort();
    modulePackagesAttribute.u2packages =
        readUnsignedShorts(modulePackagesAttribute.u2packagesCount);
  }

  public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) {
    // This attribute does not contain any additional information.
  }

  public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) {
    // This attribute does not contain any additional information.
  }

  public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) {
    signatureAttribute.u2signatureIndex = dataInput.readUnsignedShort();
  }

  public void visitConstantValueAttribute(
      Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) {
    constantValueAttribute.u2constantValueIndex = dataInput.readUnsignedShort();
  }

  public void visitMethodParametersAttribute(
      Clazz clazz, Method method, MethodParametersAttribute methodParametersAttribute) {
    // Read the parameter information.
    methodParametersAttribute.u1parametersCount = dataInput.readUnsignedByte();

    methodParametersAttribute.parameters =
        new ParameterInfo[methodParametersAttribute.u1parametersCount];
    for (int index = 0; index < methodParametersAttribute.u1parametersCount; index++) {
      ParameterInfo parameterInfo = new ParameterInfo();
      visitParameterInfo(clazz, method, index, parameterInfo);
      methodParametersAttribute.parameters[index] = parameterInfo;
    }
  }

  public void visitExceptionsAttribute(
      Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) {
    // Read the exceptions.
    exceptionsAttribute.u2exceptionIndexTableLength = dataInput.readUnsignedShort();
    exceptionsAttribute.u2exceptionIndexTable =
        readUnsignedShorts(exceptionsAttribute.u2exceptionIndexTableLength);
  }

  public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) {
    // Read the stack size and local variable frame size.
    codeAttribute.u2maxStack = dataInput.readUnsignedShort();
    codeAttribute.u2maxLocals = dataInput.readUnsignedShort();

    // Read the byte code.
    codeAttribute.u4codeLength = dataInput.readInt();

    byte[] code = new byte[codeAttribute.u4codeLength];
    dataInput.readFully(code);
    codeAttribute.code = code;

    // Read the exceptions.
    codeAttribute.u2exceptionTableLength = dataInput.readUnsignedShort();

    codeAttribute.exceptionTable = new ExceptionInfo[codeAttribute.u2exceptionTableLength];
    for (int index = 0; index < codeAttribute.u2exceptionTableLength; index++) {
      ExceptionInfo exceptionInfo = new ExceptionInfo();
      visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo);
      codeAttribute.exceptionTable[index] = exceptionInfo;
    }

    // Read the code attributes.
    codeAttribute.u2attributesCount = dataInput.readUnsignedShort();

    codeAttribute.attributes = new Attribute[codeAttribute.u2attributesCount];
    for (int index = 0; index < codeAttribute.u2attributesCount; index++) {
      Attribute attribute = createAttribute(clazz);
      attribute.accept(clazz, method, codeAttribute, this);
      codeAttribute.attributes[index] = attribute;
    }
  }

  public void visitStackMapAttribute(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      StackMapAttribute stackMapAttribute) {
    // Read the stack map frames (only full frames, without tag).
    stackMapAttribute.u2stackMapFramesCount = dataInput.readUnsignedShort();

    stackMapAttribute.stackMapFrames = new FullFrame[stackMapAttribute.u2stackMapFramesCount];
    for (int index = 0; index < stackMapAttribute.u2stackMapFramesCount; index++) {
      FullFrame stackMapFrame = new FullFrame();
      visitFullFrame(clazz, method, codeAttribute, index, stackMapFrame);
      stackMapAttribute.stackMapFrames[index] = stackMapFrame;
    }
  }

  public void visitStackMapTableAttribute(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      StackMapTableAttribute stackMapTableAttribute) {
    // Read the stack map frames.
    stackMapTableAttribute.u2stackMapFramesCount = dataInput.readUnsignedShort();

    stackMapTableAttribute.stackMapFrames =
        new StackMapFrame[stackMapTableAttribute.u2stackMapFramesCount];
    for (int index = 0; index < stackMapTableAttribute.u2stackMapFramesCount; index++) {
      StackMapFrame stackMapFrame = createStackMapFrame();
      stackMapFrame.accept(clazz, method, codeAttribute, 0, this);
      stackMapTableAttribute.stackMapFrames[index] = stackMapFrame;
    }
  }

  public void visitLineNumberTableAttribute(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      LineNumberTableAttribute lineNumberTableAttribute) {
    // Read the line numbers.
    lineNumberTableAttribute.u2lineNumberTableLength = dataInput.readUnsignedShort();

    lineNumberTableAttribute.lineNumberTable =
        new LineNumberInfo[lineNumberTableAttribute.u2lineNumberTableLength];
    for (int index = 0; index < lineNumberTableAttribute.u2lineNumberTableLength; index++) {
      LineNumberInfo lineNumberInfo = new LineNumberInfo();
      visitLineNumberInfo(clazz, method, codeAttribute, lineNumberInfo);
      lineNumberTableAttribute.lineNumberTable[index] = lineNumberInfo;
    }
  }

  public void visitLocalVariableTableAttribute(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      LocalVariableTableAttribute localVariableTableAttribute) {
    // Read the local variables.
    localVariableTableAttribute.u2localVariableTableLength = dataInput.readUnsignedShort();

    localVariableTableAttribute.localVariableTable =
        new LocalVariableInfo[localVariableTableAttribute.u2localVariableTableLength];
    for (int index = 0; index < localVariableTableAttribute.u2localVariableTableLength; index++) {
      LocalVariableInfo localVariableInfo = new LocalVariableInfo();
      visitLocalVariableInfo(clazz, method, codeAttribute, localVariableInfo);
      localVariableTableAttribute.localVariableTable[index] = localVariableInfo;
    }
  }

  public void visitLocalVariableTypeTableAttribute(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      LocalVariableTypeTableAttribute localVariableTypeTableAttribute) {
    // Read the local variable types.
    localVariableTypeTableAttribute.u2localVariableTypeTableLength = dataInput.readUnsignedShort();

    localVariableTypeTableAttribute.localVariableTypeTable =
        new LocalVariableTypeInfo[localVariableTypeTableAttribute.u2localVariableTypeTableLength];
    for (int index = 0;
        index < localVariableTypeTableAttribute.u2localVariableTypeTableLength;
        index++) {
      LocalVariableTypeInfo localVariableTypeInfo = new LocalVariableTypeInfo();
      visitLocalVariableTypeInfo(clazz, method, codeAttribute, localVariableTypeInfo);
      localVariableTypeTableAttribute.localVariableTypeTable[index] = localVariableTypeInfo;
    }
  }

  public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) {
    // Read the annotations.
    annotationsAttribute.u2annotationsCount = dataInput.readUnsignedShort();

    annotationsAttribute.annotations = new Annotation[annotationsAttribute.u2annotationsCount];
    for (int index = 0; index < annotationsAttribute.u2annotationsCount; index++) {
      Annotation annotation = new Annotation();
      visitAnnotation(clazz, annotation);
      annotationsAttribute.annotations[index] = annotation;
    }
  }

  public void visitAnyParameterAnnotationsAttribute(
      Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) {
    // Read the parameter annotations.
    parameterAnnotationsAttribute.u1parametersCount = dataInput.readUnsignedByte();
    parameterAnnotationsAttribute.u2parameterAnnotationsCount =
        new int[parameterAnnotationsAttribute.u1parametersCount];
    parameterAnnotationsAttribute.parameterAnnotations =
        new Annotation[parameterAnnotationsAttribute.u1parametersCount][];

    for (int parameterIndex = 0;
        parameterIndex < parameterAnnotationsAttribute.u1parametersCount;
        parameterIndex++) {
      // Read the parameter annotations of the given parameter.
      int u2annotationsCount = dataInput.readUnsignedShort();

      Annotation[] annotations = new Annotation[u2annotationsCount];

      for (int index = 0; index < u2annotationsCount; index++) {
        Annotation annotation = new Annotation();
        visitAnnotation(clazz, annotation);
        annotations[index] = annotation;
      }

      parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex] =
          u2annotationsCount;
      parameterAnnotationsAttribute.parameterAnnotations[parameterIndex] = annotations;
    }
  }

  public void visitAnyTypeAnnotationsAttribute(
      Clazz clazz, TypeAnnotationsAttribute typeAnnotationsAttribute) {
    // Read the type annotations.
    typeAnnotationsAttribute.u2annotationsCount = dataInput.readUnsignedShort();

    typeAnnotationsAttribute.annotations =
        new TypeAnnotation[typeAnnotationsAttribute.u2annotationsCount];
    for (int index = 0; index < typeAnnotationsAttribute.u2annotationsCount; index++) {
      TypeAnnotation typeAnnotation = new TypeAnnotation();
      visitTypeAnnotation(clazz, typeAnnotation);
      typeAnnotationsAttribute.annotations[index] = typeAnnotation;
    }
  }

  public void visitAnnotationDefaultAttribute(
      Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) {
    // Read the default element value.
    ElementValue elementValue = createElementValue();
    elementValue.accept(clazz, null, this);
    annotationDefaultAttribute.defaultValue = elementValue;
  }

  // Implementations for BootstrapMethodInfoVisitor.

  public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) {
    bootstrapMethodInfo.u2methodHandleIndex = dataInput.readUnsignedShort();

    // Read the bootstrap method arguments.
    bootstrapMethodInfo.u2methodArgumentCount = dataInput.readUnsignedShort();
    bootstrapMethodInfo.u2methodArguments =
        readUnsignedShorts(bootstrapMethodInfo.u2methodArgumentCount);
  }

  // Implementations for RecordComponentInfoVisitor.

  public void visitRecordComponentInfo(Clazz clazz, RecordComponentInfo recordComponentInfo) {
    recordComponentInfo.u2nameIndex = dataInput.readUnsignedShort();
    recordComponentInfo.u2descriptorIndex = dataInput.readUnsignedShort();

    // Read the component attributes.
    recordComponentInfo.u2attributesCount = dataInput.readUnsignedShort();

    recordComponentInfo.attributes = new Attribute[recordComponentInfo.u2attributesCount];
    for (int index = 0; index < recordComponentInfo.u2attributesCount; index++) {
      Attribute attribute = createAttribute(clazz);
      attribute.accept(clazz, this);
      recordComponentInfo.attributes[index] = attribute;
    }
  }

  // Implementations for InnerClassesInfoVisitor.

  public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) {
    innerClassesInfo.u2innerClassIndex = dataInput.readUnsignedShort();
    innerClassesInfo.u2outerClassIndex = dataInput.readUnsignedShort();
    innerClassesInfo.u2innerNameIndex = dataInput.readUnsignedShort();
    innerClassesInfo.u2innerClassAccessFlags = dataInput.readUnsignedShort();
  }

  // Implementations for ExceptionInfoVisitor.

  public void visitExceptionInfo(
      Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) {
    exceptionInfo.u2startPC = dataInput.readUnsignedShort();
    exceptionInfo.u2endPC = dataInput.readUnsignedShort();
    exceptionInfo.u2handlerPC = dataInput.readUnsignedShort();
    exceptionInfo.u2catchType = dataInput.readUnsignedShort();
  }

  // Implementations for StackMapFrameVisitor.

  public void visitSameZeroFrame(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      int offset,
      SameZeroFrame sameZeroFrame) {
    if (sameZeroFrame.getTag() == StackMapFrame.SAME_ZERO_FRAME_EXTENDED) {
      sameZeroFrame.u2offsetDelta = dataInput.readUnsignedShort();
    }
  }

  public void visitSameOneFrame(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      int offset,
      SameOneFrame sameOneFrame) {
    if (sameOneFrame.getTag() == StackMapFrame.SAME_ONE_FRAME_EXTENDED) {
      sameOneFrame.u2offsetDelta = dataInput.readUnsignedShort();
    }

    // Read the verification type of the stack entry.
    VerificationType verificationType = createVerificationType();
    verificationType.accept(clazz, method, codeAttribute, offset, this);
    sameOneFrame.stackItem = verificationType;
  }

  public void visitLessZeroFrame(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      int offset,
      LessZeroFrame lessZeroFrame) {
    lessZeroFrame.u2offsetDelta = dataInput.readUnsignedShort();
  }

  public void visitMoreZeroFrame(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      int offset,
      MoreZeroFrame moreZeroFrame) {
    moreZeroFrame.u2offsetDelta = dataInput.readUnsignedShort();

    // Read the verification types of the additional local variables.
    moreZeroFrame.additionalVariables =
        new VerificationType[moreZeroFrame.additionalVariablesCount];
    for (int index = 0; index < moreZeroFrame.additionalVariablesCount; index++) {
      VerificationType verificationType = createVerificationType();
      verificationType.accept(clazz, method, codeAttribute, offset, this);
      moreZeroFrame.additionalVariables[index] = verificationType;
    }
  }

  public void visitFullFrame(
      Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) {
    fullFrame.u2offsetDelta = dataInput.readUnsignedShort();

    // Read the verification types of the local variables.
    fullFrame.variablesCount = dataInput.readUnsignedShort();
    fullFrame.variables = new VerificationType[fullFrame.variablesCount];
    for (int index = 0; index < fullFrame.variablesCount; index++) {
      VerificationType verificationType = createVerificationType();
      verificationType.variablesAccept(clazz, method, codeAttribute, offset, index, this);
      fullFrame.variables[index] = verificationType;
    }

    // Read the verification types of the stack entries.
    fullFrame.stackCount = dataInput.readUnsignedShort();
    fullFrame.stack = new VerificationType[fullFrame.stackCount];
    for (int index = 0; index < fullFrame.stackCount; index++) {
      VerificationType verificationType = createVerificationType();
      verificationType.stackAccept(clazz, method, codeAttribute, offset, index, this);
      fullFrame.stack[index] = verificationType;
    }
  }

  // Implementations for VerificationTypeVisitor.

  public void visitAnyVerificationType(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      int offset,
      VerificationType verificationType) {
    // Most verification types don't contain any additional information.
  }

  public void visitObjectType(
      Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) {
    objectType.u2classIndex = dataInput.readUnsignedShort();
  }

  public void visitUninitializedType(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      int offset,
      UninitializedType uninitializedType) {
    uninitializedType.u2newInstructionOffset = dataInput.readUnsignedShort();
  }

  // Implementations for LineNumberInfoVisitor.

  public void visitLineNumberInfo(
      Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) {
    lineNumberInfo.u2startPC = dataInput.readUnsignedShort();
    lineNumberInfo.u2lineNumber = dataInput.readUnsignedShort();
  }

  // Implementations for ParameterInfoVisitor.

  public void visitParameterInfo(
      Clazz clazz, Method method, int parameterIndex, ParameterInfo parameterInfo) {
    parameterInfo.u2nameIndex = dataInput.readUnsignedShort();
    parameterInfo.u2accessFlags = dataInput.readUnsignedShort();
  }

  // Implementations for LocalVariableInfoVisitor.

  public void visitLocalVariableInfo(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      LocalVariableInfo localVariableInfo) {
    localVariableInfo.u2startPC = dataInput.readUnsignedShort();
    localVariableInfo.u2length = dataInput.readUnsignedShort();
    localVariableInfo.u2nameIndex = dataInput.readUnsignedShort();
    localVariableInfo.u2descriptorIndex = dataInput.readUnsignedShort();
    localVariableInfo.u2index = dataInput.readUnsignedShort();
  }

  // Implementations for LocalVariableTypeInfoVisitor.

  public void visitLocalVariableTypeInfo(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      LocalVariableTypeInfo localVariableTypeInfo) {
    localVariableTypeInfo.u2startPC = dataInput.readUnsignedShort();
    localVariableTypeInfo.u2length = dataInput.readUnsignedShort();
    localVariableTypeInfo.u2nameIndex = dataInput.readUnsignedShort();
    localVariableTypeInfo.u2signatureIndex = dataInput.readUnsignedShort();
    localVariableTypeInfo.u2index = dataInput.readUnsignedShort();
  }

  // Implementations for RequiresInfoVisitor.

  public void visitRequiresInfo(Clazz clazz, RequiresInfo requiresInfo) {
    requiresInfo.u2requiresIndex = dataInput.readUnsignedShort();
    requiresInfo.u2requiresFlags = dataInput.readUnsignedShort();
    requiresInfo.u2requiresVersionIndex = dataInput.readUnsignedShort();
  }

  // Implementations for ExportsInfoVisitor.

  public void visitExportsInfo(Clazz clazz, ExportsInfo exportsInfo) {
    exportsInfo.u2exportsIndex = dataInput.readUnsignedShort();
    exportsInfo.u2exportsFlags = dataInput.readUnsignedShort();

    // Read the targets.
    exportsInfo.u2exportsToCount = dataInput.readUnsignedShort();
    exportsInfo.u2exportsToIndex = readUnsignedShorts(exportsInfo.u2exportsToCount);
  }

  // Implementations for OpensInfoVisitor.

  public void visitOpensInfo(Clazz clazz, OpensInfo opensInfo) {
    opensInfo.u2opensIndex = dataInput.readUnsignedShort();
    opensInfo.u2opensFlags = dataInput.readUnsignedShort();

    // Read the targets.
    opensInfo.u2opensToCount = dataInput.readUnsignedShort();
    opensInfo.u2opensToIndex = readUnsignedShorts(opensInfo.u2opensToCount);
  }

  // Implementations for ProvidesInfoVisitor.

  public void visitProvidesInfo(Clazz clazz, ProvidesInfo providesInfo) {
    providesInfo.u2providesIndex = dataInput.readUnsignedShort();

    // Read the provides withs.
    providesInfo.u2providesWithCount = dataInput.readUnsignedShort();
    providesInfo.u2providesWithIndex = readUnsignedShorts(providesInfo.u2providesWithCount);
  }

  // Implementations for AnnotationVisitor.

  public void visitAnnotation(Clazz clazz, Annotation annotation) {
    // Read the annotation type.
    annotation.u2typeIndex = dataInput.readUnsignedShort();

    // Read the element value pairs.
    annotation.u2elementValuesCount = dataInput.readUnsignedShort();

    annotation.elementValues = new ElementValue[annotation.u2elementValuesCount];
    for (int index = 0; index < annotation.u2elementValuesCount; index++) {
      int u2elementNameIndex = dataInput.readUnsignedShort();
      ElementValue elementValue = createElementValue();
      elementValue.u2elementNameIndex = u2elementNameIndex;
      elementValue.accept(clazz, annotation, this);
      annotation.elementValues[index] = elementValue;
    }
  }

  // Implementations for TypeAnnotationVisitor.

  public void visitTypeAnnotation(Clazz clazz, TypeAnnotation typeAnnotation) {
    // Read the target info.
    TargetInfo targetInfo = createTargetInfo();
    targetInfo.accept(clazz, typeAnnotation, this);
    typeAnnotation.targetInfo = targetInfo;

    // Read the type path.
    int u1pathLength = dataInput.readUnsignedByte();

    typeAnnotation.typePath = new TypePathInfo[u1pathLength];
    for (int index = 0; index < u1pathLength; index++) {
      TypePathInfo typePathInfo = new TypePathInfo();
      visitTypePathInfo(clazz, typeAnnotation, typePathInfo);
      typeAnnotation.typePath[index] = typePathInfo;
    }

    // Read the actual annotation.
    visitAnnotation(clazz, typeAnnotation);
  }

  // Implementations for TargetInfoVisitor.

  public void visitTypeParameterTargetInfo(
      Clazz clazz, TypeAnnotation typeAnnotation, TypeParameterTargetInfo typeParameterTargetInfo) {
    typeParameterTargetInfo.u1typeParameterIndex = dataInput.readUnsignedByte();
  }

  public void visitSuperTypeTargetInfo(
      Clazz clazz, TypeAnnotation typeAnnotation, SuperTypeTargetInfo superTypeTargetInfo) {
    superTypeTargetInfo.u2superTypeIndex = dataInput.readUnsignedShort();
  }

  public void visitTypeParameterBoundTargetInfo(
      Clazz clazz,
      TypeAnnotation typeAnnotation,
      TypeParameterBoundTargetInfo typeParameterBoundTargetInfo) {
    typeParameterBoundTargetInfo.u1typeParameterIndex = dataInput.readUnsignedByte();
    typeParameterBoundTargetInfo.u1boundIndex = dataInput.readUnsignedByte();
  }

  public void visitEmptyTargetInfo(
      Clazz clazz, Member member, TypeAnnotation typeAnnotation, EmptyTargetInfo emptyTargetInfo) {}

  public void visitFormalParameterTargetInfo(
      Clazz clazz,
      Method method,
      TypeAnnotation typeAnnotation,
      FormalParameterTargetInfo formalParameterTargetInfo) {
    formalParameterTargetInfo.u1formalParameterIndex = dataInput.readUnsignedByte();
  }

  public void visitThrowsTargetInfo(
      Clazz clazz,
      Method method,
      TypeAnnotation typeAnnotation,
      ThrowsTargetInfo throwsTargetInfo) {
    throwsTargetInfo.u2throwsTypeIndex = dataInput.readUnsignedShort();
  }

  public void visitLocalVariableTargetInfo(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      TypeAnnotation typeAnnotation,
      LocalVariableTargetInfo localVariableTargetInfo) {
    // Read the local variable target elements.
    localVariableTargetInfo.u2tableLength = dataInput.readUnsignedShort();

    localVariableTargetInfo.table =
        new LocalVariableTargetElement[localVariableTargetInfo.u2tableLength];
    for (int index = 0; index < localVariableTargetInfo.u2tableLength; index++) {
      LocalVariableTargetElement element = new LocalVariableTargetElement();
      visitLocalVariableTargetElement(
          clazz, method, codeAttribute, typeAnnotation, localVariableTargetInfo, element);
      localVariableTargetInfo.table[index] = element;
    }
  }

  public void visitCatchTargetInfo(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      TypeAnnotation typeAnnotation,
      CatchTargetInfo catchTargetInfo) {
    catchTargetInfo.u2exceptionTableIndex = dataInput.readUnsignedShort();
  }

  public void visitOffsetTargetInfo(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      TypeAnnotation typeAnnotation,
      OffsetTargetInfo offsetTargetInfo) {
    offsetTargetInfo.u2offset = dataInput.readUnsignedShort();
  }

  public void visitTypeArgumentTargetInfo(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      TypeAnnotation typeAnnotation,
      TypeArgumentTargetInfo typeArgumentTargetInfo) {
    typeArgumentTargetInfo.u2offset = dataInput.readUnsignedShort();
    typeArgumentTargetInfo.u1typeArgumentIndex = dataInput.readUnsignedByte();
  }

  // Implementations for TypePathInfoVisitor.

  public void visitTypePathInfo(
      Clazz clazz, TypeAnnotation typeAnnotation, TypePathInfo typePathInfo) {
    typePathInfo.u1typePathKind = dataInput.readUnsignedByte();
    typePathInfo.u1typeArgumentIndex = dataInput.readUnsignedByte();
  }

  // Implementations for LocalVariableTargetElementVisitor.

  public void visitLocalVariableTargetElement(
      Clazz clazz,
      Method method,
      CodeAttribute codeAttribute,
      TypeAnnotation typeAnnotation,
      LocalVariableTargetInfo localVariableTargetInfo,
      LocalVariableTargetElement localVariableTargetElement) {
    localVariableTargetElement.u2startPC = dataInput.readShort();
    localVariableTargetElement.u2length = dataInput.readShort();
    localVariableTargetElement.u2index = dataInput.readShort();
  }

  // Implementations for ElementValueVisitor.

  public void visitConstantElementValue(
      Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) {
    constantElementValue.u2constantValueIndex = dataInput.readUnsignedShort();
  }

  public void visitEnumConstantElementValue(
      Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) {
    enumConstantElementValue.u2typeNameIndex = dataInput.readUnsignedShort();
    enumConstantElementValue.u2constantNameIndex = dataInput.readUnsignedShort();
  }

  public void visitClassElementValue(
      Clazz clazz, Annotation annotation, ClassElementValue classElementValue) {
    classElementValue.u2classInfoIndex = dataInput.readUnsignedShort();
  }

  public void visitAnnotationElementValue(
      Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) {
    // Read the annotation.
    Annotation annotationValue = new Annotation();
    visitAnnotation(clazz, annotationValue);
    annotationElementValue.annotationValue = annotationValue;
  }

  public void visitArrayElementValue(
      Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) {
    // Read the element values.
    arrayElementValue.u2elementValuesCount = dataInput.readUnsignedShort();

    arrayElementValue.elementValues = new ElementValue[arrayElementValue.u2elementValuesCount];
    for (int index = 0; index < arrayElementValue.u2elementValuesCount; index++) {
      ElementValue elementValue = createElementValue();
      elementValue.accept(clazz, annotation, this);
      arrayElementValue.elementValues[index] = elementValue;
    }
  }

  // Small utility methods.

  private Constant createConstant() {
    int u1tag = dataInput.readUnsignedByte();

    switch (u1tag) {
      case Constant.INTEGER:
        return new IntegerConstant();
      case Constant.FLOAT:
        return new FloatConstant();
      case Constant.LONG:
        return new LongConstant();
      case Constant.DOUBLE:
        return new DoubleConstant();
      case Constant.PRIMITIVE_ARRAY:
        return new PrimitiveArrayConstant();
      case Constant.STRING:
        return new StringConstant();
      case Constant.UTF8:
        return new Utf8Constant();
      case Constant.DYNAMIC:
        return new DynamicConstant();
      case Constant.INVOKE_DYNAMIC:
        return new InvokeDynamicConstant();
      case Constant.METHOD_HANDLE:
        return new MethodHandleConstant();
      case Constant.FIELDREF:
        return new FieldrefConstant();
      case Constant.METHODREF:
        return new MethodrefConstant();
      case Constant.INTERFACE_METHODREF:
        return new InterfaceMethodrefConstant();
      case Constant.CLASS:
        return new ClassConstant();
      case Constant.METHOD_TYPE:
        return new MethodTypeConstant();
      case Constant.NAME_AND_TYPE:
        return new NameAndTypeConstant();
      case Constant.MODULE:
        return new ModuleConstant();
      case Constant.PACKAGE:
        return new PackageConstant();

      default:
        throw new RuntimeException("Unknown constant type [" + u1tag + "] in constant pool");
    }
  }

  private Attribute createAttribute(Clazz clazz) {
    int u2attributeNameIndex = dataInput.readUnsignedShort();
    int u4attributeLength = dataInput.readInt();
    String attributeName = clazz.getString(u2attributeNameIndex);

    Attribute attribute =
        attributeName.equals(Attribute.BOOTSTRAP_METHODS)
            ? new BootstrapMethodsAttribute()
            : attributeName.equals(Attribute.SOURCE_FILE)
                ? new SourceFileAttribute()
                : attributeName.equals(Attribute.SOURCE_DIR)
                    ? new SourceDirAttribute()
                    : attributeName.equals(Attribute.SOURCE_DEBUG_EXTENSION)
                        ? new SourceDebugExtensionAttribute(0, u4attributeLength, null)
                        : attributeName.equals(Attribute.RECORD)
                            ? new RecordAttribute()
                            : attributeName.equals(Attribute.INNER_CLASSES)
                                ? new InnerClassesAttribute()
                                : attributeName.equals(Attribute.ENCLOSING_METHOD)
                                    ? new EnclosingMethodAttribute()
                                    : attributeName.equals(Attribute.NEST_HOST)
                                        ? new NestHostAttribute()
                                        : attributeName.equals(Attribute.NEST_MEMBERS)
                                            ? new NestMembersAttribute()
                                            : attributeName.equals(Attribute.PERMITTED_SUBCLASSES)
                                                ? new PermittedSubclassesAttribute()
                                                : attributeName.equals(Attribute.DEPRECATED)
                                                    ? new DeprecatedAttribute()
                                                    : attributeName.equals(Attribute.SYNTHETIC)
                                                        ? new SyntheticAttribute()
                                                        : attributeName.equals(Attribute.SIGNATURE)
                                                            ? new SignatureAttribute()
                                                            : attributeName.equals(
                                                                    Attribute.CONSTANT_VALUE)
                                                                ? new ConstantValueAttribute()
                                                                : attributeName.equals(
                                                                        Attribute.METHOD_PARAMETERS)
                                                                    ? new MethodParametersAttribute()
                                                                    : attributeName.equals(
                                                                            Attribute.EXCEPTIONS)
                                                                        ? new ExceptionsAttribute()
                                                                        : attributeName.equals(
                                                                                Attribute.CODE)
                                                                            ? new CodeAttribute()
                                                                            : attributeName.equals(
                                                                                        Attribute
                                                                                            .STACK_MAP)
                                                                                    && !ignoreStackMapAttributes
                                                                                ? new StackMapAttribute()
                                                                                : attributeName
                                                                                            .equals(
                                                                                                Attribute
                                                                                                    .STACK_MAP_TABLE)
                                                                                        && !ignoreStackMapAttributes
                                                                                    ? new StackMapTableAttribute()
                                                                                    : attributeName
                                                                                            .equals(
                                                                                                Attribute
                                                                                                    .LINE_NUMBER_TABLE)
                                                                                        ? new LineNumberTableAttribute()
                                                                                        : attributeName
                                                                                                .equals(
                                                                                                    Attribute
                                                                                                        .LOCAL_VARIABLE_TABLE)
                                                                                            ? new LocalVariableTableAttribute()
                                                                                            : attributeName
                                                                                                    .equals(
                                                                                                        Attribute
                                                                                                            .LOCAL_VARIABLE_TYPE_TABLE)
                                                                                                ? new LocalVariableTypeTableAttribute()
                                                                                                : attributeName
                                                                                                        .equals(
                                                                                                            Attribute
                                                                                                                .RUNTIME_VISIBLE_ANNOTATIONS)
                                                                                                    ? new RuntimeVisibleAnnotationsAttribute()
                                                                                                    : attributeName
                                                                                                            .equals(
                                                                                                                Attribute
                                                                                                                    .RUNTIME_INVISIBLE_ANNOTATIONS)
                                                                                                        ? new RuntimeInvisibleAnnotationsAttribute()
                                                                                                        : attributeName
                                                                                                                .equals(
                                                                                                                    Attribute
                                                                                                                        .RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS)
                                                                                                            ? new RuntimeVisibleParameterAnnotationsAttribute()
                                                                                                            : attributeName
                                                                                                                    .equals(
                                                                                                                        Attribute
                                                                                                                            .RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS)
                                                                                                                ? new RuntimeInvisibleParameterAnnotationsAttribute()
                                                                                                                : attributeName
                                                                                                                        .equals(
                                                                                                                            Attribute
                                                                                                                                .RUNTIME_VISIBLE_TYPE_ANNOTATIONS)
                                                                                                                    ? new RuntimeVisibleTypeAnnotationsAttribute()
                                                                                                                    : attributeName
                                                                                                                            .equals(
                                                                                                                                Attribute
                                                                                                                                    .RUNTIME_INVISIBLE_TYPE_ANNOTATIONS)
                                                                                                                        ? new RuntimeInvisibleTypeAnnotationsAttribute()
                                                                                                                        : attributeName
                                                                                                                                .equals(
                                                                                                                                    Attribute
                                                                                                                                        .ANNOTATION_DEFAULT)
                                                                                                                            ? new AnnotationDefaultAttribute()
                                                                                                                            : attributeName
                                                                                                                                    .equals(
                                                                                                                                        Attribute
                                                                                                                                            .MODULE)
                                                                                                                                ? new ModuleAttribute()
                                                                                                                                : attributeName
                                                                                                                                        .equals(
                                                                                                                                            Attribute
                                                                                                                                                .MODULE_MAIN_CLASS)
                                                                                                                                    ? new ModuleMainClassAttribute()
                                                                                                                                    : attributeName
                                                                                                                                            .equals(
                                                                                                                                                Attribute
                                                                                                                                                    .MODULE_PACKAGES)
                                                                                                                                        ? new ModulePackagesAttribute()
                                                                                                                                        : new UnknownAttribute(
                                                                                                                                            u2attributeNameIndex,
                                                                                                                                            u4attributeLength);
    attribute.u2attributeNameIndex = u2attributeNameIndex;

    return attribute;
  }

  private StackMapFrame createStackMapFrame() {
    int u1tag = dataInput.readUnsignedByte();

    return u1tag < StackMapFrame.SAME_ONE_FRAME
        ? new SameZeroFrame(u1tag)
        : u1tag < StackMapFrame.SAME_ONE_FRAME_EXTENDED
            ? new SameOneFrame(u1tag)
            : u1tag < StackMapFrame.LESS_ZERO_FRAME
                ? new SameOneFrame(u1tag)
                : u1tag < StackMapFrame.SAME_ZERO_FRAME_EXTENDED
                    ? new LessZeroFrame(u1tag)
                    : u1tag < StackMapFrame.MORE_ZERO_FRAME
                        ? new SameZeroFrame(u1tag)
                        : u1tag < StackMapFrame.FULL_FRAME
                            ? new MoreZeroFrame(u1tag)
                            : new FullFrame();
  }

  private VerificationType createVerificationType() {
    int u1tag = dataInput.readUnsignedByte();

    switch (u1tag) {
      case VerificationType.INTEGER_TYPE:
        return new IntegerType();
      case VerificationType.FLOAT_TYPE:
        return new FloatType();
      case VerificationType.LONG_TYPE:
        return new LongType();
      case VerificationType.DOUBLE_TYPE:
        return new DoubleType();
      case VerificationType.TOP_TYPE:
        return new TopType();
      case VerificationType.OBJECT_TYPE:
        return new ObjectType();
      case VerificationType.NULL_TYPE:
        return new NullType();
      case VerificationType.UNINITIALIZED_TYPE:
        return new UninitializedType();
      case VerificationType.UNINITIALIZED_THIS_TYPE:
        return new UninitializedThisType();

      default:
        throw new RuntimeException("Unknown verification type [" + u1tag + "] in stack map frame");
    }
  }

  private TargetInfo createTargetInfo() {
    byte u1targetType = dataInput.readByte();

    switch (u1targetType) {
      case TargetInfo.TARGET_TYPE_PARAMETER_GENERIC_CLASS:
      case TargetInfo.TARGET_TYPE_PARAMETER_GENERIC_METHOD:
        return new TypeParameterTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_EXTENDS:
        return new SuperTypeTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_BOUND_GENERIC_CLASS:
      case TargetInfo.TARGET_TYPE_BOUND_GENERIC_METHOD:
        return new TypeParameterBoundTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_FIELD:
      case TargetInfo.TARGET_TYPE_RETURN:
      case TargetInfo.TARGET_TYPE_RECEIVER:
        return new EmptyTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_PARAMETER:
        return new FormalParameterTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_THROWS:
        return new ThrowsTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_LOCAL_VARIABLE:
      case TargetInfo.TARGET_TYPE_RESOURCE_VARIABLE:
        return new LocalVariableTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_CATCH:
        return new CatchTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_INSTANCE_OF:
      case TargetInfo.TARGET_TYPE_NEW:
      case TargetInfo.TARGET_TYPE_METHOD_REFERENCE_NEW:
      case TargetInfo.TARGET_TYPE_METHOD_REFERENCE:
        return new OffsetTargetInfo(u1targetType);
      case TargetInfo.TARGET_TYPE_CAST:
      case TargetInfo.TARGET_TYPE_ARGUMENT_GENERIC_METHODNew:
      case TargetInfo.TARGET_TYPE_ARGUMENT_GENERIC_METHOD:
      case TargetInfo.TARGET_TYPE_ARGUMENT_GENERIC_METHODReferenceNew:
      case TargetInfo.TARGET_TYPE_ARGUMENT_GENERIC_METHODReference:
        return new TypeArgumentTargetInfo(u1targetType);

      default:
        throw new RuntimeException("Unknown annotation target type [" + u1targetType + "]");
    }
  }

  private ElementValue createElementValue() {
    int u1tag = dataInput.readUnsignedByte();

    switch (u1tag) {
      case TypeConstants.BOOLEAN:
      case TypeConstants.BYTE:
      case TypeConstants.CHAR:
      case TypeConstants.SHORT:
      case TypeConstants.INT:
      case TypeConstants.FLOAT:
      case TypeConstants.LONG:
      case TypeConstants.DOUBLE:
      case ElementValue.TAG_STRING_CONSTANT:
        return new ConstantElementValue((char) u1tag);
      case ElementValue.TAG_ENUM_CONSTANT:
        return new EnumConstantElementValue();
      case ElementValue.TAG_CLASS:
        return new ClassElementValue();
      case ElementValue.TAG_ANNOTATION:
        return new AnnotationElementValue();
      case ElementValue.TAG_ARRAY:
        return new ArrayElementValue();

      default:
        throw new IllegalArgumentException("Unknown element value tag [" + u1tag + "]");
    }
  }

  /** Reads a list of unsigned shorts of the given size. */
  private int[] readUnsignedShorts(int size) {
    int[] values = new int[size];

    for (int index = 0; index < size; index++) {
      values[index] = dataInput.readUnsignedShort();
    }

    return values;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy