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

proguard.classfile.io.ProgramClassWriter 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.*;
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.*;
import proguard.classfile.util.*;
import proguard.classfile.visitor.*;
import proguard.io.RuntimeDataOutput;

/**
 * This {@link ClassVisitor} writes out the {@link ProgramClass} instances that it visits to the
 * given {@link DataOutput} object.
 *
 * @author Eric Lafortune
 */
public class ProgramClassWriter
    implements ClassVisitor, MemberVisitor, ConstantVisitor, AttributeVisitor {
  private RuntimeDataOutput dataOutput;

  private final ConstantBodyWriter constantBodyWriter = new ConstantBodyWriter();
  private final AttributeBodyWriter attributeBodyWriter = new AttributeBodyWriter();
  private final StackMapFrameBodyWriter stackMapFrameBodyWriter = new StackMapFrameBodyWriter();
  private final VerificationTypeBodyWriter verificationTypeBodyWriter =
      new VerificationTypeBodyWriter();
  private final ElementValueBodyWriter elementValueBodyWriter = new ElementValueBodyWriter();

  /** Creates a new ProgramClassWriter for writing to the given DataOutput. */
  public ProgramClassWriter(DataOutput dataOutput) {
    this.dataOutput = new RuntimeDataOutput(dataOutput);
  }

  // Implementations for ClassVisitor.

  @Override
  public void visitAnyClass(Clazz clazz) {}

  @Override
  public void visitProgramClass(ProgramClass programClass) {
    // Write the magic number.
    dataOutput.writeInt(VersionConstants.MAGIC);

    // Write the version numbers.
    dataOutput.writeShort(ClassUtil.internalMinorClassVersion(programClass.u4version));
    dataOutput.writeShort(ClassUtil.internalMajorClassVersion(programClass.u4version));

    // Write the constant pool.
    dataOutput.writeUnsignedShort(programClass.u2constantPoolCount);

    programClass.constantPoolEntriesAccept(this);

    // Write the general class information.
    // Ignore the higher bits outside the short range - these are for
    // internal purposes only.
    dataOutput.writeUnsignedShort(programClass.u2accessFlags & 0xffff);
    dataOutput.writeUnsignedShort(programClass.u2thisClass);
    dataOutput.writeUnsignedShort(programClass.u2superClass);

    // Write the interfaces.
    writeUnsignedShorts(programClass.u2interfaces, programClass.u2interfacesCount);

    // Write the fields.
    dataOutput.writeUnsignedShort(programClass.u2fieldsCount);

    programClass.fieldsAccept(this);

    // Write the methods.
    dataOutput.writeUnsignedShort(programClass.u2methodsCount);

    programClass.methodsAccept(this);

    // Write the class attributes.
    dataOutput.writeUnsignedShort(programClass.u2attributesCount);

    programClass.attributesAccept(this);
  }

  // Implementations for MemberVisitor.

  public void visitProgramField(ProgramClass programClass, ProgramField programField) {
    // Write the general field information.
    // Ignore the higher bits outside the short range - these are for
    // internal purposes only.
    dataOutput.writeUnsignedShort(programField.u2accessFlags & 0xffff);
    dataOutput.writeUnsignedShort(programField.u2nameIndex);
    dataOutput.writeUnsignedShort(programField.u2descriptorIndex);

    // Write the field attributes.
    dataOutput.writeUnsignedShort(programField.u2attributesCount);

    programField.attributesAccept(programClass, this);
  }

  public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) {
    // Write the general method information.
    // Ignore the higher bits outside the short range - these are for
    // internal purposes only.
    dataOutput.writeUnsignedShort(programMethod.u2accessFlags & 0xffff);
    dataOutput.writeUnsignedShort(programMethod.u2nameIndex);
    dataOutput.writeUnsignedShort(programMethod.u2descriptorIndex);

    // Write the method attributes.
    dataOutput.writeUnsignedShort(programMethod.u2attributesCount);

    programMethod.attributesAccept(programClass, this);
  }

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

  // Implementations for ConstantVisitor.

  public void visitAnyConstant(Clazz clazz, Constant constant) {
    // Write the tag.
    dataOutput.writeByte(constant.getTag());

    // Write the actual body.
    constant.accept(clazz, constantBodyWriter);
  }

  private class ConstantBodyWriter
      implements ConstantVisitor, PrimitiveArrayConstantElementVisitor {
    // Implementations for ConstantVisitor.

    public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) {
      dataOutput.writeInt(integerConstant.u4value);
    }

    public void visitLongConstant(Clazz clazz, LongConstant longConstant) {
      dataOutput.writeLong(longConstant.u8value);
    }

    public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) {
      dataOutput.writeFloat(floatConstant.f4value);
    }

    public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) {
      dataOutput.writeDouble(doubleConstant.f8value);
    }

    public void visitPrimitiveArrayConstant(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant) {
      char u2primitiveType = primitiveArrayConstant.getPrimitiveType();
      int u4Length = primitiveArrayConstant.getLength();

      dataOutput.writeUnsignedShort(u2primitiveType);
      dataOutput.writeInt(u4Length);

      // Write the array values.
      primitiveArrayConstant.primitiveArrayElementsAccept(clazz, this);
    }

    public void visitStringConstant(Clazz clazz, StringConstant stringConstant) {
      dataOutput.writeUnsignedShort(stringConstant.u2stringIndex);
    }

    public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) {
      byte[] bytes = utf8Constant.getBytes();

      dataOutput.writeUnsignedShort(bytes.length);
      dataOutput.write(bytes);
    }

    public void visitDynamicConstant(Clazz clazz, DynamicConstant dynamicConstant) {
      dataOutput.writeUnsignedShort(dynamicConstant.u2bootstrapMethodAttributeIndex);
      dataOutput.writeUnsignedShort(dynamicConstant.u2nameAndTypeIndex);
    }

    public void visitInvokeDynamicConstant(
        Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) {
      dataOutput.writeUnsignedShort(invokeDynamicConstant.u2bootstrapMethodAttributeIndex);
      dataOutput.writeUnsignedShort(invokeDynamicConstant.u2nameAndTypeIndex);
    }

    public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) {
      dataOutput.writeByte(methodHandleConstant.u1referenceKind);
      dataOutput.writeUnsignedShort(methodHandleConstant.u2referenceIndex);
    }

    public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) {
      dataOutput.writeUnsignedShort(refConstant.u2classIndex);
      dataOutput.writeUnsignedShort(refConstant.u2nameAndTypeIndex);
    }

    public void visitClassConstant(Clazz clazz, ClassConstant classConstant) {
      dataOutput.writeUnsignedShort(classConstant.u2nameIndex);
    }

    public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) {
      dataOutput.writeUnsignedShort(methodTypeConstant.u2descriptorIndex);
    }

    public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) {
      dataOutput.writeUnsignedShort(nameAndTypeConstant.u2nameIndex);
      dataOutput.writeUnsignedShort(nameAndTypeConstant.u2descriptorIndex);
    }

    // Implementations for PrimitiveArrayConstantElementVisitor.

    public void visitBooleanArrayConstantElement(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, boolean value) {
      dataOutput.writeBoolean(value);
    }

    public void visitByteArrayConstantElement(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, byte value) {
      dataOutput.writeByte(value);
    }

    public void visitCharArrayConstantElement(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, char value) {
      dataOutput.writeChar(value);
    }

    public void visitShortArrayConstantElement(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, short value) {
      dataOutput.writeShort(value);
    }

    public void visitIntArrayConstantElement(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, int value) {
      dataOutput.writeInt(value);
    }

    public void visitFloatArrayConstantElement(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, float value) {
      dataOutput.writeFloat(value);
    }

    public void visitLongArrayConstantElement(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, long value) {
      dataOutput.writeLong(value);
    }

    public void visitDoubleArrayConstantElement(
        Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, double value) {
      dataOutput.writeDouble(value);
    }

    public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant) {
      dataOutput.writeUnsignedShort(moduleConstant.u2nameIndex);
    }

    public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant) {
      dataOutput.writeUnsignedShort(packageConstant.u2nameIndex);
    }
  }

  // Implementations for AttributeVisitor.

  public void visitAnyAttribute(Clazz clazz, Attribute attribute) {
    // Write the attribute name index.
    dataOutput.writeUnsignedShort(attribute.u2attributeNameIndex);

    // We'll write the attribute body into an array first, so we can
    // automatically figure out its length.
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

    // Temporarily replace the current data output.
    RuntimeDataOutput oldDataOutput = dataOutput;
    dataOutput = new RuntimeDataOutput(new DataOutputStream(byteArrayOutputStream));

    // Write the attribute body into the array. Note that the
    // accept method with two dummy null arguments never throws
    // an UnsupportedOperationException.
    attribute.accept(clazz, null, null, attributeBodyWriter);

    // Restore the original data output.
    dataOutput = oldDataOutput;

    // Write the attribute length and body.
    byte[] info = byteArrayOutputStream.toByteArray();

    dataOutput.writeInt(info.length);
    dataOutput.write(info);
  }

  private class AttributeBodyWriter
      implements AttributeVisitor,
          BootstrapMethodInfoVisitor,
          RecordComponentInfoVisitor,
          InnerClassesInfoVisitor,
          ExceptionInfoVisitor,
          StackMapFrameVisitor,
          VerificationTypeVisitor,
          LineNumberInfoVisitor,
          ParameterInfoVisitor,
          LocalVariableInfoVisitor,
          LocalVariableTypeInfoVisitor,
          RequiresInfoVisitor,
          ExportsInfoVisitor,
          OpensInfoVisitor,
          ProvidesInfoVisitor,
          AnnotationVisitor,
          TypeAnnotationVisitor,
          TargetInfoVisitor,
          TypePathInfoVisitor,
          LocalVariableTargetElementVisitor,
          ElementValueVisitor {
    // Implementations for AttributeVisitor.

    public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) {
      // Write the unknown information.
      dataOutput.write(unknownAttribute.info);
    }

    public void visitBootstrapMethodsAttribute(
        Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) {
      // Write the bootstrap methods.
      dataOutput.writeUnsignedShort(bootstrapMethodsAttribute.u2bootstrapMethodsCount);

      bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this);
    }

    public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) {
      dataOutput.writeUnsignedShort(sourceFileAttribute.u2sourceFileIndex);
    }

    public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) {
      dataOutput.writeUnsignedShort(sourceDirAttribute.u2sourceDirIndex);
    }

    public void visitSourceDebugExtensionAttribute(
        Clazz clazz, SourceDebugExtensionAttribute sourceDebugExtensionAttribute) {
      dataOutput.write(sourceDebugExtensionAttribute.info);
    }

    public void visitRecordAttribute(Clazz clazz, RecordAttribute recordAttribute) {
      // Write the components.
      dataOutput.writeUnsignedShort(recordAttribute.u2componentsCount);

      recordAttribute.componentsAccept(clazz, this);
    }

    public void visitInnerClassesAttribute(
        Clazz clazz, InnerClassesAttribute innerClassesAttribute) {
      // Write the inner classes.
      dataOutput.writeUnsignedShort(innerClassesAttribute.u2classesCount);

      innerClassesAttribute.innerClassEntriesAccept(clazz, this);
    }

    public void visitEnclosingMethodAttribute(
        Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) {
      dataOutput.writeUnsignedShort(enclosingMethodAttribute.u2classIndex);
      dataOutput.writeUnsignedShort(enclosingMethodAttribute.u2nameAndTypeIndex);
    }

    public void visitNestHostAttribute(Clazz clazz, NestHostAttribute nestHostAttribute) {
      dataOutput.writeUnsignedShort(nestHostAttribute.u2hostClassIndex);
    }

    public void visitNestMembersAttribute(Clazz clazz, NestMembersAttribute nestMembersAttribute) {
      // Write the nest host classes.
      writeUnsignedShorts(nestMembersAttribute.u2classes, nestMembersAttribute.u2classesCount);
    }

    public void visitPermittedSubclassesAttribute(
        Clazz clazz, PermittedSubclassesAttribute permittedSubclassesAttribute) {
      // Write the permitted classes.
      writeUnsignedShorts(
          permittedSubclassesAttribute.u2classes, permittedSubclassesAttribute.u2classesCount);
    }

    public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute) {
      dataOutput.writeUnsignedShort(moduleAttribute.u2moduleNameIndex);
      dataOutput.writeUnsignedShort(moduleAttribute.u2moduleFlags);
      dataOutput.writeUnsignedShort(moduleAttribute.u2moduleVersionIndex);

      // Write the requires.
      dataOutput.writeUnsignedShort(moduleAttribute.u2requiresCount);

      moduleAttribute.requiresAccept(clazz, this);

      // Write the exports.
      dataOutput.writeUnsignedShort(moduleAttribute.u2exportsCount);

      moduleAttribute.exportsAccept(clazz, this);

      // Write the opens.
      dataOutput.writeUnsignedShort(moduleAttribute.u2opensCount);

      moduleAttribute.opensAccept(clazz, this);

      // Write the uses.
      writeUnsignedShorts(moduleAttribute.u2uses, moduleAttribute.u2usesCount);

      // Write the provides.
      dataOutput.writeUnsignedShort(moduleAttribute.u2providesCount);

      moduleAttribute.providesAccept(clazz, this);
    }

    public void visitModuleMainClassAttribute(
        Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute) {
      dataOutput.writeUnsignedShort(moduleMainClassAttribute.u2mainClass);
    }

    public void visitModulePackagesAttribute(
        Clazz clazz, ModulePackagesAttribute modulePackagesAttribute) {
      // Write the packages.
      writeUnsignedShorts(
          modulePackagesAttribute.u2packages, 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) {
      dataOutput.writeUnsignedShort(signatureAttribute.u2signatureIndex);
    }

    public void visitConstantValueAttribute(
        Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) {
      dataOutput.writeUnsignedShort(constantValueAttribute.u2constantValueIndex);
    }

    public void visitMethodParametersAttribute(
        Clazz clazz, Method method, MethodParametersAttribute methodParametersAttribute) {
      // Write the parameter information.
      dataOutput.writeByte(methodParametersAttribute.u1parametersCount);

      methodParametersAttribute.parametersAccept(clazz, method, this);
    }

    public void visitExceptionsAttribute(
        Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) {
      // Write the exceptions.
      writeUnsignedShorts(
          exceptionsAttribute.u2exceptionIndexTable,
          exceptionsAttribute.u2exceptionIndexTableLength);
    }

    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) {
      // Write the stack size and local variable frame size.
      dataOutput.writeUnsignedShort(codeAttribute.u2maxStack);
      dataOutput.writeUnsignedShort(codeAttribute.u2maxLocals);

      // Write the byte code.
      dataOutput.writeInt(codeAttribute.u4codeLength);

      dataOutput.write(codeAttribute.code, 0, codeAttribute.u4codeLength);

      // Write the exceptions.
      dataOutput.writeUnsignedShort(codeAttribute.u2exceptionTableLength);

      codeAttribute.exceptionsAccept(clazz, method, this);

      // Write the code attributes.
      dataOutput.writeUnsignedShort(codeAttribute.u2attributesCount);

      codeAttribute.attributesAccept(clazz, method, ProgramClassWriter.this);
    }

    public void visitStackMapAttribute(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        StackMapAttribute stackMapAttribute) {
      // Write the stack map frames (only full frames, without tag).
      dataOutput.writeUnsignedShort(stackMapAttribute.u2stackMapFramesCount);

      stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, stackMapFrameBodyWriter);
    }

    public void visitStackMapTableAttribute(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        StackMapTableAttribute stackMapTableAttribute) {
      // Write the stack map frames.
      dataOutput.writeUnsignedShort(stackMapTableAttribute.u2stackMapFramesCount);

      stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
    }

    public void visitLineNumberTableAttribute(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        LineNumberTableAttribute lineNumberTableAttribute) {
      // Write the line numbers.
      dataOutput.writeUnsignedShort(lineNumberTableAttribute.u2lineNumberTableLength);

      lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
    }

    public void visitLocalVariableTableAttribute(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        LocalVariableTableAttribute localVariableTableAttribute) {
      // Write the local variables.
      dataOutput.writeUnsignedShort(localVariableTableAttribute.u2localVariableTableLength);

      localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
    }

    public void visitLocalVariableTypeTableAttribute(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        LocalVariableTypeTableAttribute localVariableTypeTableAttribute) {
      // Write the local variable types.
      dataOutput.writeUnsignedShort(localVariableTypeTableAttribute.u2localVariableTypeTableLength);

      localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
    }

    public void visitRequiresInfo(Clazz clazz, RequiresInfo requiresInfo) {
      dataOutput.writeUnsignedShort(requiresInfo.u2requiresIndex);
      dataOutput.writeUnsignedShort(requiresInfo.u2requiresFlags);
      dataOutput.writeUnsignedShort(requiresInfo.u2requiresVersionIndex);
    }

    public void visitExportsInfo(Clazz clazz, ExportsInfo exportsInfo) {
      dataOutput.writeUnsignedShort(exportsInfo.u2exportsIndex);
      dataOutput.writeUnsignedShort(exportsInfo.u2exportsFlags);

      // Write tthe argets.
      writeUnsignedShorts(exportsInfo.u2exportsToIndex, exportsInfo.u2exportsToCount);
    }

    public void visitOpensInfo(Clazz clazz, OpensInfo opensInfo) {
      dataOutput.writeUnsignedShort(opensInfo.u2opensIndex);
      dataOutput.writeUnsignedShort(opensInfo.u2opensFlags);

      // Write the targets.
      writeUnsignedShorts(opensInfo.u2opensToIndex, opensInfo.u2opensToCount);
    }

    public void visitProvidesInfo(Clazz clazz, ProvidesInfo providesInfo) {
      dataOutput.writeUnsignedShort(providesInfo.u2providesIndex);

      // Write the provides.
      writeUnsignedShorts(providesInfo.u2providesWithIndex, providesInfo.u2providesWithCount);
    }

    public void visitAnyAnnotationsAttribute(
        Clazz clazz, AnnotationsAttribute annotationsAttribute) {
      // Write the annotations.
      dataOutput.writeUnsignedShort(annotationsAttribute.u2annotationsCount);

      annotationsAttribute.annotationsAccept(clazz, this);
    }

    public void visitAnyParameterAnnotationsAttribute(
        Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) {
      // Write the parameter annotations.
      dataOutput.writeByte(parameterAnnotationsAttribute.u1parametersCount);

      for (int parameterIndex = 0;
          parameterIndex < parameterAnnotationsAttribute.u1parametersCount;
          parameterIndex++) {
        // Write the parameter annotations of the given parameter.
        int u2annotationsCount =
            parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex];
        Annotation[] annotations =
            parameterAnnotationsAttribute.parameterAnnotations[parameterIndex];

        dataOutput.writeUnsignedShort(u2annotationsCount);

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

    public void visitAnyTypeAnnotationsAttribute(
        Clazz clazz, TypeAnnotationsAttribute typeAnnotationsAttribute) {
      // Write the type annotations.
      dataOutput.writeUnsignedShort(typeAnnotationsAttribute.u2annotationsCount);

      typeAnnotationsAttribute.typeAnnotationsAccept(clazz, this);
    }

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

    // Implementations for BootstrapMethodInfoVisitor.

    public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) {
      dataOutput.writeUnsignedShort(bootstrapMethodInfo.u2methodHandleIndex);

      // Write the bootstrap method arguments.
      writeUnsignedShorts(
          bootstrapMethodInfo.u2methodArguments, bootstrapMethodInfo.u2methodArgumentCount);
    }

    // Implementations for RecordComponentInfoVisitor.

    public void visitRecordComponentInfo(Clazz clazz, RecordComponentInfo recordComponentInfo) {
      dataOutput.writeUnsignedShort(recordComponentInfo.u2nameIndex);
      dataOutput.writeUnsignedShort(recordComponentInfo.u2descriptorIndex);

      // Write the record attributes.
      dataOutput.writeUnsignedShort(recordComponentInfo.u2attributesCount);

      recordComponentInfo.attributesAccept(clazz, ProgramClassWriter.this);
    }

    // Implementations for InnerClassesInfoVisitor.

    public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) {
      dataOutput.writeUnsignedShort(innerClassesInfo.u2innerClassIndex);
      dataOutput.writeUnsignedShort(innerClassesInfo.u2outerClassIndex);
      dataOutput.writeUnsignedShort(innerClassesInfo.u2innerNameIndex);
      dataOutput.writeUnsignedShort(innerClassesInfo.u2innerClassAccessFlags);
    }

    // Implementations for ExceptionInfoVisitor.

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

    // Implementations for StackMapFrameVisitor.

    public void visitAnyStackMapFrame(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        int offset,
        StackMapFrame stackMapFrame) {
      // Write the stack map frame tag.
      dataOutput.writeByte(stackMapFrame.getTag());

      // Write the actual body.
      stackMapFrame.accept(clazz, method, codeAttribute, offset, stackMapFrameBodyWriter);
    }

    // Implementations for LineNumberInfoVisitor.

    public void visitLineNumberInfo(
        Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) {
      // Simply suppress line number overflows, typically caused by
      // inlined methods and their artificial line numbers.
      dataOutput.writeUnsignedShort(
          lineNumberInfo.u2startPC > 0xffff ? 0 : lineNumberInfo.u2startPC);
      dataOutput.writeUnsignedShort(
          lineNumberInfo.u2lineNumber > 0xffff ? 0 : lineNumberInfo.u2lineNumber);
    }

    // Implementations for ParameterInfoVisitor.

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

    // Implementations for LocalVariableInfoVisitor.

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

    // Implementations for LocalVariableTypeInfoVisitor.

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

    // Implementations for AnnotationVisitor.

    public void visitAnnotation(Clazz clazz, Annotation annotation) {
      // Write the annotation type.
      dataOutput.writeUnsignedShort(annotation.u2typeIndex);

      // Write the element value pairs.
      dataOutput.writeUnsignedShort(annotation.u2elementValuesCount);

      annotation.elementValuesAccept(clazz, this);
    }

    // Implementations for TypeAnnotationVisitor.

    public void visitTypeAnnotation(Clazz clazz, TypeAnnotation typeAnnotation) {
      // Write the target info.
      dataOutput.writeByte(typeAnnotation.targetInfo.u1targetType);

      typeAnnotation.targetInfoAccept(clazz, this);

      // Write the type path.
      dataOutput.writeByte(typeAnnotation.typePath.length);

      typeAnnotation.typePathInfosAccept(clazz, this);

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

    // Implementations for TargetInfoVisitor.

    public void visitTypeParameterTargetInfo(
        Clazz clazz,
        TypeAnnotation typeAnnotation,
        TypeParameterTargetInfo typeParameterTargetInfo) {
      dataOutput.writeByte(typeParameterTargetInfo.u1typeParameterIndex);
    }

    public void visitSuperTypeTargetInfo(
        Clazz clazz, TypeAnnotation typeAnnotation, SuperTypeTargetInfo superTypeTargetInfo) {
      dataOutput.writeUnsignedShort(superTypeTargetInfo.u2superTypeIndex);
    }

    public void visitTypeParameterBoundTargetInfo(
        Clazz clazz,
        TypeAnnotation typeAnnotation,
        TypeParameterBoundTargetInfo typeParameterBoundTargetInfo) {
      dataOutput.writeByte(typeParameterBoundTargetInfo.u1typeParameterIndex);
      dataOutput.writeByte(typeParameterBoundTargetInfo.u1boundIndex);
    }

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

    public void visitFormalParameterTargetInfo(
        Clazz clazz,
        Method method,
        TypeAnnotation typeAnnotation,
        FormalParameterTargetInfo formalParameterTargetInfo) {
      dataOutput.writeByte(formalParameterTargetInfo.u1formalParameterIndex);
    }

    public void visitThrowsTargetInfo(
        Clazz clazz,
        Method method,
        TypeAnnotation typeAnnotation,
        ThrowsTargetInfo throwsTargetInfo) {
      dataOutput.writeUnsignedShort(throwsTargetInfo.u2throwsTypeIndex);
    }

    public void visitLocalVariableTargetInfo(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        TypeAnnotation typeAnnotation,
        LocalVariableTargetInfo localVariableTargetInfo) {
      // Write the local variable target elements.
      dataOutput.writeUnsignedShort(localVariableTargetInfo.u2tableLength);

      localVariableTargetInfo.targetElementsAccept(
          clazz, method, codeAttribute, typeAnnotation, this);
    }

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

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

    public void visitTypeArgumentTargetInfo(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        TypeAnnotation typeAnnotation,
        TypeArgumentTargetInfo typeArgumentTargetInfo) {
      dataOutput.writeUnsignedShort(typeArgumentTargetInfo.u2offset);
      dataOutput.writeByte(typeArgumentTargetInfo.u1typeArgumentIndex);
    }

    // Implementations for TypePathInfoVisitor.

    public void visitTypePathInfo(
        Clazz clazz, TypeAnnotation typeAnnotation, TypePathInfo typePathInfo) {
      dataOutput.writeByte(typePathInfo.u1typePathKind);
      dataOutput.writeByte(typePathInfo.u1typeArgumentIndex);
    }

    // Implementations for LocalVariableTargetElementVisitor.

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

    // Implementations for ElementValueVisitor.

    public void visitAnyElementValue(
        Clazz clazz, Annotation annotation, ElementValue elementValue) {
      // Write the element name index, if applicable.
      int u2elementNameIndex = elementValue.u2elementNameIndex;
      if (u2elementNameIndex != 0) {
        dataOutput.writeUnsignedShort(u2elementNameIndex);
      }

      // Write the tag.
      dataOutput.writeByte(elementValue.getTag());

      // Write the actual body.
      elementValue.accept(clazz, annotation, elementValueBodyWriter);
    }
  }

  private class StackMapFrameBodyWriter implements StackMapFrameVisitor, VerificationTypeVisitor {
    public void visitSameZeroFrame(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        int offset,
        SameZeroFrame sameZeroFrame) {
      if (sameZeroFrame.getTag() == StackMapFrame.SAME_ZERO_FRAME_EXTENDED) {
        dataOutput.writeUnsignedShort(sameZeroFrame.u2offsetDelta);
      }
    }

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

      // Write the verification type of the stack entry.
      sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this);
    }

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

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

      // Write the verification types of the additional local variables.
      moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this);
    }

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

      // Write the verification types of the local variables.
      dataOutput.writeUnsignedShort(fullFrame.variablesCount);
      fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);

      // Write the verification types of the stack entries.
      dataOutput.writeUnsignedShort(fullFrame.stackCount);
      fullFrame.stackAccept(clazz, method, codeAttribute, offset, this);
    }

    // Implementations for VerificationTypeVisitor.

    public void visitAnyVerificationType(
        Clazz clazz,
        Method method,
        CodeAttribute codeAttribute,
        int offset,
        VerificationType verificationType) {
      // Write the verification type tag.
      dataOutput.writeByte(verificationType.getTag());

      // Write the actual body.
      verificationType.accept(clazz, method, codeAttribute, offset, verificationTypeBodyWriter);
    }
  }

  private class VerificationTypeBodyWriter implements VerificationTypeVisitor {
    // 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) {
      dataOutput.writeUnsignedShort(objectType.u2classIndex);
    }

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

  private class ElementValueBodyWriter implements ElementValueVisitor {
    // Implementations for ElementValueVisitor.

    public void visitConstantElementValue(
        Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) {
      dataOutput.writeUnsignedShort(constantElementValue.u2constantValueIndex);
    }

    public void visitEnumConstantElementValue(
        Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) {
      dataOutput.writeUnsignedShort(enumConstantElementValue.u2typeNameIndex);
      dataOutput.writeUnsignedShort(enumConstantElementValue.u2constantNameIndex);
    }

    public void visitClassElementValue(
        Clazz clazz, Annotation annotation, ClassElementValue classElementValue) {
      dataOutput.writeUnsignedShort(classElementValue.u2classInfoIndex);
    }

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

    public void visitArrayElementValue(
        Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) {
      // Write the element values.
      dataOutput.writeUnsignedShort(arrayElementValue.u2elementValuesCount);

      arrayElementValue.elementValuesAccept(clazz, annotation, attributeBodyWriter);
    }
  }

  // Small utility methods.

  /** Writes the length and the contents of the given list of unsigned shorts. */
  private void writeUnsignedShorts(int[] array, int size) {
    dataOutput.writeUnsignedShort(size);

    for (int index = 0; index < size; index++) {
      dataOutput.writeUnsignedShort(array[index]);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy