mirror of
https://github.com/revanced/smali.git
synced 2025-05-29 12:20:11 +02:00
- Added the ability to dexlib to do an annotated dump of the dex file as it is writing it (similiar to the --dump-to functionality in dx)
- Other misc refactoring and cleanup in dexlib git-svn-id: https://smali.googlecode.com/svn/trunk@50 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
dbdfc6f468
commit
35329727a4
File diff suppressed because it is too large
Load Diff
@ -36,48 +36,50 @@ import java.util.Collections;
|
|||||||
|
|
||||||
//TODO: fix field names in dex-format.html and submit
|
//TODO: fix field names in dex-format.html and submit
|
||||||
public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryItem> {
|
public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryItem> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ArrayList<FieldAnnotation> fieldAnnotationList = new ArrayList<FieldAnnotation>();
|
private final ArrayList<FieldAnnotation> fieldAnnotationList = new ArrayList<FieldAnnotation>();
|
||||||
private final ArrayList<MethodAnnotation> methodAnnotationList = new ArrayList<MethodAnnotation>();
|
private final ArrayList<MethodAnnotation> methodAnnotationList = new ArrayList<MethodAnnotation>();
|
||||||
private final ArrayList<ParameterAnnotation> parameterAnnotationList = new ArrayList<ParameterAnnotation>();
|
private final ArrayList<ParameterAnnotation> parameterAnnotationList = new ArrayList<ParameterAnnotation>();
|
||||||
|
|
||||||
private final OffsettedItemReference<AnnotationSetItem> classAnnotations;
|
private final OffsettedItemReference<AnnotationSetItem> classAnnotationsReferenceField;
|
||||||
private final ListSizeField annotatedFieldsCount;
|
private final ListSizeField annotatedFieldsCountField;
|
||||||
private final ListSizeField annotatedMethodsCount;
|
private final ListSizeField annotatedMethodsCountField;
|
||||||
private final ListSizeField annotatedParametersCount;
|
private final ListSizeField annotatedParametersCountField;
|
||||||
private final FieldListField<FieldAnnotation> fieldAnnotations;
|
private final FieldListField<FieldAnnotation> fieldAnnotationListField;
|
||||||
private final FieldListField<MethodAnnotation> methodAnnotations;
|
private final FieldListField<MethodAnnotation> methodAnnotationListField;
|
||||||
private final FieldListField<ParameterAnnotation> parameterAnnotations;
|
private final FieldListField<ParameterAnnotation> parameterAnnotationListField;
|
||||||
|
|
||||||
public AnnotationDirectoryItem(final DexFile dexFile, int offset) {
|
public AnnotationDirectoryItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
classAnnotations = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField()),
|
classAnnotationsReferenceField = new OffsettedItemReference<AnnotationSetItem>(
|
||||||
annotatedFieldsCount = new ListSizeField(fieldAnnotationList, new IntegerField()),
|
dexFile.AnnotationSetsSection, new IntegerField(null), "class_annotations_off"),
|
||||||
annotatedMethodsCount = new ListSizeField(methodAnnotationList, new IntegerField()),
|
annotatedFieldsCountField = new ListSizeField(fieldAnnotationList, new IntegerField("fields_size")),
|
||||||
annotatedParametersCount = new ListSizeField(parameterAnnotationList, new IntegerField()),
|
annotatedMethodsCountField = new ListSizeField(methodAnnotationList,
|
||||||
fieldAnnotations = new FieldListField<FieldAnnotation>(fieldAnnotationList) {
|
new IntegerField("annotated_methods_size")),
|
||||||
|
annotatedParametersCountField = new ListSizeField(parameterAnnotationList,
|
||||||
|
new IntegerField("annotated_parameters_size")),
|
||||||
|
fieldAnnotationListField = new FieldListField<FieldAnnotation>(fieldAnnotationList,
|
||||||
|
"field_annotations") {
|
||||||
protected FieldAnnotation make() {
|
protected FieldAnnotation make() {
|
||||||
return new FieldAnnotation(dexFile);
|
return new FieldAnnotation(dexFile);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methodAnnotations = new FieldListField<MethodAnnotation>(methodAnnotationList) {
|
methodAnnotationListField = new FieldListField<MethodAnnotation>(methodAnnotationList,
|
||||||
|
"method_annotations") {
|
||||||
protected MethodAnnotation make() {
|
protected MethodAnnotation make() {
|
||||||
return new MethodAnnotation(dexFile);
|
return new MethodAnnotation(dexFile);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
parameterAnnotations = new FieldListField<ParameterAnnotation>(parameterAnnotationList) {
|
parameterAnnotationListField = new FieldListField<ParameterAnnotation>(parameterAnnotationList,
|
||||||
|
"parameter_annotations") {
|
||||||
protected ParameterAnnotation make() {
|
protected ParameterAnnotation make() {
|
||||||
return new ParameterAnnotation(dexFile);
|
return new ParameterAnnotation(dexFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public AnnotationDirectoryItem(final DexFile dexFile,
|
public AnnotationDirectoryItem(final DexFile dexFile,
|
||||||
AnnotationSetItem classAnnotations,
|
AnnotationSetItem classAnnotations,
|
||||||
List<FieldAnnotation> fieldAnnotations,
|
List<FieldAnnotation> fieldAnnotations,
|
||||||
@ -85,22 +87,21 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
|||||||
List<ParameterAnnotation> parameterAnnotations) {
|
List<ParameterAnnotation> parameterAnnotations) {
|
||||||
this(dexFile, -1);
|
this(dexFile, -1);
|
||||||
|
|
||||||
this.classAnnotations.setReference(classAnnotations);
|
classAnnotationsReferenceField.setReference(classAnnotations);
|
||||||
|
|
||||||
if (fieldAnnotations != null) {
|
if (fieldAnnotationListField != null) {
|
||||||
this.fieldAnnotationList.addAll(fieldAnnotations);
|
fieldAnnotationList.addAll(fieldAnnotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methodAnnotations != null) {
|
if (methodAnnotationListField != null) {
|
||||||
this.methodAnnotationList.addAll(methodAnnotations);
|
methodAnnotationList.addAll(methodAnnotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameterAnnotations != null) {
|
if (parameterAnnotations != null) {
|
||||||
this.parameterAnnotationList.addAll(parameterAnnotations);
|
parameterAnnotationList.addAll(parameterAnnotations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int place(int index, int offset)
|
public int place(int index, int offset)
|
||||||
{
|
{
|
||||||
Collections.sort(fieldAnnotationList);
|
Collections.sort(fieldAnnotationList);
|
||||||
@ -113,54 +114,53 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
|
return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
|
||||||
|
}
|
||||||
|
|
||||||
public static class FieldAnnotation extends CompositeField<FieldAnnotation>
|
public static class FieldAnnotation extends CompositeField<FieldAnnotation>
|
||||||
implements Comparable<FieldAnnotation> {
|
implements Comparable<FieldAnnotation> {
|
||||||
private final Field[] fields;
|
private final IndexedItemReference<FieldIdItem> fieldReferenceField;
|
||||||
|
private final OffsettedItemReference<AnnotationSetItem> annotationSetReferenceField;
|
||||||
private final IndexedItemReference<FieldIdItem> field;
|
|
||||||
private final OffsettedItemReference<AnnotationSetItem> annotationSet;
|
|
||||||
|
|
||||||
public FieldAnnotation(DexFile dexFile) {
|
public FieldAnnotation(DexFile dexFile) {
|
||||||
|
super("field_annotation");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection, new IntegerField()),
|
fieldReferenceField = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection,
|
||||||
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
|
new IntegerField(null), "field_idx"),
|
||||||
|
annotationSetReferenceField = new OffsettedItemReference<AnnotationSetItem>(
|
||||||
|
dexFile.AnnotationSetsSection, new IntegerField(null), "annotations_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldAnnotation(DexFile dexFile, FieldIdItem field, AnnotationSetItem annotationSet) {
|
public FieldAnnotation(DexFile dexFile, FieldIdItem field, AnnotationSetItem annotationSet) {
|
||||||
this(dexFile);
|
this(dexFile);
|
||||||
this.field.setReference(field);
|
this.fieldReferenceField.setReference(field);
|
||||||
this.annotationSet.setReference(annotationSet);
|
this.annotationSetReferenceField.setReference(annotationSet);
|
||||||
}
|
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(FieldAnnotation o) {
|
public int compareTo(FieldAnnotation o) {
|
||||||
return ((Integer)field.getReference().getIndex()).compareTo(o.field.getReference().getIndex());
|
return ((Integer) fieldReferenceField.getReference().getIndex()).compareTo(
|
||||||
|
o.fieldReferenceField.getReference().getIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MethodAnnotation extends CompositeField<MethodAnnotation>
|
public static class MethodAnnotation extends CompositeField<MethodAnnotation>
|
||||||
implements Comparable<MethodAnnotation> {
|
implements Comparable<MethodAnnotation> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final IndexedItemReference<MethodIdItem> method;
|
private final IndexedItemReference<MethodIdItem> method;
|
||||||
private final OffsettedItemReference<AnnotationSetItem> annotationSet;
|
private final OffsettedItemReference<AnnotationSetItem> annotationSet;
|
||||||
|
|
||||||
public MethodAnnotation(DexFile dexFile) {
|
public MethodAnnotation(DexFile dexFile) {
|
||||||
|
super("method_annotation");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()),
|
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
|
||||||
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
|
new IntegerField(null), "method_idx"),
|
||||||
|
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection,
|
||||||
|
new IntegerField(null), "annotations_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,10 +170,6 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
|||||||
this.annotationSet.setReference(annotationSet);
|
this.annotationSet.setReference(annotationSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
||||||
}
|
}
|
||||||
@ -181,16 +177,16 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
|||||||
|
|
||||||
public static class ParameterAnnotation extends CompositeField<ParameterAnnotation>
|
public static class ParameterAnnotation extends CompositeField<ParameterAnnotation>
|
||||||
implements Comparable<ParameterAnnotation> {
|
implements Comparable<ParameterAnnotation> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final IndexedItemReference<MethodIdItem> method;
|
private final IndexedItemReference<MethodIdItem> method;
|
||||||
private final OffsettedItemReference<AnnotationSetRefList> parameterAnnotations;
|
private final OffsettedItemReference<AnnotationSetRefList> parameterAnnotations;
|
||||||
|
|
||||||
public ParameterAnnotation(DexFile dexFile) {
|
public ParameterAnnotation(DexFile dexFile) {
|
||||||
|
super("parameter_annotation");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()),
|
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
|
||||||
|
new IntegerField(null), "method_idx"),
|
||||||
parameterAnnotations = new OffsettedItemReference<AnnotationSetRefList>(
|
parameterAnnotations = new OffsettedItemReference<AnnotationSetRefList>(
|
||||||
dexFile.AnnotationSetRefListsSection, new IntegerField())
|
dexFile.AnnotationSetRefListsSection, new IntegerField(null), "annotations_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,10 +196,6 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
|||||||
this.parameterAnnotations.setReference(parameterAnnotations);
|
this.parameterAnnotations.setReference(parameterAnnotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int compareTo(ParameterAnnotation o) {
|
public int compareTo(ParameterAnnotation o) {
|
||||||
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
|
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
|
||||||
}
|
}
|
||||||
|
@ -32,17 +32,15 @@ import org.JesusFreke.dexlib.EncodedValue.AnnotationEncodedValueSubField;
|
|||||||
import org.JesusFreke.dexlib.ItemType;
|
import org.JesusFreke.dexlib.ItemType;
|
||||||
|
|
||||||
public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
||||||
private final Field[] fields;
|
private final ByteField visibilityField;
|
||||||
|
private final AnnotationEncodedValueSubField annotationField;
|
||||||
private final ByteField visibility;
|
|
||||||
private final AnnotationEncodedValueSubField annotation;
|
|
||||||
|
|
||||||
public AnnotationItem(DexFile dexFile, int offset) {
|
public AnnotationItem(DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
visibility = new ByteField(),
|
visibilityField = new ByteField("visibility"),
|
||||||
annotation = new AnnotationEncodedValueSubField(dexFile)
|
annotationField = new AnnotationEncodedValueSubField(dexFile)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,41 +49,16 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
|||||||
super(-1);
|
super(-1);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
this.visibility = new ByteField(visibility.value),
|
this.visibilityField = new ByteField(visibility.value, "visibility"),
|
||||||
this.annotation = annotation
|
this.annotationField = annotation
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getAlignment() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_ANNOTATION_ITEM;
|
return ItemType.TYPE_ANNOTATION_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyTo(DexFile dexFile, AnnotationItem copy) {
|
public String getConciseIdentity() {
|
||||||
visibility.copyTo(dexFile, copy.visibility);
|
return "annotation_item @0x" + Integer.toHexString(getOffset());
|
||||||
annotation.copyTo(dexFile, copy.annotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return visibility.hashCode() * 31 + annotation.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof AnnotationItem)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnnotationItem other = (AnnotationItem)o;
|
|
||||||
|
|
||||||
if (!visibility.equals(other.visibility))
|
|
||||||
return false;
|
|
||||||
return annotation.equals(other.annotation);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,23 +34,22 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ArrayList<OffsettedItemReference<AnnotationItem>> annotationReferences =
|
private final ArrayList<OffsettedItemReference<AnnotationItem>> annotationReferences =
|
||||||
new ArrayList<OffsettedItemReference<AnnotationItem>>();
|
new ArrayList<OffsettedItemReference<AnnotationItem>>();
|
||||||
|
|
||||||
private final ListSizeField annotationCount;
|
private final ListSizeField annotationCountField;
|
||||||
private final FieldListField<OffsettedItemReference<AnnotationItem>> annotations;
|
private final FieldListField<OffsettedItemReference<AnnotationItem>> annotationsListField;
|
||||||
|
|
||||||
public AnnotationSetItem(final DexFile dexFile, int offset) {
|
public AnnotationSetItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
annotationCount = new ListSizeField(annotationReferences, new IntegerField()),
|
annotationCountField = new ListSizeField(annotationReferences, new IntegerField("size")),
|
||||||
annotations = new FieldListField<OffsettedItemReference<AnnotationItem>>(annotationReferences) {
|
annotationsListField = new FieldListField<OffsettedItemReference<AnnotationItem>>(
|
||||||
|
annotationReferences, "annotation") {
|
||||||
protected OffsettedItemReference<AnnotationItem> make() {
|
protected OffsettedItemReference<AnnotationItem> make() {
|
||||||
return new OffsettedItemReference<AnnotationItem>(dexFile.AnnotationsSection,
|
return new OffsettedItemReference<AnnotationItem>(dexFile.AnnotationsSection,
|
||||||
new IntegerField());
|
new IntegerField(null), "annotation_off");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -60,8 +59,9 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
|||||||
this(dexFile, -1);
|
this(dexFile, -1);
|
||||||
|
|
||||||
for (AnnotationItem annotationItem: annotations) {
|
for (AnnotationItem annotationItem: annotations) {
|
||||||
this.annotationReferences.add(new OffsettedItemReference<AnnotationItem>(dexFile,
|
OffsettedItemReference<AnnotationItem> annotationReference = annotationsListField.make();
|
||||||
annotationItem, new IntegerField()));
|
annotationReference.setReference(annotationItem);
|
||||||
|
this.annotationReferences.add(annotationReference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,11 +69,11 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_ANNOTATION_SET_ITEM;
|
return ItemType.TYPE_ANNOTATION_SET_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "annotation_set_item @0x" + Integer.toHexString(getOffset());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,22 +34,22 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
|
public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ArrayList<OffsettedItemReference<AnnotationSetItem>> annotationSetReferences =
|
private final ArrayList<OffsettedItemReference<AnnotationSetItem>> annotationSetReferences =
|
||||||
new ArrayList<OffsettedItemReference<AnnotationSetItem>>();
|
new ArrayList<OffsettedItemReference<AnnotationSetItem>>();
|
||||||
|
|
||||||
private final ListSizeField annotationSetCount;
|
private final ListSizeField annotationSetCountField;
|
||||||
private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSets;
|
private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSetsListField;
|
||||||
|
|
||||||
public AnnotationSetRefList(final DexFile dexFile, int offset) {
|
public AnnotationSetRefList(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
annotationSetCount = new ListSizeField(annotationSetReferences, new IntegerField()),
|
annotationSetCountField = new ListSizeField(annotationSetReferences, new IntegerField("size")),
|
||||||
annotationSets = new FieldListField<OffsettedItemReference<AnnotationSetItem>>(annotationSetReferences) {
|
annotationSetsListField = new FieldListField<OffsettedItemReference<AnnotationSetItem>>(
|
||||||
|
annotationSetReferences, "list") {
|
||||||
protected OffsettedItemReference<AnnotationSetItem> make() {
|
protected OffsettedItemReference<AnnotationSetItem> make() {
|
||||||
return new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField());
|
return new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection,
|
||||||
|
new IntegerField(null), "annotation_set_ref_item");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -58,8 +58,10 @@ public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
|
|||||||
public AnnotationSetRefList(final DexFile dexFile, List<AnnotationSetItem> annotationSets) {
|
public AnnotationSetRefList(final DexFile dexFile, List<AnnotationSetItem> annotationSets) {
|
||||||
this(dexFile, -1);
|
this(dexFile, -1);
|
||||||
|
|
||||||
for (AnnotationSetItem annotation: annotationSets) {
|
for (AnnotationSetItem annotationSet: annotationSets) {
|
||||||
this.annotationSetReferences.add(new OffsettedItemReference<AnnotationSetItem>(dexFile, annotation, new IntegerField()));
|
OffsettedItemReference<AnnotationSetItem> annotationSetReference = annotationSetsListField.make();
|
||||||
|
annotationSetReference.setReference(annotationSet);
|
||||||
|
this.annotationSetReferences.add(annotationSetReference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,11 +69,11 @@ public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_ANNOTATION_SET_REF_LIST;
|
return ItemType.TYPE_ANNOTATION_SET_REF_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "annotation_set_item @0x" + Integer.toHexString(getOffset());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,16 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
|
|
||||||
public class ByteField extends CachedIntegerValueField {
|
public class ByteField extends CachedIntegerValueField {
|
||||||
protected byte value;
|
public ByteField(String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
public ByteField() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteField(byte value) {
|
public ByteField(byte value, String fieldName) {
|
||||||
this.value = value;
|
super(value, fieldName);
|
||||||
}
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
|
||||||
out.writeByte(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
@ -53,11 +48,7 @@ public class ByteField extends CachedIntegerValueField {
|
|||||||
return offset + 1;
|
return offset + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCachedValue() {
|
public void writeValue(Output out) {
|
||||||
return value;
|
out.writeByte(value);
|
||||||
}
|
|
||||||
|
|
||||||
public void cacheValue(int value) {
|
|
||||||
this.value = (byte)value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,25 +28,64 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
public abstract class CachedIntegerValueField implements Field<CachedIntegerValueField> {
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
public abstract int getCachedValue();
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
public abstract void cacheValue(int value);
|
|
||||||
|
|
||||||
public void copyTo(DexFile dexFile, CachedIntegerValueField copy) {
|
public abstract class CachedIntegerValueField<T extends CachedIntegerValueField>
|
||||||
copy.cacheValue(getCachedValue());
|
implements Field<T> {
|
||||||
|
|
||||||
|
private final String fieldName;
|
||||||
|
protected int value;
|
||||||
|
|
||||||
|
protected CachedIntegerValueField(String fieldName) {
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CachedIntegerValueField(int value, String fieldName) {
|
||||||
|
this(fieldName);
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyTo(DexFile dexFile, T copy) {
|
||||||
|
copy.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return ((Integer)getCachedValue()).hashCode();
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void writeValue(Output out);
|
||||||
|
|
||||||
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
if (fieldName != null) {
|
||||||
|
out.annotate(fieldName + ": 0x" + Integer.toHexString(getCachedValue()));
|
||||||
|
}
|
||||||
|
writeValue(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (getClass() != o.getClass()) {
|
//TODO: check if this returns false if o is a different subclass
|
||||||
|
if (!this.getClass().isInstance(o)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedIntegerValueField other = (CachedIntegerValueField)o;
|
T other = (T)o;
|
||||||
|
|
||||||
return getCachedValue() == other.getCachedValue();
|
return getCachedValue() == other.getCachedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the integer value that has been cached. This
|
||||||
|
* value is either the value that the field was constructed with, the
|
||||||
|
* value that was read via <code>readFrom</code>, or the value that was
|
||||||
|
* cached when <code>place</code> was called
|
||||||
|
* @return the cached value
|
||||||
|
*/
|
||||||
|
public int getCachedValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cacheValue(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,55 +29,55 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.ItemType;
|
import org.JesusFreke.dexlib.ItemType;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.*;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
|
||||||
import org.JesusFreke.dexlib.util.AccessFlags;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ArrayList<EncodedField> staticFieldList = new ArrayList<EncodedField>();
|
private final ArrayList<EncodedField> staticFieldList = new ArrayList<EncodedField>();
|
||||||
private final ArrayList<EncodedField> instanceFieldList = new ArrayList<EncodedField>();
|
private final ArrayList<EncodedField> instanceFieldList = new ArrayList<EncodedField>();
|
||||||
private final ArrayList<EncodedMethod> directMethodList = new ArrayList<EncodedMethod>();
|
private final ArrayList<EncodedMethod> directMethodList = new ArrayList<EncodedMethod>();
|
||||||
private final ArrayList<EncodedMethod> virtualMethodList = new ArrayList<EncodedMethod>();
|
private final ArrayList<EncodedMethod> virtualMethodList = new ArrayList<EncodedMethod>();
|
||||||
|
|
||||||
private final ListSizeField staticFieldsCount;
|
private final ListSizeField staticFieldsCountField;
|
||||||
private final ListSizeField instanceFieldsCount;
|
private final ListSizeField instanceFieldsCountField;
|
||||||
private final ListSizeField directMethodsCount;
|
private final ListSizeField directMethodsCountField;
|
||||||
private final ListSizeField virtualMethodsCount;
|
private final ListSizeField virtualMethodsCountField;
|
||||||
private final EncodedMemberList<EncodedField> staticFields;
|
private final EncodedMemberList<EncodedField> staticFieldsListField;
|
||||||
private final EncodedMemberList<EncodedField> instanceFields;
|
private final EncodedMemberList<EncodedField> instanceFieldsListField;
|
||||||
private final EncodedMemberList<EncodedMethod> directMethods;
|
private final EncodedMemberList<EncodedMethod> directMethodsListField;
|
||||||
private final EncodedMemberList<EncodedMethod> virtualMethods;
|
private final EncodedMemberList<EncodedMethod> virtualMethodsListField;
|
||||||
|
|
||||||
|
|
||||||
public ClassDataItem(final DexFile dexFile, int offset) {
|
public ClassDataItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
staticFieldsCount = new ListSizeField(staticFieldList, new Leb128Field()),
|
staticFieldsCountField = new ListSizeField(staticFieldList,
|
||||||
instanceFieldsCount = new ListSizeField(instanceFieldList, new Leb128Field()),
|
new Leb128Field("static_fields_size")),
|
||||||
directMethodsCount = new ListSizeField(directMethodList, new Leb128Field()),
|
instanceFieldsCountField = new ListSizeField(instanceFieldList,
|
||||||
virtualMethodsCount = new ListSizeField(virtualMethodList, new Leb128Field()),
|
new Leb128Field("instance_fields_size")),
|
||||||
staticFields = new EncodedMemberList<EncodedField>(staticFieldList) {
|
directMethodsCountField = new ListSizeField(directMethodList,
|
||||||
|
new Leb128Field("direct_methods_size")),
|
||||||
|
virtualMethodsCountField = new ListSizeField(virtualMethodList,
|
||||||
|
new Leb128Field("virtual_methods_size")),
|
||||||
|
staticFieldsListField = new EncodedMemberList<EncodedField>(staticFieldList, "static_fields") {
|
||||||
protected EncodedField make(EncodedField previousField) {
|
protected EncodedField make(EncodedField previousField) {
|
||||||
return new EncodedField(dexFile, previousField);
|
return new EncodedField(dexFile, previousField);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
instanceFields = new EncodedMemberList<EncodedField>(instanceFieldList) {
|
instanceFieldsListField = new EncodedMemberList<EncodedField>(instanceFieldList, "instance_fields") {
|
||||||
protected EncodedField make(EncodedField previousField) {
|
protected EncodedField make(EncodedField previousField) {
|
||||||
return new EncodedField(dexFile, previousField);
|
return new EncodedField(dexFile, previousField);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directMethods = new EncodedMemberList<EncodedMethod>(directMethodList) {
|
directMethodsListField = new EncodedMemberList<EncodedMethod>(directMethodList, "direct_methods") {
|
||||||
protected EncodedMethod make(EncodedMethod previousMethod) {
|
protected EncodedMethod make(EncodedMethod previousMethod) {
|
||||||
return new EncodedMethod(dexFile, previousMethod);
|
return new EncodedMethod(dexFile, previousMethod);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
virtualMethods = new EncodedMemberList<EncodedMethod>(virtualMethodList) {
|
virtualMethodsListField = new EncodedMemberList<EncodedMethod>(virtualMethodList, "virtual_methods") {
|
||||||
protected EncodedMethod make(EncodedMethod previousMethod) {
|
protected EncodedMethod make(EncodedMethod previousMethod) {
|
||||||
return new EncodedMethod(dexFile, previousMethod);
|
return new EncodedMethod(dexFile, previousMethod);
|
||||||
}
|
}
|
||||||
@ -112,19 +112,29 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
|
|
||||||
private static abstract class EncodedMember<T extends EncodedMember<T>> extends CompositeField<T> implements Field<T>, Comparable<T>
|
private static abstract class EncodedMember<T extends EncodedMember<T>> extends CompositeField<T> implements Field<T>, Comparable<T>
|
||||||
{
|
{
|
||||||
|
public EncodedMember(String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void setPreviousMember(T previousMember);
|
protected abstract void setPreviousMember(T previousMember);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static abstract class EncodedMemberList<T extends EncodedMember<T>> implements Field<EncodedMemberList<T>> {
|
private static abstract class EncodedMemberList<T extends EncodedMember<T>> implements Field<EncodedMemberList<T>> {
|
||||||
private final ArrayList<T> list;
|
private final ArrayList<T> list;
|
||||||
|
private final String fieldName;
|
||||||
|
|
||||||
public EncodedMemberList(ArrayList<T> list) {
|
public EncodedMemberList(ArrayList<T> list, String fieldName) {
|
||||||
this.list = list;
|
this.list = list;
|
||||||
|
this.fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
out.annotate(0, fieldName + ":");
|
||||||
|
int i=0;
|
||||||
for (T field: list) {
|
for (T field: list) {
|
||||||
|
out.annotate(0, "[0x" + Integer.toHexString(i) + "]");
|
||||||
field.writeTo(out);
|
field.writeTo(out);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,13 +206,12 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class EncodedField extends EncodedMember<EncodedField> {
|
public static class EncodedField extends EncodedMember<EncodedField> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final IndexedItemReference<FieldIdItem> field;
|
private final IndexedItemReference<FieldIdItem> field;
|
||||||
private final Leb128DeltaField fieldIndexField;
|
private final Leb128DeltaField fieldIndexField;
|
||||||
private final Leb128Field accessFlags;
|
private final Leb128Field accessFlags;
|
||||||
|
|
||||||
public EncodedField(DexFile dexFile, final EncodedField previousField) {
|
public EncodedField(DexFile dexFile, final EncodedField previousField) {
|
||||||
|
super("encoded_field");
|
||||||
Leb128DeltaField previousIndexField = null;
|
Leb128DeltaField previousIndexField = null;
|
||||||
if (previousField != null) {
|
if (previousField != null) {
|
||||||
previousIndexField = previousField.fieldIndexField;
|
previousIndexField = previousField.fieldIndexField;
|
||||||
@ -211,16 +220,17 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection,
|
field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection,
|
||||||
fieldIndexField = new Leb128DeltaField(previousIndexField)),
|
fieldIndexField = new Leb128DeltaField(previousIndexField, null), "field_idx_diff"),
|
||||||
accessFlags = new Leb128Field()
|
accessFlags = new Leb128Field("access_flags")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncodedField(DexFile dexFile, FieldIdItem field, int accessFlags) {
|
public EncodedField(DexFile dexFile, FieldIdItem field, int accessFlags) {
|
||||||
|
super("encoded_field");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
this.field = new IndexedItemReference<FieldIdItem>(dexFile, field,
|
this.field = new IndexedItemReference<FieldIdItem>(dexFile, field,
|
||||||
fieldIndexField = new Leb128DeltaField(null)),
|
fieldIndexField = new Leb128DeltaField(null), "field_idx_diff"),
|
||||||
this.accessFlags = new Leb128Field(accessFlags)
|
this.accessFlags = new Leb128Field(accessFlags, "access_flags")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,10 +242,6 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int compareTo(EncodedField other)
|
public int compareTo(EncodedField other)
|
||||||
{
|
{
|
||||||
return field.getReference().compareTo(other.field.getReference());
|
return field.getReference().compareTo(other.field.getReference());
|
||||||
@ -251,14 +257,13 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class EncodedMethod extends EncodedMember<EncodedMethod> {
|
public static class EncodedMethod extends EncodedMember<EncodedMethod> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final IndexedItemReference<MethodIdItem> method;
|
private final IndexedItemReference<MethodIdItem> method;
|
||||||
private final Leb128DeltaField methodIndexField;
|
private final Leb128DeltaField methodIndexField;
|
||||||
private final Leb128Field accessFlags;
|
private final Leb128Field accessFlags;
|
||||||
private final OffsettedItemReference<CodeItem> codeItem;
|
private final OffsettedItemReference<CodeItem> codeItem;
|
||||||
|
|
||||||
public EncodedMethod(DexFile dexFile, final EncodedMethod previousMethod) {
|
public EncodedMethod(DexFile dexFile, final EncodedMethod previousMethod) {
|
||||||
|
super("encedod_method");
|
||||||
Leb128DeltaField previousIndexField = null;
|
Leb128DeltaField previousIndexField = null;
|
||||||
if (previousMethod != null) {
|
if (previousMethod != null) {
|
||||||
previousIndexField = previousMethod.methodIndexField;
|
previousIndexField = previousMethod.methodIndexField;
|
||||||
@ -266,18 +271,21 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
|
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
|
||||||
methodIndexField = new Leb128DeltaField(previousIndexField)),
|
methodIndexField = new Leb128DeltaField(previousIndexField, null), "method_idx_diff"),
|
||||||
accessFlags = new Leb128Field(),
|
accessFlags = new Leb128Field("access_flags"),
|
||||||
codeItem = new OffsettedItemReference<CodeItem>(dexFile.CodeItemsSection, new Leb128Field())
|
codeItem = new OffsettedItemReference<CodeItem>(dexFile.CodeItemsSection,
|
||||||
|
new Leb128Field(null), "code_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncodedMethod(DexFile dexFile, MethodIdItem methodIdItem, int accessFlags, CodeItem codeItem) {
|
public EncodedMethod(DexFile dexFile, MethodIdItem methodIdItem, int accessFlags, CodeItem codeItem) {
|
||||||
|
super("encoded_method");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
this.method = new IndexedItemReference<MethodIdItem>(dexFile, methodIdItem,
|
this.method = new IndexedItemReference<MethodIdItem>(dexFile, methodIdItem,
|
||||||
methodIndexField = new Leb128DeltaField(null)),
|
methodIndexField = new Leb128DeltaField(null), "method_idx_diff"),
|
||||||
this.accessFlags = new Leb128Field(accessFlags),
|
this.accessFlags = new Leb128Field(accessFlags, "access_flags"),
|
||||||
this.codeItem = new OffsettedItemReference<CodeItem>(dexFile, codeItem, new Leb128Field())
|
this.codeItem = new OffsettedItemReference<CodeItem>(dexFile, codeItem,
|
||||||
|
new Leb128Field(null), "code_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,10 +297,6 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int compareTo(EncodedMethod other)
|
public int compareTo(EncodedMethod other)
|
||||||
{
|
{
|
||||||
return method.getReference().compareTo(other.method.getReference());
|
return method.getReference().compareTo(other.method.getReference());
|
||||||
@ -310,42 +314,51 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
* item encodes the value as per normal
|
* item encodes the value as per normal
|
||||||
*/
|
*/
|
||||||
protected static class Leb128DeltaField extends Leb128Field {
|
protected static class Leb128DeltaField extends Leb128Field {
|
||||||
private Leb128DeltaField previousField;
|
private Leb128DeltaField previousField = null;
|
||||||
|
|
||||||
public Leb128DeltaField(Leb128DeltaField previousField) {
|
public Leb128DeltaField(String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readFrom(Input in) {
|
||||||
|
super.readFrom(in);
|
||||||
|
value += getPreviousValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int place(int offset) {
|
||||||
|
return offset + Leb128Utils.unsignedLeb128Size(value - getPreviousValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPreviousValue() {
|
||||||
|
if (previousField == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return previousField.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeValue(Output out) {
|
||||||
|
out.writeUnsignedLeb128(value - getPreviousValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Leb128DeltaField(Leb128DeltaField previousField, String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
this.previousField = previousField;
|
this.previousField = previousField;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPreviousField(Leb128DeltaField previousField) {
|
public void setPreviousField(Leb128DeltaField previousField) {
|
||||||
this.previousField = previousField;
|
this.previousField = previousField;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCachedValue() {
|
|
||||||
if (previousField != null) {
|
|
||||||
return previousField.getCachedValue() + super.getCachedValue();
|
|
||||||
} else {
|
|
||||||
return super.getCachedValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cacheValue(int value) {
|
|
||||||
if (previousField != null) {
|
|
||||||
super.cacheValue(value - previousField.getCachedValue());
|
|
||||||
} else {
|
|
||||||
super.cacheValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getAlignment() {
|
protected int getAlignment() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_CLASS_DATA_ITEM;
|
return ItemType.TYPE_CLASS_DATA_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "class_data_item @0x" + Integer.toHexString(getOffset());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,16 +37,14 @@ import java.util.HashMap;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||||
private final Field[] fields;
|
private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
|
||||||
|
private final IntegerField accessFlagsField;
|
||||||
private final IndexedItemReference<TypeIdItem> classType;
|
private final IndexedItemReference<TypeIdItem> superclassTypeReferenceField;
|
||||||
private final IntegerField accessFlags;
|
private final OffsettedItemReference<TypeListItem> classInterfacesListReferenceField;
|
||||||
private final IndexedItemReference<TypeIdItem> superclassType;
|
private final IndexedItemReference<StringIdItem> sourceFileReferenceField;
|
||||||
private final OffsettedItemReference<TypeListItem> classInterfacesList;
|
private final OffsettedItemReference<AnnotationDirectoryItem> classAnnotationsReferenceField;
|
||||||
private final IndexedItemReference<StringIdItem> sourceFile;
|
private final OffsettedItemReference<ClassDataItem> classDataReferenceField;
|
||||||
private final OffsettedItemReference<AnnotationDirectoryItem> classAnnotations;
|
private final OffsettedItemReference<EncodedArrayItem> staticFieldInitialValuesReferenceField;
|
||||||
private final OffsettedItemReference<ClassDataItem> classData;
|
|
||||||
private final OffsettedItemReference<EncodedArrayItem> staticFieldInitialValues;
|
|
||||||
|
|
||||||
private ArrayList<EncodedValue> staticFieldInitialValuesList;
|
private ArrayList<EncodedValue> staticFieldInitialValuesList;
|
||||||
|
|
||||||
@ -58,14 +56,22 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
this.dexFile = dexFile;
|
this.dexFile = dexFile;
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()),
|
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
accessFlags = new IntegerField(),
|
new IntegerField(null), "class_idx"),
|
||||||
superclassType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()),
|
//TODO: add annotated output showing the flags
|
||||||
classInterfacesList = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection, new IntegerField()),
|
accessFlagsField = new IntegerField("access_flags:"),
|
||||||
sourceFile = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()),
|
superclassTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
classAnnotations = new OffsettedItemReference<AnnotationDirectoryItem>(dexFile.AnnotationDirectoriesSection, new IntegerField()),
|
new IntegerField(null), "superclass_idx"),
|
||||||
classData = new OffsettedItemReference<ClassDataItem>(dexFile.ClassDataSection, new IntegerField()),
|
classInterfacesListReferenceField = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection,
|
||||||
staticFieldInitialValues = new OffsettedItemReference<EncodedArrayItem>(dexFile.EncodedArraysSection, new IntegerField())
|
new IntegerField(null), "interfaces_off"),
|
||||||
|
sourceFileReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
|
new IntegerField(null), "source_file_off"),
|
||||||
|
classAnnotationsReferenceField = new OffsettedItemReference<AnnotationDirectoryItem>(
|
||||||
|
dexFile.AnnotationDirectoriesSection, new IntegerField(null), "annotations_off"),
|
||||||
|
classDataReferenceField = new OffsettedItemReference<ClassDataItem>(dexFile.ClassDataSection,
|
||||||
|
new IntegerField(null), "class_data_off"),
|
||||||
|
staticFieldInitialValuesReferenceField = new OffsettedItemReference<EncodedArrayItem>(
|
||||||
|
dexFile.EncodedArraysSection, new IntegerField(null), "static_values_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,36 +82,30 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
TypeListItem implementsList,
|
TypeListItem implementsList,
|
||||||
StringIdItem source,
|
StringIdItem source,
|
||||||
ClassDataItem classDataItem) {
|
ClassDataItem classDataItem) {
|
||||||
super(-1);
|
this(dexFile, -1);
|
||||||
|
|
||||||
this.dexFile = dexFile;
|
classTypeReferenceField.setReference(classType);
|
||||||
|
accessFlagsField.cacheValue(accessFlags);
|
||||||
fields = new Field[] {
|
superclassTypeReferenceField.setReference(superType);
|
||||||
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new IntegerField()),
|
classInterfacesListReferenceField.setReference(implementsList);
|
||||||
this.accessFlags = new IntegerField(accessFlags),
|
sourceFileReferenceField.setReference(source);
|
||||||
superclassType = new IndexedItemReference<TypeIdItem>(dexFile, superType, new IntegerField()),
|
classDataReferenceField.setReference(classDataItem);
|
||||||
classInterfacesList = new OffsettedItemReference<TypeListItem>(dexFile, implementsList, new IntegerField()),
|
|
||||||
sourceFile = new IndexedItemReference<StringIdItem>(dexFile, source, new IntegerField()),
|
|
||||||
classAnnotations = new OffsettedItemReference<AnnotationDirectoryItem>(dexFile.AnnotationDirectoriesSection, new IntegerField()),
|
|
||||||
classData = new OffsettedItemReference<ClassDataItem>(dexFile, classDataItem, new IntegerField()),
|
|
||||||
staticFieldInitialValues = new OffsettedItemReference<EncodedArrayItem>(dexFile.EncodedArraysSection, new IntegerField())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeIdItem getSuperclass() {
|
public TypeIdItem getSuperclass() {
|
||||||
return superclassType.getReference();
|
return superclassTypeReferenceField.getReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeIdItem getClassType() {
|
public TypeIdItem getClassTypeReferenceField() {
|
||||||
return classType.getReference();
|
return classTypeReferenceField.getReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getAlignment() {
|
protected int getAlignment() {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
public TypeIdItem getClassType() {
|
||||||
return fields;
|
return classTypeReferenceField.getReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
@ -113,15 +113,15 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
return classType.getReference().toString();
|
return classTypeReferenceField.getReference().getTypeDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String getConciseIdentity() {
|
||||||
return getClassName();
|
return "class_def_item: " + getClassName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return classType.getReference().hashCode();
|
return classTypeReferenceField.getReference().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
@ -129,7 +129,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ClassDefItem other = (ClassDefItem)o;
|
ClassDefItem other = (ClassDefItem)o;
|
||||||
return classType.equals(other.classType);
|
return classTypeReferenceField.equals(other.classTypeReferenceField);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(ClassDefItem o) {
|
public int compareTo(ClassDefItem o) {
|
||||||
@ -145,7 +145,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
throw new RuntimeException("Initial values are only allowed for static fields.");
|
throw new RuntimeException("Initial values are only allowed for static fields.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassDataItem classDataItem = this.classData.getReference();
|
ClassDataItem classDataItem = this.classDataReferenceField.getReference();
|
||||||
|
|
||||||
int fieldIndex = classDataItem.addField(encodedField);
|
int fieldIndex = classDataItem.addField(encodedField);
|
||||||
if (initialValue != null) {
|
if (initialValue != null) {
|
||||||
@ -153,13 +153,14 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
staticFieldInitialValuesList = new ArrayList<EncodedValue>();
|
staticFieldInitialValuesList = new ArrayList<EncodedValue>();
|
||||||
|
|
||||||
EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, staticFieldInitialValuesList);
|
EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, staticFieldInitialValuesList);
|
||||||
staticFieldInitialValues.setReference(encodedArrayItem);
|
staticFieldInitialValuesReferenceField.setReference(encodedArrayItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
//All static fields before this one must have an initial value. Add any default values as needed
|
//All static fields before this one must have an initial value. Add any default values as needed
|
||||||
for (int i=staticFieldInitialValuesList.size(); i < fieldIndex; i++) {
|
for (int i=staticFieldInitialValuesList.size(); i < fieldIndex; i++) {
|
||||||
ClassDataItem.EncodedField staticField = classDataItem.getStaticFieldAtIndex(i);
|
ClassDataItem.EncodedField staticField = classDataItem.getStaticFieldAtIndex(i);
|
||||||
EncodedValueSubField subField = TypeUtils.makeDefaultValueForType(dexFile, staticField.getField().getFieldType().toString());
|
EncodedValueSubField subField = TypeUtils.makeDefaultValueForType(dexFile,
|
||||||
|
staticField.getField().getFieldType().getTypeDescriptor());
|
||||||
EncodedValue encodedValue = new EncodedValue(dexFile, subField);
|
EncodedValue encodedValue = new EncodedValue(dexFile, subField);
|
||||||
staticFieldInitialValuesList.add(i, encodedValue);
|
staticFieldInitialValuesList.add(i, encodedValue);
|
||||||
}
|
}
|
||||||
@ -169,7 +170,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setAnnotations(AnnotationDirectoryItem annotations) {
|
public void setAnnotations(AnnotationDirectoryItem annotations) {
|
||||||
this.classAnnotations.setReference(annotations);
|
this.classAnnotationsReferenceField.setReference(annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int placeClassDefItems(IndexedSection<ClassDefItem> section, int offset) {
|
public static int placeClassDefItems(IndexedSection<ClassDefItem> section, int offset) {
|
||||||
@ -192,7 +193,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
this.section = section;
|
this.section = section;
|
||||||
|
|
||||||
for (ClassDefItem classDefItem: section.items) {
|
for (ClassDefItem classDefItem: section.items) {
|
||||||
TypeIdItem typeIdItem = classDefItem.classType.getReference();
|
TypeIdItem typeIdItem = classDefItem.classTypeReferenceField.getReference();
|
||||||
classDefsByType.put(typeIdItem, classDefItem);
|
classDefsByType.put(typeIdItem, classDefItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,14 +213,14 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
|
|
||||||
private void placeClass(ClassDefItem classDefItem) {
|
private void placeClass(ClassDefItem classDefItem) {
|
||||||
if (!classDefItem.isPlaced()) {
|
if (!classDefItem.isPlaced()) {
|
||||||
TypeIdItem superType = classDefItem.superclassType.getReference();
|
TypeIdItem superType = classDefItem.superclassTypeReferenceField.getReference();
|
||||||
ClassDefItem superClassDefItem = classDefsByType.get(superType);
|
ClassDefItem superClassDefItem = classDefsByType.get(superType);
|
||||||
|
|
||||||
if (superClassDefItem != null) {
|
if (superClassDefItem != null) {
|
||||||
placeClass(superClassDefItem);
|
placeClass(superClassDefItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeListItem interfaces = classDefItem.classInterfacesList.getReference();
|
TypeListItem interfaces = classDefItem.classInterfacesListReferenceField.getReference();
|
||||||
|
|
||||||
if (interfaces != null) {
|
if (interfaces != null) {
|
||||||
for (TypeIdItem interfaceType: interfaces.getTypes()) {
|
for (TypeIdItem interfaceType: interfaces.getTypes()) {
|
||||||
|
@ -32,28 +32,27 @@ import org.JesusFreke.dexlib.code.Instruction;
|
|||||||
import org.JesusFreke.dexlib.code.Opcode;
|
import org.JesusFreke.dexlib.code.Opcode;
|
||||||
import org.JesusFreke.dexlib.ItemType;
|
import org.JesusFreke.dexlib.ItemType;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class CodeItem extends OffsettedItem<CodeItem> {
|
public class CodeItem extends OffsettedItem<CodeItem> {
|
||||||
private final Field[] fields;
|
|
||||||
private final ArrayList<Instruction> instructionList;
|
private final ArrayList<Instruction> instructionList;
|
||||||
private final ArrayList<TryItem> tryItems = new ArrayList<TryItem>();
|
private final ArrayList<TryItem> tryItems = new ArrayList<TryItem>();
|
||||||
private final ArrayList<EncodedCatchHandler> catchHandlerList = new ArrayList<EncodedCatchHandler>();
|
private final ArrayList<EncodedCatchHandler> catchHandlerList = new ArrayList<EncodedCatchHandler>();
|
||||||
|
|
||||||
private final ShortIntegerField registersCount;
|
private final ShortIntegerField registersCountField;
|
||||||
private final ShortIntegerField inArgumentCount;
|
private final ShortIntegerField inArgumentCountField;
|
||||||
private final ShortIntegerField outArgumentCount;
|
private final ShortIntegerField outArgumentCountField;
|
||||||
private final ListSizeField triesCount;
|
private final ListSizeField triesCountField;
|
||||||
private final OffsettedItemReference<DebugInfoItem> debugInfo;
|
private final OffsettedItemReference<DebugInfoItem> debugInfoReferenceField;
|
||||||
private final IntegerField instructionsSize;
|
private final IntegerField instructionsSizeField;
|
||||||
private final InstructionListField instructionListField;
|
private final InstructionListField instructionListField;
|
||||||
private final PaddingField padding;
|
private final PaddingField paddingField;
|
||||||
private final FieldListField<TryItem> tries;
|
private final FieldListField<TryItem> triesListField;
|
||||||
private final EncodedCatchHandlerList catchHandlers;
|
private final EncodedCatchHandlerList catchHandlersListField;
|
||||||
|
|
||||||
public CodeItem(final DexFile dexFile, int offset) {
|
public CodeItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(offset);
|
||||||
@ -61,37 +60,36 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
instructionList = new ArrayList<Instruction>();
|
instructionList = new ArrayList<Instruction>();
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
registersCount = new ShortIntegerField(),
|
registersCountField = new ShortIntegerField("registers_size"),
|
||||||
inArgumentCount = new ShortIntegerField(),
|
inArgumentCountField = new ShortIntegerField("ins_size"),
|
||||||
outArgumentCount = new ShortIntegerField(),
|
outArgumentCountField = new ShortIntegerField("outs_size"),
|
||||||
triesCount = new ListSizeField(tryItems, new ShortIntegerField()),
|
triesCountField = new ListSizeField(tryItems, new ShortIntegerField("tries_size")),
|
||||||
debugInfo = new OffsettedItemReference<DebugInfoItem>(dexFile.DebugInfoItemsSection, new IntegerField()),
|
debugInfoReferenceField = new OffsettedItemReference<DebugInfoItem>(dexFile.DebugInfoItemsSection,
|
||||||
instructionsSize = new IntegerField(),
|
new IntegerField(null), "debug_off"),
|
||||||
|
instructionsSizeField = new IntegerField("insns_size"),
|
||||||
instructionListField = new InstructionListField(dexFile),
|
instructionListField = new InstructionListField(dexFile),
|
||||||
padding = new PaddingField(),
|
paddingField = new PaddingField(),
|
||||||
tries = new FieldListField<TryItem>(tryItems) {
|
triesListField = new FieldListField<TryItem>(tryItems, "try_item") {
|
||||||
protected TryItem make() {
|
protected TryItem make() {
|
||||||
return new TryItem(catchHandlers);
|
return new TryItem(catchHandlersListField);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
catchHandlers = new EncodedCatchHandlerList(dexFile)
|
catchHandlersListField = new EncodedCatchHandlerList(dexFile)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public CodeItem(final DexFile dexFile,
|
public CodeItem(final DexFile dexFile,
|
||||||
int registersCount,
|
int registersCount,
|
||||||
int inArguments,
|
int inArguments,
|
||||||
ArrayList<Instruction> instructions,
|
List<Instruction> instructions,
|
||||||
DebugInfoItem debugInfo,
|
DebugInfoItem debugInfo,
|
||||||
List<TryItem> tries,
|
List<TryItem> tries,
|
||||||
List<EncodedCatchHandler> handlers) {
|
List<EncodedCatchHandler> handlers) {
|
||||||
super(-1);
|
this(dexFile, 0);
|
||||||
|
|
||||||
this.instructionList = new ArrayList<Instruction>(instructions);
|
instructionList.addAll(instructions);
|
||||||
this.instructionListField = new InstructionListField(dexFile);
|
instructionsSizeField.cacheValue(instructionListField.getInstructionWordCount());
|
||||||
|
|
||||||
if (tries != null) {
|
if (tries != null) {
|
||||||
tryItems.addAll(tries);
|
tryItems.addAll(tries);
|
||||||
@ -103,22 +101,10 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
throw new RuntimeException("The handlers parameter must be null if the tries parameter is null");
|
throw new RuntimeException("The handlers parameter must be null if the tries parameter is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
fields = new Field[] {
|
registersCountField.cacheValue(registersCount);
|
||||||
this.registersCount = new ShortIntegerField(registersCount),
|
inArgumentCountField.cacheValue(inArguments);
|
||||||
this.inArgumentCount = new ShortIntegerField(inArguments),
|
outArgumentCountField.cacheValue(instructionListField.getOutArguments());
|
||||||
this.outArgumentCount = new ShortIntegerField(instructionListField.getOutArguments()),
|
debugInfoReferenceField.setReference(debugInfo);
|
||||||
this.triesCount = new ListSizeField(tryItems, new ShortIntegerField(0)),
|
|
||||||
this.debugInfo = new OffsettedItemReference<DebugInfoItem>(dexFile, debugInfo, new IntegerField()),
|
|
||||||
this.instructionsSize = new IntegerField(instructionListField.getInstructionWordCount()),
|
|
||||||
instructionListField,
|
|
||||||
this.padding = new PaddingField(),
|
|
||||||
this.tries = new FieldListField<TryItem>(tryItems) {
|
|
||||||
protected TryItem make() {
|
|
||||||
return new TryItem(catchHandlers);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
this.catchHandlers = new EncodedCatchHandlerList(dexFile)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getAlignment() {
|
protected int getAlignment() {
|
||||||
@ -131,48 +117,43 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
|
|
||||||
public void copyTo(DexFile dexFile, CodeItem copy)
|
public void copyTo(DexFile dexFile, CodeItem copy)
|
||||||
{
|
{
|
||||||
Field[] fields = getFields();
|
|
||||||
Field[] fieldsCopy = copy.getFields();
|
|
||||||
for (int i = 0; i < fields.length-2; i++) {
|
for (int i = 0; i < fields.length-2; i++) {
|
||||||
fields[i].copyTo(dexFile, fieldsCopy[i]);
|
fields[i].copyTo(dexFile, copy.fields[i]);
|
||||||
}
|
}
|
||||||
//we need to do this in reverse order, so when the tries are copied,
|
//we need to do this in reverse order, so when the tries are copied,
|
||||||
//the catchHandler copies will already exist
|
//the catchHandler copies will already exist
|
||||||
catchHandlers.copyTo(dexFile, copy.catchHandlers);
|
catchHandlersListField.copyTo(dexFile, copy.catchHandlersListField);
|
||||||
tries.copyTo(dexFile, copy.tries);
|
triesListField.copyTo(dexFile, copy.triesListField);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Field[] getFields() {
|
public String getConciseIdentity() {
|
||||||
return fields;
|
//TODO: should mention the method name here
|
||||||
|
return "code_item @0x" + Integer.toHexString(getOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TryItem extends CompositeField<TryItem> {
|
public static class TryItem extends CompositeField<TryItem> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final IntegerField startAddr;
|
private final IntegerField startAddr;
|
||||||
private final ShortIntegerField insnCount;
|
private final ShortIntegerField insnCount;
|
||||||
private final EncodedCatchHandlerReference encodedCatchHandlerReference;
|
private final EncodedCatchHandlerReference encodedCatchHandlerReference;
|
||||||
|
|
||||||
public TryItem(EncodedCatchHandlerList encodedCatchHandlerList) {
|
public TryItem(EncodedCatchHandlerList encodedCatchHandlerList) {
|
||||||
|
super("try_item");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
startAddr = new IntegerField(),
|
startAddr = new IntegerField("start_addr"),
|
||||||
insnCount = new ShortIntegerField(),
|
insnCount = new ShortIntegerField("insn_count"),
|
||||||
encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandlerList)
|
encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandlerList)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public TryItem(int startAddr, int insnCount, EncodedCatchHandler encodedCatchHandler) {
|
public TryItem(int startAddr, int insnCount, EncodedCatchHandler encodedCatchHandler) {
|
||||||
|
super("try_item");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
this.startAddr = new IntegerField(startAddr),
|
this.startAddr = new IntegerField(startAddr, "start_addr"),
|
||||||
this.insnCount = new ShortIntegerField(insnCount),
|
this.insnCount = new ShortIntegerField(insnCount, "insn_count"),
|
||||||
this.encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandler)
|
this.encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandler)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStartAddress() {
|
public int getStartAddress() {
|
||||||
return startAddr.getCachedValue();
|
return startAddr.getCachedValue();
|
||||||
}
|
}
|
||||||
@ -191,10 +172,12 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
private EncodedCatchHandler encodedCatchHandler;
|
private EncodedCatchHandler encodedCatchHandler;
|
||||||
|
|
||||||
public EncodedCatchHandlerReference(EncodedCatchHandlerList encodedCatchHandlerList) {
|
public EncodedCatchHandlerReference(EncodedCatchHandlerList encodedCatchHandlerList) {
|
||||||
|
super("encoded_catch_handler");
|
||||||
this.encodedCatchHandlerList = encodedCatchHandlerList;
|
this.encodedCatchHandlerList = encodedCatchHandlerList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncodedCatchHandlerReference(EncodedCatchHandler encodedCatchHandler) {
|
public EncodedCatchHandlerReference(EncodedCatchHandler encodedCatchHandler) {
|
||||||
|
super("encoded_catch_handler");
|
||||||
this.encodedCatchHandlerList = null;
|
this.encodedCatchHandlerList = null;
|
||||||
this.encodedCatchHandler = encodedCatchHandler;
|
this.encodedCatchHandler = encodedCatchHandler;
|
||||||
}
|
}
|
||||||
@ -212,7 +195,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void copyTo(DexFile dexFile, CachedIntegerValueField _copy) {
|
public void copyTo(DexFile dexFile, CachedIntegerValueField _copy) {
|
||||||
|
|
||||||
EncodedCatchHandlerReference copy = (EncodedCatchHandlerReference)_copy;
|
EncodedCatchHandlerReference copy = (EncodedCatchHandlerReference)_copy;
|
||||||
EncodedCatchHandler copiedItem = copy.getEncodedCatchHandlerList().getByOffset(
|
EncodedCatchHandler copiedItem = copy.getEncodedCatchHandlerList().getByOffset(
|
||||||
encodedCatchHandler.getOffsetInList());
|
encodedCatchHandler.getOffsetInList());
|
||||||
@ -220,7 +202,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
cacheValue(encodedCatchHandler.getOffsetInList());
|
cacheValue(encodedCatchHandler.getOffsetInList());
|
||||||
|
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
@ -252,18 +234,17 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
itemsByOffset.put(offset, encodedCatchHandler);
|
itemsByOffset.put(offset, encodedCatchHandler);
|
||||||
}
|
}
|
||||||
return encodedCatchHandler;
|
return encodedCatchHandler;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncodedCatchHandlerList(DexFile dexFile) {
|
public EncodedCatchHandlerList(final DexFile dexFile) {
|
||||||
|
super("encoded_catch_handler_list");
|
||||||
this.dexFile = dexFile;
|
this.dexFile = dexFile;
|
||||||
}
|
|
||||||
|
|
||||||
private final ListSizeField sizeField;
|
fields = new Field[] {
|
||||||
private final FieldListField<EncodedCatchHandler> listField;
|
sizeField = new ListSizeField(catchHandlerList, new Leb128Field("size")),
|
||||||
|
listField = new FieldListField<EncodedCatchHandler>(catchHandlerList, "encoded_catch_handler") {
|
||||||
private final Field[] fields = new Field[] {
|
|
||||||
sizeField = new ListSizeField(catchHandlerList, new Leb128Field()),
|
|
||||||
listField = new FieldListField<EncodedCatchHandler>(catchHandlerList) {
|
|
||||||
protected EncodedCatchHandler make() {
|
protected EncodedCatchHandler make() {
|
||||||
return new EncodedCatchHandler(dexFile, 0);
|
return new EncodedCatchHandler(dexFile, 0);
|
||||||
}
|
}
|
||||||
@ -287,7 +268,11 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ListSizeField sizeField;
|
||||||
|
private final FieldListField<EncodedCatchHandler> listField;
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
if (tryItems.size() > 0) {
|
if (tryItems.size() > 0) {
|
||||||
@ -296,7 +281,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
if (fieldPresent) {
|
if (fieldPresent) {
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
@ -314,10 +299,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyTo(DexFile dexFile, EncodedCatchHandlerList copy) {
|
public void copyTo(DexFile dexFile, EncodedCatchHandlerList copy) {
|
||||||
super.copyTo(dexFile, copy);
|
super.copyTo(dexFile, copy);
|
||||||
copy.fieldPresent = fieldPresent;
|
copy.fieldPresent = fieldPresent;
|
||||||
@ -329,7 +310,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class EncodedCatchHandler extends CompositeField<EncodedCatchHandler> {
|
public static class EncodedCatchHandler extends CompositeField<EncodedCatchHandler> {
|
||||||
public final Field[] fields;
|
|
||||||
private ArrayList<EncodedTypeAddrPair> list;
|
private ArrayList<EncodedTypeAddrPair> list;
|
||||||
boolean hasCatchAll = false;
|
boolean hasCatchAll = false;
|
||||||
private int baseOffset = 0;
|
private int baseOffset = 0;
|
||||||
@ -341,11 +321,12 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
private int offset;
|
private int offset;
|
||||||
|
|
||||||
public EncodedCatchHandler(final DexFile dexFile, int offset) {
|
public EncodedCatchHandler(final DexFile dexFile, int offset) {
|
||||||
|
super("encoded_catch_handler");
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
|
|
||||||
list = new ArrayList<EncodedTypeAddrPair>();
|
list = new ArrayList<EncodedTypeAddrPair>();
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
size = new ListSizeField(list, new SignedLeb128Field() {
|
size = new ListSizeField(list, new SignedLeb128Field("size") {
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
super.readFrom(in);
|
super.readFrom(in);
|
||||||
hasCatchAll = (getCachedValue() <= 0);
|
hasCatchAll = (getCachedValue() <= 0);
|
||||||
@ -355,19 +336,19 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
super.cacheValue(value * (hasCatchAll?-1:1));
|
super.cacheValue(value * (hasCatchAll?-1:1));
|
||||||
}})
|
}})
|
||||||
,
|
,
|
||||||
handlers = new FieldListField<EncodedTypeAddrPair>(list) {
|
handlers = new FieldListField<EncodedTypeAddrPair>(list, "encoded_type_addr_pair") {
|
||||||
protected EncodedTypeAddrPair make() {
|
protected EncodedTypeAddrPair make() {
|
||||||
return new EncodedTypeAddrPair(dexFile);
|
return new EncodedTypeAddrPair(dexFile);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
catchAllAddress = new Leb128Field() {
|
catchAllAddress = new Leb128Field("catch_all_addr") {
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
if (hasCatchAll) {
|
if (hasCatchAll) {
|
||||||
super.readFrom(in);
|
super.readFrom(in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
if (hasCatchAll) {
|
if (hasCatchAll) {
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
@ -393,10 +374,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOffsetInList() {
|
public int getOffsetInList() {
|
||||||
return offset-baseOffset;
|
return offset-baseOffset;
|
||||||
}
|
}
|
||||||
@ -434,35 +411,30 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class EncodedTypeAddrPair extends CompositeField<EncodedTypeAddrPair> {
|
public static class EncodedTypeAddrPair extends CompositeField<EncodedTypeAddrPair> {
|
||||||
public final Field[] fields;
|
public final IndexedItemReference<TypeIdItem> typeReferenceField;
|
||||||
|
public final Leb128Field handlerAddressField;
|
||||||
public final IndexedItemReference<TypeIdItem> type;
|
|
||||||
public final Leb128Field handlerAddress;
|
|
||||||
|
|
||||||
public EncodedTypeAddrPair(DexFile dexFile) {
|
public EncodedTypeAddrPair(DexFile dexFile) {
|
||||||
|
super("encoded_type_addr_pair");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
type = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128Field()),
|
typeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
handlerAddress = new Leb128Field()
|
new Leb128Field(null), "type_idx"),
|
||||||
|
handlerAddressField = new Leb128Field("addr")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncodedTypeAddrPair(DexFile dexFile, TypeIdItem type, int handlerOffset) {
|
public EncodedTypeAddrPair(DexFile dexFile, TypeIdItem type, int handlerOffset) {
|
||||||
fields = new Field[] {
|
this(dexFile);
|
||||||
this.type = new IndexedItemReference<TypeIdItem>(dexFile, type, new Leb128Field()),
|
typeReferenceField.setReference(type);
|
||||||
this.handlerAddress = new Leb128Field(handlerOffset)
|
handlerAddressField.cacheValue(handlerOffset);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
public TypeIdItem getTypeReferenceField() {
|
||||||
return fields;
|
return typeReferenceField.getReference();
|
||||||
}
|
|
||||||
|
|
||||||
public TypeIdItem getType() {
|
|
||||||
return type.getReference();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHandlerAddress() {
|
public int getHandlerAddress() {
|
||||||
return handlerAddress.getCachedValue();
|
return handlerAddressField.getCachedValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,18 +445,18 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
this.dexFile = dexFile;
|
this.dexFile = dexFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
int startPosition = out.getCursor();
|
int startPosition = out.getCursor();
|
||||||
for (Instruction instruction: instructionList) {
|
for (Instruction instruction: instructionList) {
|
||||||
instruction.writeTo(out);
|
instruction.writeTo(out);
|
||||||
}
|
}
|
||||||
if ((out.getCursor() - startPosition) != (instructionsSize.getCachedValue() * 2)) {
|
if ((out.getCursor() - startPosition) != (instructionsSizeField.getCachedValue() * 2)) {
|
||||||
throw new RuntimeException("Did not write the expected amount of bytes");
|
throw new RuntimeException("Did not write the expected amount of bytes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
int numBytes = instructionsSize.getCachedValue() * 2;
|
int numBytes = instructionsSizeField.getCachedValue() * 2;
|
||||||
int startPosition = in.getCursor();
|
int startPosition = in.getCursor();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -499,7 +471,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int place(int offset) {
|
public int place(int offset) {
|
||||||
return offset + (instructionsSize.getCachedValue() * 2);
|
return offset + (instructionsSizeField.getCachedValue() * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyTo(DexFile dexFile, InstructionListField copy) {
|
public void copyTo(DexFile dexFile, InstructionListField copy) {
|
||||||
@ -539,7 +511,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
|
if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
|
||||||
isStatic = true;
|
isStatic = true;
|
||||||
}
|
}
|
||||||
int paramWordCount = methodIdItem.getParameterWordCount(isStatic);
|
int paramWordCount = methodIdItem.getParameterRegisterCount(isStatic);
|
||||||
|
|
||||||
if (maxParamWordCount < paramWordCount) {
|
if (maxParamWordCount < paramWordCount) {
|
||||||
maxParamWordCount = paramWordCount;
|
maxParamWordCount = paramWordCount;
|
||||||
@ -556,10 +528,10 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean needsAlign() {
|
private boolean needsAlign() {
|
||||||
return (triesCount.getCachedValue() > 0) && (instructionsSize.getCachedValue() % 2 == 1);
|
return (triesCountField.getCachedValue() > 0) && (instructionsSizeField.getCachedValue() % 2 == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
if (needsAlign()) {
|
if (needsAlign()) {
|
||||||
out.writeShort(0);
|
out.writeShort(0);
|
||||||
}
|
}
|
||||||
|
@ -28,53 +28,58 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
|
|
||||||
public abstract class CompositeField<T extends CompositeField<T>> implements Field<T> {
|
public abstract class CompositeField<T extends CompositeField<T>> implements Field<T> {
|
||||||
/**
|
protected Field[] fields;
|
||||||
* Every instance of a specific subclass should return an array with the same structure,
|
private final String fieldName;
|
||||||
* in other words have the same size, and the same type of field at each position.
|
|
||||||
* @return An array of fields that represents the sub-fields that make up this CompositeField
|
|
||||||
*/
|
|
||||||
protected abstract Field[] getFields();
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
/**
|
||||||
for (Field field: getFields()) {
|
* Every instance of a specific subclass have a field array with the same structure.
|
||||||
|
* In other words have the same size, and the same type of field at each position.
|
||||||
|
*/
|
||||||
|
public CompositeField(String fieldName){
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
out.annotate(0, fieldName + ":");
|
||||||
|
out.indent();
|
||||||
|
for (Field field: fields) {
|
||||||
field.writeTo(out);
|
field.writeTo(out);
|
||||||
}
|
}
|
||||||
|
out.deindent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
for (Field field: getFields()) {
|
for (Field field: fields) {
|
||||||
field.readFrom(in);
|
field.readFrom(in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int place(int offset) {
|
public int place(int offset) {
|
||||||
for (Field field: getFields()) {
|
for (Field field: fields) {
|
||||||
offset = field.place(offset);
|
offset = field.place(offset);
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyTo(DexFile dexFile, T copy) {
|
public void copyTo(DexFile dexFile, T copy) {
|
||||||
Field[] fields = getFields();
|
|
||||||
Field[] copyFields = copy.getFields();
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
/**
|
/**
|
||||||
* This assumes that the fields will be the same for every instance
|
* This assumes that the fields will be the same for every instance
|
||||||
* of a specific concrete subclass. By making this assumption, every subclass is
|
* of a specific concrete subclass. By making this assumption, every subclass is
|
||||||
* prevented from having to implement copyTo
|
* prevented from having to implement copyTo
|
||||||
*/
|
*/
|
||||||
fields[i].copyTo(dexFile, copyFields[i]);
|
fields[i].copyTo(dexFile, copy.fields[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int h = 1;
|
int h = 1;
|
||||||
for (Field field: getFields()) {
|
for (Field field: fields) {
|
||||||
h = h * 31 + field.hashCode();
|
h = h * 31 + field.hashCode();
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
@ -86,13 +91,11 @@ public abstract class CompositeField<T extends CompositeField<T>> implements Fie
|
|||||||
}
|
}
|
||||||
|
|
||||||
CompositeField other = (CompositeField)o;
|
CompositeField other = (CompositeField)o;
|
||||||
Field[] fields = getFields();
|
if (fields.length != other.fields.length) {
|
||||||
Field[] otherFields = other.getFields();
|
|
||||||
if (fields.length != otherFields.length) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
if (!fields[i].equals(otherFields[i])) {
|
if (!fields[i].equals(other.fields[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,13 @@ import org.JesusFreke.dexlib.ItemType;
|
|||||||
import org.JesusFreke.dexlib.debug.DebugInstructionFactory;
|
import org.JesusFreke.dexlib.debug.DebugInstructionFactory;
|
||||||
import org.JesusFreke.dexlib.debug.EndSequence;
|
import org.JesusFreke.dexlib.debug.EndSequence;
|
||||||
import org.JesusFreke.dexlib.debug.DebugInstruction;
|
import org.JesusFreke.dexlib.debug.DebugInstruction;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ArrayList<IndexedItemReference<StringIdItem>> parameterNames =
|
private final ArrayList<IndexedItemReference<StringIdItem>> parameterNames =
|
||||||
new ArrayList<IndexedItemReference<StringIdItem>>();
|
new ArrayList<IndexedItemReference<StringIdItem>>();
|
||||||
|
|
||||||
@ -55,11 +53,13 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
|||||||
super(offset);
|
super(offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
lineStartField = new Leb128Field(),
|
lineStartField = new Leb128Field("line_start"),
|
||||||
parameterNamesSizeField = new ListSizeField(parameterNames, new Leb128Field()),
|
parameterNamesSizeField = new ListSizeField(parameterNames, new Leb128Field("parameters_size")),
|
||||||
parameterNamesField = new FieldListField<IndexedItemReference<StringIdItem>>(parameterNames) {
|
parameterNamesField = new FieldListField<IndexedItemReference<StringIdItem>>(
|
||||||
|
parameterNames, "parameter_names") {
|
||||||
protected IndexedItemReference<StringIdItem> make() {
|
protected IndexedItemReference<StringIdItem> make() {
|
||||||
return new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field());
|
return new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
|
new Leb128p1Field(null), "parameter_name");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
debugInstructionListField = new DebugInstructionList(dexFile)
|
debugInstructionListField = new DebugInstructionList(dexFile)
|
||||||
@ -75,25 +75,22 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
|||||||
this.lineStartField.cacheValue(lineStart);
|
this.lineStartField.cacheValue(lineStart);
|
||||||
|
|
||||||
for (StringIdItem parameterName: parameterNames) {
|
for (StringIdItem parameterName: parameterNames) {
|
||||||
this.parameterNames.add(new IndexedItemReference<StringIdItem>(dexFile, parameterName,
|
IndexedItemReference<StringIdItem> parameterReference = parameterNamesField.make();
|
||||||
new Leb128p1Field()));
|
parameterReference.setReference(parameterName);
|
||||||
|
this.parameterNames.add(parameterReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.instructionFields.addAll(debugInstructions);
|
this.instructionFields.addAll(debugInstructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getAlignment() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_DEBUG_INFO_ITEM;
|
return ItemType.TYPE_DEBUG_INFO_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "debug_info_item @0x" + Integer.toHexString(getOffset());
|
||||||
|
}
|
||||||
|
|
||||||
private class DebugInstructionList implements Field<DebugInstructionList> {
|
private class DebugInstructionList implements Field<DebugInstructionList> {
|
||||||
private final DexFile dexFile;
|
private final DexFile dexFile;
|
||||||
private final ArrayList<DebugInstruction> list;
|
private final ArrayList<DebugInstruction> list;
|
||||||
@ -103,7 +100,7 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
|||||||
list = instructionFields;
|
list = instructionFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
for (DebugInstruction debugInstruction: list) {
|
for (DebugInstruction debugInstruction: list) {
|
||||||
debugInstruction.writeTo(out);
|
debugInstruction.writeTo(out);
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,7 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.*;
|
||||||
import org.JesusFreke.dexlib.util.ByteArrayInput;
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.FileUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -176,7 +173,7 @@ public class DexFile
|
|||||||
fileSize = offset;
|
fileSize = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
HeaderItemSection.writeTo(out);
|
HeaderItemSection.writeTo(out);
|
||||||
for (IndexedSection indexedSection: indexedSections) {
|
for (IndexedSection indexedSection: indexedSections) {
|
||||||
indexedSection.writeTo(out);
|
indexedSection.writeTo(out);
|
||||||
@ -189,29 +186,6 @@ public class DexFile
|
|||||||
MapSection.writeTo(out);
|
MapSection.writeTo(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassDefItem getClassByName(String className) {
|
|
||||||
for (ClassDefItem classDefItem: ClassDefsSection.items) {
|
|
||||||
if (classDefItem.getClassName().equals(className)) {
|
|
||||||
return classDefItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new RuntimeException("class not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
public MethodIdItem[] getMethodsByClass(TypeIdItem classType) {
|
|
||||||
ArrayList<MethodIdItem> methods = new ArrayList<MethodIdItem>();
|
|
||||||
|
|
||||||
for (MethodIdItem methodIdItem: MethodIdsSection.items) {
|
|
||||||
if (methodIdItem.getClassType() == classType) {
|
|
||||||
methods.add(methodIdItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return methods.toArray(new MethodIdItem[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public final IndexedSection<HeaderItem> HeaderItemSection = new IndexedSection<HeaderItem>() {
|
public final IndexedSection<HeaderItem> HeaderItemSection = new IndexedSection<HeaderItem>() {
|
||||||
protected HeaderItem make(int index) {
|
protected HeaderItem make(int index) {
|
||||||
try {
|
try {
|
||||||
|
@ -32,13 +32,11 @@ import org.JesusFreke.dexlib.ItemType;
|
|||||||
import org.JesusFreke.dexlib.EncodedValue.ArrayEncodedValueSubField;
|
import org.JesusFreke.dexlib.EncodedValue.ArrayEncodedValueSubField;
|
||||||
import org.JesusFreke.dexlib.EncodedValue.EncodedValue;
|
import org.JesusFreke.dexlib.EncodedValue.EncodedValue;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ArrayEncodedValueSubField encodedArray;
|
private final ArrayEncodedValueSubField encodedArray;
|
||||||
|
|
||||||
public EncodedArrayItem(DexFile dexFile, int offset) {
|
public EncodedArrayItem(DexFile dexFile, int offset) {
|
||||||
@ -50,7 +48,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public EncodedArrayItem(DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
public EncodedArrayItem(DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
||||||
super(-1);
|
super(0);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues)
|
encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues)
|
||||||
@ -65,7 +63,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
|||||||
return super.place(index, offset);
|
return super.place(index, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,10 +71,6 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOffset() {
|
public int getOffset() {
|
||||||
return super.getOffset();
|
return super.getOffset();
|
||||||
}
|
}
|
||||||
@ -88,4 +82,8 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
|||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_ENCODED_ARRAY_ITEM;
|
return ItemType.TYPE_ENCODED_ARRAY_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "encoded_array @0x" + Integer.toHexString(getOffset());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,26 +31,24 @@ package org.JesusFreke.dexlib.EncodedValue;
|
|||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
|
|
||||||
public class AnnotationElement extends CompositeField<AnnotationElement> {
|
public class AnnotationElement extends CompositeField<AnnotationElement> {
|
||||||
private Field[] fields;
|
|
||||||
|
|
||||||
private final IndexedItemReference<StringIdItem> elementName;
|
private final IndexedItemReference<StringIdItem> elementName;
|
||||||
private final EncodedValue encodedValue;
|
private final EncodedValue encodedValue;
|
||||||
|
|
||||||
public AnnotationElement(final DexFile dexFile) {
|
public AnnotationElement(final DexFile dexFile) {
|
||||||
|
super("annotation_element");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
elementName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128Field()),
|
elementName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
|
new Leb128Field(null), "element_name"),
|
||||||
encodedValue = new EncodedValue(dexFile)
|
encodedValue = new EncodedValue(dexFile)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnnotationElement(final DexFile dexFile, StringIdItem elementName, EncodedValue encodedValue) {
|
public AnnotationElement(final DexFile dexFile, StringIdItem elementName, EncodedValue encodedValue) {
|
||||||
|
super("annotation_element");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
this.elementName = new IndexedItemReference<StringIdItem>(dexFile, elementName, new Leb128Field()),
|
this.elementName = new IndexedItemReference<StringIdItem>(dexFile, elementName,
|
||||||
|
new Leb128Field(null), "element_name"),
|
||||||
this.encodedValue = encodedValue
|
this.encodedValue = encodedValue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ import java.util.List;
|
|||||||
public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEncodedValueSubField>
|
public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEncodedValueSubField>
|
||||||
implements EncodedValueSubField<AnnotationEncodedValueSubField> {
|
implements EncodedValueSubField<AnnotationEncodedValueSubField> {
|
||||||
|
|
||||||
private final Field[] fields;
|
|
||||||
private final ArrayList<AnnotationElement> annotationElementList = new ArrayList<AnnotationElement>();
|
private final ArrayList<AnnotationElement> annotationElementList = new ArrayList<AnnotationElement>();
|
||||||
|
|
||||||
private final IndexedItemReference<TypeIdItem> annotationType;
|
private final IndexedItemReference<TypeIdItem> annotationType;
|
||||||
@ -44,10 +43,12 @@ public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEnc
|
|||||||
private final FieldListField<AnnotationElement> annotationElements;
|
private final FieldListField<AnnotationElement> annotationElements;
|
||||||
|
|
||||||
public AnnotationEncodedValueSubField(final DexFile dexFile) {
|
public AnnotationEncodedValueSubField(final DexFile dexFile) {
|
||||||
|
super("encoded_annotation");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
annotationType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128Field()),
|
annotationType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
annotationCount = new ListSizeField(annotationElementList, new Leb128Field()),
|
new Leb128Field(null), "type_idx"),
|
||||||
annotationElements = new FieldListField<AnnotationElement>(annotationElementList) {
|
annotationCount = new ListSizeField(annotationElementList, new Leb128Field("size")),
|
||||||
|
annotationElements = new FieldListField<AnnotationElement>(annotationElementList, "elements") {
|
||||||
protected AnnotationElement make() {
|
protected AnnotationElement make() {
|
||||||
return new AnnotationElement(dexFile);
|
return new AnnotationElement(dexFile);
|
||||||
}
|
}
|
||||||
@ -62,10 +63,6 @@ public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEnc
|
|||||||
this.annotationElementList.addAll(annotationElements);
|
this.annotationElementList.addAll(annotationElements);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInitialValueArg(byte valueArg) {
|
public void setInitialValueArg(byte valueArg) {
|
||||||
//valueArg is ignored for annotations
|
//valueArg is ignored for annotations
|
||||||
}
|
}
|
||||||
|
@ -36,14 +36,15 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
|
|||||||
implements EncodedValueSubField<ArrayEncodedValueSubField>
|
implements EncodedValueSubField<ArrayEncodedValueSubField>
|
||||||
{
|
{
|
||||||
|
|
||||||
private final Field[] fields;
|
|
||||||
private final ArrayList<EncodedValue> encodedValues;
|
private final ArrayList<EncodedValue> encodedValues;
|
||||||
|
|
||||||
public ArrayEncodedValueSubField(final DexFile dexFile) {
|
public ArrayEncodedValueSubField(final DexFile dexFile) {
|
||||||
|
super("encoded_array");
|
||||||
|
|
||||||
encodedValues = new ArrayList<EncodedValue>();
|
encodedValues = new ArrayList<EncodedValue>();
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ListSizeField(encodedValues, new Leb128Field()),
|
new ListSizeField(encodedValues, new Leb128Field("size")),
|
||||||
new FieldListField<EncodedValue>(encodedValues) {
|
new FieldListField<EncodedValue>(encodedValues, "values") {
|
||||||
protected EncodedValue make() {
|
protected EncodedValue make() {
|
||||||
return new EncodedValue(dexFile);
|
return new EncodedValue(dexFile);
|
||||||
}
|
}
|
||||||
@ -52,11 +53,13 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ArrayEncodedValueSubField(final DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
public ArrayEncodedValueSubField(final DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
||||||
|
super("encoded_array");
|
||||||
|
|
||||||
this.encodedValues = encodedValues;
|
this.encodedValues = encodedValues;
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ListSizeField(this.encodedValues, new Leb128Field()),
|
new ListSizeField(this.encodedValues, new Leb128Field("size")),
|
||||||
new FieldListField<EncodedValue>(encodedValues) {
|
new FieldListField<EncodedValue>(encodedValues, "values") {
|
||||||
protected EncodedValue make() {
|
protected EncodedValue make() {
|
||||||
return new EncodedValue(dexFile);
|
return new EncodedValue(dexFile);
|
||||||
}
|
}
|
||||||
@ -64,10 +67,6 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInitialValueArg(byte valueArg) {
|
public void setInitialValueArg(byte valueArg) {
|
||||||
//valueArg is ignored for arrays
|
//valueArg is ignored for arrays
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class BoolEncodedValueSubField
|
public class BoolEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Boolean, BoolEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Boolean, BoolEncodedValueSubField>
|
||||||
@ -41,7 +41,7 @@ public class BoolEncodedValueSubField
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class ByteEncodedValueSubField
|
public class ByteEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Byte, ByteEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Byte, ByteEncodedValueSubField>
|
||||||
@ -41,7 +41,8 @@ public class ByteEncodedValueSubField
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
out.annotate(1, "byte" + Integer.toHexString(value) + " " + Integer.toString(value));
|
||||||
out.writeByte(value);
|
out.writeByte(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class CharEncodedValueSubField
|
public class CharEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Character, CharEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Character, CharEncodedValueSubField>
|
||||||
@ -42,8 +42,10 @@ public class CharEncodedValueSubField
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
out.write(EncodedValueUtils.encodeUnsignedIntegralValue(value));
|
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value);
|
||||||
|
out.annotate(bytes.length, "CharEncodedValueSubField");
|
||||||
|
out.write(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class DoubleEncodedValueSubField
|
public class DoubleEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Double, DoubleEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Double, DoubleEncodedValueSubField>
|
||||||
@ -42,9 +42,10 @@ public class DoubleEncodedValueSubField
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
out.write(EncodedValueUtils.encodeRightZeroExtendedValue(
|
byte[] bytes = EncodedValueUtils.encodeRightZeroExtendedValue(Double.doubleToLongBits(value));
|
||||||
Double.doubleToLongBits(value)));
|
out.annotate(bytes.length, "DoubleEncodedValueSubField");
|
||||||
|
out.write(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
|
@ -29,25 +29,25 @@
|
|||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
/** TODO: it should be possible to somehow use the IndexedItemReference class */
|
|
||||||
public class EncodedIndexedItemReference<T extends IndexedItem<T>>
|
public class EncodedIndexedItemReference<T extends IndexedItem<T>>
|
||||||
extends ItemReference<T, EncodedIndexedItemReference<T>>
|
|
||||||
implements EncodedValueSubField<EncodedIndexedItemReference<T>> {
|
implements EncodedValueSubField<EncodedIndexedItemReference<T>> {
|
||||||
private int initialValueArg;
|
private int initialValueArg;
|
||||||
private ValueType valueType;
|
private ValueType valueType;
|
||||||
|
|
||||||
|
private T item = null;
|
||||||
|
private IndexedSection<T> section;
|
||||||
|
|
||||||
public EncodedIndexedItemReference(IndexedSection<T> section, ValueType valueType) {
|
public EncodedIndexedItemReference(IndexedSection<T> section, ValueType valueType) {
|
||||||
super(section);
|
|
||||||
this.valueType = valueType;
|
this.valueType = valueType;
|
||||||
|
this.section = section;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: implement support for enum values
|
//TODO: implement support for enum values
|
||||||
public EncodedIndexedItemReference(DexFile dexFile, T item) {
|
public EncodedIndexedItemReference(DexFile dexFile, T item) {
|
||||||
super(dexFile, item);
|
|
||||||
if (item.getClass() == StringIdItem.class) {
|
if (item.getClass() == StringIdItem.class) {
|
||||||
valueType = ValueType.VALUE_STRING;
|
valueType = ValueType.VALUE_STRING;
|
||||||
} else if (item.getClass() == TypeIdItem.class) {
|
} else if (item.getClass() == TypeIdItem.class) {
|
||||||
@ -57,31 +57,48 @@ public class EncodedIndexedItemReference<T extends IndexedItem<T>>
|
|||||||
} else if (item.getClass() == MethodIdItem.class) {
|
} else if (item.getClass() == MethodIdItem.class) {
|
||||||
valueType = ValueType.VALUE_METHOD;
|
valueType = ValueType.VALUE_METHOD;
|
||||||
}
|
}
|
||||||
|
this.item = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
T item = getReference();
|
|
||||||
if (!item.isPlaced()) {
|
if (!item.isPlaced()) {
|
||||||
throw new RuntimeException("Trying to write a reference to an item that hasn't been placed.");
|
throw new RuntimeException("Trying to write a reference to an item that hasn't been placed.");
|
||||||
}
|
}
|
||||||
out.write(EncodedValueUtils.encodeUnsignedIntegralValue(item.getIndex()));
|
|
||||||
|
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(item.getIndex());
|
||||||
|
|
||||||
|
if (item != null) {
|
||||||
|
out.annotate(bytes.length, item.getItemType().getTypeName() + " reference");
|
||||||
|
} else {
|
||||||
|
out.annotate(bytes.length, "null reference");
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
setReference(((IndexedSection<T>)getSection()).getByIndex(
|
item = section.getByIndex(
|
||||||
(int)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(initialValueArg + 1))));
|
(int)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(initialValueArg + 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int place(int offset) {
|
public int place(int offset) {
|
||||||
T item = getReference();
|
|
||||||
if (!item.isPlaced()) {
|
if (!item.isPlaced()) {
|
||||||
throw new RuntimeException("Trying to place a reference to an item that hasn't been placed.");
|
throw new RuntimeException("Trying to place a reference to an item that hasn't been placed.");
|
||||||
}
|
}
|
||||||
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(item.getIndex());
|
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(item.getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void copyTo(DexFile dexFile, EncodedIndexedItemReference<T> copy) {
|
||||||
|
if (item == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
T copiedItem = copy.section.intern(dexFile, item);
|
||||||
|
copy.item = copiedItem;
|
||||||
|
}
|
||||||
|
|
||||||
public T getValue() {
|
public T getValue() {
|
||||||
return getReference();
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInitialValueArg(byte valueArg)
|
public void setInitialValueArg(byte valueArg)
|
||||||
@ -90,7 +107,7 @@ public class EncodedIndexedItemReference<T extends IndexedItem<T>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte getValueArg() {
|
public byte getValueArg() {
|
||||||
return EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(getReference().getIndex());
|
return EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(item.getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueType getValueType() {
|
public ValueType getValueType() {
|
||||||
|
@ -28,13 +28,11 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
|
|
||||||
public class EncodedValue extends CompositeField<EncodedValue> {
|
public class EncodedValue extends CompositeField<EncodedValue> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private class ValueTypeArgField implements Field<ValueTypeArgField> {
|
private class ValueTypeArgField implements Field<ValueTypeArgField> {
|
||||||
private ValueType valueType;
|
private ValueType valueType;
|
||||||
private byte valueArg;
|
private byte valueArg;
|
||||||
@ -46,8 +44,8 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
|||||||
this.valueType = valueType;
|
this.valueType = valueType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
out.annotate(1, "valuetype=" + Integer.toString(valueType.getMapValue()) + " valueArg=" + Integer.toString(valueArg));
|
||||||
byte value = (byte)(valueType.getMapValue() | (valueArg << 5));
|
byte value = (byte)(valueType.getMapValue() | (valueArg << 5));
|
||||||
out.writeByte(value);
|
out.writeByte(value);
|
||||||
}
|
}
|
||||||
@ -102,7 +100,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
|||||||
this.subField = subField;
|
this.subField = subField;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
subField.writeTo(out);
|
subField.writeTo(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +145,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
|||||||
private final EncodedValueSubFieldWrapper encodedValue;
|
private final EncodedValueSubFieldWrapper encodedValue;
|
||||||
|
|
||||||
public EncodedValue(final DexFile dexFile) {
|
public EncodedValue(final DexFile dexFile) {
|
||||||
|
super("encoded_value");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
valueTypeArg = new ValueTypeArgField(),
|
valueTypeArg = new ValueTypeArgField(),
|
||||||
encodedValue = new EncodedValueSubFieldWrapper(dexFile)
|
encodedValue = new EncodedValueSubFieldWrapper(dexFile)
|
||||||
@ -154,6 +153,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public EncodedValue(final DexFile dexFile, EncodedValueSubField subField) {
|
public EncodedValue(final DexFile dexFile, EncodedValueSubField subField) {
|
||||||
|
super("encoded_value");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
valueTypeArg = new ValueTypeArgField(subField.getValueType()),
|
valueTypeArg = new ValueTypeArgField(subField.getValueType()),
|
||||||
encodedValue = new EncodedValueSubFieldWrapper(dexFile, subField)
|
encodedValue = new EncodedValueSubFieldWrapper(dexFile, subField)
|
||||||
@ -182,8 +182,4 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
|||||||
public byte getValueArg() {
|
public byte getValueArg() {
|
||||||
return valueTypeArg.getValueArg();
|
return valueTypeArg.getValueArg();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class FloatEncodedValueSubField
|
public class FloatEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Float, FloatEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Float, FloatEncodedValueSubField>
|
||||||
@ -41,9 +41,10 @@ public class FloatEncodedValueSubField
|
|||||||
public FloatEncodedValueSubField(float value) {
|
public FloatEncodedValueSubField(float value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
out.write(EncodedValueUtils.encodeRightZeroExtendedValue(
|
byte[] bytes = EncodedValueUtils.encodeRightZeroExtendedValue(((long)Float.floatToIntBits(value)) << 32);
|
||||||
((long)Float.floatToIntBits(value)) << 32));
|
out.annotate(bytes.length, "FloatEncodedValueSubField");
|
||||||
|
out.write(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class IntEncodedValueSubField
|
public class IntEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Integer, IntEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Integer, IntEncodedValueSubField>
|
||||||
@ -42,8 +42,10 @@ public class IntEncodedValueSubField
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
out.write(EncodedValueUtils.encodeSignedIntegralValue(value));
|
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||||
|
out.annotate(bytes.length, "IntEncodedValueSubField");
|
||||||
|
out.write(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class LongEncodedValueSubField
|
public class LongEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Long, LongEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Long, LongEncodedValueSubField>
|
||||||
@ -42,8 +42,10 @@ public class LongEncodedValueSubField
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
out.write(EncodedValueUtils.encodeSignedIntegralValue(value));
|
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||||
|
out.annotate(bytes.length, "LongEncodedValueSubField");
|
||||||
|
out.write(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class NullEncodedValueSubField
|
public class NullEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Object, NullEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Object, NullEncodedValueSubField>
|
||||||
@ -37,7 +37,7 @@ public class NullEncodedValueSubField
|
|||||||
public NullEncodedValueSubField() {
|
public NullEncodedValueSubField() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib.EncodedValue;
|
package org.JesusFreke.dexlib.EncodedValue;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class ShortEncodedValueSubField
|
public class ShortEncodedValueSubField
|
||||||
extends SimpleEncodedValueSubField<Short, ShortEncodedValueSubField>
|
extends SimpleEncodedValueSubField<Short, ShortEncodedValueSubField>
|
||||||
@ -42,8 +42,10 @@ public class ShortEncodedValueSubField
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
out.write(EncodedValueUtils.encodeSignedIntegralValue(value));
|
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||||
|
out.annotate(bytes.length, "ShortEncodedValueSubField");
|
||||||
|
out.write(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
|
@ -30,9 +30,10 @@ package org.JesusFreke.dexlib;
|
|||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public interface Field<T extends Field> {
|
public interface Field<T extends Field> {
|
||||||
public void writeTo(Output out);
|
public void writeTo(AnnotatedOutput out);
|
||||||
public void readFrom(Input in);
|
public void readFrom(Input in);
|
||||||
public int place(int offset);
|
public int place(int offset);
|
||||||
public void copyTo(DexFile dexFile, T copy);
|
public void copyTo(DexFile dexFile, T copy);
|
||||||
|
@ -28,31 +28,28 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.ItemType;
|
|
||||||
|
|
||||||
public class FieldIdItem extends IndexedItem<FieldIdItem> {
|
public class FieldIdItem extends IndexedItem<FieldIdItem> {
|
||||||
private final Field[] fields;
|
private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
|
||||||
|
private final IndexedItemReference<TypeIdItem> fieldTypeReferenceField;
|
||||||
private final IndexedItemReference<TypeIdItem> classType;
|
private final IndexedItemReference<StringIdItem> fieldNameReferenceField;
|
||||||
private final IndexedItemReference<TypeIdItem> fieldType;
|
|
||||||
private final IndexedItemReference<StringIdItem> fieldName;
|
|
||||||
|
|
||||||
public FieldIdItem(DexFile dexFile, int index) {
|
public FieldIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()),
|
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
fieldType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()),
|
new ShortIntegerField(null), "class_idx"),
|
||||||
fieldName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField())
|
fieldTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
|
new ShortIntegerField(null), "type_idx"),
|
||||||
|
fieldNameReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
|
new IntegerField(null), "parameters_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem fieldName, TypeIdItem fieldType) {
|
public FieldIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem fieldName, TypeIdItem fieldType) {
|
||||||
super(-1);
|
this(dexFile, -1);
|
||||||
fields = new Field[] {
|
classTypeReferenceField.setReference(classType);
|
||||||
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new ShortIntegerField()),
|
fieldTypeReferenceField.setReference(fieldType);
|
||||||
this.fieldType = new IndexedItemReference<TypeIdItem>(dexFile, fieldType, new ShortIntegerField()),
|
fieldNameReferenceField.setReference(fieldName);
|
||||||
this.fieldName = new IndexedItemReference<StringIdItem>(dexFile, fieldName, new IntegerField())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldIdItem(DexFile dexFile, TypeIdItem classType, String fieldName, TypeIdItem fieldType) {
|
public FieldIdItem(DexFile dexFile, TypeIdItem classType, String fieldName, TypeIdItem fieldType) {
|
||||||
@ -63,34 +60,35 @@ public class FieldIdItem extends IndexedItem<FieldIdItem> {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_FIELD_ID_ITEM;
|
return ItemType.TYPE_FIELD_ID_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String getConciseIdentity() {
|
||||||
return classType.toString() + " - " + fieldName.toString();
|
String parentClass = classTypeReferenceField.getReference().getTypeDescriptor();
|
||||||
|
//strip off the leading L and trailing ;
|
||||||
|
parentClass = parentClass.substring(1, parentClass.length() - 1);
|
||||||
|
|
||||||
|
return parentClass + "/" + fieldNameReferenceField.getReference().getStringValue() +
|
||||||
|
":" + fieldTypeReferenceField.getReference().getTypeDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(FieldIdItem o) {
|
public int compareTo(FieldIdItem o) {
|
||||||
int result = classType.compareTo(o.classType);
|
int result = classTypeReferenceField.compareTo(o.classTypeReferenceField);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = fieldName.compareTo(o.fieldName);
|
result = fieldNameReferenceField.compareTo(o.fieldNameReferenceField);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fieldType.compareTo(o.fieldType);
|
return fieldTypeReferenceField.compareTo(o.fieldTypeReferenceField);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeIdItem getFieldType() {
|
public TypeIdItem getFieldType() {
|
||||||
return fieldType.getReference();
|
return fieldTypeReferenceField.getReference();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,30 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public abstract class FieldListField<T extends Field> implements Field<FieldListField<T>> {
|
public abstract class FieldListField<T extends Field> implements Field<FieldListField<T>> {
|
||||||
final ArrayList<T> list;
|
final ArrayList<T> list;
|
||||||
|
private final String fieldName;
|
||||||
|
|
||||||
public FieldListField(ArrayList<T> list) {
|
public FieldListField(ArrayList<T> list, String fieldName) {
|
||||||
this.list = list;
|
this.list = list;
|
||||||
|
this.fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
for (Field field: list) {
|
if (list.size() > 0) {
|
||||||
field.writeTo(out);
|
int i=0;
|
||||||
|
for (Field field: list) {
|
||||||
|
out.annotate(0, fieldName + "[" + Integer.toString(i) + "]");
|
||||||
|
out.indent();
|
||||||
|
field.writeTo(out);
|
||||||
|
out.deindent();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,27 +28,34 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.ByteArray;
|
import org.JesusFreke.dexlib.util.ByteArray;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class FixedByteArrayField implements Field<FixedByteArrayField> {
|
public class FixedByteArrayField implements Field<FixedByteArrayField> {
|
||||||
protected byte[] value;
|
protected byte[] value;
|
||||||
|
private final String fieldName;
|
||||||
|
|
||||||
public FixedByteArrayField(int size) {
|
public FixedByteArrayField(int size, String fieldName) {
|
||||||
value = new byte[size];
|
value = new byte[size];
|
||||||
|
this.fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedByteArrayField(byte[] bytes) {
|
public FixedByteArrayField(byte[] bytes, String fieldName) {
|
||||||
this.value = bytes.clone();
|
this.value = bytes.clone();
|
||||||
|
this.fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedByteArrayField(ByteArray byteArray) {
|
public FixedByteArrayField(ByteArray byteArray, String fieldName) {
|
||||||
value = new byte[byteArray.size()];
|
value = new byte[byteArray.size()];
|
||||||
byteArray.getBytes(value, 0);
|
byteArray.getBytes(value, 0);
|
||||||
|
this.fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
if (fieldName != null) {
|
||||||
|
out.annotate(fieldName);
|
||||||
|
}
|
||||||
out.write(value);
|
out.write(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.ItemType;
|
import org.JesusFreke.dexlib.ItemType;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
@ -46,103 +46,97 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
|||||||
/** the endianness tag */
|
/** the endianness tag */
|
||||||
private static final int ENDIAN_TAG = 0x12345678;
|
private static final int ENDIAN_TAG = 0x12345678;
|
||||||
|
|
||||||
private final Field[] fields;
|
private final FixedByteArrayField magicField;
|
||||||
|
private final IntegerField checksumField;
|
||||||
protected Field[] getFields() {
|
private final FixedByteArrayField signatureField;
|
||||||
return fields;
|
private final IntegerField fileSizeField;
|
||||||
}
|
private final IntegerField headerSizeField;
|
||||||
|
private final IntegerField endianTagField;
|
||||||
private final FixedByteArrayField magic;
|
private final IntegerField linkSizeField;
|
||||||
private final IntegerField checksum;
|
private final IntegerField linkOffField;
|
||||||
private final FixedByteArrayField signature;
|
private final IntegerField mapOffField;
|
||||||
private final IntegerField fileSize;
|
private final SectionHeaderInfo StringIdsHeaderField;
|
||||||
private final IntegerField headerSize;
|
private final SectionHeaderInfo TypeIdsHeaderField;
|
||||||
private final IntegerField endianTag;
|
private final SectionHeaderInfo ProtoIdsHeaderField;
|
||||||
private final IntegerField linkSize;
|
private final SectionHeaderInfo FieldIdsHeaderField;
|
||||||
private final IntegerField linkOff;
|
private final SectionHeaderInfo MethodIdsHeaderField;
|
||||||
private final IntegerField mapOff;
|
private final SectionHeaderInfo ClassDefsHeaderField;
|
||||||
private final SectionHeaderInfo StringIdsInfo;
|
private final IntegerField dataSizeField;
|
||||||
private final SectionHeaderInfo TypeIdsInfo;
|
private final IntegerField dataOffField;
|
||||||
private final SectionHeaderInfo ProtoIdsInfo;
|
|
||||||
private final SectionHeaderInfo FieldIdsInfo;
|
|
||||||
private final SectionHeaderInfo MethodIdsInfo;
|
|
||||||
private final SectionHeaderInfo ClassDefsInfo;
|
|
||||||
private final IntegerField dataSize;
|
|
||||||
private final IntegerField dataOff;
|
|
||||||
|
|
||||||
public HeaderItem(final DexFile file, int index) throws UnsupportedEncodingException {
|
public HeaderItem(final DexFile file, int index) throws UnsupportedEncodingException {
|
||||||
super(index);
|
super(index);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
magic = new FixedByteArrayField(MAGIC.getBytes("US-ASCII")),
|
magicField = new FixedByteArrayField(MAGIC.getBytes("US-ASCII"), "magic"),
|
||||||
checksum = new IntegerField() {
|
checksumField = new IntegerField("checksum") {
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
cacheValue(0);
|
cacheValue(0);
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
signature = new FixedByteArrayField(20) {
|
signatureField = new FixedByteArrayField(20, "signature") {
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
for (int i = 0; i < value.length; i++) {
|
for (int i = 0; i < value.length; i++) {
|
||||||
value[i] = 0;
|
value[i] = 0;
|
||||||
}
|
}
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fileSize = new IntegerField() {
|
fileSizeField = new IntegerField("file_size") {
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
cacheValue(file.getFileSize());
|
cacheValue(file.getFileSize());
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
headerSize = new IntegerField(HEADER_SIZE),
|
headerSizeField = new IntegerField(HEADER_SIZE,"header_size"),
|
||||||
endianTag = new IntegerField(ENDIAN_TAG),
|
endianTagField = new IntegerField(ENDIAN_TAG,"endian_tag"),
|
||||||
linkSize = new IntegerField(0),
|
linkSizeField = new IntegerField(0,"link_size"),
|
||||||
linkOff = new IntegerField(0),
|
linkOffField = new IntegerField(0,"link_off"),
|
||||||
mapOff = new IntegerField() {
|
mapOffField = new IntegerField("map_off") {
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
cacheValue(file.MapSection.getOffset());
|
cacheValue(file.MapSection.getOffset());
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
StringIdsInfo = new SectionHeaderInfo() {
|
StringIdsHeaderField = new SectionHeaderInfo("string_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.StringIdsSection;
|
return file.StringIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TypeIdsInfo = new SectionHeaderInfo() {
|
TypeIdsHeaderField = new SectionHeaderInfo("type_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.TypeIdsSection;
|
return file.TypeIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ProtoIdsInfo = new SectionHeaderInfo() {
|
ProtoIdsHeaderField = new SectionHeaderInfo("proto_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.ProtoIdsSection;
|
return file.ProtoIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FieldIdsInfo = new SectionHeaderInfo() {
|
FieldIdsHeaderField = new SectionHeaderInfo("field_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.FieldIdsSection;
|
return file.FieldIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MethodIdsInfo = new SectionHeaderInfo() {
|
MethodIdsHeaderField = new SectionHeaderInfo("method_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.MethodIdsSection;
|
return file.MethodIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ClassDefsInfo = new SectionHeaderInfo() {
|
ClassDefsHeaderField = new SectionHeaderInfo("class_defs") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.ClassDefsSection;
|
return file.ClassDefsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dataSize = new IntegerField() {
|
dataSizeField = new IntegerField("data_size") {
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
cacheValue(file.getDataSize());
|
cacheValue(file.getDataSize());
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dataOff = new IntegerField() {
|
dataOffField = new IntegerField("data_off") {
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
cacheValue(file.getDataOffset());
|
cacheValue(file.getDataOffset());
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
@ -151,7 +145,7 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getMapOffset() {
|
public int getMapOffset() {
|
||||||
return mapOff.getCachedValue();
|
return mapOffField.getCachedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getAlignment() {
|
protected int getAlignment() {
|
||||||
@ -162,6 +156,10 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
|||||||
return ItemType.TYPE_HEADER_ITEM;
|
return ItemType.TYPE_HEADER_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "header_item";
|
||||||
|
}
|
||||||
|
|
||||||
public int compareTo(HeaderItem o) {
|
public int compareTo(HeaderItem o) {
|
||||||
//there is only 1 header item
|
//there is only 1 header item
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -29,18 +29,7 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
public abstract class IndexedItem<T extends IndexedItem> extends Item<T> implements Comparable<T> {
|
public abstract class IndexedItem<T extends IndexedItem> extends Item<T> implements Comparable<T> {
|
||||||
private int index;
|
|
||||||
|
|
||||||
protected IndexedItem(int index) {
|
protected IndexedItem(int index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public int place(int index, int offset) {
|
|
||||||
this.index = index;
|
|
||||||
return super.place(index, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getIndex() {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,49 +28,41 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class IndexedItemReference<T extends IndexedItem<T>> extends
|
public class IndexedItemReference<T extends IndexedItem<T>> extends
|
||||||
ItemReference<T,IndexedItemReference<T>> implements Comparable<IndexedItemReference<T>> {
|
ItemReference<T,IndexedItemReference<T>> implements Comparable<IndexedItemReference<T>> {
|
||||||
private final CachedIntegerValueField underlyingField;
|
|
||||||
|
|
||||||
public IndexedItemReference(IndexedSection<T> section, CachedIntegerValueField underlyingField) {
|
public IndexedItemReference(IndexedSection<T> section, CachedIntegerValueField underlyingField,
|
||||||
super(section);
|
String fieldName) {
|
||||||
this.underlyingField = underlyingField;
|
super(section, underlyingField, fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField) {
|
public IndexedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField,
|
||||||
super(dexFile, item);
|
String fieldName) {
|
||||||
this.underlyingField = underlyingField;
|
super(dexFile, item, underlyingField, fieldName);
|
||||||
}
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
|
||||||
T item = getReference();
|
|
||||||
if (item != null && !item.isPlaced()) {
|
|
||||||
throw new RuntimeException("Trying to write a reference to an item that hasn't been placed.");
|
|
||||||
}
|
|
||||||
underlyingField.writeTo(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
|
||||||
underlyingField.readFrom(in);
|
|
||||||
if (underlyingField.getCachedValue() != -1) {
|
|
||||||
setReference(getSection().getByIndex(underlyingField.getCachedValue()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexedSection<T> getSection() {
|
public IndexedSection<T> getSection() {
|
||||||
return (IndexedSection<T>)super.getSection();
|
return (IndexedSection<T>)super.getSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int place(int offset) {
|
protected int getReferenceValue() {
|
||||||
if (getReference() != null) {
|
T item = getReference();
|
||||||
underlyingField.cacheValue(getReference().getIndex());
|
if (item == null) {
|
||||||
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
underlyingField.cacheValue(-1);
|
return item.getIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T getReferencedItem(int referenceValue) {
|
||||||
|
if (referenceValue == -1) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return getSection().getByIndex(referenceValue);
|
||||||
}
|
}
|
||||||
return underlyingField.place(offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(IndexedItemReference<T> o) {
|
public int compareTo(IndexedItemReference<T> o) {
|
||||||
|
@ -28,21 +28,16 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
|
|
||||||
public class IntegerField extends CachedIntegerValueField {
|
public class IntegerField extends CachedIntegerValueField<IntegerField> {
|
||||||
protected int value = 0;
|
public IntegerField(String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
public IntegerField() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntegerField(int value) {
|
public IntegerField(int value, String fieldName) {
|
||||||
this.value = value;
|
super(value, fieldName);
|
||||||
}
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
|
||||||
out.writeInt(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
@ -53,18 +48,7 @@ public class IntegerField extends CachedIntegerValueField {
|
|||||||
return offset + 4;
|
return offset + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected void writeValue(Output out) {
|
||||||
* This method returns the integer value that has been cached. This
|
out.writeInt(value);
|
||||||
* value is either the value that the field was constructed with, the
|
|
||||||
* value that was read via <code>readFrom</code>, or the value that was
|
|
||||||
* cached when <code>place</code> was called
|
|
||||||
* @return the cached value
|
|
||||||
*/
|
|
||||||
public int getCachedValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cacheValue(int value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,18 +30,18 @@ package org.JesusFreke.dexlib;
|
|||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
import org.JesusFreke.dexlib.ItemType;
|
import org.JesusFreke.dexlib.ItemType;
|
||||||
|
|
||||||
public abstract class Item<T extends Item> {
|
public abstract class Item<T extends Item> {
|
||||||
private int offset = -1;
|
protected int offset = -1;
|
||||||
|
protected int index = -1;
|
||||||
|
|
||||||
|
protected Field[] fields;
|
||||||
|
|
||||||
protected Item() {
|
protected Item() {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Item(int offset) {
|
|
||||||
this.offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPlaced() {
|
public boolean isPlaced() {
|
||||||
return offset > -1;
|
return offset > -1;
|
||||||
}
|
}
|
||||||
@ -53,10 +53,9 @@ public abstract class Item<T extends Item> {
|
|||||||
public int place(int index, int offset) {
|
public int place(int index, int offset) {
|
||||||
offset = alignOffset(offset);
|
offset = alignOffset(offset);
|
||||||
|
|
||||||
|
this.index = index;
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
|
|
||||||
Field[] fields = getFields();
|
|
||||||
|
|
||||||
for (Field field: fields) {
|
for (Field field: fields) {
|
||||||
offset = field.place(offset);
|
offset = field.place(offset);
|
||||||
}
|
}
|
||||||
@ -64,23 +63,30 @@ public abstract class Item<T extends Item> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
for (Field field: getFields()) {
|
for (Field field: fields) {
|
||||||
field.readFrom(in);
|
field.readFrom(in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
out.alignTo(getAlignment());
|
out.alignTo(getAlignment());
|
||||||
|
|
||||||
|
out.annotate(0, "[0x" + Integer.toHexString(this.getIndex()) + "] " + this.getItemType().getTypeName() );
|
||||||
|
out.indent();
|
||||||
|
|
||||||
if (out.getCursor() != offset) {
|
if (out.getCursor() != offset) {
|
||||||
throw new RuntimeException("Item is being written somewhere other than where it was placed");
|
throw new RuntimeException("Item is being written somewhere other than where it was placed");
|
||||||
}
|
}
|
||||||
for (Field field: getFields()) {
|
for (Field field: fields) {
|
||||||
field.writeTo(out);
|
field.writeTo(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out.deindent();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract int getAlignment();
|
protected int getAlignment() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
protected int alignOffset(int offset) {
|
protected int alignOffset(int offset) {
|
||||||
int mask = getAlignment() - 1;
|
int mask = getAlignment() - 1;
|
||||||
@ -88,49 +94,57 @@ public abstract class Item<T extends Item> {
|
|||||||
return (offset + mask) & ~mask;
|
return (offset + mask) & ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getOffset() {
|
public int getOffset() {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Field[] getFields();
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract ItemType getItemType();
|
public abstract ItemType getItemType();
|
||||||
|
|
||||||
public void copyTo(DexFile dexFile, T copy) {
|
public void copyTo(DexFile dexFile, T copy) {
|
||||||
Field[] fields = getFields();
|
|
||||||
Field[] fieldsCopy = copy.getFields();
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
fields[i].copyTo(dexFile, fieldsCopy[i]);
|
fields[i].copyTo(dexFile, copy.fields[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int h = 1;
|
int h = 1;
|
||||||
for (Field field: getFields()) {
|
for (Field field: fields) {
|
||||||
h = h*31 + field.hashCode();
|
h = h*31 + field.hashCode();
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof Item)) {
|
if (!this.getClass().isInstance(o)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Item other = (Item)o;
|
Item other = (Item)o;
|
||||||
Field[] fields = getFields();
|
|
||||||
Field[] otherFields = other.getFields();
|
|
||||||
|
|
||||||
if (fields.length != otherFields.length) {
|
if (fields.length != other.fields.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
if (!fields[i].equals(otherFields[i])) {
|
if (!fields[i].equals(other.fields[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a concise string value that conveys the identity of this item
|
||||||
|
* @return A concise string value that conveys the identity of this item
|
||||||
|
*/
|
||||||
|
public abstract String getConciseIdentity();
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getConciseIdentity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,19 +28,28 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
|
||||||
public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T,S>> implements Field<S> {
|
public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T,S>> implements Field<S> {
|
||||||
private T item = null;
|
private T item = null;
|
||||||
private Section<T> section;
|
private Section<T> section;
|
||||||
|
private final CachedIntegerValueField underlyingField;
|
||||||
|
private final String fieldName;
|
||||||
|
|
||||||
public ItemReference(Section<T> section) {
|
public ItemReference(Section<T> section, CachedIntegerValueField underlyingField, String fieldName) {
|
||||||
this.section = section;
|
this.section = section;
|
||||||
|
this.underlyingField = underlyingField;
|
||||||
|
this.fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemReference(DexFile dexFile, T item) {
|
public ItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField, String fieldName) {
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
section = dexFile.getSectionForItem(item);
|
section = dexFile.getSectionForItem(item);
|
||||||
this.item = item;
|
this.item = item;
|
||||||
}
|
}
|
||||||
|
this.underlyingField = underlyingField;
|
||||||
|
this.fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getReference() {
|
public T getReference() {
|
||||||
@ -65,6 +74,34 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
|
|||||||
copy.setReference(copiedItem);
|
copy.setReference(copiedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
T item = getReference();
|
||||||
|
|
||||||
|
if (item != null) {
|
||||||
|
if (!item.isPlaced()) {
|
||||||
|
throw new RuntimeException("Trying to write reference to an item that hasn't been placed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//in some cases, we have to re-cache the value here, because the exact offset wasn't known yet
|
||||||
|
//during placement. Luckily, all variable sized reference offsets (Leb128) are known at placement,
|
||||||
|
//so this won't change the size of anything
|
||||||
|
underlyingField.cacheValue(getReferenceValue());
|
||||||
|
|
||||||
|
String annotation = fieldName + ": 0x" + Integer.toHexString(underlyingField.getCachedValue());
|
||||||
|
if (item != null) {
|
||||||
|
annotation += " (" + item.getConciseIdentity() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
out.annotate(annotation);
|
||||||
|
underlyingField.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readFrom(Input in) {
|
||||||
|
underlyingField.readFrom(in);
|
||||||
|
setReference(getReferencedItem(underlyingField.getCachedValue()));
|
||||||
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -84,4 +121,20 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
|
|||||||
return other.item == null;
|
return other.item == null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int place(int offset) {
|
||||||
|
/**
|
||||||
|
* We need to cache the reference value so that the underlying field can calculate its length.
|
||||||
|
* Sometimes this value isn't correct, but the order that items are placed is such that
|
||||||
|
* the value is correct for any references using a variable sized field (i.e. leb128) to
|
||||||
|
* store the reference. For non-variable sized fields, it doesn't matter if the value is
|
||||||
|
* correct or not. We'll get the correct value for these in writeTo(), just before it is
|
||||||
|
* written
|
||||||
|
*/
|
||||||
|
underlyingField.cacheValue(getReferenceValue());
|
||||||
|
return underlyingField.place(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int getReferenceValue();
|
||||||
|
protected abstract T getReferencedItem(int referenceValue);
|
||||||
}
|
}
|
||||||
|
@ -28,22 +28,17 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.Leb128Utils;
|
import org.JesusFreke.dexlib.util.Leb128Utils;
|
||||||
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
|
|
||||||
public class Leb128Field extends CachedIntegerValueField {
|
public class Leb128Field extends CachedIntegerValueField {
|
||||||
protected int value;
|
public Leb128Field(String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
public Leb128Field() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Leb128Field(int value) {
|
public Leb128Field(int value, String fieldName) {
|
||||||
this.value = value;
|
super(value, fieldName);
|
||||||
}
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
|
||||||
out.writeUnsignedLeb128(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
@ -54,11 +49,7 @@ public class Leb128Field extends CachedIntegerValueField {
|
|||||||
return offset + Leb128Utils.unsignedLeb128Size(value);
|
return offset + Leb128Utils.unsignedLeb128Size(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCachedValue() {
|
public void writeValue(Output out) {
|
||||||
return value;
|
out.writeUnsignedLeb128(value);
|
||||||
}
|
|
||||||
|
|
||||||
public void cacheValue(int value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,22 +28,17 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.Leb128Utils;
|
import org.JesusFreke.dexlib.util.Leb128Utils;
|
||||||
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
|
|
||||||
public class Leb128p1Field extends CachedIntegerValueField {
|
public class Leb128p1Field extends CachedIntegerValueField {
|
||||||
protected int value;
|
public Leb128p1Field(String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
public Leb128p1Field() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Leb128p1Field(int value) {
|
public Leb128p1Field(int value, String fieldName) {
|
||||||
this.value = value;
|
super(value, fieldName);
|
||||||
}
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
|
||||||
out.writeUnsignedLeb128(value + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
@ -54,11 +49,7 @@ public class Leb128p1Field extends CachedIntegerValueField {
|
|||||||
return offset + Leb128Utils.unsignedLeb128Size(value + 1);
|
return offset + Leb128Utils.unsignedLeb128Size(value + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCachedValue() {
|
public void writeValue(Output out) {
|
||||||
return value;
|
out.writeUnsignedLeb128(value + 1);
|
||||||
}
|
|
||||||
|
|
||||||
public void cacheValue(int value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,11 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class ListSizeField extends CachedIntegerValueField {
|
public class ListSizeField implements Field<ListSizeField> {
|
||||||
private final ArrayList<?> list;
|
private final ArrayList<?> list;
|
||||||
private final CachedIntegerValueField underlyingField;
|
private final CachedIntegerValueField underlyingField;
|
||||||
|
|
||||||
@ -42,13 +42,14 @@ public class ListSizeField extends CachedIntegerValueField {
|
|||||||
this.underlyingField = underlyingField;
|
this.underlyingField = underlyingField;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
underlyingField.writeTo(out);
|
underlyingField.writeTo(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
underlyingField.readFrom(in);
|
underlyingField.readFrom(in);
|
||||||
/** the absolute value operation is needed for the case when a list sized is
|
/**
|
||||||
|
* the absolute value operation is needed for the case when a list size is
|
||||||
* encoded as the absolute value of a signed integer
|
* encoded as the absolute value of a signed integer
|
||||||
*/
|
*/
|
||||||
int listSize = Math.abs(underlyingField.getCachedValue());
|
int listSize = Math.abs(underlyingField.getCachedValue());
|
||||||
@ -65,6 +66,10 @@ public class ListSizeField extends CachedIntegerValueField {
|
|||||||
return underlyingField.place(offset);
|
return underlyingField.place(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void copyTo(DexFile dexFile, ListSizeField copy) {
|
||||||
|
//nothing to do, the value is retrieved from the list
|
||||||
|
}
|
||||||
|
|
||||||
public int getCachedValue() {
|
public int getCachedValue() {
|
||||||
return underlyingField.getCachedValue();
|
return underlyingField.getCachedValue();
|
||||||
}
|
}
|
||||||
|
@ -29,32 +29,20 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.ItemType;
|
import org.JesusFreke.dexlib.ItemType;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class MapField extends CompositeField<MapField> {
|
public class MapField extends CompositeField<MapField> {
|
||||||
private final Field[] fields;
|
private final ShortIntegerField sectionTypeField;
|
||||||
|
private final ShortIntegerField unusedField;
|
||||||
public ItemType getSectionItemType() {
|
private final SectionHeaderInfo sectionInfoField;
|
||||||
return ItemType.fromInt(sectionType.getCachedValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSectionSize() {
|
|
||||||
return sectionInfo.getSectionSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSectionOffset() {
|
|
||||||
return sectionInfo.getSectionOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ShortIntegerField sectionType;
|
|
||||||
private final ShortIntegerField unused;
|
|
||||||
private final SectionHeaderInfo sectionInfo;
|
|
||||||
|
|
||||||
public MapField(final DexFile dexFile) {
|
public MapField(final DexFile dexFile) {
|
||||||
|
super("map_entry");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
sectionType = new ShortIntegerField(),
|
//TODO: add an annotation for the item type
|
||||||
unused = new ShortIntegerField((short)0),
|
sectionTypeField = new ShortIntegerField("type"),
|
||||||
sectionInfo = new SectionHeaderInfo() {
|
unusedField = new ShortIntegerField((short)0, "not used"),
|
||||||
|
sectionInfoField = new SectionHeaderInfo("section") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return dexFile.getSectionForType(getSectionItemType());
|
return dexFile.getSectionForType(getSectionItemType());
|
||||||
}
|
}
|
||||||
@ -63,26 +51,19 @@ public class MapField extends CompositeField<MapField> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MapField(final DexFile dexFile, short sectionType) {
|
public MapField(final DexFile dexFile, short sectionType) {
|
||||||
fields = new Field[] {
|
this(dexFile);
|
||||||
this.sectionType = new ShortIntegerField(sectionType),
|
sectionTypeField.cacheValue(sectionType);
|
||||||
this.unused = new ShortIntegerField((short)0),
|
}
|
||||||
this.sectionInfo = new SectionHeaderInfo() {
|
|
||||||
protected Section getSection() {
|
public ItemType getSectionItemType() {
|
||||||
return dexFile.getSectionForType(getSectionItemType());
|
return ItemType.fromInt(sectionTypeField.getCachedValue());
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int place(int offset) {
|
public int getSectionSize() {
|
||||||
return super.place(offset);
|
return sectionInfoField.getSectionSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public int getSectionOffset() {
|
||||||
super.writeTo(out);
|
return sectionInfoField.getSectionOffset();
|
||||||
}
|
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,22 +29,21 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.ItemType;
|
import org.JesusFreke.dexlib.ItemType;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public class MapItem extends IndexedItem<MapItem> {
|
public class MapItem extends IndexedItem<MapItem> {
|
||||||
private final Field[] fields;
|
|
||||||
private ArrayList<MapField> mapEntries = new ArrayList<MapField>();
|
private ArrayList<MapField> mapEntries = new ArrayList<MapField>();
|
||||||
|
|
||||||
public MapItem(final DexFile dexFile, int index) {
|
public MapItem(final DexFile dexFile, int index) {
|
||||||
super(index);
|
super(index);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ListSizeField(mapEntries, new IntegerField()),
|
new ListSizeField(mapEntries, new IntegerField("size")),
|
||||||
new FieldListField<MapField>(mapEntries) {
|
new FieldListField<MapField>(mapEntries, "map_entry") {
|
||||||
protected MapField make() {
|
protected MapField make() {
|
||||||
return new MapField(dexFile);
|
return new MapField(dexFile);
|
||||||
}
|
}
|
||||||
@ -64,7 +63,7 @@ public class MapItem extends IndexedItem<MapItem> {
|
|||||||
return super.place(index, offset);
|
return super.place(index, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
Collections.sort(mapEntries, new Comparator<MapField>() {
|
Collections.sort(mapEntries, new Comparator<MapField>() {
|
||||||
|
|
||||||
public int compare(MapField o1, MapField o2) {
|
public int compare(MapField o1, MapField o2) {
|
||||||
@ -108,10 +107,6 @@ public class MapItem extends IndexedItem<MapItem> {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_MAP_LIST;
|
return ItemType.TYPE_MAP_LIST;
|
||||||
}
|
}
|
||||||
@ -128,6 +123,10 @@ public class MapItem extends IndexedItem<MapItem> {
|
|||||||
return getClass() == o.getClass();
|
return getClass() == o.getClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "map_item";
|
||||||
|
}
|
||||||
|
|
||||||
public int compareTo(MapItem o) {
|
public int compareTo(MapItem o) {
|
||||||
//there is only 1 map item
|
//there is only 1 map item
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -29,65 +29,60 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
public class MethodIdItem extends IndexedItem<MethodIdItem> {
|
public class MethodIdItem extends IndexedItem<MethodIdItem> {
|
||||||
private final Field[] fields;
|
private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
|
||||||
|
private final IndexedItemReference<ProtoIdItem> prototypeReferenceField;
|
||||||
private final IndexedItemReference<TypeIdItem> classType;
|
private final IndexedItemReference<StringIdItem> methodNameReferenceField;
|
||||||
private final IndexedItemReference<ProtoIdItem> prototype;
|
|
||||||
private final IndexedItemReference<StringIdItem> methodName;
|
|
||||||
|
|
||||||
public MethodIdItem(DexFile dexFile, int index) {
|
public MethodIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()),
|
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
prototype = new IndexedItemReference<ProtoIdItem>(dexFile.ProtoIdsSection, new ShortIntegerField()),
|
new ShortIntegerField(null), "class_idx"),
|
||||||
methodName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField())
|
prototypeReferenceField = new IndexedItemReference<ProtoIdItem>(dexFile.ProtoIdsSection,
|
||||||
|
new ShortIntegerField(null), "proto_idx"),
|
||||||
|
methodNameReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
|
new IntegerField(null), "name_idx")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem methodName, ProtoIdItem prototype) {
|
public MethodIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem methodName, ProtoIdItem prototype) {
|
||||||
super(-1);
|
this(dexFile, -1);
|
||||||
fields = new Field[] {
|
classTypeReferenceField.setReference(classType);
|
||||||
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new ShortIntegerField()),
|
prototypeReferenceField.setReference(prototype);
|
||||||
this.prototype = new IndexedItemReference<ProtoIdItem>(dexFile, prototype, new ShortIntegerField()),
|
methodNameReferenceField.setReference(methodName);
|
||||||
this.methodName = new IndexedItemReference<StringIdItem>(dexFile, methodName, new IntegerField())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodIdItem(DexFile dexFile, TypeIdItem classType, String methodName, ProtoIdItem prototype) {
|
|
||||||
this(dexFile, classType, new StringIdItem(dexFile, methodName), prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected int getAlignment() {
|
protected int getAlignment() {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_METHOD_ID_ITEM;
|
return ItemType.TYPE_METHOD_ID_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeIdItem getClassType() {
|
public String getConciseIdentity() {
|
||||||
return classType.getReference();
|
return "method_id_item: " + getMethodString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cachedMethodString = null;
|
||||||
|
public String getMethodString() {
|
||||||
|
if (cachedMethodString == null) {
|
||||||
|
String parentClass = classTypeReferenceField.getReference().getTypeDescriptor();
|
||||||
|
//strip the leading L and trailing ;
|
||||||
|
parentClass = parentClass.substring(1, parentClass.length() - 1);
|
||||||
|
|
||||||
|
cachedMethodString = parentClass + methodNameReferenceField.getReference().getStringValue() +
|
||||||
|
prototypeReferenceField.getReference().getPrototypeString();
|
||||||
|
}
|
||||||
|
return cachedMethodString;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMethodName() {
|
public String getMethodName() {
|
||||||
return methodName.getReference().toString();
|
return methodNameReferenceField.getReference().getStringValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClassType(TypeIdItem newClassType) {
|
public int getParameterRegisterCount(boolean isStatic) {
|
||||||
classType.setReference(newClassType);
|
return prototypeReferenceField.getReference().getParameterRegisterCount() + (isStatic?0:1);
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return classType.getReference().toString() + " - " + methodName.getReference().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getParameterWordCount(boolean isStatic) {
|
|
||||||
return prototype.getReference().getParameterWordCount() + (isStatic?0:1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,20 +90,20 @@ public class MethodIdItem extends IndexedItem<MethodIdItem> {
|
|||||||
* @return The number of parameters, not including the "this" parameter, if any
|
* @return The number of parameters, not including the "this" parameter, if any
|
||||||
*/
|
*/
|
||||||
public int getParameterCount() {
|
public int getParameterCount() {
|
||||||
return prototype.getReference().getParameterCount();
|
return prototypeReferenceField.getReference().getParameterCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(MethodIdItem o) {
|
public int compareTo(MethodIdItem o) {
|
||||||
int result = classType.compareTo(o.classType);
|
int result = classTypeReferenceField.compareTo(o.classTypeReferenceField);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = methodName.compareTo(o.methodName);
|
result = methodNameReferenceField.compareTo(o.methodNameReferenceField);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return prototype.compareTo(o.prototype);
|
return prototypeReferenceField.compareTo(o.prototypeReferenceField);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,26 +28,31 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.ByteArray;
|
import org.JesusFreke.dexlib.util.ByteArray;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class NullTerminatedByteArrayField implements Field<NullTerminatedByteArrayField> {
|
public class NullTerminatedByteArrayField implements Field<NullTerminatedByteArrayField> {
|
||||||
protected byte[] value;
|
protected byte[] value;
|
||||||
|
private final String fieldName;
|
||||||
|
|
||||||
public NullTerminatedByteArrayField() {
|
public NullTerminatedByteArrayField(String fieldName) {
|
||||||
|
this.fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NullTerminatedByteArrayField(byte[] value) {
|
public NullTerminatedByteArrayField(byte[] value, String fieldName) {
|
||||||
|
this(fieldName);
|
||||||
this.value = value.clone();
|
this.value = value.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public NullTerminatedByteArrayField(ByteArray byteArray) {
|
public NullTerminatedByteArrayField(ByteArray byteArray, String fieldName) {
|
||||||
|
this(fieldName);
|
||||||
value = new byte[byteArray.size()];
|
value = new byte[byteArray.size()];
|
||||||
byteArray.getBytes(value, 0);
|
byteArray.getBytes(value, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
out.annotate(fieldName);
|
||||||
out.write(value);
|
out.write(value);
|
||||||
out.writeByte(0);
|
out.writeByte(0);
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,7 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
public abstract class OffsettedItem<T extends OffsettedItem<T>> extends Item<T> {
|
public abstract class OffsettedItem<T extends OffsettedItem<T>> extends Item<T> {
|
||||||
|
|
||||||
public OffsettedItem(int offset) {
|
public OffsettedItem(int offset) {
|
||||||
super(offset);
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,56 +28,41 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public class OffsettedItemReference<T extends OffsettedItem<T>> extends
|
public class OffsettedItemReference<T extends OffsettedItem<T>> extends
|
||||||
ItemReference<T,OffsettedItemReference<T>> {
|
ItemReference<T,OffsettedItemReference<T>> {
|
||||||
private final CachedIntegerValueField underlyingField;
|
|
||||||
|
public OffsettedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField,
|
||||||
public OffsettedItemReference(OffsettedSection<T> section, CachedIntegerValueField underlyingField) {
|
String fieldName) {
|
||||||
super(section);
|
super(dexFile, item, underlyingField, fieldName);
|
||||||
this.underlyingField = underlyingField;
|
}
|
||||||
|
|
||||||
|
public OffsettedItemReference(OffsettedSection<T> section, CachedIntegerValueField underlyingField,
|
||||||
|
String fieldName) {
|
||||||
|
super(section, underlyingField, fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OffsettedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField) {
|
|
||||||
super(dexFile, item);
|
|
||||||
this.underlyingField = underlyingField;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OffsettedSection<T> getSection() {
|
public OffsettedSection<T> getSection() {
|
||||||
return (OffsettedSection<T>)super.getSection();
|
return (OffsettedSection<T>)super.getSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
protected int getReferenceValue() {
|
||||||
T item = getReference();
|
T item = getReference();
|
||||||
if (item != null && !item.isPlaced()) {
|
|
||||||
throw new RuntimeException("Trying to write reference to an item that hasn't been placed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: this is a hack to force it to reload the correct offset value
|
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
underlyingField.cacheValue(0);
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
underlyingField.cacheValue(item.getOffset());
|
return item.getOffset();
|
||||||
}
|
|
||||||
|
|
||||||
underlyingField.writeTo(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
|
||||||
underlyingField.readFrom(in);
|
|
||||||
if (underlyingField.getCachedValue() != 0) {
|
|
||||||
setReference(getSection().getByOffset(underlyingField.getCachedValue()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int place(int offset) {
|
protected T getReferencedItem(int referenceValue) {
|
||||||
if (getReference() != null) {
|
if (referenceValue == 0) {
|
||||||
underlyingField.cacheValue(getReference().getOffset());
|
return null;
|
||||||
} else {
|
|
||||||
underlyingField.cacheValue(0);
|
|
||||||
}
|
}
|
||||||
return underlyingField.place(offset);
|
return getSection().getByOffset(referenceValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,40 +33,41 @@ import org.JesusFreke.dexlib.ItemType;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
||||||
private final Field[] fields;
|
private final IndexedItemReference<StringIdItem> shortyDescriptorReferenceField;
|
||||||
|
private final IndexedItemReference<TypeIdItem> returnTypeReferenceField;
|
||||||
private final IndexedItemReference<StringIdItem> shortyDescriptor;
|
private final OffsettedItemReference<TypeListItem> parametersReferenceField;
|
||||||
private final IndexedItemReference<TypeIdItem> returnType;
|
|
||||||
private final OffsettedItemReference<TypeListItem> parameters;
|
|
||||||
|
|
||||||
public ProtoIdItem(DexFile dexFile, int index) {
|
public ProtoIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
shortyDescriptor = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()),
|
shortyDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
returnType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()),
|
new IntegerField(null), "shorty_idx"),
|
||||||
parameters = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection, new IntegerField())
|
returnTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
|
new IntegerField(null), "return_type_idx"),
|
||||||
|
parametersReferenceField = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection,
|
||||||
|
new IntegerField(null), "parameters_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtoIdItem(DexFile dexFile, TypeIdItem returnType, ArrayList<TypeIdItem> parameters)
|
public ProtoIdItem(DexFile dexFile, TypeIdItem returnType, ArrayList<TypeIdItem> parameters)
|
||||||
{
|
{
|
||||||
super(-1);
|
this(dexFile, -1);
|
||||||
StringIdItem stringIdItem = new StringIdItem(dexFile, createShortyDescriptor(returnType, parameters));
|
shortyDescriptorReferenceField.setReference(
|
||||||
TypeListItem typeListItem = new TypeListItem(dexFile, parameters);
|
new StringIdItem(dexFile, createShortyDescriptor(returnType, parameters)));
|
||||||
|
returnTypeReferenceField.setReference(returnType);
|
||||||
fields = new Field[] {
|
if (parameters != null && parameters.size() > 0) {
|
||||||
this.shortyDescriptor = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField()),
|
parametersReferenceField.setReference(new TypeListItem(dexFile, parameters));
|
||||||
this.returnType = new IndexedItemReference<TypeIdItem>(dexFile, returnType, new IntegerField()),
|
}
|
||||||
this.parameters = new OffsettedItemReference<TypeListItem>(dexFile, typeListItem, new IntegerField())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createShortyDescriptor(TypeIdItem returnType, ArrayList<TypeIdItem> parameters) {
|
private String createShortyDescriptor(TypeIdItem returnType, ArrayList<TypeIdItem> parameters) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(returnType.toShorty());
|
sb.append(returnType.toShorty());
|
||||||
|
|
||||||
for (TypeIdItem typeIdItem: parameters) {
|
if (parameters != null) {
|
||||||
sb.append(typeIdItem.toShorty());
|
for (TypeIdItem typeIdItem: parameters) {
|
||||||
|
sb.append(typeIdItem.toShorty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
@ -75,18 +76,17 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getParameterWordCount() {
|
public int getParameterRegisterCount() {
|
||||||
TypeListItem typeList = parameters.getReference();
|
TypeListItem typeList = parametersReferenceField.getReference();
|
||||||
if (typeList == null) {
|
if (typeList == null) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return typeList.getWordCount();
|
return typeList.getRegisterCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getParameterCount() {
|
public int getParameterCount() {
|
||||||
TypeListItem typeList = parameters.getReference();
|
TypeListItem typeList = parametersReferenceField.getReference();
|
||||||
if (typeList == null) {
|
if (typeList == null) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@ -94,29 +94,44 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_PROTO_ID_ITEM;
|
return ItemType.TYPE_PROTO_ID_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(ProtoIdItem o) {
|
public int compareTo(ProtoIdItem o) {
|
||||||
int result = returnType.compareTo(o.returnType);
|
int result = returnTypeReferenceField.compareTo(o.returnTypeReferenceField);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeListItem thisParameters = parameters.getReference();
|
TypeListItem thisParameters = parametersReferenceField.getReference();
|
||||||
if (thisParameters == null) {
|
if (thisParameters == null) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return thisParameters.compareTo(o.parameters.getReference());
|
return thisParameters.compareTo(o.parametersReferenceField.getReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String getConciseIdentity() {
|
||||||
return shortyDescriptor.toString();
|
return "proto_id_item: " + getPrototypeString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cachedPrototypeString = null;
|
||||||
|
public String getPrototypeString() {
|
||||||
|
if (cachedPrototypeString == null) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
TypeListItem parameterList = this.parametersReferenceField.getReference();
|
||||||
|
|
||||||
|
if (parameterList != null) {
|
||||||
|
for (TypeIdItem type: parameterList.getTypes()) {
|
||||||
|
sb.append(type.getTypeDescriptor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedPrototypeString = "(" + sb.toString() + ")" +
|
||||||
|
this.returnTypeReferenceField.getReference().getTypeDescriptor();
|
||||||
|
}
|
||||||
|
return cachedPrototypeString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ package org.JesusFreke.dexlib;
|
|||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -56,14 +57,14 @@ public abstract class Section<T extends Item> {
|
|||||||
for (int i=0; i < items.size(); i++) {
|
for (int i=0; i < items.size(); i++) {
|
||||||
T item = items.get(i);
|
T item = items.get(i);
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
items.remove(i--);
|
throw new RuntimeException("This section contains a null item");
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
offset = item.place(i, offset);
|
offset = item.place(i, offset);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
/** if this item type has an alignment requirement,
|
/**
|
||||||
|
* if this item type has an alignment requirement,
|
||||||
* then item.getOffset() may be different than the
|
* then item.getOffset() may be different than the
|
||||||
* offset before item.place was called, so we have
|
* offset that was passed in to this method, so we have
|
||||||
* to initialize the section offset to the actual
|
* to initialize the section offset to the actual
|
||||||
* (post-alignment) offset of the first item
|
* (post-alignment) offset of the first item
|
||||||
*/
|
*/
|
||||||
@ -80,21 +81,24 @@ public abstract class Section<T extends Item> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
for (int i = 0; i < size(); i++) {
|
for (int i = 0; i < size(); i++) {
|
||||||
T item = items.get(i);
|
T item = items.get(i);
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
throw new RuntimeException("Cannot write section because all items haven't been initialized");
|
throw new RuntimeException("Cannot write section because all items haven't been initialized");
|
||||||
}
|
}
|
||||||
item.writeTo(out);
|
item.writeTo(out);
|
||||||
|
out.annotate(0, " ");
|
||||||
}
|
}
|
||||||
|
out.annotate(0, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void readFrom(int size, Input in);
|
public abstract void readFrom(int size, Input in);
|
||||||
|
|
||||||
protected void setSize(int size) {
|
protected void setSize(int size) {
|
||||||
if (items.size() > size) {
|
if (items.size() > size) {
|
||||||
throw new RuntimeException("This section contains references to items beyond the size of the section");
|
throw new RuntimeException("There are references elsewhere to items in this section, that are " +
|
||||||
|
"beyond the end of the section");
|
||||||
}
|
}
|
||||||
|
|
||||||
items.ensureCapacity(size);
|
items.ensureCapacity(size);
|
||||||
|
@ -28,56 +28,44 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public abstract class SectionHeaderInfo implements Field<SectionHeaderInfo> {
|
public abstract class SectionHeaderInfo extends CompositeField<SectionHeaderInfo> {
|
||||||
private int sectionSize;
|
private final String sectionName;
|
||||||
private int sectionOffset;
|
|
||||||
|
|
||||||
public SectionHeaderInfo() {
|
private final IntegerField sectionSizeField;
|
||||||
|
private final IntegerField sectionOffsetField;
|
||||||
|
|
||||||
|
|
||||||
|
public SectionHeaderInfo(String sectionName) {
|
||||||
|
super(sectionName);
|
||||||
|
fields = new Field[] {
|
||||||
|
sectionSizeField = new IntegerField(sectionName + "_size"),
|
||||||
|
sectionOffsetField = new IntegerField(sectionName + "_off")
|
||||||
|
};
|
||||||
|
this.sectionName = sectionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Section getSection();
|
protected abstract Section getSection();
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
Section section = getSection();
|
Section section = getSection();
|
||||||
|
|
||||||
if (!section.isPlaced()) {
|
if (!section.isPlaced()) {
|
||||||
throw new RuntimeException("Trying to write a reference to a section that hasn't been placed.");
|
throw new RuntimeException("Trying to write a reference to a section that hasn't been placed.");
|
||||||
}
|
}
|
||||||
sectionSize = section.size();
|
sectionSizeField.cacheValue(section.size());
|
||||||
sectionOffset = section.getOffset();
|
sectionOffsetField.cacheValue(section.getOffset());
|
||||||
|
|
||||||
out.writeInt(sectionSize);
|
super.writeTo(out);
|
||||||
out.writeInt(sectionOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
|
||||||
sectionSize = in.readInt();
|
|
||||||
sectionOffset = in.readInt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSectionSize() {
|
public int getSectionSize() {
|
||||||
return sectionSize;
|
return sectionSizeField.getCachedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSectionOffset() {
|
public int getSectionOffset() {
|
||||||
return sectionOffset;
|
return sectionOffsetField.getCachedValue();
|
||||||
}
|
|
||||||
|
|
||||||
public int place(int offset) {
|
|
||||||
Section section = getSection();
|
|
||||||
sectionSize = section.size();
|
|
||||||
sectionOffset = section.getOffset();
|
|
||||||
|
|
||||||
return offset+8;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyTo(DexFile dexFile, SectionHeaderInfo copy) {
|
|
||||||
/**
|
|
||||||
* do nothing. the section size and offset are dynamically generated
|
|
||||||
* when the copy is written
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,16 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
|
|
||||||
public class ShortIntegerField extends CachedIntegerValueField {
|
public class ShortIntegerField extends CachedIntegerValueField {
|
||||||
protected int value = 0;
|
public ShortIntegerField(String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
public ShortIntegerField() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShortIntegerField(int value) {
|
public ShortIntegerField(int value, String fieldName) {
|
||||||
this.value = value;
|
super(value, fieldName);
|
||||||
}
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
|
||||||
out.writeShort(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
@ -53,18 +48,7 @@ public class ShortIntegerField extends CachedIntegerValueField {
|
|||||||
return offset + 2;
|
return offset + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected void writeValue(Output out) {
|
||||||
* This method returns the short integer value that has been cached. This
|
out.writeShort(value);
|
||||||
* value is either the value that the field was constructed with, the
|
|
||||||
* value that was read via <code>readFrom</code>, or the value that was
|
|
||||||
* cached when <code>place</code> was called
|
|
||||||
* @return the cached value
|
|
||||||
*/
|
|
||||||
public int getCachedValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cacheValue(int value) {
|
|
||||||
this.value = (short)value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,22 +28,17 @@
|
|||||||
|
|
||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.Leb128Utils;
|
import org.JesusFreke.dexlib.util.Leb128Utils;
|
||||||
|
import org.JesusFreke.dexlib.util.Output;
|
||||||
|
|
||||||
public class SignedLeb128Field extends CachedIntegerValueField {
|
public class SignedLeb128Field extends CachedIntegerValueField {
|
||||||
protected int value;
|
public SignedLeb128Field(String fieldName) {
|
||||||
|
super(fieldName);
|
||||||
public SignedLeb128Field() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignedLeb128Field(int value) {
|
public SignedLeb128Field(int value, String fieldName) {
|
||||||
this.value = value;
|
super(value, fieldName);
|
||||||
}
|
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
|
||||||
out.writeSignedLeb128(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Input in) {
|
public void readFrom(Input in) {
|
||||||
@ -54,11 +49,7 @@ public class SignedLeb128Field extends CachedIntegerValueField {
|
|||||||
return offset + Leb128Utils.signedLeb128Size(value);
|
return offset + Leb128Utils.signedLeb128Size(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCachedValue() {
|
public void writeValue(Output out) {
|
||||||
return value;
|
out.writeSignedLeb128(value);
|
||||||
}
|
|
||||||
|
|
||||||
public void cacheValue(int value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,6 @@ import org.JesusFreke.dexlib.util.ByteArray;
|
|||||||
import org.JesusFreke.dexlib.util.Utf8Utils;
|
import org.JesusFreke.dexlib.util.Utf8Utils;
|
||||||
|
|
||||||
public class StringDataItem extends OffsettedItem<StringDataItem> implements Comparable<StringDataItem> {
|
public class StringDataItem extends OffsettedItem<StringDataItem> implements Comparable<StringDataItem> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private String value = null;
|
private String value = null;
|
||||||
|
|
||||||
private final Leb128Field stringSize;
|
private final Leb128Field stringSize;
|
||||||
@ -43,8 +41,8 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
|
|||||||
super(offset);
|
super(offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
stringSize = new Leb128Field(),
|
stringSize = new Leb128Field("string_length"),
|
||||||
stringByteArray = new NullTerminatedByteArrayField()
|
stringByteArray = new NullTerminatedByteArrayField("data")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,32 +52,28 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
stringSize = new Leb128Field(value.length()),
|
stringSize = new Leb128Field(value.length(), "string_length"),
|
||||||
stringByteArray = new NullTerminatedByteArrayField(Utf8Utils.stringToUtf8Bytes(value))
|
stringByteArray = new NullTerminatedByteArrayField(Utf8Utils.stringToUtf8Bytes(value), "data")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAlignment() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_STRING_DATA_ITEM;
|
return ItemType.TYPE_STRING_DATA_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String getStringValue() {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value = Utf8Utils.utf8BytesToString(new ByteArray(((NullTerminatedByteArrayField)fields[1]).value));
|
value = Utf8Utils.utf8BytesToString(new ByteArray(((NullTerminatedByteArrayField)fields[1]).value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "string_data_item: " + getStringValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(StringDataItem o) {
|
public int compareTo(StringDataItem o) {
|
||||||
return toString().compareTo(o.toString());
|
return getStringValue().compareTo(o.getStringValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,23 +29,19 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
public class StringIdItem extends IndexedItem<StringIdItem> {
|
public class StringIdItem extends IndexedItem<StringIdItem> {
|
||||||
private final Field[] fields;
|
private final OffsettedItemReference<StringDataItem> stringDataReferenceField;
|
||||||
|
|
||||||
private final OffsettedItemReference<StringDataItem> stringData;
|
|
||||||
|
|
||||||
public StringIdItem(DexFile dexFile, int index) {
|
public StringIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
stringData = new OffsettedItemReference<StringDataItem>(dexFile.StringDataSection, new IntegerField())
|
stringDataReferenceField = new OffsettedItemReference<StringDataItem>(dexFile.StringDataSection,
|
||||||
|
new IntegerField(null), "string_data_off")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringIdItem(DexFile dexFile, StringDataItem stringDataItem) {
|
public StringIdItem(DexFile dexFile, StringDataItem stringDataItem) {
|
||||||
super(-1);
|
this(dexFile, -1);
|
||||||
|
stringDataReferenceField.setReference(stringDataItem);
|
||||||
fields = new Field[] {
|
|
||||||
stringData = new OffsettedItemReference<StringDataItem>(dexFile, stringDataItem, new IntegerField())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringIdItem(DexFile dexFile, String value) {
|
public StringIdItem(DexFile dexFile, String value) {
|
||||||
@ -56,20 +52,20 @@ public class StringIdItem extends IndexedItem<StringIdItem> {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType getItemType() {
|
public ItemType getItemType() {
|
||||||
return ItemType.TYPE_STRING_ID_ITEM;
|
return ItemType.TYPE_STRING_ID_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String getConciseIdentity() {
|
||||||
return stringData.getReference().toString();
|
return "string_id_item: " + getStringValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStringValue() {
|
||||||
|
return stringDataReferenceField.getReference().getStringValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(StringIdItem o) {
|
public int compareTo(StringIdItem o) {
|
||||||
//sort by the string value
|
//sort by the string value
|
||||||
return toString().compareTo(o.toString());
|
return getStringValue().compareTo(o.getStringValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,43 +29,35 @@
|
|||||||
package org.JesusFreke.dexlib;
|
package org.JesusFreke.dexlib;
|
||||||
|
|
||||||
public class TypeIdItem extends IndexedItem<TypeIdItem> {
|
public class TypeIdItem extends IndexedItem<TypeIdItem> {
|
||||||
private final Field[] fields;
|
private final IndexedItemReference<StringIdItem> typeDescriptorReferenceField;
|
||||||
|
|
||||||
private final IndexedItemReference<StringIdItem> type;
|
|
||||||
|
|
||||||
public TypeIdItem(DexFile dexFile, int index) {
|
public TypeIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
type = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField())
|
typeDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
|
new IntegerField(null), "descriptor_idx")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeIdItem(DexFile dexFile, StringIdItem stringIdItem) {
|
public TypeIdItem(DexFile dexFile, StringIdItem stringIdItem) {
|
||||||
super(-1);
|
this(dexFile, -1);
|
||||||
fields = new Field[] {
|
typeDescriptorReferenceField.setReference(stringIdItem);
|
||||||
type = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeIdItem(DexFile dexFile, String value) {
|
public TypeIdItem(DexFile dexFile, String value) {
|
||||||
super(-1);
|
this(dexFile, new StringIdItem(dexFile, value));
|
||||||
StringDataItem stringDataItem = new StringDataItem(value);
|
|
||||||
StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem);
|
|
||||||
fields = new Field[] {
|
|
||||||
type = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getAlignment() {
|
protected int getAlignment() {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
/**
|
||||||
return fields;
|
* Returns the number of 2-byte registers that an instance of this type requires
|
||||||
}
|
* @return The number of 2-byte registers that an instance of this type requires
|
||||||
|
*/
|
||||||
public int getWordCount() {
|
public int getRegisterCount() {
|
||||||
String type = this.toString();
|
String type = this.getTypeDescriptor();
|
||||||
/** Only the long and double primitive types are 2 words,
|
/** Only the long and double primitive types are 2 words,
|
||||||
* everything else is a single word
|
* everything else is a single word
|
||||||
*/
|
*/
|
||||||
@ -80,17 +72,21 @@ public class TypeIdItem extends IndexedItem<TypeIdItem> {
|
|||||||
return ItemType.TYPE_TYPE_ID_ITEM;
|
return ItemType.TYPE_TYPE_ID_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String getConciseIdentity() {
|
||||||
return type.getReference().toString();
|
return "type_id_item: " + getTypeDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeDescriptor() {
|
||||||
|
return typeDescriptorReferenceField.getReference().getStringValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(TypeIdItem o) {
|
public int compareTo(TypeIdItem o) {
|
||||||
//sort by the index of the StringIdItem
|
//sort by the index of the StringIdItem
|
||||||
return type.compareTo(o.type);
|
return typeDescriptorReferenceField.compareTo(o.typeDescriptorReferenceField);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toShorty() {
|
public String toShorty() {
|
||||||
String type = toString();
|
String type = getTypeDescriptor();
|
||||||
if (type.length() > 1) {
|
if (type.length() > 1) {
|
||||||
return "L";
|
return "L";
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,17 +32,20 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TypeListItem extends OffsettedItem<TypeListItem> implements Comparable<TypeListItem> {
|
public class TypeListItem extends OffsettedItem<TypeListItem> implements Comparable<TypeListItem> {
|
||||||
private final Field[] fields;
|
|
||||||
private final ArrayList<IndexedItemReference<TypeIdItem>> typeList = new ArrayList<IndexedItemReference<TypeIdItem>>();
|
private final ArrayList<IndexedItemReference<TypeIdItem>> typeList = new ArrayList<IndexedItemReference<TypeIdItem>>();
|
||||||
|
|
||||||
|
private final ListSizeField sizeField;
|
||||||
|
private final FieldListField<IndexedItemReference<TypeIdItem>> listField;
|
||||||
|
|
||||||
public TypeListItem(final DexFile dexFile, int offset) {
|
public TypeListItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ListSizeField(typeList, new IntegerField()),
|
sizeField = new ListSizeField(typeList, new IntegerField("size")),
|
||||||
new FieldListField<IndexedItemReference<TypeIdItem>>(typeList) {
|
listField = new FieldListField<IndexedItemReference<TypeIdItem>>(typeList, "type_item") {
|
||||||
protected IndexedItemReference<TypeIdItem> make() {
|
protected IndexedItemReference<TypeIdItem> make() {
|
||||||
return new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField());
|
return new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
|
new ShortIntegerField(null), "type_idx");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -52,7 +55,9 @@ public class TypeListItem extends OffsettedItem<TypeListItem> implements Compara
|
|||||||
this(dexFile, 0);
|
this(dexFile, 0);
|
||||||
|
|
||||||
for (TypeIdItem typeIdItem: types) {
|
for (TypeIdItem typeIdItem: types) {
|
||||||
typeList.add(new IndexedItemReference<TypeIdItem>(dexFile, typeIdItem, new ShortIntegerField()));
|
IndexedItemReference<TypeIdItem> typeReference = listField.make();
|
||||||
|
typeReference.setReference(typeIdItem);
|
||||||
|
typeList.add(typeReference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,15 +71,11 @@ public class TypeListItem extends OffsettedItem<TypeListItem> implements Compara
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Field[] getFields() {
|
public int getRegisterCount() {
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWordCount() {
|
|
||||||
int wordCount = 0;
|
int wordCount = 0;
|
||||||
for (IndexedItemReference<TypeIdItem> typeRef: typeList) {
|
for (IndexedItemReference<TypeIdItem> typeRef: typeList) {
|
||||||
TypeIdItem item = typeRef.getReference();
|
TypeIdItem item = typeRef.getReference();
|
||||||
wordCount += item.getWordCount();
|
wordCount += item.getRegisterCount();
|
||||||
}
|
}
|
||||||
return wordCount;
|
return wordCount;
|
||||||
}
|
}
|
||||||
@ -91,6 +92,23 @@ public class TypeListItem extends OffsettedItem<TypeListItem> implements Compara
|
|||||||
return ItemType.TYPE_TYPE_LIST;
|
return ItemType.TYPE_TYPE_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConciseIdentity() {
|
||||||
|
return "type_list: " + getTypeListString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cachedTypeListString = null;
|
||||||
|
public String getTypeListString() {
|
||||||
|
if (cachedTypeListString == null) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
for (IndexedItemReference<TypeIdItem> typeReference: typeList) {
|
||||||
|
sb.append(typeReference.getReference().getTypeDescriptor());
|
||||||
|
}
|
||||||
|
cachedTypeListString = sb.toString();
|
||||||
|
}
|
||||||
|
return cachedTypeListString;
|
||||||
|
}
|
||||||
|
|
||||||
public int compareTo(TypeListItem o) {
|
public int compareTo(TypeListItem o) {
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -53,7 +53,7 @@ public class Format21c extends Format
|
|||||||
throw new RuntimeException("The register number must be less than v256");
|
throw new RuntimeException("The register number must be less than v256");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode == Opcode.NEW_INSTANCE.value && ((TypeIdItem)item).toString().charAt(0) != 'L') {
|
if (opcode == Opcode.NEW_INSTANCE.value && ((TypeIdItem)item).getTypeDescriptor().charAt(0) != 'L') {
|
||||||
throw new RuntimeException("Only class references can be used with the new-instance opcode");
|
throw new RuntimeException("Only class references can be used with the new-instance opcode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ public class Format35c extends Format
|
|||||||
|
|
||||||
if (opcode == FILLED_NEW_ARRAY.value) {
|
if (opcode == FILLED_NEW_ARRAY.value) {
|
||||||
//check data for filled-new-array opcode
|
//check data for filled-new-array opcode
|
||||||
String type = ((TypeIdItem)item).toString();
|
String type = ((TypeIdItem)item).getTypeDescriptor();
|
||||||
if (type.charAt(0) != '[') {
|
if (type.charAt(0) != '[') {
|
||||||
throw new RuntimeException("The type must be an array type");
|
throw new RuntimeException("The type must be an array type");
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ public class Format35c extends Format
|
|||||||
} else if (opcode >= INVOKE_VIRTUAL.value && opcode <= INVOKE_INTERFACE.value) {
|
} else if (opcode >= INVOKE_VIRTUAL.value && opcode <= INVOKE_INTERFACE.value) {
|
||||||
//check data for invoke-* opcodes
|
//check data for invoke-* opcodes
|
||||||
MethodIdItem methodIdItem = (MethodIdItem)item;
|
MethodIdItem methodIdItem = (MethodIdItem)item;
|
||||||
if (methodIdItem.getParameterWordCount(opcode == INVOKE_STATIC.value) != regCount) {
|
if (methodIdItem.getParameterRegisterCount(opcode == INVOKE_STATIC.value) != regCount) {
|
||||||
throw new RuntimeException("regCount does not match the number of arguments of the method");
|
throw new RuntimeException("regCount does not match the number of arguments of the method");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,7 +72,7 @@ public class Format3rc extends Format
|
|||||||
|
|
||||||
if (opcode == FILLED_NEW_ARRAY_RANGE.value) {
|
if (opcode == FILLED_NEW_ARRAY_RANGE.value) {
|
||||||
//check data for filled-new-array/range opcode
|
//check data for filled-new-array/range opcode
|
||||||
String type = ((TypeIdItem)item).toString();
|
String type = ((TypeIdItem)item).getTypeDescriptor();
|
||||||
if (type.charAt(0) != '[') {
|
if (type.charAt(0) != '[') {
|
||||||
throw new RuntimeException("The type must be an array type");
|
throw new RuntimeException("The type must be an array type");
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ public class Format3rc extends Format
|
|||||||
} else if (opcode >= INVOKE_VIRTUAL_RANGE.value && opcode <= INVOKE_INTERFACE_RANGE.value) {
|
} else if (opcode >= INVOKE_VIRTUAL_RANGE.value && opcode <= INVOKE_INTERFACE_RANGE.value) {
|
||||||
//check data for invoke-*/range opcodes
|
//check data for invoke-*/range opcodes
|
||||||
MethodIdItem methodIdItem = (MethodIdItem)item;
|
MethodIdItem methodIdItem = (MethodIdItem)item;
|
||||||
if (methodIdItem.getParameterWordCount(opcode == INVOKE_STATIC.value) != regCount) {
|
if (methodIdItem.getParameterRegisterCount(opcode == INVOKE_STATIC.value) != regCount) {
|
||||||
throw new RuntimeException("regCount does not match the number of arguments of the method");
|
throw new RuntimeException("regCount does not match the number of arguments of the method");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -30,7 +30,7 @@ package org.JesusFreke.dexlib.code;
|
|||||||
|
|
||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
import org.JesusFreke.dexlib.util.Input;
|
import org.JesusFreke.dexlib.util.Input;
|
||||||
import org.JesusFreke.dexlib.util.Output;
|
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||||
|
|
||||||
public final class Instruction implements Field<Instruction> {
|
public final class Instruction implements Field<Instruction> {
|
||||||
private DexFile dexFile;
|
private DexFile dexFile;
|
||||||
@ -143,7 +143,8 @@ public final class Instruction implements Field<Instruction> {
|
|||||||
bytes = in.readBytes(opcode.numBytes);
|
bytes = in.readBytes(opcode.numBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Output out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
|
out.annotate(bytes.length, "instruction");
|
||||||
if (bytes[0] == 0 && bytes[1] > 0) {
|
if (bytes[0] == 0 && bytes[1] > 0) {
|
||||||
//the "special instructions" must be 4 byte aligned
|
//the "special instructions" must be 4 byte aligned
|
||||||
out.alignTo(4);
|
out.alignTo(4);
|
||||||
|
@ -34,15 +34,14 @@ import org.JesusFreke.dexlib.ByteField;
|
|||||||
import org.JesusFreke.dexlib.SignedLeb128Field;
|
import org.JesusFreke.dexlib.SignedLeb128Field;
|
||||||
|
|
||||||
public class AdvanceLine extends CompositeField<AdvanceLine> implements DebugInstruction<AdvanceLine> {
|
public class AdvanceLine extends CompositeField<AdvanceLine> implements DebugInstruction<AdvanceLine> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ByteField opcodeField;
|
private final ByteField opcodeField;
|
||||||
private final SignedLeb128Field lineDeltaField;
|
private final SignedLeb128Field lineDeltaField;
|
||||||
|
|
||||||
public AdvanceLine() {
|
public AdvanceLine() {
|
||||||
|
super("DBG_ADVANCE_LINE");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcodeField = new ByteField((byte)0x02),
|
opcodeField = new ByteField((byte)0x02, "opcode"),
|
||||||
lineDeltaField = new SignedLeb128Field()
|
lineDeltaField = new SignedLeb128Field("line_diff")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +50,6 @@ public class AdvanceLine extends CompositeField<AdvanceLine> implements DebugIns
|
|||||||
lineDeltaField.cacheValue(lineDelta);
|
lineDeltaField.cacheValue(lineDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x02;
|
return 0x02;
|
||||||
}
|
}
|
||||||
|
@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
|
|||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
|
|
||||||
public class AdvancePC extends CompositeField<AdvancePC> implements DebugInstruction<AdvancePC> {
|
public class AdvancePC extends CompositeField<AdvancePC> implements DebugInstruction<AdvancePC> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ByteField opcodeField;
|
private final ByteField opcodeField;
|
||||||
private final Leb128Field addressDeltaField;
|
private final Leb128Field addressDeltaField;
|
||||||
|
|
||||||
public AdvancePC() {
|
public AdvancePC() {
|
||||||
|
super("DBG_ADVANCE_PC");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcodeField = new ByteField((byte)0x01),
|
opcodeField = new ByteField((byte)0x01, "opcode"),
|
||||||
addressDeltaField = new Leb128Field()
|
addressDeltaField = new Leb128Field("addr_diff")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +47,6 @@ public class AdvancePC extends CompositeField<AdvancePC> implements DebugInstruc
|
|||||||
addressDeltaField.cacheValue(addressDelta);
|
addressDeltaField.cacheValue(addressDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x01;
|
return 0x01;
|
||||||
}
|
}
|
||||||
|
@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
|
|||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
|
|
||||||
public class EndLocal extends CompositeField<EndLocal> implements DebugInstruction<EndLocal> {
|
public class EndLocal extends CompositeField<EndLocal> implements DebugInstruction<EndLocal> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ByteField opcode;
|
private final ByteField opcode;
|
||||||
private final Leb128Field registerNumber;
|
private final Leb128Field registerNumber;
|
||||||
|
|
||||||
public EndLocal() {
|
public EndLocal() {
|
||||||
|
super("DBG_END_LOCAL");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcode = new ByteField((byte)0x05),
|
opcode = new ByteField((byte)0x05, "opcode"),
|
||||||
registerNumber = new Leb128Field()
|
registerNumber = new Leb128Field("register_num")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +47,6 @@ public class EndLocal extends CompositeField<EndLocal> implements DebugInstructi
|
|||||||
this.registerNumber.cacheValue(registerNumber);
|
this.registerNumber.cacheValue(registerNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x05;
|
return 0x05;
|
||||||
}
|
}
|
||||||
|
@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
|
|||||||
import org.JesusFreke.dexlib.ByteField;
|
import org.JesusFreke.dexlib.ByteField;
|
||||||
|
|
||||||
public class EndSequence extends CompositeField<EndSequence> implements DebugInstruction<EndSequence> {
|
public class EndSequence extends CompositeField<EndSequence> implements DebugInstruction<EndSequence> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
public EndSequence() {
|
public EndSequence() {
|
||||||
|
super("DBG_END_SEQUENCE");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ByteField((byte)0x00)
|
new ByteField((byte)0x00, "opcode")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
|
|||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
|
|
||||||
public class RestartLocal extends CompositeField<RestartLocal> implements DebugInstruction<RestartLocal> {
|
public class RestartLocal extends CompositeField<RestartLocal> implements DebugInstruction<RestartLocal> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ByteField opcode;
|
private final ByteField opcode;
|
||||||
private final Leb128Field registerNumber;
|
private final Leb128Field registerNumber;
|
||||||
|
|
||||||
public RestartLocal() {
|
public RestartLocal() {
|
||||||
|
super("DBG_RESTART_LOCAL");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcode = new ByteField((byte)0x06),
|
opcode = new ByteField((byte)0x06, "opcode"),
|
||||||
registerNumber = new Leb128Field()
|
registerNumber = new Leb128Field("register_num")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +47,6 @@ public class RestartLocal extends CompositeField<RestartLocal> implements DebugI
|
|||||||
this.registerNumber.cacheValue(registerNumber);
|
this.registerNumber.cacheValue(registerNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x06;
|
return 0x06;
|
||||||
}
|
}
|
||||||
|
@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
|
|||||||
import org.JesusFreke.dexlib.ByteField;
|
import org.JesusFreke.dexlib.ByteField;
|
||||||
|
|
||||||
public class SetEpilogueBegin extends CompositeField<SetEpilogueBegin> implements DebugInstruction<SetEpilogueBegin> {
|
public class SetEpilogueBegin extends CompositeField<SetEpilogueBegin> implements DebugInstruction<SetEpilogueBegin> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
public SetEpilogueBegin() {
|
public SetEpilogueBegin() {
|
||||||
|
super("DBG_SET_EPILOGUE_BEGIN");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ByteField((byte)0x08)
|
new ByteField((byte)0x08, "opcode")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x08;
|
return 0x08;
|
||||||
}
|
}
|
||||||
|
@ -31,15 +31,15 @@ package org.JesusFreke.dexlib.debug;
|
|||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
|
|
||||||
public class SetFile extends CompositeField<SetFile> implements DebugInstruction<SetFile> {
|
public class SetFile extends CompositeField<SetFile> implements DebugInstruction<SetFile> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ByteField opcode;
|
private final ByteField opcode;
|
||||||
private final IndexedItemReference<StringIdItem> fileName;
|
private final IndexedItemReference<StringIdItem> fileName;
|
||||||
|
|
||||||
public SetFile(DexFile dexFile) {
|
public SetFile(DexFile dexFile) {
|
||||||
|
super("DBG_SET_FILE");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcode = new ByteField((byte)0x09),
|
opcode = new ByteField((byte)0x09, "opcode"),
|
||||||
fileName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field())
|
fileName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
|
new Leb128p1Field(null), "name_idx")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +48,6 @@ public class SetFile extends CompositeField<SetFile> implements DebugInstruction
|
|||||||
this.fileName.setReference(fileName);
|
this.fileName.setReference(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x09;
|
return 0x09;
|
||||||
}
|
}
|
||||||
|
@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
|
|||||||
import org.JesusFreke.dexlib.ByteField;
|
import org.JesusFreke.dexlib.ByteField;
|
||||||
|
|
||||||
public class SetPrologueEnd extends CompositeField<SetPrologueEnd> implements DebugInstruction<SetPrologueEnd> {
|
public class SetPrologueEnd extends CompositeField<SetPrologueEnd> implements DebugInstruction<SetPrologueEnd> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
public SetPrologueEnd() {
|
public SetPrologueEnd() {
|
||||||
|
super("DBG_SET_PROLOGUE_END");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ByteField((byte)0x07)
|
new ByteField((byte)0x07, "opcode")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x07;
|
return 0x07;
|
||||||
}
|
}
|
||||||
|
@ -33,21 +33,17 @@ import org.JesusFreke.dexlib.Field;
|
|||||||
import org.JesusFreke.dexlib.ByteField;
|
import org.JesusFreke.dexlib.ByteField;
|
||||||
|
|
||||||
public class SpecialOpcode extends CompositeField<SpecialOpcode> implements DebugInstruction<SpecialOpcode> {
|
public class SpecialOpcode extends CompositeField<SpecialOpcode> implements DebugInstruction<SpecialOpcode> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final byte opcode;
|
private final byte opcode;
|
||||||
|
|
||||||
public SpecialOpcode(byte opcode) {
|
public SpecialOpcode(byte opcode) {
|
||||||
|
super("SPECIAL_OPCODE");
|
||||||
this.opcode = opcode;
|
this.opcode = opcode;
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ByteField(opcode)
|
//TODO: annotate the line and address delta
|
||||||
|
new ByteField(opcode, "opcode")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return opcode;
|
return opcode;
|
||||||
}
|
}
|
||||||
|
@ -31,19 +31,20 @@ package org.JesusFreke.dexlib.debug;
|
|||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
|
|
||||||
public class StartLocal extends CompositeField<StartLocal> implements DebugInstruction<StartLocal> {
|
public class StartLocal extends CompositeField<StartLocal> implements DebugInstruction<StartLocal> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ByteField opcodeField;
|
private final ByteField opcodeField;
|
||||||
private final SignedLeb128Field registerNumber;
|
private final SignedLeb128Field registerNumber;
|
||||||
private final IndexedItemReference<StringIdItem> localName;
|
private final IndexedItemReference<StringIdItem> localName;
|
||||||
private final IndexedItemReference<TypeIdItem> localType;
|
private final IndexedItemReference<TypeIdItem> localType;
|
||||||
|
|
||||||
public StartLocal(DexFile dexFile) {
|
public StartLocal(DexFile dexFile) {
|
||||||
|
super("DBG_START_LOCAL");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcodeField = new ByteField((byte)0x03),
|
opcodeField = new ByteField((byte)0x03, "opcode"),
|
||||||
registerNumber = new SignedLeb128Field(),
|
registerNumber = new SignedLeb128Field("register_num"),
|
||||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()),
|
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128p1Field()),
|
new Leb128p1Field(null), "name_idx"),
|
||||||
|
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
|
new Leb128p1Field(null), "type_idx"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,10 +55,6 @@ public class StartLocal extends CompositeField<StartLocal> implements DebugInstr
|
|||||||
this.localType.setReference(localType);
|
this.localType.setReference(localType);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x03;
|
return 0x03;
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,6 @@ package org.JesusFreke.dexlib.debug;
|
|||||||
import org.JesusFreke.dexlib.*;
|
import org.JesusFreke.dexlib.*;
|
||||||
|
|
||||||
public class StartLocalExtended extends CompositeField<StartLocalExtended> implements DebugInstruction<StartLocalExtended> {
|
public class StartLocalExtended extends CompositeField<StartLocalExtended> implements DebugInstruction<StartLocalExtended> {
|
||||||
private final Field[] fields;
|
|
||||||
|
|
||||||
private final ByteField opcodeField;
|
private final ByteField opcodeField;
|
||||||
//TODO: signed or unsigned leb?
|
//TODO: signed or unsigned leb?
|
||||||
private final SignedLeb128Field registerNumber;
|
private final SignedLeb128Field registerNumber;
|
||||||
@ -41,12 +39,16 @@ public class StartLocalExtended extends CompositeField<StartLocalExtended> imple
|
|||||||
private final IndexedItemReference<StringIdItem> signature;
|
private final IndexedItemReference<StringIdItem> signature;
|
||||||
|
|
||||||
public StartLocalExtended(DexFile dexFile) {
|
public StartLocalExtended(DexFile dexFile) {
|
||||||
|
super("DBG_START_LOCAL_EXTENDED");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcodeField = new ByteField((byte)0x04),
|
opcodeField = new ByteField((byte)0x04, "opcode"),
|
||||||
registerNumber = new SignedLeb128Field(),
|
registerNumber = new SignedLeb128Field("register_num"),
|
||||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()),
|
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128p1Field()),
|
new Leb128p1Field(null), "name_idx"),
|
||||||
signature = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field())
|
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
|
new Leb128p1Field(null), "type_idx"),
|
||||||
|
signature = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
|
new Leb128p1Field(null), "sig_idx")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,10 +61,6 @@ public class StartLocalExtended extends CompositeField<StartLocalExtended> imple
|
|||||||
this.signature.setReference(signature);
|
this.signature.setReference(signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Field[] getFields() {
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
return 0x04;
|
return 0x04;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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 org.JesusFreke.dexlib.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a binary output destination that may be augmented
|
||||||
|
* with textual annotations.
|
||||||
|
*/
|
||||||
|
public interface AnnotatedOutput
|
||||||
|
extends Output {
|
||||||
|
/**
|
||||||
|
* Get whether this instance will actually keep annotations.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> iff annotations are being kept
|
||||||
|
*/
|
||||||
|
public boolean annotates();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether this instance is intended to keep verbose annotations.
|
||||||
|
* Annotators may use the result of calling this method to inform their
|
||||||
|
* annotation activity.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> iff annotations are to be verbose
|
||||||
|
*/
|
||||||
|
public boolean isVerbose();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an annotation for the subsequent output. Any previously
|
||||||
|
* open annotation will be closed by this call, and the new
|
||||||
|
* annotation marks all subsequent output until another annotation
|
||||||
|
* call.
|
||||||
|
*
|
||||||
|
* @param msg non-null; the annotation message
|
||||||
|
*/
|
||||||
|
public void annotate(String msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an annotation for a specified amount of subsequent
|
||||||
|
* output. Any previously open annotation will be closed by this
|
||||||
|
* call. If there is already pending annotation from one or more
|
||||||
|
* previous calls to this method, the new call "consumes" output
|
||||||
|
* after all the output covered by the previous calls.
|
||||||
|
*
|
||||||
|
* @param amt >= 0; the amount of output for this annotation to
|
||||||
|
* cover
|
||||||
|
* @param msg non-null; the annotation message
|
||||||
|
*/
|
||||||
|
public void annotate(int amt, String msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End the most recent annotation. Subsequent output will be unannotated,
|
||||||
|
* until the next call to {@link #annotate}.
|
||||||
|
*/
|
||||||
|
public void endAnnotation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the maximum width of the annotated output. This is advisory:
|
||||||
|
* Implementations of this interface are encouraged to deal with too-wide
|
||||||
|
* output, but annotaters are encouraged to attempt to avoid exceeding
|
||||||
|
* the indicated width.
|
||||||
|
*
|
||||||
|
* @return >= 1; the maximum width
|
||||||
|
*/
|
||||||
|
public int getAnnotationWidth();
|
||||||
|
|
||||||
|
public void setIndentAmount(int indentAmount);
|
||||||
|
public void indent();
|
||||||
|
public void deindent();
|
||||||
|
}
|
@ -0,0 +1,669 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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 org.JesusFreke.dexlib.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of {@link AnnotatedOutput} which stores the written data
|
||||||
|
* into a <code>byte[]</code>.
|
||||||
|
*
|
||||||
|
* <p><b>Note:</b> As per the {@link Output} interface, multi-byte
|
||||||
|
* writes all use little-endian order.</p>
|
||||||
|
*/
|
||||||
|
public final class ByteArrayAnnotatedOutput
|
||||||
|
implements AnnotatedOutput {
|
||||||
|
/** default size for stretchy instances */
|
||||||
|
private static final int DEFAULT_SIZE = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether the instance is stretchy, that is, whether its array
|
||||||
|
* may be resized to increase capacity
|
||||||
|
*/
|
||||||
|
private final boolean stretchy;
|
||||||
|
|
||||||
|
/** non-null; the data itself */
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
/** >= 0; current output cursor */
|
||||||
|
private int cursor;
|
||||||
|
|
||||||
|
/** whether annotations are to be verbose */
|
||||||
|
private boolean verbose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* null-ok; list of annotations, or <code>null</code> if this instance
|
||||||
|
* isn't keeping them
|
||||||
|
*/
|
||||||
|
private ArrayList<Annotation> annotations;
|
||||||
|
|
||||||
|
/** >= 40 (if used); the desired maximum annotation width */
|
||||||
|
private int annotationWidth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* >= 8 (if used); the number of bytes of hex output to use
|
||||||
|
* in annotations
|
||||||
|
*/
|
||||||
|
private int hexCols;
|
||||||
|
|
||||||
|
private int currentIndent = 0;
|
||||||
|
private int indentAmount = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance with a fixed maximum size. Note that the
|
||||||
|
* given array is the only one that will be used to store data. In
|
||||||
|
* particular, no reallocation will occur in order to expand the
|
||||||
|
* capacity of the resulting instance. Also, the constructed
|
||||||
|
* instance does not keep annotations by default.
|
||||||
|
*
|
||||||
|
* @param data non-null; data array to use for output
|
||||||
|
*/
|
||||||
|
public ByteArrayAnnotatedOutput(byte[] data) {
|
||||||
|
this(data, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a "stretchy" instance. The underlying array may be
|
||||||
|
* reallocated. The constructed instance does not keep annotations
|
||||||
|
* by default.
|
||||||
|
*/
|
||||||
|
public ByteArrayAnnotatedOutput() {
|
||||||
|
this(new byte[DEFAULT_SIZE], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal constructor.
|
||||||
|
*
|
||||||
|
* @param data non-null; data array to use for output
|
||||||
|
* @param stretchy whether the instance is to be stretchy
|
||||||
|
*/
|
||||||
|
private ByteArrayAnnotatedOutput(byte[] data, boolean stretchy) {
|
||||||
|
if (data == null) {
|
||||||
|
throw new NullPointerException("data == null");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stretchy = stretchy;
|
||||||
|
this.data = data;
|
||||||
|
this.cursor = 0;
|
||||||
|
this.verbose = false;
|
||||||
|
this.annotations = null;
|
||||||
|
this.annotationWidth = 0;
|
||||||
|
this.hexCols = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the underlying <code>byte[]</code> of this instance, which
|
||||||
|
* may be larger than the number of bytes written
|
||||||
|
*
|
||||||
|
* @see #toByteArray
|
||||||
|
*
|
||||||
|
* @return non-null; the <code>byte[]</code>
|
||||||
|
*/
|
||||||
|
public byte[] getArray() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs and returns a new <code>byte[]</code> that contains
|
||||||
|
* the written contents exactly (that is, with no extra unwritten
|
||||||
|
* bytes at the end).
|
||||||
|
*
|
||||||
|
* @see #getArray
|
||||||
|
*
|
||||||
|
* @return non-null; an appropriately-constructed array
|
||||||
|
*/
|
||||||
|
public byte[] toByteArray() {
|
||||||
|
byte[] result = new byte[cursor];
|
||||||
|
System.arraycopy(data, 0, result, 0, cursor);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public int getCursor() {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void assertCursor(int expectedCursor) {
|
||||||
|
if (cursor != expectedCursor) {
|
||||||
|
throw new ExceptionWithContext("expected cursor " +
|
||||||
|
expectedCursor + "; actual value: " + cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void writeByte(int value) {
|
||||||
|
int writeAt = cursor;
|
||||||
|
int end = writeAt + 1;
|
||||||
|
|
||||||
|
if (stretchy) {
|
||||||
|
ensureCapacity(end);
|
||||||
|
} else if (end > data.length) {
|
||||||
|
throwBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[writeAt] = (byte) value;
|
||||||
|
cursor = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void writeShort(int value) {
|
||||||
|
int writeAt = cursor;
|
||||||
|
int end = writeAt + 2;
|
||||||
|
|
||||||
|
if (stretchy) {
|
||||||
|
ensureCapacity(end);
|
||||||
|
} else if (end > data.length) {
|
||||||
|
throwBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[writeAt] = (byte) value;
|
||||||
|
data[writeAt + 1] = (byte) (value >> 8);
|
||||||
|
cursor = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void writeInt(int value) {
|
||||||
|
int writeAt = cursor;
|
||||||
|
int end = writeAt + 4;
|
||||||
|
|
||||||
|
if (stretchy) {
|
||||||
|
ensureCapacity(end);
|
||||||
|
} else if (end > data.length) {
|
||||||
|
throwBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[writeAt] = (byte) value;
|
||||||
|
data[writeAt + 1] = (byte) (value >> 8);
|
||||||
|
data[writeAt + 2] = (byte) (value >> 16);
|
||||||
|
data[writeAt + 3] = (byte) (value >> 24);
|
||||||
|
cursor = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void writeLong(long value) {
|
||||||
|
int writeAt = cursor;
|
||||||
|
int end = writeAt + 8;
|
||||||
|
|
||||||
|
if (stretchy) {
|
||||||
|
ensureCapacity(end);
|
||||||
|
} else if (end > data.length) {
|
||||||
|
throwBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int half = (int) value;
|
||||||
|
data[writeAt] = (byte) half;
|
||||||
|
data[writeAt + 1] = (byte) (half >> 8);
|
||||||
|
data[writeAt + 2] = (byte) (half >> 16);
|
||||||
|
data[writeAt + 3] = (byte) (half >> 24);
|
||||||
|
|
||||||
|
half = (int) (value >> 32);
|
||||||
|
data[writeAt + 4] = (byte) half;
|
||||||
|
data[writeAt + 5] = (byte) (half >> 8);
|
||||||
|
data[writeAt + 6] = (byte) (half >> 16);
|
||||||
|
data[writeAt + 7] = (byte) (half >> 24);
|
||||||
|
|
||||||
|
cursor = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public int writeUnsignedLeb128(int value) {
|
||||||
|
int remaining = value >> 7;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while (remaining != 0) {
|
||||||
|
writeByte((value & 0x7f) | 0x80);
|
||||||
|
value = remaining;
|
||||||
|
remaining >>= 7;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeByte(value & 0x7f);
|
||||||
|
return count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public int writeSignedLeb128(int value) {
|
||||||
|
int remaining = value >> 7;
|
||||||
|
int count = 0;
|
||||||
|
boolean hasMore = true;
|
||||||
|
int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
|
||||||
|
|
||||||
|
while (hasMore) {
|
||||||
|
hasMore = (remaining != end)
|
||||||
|
|| ((remaining & 1) != ((value >> 6) & 1));
|
||||||
|
|
||||||
|
writeByte((value & 0x7f) | (hasMore ? 0x80 : 0));
|
||||||
|
value = remaining;
|
||||||
|
remaining >>= 7;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void write(ByteArray bytes) {
|
||||||
|
int blen = bytes.size();
|
||||||
|
int writeAt = cursor;
|
||||||
|
int end = writeAt + blen;
|
||||||
|
|
||||||
|
if (stretchy) {
|
||||||
|
ensureCapacity(end);
|
||||||
|
} else if (end > data.length) {
|
||||||
|
throwBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes.getBytes(data, writeAt);
|
||||||
|
cursor = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void write(byte[] bytes, int offset, int length) {
|
||||||
|
int writeAt = cursor;
|
||||||
|
int end = writeAt + length;
|
||||||
|
int bytesEnd = offset + length;
|
||||||
|
|
||||||
|
// twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
|
||||||
|
if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
|
||||||
|
throw new IndexOutOfBoundsException("bytes.length " +
|
||||||
|
bytes.length + "; " +
|
||||||
|
offset + "..!" + end);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stretchy) {
|
||||||
|
ensureCapacity(end);
|
||||||
|
} else if (end > data.length) {
|
||||||
|
throwBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.arraycopy(bytes, offset, data, writeAt, length);
|
||||||
|
cursor = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void write(byte[] bytes) {
|
||||||
|
write(bytes, 0, bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void writeZeroes(int count) {
|
||||||
|
if (count < 0) {
|
||||||
|
throw new IllegalArgumentException("count < 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = cursor + count;
|
||||||
|
|
||||||
|
if (stretchy) {
|
||||||
|
ensureCapacity(end);
|
||||||
|
} else if (end > data.length) {
|
||||||
|
throwBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is no need to actually write zeroes, since the array is
|
||||||
|
* already preinitialized with zeroes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
cursor = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void alignTo(int alignment) {
|
||||||
|
int mask = alignment - 1;
|
||||||
|
|
||||||
|
if ((alignment < 0) || ((mask & alignment) != 0)) {
|
||||||
|
throw new IllegalArgumentException("bogus alignment");
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = (cursor + mask) & ~mask;
|
||||||
|
|
||||||
|
if (stretchy) {
|
||||||
|
ensureCapacity(end);
|
||||||
|
} else if (end > data.length) {
|
||||||
|
throwBounds();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is no need to actually write zeroes, since the array is
|
||||||
|
* already preinitialized with zeroes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
cursor = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public boolean annotates() {
|
||||||
|
return (annotations != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public boolean isVerbose() {
|
||||||
|
return verbose;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void annotate(String msg) {
|
||||||
|
if (annotations == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
endAnnotation();
|
||||||
|
annotations.add(new Annotation(cursor, msg, currentIndent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void indent() {
|
||||||
|
currentIndent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deindent() {
|
||||||
|
currentIndent--;
|
||||||
|
if (currentIndent < 0) {
|
||||||
|
currentIndent = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndentAmount(int indentAmount) {
|
||||||
|
this.indentAmount = indentAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void annotate(int amt, String msg) {
|
||||||
|
if (annotations == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
endAnnotation();
|
||||||
|
|
||||||
|
int asz = annotations.size();
|
||||||
|
int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd();
|
||||||
|
int startAt;
|
||||||
|
|
||||||
|
if (lastEnd <= cursor) {
|
||||||
|
startAt = cursor;
|
||||||
|
} else {
|
||||||
|
startAt = lastEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
annotations.add(new Annotation(startAt, startAt + amt, msg, currentIndent));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void endAnnotation() {
|
||||||
|
if (annotations == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sz = annotations.size();
|
||||||
|
|
||||||
|
if (sz != 0) {
|
||||||
|
annotations.get(sz - 1).setEndIfUnset(cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public int getAnnotationWidth() {
|
||||||
|
int leftWidth = 8 + (hexCols * 2) + (hexCols / 2);
|
||||||
|
|
||||||
|
return annotationWidth - leftWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that this instance should keep annotations. This method may
|
||||||
|
* be called only once per instance, and only before any data has been
|
||||||
|
* written to the it.
|
||||||
|
*
|
||||||
|
* @param annotationWidth >= 40; the desired maximum annotation width
|
||||||
|
* @param verbose whether or not to indicate verbose annotations
|
||||||
|
*/
|
||||||
|
public void enableAnnotations(int annotationWidth, boolean verbose) {
|
||||||
|
if ((annotations != null) || (cursor != 0)) {
|
||||||
|
throw new RuntimeException("cannot enable annotations");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (annotationWidth < 40) {
|
||||||
|
throw new IllegalArgumentException("annotationWidth < 40");
|
||||||
|
}
|
||||||
|
|
||||||
|
int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1;
|
||||||
|
if (hexCols < 6) {
|
||||||
|
hexCols = 6;
|
||||||
|
} else if (hexCols > 10) {
|
||||||
|
hexCols = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.annotations = new ArrayList<Annotation>(1000);
|
||||||
|
this.annotationWidth = annotationWidth;
|
||||||
|
this.hexCols = hexCols;
|
||||||
|
this.verbose = verbose;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes up annotation processing. This closes off any open
|
||||||
|
* annotations and removes annotations that don't refer to written
|
||||||
|
* data.
|
||||||
|
*/
|
||||||
|
public void finishAnnotating() {
|
||||||
|
// Close off the final annotation, if any.
|
||||||
|
endAnnotation();
|
||||||
|
|
||||||
|
// Remove annotations that refer to unwritten data.
|
||||||
|
if (annotations != null) {
|
||||||
|
int asz = annotations.size();
|
||||||
|
while (asz > 0) {
|
||||||
|
Annotation last = annotations.get(asz - 1);
|
||||||
|
if (last.getStart() > cursor) {
|
||||||
|
annotations.remove(asz - 1);
|
||||||
|
asz--;
|
||||||
|
} else if (last.getEnd() > cursor) {
|
||||||
|
last.setEnd(cursor);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the annotated content of this instance to the given writer.
|
||||||
|
*
|
||||||
|
* @param out non-null; where to write to
|
||||||
|
*/
|
||||||
|
public void writeAnnotationsTo(Writer out) throws IOException {
|
||||||
|
int width2 = getAnnotationWidth();
|
||||||
|
int width1 = annotationWidth - width2 - 1;
|
||||||
|
|
||||||
|
StringBuilder padding = new StringBuilder();
|
||||||
|
for (int i=0; i<1000; i++) {
|
||||||
|
padding.append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
TwoColumnOutput twoc = new TwoColumnOutput(out, width1, width2, "|");
|
||||||
|
Writer left = twoc.getLeft();
|
||||||
|
Writer right = twoc.getRight();
|
||||||
|
int leftAt = 0; // left-hand byte output cursor
|
||||||
|
int rightAt = 0; // right-hand annotation index
|
||||||
|
int rightSz = annotations.size();
|
||||||
|
|
||||||
|
while ((leftAt < cursor) && (rightAt < rightSz)) {
|
||||||
|
Annotation a = annotations.get(rightAt);
|
||||||
|
int start = a.getStart();
|
||||||
|
int end;
|
||||||
|
String text;
|
||||||
|
|
||||||
|
if (leftAt < start) {
|
||||||
|
// This is an area with no annotation.
|
||||||
|
end = start;
|
||||||
|
start = leftAt;
|
||||||
|
text = "";
|
||||||
|
} else {
|
||||||
|
// This is an area with an annotation.
|
||||||
|
end = a.getEnd();
|
||||||
|
text = padding.substring(0, a.getIndent() * this.indentAmount) + a.getText();
|
||||||
|
rightAt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
left.write(Hex.dump(data, start, end - start, start, hexCols, 6));
|
||||||
|
right.write(text);
|
||||||
|
twoc.flush();
|
||||||
|
leftAt = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftAt < cursor) {
|
||||||
|
// There is unannotated output at the end.
|
||||||
|
left.write(Hex.dump(data, leftAt, cursor - leftAt, leftAt,
|
||||||
|
hexCols, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (rightAt < rightSz) {
|
||||||
|
// There are zero-byte annotations at the end.
|
||||||
|
right.write(annotations.get(rightAt).getText());
|
||||||
|
rightAt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
twoc.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws the excpetion for when an attempt is made to write past the
|
||||||
|
* end of the instance.
|
||||||
|
*/
|
||||||
|
private static void throwBounds() {
|
||||||
|
throw new IndexOutOfBoundsException("attempt to write past the end");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reallocates the underlying array if necessary. Calls to this method
|
||||||
|
* should be guarded by a test of {@link #stretchy}.
|
||||||
|
*
|
||||||
|
* @param desiredSize >= 0; the desired minimum total size of the array
|
||||||
|
*/
|
||||||
|
private void ensureCapacity(int desiredSize) {
|
||||||
|
if (data.length < desiredSize) {
|
||||||
|
byte[] newData = new byte[desiredSize * 2 + 1000];
|
||||||
|
System.arraycopy(data, 0, newData, 0, cursor);
|
||||||
|
data = newData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation on output.
|
||||||
|
*/
|
||||||
|
private static class Annotation {
|
||||||
|
/** >= 0; start of annotated range (inclusive) */
|
||||||
|
private final int start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* >= 0; end of annotated range (exclusive);
|
||||||
|
* <code>Integer.MAX_VALUE</code> if unclosed
|
||||||
|
*/
|
||||||
|
private int end;
|
||||||
|
|
||||||
|
/** non-null; annotation text */
|
||||||
|
private final String text;
|
||||||
|
|
||||||
|
private int indent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance.
|
||||||
|
*
|
||||||
|
* @param start >= 0; start of annotated range
|
||||||
|
* @param end >= start; end of annotated range (exclusive) or
|
||||||
|
* <code>Integer.MAX_VALUE</code> if unclosed
|
||||||
|
* @param text non-null; annotation text
|
||||||
|
*/
|
||||||
|
public Annotation(int start, int end, String text, int indent) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.text = text;
|
||||||
|
this.indent = indent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance. It is initally unclosed.
|
||||||
|
*
|
||||||
|
* @param start >= 0; start of annotated range
|
||||||
|
* @param text non-null; annotation text
|
||||||
|
*/
|
||||||
|
public Annotation(int start, String text, int indent) {
|
||||||
|
this(start, Integer.MAX_VALUE, text, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the end as given, but only if the instance is unclosed;
|
||||||
|
* otherwise, do nothing.
|
||||||
|
*
|
||||||
|
* @param end >= start; the end
|
||||||
|
*/
|
||||||
|
public void setEndIfUnset(int end) {
|
||||||
|
if (this.end == Integer.MAX_VALUE) {
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the end as given.
|
||||||
|
*
|
||||||
|
* @param end >= start; the end
|
||||||
|
*/
|
||||||
|
public void setEnd(int end) {
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the start.
|
||||||
|
*
|
||||||
|
* @return the start
|
||||||
|
*/
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the end.
|
||||||
|
*
|
||||||
|
* @return the end
|
||||||
|
*/
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the text.
|
||||||
|
*
|
||||||
|
* @return non-null; the text
|
||||||
|
*/
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndent() {
|
||||||
|
return indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
169
src/main/java/org/JesusFreke/dexlib/util/IndentingWriter.java
Normal file
169
src/main/java/org/JesusFreke/dexlib/util/IndentingWriter.java
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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 org.JesusFreke.dexlib.util;
|
||||||
|
|
||||||
|
import java.io.FilterWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writer that wraps another writer and passes width-limited and
|
||||||
|
* optionally-prefixed output to its subordinate. When lines are
|
||||||
|
* wrapped they are automatically indented based on the start of the
|
||||||
|
* line.
|
||||||
|
*/
|
||||||
|
public final class IndentingWriter extends FilterWriter {
|
||||||
|
/** null-ok; optional prefix for every line */
|
||||||
|
private final String prefix;
|
||||||
|
|
||||||
|
/** > 0; the maximum output width */
|
||||||
|
private final int width;
|
||||||
|
|
||||||
|
/** > 0; the maximum indent */
|
||||||
|
private final int maxIndent;
|
||||||
|
|
||||||
|
/** >= 0; current output column (zero-based) */
|
||||||
|
private int column;
|
||||||
|
|
||||||
|
/** whether indent spaces are currently being collected */
|
||||||
|
private boolean collectingIndent;
|
||||||
|
|
||||||
|
/** >= 0; current indent amount */
|
||||||
|
private int indent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance.
|
||||||
|
*
|
||||||
|
* @param out non-null; writer to send final output to
|
||||||
|
* @param width >= 0; the maximum output width (not including
|
||||||
|
* <code>prefix</code>), or <code>0</code> for no maximum
|
||||||
|
* @param prefix non-null; the prefix for each line
|
||||||
|
*/
|
||||||
|
public IndentingWriter(Writer out, int width, String prefix) {
|
||||||
|
super(out);
|
||||||
|
|
||||||
|
if (out == null) {
|
||||||
|
throw new NullPointerException("out == null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width < 0) {
|
||||||
|
throw new IllegalArgumentException("width < 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefix == null) {
|
||||||
|
throw new NullPointerException("prefix == null");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.width = (width != 0) ? width : Integer.MAX_VALUE;
|
||||||
|
this.maxIndent = width >> 1;
|
||||||
|
this.prefix = (prefix.length() == 0) ? null : prefix;
|
||||||
|
|
||||||
|
bol();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a no-prefix instance.
|
||||||
|
*
|
||||||
|
* @param out non-null; writer to send final output to
|
||||||
|
* @param width >= 0; the maximum output width (not including
|
||||||
|
* <code>prefix</code>), or <code>0</code> for no maximum
|
||||||
|
*/
|
||||||
|
public IndentingWriter(Writer out, int width) {
|
||||||
|
this(out, width, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void write(int c) throws IOException {
|
||||||
|
synchronized (lock) {
|
||||||
|
if (collectingIndent) {
|
||||||
|
if (c == ' ') {
|
||||||
|
indent++;
|
||||||
|
if (indent >= maxIndent) {
|
||||||
|
indent = maxIndent;
|
||||||
|
collectingIndent = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
collectingIndent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((column == width) && (c != '\n')) {
|
||||||
|
out.write('\n');
|
||||||
|
column = 0;
|
||||||
|
/*
|
||||||
|
* Note: No else, so this should fall through to the next
|
||||||
|
* if statement.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (column == 0) {
|
||||||
|
if (prefix != null) {
|
||||||
|
out.write(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!collectingIndent) {
|
||||||
|
for (int i = 0; i < indent; i++) {
|
||||||
|
out.write(' ');
|
||||||
|
}
|
||||||
|
column = indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write(c);
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
bol();
|
||||||
|
} else {
|
||||||
|
column++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||||
|
synchronized (lock) {
|
||||||
|
while (len > 0) {
|
||||||
|
write(cbuf[off]);
|
||||||
|
off++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void write(String str, int off, int len) throws IOException {
|
||||||
|
synchronized (lock) {
|
||||||
|
while (len > 0) {
|
||||||
|
write(str.charAt(off));
|
||||||
|
off++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that output is at the beginning of a line.
|
||||||
|
*/
|
||||||
|
private void bol() {
|
||||||
|
column = 0;
|
||||||
|
collectingIndent = (maxIndent != 0);
|
||||||
|
indent = 0;
|
||||||
|
}
|
||||||
|
}
|
254
src/main/java/org/JesusFreke/dexlib/util/TwoColumnOutput.java
Normal file
254
src/main/java/org/JesusFreke/dexlib/util/TwoColumnOutput.java
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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 org.JesusFreke.dexlib.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that takes a combined output destination and provides two
|
||||||
|
* output writers, one of which ends up writing to the left column and
|
||||||
|
* one which goes on the right.
|
||||||
|
*/
|
||||||
|
public final class TwoColumnOutput {
|
||||||
|
/** non-null; underlying writer for final output */
|
||||||
|
private final Writer out;
|
||||||
|
|
||||||
|
/** > 0; the left column width */
|
||||||
|
private final int leftWidth;
|
||||||
|
|
||||||
|
/** non-null; pending left column output */
|
||||||
|
private final StringBuffer leftBuf;
|
||||||
|
|
||||||
|
/** non-null; pending right column output */
|
||||||
|
private final StringBuffer rightBuf;
|
||||||
|
|
||||||
|
/** non-null; left column writer */
|
||||||
|
private final IndentingWriter leftColumn;
|
||||||
|
|
||||||
|
/** non-null; right column writer */
|
||||||
|
private final IndentingWriter rightColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns the given two strings (with widths) and spacer into a formatted
|
||||||
|
* two-column string.
|
||||||
|
*
|
||||||
|
* @param s1 non-null; first string
|
||||||
|
* @param width1 > 0; width of the first column
|
||||||
|
* @param spacer non-null; spacer string
|
||||||
|
* @param s2 non-null; second string
|
||||||
|
* @param width2 > 0; width of the second column
|
||||||
|
* @return non-null; an appropriately-formatted string
|
||||||
|
*/
|
||||||
|
public static String toString(String s1, int width1, String spacer,
|
||||||
|
String s2, int width2) {
|
||||||
|
int len1 = s1.length();
|
||||||
|
int len2 = s2.length();
|
||||||
|
|
||||||
|
StringWriter sw = new StringWriter((len1 + len2) * 3);
|
||||||
|
TwoColumnOutput twoOut =
|
||||||
|
new TwoColumnOutput(sw, width1, width2, spacer);
|
||||||
|
|
||||||
|
try {
|
||||||
|
twoOut.getLeft().write(s1);
|
||||||
|
twoOut.getRight().write(s2);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException("shouldn't happen", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
twoOut.flush();
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance.
|
||||||
|
*
|
||||||
|
* @param out non-null; writer to send final output to
|
||||||
|
* @param leftWidth > 0; width of the left column, in characters
|
||||||
|
* @param rightWidth > 0; width of the right column, in characters
|
||||||
|
* @param spacer non-null; spacer string to sit between the two columns
|
||||||
|
*/
|
||||||
|
public TwoColumnOutput(Writer out, int leftWidth, int rightWidth,
|
||||||
|
String spacer) {
|
||||||
|
if (out == null) {
|
||||||
|
throw new NullPointerException("out == null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftWidth < 1) {
|
||||||
|
throw new IllegalArgumentException("leftWidth < 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightWidth < 1) {
|
||||||
|
throw new IllegalArgumentException("rightWidth < 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spacer == null) {
|
||||||
|
throw new NullPointerException("spacer == null");
|
||||||
|
}
|
||||||
|
|
||||||
|
StringWriter leftWriter = new StringWriter(1000);
|
||||||
|
StringWriter rightWriter = new StringWriter(1000);
|
||||||
|
|
||||||
|
this.out = out;
|
||||||
|
this.leftWidth = leftWidth;
|
||||||
|
this.leftBuf = leftWriter.getBuffer();
|
||||||
|
this.rightBuf = rightWriter.getBuffer();
|
||||||
|
this.leftColumn = new IndentingWriter(leftWriter, leftWidth);
|
||||||
|
this.rightColumn =
|
||||||
|
new IndentingWriter(rightWriter, rightWidth, spacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance.
|
||||||
|
*
|
||||||
|
* @param out non-null; stream to send final output to
|
||||||
|
* @param leftWidth >= 1; width of the left column, in characters
|
||||||
|
* @param rightWidth >= 1; width of the right column, in characters
|
||||||
|
* @param spacer non-null; spacer string to sit between the two columns
|
||||||
|
*/
|
||||||
|
public TwoColumnOutput(OutputStream out, int leftWidth, int rightWidth,
|
||||||
|
String spacer) {
|
||||||
|
this(new OutputStreamWriter(out), leftWidth, rightWidth, spacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the writer to use to write to the left column.
|
||||||
|
*
|
||||||
|
* @return non-null; the left column writer
|
||||||
|
*/
|
||||||
|
public Writer getLeft() {
|
||||||
|
return leftColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the writer to use to write to the right column.
|
||||||
|
*
|
||||||
|
* @return non-null; the right column writer
|
||||||
|
*/
|
||||||
|
public Writer getRight() {
|
||||||
|
return rightColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes the output. If there are more lines of pending output in one
|
||||||
|
* column, then the other column will get filled with blank lines.
|
||||||
|
*/
|
||||||
|
public void flush() {
|
||||||
|
try {
|
||||||
|
appendNewlineIfNecessary(leftBuf, leftColumn);
|
||||||
|
appendNewlineIfNecessary(rightBuf, rightColumn);
|
||||||
|
outputFullLines();
|
||||||
|
flushLeft();
|
||||||
|
flushRight();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs to the final destination as many full line pairs as
|
||||||
|
* there are in the pending output, removing those lines from
|
||||||
|
* their respective buffers. This method terminates when at
|
||||||
|
* least one of the two column buffers is empty.
|
||||||
|
*/
|
||||||
|
private void outputFullLines() throws IOException {
|
||||||
|
for (;;) {
|
||||||
|
int leftLen = leftBuf.indexOf("\n");
|
||||||
|
if (leftLen < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rightLen = rightBuf.indexOf("\n");
|
||||||
|
if (rightLen < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftLen != 0) {
|
||||||
|
out.write(leftBuf.substring(0, leftLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightLen != 0) {
|
||||||
|
writeSpaces(out, leftWidth - leftLen);
|
||||||
|
out.write(rightBuf.substring(0, rightLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write('\n');
|
||||||
|
|
||||||
|
leftBuf.delete(0, leftLen + 1);
|
||||||
|
rightBuf.delete(0, rightLen + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes the left column buffer, printing it and clearing the buffer.
|
||||||
|
* If the buffer is already empty, this does nothing.
|
||||||
|
*/
|
||||||
|
private void flushLeft() throws IOException {
|
||||||
|
appendNewlineIfNecessary(leftBuf, leftColumn);
|
||||||
|
|
||||||
|
while (leftBuf.length() != 0) {
|
||||||
|
rightColumn.write('\n');
|
||||||
|
outputFullLines();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes the right column buffer, printing it and clearing the buffer.
|
||||||
|
* If the buffer is already empty, this does nothing.
|
||||||
|
*/
|
||||||
|
private void flushRight() throws IOException {
|
||||||
|
appendNewlineIfNecessary(rightBuf, rightColumn);
|
||||||
|
|
||||||
|
while (rightBuf.length() != 0) {
|
||||||
|
leftColumn.write('\n');
|
||||||
|
outputFullLines();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a newline to the given buffer via the given writer, but
|
||||||
|
* only if it isn't empty and doesn't already end with one.
|
||||||
|
*
|
||||||
|
* @param buf non-null; the buffer in question
|
||||||
|
* @param out non-null; the writer to use
|
||||||
|
*/
|
||||||
|
private static void appendNewlineIfNecessary(StringBuffer buf,
|
||||||
|
Writer out)
|
||||||
|
throws IOException {
|
||||||
|
int len = buf.length();
|
||||||
|
|
||||||
|
if ((len != 0) && (buf.charAt(len - 1) != '\n')) {
|
||||||
|
out.write('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the given number of spaces to the given writer.
|
||||||
|
*
|
||||||
|
* @param out non-null; where to write
|
||||||
|
* @param amt >= 0; the number of spaces to write
|
||||||
|
*/
|
||||||
|
private static void writeSpaces(Writer out, int amt) throws IOException {
|
||||||
|
while (amt > 0) {
|
||||||
|
out.write(' ');
|
||||||
|
amt--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,7 @@ package org.JesusFreke.smali;
|
|||||||
|
|
||||||
import org.JesusFreke.dexlib.DexFile;
|
import org.JesusFreke.dexlib.DexFile;
|
||||||
import org.JesusFreke.dexlib.util.ByteArrayOutput;
|
import org.JesusFreke.dexlib.util.ByteArrayOutput;
|
||||||
|
import org.JesusFreke.dexlib.util.ByteArrayAnnotatedOutput;
|
||||||
import org.antlr.runtime.ANTLRInputStream;
|
import org.antlr.runtime.ANTLRInputStream;
|
||||||
import org.antlr.runtime.CommonTokenStream;
|
import org.antlr.runtime.CommonTokenStream;
|
||||||
import org.antlr.runtime.Token;
|
import org.antlr.runtime.Token;
|
||||||
@ -38,6 +39,7 @@ import org.antlr.runtime.tree.CommonTreeNodeStream;
|
|||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
|
||||||
public class smali
|
public class smali
|
||||||
{
|
{
|
||||||
@ -70,7 +72,8 @@ public class smali
|
|||||||
dexFile.place();
|
dexFile.place();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ByteArrayOutput out = new ByteArrayOutput();
|
ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
|
||||||
|
out.enableAnnotations(120, true);
|
||||||
dexFile.writeTo(out);
|
dexFile.writeTo(out);
|
||||||
|
|
||||||
byte[] bytes = out.toByteArray();
|
byte[] bytes = out.toByteArray();
|
||||||
@ -78,6 +81,17 @@ public class smali
|
|||||||
DexFile.calcSignature(bytes);
|
DexFile.calcSignature(bytes);
|
||||||
DexFile.calcChecksum(bytes);
|
DexFile.calcChecksum(bytes);
|
||||||
|
|
||||||
|
|
||||||
|
out.finishAnnotating();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FileWriter fileWriter = new FileWriter("classes.dump");
|
||||||
|
|
||||||
|
out.writeAnnotationsTo(fileWriter);
|
||||||
|
fileWriter.flush();
|
||||||
|
fileWriter.close();
|
||||||
|
|
||||||
FileOutputStream fileOutputStream = new FileOutputStream("classes.dex");
|
FileOutputStream fileOutputStream = new FileOutputStream("classes.dex");
|
||||||
|
|
||||||
fileOutputStream.write(bytes);
|
fileOutputStream.write(bytes);
|
||||||
|
@ -70,7 +70,7 @@ public class TryListBuilderTest
|
|||||||
CodeItem.EncodedTypeAddrPair typeAddrPair = encodedCatchHandler.getHandler(i);
|
CodeItem.EncodedTypeAddrPair typeAddrPair = encodedCatchHandler.getHandler(i);
|
||||||
Handler handler = handlers[i];
|
Handler handler = handlers[i];
|
||||||
|
|
||||||
Assert.assertTrue(typeAddrPair.getType().toString().compareTo(handler.type) == 0);
|
Assert.assertTrue(typeAddrPair.getTypeReferenceField().toString().compareTo(handler.type) == 0);
|
||||||
Assert.assertTrue(typeAddrPair.getHandlerAddress() == handler.handlerAddress);
|
Assert.assertTrue(typeAddrPair.getHandlerAddress() == handler.handlerAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user