blob: bcc34039b8be11becca13fe2aa7fa0665b18f2da [file] [log] [blame]
/*
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
* Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package proguard.classfile.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.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 java.io.*;
/**
* This ClassVisitor writes out the ProgramClass objects that it visits to the
* given DataOutput object.
*
* @author Eric Lafortune
*/
public class ProgramClassWriter
extends SimplifiedVisitor
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.
public void visitProgramClass(ProgramClass programClass)
{
// Write the magic number.
dataOutput.writeInt(programClass.u4magic);
// Write the version numbers.
dataOutput.writeShort(ClassUtil.internalMinorClassVersion(programClass.u4version));
dataOutput.writeShort(ClassUtil.internalMajorClassVersion(programClass.u4version));
// Write the constant pool.
dataOutput.writeShort(programClass.u2constantPoolCount);
programClass.constantPoolEntriesAccept(this);
// Write the general class information.
dataOutput.writeShort(programClass.u2accessFlags);
dataOutput.writeShort(programClass.u2thisClass);
dataOutput.writeShort(programClass.u2superClass);
// Write the interfaces.
dataOutput.writeShort(programClass.u2interfacesCount);
for (int index = 0; index < programClass.u2interfacesCount; index++)
{
dataOutput.writeShort(programClass.u2interfaces[index]);
}
// Write the fields.
dataOutput.writeShort(programClass.u2fieldsCount);
programClass.fieldsAccept(this);
// Write the methods.
dataOutput.writeShort(programClass.u2methodsCount);
programClass.methodsAccept(this);
// Write the class attributes.
dataOutput.writeShort(programClass.u2attributesCount);
programClass.attributesAccept(this);
}
public void visitLibraryClass(LibraryClass libraryClass)
{
}
// Implementations for MemberVisitor.
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
// Write the general field information.
dataOutput.writeShort(programField.u2accessFlags);
dataOutput.writeShort(programField.u2nameIndex);
dataOutput.writeShort(programField.u2descriptorIndex);
// Write the field attributes.
dataOutput.writeShort(programField.u2attributesCount);
programField.attributesAccept(programClass, this);
}
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
// Write the general method information.
dataOutput.writeShort(programMethod.u2accessFlags);
dataOutput.writeShort(programMethod.u2nameIndex);
dataOutput.writeShort(programMethod.u2descriptorIndex);
// Write the method attributes.
dataOutput.writeShort(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
extends SimplifiedVisitor
implements ConstantVisitor
{
// 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 visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
dataOutput.writeShort(stringConstant.u2stringIndex);
}
public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
{
byte[] bytes = utf8Constant.getBytes();
dataOutput.writeShort(bytes.length);
dataOutput.write(bytes);
}
public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
{
dataOutput.writeShort(invokeDynamicConstant.u2bootstrapMethodAttributeIndex);
dataOutput.writeShort(invokeDynamicConstant.u2nameAndTypeIndex);
}
public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
{
dataOutput.writeByte(methodHandleConstant.u1referenceKind);
dataOutput.writeShort(methodHandleConstant.u2referenceIndex);
}
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
dataOutput.writeShort(refConstant.u2classIndex);
dataOutput.writeShort(refConstant.u2nameAndTypeIndex);
}
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
dataOutput.writeShort(classConstant.u2nameIndex);
}
public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
{
dataOutput.writeShort(methodTypeConstant.u2descriptorIndex);
}
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
dataOutput.writeShort(nameAndTypeConstant.u2nameIndex);
dataOutput.writeShort(nameAndTypeConstant.u2descriptorIndex);
}
}
// Implementations for AttributeVisitor.
public void visitAnyAttribute(Clazz clazz, Attribute attribute)
{
// Write the attribute name index.
dataOutput.writeShort(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
extends SimplifiedVisitor
implements AttributeVisitor,
BootstrapMethodInfoVisitor,
InnerClassesInfoVisitor,
ExceptionInfoVisitor,
StackMapFrameVisitor,
VerificationTypeVisitor,
LineNumberInfoVisitor,
ParameterInfoVisitor,
LocalVariableInfoVisitor,
LocalVariableTypeInfoVisitor,
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.writeShort(bootstrapMethodsAttribute.u2bootstrapMethodsCount);
bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this);
}
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
dataOutput.writeShort(sourceFileAttribute.u2sourceFileIndex);
}
public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
{
dataOutput.writeShort(sourceDirAttribute.u2sourceDirIndex);
}
public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
{
// Write the inner classes.
dataOutput.writeShort(innerClassesAttribute.u2classesCount);
innerClassesAttribute.innerClassEntriesAccept(clazz, this);
}
public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
{
dataOutput.writeShort(enclosingMethodAttribute.u2classIndex);
dataOutput.writeShort(enclosingMethodAttribute.u2nameAndTypeIndex);
}
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.writeShort(signatureAttribute.u2signatureIndex);
}
public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
{
dataOutput.writeShort(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.
dataOutput.writeShort(exceptionsAttribute.u2exceptionIndexTableLength);
for (int index = 0; index < exceptionsAttribute.u2exceptionIndexTableLength; index++)
{
dataOutput.writeShort(exceptionsAttribute.u2exceptionIndexTable[index]);
}
}
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
// Write the stack size and local variable frame size.
dataOutput.writeShort(codeAttribute.u2maxStack);
dataOutput.writeShort(codeAttribute.u2maxLocals);
// Write the byte code.
dataOutput.writeInt(codeAttribute.u4codeLength);
dataOutput.write(codeAttribute.code, 0, codeAttribute.u4codeLength);
// Write the exceptions.
dataOutput.writeShort(codeAttribute.u2exceptionTableLength);
codeAttribute.exceptionsAccept(clazz, method, this);
// Write the code attributes.
dataOutput.writeShort(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.writeShort(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.writeShort(stackMapTableAttribute.u2stackMapFramesCount);
stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
}
public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
{
// Write the line numbers.
dataOutput.writeShort(lineNumberTableAttribute.u2lineNumberTableLength);
lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
}
public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
{
// Write the local variables.
dataOutput.writeShort(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.writeShort(localVariableTypeTableAttribute.u2localVariableTypeTableLength);
localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
}
public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
{
// Write the annotations.
dataOutput.writeShort(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.writeShort(u2annotationsCount);
for (int index = 0; index < u2annotationsCount; index++)
{
visitAnnotation(clazz, annotations[index]);
}
}
}
public void visitAnyTypeAnnotationsAttribute(Clazz clazz, TypeAnnotationsAttribute typeAnnotationsAttribute)
{
// Write the type annotations.
dataOutput.writeShort(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.writeShort(bootstrapMethodInfo.u2methodHandleIndex);
// Write the bootstrap method arguments.
dataOutput.writeShort(bootstrapMethodInfo.u2methodArgumentCount);
for (int index = 0; index < bootstrapMethodInfo.u2methodArgumentCount; index++)
{
dataOutput.writeShort(bootstrapMethodInfo.u2methodArguments[index]);
}
}
// Implementations for InnerClassesInfoVisitor.
public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
{
dataOutput.writeShort(innerClassesInfo.u2innerClassIndex);
dataOutput.writeShort(innerClassesInfo.u2outerClassIndex);
dataOutput.writeShort(innerClassesInfo.u2innerNameIndex);
dataOutput.writeShort(innerClassesInfo.u2innerClassAccessFlags);
}
// Implementations for ExceptionInfoVisitor.
public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
{
dataOutput.writeShort(exceptionInfo.u2startPC);
dataOutput.writeShort(exceptionInfo.u2endPC);
dataOutput.writeShort(exceptionInfo.u2handlerPC);
dataOutput.writeShort(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)
{
dataOutput.writeShort(lineNumberInfo.u2startPC);
dataOutput.writeShort(lineNumberInfo.u2lineNumber);
}
// Implementations for ParameterInfoVisitor.
public void visitParameterInfo(Clazz clazz, Method method, int parameterIndex, ParameterInfo parameterInfo)
{
dataOutput.writeShort(parameterInfo.u2nameIndex);
dataOutput.writeShort(parameterInfo.u2accessFlags);
}
// Implementations for LocalVariableInfoVisitor.
public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
{
dataOutput.writeShort(localVariableInfo.u2startPC);
dataOutput.writeShort(localVariableInfo.u2length);
dataOutput.writeShort(localVariableInfo.u2nameIndex);
dataOutput.writeShort(localVariableInfo.u2descriptorIndex);
dataOutput.writeShort(localVariableInfo.u2index);
}
// Implementations for LocalVariableTypeInfoVisitor.
public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
{
dataOutput.writeShort(localVariableTypeInfo.u2startPC);
dataOutput.writeShort(localVariableTypeInfo.u2length);
dataOutput.writeShort(localVariableTypeInfo.u2nameIndex);
dataOutput.writeShort(localVariableTypeInfo.u2signatureIndex);
dataOutput.writeShort(localVariableTypeInfo.u2index);
}
// Implementations for AnnotationVisitor.
public void visitAnnotation(Clazz clazz, Annotation annotation)
{
// Write the annotation type.
dataOutput.writeShort(annotation.u2typeIndex);
// Write the element value pairs.
dataOutput.writeShort(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.writeShort(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.writeShort(throwsTargetInfo.u2throwsTypeIndex);
}
public void visitLocalVariableTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, LocalVariableTargetInfo localVariableTargetInfo)
{
// Write the local variable target elements.
dataOutput.writeShort(localVariableTargetInfo.u2tableLength);
localVariableTargetInfo.targetElementsAccept(clazz, method, codeAttribute, typeAnnotation, this);
}
public void visitCatchTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, CatchTargetInfo catchTargetInfo)
{
dataOutput.writeShort(catchTargetInfo.u2exceptionTableIndex);
}
public void visitOffsetTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, OffsetTargetInfo offsetTargetInfo)
{
dataOutput.writeShort(offsetTargetInfo.u2offset);
}
public void visitTypeArgumentTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, TypeArgumentTargetInfo typeArgumentTargetInfo)
{
dataOutput.writeShort(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.writeShort(localVariableTargetElement.u2startPC);
dataOutput.writeShort(localVariableTargetElement.u2length);
dataOutput.writeShort(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.writeShort(u2elementNameIndex);
}
// Write the tag.
dataOutput.writeByte(elementValue.getTag());
// Write the actual body.
elementValue.accept(clazz, annotation, elementValueBodyWriter);
}
}
private class StackMapFrameBodyWriter
extends SimplifiedVisitor
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.writeShort(sameZeroFrame.u2offsetDelta);
}
}
public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame)
{
if (sameOneFrame.getTag() == StackMapFrame.SAME_ONE_FRAME_EXTENDED)
{
dataOutput.writeShort(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.writeShort(lessZeroFrame.u2offsetDelta);
}
public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame)
{
dataOutput.writeShort(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.writeShort(fullFrame.u2offsetDelta);
// Write the verification types of the local variables.
dataOutput.writeShort(fullFrame.variablesCount);
fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);
// Write the verification types of the stack entries.
dataOutput.writeShort(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
extends SimplifiedVisitor
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.writeShort(objectType.u2classIndex);
}
public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType)
{
dataOutput.writeShort(uninitializedType.u2newInstructionOffset);
}
}
private class ElementValueBodyWriter
extends SimplifiedVisitor
implements ElementValueVisitor
{
// Implementations for ElementValueVisitor.
public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
{
dataOutput.writeShort(constantElementValue.u2constantValueIndex);
}
public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
{
dataOutput.writeShort(enumConstantElementValue.u2typeNameIndex);
dataOutput.writeShort(enumConstantElementValue.u2constantNameIndex);
}
public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
{
dataOutput.writeShort(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.writeShort(arrayElementValue.u2elementValuesCount);
arrayElementValue.elementValuesAccept(clazz, annotation, attributeBodyWriter);
}
}
}