mirror of
https://github.com/revanced/smali.git
synced 2025-06-13 04:27:38 +02:00
Implemented class and method annotations
git-svn-id: https://smali.googlecode.com/svn/trunk@166 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* [The "BSD licence"]
|
||||||
|
* Copyright (c) 2009 Ben Gruver
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
|
import org.jf.dexlib.AnnotationItem;
|
||||||
|
import org.jf.baksmali.Adaptors.EncodedValue.AnnotationEncodedValueAdaptor;
|
||||||
|
import org.jf.baksmali.Adaptors.Reference.TypeReference;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AnnotationAdaptor {
|
||||||
|
private AnnotationItem annotationItem;
|
||||||
|
private AnnotationEncodedValueAdaptor encodedAnnotationAdaptor;
|
||||||
|
|
||||||
|
public AnnotationAdaptor(AnnotationItem annotationItem) {
|
||||||
|
this.annotationItem = annotationItem;
|
||||||
|
this.encodedAnnotationAdaptor = new AnnotationEncodedValueAdaptor(annotationItem.getEncodedAnnotation());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVisibility() {
|
||||||
|
switch (annotationItem.getVisibility()) {
|
||||||
|
case 0:
|
||||||
|
return "build";
|
||||||
|
case 1:
|
||||||
|
return "runtime";
|
||||||
|
case 2:
|
||||||
|
return "system";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeReference getAnnotationType() {
|
||||||
|
return encodedAnnotationAdaptor.getAnnotationType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AnnotationEncodedValueAdaptor.AnnotationElementAdaptor> getElements() {
|
||||||
|
return encodedAnnotationAdaptor.getElements();
|
||||||
|
}
|
||||||
|
}
|
@ -28,23 +28,37 @@
|
|||||||
|
|
||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
import org.jf.dexlib.ClassDataItem;
|
|
||||||
import org.jf.dexlib.ClassDefItem;
|
|
||||||
import org.jf.dexlib.EncodedArrayItem;
|
|
||||||
import org.jf.dexlib.EncodedValue.EncodedValue;
|
import org.jf.dexlib.EncodedValue.EncodedValue;
|
||||||
import org.jf.dexlib.TypeIdItem;
|
import org.jf.dexlib.*;
|
||||||
import org.jf.dexlib.util.AccessFlags;
|
import org.jf.dexlib.util.AccessFlags;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ClassDefinition {
|
public class ClassDefinition {
|
||||||
private ClassDefItem classDefItem;
|
private ClassDefItem classDefItem;
|
||||||
private ClassDataItem classDataItem;
|
private ClassDataItem classDataItem;
|
||||||
|
|
||||||
|
private HashMap<Integer, AnnotationSetItem> methodAnnotations = new HashMap<Integer, AnnotationSetItem>();
|
||||||
|
|
||||||
public ClassDefinition(ClassDefItem classDefItem) {
|
public ClassDefinition(ClassDefItem classDefItem) {
|
||||||
this.classDefItem = classDefItem;
|
this.classDefItem = classDefItem;
|
||||||
this.classDataItem = classDefItem.getClassData();
|
this.classDataItem = classDefItem.getClassData();
|
||||||
|
buildAnnotationMaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildAnnotationMaps() {
|
||||||
|
AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotationDirectory();
|
||||||
|
if (annotationDirectory == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AnnotationDirectoryItem.MethodAnnotation> methodAnnotationList = annotationDirectory.getMethodAnnotations();
|
||||||
|
|
||||||
|
if (methodAnnotations != null) {
|
||||||
|
for (AnnotationDirectoryItem.MethodAnnotation methodAnnotation: methodAnnotationList) {
|
||||||
|
methodAnnotations.put(methodAnnotation.getMethod().getIndex(), methodAnnotation.getAnnotationSet());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> accessFlags = null;
|
private List<String> accessFlags = null;
|
||||||
@ -142,7 +156,8 @@ public class ClassDefinition {
|
|||||||
|
|
||||||
if (classDataItem != null) {
|
if (classDataItem != null) {
|
||||||
for (ClassDataItem.EncodedMethod method: classDataItem.getDirectMethods()) {
|
for (ClassDataItem.EncodedMethod method: classDataItem.getDirectMethods()) {
|
||||||
directMethods.add(new MethodDefinition(method));
|
AnnotationSetItem annotationSet = methodAnnotations.get(method.getMethod().getIndex());
|
||||||
|
directMethods.add(new MethodDefinition(method, annotationSet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,10 +171,30 @@ public class ClassDefinition {
|
|||||||
|
|
||||||
if (classDataItem != null) {
|
if (classDataItem != null) {
|
||||||
for (ClassDataItem.EncodedMethod method: classDataItem.getVirtualMethods()) {
|
for (ClassDataItem.EncodedMethod method: classDataItem.getVirtualMethods()) {
|
||||||
virtualMethods.add(new MethodDefinition(method));
|
AnnotationSetItem annotationSet = methodAnnotations.get(method.getMethod().getIndex());
|
||||||
|
virtualMethods.add(new MethodDefinition(method, annotationSet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return virtualMethods;
|
return virtualMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<AnnotationAdaptor> getAnnotations() {
|
||||||
|
AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotationDirectory();
|
||||||
|
if (annotationDirectory == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations();
|
||||||
|
if (annotationSet == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AnnotationAdaptor> annotationAdaptors = new ArrayList<AnnotationAdaptor>();
|
||||||
|
|
||||||
|
for (AnnotationItem annotationItem: annotationSet.getAnnotationItems()) {
|
||||||
|
annotationAdaptors.add(new AnnotationAdaptor(annotationItem));
|
||||||
|
}
|
||||||
|
return annotationAdaptors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,7 @@
|
|||||||
package org.jf.baksmali.Adaptors;
|
package org.jf.baksmali.Adaptors;
|
||||||
|
|
||||||
import org.jf.baksmali.Adaptors.Format.*;
|
import org.jf.baksmali.Adaptors.Format.*;
|
||||||
import org.jf.dexlib.ClassDataItem;
|
import org.jf.dexlib.*;
|
||||||
import org.jf.dexlib.CodeItem;
|
|
||||||
import org.jf.dexlib.MethodIdItem;
|
|
||||||
import org.jf.dexlib.code.Format.*;
|
import org.jf.dexlib.code.Format.*;
|
||||||
import org.jf.dexlib.code.Instruction;
|
import org.jf.dexlib.code.Instruction;
|
||||||
import org.jf.dexlib.code.InstructionField;
|
import org.jf.dexlib.code.InstructionField;
|
||||||
@ -44,11 +42,13 @@ public class MethodDefinition {
|
|||||||
private ClassDataItem.EncodedMethod encodedMethod;
|
private ClassDataItem.EncodedMethod encodedMethod;
|
||||||
private MethodIdItem methodIdItem;
|
private MethodIdItem methodIdItem;
|
||||||
private CodeItem codeItem;
|
private CodeItem codeItem;
|
||||||
|
private AnnotationSetItem annotationSet;
|
||||||
|
|
||||||
public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) {
|
public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod, AnnotationSetItem annotationSet) {
|
||||||
this.encodedMethod = encodedMethod;
|
this.encodedMethod = encodedMethod;
|
||||||
this.methodIdItem = encodedMethod.getMethod();
|
this.methodIdItem = encodedMethod.getMethod();
|
||||||
this.codeItem = encodedMethod.getCodeItem();
|
this.codeItem = encodedMethod.getCodeItem();
|
||||||
|
this.annotationSet = annotationSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String methodName = null;
|
private String methodName = null;
|
||||||
@ -99,6 +99,19 @@ public class MethodDefinition {
|
|||||||
return registerCount;
|
return registerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<AnnotationAdaptor> getAnnotations() {
|
||||||
|
if (annotationSet == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AnnotationAdaptor> annotationAdaptors = new ArrayList<AnnotationAdaptor>();
|
||||||
|
|
||||||
|
for (AnnotationItem annotationItem: annotationSet.getAnnotationItems()) {
|
||||||
|
annotationAdaptors.add(new AnnotationAdaptor(annotationItem));
|
||||||
|
}
|
||||||
|
return annotationAdaptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<MethodItem> methodItems = null;
|
private List<MethodItem> methodItems = null;
|
||||||
public List<MethodItem> getMethodItems() {
|
public List<MethodItem> getMethodItems() {
|
||||||
|
@ -9,6 +9,13 @@ smaliFile(classDef) ::=
|
|||||||
# interfaces
|
# interfaces
|
||||||
<classDef.Interfaces: implement(it); separator="\n">
|
<classDef.Interfaces: implement(it); separator="\n">
|
||||||
|
|
||||||
|
<endif>
|
||||||
|
<if(classDef.Annotations)>
|
||||||
|
|
||||||
|
|
||||||
|
# annotations
|
||||||
|
<classDef.Annotations: annotation(it); separator="\n\n">
|
||||||
|
|
||||||
<endif>
|
<endif>
|
||||||
<if(classDef.StaticFields)>
|
<if(classDef.StaticFields)>
|
||||||
|
|
||||||
@ -49,6 +56,19 @@ implement(interface) ::=
|
|||||||
>>
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
annotation(annotationAdaptor) ::=
|
||||||
|
<<
|
||||||
|
.annotation <annotationAdaptor.Visibility> <Reference(annotationAdaptor.AnnotationType)>
|
||||||
|
<if(annotationAdaptor.Elements)>
|
||||||
|
<annotationAdaptor.Elements: AnnotationElement(it); separator="\n">
|
||||||
|
<endif>
|
||||||
|
<if(annotationAdaptor.Elements)>
|
||||||
|
|
||||||
|
|
||||||
|
<endif>
|
||||||
|
.end annotation
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
field(fieldDef) ::=
|
field(fieldDef) ::=
|
||||||
@ -60,12 +80,19 @@ field(fieldDef) ::=
|
|||||||
method(methodDef) ::=
|
method(methodDef) ::=
|
||||||
<<
|
<<
|
||||||
.method <methodDef.AccessFlags; separator=" "> <methodDef.MethodName><methodDef.Prototype>
|
.method <methodDef.AccessFlags; separator=" "> <methodDef.MethodName><methodDef.Prototype>
|
||||||
<if(methodDef.hasCode)>
|
<if(methodDef.hasCode)>
|
||||||
.registers <methodDef.RegisterCount>
|
.registers <methodDef.RegisterCount>
|
||||||
|
<if(methodDef.Annotations)>
|
||||||
|
<methodDef.Annotations: annotation(it); separator="\n\n">
|
||||||
|
<endif>
|
||||||
|
|
||||||
<methodDef.MethodItems: MethodItem(it); separator="\n">
|
<methodDef.MethodItems: MethodItem(it); separator="\n">
|
||||||
<endif>
|
|
||||||
.end method
|
.end method
|
||||||
|
<elseif(methodDef.Annotations)>
|
||||||
|
<methodDef.Annotations: annotation(it); separator="\n\n">
|
||||||
|
.end method
|
||||||
|
<endif>
|
||||||
|
|
||||||
>>
|
>>
|
||||||
|
|
||||||
MethodItem(MethodItem) ::=
|
MethodItem(MethodItem) ::=
|
||||||
@ -291,7 +318,7 @@ EnumEncodedValue(EncodedValue) ::=
|
|||||||
|
|
||||||
AnnotationEncodedValue(EncodedValue) ::=
|
AnnotationEncodedValue(EncodedValue) ::=
|
||||||
<<
|
<<
|
||||||
.subannotation EncodedValue.Type
|
.subannotation <Reference(EncodedValue.AnnotationType)>
|
||||||
<EncodedValue.Elements: AnnotationElement(it); separator="\n">
|
<EncodedValue.Elements: AnnotationElement(it); separator="\n">
|
||||||
.end subannotation
|
.end subannotation
|
||||||
>>
|
>>
|
||||||
|
@ -5,6 +5,19 @@
|
|||||||
.implements Lsome/other/interface;
|
.implements Lsome/other/interface;
|
||||||
|
|
||||||
|
|
||||||
|
.annotation build Lsome/annotation;
|
||||||
|
value1 = "test"
|
||||||
|
value2 = .subannotation Lsome/annotation;
|
||||||
|
value1 = "test2"
|
||||||
|
value2 = Lsome/enum;
|
||||||
|
.end subannotation
|
||||||
|
.end annotation
|
||||||
|
|
||||||
|
.annotation system Lsome/annotation;
|
||||||
|
.end annotation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.field public static aStaticFieldWithoutAnInitializer:I
|
.field public static aStaticFieldWithoutAnInitializer:I
|
||||||
|
|
||||||
.field public static longStaticField:J = 0x300000000L
|
.field public static longStaticField:J = 0x300000000L
|
||||||
@ -63,6 +76,12 @@
|
|||||||
|
|
||||||
.method public testMethod(ILjava/lang/String;)Ljava/lang/String;
|
.method public testMethod(ILjava/lang/String;)Ljava/lang/String;
|
||||||
.registers 3
|
.registers 3
|
||||||
|
.annotation runtime Lorg/junit/Test;
|
||||||
|
.end annotation
|
||||||
|
.annotation system Lyet/another/annotation;
|
||||||
|
somevalue = 1234
|
||||||
|
anothervalue = 3.14159
|
||||||
|
.end annotation
|
||||||
|
|
||||||
const-string v0, "testing\n123"
|
const-string v0, "testing\n123"
|
||||||
|
|
||||||
@ -96,3 +115,13 @@
|
|||||||
|
|
||||||
.end method
|
.end method
|
||||||
|
|
||||||
|
.method public abstract testMethod2()V
|
||||||
|
.annotation runtime Lsome/annotation;
|
||||||
|
subannotation = .subannotation Lsome/other/annotation;
|
||||||
|
value = "value"
|
||||||
|
.end subannotation
|
||||||
|
.end annotation
|
||||||
|
.annotation runtime Lorg/junit/Test;
|
||||||
|
.end annotation
|
||||||
|
.end method
|
||||||
|
|
||||||
|
@ -119,6 +119,14 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
|||||||
return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
|
return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AnnotationSetItem getClassAnnotations() {
|
||||||
|
return classAnnotationsReferenceField.getReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MethodAnnotation> getMethodAnnotations() {
|
||||||
|
return methodAnnotationList;
|
||||||
|
}
|
||||||
|
|
||||||
public static class FieldAnnotation extends CompositeField<FieldAnnotation>
|
public static class FieldAnnotation extends CompositeField<FieldAnnotation>
|
||||||
implements Comparable<FieldAnnotation> {
|
implements Comparable<FieldAnnotation> {
|
||||||
private final IndexedItemReference<FieldIdItem> fieldReferenceField;
|
private final IndexedItemReference<FieldIdItem> fieldReferenceField;
|
||||||
@ -170,6 +178,14 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
|||||||
public int compareTo(MethodAnnotation o) {
|
public int compareTo(MethodAnnotation o) {
|
||||||
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
|
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MethodIdItem getMethod() {
|
||||||
|
return method.getReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnnotationSetItem getAnnotationSet() {
|
||||||
|
return annotationSet.getReference();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ParameterAnnotation extends CompositeField<ParameterAnnotation>
|
public static class ParameterAnnotation extends CompositeField<ParameterAnnotation>
|
||||||
|
@ -60,4 +60,12 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
|||||||
public String getConciseIdentity() {
|
public String getConciseIdentity() {
|
||||||
return "annotation_item @0x" + Integer.toHexString(getOffset());
|
return "annotation_item @0x" + Integer.toHexString(getOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getVisibility() {
|
||||||
|
return (byte)visibilityField.getCachedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnnotationEncodedValueSubField getEncodedAnnotation() {
|
||||||
|
return annotationField;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,4 +74,13 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
|||||||
public String getConciseIdentity() {
|
public String getConciseIdentity() {
|
||||||
return "annotation_set_item @0x" + Integer.toHexString(getOffset());
|
return "annotation_set_item @0x" + Integer.toHexString(getOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<AnnotationItem> getAnnotationItems() {
|
||||||
|
List<AnnotationItem> annotationItems = new ArrayList<AnnotationItem>();
|
||||||
|
|
||||||
|
for (OffsettedItemReference<AnnotationItem> annotationItemReference: annotationReferences) {
|
||||||
|
annotationItems.add(annotationItemReference.getReference());
|
||||||
|
}
|
||||||
|
return annotationItems;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,10 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
return classDataReferenceField.getReference();
|
return classDataReferenceField.getReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AnnotationDirectoryItem getAnnotationDirectory() {
|
||||||
|
return classAnnotationsReferenceField.getReference();
|
||||||
|
}
|
||||||
|
|
||||||
public String getConciseIdentity() {
|
public String getConciseIdentity() {
|
||||||
return "class_def_item: " + getClassName();
|
return "class_def_item: " + getClassName();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user