diff options
Diffstat (limited to 'src/proguard/classfile/io/ProgramClassWriter.java')
-rw-r--r-- | src/proguard/classfile/io/ProgramClassWriter.java | 690 |
1 files changed, 690 insertions, 0 deletions
diff --git a/src/proguard/classfile/io/ProgramClassWriter.java b/src/proguard/classfile/io/ProgramClassWriter.java new file mode 100644 index 0000000..e56f08a --- /dev/null +++ b/src/proguard/classfile/io/ProgramClassWriter.java @@ -0,0 +1,690 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.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 reading from 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 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 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, + InnerClassesInfoVisitor, + ExceptionInfoVisitor, + StackMapFrameVisitor, + VerificationTypeVisitor, + LineNumberInfoVisitor, + LocalVariableInfoVisitor, + LocalVariableTypeInfoVisitor, + AnnotationVisitor, + ElementValueVisitor + { + // Implementations for AttributeVisitor. + + public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) + { + // Write the unknown information. + dataOutput.write(unknownAttribute.info); + } + + + 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 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.u2parametersCount); + + for (int parameterIndex = 0; parameterIndex < parameterAnnotationsAttribute.u2parametersCount; 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++) + { + Annotation annotation = annotations[index]; + this.visitAnnotation(clazz, annotation); + } + + } + } + + + public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) + { + // Write the default element value. + annotationDefaultAttribute.defaultValue.accept(clazz, null, this); + } + + + // 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 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 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); + } + } +} |