blob: 9abea450c187e6df7ccba17b11059853526b5442 [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.editor;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* This AttributeVisitor adds all attributes that it visits to the given
* target class, class member, or attribute.
*
* @author Eric Lafortune
*/
public class AttributeAdder
extends SimplifiedVisitor
implements AttributeVisitor
{
private static final byte[] EMPTY_BYTES = new byte[0];
private static final int[] EMPTY_INTS = new int[0];
private static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0];
private static final ExceptionInfo[] EMPTY_EXCEPTIONS = new ExceptionInfo[0];
private static final Annotation[] EMPTY_ANNOTATIONS = new Annotation[0];
private final ProgramClass targetClass;
private final ProgramMember targetMember;
private final CodeAttribute targetCodeAttribute;
private final boolean replaceAttributes;
private final ConstantAdder constantAdder;
private final AttributesEditor attributesEditor;
/**
* Creates a new AttributeAdder that will copy attributes into the given
* target class.
*/
public AttributeAdder(ProgramClass targetClass,
boolean replaceAttributes)
{
this(targetClass, null, null, replaceAttributes);
}
/**
* Creates a new AttributeAdder that will copy attributes into the given
* target class member.
*/
public AttributeAdder(ProgramClass targetClass,
ProgramMember targetMember,
boolean replaceAttributes)
{
this(targetClass, targetMember, null, replaceAttributes);
}
/**
* Creates a new AttributeAdder that will copy attributes into the given
* target attribute.
*/
public AttributeAdder(ProgramClass targetClass,
ProgramMember targetMember,
CodeAttribute targetCodeAttribute,
boolean replaceAttributes)
{
this.targetClass = targetClass;
this.targetMember = targetMember;
this.targetCodeAttribute = targetCodeAttribute;
this.replaceAttributes = replaceAttributes;
constantAdder = new ConstantAdder(targetClass);
attributesEditor = new AttributesEditor(targetClass,
targetMember,
targetCodeAttribute,
replaceAttributes);
}
// Implementations for AttributeVisitor.
public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
{
// Create a copy of the attribute.
UnknownAttribute newUnknownAttribute =
new UnknownAttribute(constantAdder.addConstant(clazz, unknownAttribute.u2attributeNameIndex),
unknownAttribute.u4attributeLength,
unknownAttribute.info);
// Add it to the target class.
attributesEditor.addAttribute(newUnknownAttribute);
}
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
// Create a copy of the attribute.
SourceFileAttribute newSourceFileAttribute =
new SourceFileAttribute(constantAdder.addConstant(clazz, sourceFileAttribute.u2attributeNameIndex),
constantAdder.addConstant(clazz, sourceFileAttribute.u2sourceFileIndex));
// Add it to the target class.
attributesEditor.addAttribute(newSourceFileAttribute);
}
public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
{
// Create a copy of the attribute.
SourceDirAttribute newSourceDirAttribute =
new SourceDirAttribute(constantAdder.addConstant(clazz, sourceDirAttribute.u2attributeNameIndex),
constantAdder.addConstant(clazz, sourceDirAttribute.u2sourceDirIndex));
// Add it to the target class.
attributesEditor.addAttribute(newSourceDirAttribute);
}
public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
{
// Create a copy of the attribute.
InnerClassesAttribute newInnerClassesAttribute =
new InnerClassesAttribute(constantAdder.addConstant(clazz, innerClassesAttribute.u2attributeNameIndex),
0,
null);
// Add it to the target class.
attributesEditor.addAttribute(newInnerClassesAttribute);
}
public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
{
// Create a copy of the attribute.
EnclosingMethodAttribute newEnclosingMethodAttribute =
new EnclosingMethodAttribute(constantAdder.addConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex),
constantAdder.addConstant(clazz, enclosingMethodAttribute.u2classIndex),
enclosingMethodAttribute.u2nameAndTypeIndex == 0 ? 0 :
constantAdder.addConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex));
newEnclosingMethodAttribute.referencedClass = enclosingMethodAttribute.referencedClass;
newEnclosingMethodAttribute.referencedMethod = enclosingMethodAttribute.referencedMethod;
// Add it to the target class.
attributesEditor.addAttribute(newEnclosingMethodAttribute);
}
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
// Create a copy of the attribute.
DeprecatedAttribute newDeprecatedAttribute =
new DeprecatedAttribute(constantAdder.addConstant(clazz, deprecatedAttribute.u2attributeNameIndex));
// Add it to the target.
attributesEditor.addAttribute(newDeprecatedAttribute);
}
public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
{
// Create a copy of the attribute.
SyntheticAttribute newSyntheticAttribute =
new SyntheticAttribute(constantAdder.addConstant(clazz, syntheticAttribute.u2attributeNameIndex));
// Add it to the target.
attributesEditor.addAttribute(newSyntheticAttribute);
}
public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
{
// Create a copy of the attribute.
SignatureAttribute newSignatureAttribute =
new SignatureAttribute(constantAdder.addConstant(clazz, signatureAttribute.u2attributeNameIndex),
constantAdder.addConstant(clazz, signatureAttribute.u2signatureIndex));
newSignatureAttribute.referencedClasses = signatureAttribute.referencedClasses;
// Add it to the target.
attributesEditor.addAttribute(newSignatureAttribute);
}
public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
{
// Create a copy of the attribute.
ConstantValueAttribute newConstantValueAttribute =
new ConstantValueAttribute(constantAdder.addConstant(clazz, constantValueAttribute.u2attributeNameIndex),
constantAdder.addConstant(clazz, constantValueAttribute.u2constantValueIndex));
// Add it to the target field.
attributesEditor.addAttribute(newConstantValueAttribute);
}
public void visitMethodParametersAttribute(Clazz clazz, Method method, MethodParametersAttribute methodParametersAttribute)
{
// Create a new local variable table attribute.
MethodParametersAttribute newMethodParametersAttribute =
new MethodParametersAttribute(constantAdder.addConstant(clazz, methodParametersAttribute.u2attributeNameIndex),
methodParametersAttribute.u1parametersCount,
new ParameterInfo[methodParametersAttribute.u1parametersCount]);
// Add the local variables.
methodParametersAttribute.parametersAccept(clazz,
method,
new ParameterInfoAdder(targetClass, newMethodParametersAttribute));
// Add it to the target.
attributesEditor.addAttribute(newMethodParametersAttribute);
}
public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
{
// Create a new exceptions attribute.
ExceptionsAttribute newExceptionsAttribute =
new ExceptionsAttribute(constantAdder.addConstant(clazz, exceptionsAttribute.u2attributeNameIndex),
0,
exceptionsAttribute.u2exceptionIndexTableLength > 0 ?
new int[exceptionsAttribute.u2exceptionIndexTableLength] :
EMPTY_INTS);
// Add the exceptions.
exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz,
new ExceptionAdder(targetClass,
newExceptionsAttribute));
// Add it to the target method.
attributesEditor.addAttribute(newExceptionsAttribute);
}
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
// Create a new code attribute.
CodeAttribute newCodeAttribute =
new CodeAttribute(constantAdder.addConstant(clazz, codeAttribute.u2attributeNameIndex),
codeAttribute.u2maxStack,
codeAttribute.u2maxLocals,
0,
EMPTY_BYTES,
0,
codeAttribute.u2exceptionTableLength > 0 ?
new ExceptionInfo[codeAttribute.u2exceptionTableLength] :
EMPTY_EXCEPTIONS,
0,
codeAttribute.u2attributesCount > 0 ?
new Attribute[codeAttribute.u2attributesCount] :
EMPTY_ATTRIBUTES);
CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer();
codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength + 32);
// Add the instructions.
codeAttribute.instructionsAccept(clazz,
method,
new InstructionAdder(targetClass,
codeAttributeComposer));
// Append a label just after the code.
codeAttributeComposer.appendLabel(codeAttribute.u4codeLength);
// Add the exceptions.
codeAttribute.exceptionsAccept(clazz,
method,
new ExceptionInfoAdder(targetClass,
codeAttributeComposer));
codeAttributeComposer.endCodeFragment();
// Add the attributes.
codeAttribute.attributesAccept(clazz,
method,
new AttributeAdder(targetClass,
targetMember,
newCodeAttribute,
replaceAttributes));
// Apply these changes to the new code attribute.
codeAttributeComposer.visitCodeAttribute(targetClass,
(Method)targetMember,
newCodeAttribute);
// Add the completed code attribute to the target method.
attributesEditor.addAttribute(newCodeAttribute);
}
public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
{
// TODO: Implement method.
}
public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
{
// TODO: Implement method.
}
public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
{
// Create a new line number table attribute.
LineNumberTableAttribute newLineNumberTableAttribute =
new LineNumberTableAttribute(constantAdder.addConstant(clazz, lineNumberTableAttribute.u2attributeNameIndex),
0,
new LineNumberInfo[lineNumberTableAttribute.u2lineNumberTableLength]);
// Add the line numbers.
lineNumberTableAttribute.lineNumbersAccept(clazz,
method,
codeAttribute,
new LineNumberInfoAdder(newLineNumberTableAttribute));
// Add it to the target.
attributesEditor.addAttribute(newLineNumberTableAttribute);
}
public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
{
// Create a new local variable table attribute.
LocalVariableTableAttribute newLocalVariableTableAttribute =
new LocalVariableTableAttribute(constantAdder.addConstant(clazz, localVariableTableAttribute.u2attributeNameIndex),
0,
new LocalVariableInfo[localVariableTableAttribute.u2localVariableTableLength]);
// Add the local variables.
localVariableTableAttribute.localVariablesAccept(clazz,
method,
codeAttribute,
new LocalVariableInfoAdder(targetClass, newLocalVariableTableAttribute));
// Add it to the target.
attributesEditor.addAttribute(newLocalVariableTableAttribute);
}
public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
{
// Create a new local variable type table attribute.
LocalVariableTypeTableAttribute newLocalVariableTypeTableAttribute =
new LocalVariableTypeTableAttribute(constantAdder.addConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex),
0,
new LocalVariableTypeInfo[localVariableTypeTableAttribute.u2localVariableTypeTableLength]);
// Add the local variable types.
localVariableTypeTableAttribute.localVariablesAccept(clazz,
method,
codeAttribute,
new LocalVariableTypeInfoAdder(targetClass, newLocalVariableTypeTableAttribute));
// Add it to the target.
attributesEditor.addAttribute(newLocalVariableTypeTableAttribute);
}
public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
{
// Create a new annotations attribute.
RuntimeVisibleAnnotationsAttribute newAnnotationsAttribute =
new RuntimeVisibleAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleAnnotationsAttribute.u2attributeNameIndex),
0,
new Annotation[runtimeVisibleAnnotationsAttribute.u2annotationsCount]);
// Add the annotations.
runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz,
new AnnotationAdder(targetClass,
newAnnotationsAttribute));
// Add it to the target.
attributesEditor.addAttribute(newAnnotationsAttribute);
}
public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
{
// Create a new annotations attribute.
RuntimeInvisibleAnnotationsAttribute newAnnotationsAttribute =
new RuntimeInvisibleAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleAnnotationsAttribute.u2attributeNameIndex),
0,
new Annotation[runtimeInvisibleAnnotationsAttribute.u2annotationsCount]);
// Add the annotations.
runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz,
new AnnotationAdder(targetClass,
newAnnotationsAttribute));
// Add it to the target.
attributesEditor.addAttribute(newAnnotationsAttribute);
}
public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute)
{
// Create a new annotations attribute.
Annotation[][] parameterAnnotations =
new Annotation[runtimeVisibleParameterAnnotationsAttribute.u1parametersCount][];
Arrays.fill(parameterAnnotations, EMPTY_ANNOTATIONS);
RuntimeVisibleParameterAnnotationsAttribute newParameterAnnotationsAttribute =
new RuntimeVisibleParameterAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleParameterAnnotationsAttribute.u2attributeNameIndex),
0,
new int[runtimeVisibleParameterAnnotationsAttribute.u1parametersCount],
parameterAnnotations);
// Add the annotations.
runtimeVisibleParameterAnnotationsAttribute.annotationsAccept(clazz,
method,
new AnnotationAdder(targetClass,
newParameterAnnotationsAttribute));
// Add it to the target.
attributesEditor.addAttribute(newParameterAnnotationsAttribute);
}
public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute)
{
// Create a new annotations attribute.
Annotation[][] parameterAnnotations =
new Annotation[runtimeInvisibleParameterAnnotationsAttribute.u1parametersCount][];
Arrays.fill(parameterAnnotations, EMPTY_ANNOTATIONS);
RuntimeInvisibleParameterAnnotationsAttribute newParameterAnnotationsAttribute =
new RuntimeInvisibleParameterAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleParameterAnnotationsAttribute.u2attributeNameIndex),
0,
new int[runtimeInvisibleParameterAnnotationsAttribute.u1parametersCount],
parameterAnnotations);
// Add the annotations.
runtimeInvisibleParameterAnnotationsAttribute.annotationsAccept(clazz,
method,
new AnnotationAdder(targetClass,
newParameterAnnotationsAttribute));
// Add it to the target.
attributesEditor.addAttribute(newParameterAnnotationsAttribute);
}
public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
{
// Create a new annotation default attribute.
AnnotationDefaultAttribute newAnnotationDefaultAttribute =
new AnnotationDefaultAttribute(constantAdder.addConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex),
null);
// Add the annotations.
annotationDefaultAttribute.defaultValueAccept(clazz,
new ElementValueAdder(targetClass,
newAnnotationDefaultAttribute,
false));
// Add it to the target.
attributesEditor.addAttribute(newAnnotationDefaultAttribute);
}
}