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
@ -364,7 +364,7 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
|
||||
ArrayList<Instruction> instructions = $statements.instructions;
|
||||
|
||||
|
||||
int minRegisters = methodIdItem.getParameterWordCount((access & AccessFlags.STATIC) != 0);
|
||||
int minRegisters = methodIdItem.getParameterRegisterCount((access & AccessFlags.STATIC) != 0);
|
||||
|
||||
if (registers < minRegisters) {
|
||||
//TODO: throw the correct exception type
|
||||
@ -390,7 +390,7 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
|
||||
|
||||
CodeItem codeItem = new CodeItem(dexFile,
|
||||
registers,
|
||||
methodIdItem.getParameterWordCount(isStatic),
|
||||
methodIdItem.getParameterRegisterCount(isStatic),
|
||||
instructions,
|
||||
debugInfoItem,
|
||||
tries,
|
||||
@ -552,9 +552,9 @@ local
|
||||
int registerNumber = parseRegister_short($REGISTER.text);
|
||||
|
||||
if ($string_literal.value != null) {
|
||||
$method::debugInfo.addLocalExtended($address.address, registerNumber, $SIMPLE_NAME.text, $field_type_descriptor.type.toString(), $string_literal.value);
|
||||
$method::debugInfo.addLocalExtended($address.address, registerNumber, $SIMPLE_NAME.text, $field_type_descriptor.type.getTypeDescriptor(), $string_literal.value);
|
||||
} else {
|
||||
$method::debugInfo.addLocal($address.address, registerNumber, $SIMPLE_NAME.text, $field_type_descriptor.type.toString());
|
||||
$method::debugInfo.addLocal($address.address, registerNumber, $SIMPLE_NAME.text, $field_type_descriptor.type.getTypeDescriptor());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -36,39 +36,43 @@ import java.util.Collections;
|
||||
|
||||
//TODO: fix field names in dex-format.html and submit
|
||||
public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ArrayList<FieldAnnotation> fieldAnnotationList = new ArrayList<FieldAnnotation>();
|
||||
private final ArrayList<MethodAnnotation> methodAnnotationList = new ArrayList<MethodAnnotation>();
|
||||
private final ArrayList<ParameterAnnotation> parameterAnnotationList = new ArrayList<ParameterAnnotation>();
|
||||
|
||||
private final OffsettedItemReference<AnnotationSetItem> classAnnotations;
|
||||
private final ListSizeField annotatedFieldsCount;
|
||||
private final ListSizeField annotatedMethodsCount;
|
||||
private final ListSizeField annotatedParametersCount;
|
||||
private final FieldListField<FieldAnnotation> fieldAnnotations;
|
||||
private final FieldListField<MethodAnnotation> methodAnnotations;
|
||||
private final FieldListField<ParameterAnnotation> parameterAnnotations;
|
||||
private final OffsettedItemReference<AnnotationSetItem> classAnnotationsReferenceField;
|
||||
private final ListSizeField annotatedFieldsCountField;
|
||||
private final ListSizeField annotatedMethodsCountField;
|
||||
private final ListSizeField annotatedParametersCountField;
|
||||
private final FieldListField<FieldAnnotation> fieldAnnotationListField;
|
||||
private final FieldListField<MethodAnnotation> methodAnnotationListField;
|
||||
private final FieldListField<ParameterAnnotation> parameterAnnotationListField;
|
||||
|
||||
public AnnotationDirectoryItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
|
||||
fields = new Field[] {
|
||||
classAnnotations = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField()),
|
||||
annotatedFieldsCount = new ListSizeField(fieldAnnotationList, new IntegerField()),
|
||||
annotatedMethodsCount = new ListSizeField(methodAnnotationList, new IntegerField()),
|
||||
annotatedParametersCount = new ListSizeField(parameterAnnotationList, new IntegerField()),
|
||||
fieldAnnotations = new FieldListField<FieldAnnotation>(fieldAnnotationList) {
|
||||
classAnnotationsReferenceField = new OffsettedItemReference<AnnotationSetItem>(
|
||||
dexFile.AnnotationSetsSection, new IntegerField(null), "class_annotations_off"),
|
||||
annotatedFieldsCountField = new ListSizeField(fieldAnnotationList, new IntegerField("fields_size")),
|
||||
annotatedMethodsCountField = new ListSizeField(methodAnnotationList,
|
||||
new IntegerField("annotated_methods_size")),
|
||||
annotatedParametersCountField = new ListSizeField(parameterAnnotationList,
|
||||
new IntegerField("annotated_parameters_size")),
|
||||
fieldAnnotationListField = new FieldListField<FieldAnnotation>(fieldAnnotationList,
|
||||
"field_annotations") {
|
||||
protected FieldAnnotation make() {
|
||||
return new FieldAnnotation(dexFile);
|
||||
}
|
||||
},
|
||||
methodAnnotations = new FieldListField<MethodAnnotation>(methodAnnotationList) {
|
||||
methodAnnotationListField = new FieldListField<MethodAnnotation>(methodAnnotationList,
|
||||
"method_annotations") {
|
||||
protected MethodAnnotation make() {
|
||||
return new MethodAnnotation(dexFile);
|
||||
}
|
||||
},
|
||||
parameterAnnotations = new FieldListField<ParameterAnnotation>(parameterAnnotationList) {
|
||||
parameterAnnotationListField = new FieldListField<ParameterAnnotation>(parameterAnnotationList,
|
||||
"parameter_annotations") {
|
||||
protected ParameterAnnotation make() {
|
||||
return new ParameterAnnotation(dexFile);
|
||||
}
|
||||
@ -76,8 +80,6 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
public AnnotationDirectoryItem(final DexFile dexFile,
|
||||
AnnotationSetItem classAnnotations,
|
||||
List<FieldAnnotation> fieldAnnotations,
|
||||
@ -85,22 +87,21 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
||||
List<ParameterAnnotation> parameterAnnotations) {
|
||||
this(dexFile, -1);
|
||||
|
||||
this.classAnnotations.setReference(classAnnotations);
|
||||
classAnnotationsReferenceField.setReference(classAnnotations);
|
||||
|
||||
if (fieldAnnotations != null) {
|
||||
this.fieldAnnotationList.addAll(fieldAnnotations);
|
||||
if (fieldAnnotationListField != null) {
|
||||
fieldAnnotationList.addAll(fieldAnnotations);
|
||||
}
|
||||
|
||||
if (methodAnnotations != null) {
|
||||
this.methodAnnotationList.addAll(methodAnnotations);
|
||||
if (methodAnnotationListField != null) {
|
||||
methodAnnotationList.addAll(methodAnnotations);
|
||||
}
|
||||
|
||||
if (parameterAnnotations != null) {
|
||||
this.parameterAnnotationList.addAll(parameterAnnotations);
|
||||
parameterAnnotationList.addAll(parameterAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int place(int index, int offset)
|
||||
{
|
||||
Collections.sort(fieldAnnotationList);
|
||||
@ -113,54 +114,53 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
|
||||
}
|
||||
|
||||
public String getConciseIdentity() {
|
||||
return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
public static class FieldAnnotation extends CompositeField<FieldAnnotation>
|
||||
implements Comparable<FieldAnnotation> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<FieldIdItem> field;
|
||||
private final OffsettedItemReference<AnnotationSetItem> annotationSet;
|
||||
private final IndexedItemReference<FieldIdItem> fieldReferenceField;
|
||||
private final OffsettedItemReference<AnnotationSetItem> annotationSetReferenceField;
|
||||
|
||||
public FieldAnnotation(DexFile dexFile) {
|
||||
super("field_annotation");
|
||||
fields = new Field[] {
|
||||
field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection, new IntegerField()),
|
||||
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
|
||||
fieldReferenceField = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection,
|
||||
new IntegerField(null), "field_idx"),
|
||||
annotationSetReferenceField = new OffsettedItemReference<AnnotationSetItem>(
|
||||
dexFile.AnnotationSetsSection, new IntegerField(null), "annotations_off")
|
||||
};
|
||||
}
|
||||
|
||||
public FieldAnnotation(DexFile dexFile, FieldIdItem field, AnnotationSetItem annotationSet) {
|
||||
this(dexFile);
|
||||
this.field.setReference(field);
|
||||
this.annotationSet.setReference(annotationSet);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
this.fieldReferenceField.setReference(field);
|
||||
this.annotationSetReferenceField.setReference(annotationSet);
|
||||
}
|
||||
|
||||
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>
|
||||
implements Comparable<MethodAnnotation> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<MethodIdItem> method;
|
||||
private final OffsettedItemReference<AnnotationSetItem> annotationSet;
|
||||
|
||||
public MethodAnnotation(DexFile dexFile) {
|
||||
super("method_annotation");
|
||||
fields = new Field[] {
|
||||
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()),
|
||||
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField())
|
||||
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
|
||||
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);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public int compareTo(MethodAnnotation o) {
|
||||
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>
|
||||
implements Comparable<ParameterAnnotation> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<MethodIdItem> method;
|
||||
private final OffsettedItemReference<AnnotationSetRefList> parameterAnnotations;
|
||||
|
||||
public ParameterAnnotation(DexFile dexFile) {
|
||||
super("parameter_annotation");
|
||||
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>(
|
||||
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);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public int compareTo(ParameterAnnotation o) {
|
||||
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;
|
||||
|
||||
public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField visibility;
|
||||
private final AnnotationEncodedValueSubField annotation;
|
||||
private final ByteField visibilityField;
|
||||
private final AnnotationEncodedValueSubField annotationField;
|
||||
|
||||
public AnnotationItem(DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
|
||||
fields = new Field[] {
|
||||
visibility = new ByteField(),
|
||||
annotation = new AnnotationEncodedValueSubField(dexFile)
|
||||
visibilityField = new ByteField("visibility"),
|
||||
annotationField = new AnnotationEncodedValueSubField(dexFile)
|
||||
};
|
||||
}
|
||||
|
||||
@ -51,41 +49,16 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
||||
super(-1);
|
||||
|
||||
fields = new Field[] {
|
||||
this.visibility = new ByteField(visibility.value),
|
||||
this.annotation = annotation
|
||||
this.visibilityField = new ByteField(visibility.value, "visibility"),
|
||||
this.annotationField = annotation
|
||||
};
|
||||
}
|
||||
|
||||
protected int getAlignment() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_ANNOTATION_ITEM;
|
||||
}
|
||||
|
||||
public void copyTo(DexFile dexFile, AnnotationItem copy) {
|
||||
visibility.copyTo(dexFile, copy.visibility);
|
||||
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);
|
||||
public String getConciseIdentity() {
|
||||
return "annotation_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
}
|
||||
|
@ -34,23 +34,22 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ArrayList<OffsettedItemReference<AnnotationItem>> annotationReferences =
|
||||
new ArrayList<OffsettedItemReference<AnnotationItem>>();
|
||||
|
||||
private final ListSizeField annotationCount;
|
||||
private final FieldListField<OffsettedItemReference<AnnotationItem>> annotations;
|
||||
private final ListSizeField annotationCountField;
|
||||
private final FieldListField<OffsettedItemReference<AnnotationItem>> annotationsListField;
|
||||
|
||||
public AnnotationSetItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
|
||||
fields = new Field[] {
|
||||
annotationCount = new ListSizeField(annotationReferences, new IntegerField()),
|
||||
annotations = new FieldListField<OffsettedItemReference<AnnotationItem>>(annotationReferences) {
|
||||
annotationCountField = new ListSizeField(annotationReferences, new IntegerField("size")),
|
||||
annotationsListField = new FieldListField<OffsettedItemReference<AnnotationItem>>(
|
||||
annotationReferences, "annotation") {
|
||||
protected OffsettedItemReference<AnnotationItem> make() {
|
||||
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);
|
||||
|
||||
for (AnnotationItem annotationItem: annotations) {
|
||||
this.annotationReferences.add(new OffsettedItemReference<AnnotationItem>(dexFile,
|
||||
annotationItem, new IntegerField()));
|
||||
OffsettedItemReference<AnnotationItem> annotationReference = annotationsListField.make();
|
||||
annotationReference.setReference(annotationItem);
|
||||
this.annotationReferences.add(annotationReference);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,11 +69,11 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
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;
|
||||
|
||||
public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ArrayList<OffsettedItemReference<AnnotationSetItem>> annotationSetReferences =
|
||||
new ArrayList<OffsettedItemReference<AnnotationSetItem>>();
|
||||
|
||||
private final ListSizeField annotationSetCount;
|
||||
private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSets;
|
||||
private final ListSizeField annotationSetCountField;
|
||||
private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSetsListField;
|
||||
|
||||
public AnnotationSetRefList(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
|
||||
fields = new Field[] {
|
||||
annotationSetCount = new ListSizeField(annotationSetReferences, new IntegerField()),
|
||||
annotationSets = new FieldListField<OffsettedItemReference<AnnotationSetItem>>(annotationSetReferences) {
|
||||
annotationSetCountField = new ListSizeField(annotationSetReferences, new IntegerField("size")),
|
||||
annotationSetsListField = new FieldListField<OffsettedItemReference<AnnotationSetItem>>(
|
||||
annotationSetReferences, "list") {
|
||||
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) {
|
||||
this(dexFile, -1);
|
||||
|
||||
for (AnnotationSetItem annotation: annotationSets) {
|
||||
this.annotationSetReferences.add(new OffsettedItemReference<AnnotationSetItem>(dexFile, annotation, new IntegerField()));
|
||||
for (AnnotationSetItem annotationSet: annotationSets) {
|
||||
OffsettedItemReference<AnnotationSetItem> annotationSetReference = annotationSetsListField.make();
|
||||
annotationSetReference.setReference(annotationSet);
|
||||
this.annotationSetReferences.add(annotationSetReference);
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,11 +69,11 @@ public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
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;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
|
||||
public class ByteField extends CachedIntegerValueField {
|
||||
protected byte value;
|
||||
|
||||
public ByteField() {
|
||||
public ByteField(String fieldName) {
|
||||
super(fieldName);
|
||||
}
|
||||
|
||||
public ByteField(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.writeByte(value);
|
||||
public ByteField(byte value, String fieldName) {
|
||||
super(value, fieldName);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
@ -53,11 +48,7 @@ public class ByteField extends CachedIntegerValueField {
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
public int getCachedValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void cacheValue(int value) {
|
||||
this.value = (byte)value;
|
||||
public void writeValue(Output out) {
|
||||
out.writeByte(value);
|
||||
}
|
||||
}
|
||||
|
@ -28,25 +28,64 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
public abstract class CachedIntegerValueField implements Field<CachedIntegerValueField> {
|
||||
public abstract int getCachedValue();
|
||||
public abstract void cacheValue(int value);
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
|
||||
public void copyTo(DexFile dexFile, CachedIntegerValueField copy) {
|
||||
copy.cacheValue(getCachedValue());
|
||||
public abstract class CachedIntegerValueField<T extends CachedIntegerValueField>
|
||||
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() {
|
||||
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) {
|
||||
if (getClass() != o.getClass()) {
|
||||
//TODO: check if this returns false if o is a different subclass
|
||||
if (!this.getClass().isInstance(o)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CachedIntegerValueField other = (CachedIntegerValueField)o;
|
||||
T other = (T)o;
|
||||
|
||||
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;
|
||||
|
||||
import org.JesusFreke.dexlib.ItemType;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AccessFlags;
|
||||
import org.JesusFreke.dexlib.util.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ArrayList<EncodedField> staticFieldList = new ArrayList<EncodedField>();
|
||||
private final ArrayList<EncodedField> instanceFieldList = new ArrayList<EncodedField>();
|
||||
private final ArrayList<EncodedMethod> directMethodList = new ArrayList<EncodedMethod>();
|
||||
private final ArrayList<EncodedMethod> virtualMethodList = new ArrayList<EncodedMethod>();
|
||||
|
||||
private final ListSizeField staticFieldsCount;
|
||||
private final ListSizeField instanceFieldsCount;
|
||||
private final ListSizeField directMethodsCount;
|
||||
private final ListSizeField virtualMethodsCount;
|
||||
private final EncodedMemberList<EncodedField> staticFields;
|
||||
private final EncodedMemberList<EncodedField> instanceFields;
|
||||
private final EncodedMemberList<EncodedMethod> directMethods;
|
||||
private final EncodedMemberList<EncodedMethod> virtualMethods;
|
||||
private final ListSizeField staticFieldsCountField;
|
||||
private final ListSizeField instanceFieldsCountField;
|
||||
private final ListSizeField directMethodsCountField;
|
||||
private final ListSizeField virtualMethodsCountField;
|
||||
private final EncodedMemberList<EncodedField> staticFieldsListField;
|
||||
private final EncodedMemberList<EncodedField> instanceFieldsListField;
|
||||
private final EncodedMemberList<EncodedMethod> directMethodsListField;
|
||||
private final EncodedMemberList<EncodedMethod> virtualMethodsListField;
|
||||
|
||||
|
||||
public ClassDataItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
|
||||
fields = new Field[] {
|
||||
staticFieldsCount = new ListSizeField(staticFieldList, new Leb128Field()),
|
||||
instanceFieldsCount = new ListSizeField(instanceFieldList, new Leb128Field()),
|
||||
directMethodsCount = new ListSizeField(directMethodList, new Leb128Field()),
|
||||
virtualMethodsCount = new ListSizeField(virtualMethodList, new Leb128Field()),
|
||||
staticFields = new EncodedMemberList<EncodedField>(staticFieldList) {
|
||||
staticFieldsCountField = new ListSizeField(staticFieldList,
|
||||
new Leb128Field("static_fields_size")),
|
||||
instanceFieldsCountField = new ListSizeField(instanceFieldList,
|
||||
new Leb128Field("instance_fields_size")),
|
||||
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) {
|
||||
return new EncodedField(dexFile, previousField);
|
||||
}
|
||||
},
|
||||
instanceFields = new EncodedMemberList<EncodedField>(instanceFieldList) {
|
||||
instanceFieldsListField = new EncodedMemberList<EncodedField>(instanceFieldList, "instance_fields") {
|
||||
protected EncodedField make(EncodedField previousField) {
|
||||
return new EncodedField(dexFile, previousField);
|
||||
}
|
||||
},
|
||||
directMethods = new EncodedMemberList<EncodedMethod>(directMethodList) {
|
||||
directMethodsListField = new EncodedMemberList<EncodedMethod>(directMethodList, "direct_methods") {
|
||||
protected EncodedMethod make(EncodedMethod previousMethod) {
|
||||
return new EncodedMethod(dexFile, previousMethod);
|
||||
}
|
||||
},
|
||||
virtualMethods = new EncodedMemberList<EncodedMethod>(virtualMethodList) {
|
||||
virtualMethodsListField = new EncodedMemberList<EncodedMethod>(virtualMethodList, "virtual_methods") {
|
||||
protected EncodedMethod make(EncodedMethod 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>
|
||||
{
|
||||
public EncodedMember(String fieldName) {
|
||||
super(fieldName);
|
||||
}
|
||||
|
||||
protected abstract void setPreviousMember(T previousMember);
|
||||
}
|
||||
|
||||
private static abstract class EncodedMemberList<T extends EncodedMember<T>> implements Field<EncodedMemberList<T>> {
|
||||
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.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
out.annotate(0, fieldName + ":");
|
||||
int i=0;
|
||||
for (T field: list) {
|
||||
out.annotate(0, "[0x" + Integer.toHexString(i) + "]");
|
||||
field.writeTo(out);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,13 +206,12 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
||||
}
|
||||
|
||||
public static class EncodedField extends EncodedMember<EncodedField> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<FieldIdItem> field;
|
||||
private final Leb128DeltaField fieldIndexField;
|
||||
private final Leb128Field accessFlags;
|
||||
|
||||
public EncodedField(DexFile dexFile, final EncodedField previousField) {
|
||||
super("encoded_field");
|
||||
Leb128DeltaField previousIndexField = null;
|
||||
if (previousField != null) {
|
||||
previousIndexField = previousField.fieldIndexField;
|
||||
@ -211,16 +220,17 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
||||
|
||||
fields = new Field[] {
|
||||
field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection,
|
||||
fieldIndexField = new Leb128DeltaField(previousIndexField)),
|
||||
accessFlags = new Leb128Field()
|
||||
fieldIndexField = new Leb128DeltaField(previousIndexField, null), "field_idx_diff"),
|
||||
accessFlags = new Leb128Field("access_flags")
|
||||
};
|
||||
}
|
||||
|
||||
public EncodedField(DexFile dexFile, FieldIdItem field, int accessFlags) {
|
||||
super("encoded_field");
|
||||
fields = new Field[] {
|
||||
this.field = new IndexedItemReference<FieldIdItem>(dexFile, field,
|
||||
fieldIndexField = new Leb128DeltaField(null)),
|
||||
this.accessFlags = new Leb128Field(accessFlags)
|
||||
fieldIndexField = new Leb128DeltaField(null), "field_idx_diff"),
|
||||
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)
|
||||
{
|
||||
return field.getReference().compareTo(other.field.getReference());
|
||||
@ -251,14 +257,13 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
||||
}
|
||||
|
||||
public static class EncodedMethod extends EncodedMember<EncodedMethod> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<MethodIdItem> method;
|
||||
private final Leb128DeltaField methodIndexField;
|
||||
private final Leb128Field accessFlags;
|
||||
private final OffsettedItemReference<CodeItem> codeItem;
|
||||
|
||||
public EncodedMethod(DexFile dexFile, final EncodedMethod previousMethod) {
|
||||
super("encedod_method");
|
||||
Leb128DeltaField previousIndexField = null;
|
||||
if (previousMethod != null) {
|
||||
previousIndexField = previousMethod.methodIndexField;
|
||||
@ -266,18 +271,21 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
||||
|
||||
fields = new Field[] {
|
||||
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
|
||||
methodIndexField = new Leb128DeltaField(previousIndexField)),
|
||||
accessFlags = new Leb128Field(),
|
||||
codeItem = new OffsettedItemReference<CodeItem>(dexFile.CodeItemsSection, new Leb128Field())
|
||||
methodIndexField = new Leb128DeltaField(previousIndexField, null), "method_idx_diff"),
|
||||
accessFlags = new Leb128Field("access_flags"),
|
||||
codeItem = new OffsettedItemReference<CodeItem>(dexFile.CodeItemsSection,
|
||||
new Leb128Field(null), "code_off")
|
||||
};
|
||||
}
|
||||
|
||||
public EncodedMethod(DexFile dexFile, MethodIdItem methodIdItem, int accessFlags, CodeItem codeItem) {
|
||||
super("encoded_method");
|
||||
fields = new Field[] {
|
||||
this.method = new IndexedItemReference<MethodIdItem>(dexFile, methodIdItem,
|
||||
methodIndexField = new Leb128DeltaField(null)),
|
||||
this.accessFlags = new Leb128Field(accessFlags),
|
||||
this.codeItem = new OffsettedItemReference<CodeItem>(dexFile, codeItem, new Leb128Field())
|
||||
methodIndexField = new Leb128DeltaField(null), "method_idx_diff"),
|
||||
this.accessFlags = new Leb128Field(accessFlags, "access_flags"),
|
||||
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)
|
||||
{
|
||||
return method.getReference().compareTo(other.method.getReference());
|
||||
@ -310,42 +314,51 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
||||
* item encodes the value as per normal
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
public void setPreviousField(Leb128DeltaField 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() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
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;
|
||||
|
||||
public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<TypeIdItem> classType;
|
||||
private final IntegerField accessFlags;
|
||||
private final IndexedItemReference<TypeIdItem> superclassType;
|
||||
private final OffsettedItemReference<TypeListItem> classInterfacesList;
|
||||
private final IndexedItemReference<StringIdItem> sourceFile;
|
||||
private final OffsettedItemReference<AnnotationDirectoryItem> classAnnotations;
|
||||
private final OffsettedItemReference<ClassDataItem> classData;
|
||||
private final OffsettedItemReference<EncodedArrayItem> staticFieldInitialValues;
|
||||
private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
|
||||
private final IntegerField accessFlagsField;
|
||||
private final IndexedItemReference<TypeIdItem> superclassTypeReferenceField;
|
||||
private final OffsettedItemReference<TypeListItem> classInterfacesListReferenceField;
|
||||
private final IndexedItemReference<StringIdItem> sourceFileReferenceField;
|
||||
private final OffsettedItemReference<AnnotationDirectoryItem> classAnnotationsReferenceField;
|
||||
private final OffsettedItemReference<ClassDataItem> classDataReferenceField;
|
||||
private final OffsettedItemReference<EncodedArrayItem> staticFieldInitialValuesReferenceField;
|
||||
|
||||
private ArrayList<EncodedValue> staticFieldInitialValuesList;
|
||||
|
||||
@ -58,14 +56,22 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
this.dexFile = dexFile;
|
||||
|
||||
fields = new Field[] {
|
||||
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()),
|
||||
accessFlags = new IntegerField(),
|
||||
superclassType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()),
|
||||
classInterfacesList = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection, new IntegerField()),
|
||||
sourceFile = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()),
|
||||
classAnnotations = new OffsettedItemReference<AnnotationDirectoryItem>(dexFile.AnnotationDirectoriesSection, new IntegerField()),
|
||||
classData = new OffsettedItemReference<ClassDataItem>(dexFile.ClassDataSection, new IntegerField()),
|
||||
staticFieldInitialValues = new OffsettedItemReference<EncodedArrayItem>(dexFile.EncodedArraysSection, new IntegerField())
|
||||
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||
new IntegerField(null), "class_idx"),
|
||||
//TODO: add annotated output showing the flags
|
||||
accessFlagsField = new IntegerField("access_flags:"),
|
||||
superclassTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||
new IntegerField(null), "superclass_idx"),
|
||||
classInterfacesListReferenceField = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection,
|
||||
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,
|
||||
StringIdItem source,
|
||||
ClassDataItem classDataItem) {
|
||||
super(-1);
|
||||
this(dexFile, -1);
|
||||
|
||||
this.dexFile = dexFile;
|
||||
|
||||
fields = new Field[] {
|
||||
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new IntegerField()),
|
||||
this.accessFlags = new IntegerField(accessFlags),
|
||||
superclassType = new IndexedItemReference<TypeIdItem>(dexFile, superType, new IntegerField()),
|
||||
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())
|
||||
};
|
||||
classTypeReferenceField.setReference(classType);
|
||||
accessFlagsField.cacheValue(accessFlags);
|
||||
superclassTypeReferenceField.setReference(superType);
|
||||
classInterfacesListReferenceField.setReference(implementsList);
|
||||
sourceFileReferenceField.setReference(source);
|
||||
classDataReferenceField.setReference(classDataItem);
|
||||
}
|
||||
|
||||
public TypeIdItem getSuperclass() {
|
||||
return superclassType.getReference();
|
||||
return superclassTypeReferenceField.getReference();
|
||||
}
|
||||
|
||||
public TypeIdItem getClassType() {
|
||||
return classType.getReference();
|
||||
public TypeIdItem getClassTypeReferenceField() {
|
||||
return classTypeReferenceField.getReference();
|
||||
}
|
||||
|
||||
protected int getAlignment() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
public TypeIdItem getClassType() {
|
||||
return classTypeReferenceField.getReference();
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
@ -113,15 +113,15 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return classType.getReference().toString();
|
||||
return classTypeReferenceField.getReference().getTypeDescriptor();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getClassName();
|
||||
public String getConciseIdentity() {
|
||||
return "class_def_item: " + getClassName();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return classType.getReference().hashCode();
|
||||
return classTypeReferenceField.getReference().hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
@ -129,7 +129,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
return false;
|
||||
}
|
||||
ClassDefItem other = (ClassDefItem)o;
|
||||
return classType.equals(other.classType);
|
||||
return classTypeReferenceField.equals(other.classTypeReferenceField);
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
ClassDataItem classDataItem = this.classData.getReference();
|
||||
ClassDataItem classDataItem = this.classDataReferenceField.getReference();
|
||||
|
||||
int fieldIndex = classDataItem.addField(encodedField);
|
||||
if (initialValue != null) {
|
||||
@ -153,13 +153,14 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
staticFieldInitialValuesList = new ArrayList<EncodedValue>();
|
||||
|
||||
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
|
||||
for (int i=staticFieldInitialValuesList.size(); i < fieldIndex; 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);
|
||||
staticFieldInitialValuesList.add(i, encodedValue);
|
||||
}
|
||||
@ -169,7 +170,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
}
|
||||
|
||||
public void setAnnotations(AnnotationDirectoryItem annotations) {
|
||||
this.classAnnotations.setReference(annotations);
|
||||
this.classAnnotationsReferenceField.setReference(annotations);
|
||||
}
|
||||
|
||||
public static int placeClassDefItems(IndexedSection<ClassDefItem> section, int offset) {
|
||||
@ -192,7 +193,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
this.section = section;
|
||||
|
||||
for (ClassDefItem classDefItem: section.items) {
|
||||
TypeIdItem typeIdItem = classDefItem.classType.getReference();
|
||||
TypeIdItem typeIdItem = classDefItem.classTypeReferenceField.getReference();
|
||||
classDefsByType.put(typeIdItem, classDefItem);
|
||||
}
|
||||
}
|
||||
@ -212,14 +213,14 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
|
||||
private void placeClass(ClassDefItem classDefItem) {
|
||||
if (!classDefItem.isPlaced()) {
|
||||
TypeIdItem superType = classDefItem.superclassType.getReference();
|
||||
TypeIdItem superType = classDefItem.superclassTypeReferenceField.getReference();
|
||||
ClassDefItem superClassDefItem = classDefsByType.get(superType);
|
||||
|
||||
if (superClassDefItem != null) {
|
||||
placeClass(superClassDefItem);
|
||||
}
|
||||
|
||||
TypeListItem interfaces = classDefItem.classInterfacesList.getReference();
|
||||
TypeListItem interfaces = classDefItem.classInterfacesListReferenceField.getReference();
|
||||
|
||||
if (interfaces != null) {
|
||||
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.ItemType;
|
||||
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.List;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
private final Field[] fields;
|
||||
private final ArrayList<Instruction> instructionList;
|
||||
private final ArrayList<TryItem> tryItems = new ArrayList<TryItem>();
|
||||
private final ArrayList<EncodedCatchHandler> catchHandlerList = new ArrayList<EncodedCatchHandler>();
|
||||
|
||||
private final ShortIntegerField registersCount;
|
||||
private final ShortIntegerField inArgumentCount;
|
||||
private final ShortIntegerField outArgumentCount;
|
||||
private final ListSizeField triesCount;
|
||||
private final OffsettedItemReference<DebugInfoItem> debugInfo;
|
||||
private final IntegerField instructionsSize;
|
||||
private final ShortIntegerField registersCountField;
|
||||
private final ShortIntegerField inArgumentCountField;
|
||||
private final ShortIntegerField outArgumentCountField;
|
||||
private final ListSizeField triesCountField;
|
||||
private final OffsettedItemReference<DebugInfoItem> debugInfoReferenceField;
|
||||
private final IntegerField instructionsSizeField;
|
||||
private final InstructionListField instructionListField;
|
||||
private final PaddingField padding;
|
||||
private final FieldListField<TryItem> tries;
|
||||
private final EncodedCatchHandlerList catchHandlers;
|
||||
private final PaddingField paddingField;
|
||||
private final FieldListField<TryItem> triesListField;
|
||||
private final EncodedCatchHandlerList catchHandlersListField;
|
||||
|
||||
public CodeItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
@ -61,37 +60,36 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
instructionList = new ArrayList<Instruction>();
|
||||
|
||||
fields = new Field[] {
|
||||
registersCount = new ShortIntegerField(),
|
||||
inArgumentCount = new ShortIntegerField(),
|
||||
outArgumentCount = new ShortIntegerField(),
|
||||
triesCount = new ListSizeField(tryItems, new ShortIntegerField()),
|
||||
debugInfo = new OffsettedItemReference<DebugInfoItem>(dexFile.DebugInfoItemsSection, new IntegerField()),
|
||||
instructionsSize = new IntegerField(),
|
||||
registersCountField = new ShortIntegerField("registers_size"),
|
||||
inArgumentCountField = new ShortIntegerField("ins_size"),
|
||||
outArgumentCountField = new ShortIntegerField("outs_size"),
|
||||
triesCountField = new ListSizeField(tryItems, new ShortIntegerField("tries_size")),
|
||||
debugInfoReferenceField = new OffsettedItemReference<DebugInfoItem>(dexFile.DebugInfoItemsSection,
|
||||
new IntegerField(null), "debug_off"),
|
||||
instructionsSizeField = new IntegerField("insns_size"),
|
||||
instructionListField = new InstructionListField(dexFile),
|
||||
padding = new PaddingField(),
|
||||
tries = new FieldListField<TryItem>(tryItems) {
|
||||
paddingField = new PaddingField(),
|
||||
triesListField = new FieldListField<TryItem>(tryItems, "try_item") {
|
||||
protected TryItem make() {
|
||||
return new TryItem(catchHandlers);
|
||||
return new TryItem(catchHandlersListField);
|
||||
}
|
||||
},
|
||||
|
||||
catchHandlers = new EncodedCatchHandlerList(dexFile)
|
||||
catchHandlersListField = new EncodedCatchHandlerList(dexFile)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
public CodeItem(final DexFile dexFile,
|
||||
int registersCount,
|
||||
int inArguments,
|
||||
ArrayList<Instruction> instructions,
|
||||
List<Instruction> instructions,
|
||||
DebugInfoItem debugInfo,
|
||||
List<TryItem> tries,
|
||||
List<EncodedCatchHandler> handlers) {
|
||||
super(-1);
|
||||
this(dexFile, 0);
|
||||
|
||||
this.instructionList = new ArrayList<Instruction>(instructions);
|
||||
this.instructionListField = new InstructionListField(dexFile);
|
||||
instructionList.addAll(instructions);
|
||||
instructionsSizeField.cacheValue(instructionListField.getInstructionWordCount());
|
||||
|
||||
if (tries != null) {
|
||||
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");
|
||||
}
|
||||
|
||||
fields = new Field[] {
|
||||
this.registersCount = new ShortIntegerField(registersCount),
|
||||
this.inArgumentCount = new ShortIntegerField(inArguments),
|
||||
this.outArgumentCount = new ShortIntegerField(instructionListField.getOutArguments()),
|
||||
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)
|
||||
};
|
||||
registersCountField.cacheValue(registersCount);
|
||||
inArgumentCountField.cacheValue(inArguments);
|
||||
outArgumentCountField.cacheValue(instructionListField.getOutArguments());
|
||||
debugInfoReferenceField.setReference(debugInfo);
|
||||
}
|
||||
|
||||
protected int getAlignment() {
|
||||
@ -131,48 +117,43 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
|
||||
public void copyTo(DexFile dexFile, CodeItem copy)
|
||||
{
|
||||
Field[] fields = getFields();
|
||||
Field[] fieldsCopy = copy.getFields();
|
||||
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,
|
||||
//the catchHandler copies will already exist
|
||||
catchHandlers.copyTo(dexFile, copy.catchHandlers);
|
||||
tries.copyTo(dexFile, copy.tries);
|
||||
catchHandlersListField.copyTo(dexFile, copy.catchHandlersListField);
|
||||
triesListField.copyTo(dexFile, copy.triesListField);
|
||||
}
|
||||
|
||||
public Field[] getFields() {
|
||||
return fields;
|
||||
public String getConciseIdentity() {
|
||||
//TODO: should mention the method name here
|
||||
return "code_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
public static class TryItem extends CompositeField<TryItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IntegerField startAddr;
|
||||
private final ShortIntegerField insnCount;
|
||||
private final EncodedCatchHandlerReference encodedCatchHandlerReference;
|
||||
|
||||
public TryItem(EncodedCatchHandlerList encodedCatchHandlerList) {
|
||||
super("try_item");
|
||||
fields = new Field[] {
|
||||
startAddr = new IntegerField(),
|
||||
insnCount = new ShortIntegerField(),
|
||||
startAddr = new IntegerField("start_addr"),
|
||||
insnCount = new ShortIntegerField("insn_count"),
|
||||
encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandlerList)
|
||||
};
|
||||
}
|
||||
|
||||
public TryItem(int startAddr, int insnCount, EncodedCatchHandler encodedCatchHandler) {
|
||||
super("try_item");
|
||||
fields = new Field[] {
|
||||
this.startAddr = new IntegerField(startAddr),
|
||||
this.insnCount = new ShortIntegerField(insnCount),
|
||||
this.startAddr = new IntegerField(startAddr, "start_addr"),
|
||||
this.insnCount = new ShortIntegerField(insnCount, "insn_count"),
|
||||
this.encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandler)
|
||||
};
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public int getStartAddress() {
|
||||
return startAddr.getCachedValue();
|
||||
}
|
||||
@ -191,10 +172,12 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
private EncodedCatchHandler encodedCatchHandler;
|
||||
|
||||
public EncodedCatchHandlerReference(EncodedCatchHandlerList encodedCatchHandlerList) {
|
||||
super("encoded_catch_handler");
|
||||
this.encodedCatchHandlerList = encodedCatchHandlerList;
|
||||
}
|
||||
|
||||
public EncodedCatchHandlerReference(EncodedCatchHandler encodedCatchHandler) {
|
||||
super("encoded_catch_handler");
|
||||
this.encodedCatchHandlerList = null;
|
||||
this.encodedCatchHandler = encodedCatchHandler;
|
||||
}
|
||||
@ -212,7 +195,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
}
|
||||
|
||||
public void copyTo(DexFile dexFile, CachedIntegerValueField _copy) {
|
||||
|
||||
EncodedCatchHandlerReference copy = (EncodedCatchHandlerReference)_copy;
|
||||
EncodedCatchHandler copiedItem = copy.getEncodedCatchHandlerList().getByOffset(
|
||||
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());
|
||||
|
||||
super.writeTo(out);
|
||||
@ -252,18 +234,17 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
itemsByOffset.put(offset, encodedCatchHandler);
|
||||
}
|
||||
return encodedCatchHandler;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public EncodedCatchHandlerList(DexFile dexFile) {
|
||||
public EncodedCatchHandlerList(final DexFile dexFile) {
|
||||
super("encoded_catch_handler_list");
|
||||
this.dexFile = dexFile;
|
||||
}
|
||||
|
||||
private final ListSizeField sizeField;
|
||||
private final FieldListField<EncodedCatchHandler> listField;
|
||||
|
||||
private final Field[] fields = new Field[] {
|
||||
sizeField = new ListSizeField(catchHandlerList, new Leb128Field()),
|
||||
listField = new FieldListField<EncodedCatchHandler>(catchHandlerList) {
|
||||
fields = new Field[] {
|
||||
sizeField = new ListSizeField(catchHandlerList, new Leb128Field("size")),
|
||||
listField = new FieldListField<EncodedCatchHandler>(catchHandlerList, "encoded_catch_handler") {
|
||||
protected EncodedCatchHandler make() {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
super.copyTo(dexFile, copy);
|
||||
copy.fieldPresent = fieldPresent;
|
||||
@ -329,7 +310,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
}
|
||||
|
||||
public static class EncodedCatchHandler extends CompositeField<EncodedCatchHandler> {
|
||||
public final Field[] fields;
|
||||
private ArrayList<EncodedTypeAddrPair> list;
|
||||
boolean hasCatchAll = false;
|
||||
private int baseOffset = 0;
|
||||
@ -341,11 +321,12 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
private int offset;
|
||||
|
||||
public EncodedCatchHandler(final DexFile dexFile, int offset) {
|
||||
super("encoded_catch_handler");
|
||||
this.offset = offset;
|
||||
|
||||
list = new ArrayList<EncodedTypeAddrPair>();
|
||||
fields = new Field[] {
|
||||
size = new ListSizeField(list, new SignedLeb128Field() {
|
||||
size = new ListSizeField(list, new SignedLeb128Field("size") {
|
||||
public void readFrom(Input in) {
|
||||
super.readFrom(in);
|
||||
hasCatchAll = (getCachedValue() <= 0);
|
||||
@ -355,19 +336,19 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
super.cacheValue(value * (hasCatchAll?-1:1));
|
||||
}})
|
||||
,
|
||||
handlers = new FieldListField<EncodedTypeAddrPair>(list) {
|
||||
handlers = new FieldListField<EncodedTypeAddrPair>(list, "encoded_type_addr_pair") {
|
||||
protected EncodedTypeAddrPair make() {
|
||||
return new EncodedTypeAddrPair(dexFile);
|
||||
}
|
||||
},
|
||||
catchAllAddress = new Leb128Field() {
|
||||
catchAllAddress = new Leb128Field("catch_all_addr") {
|
||||
public void readFrom(Input in) {
|
||||
if (hasCatchAll) {
|
||||
super.readFrom(in);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
if (hasCatchAll) {
|
||||
super.writeTo(out);
|
||||
}
|
||||
@ -393,10 +374,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
}
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public int getOffsetInList() {
|
||||
return offset-baseOffset;
|
||||
}
|
||||
@ -434,35 +411,30 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
}
|
||||
|
||||
public static class EncodedTypeAddrPair extends CompositeField<EncodedTypeAddrPair> {
|
||||
public final Field[] fields;
|
||||
|
||||
public final IndexedItemReference<TypeIdItem> type;
|
||||
public final Leb128Field handlerAddress;
|
||||
public final IndexedItemReference<TypeIdItem> typeReferenceField;
|
||||
public final Leb128Field handlerAddressField;
|
||||
|
||||
public EncodedTypeAddrPair(DexFile dexFile) {
|
||||
super("encoded_type_addr_pair");
|
||||
fields = new Field[] {
|
||||
type = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128Field()),
|
||||
handlerAddress = new Leb128Field()
|
||||
typeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||
new Leb128Field(null), "type_idx"),
|
||||
handlerAddressField = new Leb128Field("addr")
|
||||
};
|
||||
}
|
||||
|
||||
public EncodedTypeAddrPair(DexFile dexFile, TypeIdItem type, int handlerOffset) {
|
||||
fields = new Field[] {
|
||||
this.type = new IndexedItemReference<TypeIdItem>(dexFile, type, new Leb128Field()),
|
||||
this.handlerAddress = new Leb128Field(handlerOffset)
|
||||
};
|
||||
this(dexFile);
|
||||
typeReferenceField.setReference(type);
|
||||
handlerAddressField.cacheValue(handlerOffset);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public TypeIdItem getType() {
|
||||
return type.getReference();
|
||||
public TypeIdItem getTypeReferenceField() {
|
||||
return typeReferenceField.getReference();
|
||||
}
|
||||
|
||||
public int getHandlerAddress() {
|
||||
return handlerAddress.getCachedValue();
|
||||
return handlerAddressField.getCachedValue();
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,18 +445,18 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
this.dexFile = dexFile;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
int startPosition = out.getCursor();
|
||||
for (Instruction instruction: instructionList) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
int numBytes = instructionsSize.getCachedValue() * 2;
|
||||
int numBytes = instructionsSizeField.getCachedValue() * 2;
|
||||
int startPosition = in.getCursor();
|
||||
|
||||
do {
|
||||
@ -499,7 +471,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
return offset + (instructionsSize.getCachedValue() * 2);
|
||||
return offset + (instructionsSizeField.getCachedValue() * 2);
|
||||
}
|
||||
|
||||
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) {
|
||||
isStatic = true;
|
||||
}
|
||||
int paramWordCount = methodIdItem.getParameterWordCount(isStatic);
|
||||
int paramWordCount = methodIdItem.getParameterRegisterCount(isStatic);
|
||||
|
||||
if (maxParamWordCount < paramWordCount) {
|
||||
maxParamWordCount = paramWordCount;
|
||||
@ -556,10 +528,10 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
}
|
||||
|
||||
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()) {
|
||||
out.writeShort(0);
|
||||
}
|
||||
|
@ -28,53 +28,58 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
|
||||
public abstract class CompositeField<T extends CompositeField<T>> implements Field<T> {
|
||||
/**
|
||||
* Every instance of a specific subclass should return an array with the same structure,
|
||||
* 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();
|
||||
protected Field[] fields;
|
||||
private final String fieldName;
|
||||
|
||||
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);
|
||||
}
|
||||
out.deindent();
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
for (Field field: getFields()) {
|
||||
for (Field field: fields) {
|
||||
field.readFrom(in);
|
||||
}
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
for (Field field: getFields()) {
|
||||
for (Field field: fields) {
|
||||
offset = field.place(offset);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void copyTo(DexFile dexFile, T copy) {
|
||||
Field[] fields = getFields();
|
||||
Field[] copyFields = copy.getFields();
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
/**
|
||||
* This assumes that the fields will be the same for every instance
|
||||
* of a specific concrete subclass. By making this assumption, every subclass is
|
||||
* prevented from having to implement copyTo
|
||||
*/
|
||||
fields[i].copyTo(dexFile, copyFields[i]);
|
||||
fields[i].copyTo(dexFile, copy.fields[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int h = 1;
|
||||
for (Field field: getFields()) {
|
||||
for (Field field: fields) {
|
||||
h = h * 31 + field.hashCode();
|
||||
}
|
||||
return h;
|
||||
@ -86,13 +91,11 @@ public abstract class CompositeField<T extends CompositeField<T>> implements Fie
|
||||
}
|
||||
|
||||
CompositeField other = (CompositeField)o;
|
||||
Field[] fields = getFields();
|
||||
Field[] otherFields = other.getFields();
|
||||
if (fields.length != otherFields.length) {
|
||||
if (fields.length != other.fields.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if (!fields[i].equals(otherFields[i])) {
|
||||
if (!fields[i].equals(other.fields[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -32,15 +32,13 @@ import org.JesusFreke.dexlib.ItemType;
|
||||
import org.JesusFreke.dexlib.debug.DebugInstructionFactory;
|
||||
import org.JesusFreke.dexlib.debug.EndSequence;
|
||||
import org.JesusFreke.dexlib.debug.DebugInstruction;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ArrayList<IndexedItemReference<StringIdItem>> parameterNames =
|
||||
new ArrayList<IndexedItemReference<StringIdItem>>();
|
||||
|
||||
@ -55,11 +53,13 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
||||
super(offset);
|
||||
|
||||
fields = new Field[] {
|
||||
lineStartField = new Leb128Field(),
|
||||
parameterNamesSizeField = new ListSizeField(parameterNames, new Leb128Field()),
|
||||
parameterNamesField = new FieldListField<IndexedItemReference<StringIdItem>>(parameterNames) {
|
||||
lineStartField = new Leb128Field("line_start"),
|
||||
parameterNamesSizeField = new ListSizeField(parameterNames, new Leb128Field("parameters_size")),
|
||||
parameterNamesField = new FieldListField<IndexedItemReference<StringIdItem>>(
|
||||
parameterNames, "parameter_names") {
|
||||
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)
|
||||
@ -75,25 +75,22 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
||||
this.lineStartField.cacheValue(lineStart);
|
||||
|
||||
for (StringIdItem parameterName: parameterNames) {
|
||||
this.parameterNames.add(new IndexedItemReference<StringIdItem>(dexFile, parameterName,
|
||||
new Leb128p1Field()));
|
||||
IndexedItemReference<StringIdItem> parameterReference = parameterNamesField.make();
|
||||
parameterReference.setReference(parameterName);
|
||||
this.parameterNames.add(parameterReference);
|
||||
}
|
||||
|
||||
this.instructionFields.addAll(debugInstructions);
|
||||
}
|
||||
|
||||
protected int getAlignment() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_DEBUG_INFO_ITEM;
|
||||
}
|
||||
|
||||
public String getConciseIdentity() {
|
||||
return "debug_info_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
private class DebugInstructionList implements Field<DebugInstructionList> {
|
||||
private final DexFile dexFile;
|
||||
private final ArrayList<DebugInstruction> list;
|
||||
@ -103,7 +100,7 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
||||
list = instructionFields;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
for (DebugInstruction debugInstruction: list) {
|
||||
debugInstruction.writeTo(out);
|
||||
}
|
||||
|
@ -28,10 +28,7 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.ByteArrayInput;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.FileUtils;
|
||||
import org.JesusFreke.dexlib.util.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
@ -176,7 +173,7 @@ public class DexFile
|
||||
fileSize = offset;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
HeaderItemSection.writeTo(out);
|
||||
for (IndexedSection indexedSection: indexedSections) {
|
||||
indexedSection.writeTo(out);
|
||||
@ -189,29 +186,6 @@ public class DexFile
|
||||
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>() {
|
||||
protected HeaderItem make(int index) {
|
||||
try {
|
||||
|
@ -32,13 +32,11 @@ import org.JesusFreke.dexlib.ItemType;
|
||||
import org.JesusFreke.dexlib.EncodedValue.ArrayEncodedValueSubField;
|
||||
import org.JesusFreke.dexlib.EncodedValue.EncodedValue;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ArrayEncodedValueSubField encodedArray;
|
||||
|
||||
public EncodedArrayItem(DexFile dexFile, int offset) {
|
||||
@ -50,7 +48,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
||||
}
|
||||
|
||||
public EncodedArrayItem(DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
||||
super(-1);
|
||||
super(0);
|
||||
|
||||
fields = new Field[] {
|
||||
encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues)
|
||||
@ -65,7 +63,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
||||
return super.place(index, offset);
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
super.writeTo(out);
|
||||
}
|
||||
|
||||
@ -73,10 +71,6 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return super.getOffset();
|
||||
}
|
||||
@ -88,4 +82,8 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
||||
public ItemType getItemType() {
|
||||
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.*;
|
||||
|
||||
public class AnnotationElement extends CompositeField<AnnotationElement> {
|
||||
private Field[] fields;
|
||||
|
||||
private final IndexedItemReference<StringIdItem> elementName;
|
||||
private final EncodedValue encodedValue;
|
||||
|
||||
public AnnotationElement(final DexFile dexFile) {
|
||||
super("annotation_element");
|
||||
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)
|
||||
};
|
||||
}
|
||||
|
||||
public AnnotationElement(final DexFile dexFile, StringIdItem elementName, EncodedValue encodedValue) {
|
||||
super("annotation_element");
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ import java.util.List;
|
||||
public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEncodedValueSubField>
|
||||
implements EncodedValueSubField<AnnotationEncodedValueSubField> {
|
||||
|
||||
private final Field[] fields;
|
||||
private final ArrayList<AnnotationElement> annotationElementList = new ArrayList<AnnotationElement>();
|
||||
|
||||
private final IndexedItemReference<TypeIdItem> annotationType;
|
||||
@ -44,10 +43,12 @@ public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEnc
|
||||
private final FieldListField<AnnotationElement> annotationElements;
|
||||
|
||||
public AnnotationEncodedValueSubField(final DexFile dexFile) {
|
||||
super("encoded_annotation");
|
||||
fields = new Field[] {
|
||||
annotationType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128Field()),
|
||||
annotationCount = new ListSizeField(annotationElementList, new Leb128Field()),
|
||||
annotationElements = new FieldListField<AnnotationElement>(annotationElementList) {
|
||||
annotationType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||
new Leb128Field(null), "type_idx"),
|
||||
annotationCount = new ListSizeField(annotationElementList, new Leb128Field("size")),
|
||||
annotationElements = new FieldListField<AnnotationElement>(annotationElementList, "elements") {
|
||||
protected AnnotationElement make() {
|
||||
return new AnnotationElement(dexFile);
|
||||
}
|
||||
@ -62,10 +63,6 @@ public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEnc
|
||||
this.annotationElementList.addAll(annotationElements);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setInitialValueArg(byte valueArg) {
|
||||
//valueArg is ignored for annotations
|
||||
}
|
||||
|
@ -36,14 +36,15 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
|
||||
implements EncodedValueSubField<ArrayEncodedValueSubField>
|
||||
{
|
||||
|
||||
private final Field[] fields;
|
||||
private final ArrayList<EncodedValue> encodedValues;
|
||||
|
||||
public ArrayEncodedValueSubField(final DexFile dexFile) {
|
||||
super("encoded_array");
|
||||
|
||||
encodedValues = new ArrayList<EncodedValue>();
|
||||
fields = new Field[] {
|
||||
new ListSizeField(encodedValues, new Leb128Field()),
|
||||
new FieldListField<EncodedValue>(encodedValues) {
|
||||
new ListSizeField(encodedValues, new Leb128Field("size")),
|
||||
new FieldListField<EncodedValue>(encodedValues, "values") {
|
||||
protected EncodedValue make() {
|
||||
return new EncodedValue(dexFile);
|
||||
}
|
||||
@ -52,11 +53,13 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
|
||||
}
|
||||
|
||||
public ArrayEncodedValueSubField(final DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
||||
super("encoded_array");
|
||||
|
||||
this.encodedValues = encodedValues;
|
||||
|
||||
fields = new Field[] {
|
||||
new ListSizeField(this.encodedValues, new Leb128Field()),
|
||||
new FieldListField<EncodedValue>(encodedValues) {
|
||||
new ListSizeField(this.encodedValues, new Leb128Field("size")),
|
||||
new FieldListField<EncodedValue>(encodedValues, "values") {
|
||||
protected EncodedValue make() {
|
||||
return new EncodedValue(dexFile);
|
||||
}
|
||||
@ -64,10 +67,6 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
|
||||
};
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setInitialValueArg(byte valueArg) {
|
||||
//valueArg is ignored for arrays
|
||||
}
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class BoolEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Boolean, BoolEncodedValueSubField>
|
||||
@ -41,7 +41,7 @@ public class BoolEncodedValueSubField
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class ByteEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Byte, ByteEncodedValueSubField>
|
||||
@ -41,7 +41,8 @@ public class ByteEncodedValueSubField
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class CharEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Character, CharEncodedValueSubField>
|
||||
@ -42,8 +42,10 @@ public class CharEncodedValueSubField
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.write(EncodedValueUtils.encodeUnsignedIntegralValue(value));
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value);
|
||||
out.annotate(bytes.length, "CharEncodedValueSubField");
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class DoubleEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Double, DoubleEncodedValueSubField>
|
||||
@ -42,9 +42,10 @@ public class DoubleEncodedValueSubField
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.write(EncodedValueUtils.encodeRightZeroExtendedValue(
|
||||
Double.doubleToLongBits(value)));
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeRightZeroExtendedValue(Double.doubleToLongBits(value));
|
||||
out.annotate(bytes.length, "DoubleEncodedValueSubField");
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
|
@ -29,25 +29,25 @@
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.*;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
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>>
|
||||
extends ItemReference<T, EncodedIndexedItemReference<T>>
|
||||
implements EncodedValueSubField<EncodedIndexedItemReference<T>> {
|
||||
private int initialValueArg;
|
||||
private ValueType valueType;
|
||||
|
||||
private T item = null;
|
||||
private IndexedSection<T> section;
|
||||
|
||||
public EncodedIndexedItemReference(IndexedSection<T> section, ValueType valueType) {
|
||||
super(section);
|
||||
this.valueType = valueType;
|
||||
this.section = section;
|
||||
}
|
||||
|
||||
//TODO: implement support for enum values
|
||||
public EncodedIndexedItemReference(DexFile dexFile, T item) {
|
||||
super(dexFile, item);
|
||||
if (item.getClass() == StringIdItem.class) {
|
||||
valueType = ValueType.VALUE_STRING;
|
||||
} else if (item.getClass() == TypeIdItem.class) {
|
||||
@ -57,31 +57,48 @@ public class EncodedIndexedItemReference<T extends IndexedItem<T>>
|
||||
} else if (item.getClass() == MethodIdItem.class) {
|
||||
valueType = ValueType.VALUE_METHOD;
|
||||
}
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
T item = getReference();
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
|
||||
if (!item.isPlaced()) {
|
||||
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) {
|
||||
setReference(((IndexedSection<T>)getSection()).getByIndex(
|
||||
(int)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(initialValueArg + 1))));
|
||||
item = section.getByIndex(
|
||||
(int)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(initialValueArg + 1)));
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
T item = getReference();
|
||||
if (!item.isPlaced()) {
|
||||
throw new RuntimeException("Trying to place a reference to an item that hasn't been placed.");
|
||||
}
|
||||
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() {
|
||||
return getReference();
|
||||
return item;
|
||||
}
|
||||
|
||||
public void setInitialValueArg(byte valueArg)
|
||||
@ -90,7 +107,7 @@ public class EncodedIndexedItemReference<T extends IndexedItem<T>>
|
||||
}
|
||||
|
||||
public byte getValueArg() {
|
||||
return EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(getReference().getIndex());
|
||||
return EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(item.getIndex());
|
||||
}
|
||||
|
||||
public ValueType getValueType() {
|
||||
|
@ -28,13 +28,11 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
import org.JesusFreke.dexlib.*;
|
||||
|
||||
public class EncodedValue extends CompositeField<EncodedValue> {
|
||||
private final Field[] fields;
|
||||
|
||||
private class ValueTypeArgField implements Field<ValueTypeArgField> {
|
||||
private ValueType valueType;
|
||||
private byte valueArg;
|
||||
@ -46,8 +44,8 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
||||
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));
|
||||
out.writeByte(value);
|
||||
}
|
||||
@ -102,7 +100,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
||||
this.subField = subField;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
subField.writeTo(out);
|
||||
}
|
||||
|
||||
@ -147,6 +145,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
||||
private final EncodedValueSubFieldWrapper encodedValue;
|
||||
|
||||
public EncodedValue(final DexFile dexFile) {
|
||||
super("encoded_value");
|
||||
fields = new Field[] {
|
||||
valueTypeArg = new ValueTypeArgField(),
|
||||
encodedValue = new EncodedValueSubFieldWrapper(dexFile)
|
||||
@ -154,6 +153,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
||||
}
|
||||
|
||||
public EncodedValue(final DexFile dexFile, EncodedValueSubField subField) {
|
||||
super("encoded_value");
|
||||
fields = new Field[] {
|
||||
valueTypeArg = new ValueTypeArgField(subField.getValueType()),
|
||||
encodedValue = new EncodedValueSubFieldWrapper(dexFile, subField)
|
||||
@ -182,8 +182,4 @@ public class EncodedValue extends CompositeField<EncodedValue> {
|
||||
public byte getValueArg() {
|
||||
return valueTypeArg.getValueArg();
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class FloatEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Float, FloatEncodedValueSubField>
|
||||
@ -41,9 +41,10 @@ public class FloatEncodedValueSubField
|
||||
public FloatEncodedValueSubField(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
public void writeTo(Output out) {
|
||||
out.write(EncodedValueUtils.encodeRightZeroExtendedValue(
|
||||
((long)Float.floatToIntBits(value)) << 32));
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeRightZeroExtendedValue(((long)Float.floatToIntBits(value)) << 32);
|
||||
out.annotate(bytes.length, "FloatEncodedValueSubField");
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class IntEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Integer, IntEncodedValueSubField>
|
||||
@ -42,8 +42,10 @@ public class IntEncodedValueSubField
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.write(EncodedValueUtils.encodeSignedIntegralValue(value));
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||
out.annotate(bytes.length, "IntEncodedValueSubField");
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class LongEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Long, LongEncodedValueSubField>
|
||||
@ -42,8 +42,10 @@ public class LongEncodedValueSubField
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.write(EncodedValueUtils.encodeSignedIntegralValue(value));
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||
out.annotate(bytes.length, "LongEncodedValueSubField");
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class NullEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Object, NullEncodedValueSubField>
|
||||
@ -37,7 +37,7 @@ public class NullEncodedValueSubField
|
||||
public NullEncodedValueSubField() {
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
package org.JesusFreke.dexlib.EncodedValue;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.EncodedValueUtils;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class ShortEncodedValueSubField
|
||||
extends SimpleEncodedValueSubField<Short, ShortEncodedValueSubField>
|
||||
@ -42,8 +42,10 @@ public class ShortEncodedValueSubField
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.write(EncodedValueUtils.encodeSignedIntegralValue(value));
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||
out.annotate(bytes.length, "ShortEncodedValueSubField");
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
|
@ -30,9 +30,10 @@ package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public interface Field<T extends Field> {
|
||||
public void writeTo(Output out);
|
||||
public void writeTo(AnnotatedOutput out);
|
||||
public void readFrom(Input in);
|
||||
public int place(int offset);
|
||||
public void copyTo(DexFile dexFile, T copy);
|
||||
|
@ -28,31 +28,28 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.ItemType;
|
||||
|
||||
public class FieldIdItem extends IndexedItem<FieldIdItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<TypeIdItem> classType;
|
||||
private final IndexedItemReference<TypeIdItem> fieldType;
|
||||
private final IndexedItemReference<StringIdItem> fieldName;
|
||||
private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
|
||||
private final IndexedItemReference<TypeIdItem> fieldTypeReferenceField;
|
||||
private final IndexedItemReference<StringIdItem> fieldNameReferenceField;
|
||||
|
||||
public FieldIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
fields = new Field[] {
|
||||
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()),
|
||||
fieldType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()),
|
||||
fieldName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField())
|
||||
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||
new ShortIntegerField(null), "class_idx"),
|
||||
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) {
|
||||
super(-1);
|
||||
fields = new Field[] {
|
||||
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new ShortIntegerField()),
|
||||
this.fieldType = new IndexedItemReference<TypeIdItem>(dexFile, fieldType, new ShortIntegerField()),
|
||||
this.fieldName = new IndexedItemReference<StringIdItem>(dexFile, fieldName, new IntegerField())
|
||||
};
|
||||
this(dexFile, -1);
|
||||
classTypeReferenceField.setReference(classType);
|
||||
fieldTypeReferenceField.setReference(fieldType);
|
||||
fieldNameReferenceField.setReference(fieldName);
|
||||
}
|
||||
|
||||
public FieldIdItem(DexFile dexFile, TypeIdItem classType, String fieldName, TypeIdItem fieldType) {
|
||||
@ -63,34 +60,35 @@ public class FieldIdItem extends IndexedItem<FieldIdItem> {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_FIELD_ID_ITEM;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return classType.toString() + " - " + fieldName.toString();
|
||||
public String getConciseIdentity() {
|
||||
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) {
|
||||
int result = classType.compareTo(o.classType);
|
||||
int result = classTypeReferenceField.compareTo(o.classTypeReferenceField);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = fieldName.compareTo(o.fieldName);
|
||||
result = fieldNameReferenceField.compareTo(o.fieldNameReferenceField);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return fieldType.compareTo(o.fieldType);
|
||||
return fieldTypeReferenceField.compareTo(o.fieldTypeReferenceField);
|
||||
|
||||
}
|
||||
|
||||
public TypeIdItem getFieldType() {
|
||||
return fieldType.getReference();
|
||||
return fieldTypeReferenceField.getReference();
|
||||
}
|
||||
}
|
||||
|
@ -28,21 +28,30 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class FieldListField<T extends Field> implements Field<FieldListField<T>> {
|
||||
final ArrayList<T> list;
|
||||
private final String fieldName;
|
||||
|
||||
public FieldListField(ArrayList<T> list) {
|
||||
public FieldListField(ArrayList<T> list, String fieldName) {
|
||||
this.list = list;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
for (Field field: list) {
|
||||
field.writeTo(out);
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
if (list.size() > 0) {
|
||||
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;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.ByteArray;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class FixedByteArrayField implements Field<FixedByteArrayField> {
|
||||
protected byte[] value;
|
||||
private final String fieldName;
|
||||
|
||||
public FixedByteArrayField(int size) {
|
||||
public FixedByteArrayField(int size, String fieldName) {
|
||||
value = new byte[size];
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public FixedByteArrayField(byte[] bytes) {
|
||||
public FixedByteArrayField(byte[] bytes, String fieldName) {
|
||||
this.value = bytes.clone();
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public FixedByteArrayField(ByteArray byteArray) {
|
||||
public FixedByteArrayField(ByteArray byteArray, String fieldName) {
|
||||
value = new byte[byteArray.size()];
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.ItemType;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
@ -46,103 +46,97 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
||||
/** the endianness tag */
|
||||
private static final int ENDIAN_TAG = 0x12345678;
|
||||
|
||||
private final Field[] fields;
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
private final FixedByteArrayField magic;
|
||||
private final IntegerField checksum;
|
||||
private final FixedByteArrayField signature;
|
||||
private final IntegerField fileSize;
|
||||
private final IntegerField headerSize;
|
||||
private final IntegerField endianTag;
|
||||
private final IntegerField linkSize;
|
||||
private final IntegerField linkOff;
|
||||
private final IntegerField mapOff;
|
||||
private final SectionHeaderInfo StringIdsInfo;
|
||||
private final SectionHeaderInfo TypeIdsInfo;
|
||||
private final SectionHeaderInfo ProtoIdsInfo;
|
||||
private final SectionHeaderInfo FieldIdsInfo;
|
||||
private final SectionHeaderInfo MethodIdsInfo;
|
||||
private final SectionHeaderInfo ClassDefsInfo;
|
||||
private final IntegerField dataSize;
|
||||
private final IntegerField dataOff;
|
||||
private final FixedByteArrayField magicField;
|
||||
private final IntegerField checksumField;
|
||||
private final FixedByteArrayField signatureField;
|
||||
private final IntegerField fileSizeField;
|
||||
private final IntegerField headerSizeField;
|
||||
private final IntegerField endianTagField;
|
||||
private final IntegerField linkSizeField;
|
||||
private final IntegerField linkOffField;
|
||||
private final IntegerField mapOffField;
|
||||
private final SectionHeaderInfo StringIdsHeaderField;
|
||||
private final SectionHeaderInfo TypeIdsHeaderField;
|
||||
private final SectionHeaderInfo ProtoIdsHeaderField;
|
||||
private final SectionHeaderInfo FieldIdsHeaderField;
|
||||
private final SectionHeaderInfo MethodIdsHeaderField;
|
||||
private final SectionHeaderInfo ClassDefsHeaderField;
|
||||
private final IntegerField dataSizeField;
|
||||
private final IntegerField dataOffField;
|
||||
|
||||
public HeaderItem(final DexFile file, int index) throws UnsupportedEncodingException {
|
||||
super(index);
|
||||
|
||||
fields = new Field[] {
|
||||
magic = new FixedByteArrayField(MAGIC.getBytes("US-ASCII")),
|
||||
checksum = new IntegerField() {
|
||||
public void writeTo(Output out) {
|
||||
magicField = new FixedByteArrayField(MAGIC.getBytes("US-ASCII"), "magic"),
|
||||
checksumField = new IntegerField("checksum") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(0);
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
signature = new FixedByteArrayField(20) {
|
||||
public void writeTo(Output out) {
|
||||
signatureField = new FixedByteArrayField(20, "signature") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
value[i] = 0;
|
||||
}
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
fileSize = new IntegerField() {
|
||||
public void writeTo(Output out) {
|
||||
fileSizeField = new IntegerField("file_size") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(file.getFileSize());
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
headerSize = new IntegerField(HEADER_SIZE),
|
||||
endianTag = new IntegerField(ENDIAN_TAG),
|
||||
linkSize = new IntegerField(0),
|
||||
linkOff = new IntegerField(0),
|
||||
mapOff = new IntegerField() {
|
||||
public void writeTo(Output out) {
|
||||
headerSizeField = new IntegerField(HEADER_SIZE,"header_size"),
|
||||
endianTagField = new IntegerField(ENDIAN_TAG,"endian_tag"),
|
||||
linkSizeField = new IntegerField(0,"link_size"),
|
||||
linkOffField = new IntegerField(0,"link_off"),
|
||||
mapOffField = new IntegerField("map_off") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(file.MapSection.getOffset());
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
StringIdsInfo = new SectionHeaderInfo() {
|
||||
StringIdsHeaderField = new SectionHeaderInfo("string_ids") {
|
||||
protected Section getSection() {
|
||||
return file.StringIdsSection;
|
||||
}
|
||||
},
|
||||
TypeIdsInfo = new SectionHeaderInfo() {
|
||||
TypeIdsHeaderField = new SectionHeaderInfo("type_ids") {
|
||||
protected Section getSection() {
|
||||
return file.TypeIdsSection;
|
||||
}
|
||||
},
|
||||
ProtoIdsInfo = new SectionHeaderInfo() {
|
||||
ProtoIdsHeaderField = new SectionHeaderInfo("proto_ids") {
|
||||
protected Section getSection() {
|
||||
return file.ProtoIdsSection;
|
||||
}
|
||||
},
|
||||
FieldIdsInfo = new SectionHeaderInfo() {
|
||||
FieldIdsHeaderField = new SectionHeaderInfo("field_ids") {
|
||||
protected Section getSection() {
|
||||
return file.FieldIdsSection;
|
||||
}
|
||||
},
|
||||
MethodIdsInfo = new SectionHeaderInfo() {
|
||||
MethodIdsHeaderField = new SectionHeaderInfo("method_ids") {
|
||||
protected Section getSection() {
|
||||
return file.MethodIdsSection;
|
||||
}
|
||||
},
|
||||
ClassDefsInfo = new SectionHeaderInfo() {
|
||||
ClassDefsHeaderField = new SectionHeaderInfo("class_defs") {
|
||||
protected Section getSection() {
|
||||
return file.ClassDefsSection;
|
||||
}
|
||||
},
|
||||
dataSize = new IntegerField() {
|
||||
public void writeTo(Output out) {
|
||||
dataSizeField = new IntegerField("data_size") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(file.getDataSize());
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
dataOff = new IntegerField() {
|
||||
public void writeTo(Output out) {
|
||||
dataOffField = new IntegerField("data_off") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(file.getDataOffset());
|
||||
super.writeTo(out);
|
||||
}
|
||||
@ -151,7 +145,7 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
||||
}
|
||||
|
||||
public int getMapOffset() {
|
||||
return mapOff.getCachedValue();
|
||||
return mapOffField.getCachedValue();
|
||||
}
|
||||
|
||||
protected int getAlignment() {
|
||||
@ -162,6 +156,10 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
||||
return ItemType.TYPE_HEADER_ITEM;
|
||||
}
|
||||
|
||||
public String getConciseIdentity() {
|
||||
return "header_item";
|
||||
}
|
||||
|
||||
public int compareTo(HeaderItem o) {
|
||||
//there is only 1 header item
|
||||
return 0;
|
||||
|
@ -29,18 +29,7 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
public abstract class IndexedItem<T extends IndexedItem> extends Item<T> implements Comparable<T> {
|
||||
private int index;
|
||||
|
||||
protected IndexedItem(int 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;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class IndexedItemReference<T extends IndexedItem<T>> extends
|
||||
ItemReference<T,IndexedItemReference<T>> implements Comparable<IndexedItemReference<T>> {
|
||||
private final CachedIntegerValueField underlyingField;
|
||||
|
||||
public IndexedItemReference(IndexedSection<T> section, CachedIntegerValueField underlyingField) {
|
||||
super(section);
|
||||
this.underlyingField = underlyingField;
|
||||
public IndexedItemReference(IndexedSection<T> section, CachedIntegerValueField underlyingField,
|
||||
String fieldName) {
|
||||
super(section, underlyingField, fieldName);
|
||||
}
|
||||
|
||||
public IndexedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField) {
|
||||
super(dexFile, item);
|
||||
this.underlyingField = underlyingField;
|
||||
}
|
||||
|
||||
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 IndexedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField,
|
||||
String fieldName) {
|
||||
super(dexFile, item, underlyingField, fieldName);
|
||||
}
|
||||
|
||||
public IndexedSection<T> getSection() {
|
||||
return (IndexedSection<T>)super.getSection();
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
if (getReference() != null) {
|
||||
underlyingField.cacheValue(getReference().getIndex());
|
||||
protected int getReferenceValue() {
|
||||
T item = getReference();
|
||||
if (item == null) {
|
||||
return -1;
|
||||
} 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) {
|
||||
|
@ -28,21 +28,16 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
|
||||
public class IntegerField extends CachedIntegerValueField {
|
||||
protected int value = 0;
|
||||
|
||||
public IntegerField() {
|
||||
public class IntegerField extends CachedIntegerValueField<IntegerField> {
|
||||
public IntegerField(String fieldName) {
|
||||
super(fieldName);
|
||||
}
|
||||
|
||||
public IntegerField(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.writeInt(value);
|
||||
public IntegerField(int value, String fieldName) {
|
||||
super(value, fieldName);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
@ -53,18 +48,7 @@ public class IntegerField extends CachedIntegerValueField {
|
||||
return offset + 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
protected void writeValue(Output out) {
|
||||
out.writeInt(value);
|
||||
}
|
||||
}
|
||||
|
@ -30,18 +30,18 @@ package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
import org.JesusFreke.dexlib.ItemType;
|
||||
|
||||
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(int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public boolean isPlaced() {
|
||||
return offset > -1;
|
||||
}
|
||||
@ -53,10 +53,9 @@ public abstract class Item<T extends Item> {
|
||||
public int place(int index, int offset) {
|
||||
offset = alignOffset(offset);
|
||||
|
||||
this.index = index;
|
||||
this.offset = offset;
|
||||
|
||||
Field[] fields = getFields();
|
||||
|
||||
for (Field field: fields) {
|
||||
offset = field.place(offset);
|
||||
}
|
||||
@ -64,23 +63,30 @@ public abstract class Item<T extends Item> {
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
for (Field field: getFields()) {
|
||||
for (Field field: fields) {
|
||||
field.readFrom(in);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
out.alignTo(getAlignment());
|
||||
|
||||
out.annotate(0, "[0x" + Integer.toHexString(this.getIndex()) + "] " + this.getItemType().getTypeName() );
|
||||
out.indent();
|
||||
|
||||
if (out.getCursor() != offset) {
|
||||
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);
|
||||
}
|
||||
|
||||
out.deindent();
|
||||
}
|
||||
|
||||
protected abstract int getAlignment();
|
||||
protected int getAlignment() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected int alignOffset(int offset) {
|
||||
int mask = getAlignment() - 1;
|
||||
@ -88,49 +94,57 @@ public abstract class Item<T extends Item> {
|
||||
return (offset + mask) & ~mask;
|
||||
}
|
||||
|
||||
protected int getOffset() {
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected abstract Field[] getFields();
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public abstract ItemType getItemType();
|
||||
|
||||
public void copyTo(DexFile dexFile, T copy) {
|
||||
Field[] fields = getFields();
|
||||
Field[] fieldsCopy = copy.getFields();
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
fields[i].copyTo(dexFile, fieldsCopy[i]);
|
||||
fields[i].copyTo(dexFile, copy.fields[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int h = 1;
|
||||
for (Field field: getFields()) {
|
||||
for (Field field: fields) {
|
||||
h = h*31 + field.hashCode();
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Item)) {
|
||||
if (!this.getClass().isInstance(o)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Item other = (Item)o;
|
||||
Field[] fields = getFields();
|
||||
Field[] otherFields = other.getFields();
|
||||
|
||||
if (fields.length != otherFields.length) {
|
||||
if (fields.length != other.fields.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if (!fields[i].equals(otherFields[i])) {
|
||||
if (!fields[i].equals(other.fields[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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> {
|
||||
private T item = null;
|
||||
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.underlyingField = underlyingField;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public ItemReference(DexFile dexFile, T item) {
|
||||
public ItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField, String fieldName) {
|
||||
if (item != null) {
|
||||
section = dexFile.getSectionForItem(item);
|
||||
this.item = item;
|
||||
}
|
||||
this.underlyingField = underlyingField;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public T getReference() {
|
||||
@ -65,6 +74,34 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
|
||||
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() {
|
||||
if (item == null) {
|
||||
return 0;
|
||||
@ -84,4 +121,20 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
|
||||
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;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Leb128Utils;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
|
||||
public class Leb128Field extends CachedIntegerValueField {
|
||||
protected int value;
|
||||
|
||||
public Leb128Field() {
|
||||
public Leb128Field(String fieldName) {
|
||||
super(fieldName);
|
||||
}
|
||||
|
||||
public Leb128Field(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.writeUnsignedLeb128(value);
|
||||
public Leb128Field(int value, String fieldName) {
|
||||
super(value, fieldName);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
@ -54,11 +49,7 @@ public class Leb128Field extends CachedIntegerValueField {
|
||||
return offset + Leb128Utils.unsignedLeb128Size(value);
|
||||
}
|
||||
|
||||
public int getCachedValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void cacheValue(int value) {
|
||||
this.value = value;
|
||||
public void writeValue(Output out) {
|
||||
out.writeUnsignedLeb128(value);
|
||||
}
|
||||
}
|
||||
|
@ -28,22 +28,17 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Leb128Utils;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
|
||||
public class Leb128p1Field extends CachedIntegerValueField {
|
||||
protected int value;
|
||||
|
||||
public Leb128p1Field() {
|
||||
public Leb128p1Field(String fieldName) {
|
||||
super(fieldName);
|
||||
}
|
||||
|
||||
public Leb128p1Field(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.writeUnsignedLeb128(value + 1);
|
||||
public Leb128p1Field(int value, String fieldName) {
|
||||
super(value, fieldName);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
@ -54,11 +49,7 @@ public class Leb128p1Field extends CachedIntegerValueField {
|
||||
return offset + Leb128Utils.unsignedLeb128Size(value + 1);
|
||||
}
|
||||
|
||||
public int getCachedValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void cacheValue(int value) {
|
||||
this.value = value;
|
||||
public void writeValue(Output out) {
|
||||
out.writeUnsignedLeb128(value + 1);
|
||||
}
|
||||
}
|
||||
|
@ -29,11 +29,11 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ListSizeField extends CachedIntegerValueField {
|
||||
public class ListSizeField implements Field<ListSizeField> {
|
||||
private final ArrayList<?> list;
|
||||
private final CachedIntegerValueField underlyingField;
|
||||
|
||||
@ -42,13 +42,14 @@ public class ListSizeField extends CachedIntegerValueField {
|
||||
this.underlyingField = underlyingField;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
underlyingField.writeTo(out);
|
||||
}
|
||||
|
||||
public void readFrom(Input 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
|
||||
*/
|
||||
int listSize = Math.abs(underlyingField.getCachedValue());
|
||||
@ -65,6 +66,10 @@ public class ListSizeField extends CachedIntegerValueField {
|
||||
return underlyingField.place(offset);
|
||||
}
|
||||
|
||||
public void copyTo(DexFile dexFile, ListSizeField copy) {
|
||||
//nothing to do, the value is retrieved from the list
|
||||
}
|
||||
|
||||
public int getCachedValue() {
|
||||
return underlyingField.getCachedValue();
|
||||
}
|
||||
|
@ -29,32 +29,20 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.ItemType;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class MapField extends CompositeField<MapField> {
|
||||
private final Field[] fields;
|
||||
|
||||
public ItemType getSectionItemType() {
|
||||
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;
|
||||
private final ShortIntegerField sectionTypeField;
|
||||
private final ShortIntegerField unusedField;
|
||||
private final SectionHeaderInfo sectionInfoField;
|
||||
|
||||
public MapField(final DexFile dexFile) {
|
||||
super("map_entry");
|
||||
fields = new Field[] {
|
||||
sectionType = new ShortIntegerField(),
|
||||
unused = new ShortIntegerField((short)0),
|
||||
sectionInfo = new SectionHeaderInfo() {
|
||||
//TODO: add an annotation for the item type
|
||||
sectionTypeField = new ShortIntegerField("type"),
|
||||
unusedField = new ShortIntegerField((short)0, "not used"),
|
||||
sectionInfoField = new SectionHeaderInfo("section") {
|
||||
protected Section getSection() {
|
||||
return dexFile.getSectionForType(getSectionItemType());
|
||||
}
|
||||
@ -63,26 +51,19 @@ public class MapField extends CompositeField<MapField> {
|
||||
}
|
||||
|
||||
public MapField(final DexFile dexFile, short sectionType) {
|
||||
fields = new Field[] {
|
||||
this.sectionType = new ShortIntegerField(sectionType),
|
||||
this.unused = new ShortIntegerField((short)0),
|
||||
this.sectionInfo = new SectionHeaderInfo() {
|
||||
protected Section getSection() {
|
||||
return dexFile.getSectionForType(getSectionItemType());
|
||||
}
|
||||
}
|
||||
};
|
||||
this(dexFile);
|
||||
sectionTypeField.cacheValue(sectionType);
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
return super.place(offset);
|
||||
public ItemType getSectionItemType() {
|
||||
return ItemType.fromInt(sectionTypeField.getCachedValue());
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
super.writeTo(out);
|
||||
public int getSectionSize() {
|
||||
return sectionInfoField.getSectionSize();
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
public int getSectionOffset() {
|
||||
return sectionInfoField.getSectionOffset();
|
||||
}
|
||||
}
|
||||
|
@ -29,22 +29,21 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.ItemType;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class MapItem extends IndexedItem<MapItem> {
|
||||
private final Field[] fields;
|
||||
private ArrayList<MapField> mapEntries = new ArrayList<MapField>();
|
||||
|
||||
public MapItem(final DexFile dexFile, int index) {
|
||||
super(index);
|
||||
|
||||
fields = new Field[] {
|
||||
new ListSizeField(mapEntries, new IntegerField()),
|
||||
new FieldListField<MapField>(mapEntries) {
|
||||
new ListSizeField(mapEntries, new IntegerField("size")),
|
||||
new FieldListField<MapField>(mapEntries, "map_entry") {
|
||||
protected MapField make() {
|
||||
return new MapField(dexFile);
|
||||
}
|
||||
@ -64,7 +63,7 @@ public class MapItem extends IndexedItem<MapItem> {
|
||||
return super.place(index, offset);
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
Collections.sort(mapEntries, new Comparator<MapField>() {
|
||||
|
||||
public int compare(MapField o1, MapField o2) {
|
||||
@ -108,10 +107,6 @@ public class MapItem extends IndexedItem<MapItem> {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_MAP_LIST;
|
||||
}
|
||||
@ -128,6 +123,10 @@ public class MapItem extends IndexedItem<MapItem> {
|
||||
return getClass() == o.getClass();
|
||||
}
|
||||
|
||||
public String getConciseIdentity() {
|
||||
return "map_item";
|
||||
}
|
||||
|
||||
public int compareTo(MapItem o) {
|
||||
//there is only 1 map item
|
||||
return 1;
|
||||
|
@ -29,65 +29,60 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
public class MethodIdItem extends IndexedItem<MethodIdItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<TypeIdItem> classType;
|
||||
private final IndexedItemReference<ProtoIdItem> prototype;
|
||||
private final IndexedItemReference<StringIdItem> methodName;
|
||||
private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
|
||||
private final IndexedItemReference<ProtoIdItem> prototypeReferenceField;
|
||||
private final IndexedItemReference<StringIdItem> methodNameReferenceField;
|
||||
|
||||
public MethodIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
fields = new Field[] {
|
||||
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()),
|
||||
prototype = new IndexedItemReference<ProtoIdItem>(dexFile.ProtoIdsSection, new ShortIntegerField()),
|
||||
methodName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField())
|
||||
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||
new ShortIntegerField(null), "class_idx"),
|
||||
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) {
|
||||
super(-1);
|
||||
fields = new Field[] {
|
||||
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new ShortIntegerField()),
|
||||
this.prototype = new IndexedItemReference<ProtoIdItem>(dexFile, prototype, new ShortIntegerField()),
|
||||
this.methodName = new IndexedItemReference<StringIdItem>(dexFile, methodName, new IntegerField())
|
||||
};
|
||||
this(dexFile, -1);
|
||||
classTypeReferenceField.setReference(classType);
|
||||
prototypeReferenceField.setReference(prototype);
|
||||
methodNameReferenceField.setReference(methodName);
|
||||
}
|
||||
|
||||
public MethodIdItem(DexFile dexFile, TypeIdItem classType, String methodName, ProtoIdItem prototype) {
|
||||
this(dexFile, classType, new StringIdItem(dexFile, methodName), prototype);
|
||||
}
|
||||
|
||||
|
||||
protected int getAlignment() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_METHOD_ID_ITEM;
|
||||
}
|
||||
|
||||
public TypeIdItem getClassType() {
|
||||
return classType.getReference();
|
||||
public String getConciseIdentity() {
|
||||
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() {
|
||||
return methodName.getReference().toString();
|
||||
return methodNameReferenceField.getReference().getStringValue();
|
||||
}
|
||||
|
||||
public void setClassType(TypeIdItem newClassType) {
|
||||
classType.setReference(newClassType);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return classType.getReference().toString() + " - " + methodName.getReference().toString();
|
||||
}
|
||||
|
||||
public int getParameterWordCount(boolean isStatic) {
|
||||
return prototype.getReference().getParameterWordCount() + (isStatic?0:1);
|
||||
public int getParameterRegisterCount(boolean isStatic) {
|
||||
return prototypeReferenceField.getReference().getParameterRegisterCount() + (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
|
||||
*/
|
||||
public int getParameterCount() {
|
||||
return prototype.getReference().getParameterCount();
|
||||
return prototypeReferenceField.getReference().getParameterCount();
|
||||
}
|
||||
|
||||
public int compareTo(MethodIdItem o) {
|
||||
int result = classType.compareTo(o.classType);
|
||||
int result = classTypeReferenceField.compareTo(o.classTypeReferenceField);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = methodName.compareTo(o.methodName);
|
||||
result = methodNameReferenceField.compareTo(o.methodNameReferenceField);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return prototype.compareTo(o.prototype);
|
||||
return prototypeReferenceField.compareTo(o.prototypeReferenceField);
|
||||
}
|
||||
}
|
||||
|
@ -28,26 +28,31 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.ByteArray;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class NullTerminatedByteArrayField implements Field<NullTerminatedByteArrayField> {
|
||||
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();
|
||||
}
|
||||
|
||||
public NullTerminatedByteArrayField(ByteArray byteArray) {
|
||||
public NullTerminatedByteArrayField(ByteArray byteArray, String fieldName) {
|
||||
this(fieldName);
|
||||
value = new byte[byteArray.size()];
|
||||
byteArray.getBytes(value, 0);
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
out.annotate(fieldName);
|
||||
out.write(value);
|
||||
out.writeByte(0);
|
||||
}
|
||||
|
@ -29,8 +29,7 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
public abstract class OffsettedItem<T extends OffsettedItem<T>> extends Item<T> {
|
||||
|
||||
public OffsettedItem(int offset) {
|
||||
super(offset);
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
|
@ -28,56 +28,41 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public class OffsettedItemReference<T extends OffsettedItem<T>> extends
|
||||
ItemReference<T,OffsettedItemReference<T>> {
|
||||
private final CachedIntegerValueField underlyingField;
|
||||
|
||||
public OffsettedItemReference(OffsettedSection<T> section, CachedIntegerValueField underlyingField) {
|
||||
super(section);
|
||||
this.underlyingField = underlyingField;
|
||||
public OffsettedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField,
|
||||
String fieldName) {
|
||||
super(dexFile, item, underlyingField, fieldName);
|
||||
}
|
||||
|
||||
public OffsettedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField) {
|
||||
super(dexFile, item);
|
||||
this.underlyingField = underlyingField;
|
||||
public OffsettedItemReference(OffsettedSection<T> section, CachedIntegerValueField underlyingField,
|
||||
String fieldName) {
|
||||
super(section, underlyingField, fieldName);
|
||||
}
|
||||
|
||||
|
||||
public OffsettedSection<T> getSection() {
|
||||
return (OffsettedSection<T>)super.getSection();
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
protected int getReferenceValue() {
|
||||
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) {
|
||||
underlyingField.cacheValue(0);
|
||||
return 0;
|
||||
} else {
|
||||
underlyingField.cacheValue(item.getOffset());
|
||||
}
|
||||
|
||||
underlyingField.writeTo(out);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
underlyingField.readFrom(in);
|
||||
if (underlyingField.getCachedValue() != 0) {
|
||||
setReference(getSection().getByOffset(underlyingField.getCachedValue()));
|
||||
return item.getOffset();
|
||||
}
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
if (getReference() != null) {
|
||||
underlyingField.cacheValue(getReference().getOffset());
|
||||
} else {
|
||||
underlyingField.cacheValue(0);
|
||||
protected T getReferencedItem(int referenceValue) {
|
||||
if (referenceValue == 0) {
|
||||
return null;
|
||||
}
|
||||
return underlyingField.place(offset);
|
||||
return getSection().getByOffset(referenceValue);
|
||||
}
|
||||
}
|
||||
|
@ -33,40 +33,41 @@ import org.JesusFreke.dexlib.ItemType;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<StringIdItem> shortyDescriptor;
|
||||
private final IndexedItemReference<TypeIdItem> returnType;
|
||||
private final OffsettedItemReference<TypeListItem> parameters;
|
||||
private final IndexedItemReference<StringIdItem> shortyDescriptorReferenceField;
|
||||
private final IndexedItemReference<TypeIdItem> returnTypeReferenceField;
|
||||
private final OffsettedItemReference<TypeListItem> parametersReferenceField;
|
||||
|
||||
public ProtoIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
fields = new Field[] {
|
||||
shortyDescriptor = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()),
|
||||
returnType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()),
|
||||
parameters = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection, new IntegerField())
|
||||
shortyDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||
new IntegerField(null), "shorty_idx"),
|
||||
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)
|
||||
{
|
||||
super(-1);
|
||||
StringIdItem stringIdItem = new StringIdItem(dexFile, createShortyDescriptor(returnType, parameters));
|
||||
TypeListItem typeListItem = new TypeListItem(dexFile, parameters);
|
||||
|
||||
fields = new Field[] {
|
||||
this.shortyDescriptor = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField()),
|
||||
this.returnType = new IndexedItemReference<TypeIdItem>(dexFile, returnType, new IntegerField()),
|
||||
this.parameters = new OffsettedItemReference<TypeListItem>(dexFile, typeListItem, new IntegerField())
|
||||
};
|
||||
this(dexFile, -1);
|
||||
shortyDescriptorReferenceField.setReference(
|
||||
new StringIdItem(dexFile, createShortyDescriptor(returnType, parameters)));
|
||||
returnTypeReferenceField.setReference(returnType);
|
||||
if (parameters != null && parameters.size() > 0) {
|
||||
parametersReferenceField.setReference(new TypeListItem(dexFile, parameters));
|
||||
}
|
||||
}
|
||||
|
||||
private String createShortyDescriptor(TypeIdItem returnType, ArrayList<TypeIdItem> parameters) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(returnType.toShorty());
|
||||
|
||||
for (TypeIdItem typeIdItem: parameters) {
|
||||
sb.append(typeIdItem.toShorty());
|
||||
if (parameters != null) {
|
||||
for (TypeIdItem typeIdItem: parameters) {
|
||||
sb.append(typeIdItem.toShorty());
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@ -75,18 +76,17 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public int getParameterWordCount() {
|
||||
TypeListItem typeList = parameters.getReference();
|
||||
public int getParameterRegisterCount() {
|
||||
TypeListItem typeList = parametersReferenceField.getReference();
|
||||
if (typeList == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return typeList.getWordCount();
|
||||
return typeList.getRegisterCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int getParameterCount() {
|
||||
TypeListItem typeList = parameters.getReference();
|
||||
TypeListItem typeList = parametersReferenceField.getReference();
|
||||
if (typeList == null) {
|
||||
return 0;
|
||||
} else {
|
||||
@ -94,29 +94,44 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
||||
}
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_PROTO_ID_ITEM;
|
||||
}
|
||||
|
||||
public int compareTo(ProtoIdItem o) {
|
||||
int result = returnType.compareTo(o.returnType);
|
||||
int result = returnTypeReferenceField.compareTo(o.returnTypeReferenceField);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
TypeListItem thisParameters = parameters.getReference();
|
||||
TypeListItem thisParameters = parametersReferenceField.getReference();
|
||||
if (thisParameters == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return thisParameters.compareTo(o.parameters.getReference());
|
||||
return thisParameters.compareTo(o.parametersReferenceField.getReference());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return shortyDescriptor.toString();
|
||||
public String getConciseIdentity() {
|
||||
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.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -56,14 +57,14 @@ public abstract class Section<T extends Item> {
|
||||
for (int i=0; i < items.size(); i++) {
|
||||
T item = items.get(i);
|
||||
if (item == null) {
|
||||
items.remove(i--);
|
||||
continue;
|
||||
throw new RuntimeException("This section contains a null item");
|
||||
}
|
||||
offset = item.place(i, offset);
|
||||
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
|
||||
* 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
|
||||
* (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++) {
|
||||
T item = items.get(i);
|
||||
if (item == null) {
|
||||
throw new RuntimeException("Cannot write section because all items haven't been initialized");
|
||||
}
|
||||
item.writeTo(out);
|
||||
out.annotate(0, " ");
|
||||
}
|
||||
out.annotate(0, " ");
|
||||
}
|
||||
|
||||
public abstract void readFrom(int size, Input in);
|
||||
|
||||
protected void setSize(int 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);
|
||||
|
@ -28,56 +28,44 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.AnnotatedOutput;
|
||||
|
||||
public abstract class SectionHeaderInfo implements Field<SectionHeaderInfo> {
|
||||
private int sectionSize;
|
||||
private int sectionOffset;
|
||||
public abstract class SectionHeaderInfo extends CompositeField<SectionHeaderInfo> {
|
||||
private final String sectionName;
|
||||
|
||||
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();
|
||||
|
||||
public void writeTo(Output out) {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
Section section = getSection();
|
||||
|
||||
if (!section.isPlaced()) {
|
||||
throw new RuntimeException("Trying to write a reference to a section that hasn't been placed.");
|
||||
}
|
||||
sectionSize = section.size();
|
||||
sectionOffset = section.getOffset();
|
||||
sectionSizeField.cacheValue(section.size());
|
||||
sectionOffsetField.cacheValue(section.getOffset());
|
||||
|
||||
out.writeInt(sectionSize);
|
||||
out.writeInt(sectionOffset);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
sectionSize = in.readInt();
|
||||
sectionOffset = in.readInt();
|
||||
super.writeTo(out);
|
||||
}
|
||||
|
||||
public int getSectionSize() {
|
||||
return sectionSize;
|
||||
return sectionSizeField.getCachedValue();
|
||||
}
|
||||
|
||||
public int getSectionOffset() {
|
||||
return sectionOffset;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
return sectionOffsetField.getCachedValue();
|
||||
}
|
||||
}
|
||||
|
@ -28,21 +28,16 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
|
||||
public class ShortIntegerField extends CachedIntegerValueField {
|
||||
protected int value = 0;
|
||||
|
||||
public ShortIntegerField() {
|
||||
public ShortIntegerField(String fieldName) {
|
||||
super(fieldName);
|
||||
}
|
||||
|
||||
public ShortIntegerField(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.writeShort(value);
|
||||
public ShortIntegerField(int value, String fieldName) {
|
||||
super(value, fieldName);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
@ -53,18 +48,7 @@ public class ShortIntegerField extends CachedIntegerValueField {
|
||||
return offset + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the short 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 = (short)value;
|
||||
protected void writeValue(Output out) {
|
||||
out.writeShort(value);
|
||||
}
|
||||
}
|
||||
|
@ -28,22 +28,17 @@
|
||||
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
import org.JesusFreke.dexlib.util.Input;
|
||||
import org.JesusFreke.dexlib.util.Leb128Utils;
|
||||
import org.JesusFreke.dexlib.util.Output;
|
||||
|
||||
public class SignedLeb128Field extends CachedIntegerValueField {
|
||||
protected int value;
|
||||
|
||||
public SignedLeb128Field() {
|
||||
public SignedLeb128Field(String fieldName) {
|
||||
super(fieldName);
|
||||
}
|
||||
|
||||
public SignedLeb128Field(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void writeTo(Output out) {
|
||||
out.writeSignedLeb128(value);
|
||||
public SignedLeb128Field(int value, String fieldName) {
|
||||
super(value, fieldName);
|
||||
}
|
||||
|
||||
public void readFrom(Input in) {
|
||||
@ -54,11 +49,7 @@ public class SignedLeb128Field extends CachedIntegerValueField {
|
||||
return offset + Leb128Utils.signedLeb128Size(value);
|
||||
}
|
||||
|
||||
public int getCachedValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void cacheValue(int value) {
|
||||
this.value = value;
|
||||
public void writeValue(Output out) {
|
||||
out.writeSignedLeb128(value);
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,6 @@ import org.JesusFreke.dexlib.util.ByteArray;
|
||||
import org.JesusFreke.dexlib.util.Utf8Utils;
|
||||
|
||||
public class StringDataItem extends OffsettedItem<StringDataItem> implements Comparable<StringDataItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private String value = null;
|
||||
|
||||
private final Leb128Field stringSize;
|
||||
@ -43,8 +41,8 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
|
||||
super(offset);
|
||||
|
||||
fields = new Field[] {
|
||||
stringSize = new Leb128Field(),
|
||||
stringByteArray = new NullTerminatedByteArrayField()
|
||||
stringSize = new Leb128Field("string_length"),
|
||||
stringByteArray = new NullTerminatedByteArrayField("data")
|
||||
};
|
||||
}
|
||||
|
||||
@ -54,24 +52,16 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
|
||||
this.value = value;
|
||||
|
||||
fields = new Field[] {
|
||||
stringSize = new Leb128Field(value.length()),
|
||||
stringByteArray = new NullTerminatedByteArrayField(Utf8Utils.stringToUtf8Bytes(value))
|
||||
stringSize = new Leb128Field(value.length(), "string_length"),
|
||||
stringByteArray = new NullTerminatedByteArrayField(Utf8Utils.stringToUtf8Bytes(value), "data")
|
||||
};
|
||||
}
|
||||
|
||||
public Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_STRING_DATA_ITEM;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
public String getStringValue() {
|
||||
if (value == null) {
|
||||
value = Utf8Utils.utf8BytesToString(new ByteArray(((NullTerminatedByteArrayField)fields[1]).value));
|
||||
}
|
||||
@ -79,7 +69,11 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getConciseIdentity() {
|
||||
return "string_data_item: " + getStringValue();
|
||||
}
|
||||
|
||||
public int compareTo(StringDataItem o) {
|
||||
return toString().compareTo(o.toString());
|
||||
return getStringValue().compareTo(o.getStringValue());
|
||||
}
|
||||
}
|
||||
|
@ -29,23 +29,19 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
public class StringIdItem extends IndexedItem<StringIdItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final OffsettedItemReference<StringDataItem> stringData;
|
||||
private final OffsettedItemReference<StringDataItem> stringDataReferenceField;
|
||||
|
||||
public StringIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
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) {
|
||||
super(-1);
|
||||
|
||||
fields = new Field[] {
|
||||
stringData = new OffsettedItemReference<StringDataItem>(dexFile, stringDataItem, new IntegerField())
|
||||
};
|
||||
this(dexFile, -1);
|
||||
stringDataReferenceField.setReference(stringDataItem);
|
||||
}
|
||||
|
||||
public StringIdItem(DexFile dexFile, String value) {
|
||||
@ -56,20 +52,20 @@ public class StringIdItem extends IndexedItem<StringIdItem> {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_STRING_ID_ITEM;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return stringData.getReference().toString();
|
||||
public String getConciseIdentity() {
|
||||
return "string_id_item: " + getStringValue();
|
||||
}
|
||||
|
||||
public String getStringValue() {
|
||||
return stringDataReferenceField.getReference().getStringValue();
|
||||
}
|
||||
|
||||
public int compareTo(StringIdItem o) {
|
||||
//sort by the string value
|
||||
return toString().compareTo(o.toString());
|
||||
return getStringValue().compareTo(o.getStringValue());
|
||||
}
|
||||
}
|
||||
|
@ -29,43 +29,35 @@
|
||||
package org.JesusFreke.dexlib;
|
||||
|
||||
public class TypeIdItem extends IndexedItem<TypeIdItem> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final IndexedItemReference<StringIdItem> type;
|
||||
private final IndexedItemReference<StringIdItem> typeDescriptorReferenceField;
|
||||
|
||||
public TypeIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
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) {
|
||||
super(-1);
|
||||
fields = new Field[] {
|
||||
type = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField())
|
||||
};
|
||||
this(dexFile, -1);
|
||||
typeDescriptorReferenceField.setReference(stringIdItem);
|
||||
}
|
||||
|
||||
public TypeIdItem(DexFile dexFile, String value) {
|
||||
super(-1);
|
||||
StringDataItem stringDataItem = new StringDataItem(value);
|
||||
StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem);
|
||||
fields = new Field[] {
|
||||
type = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField())
|
||||
};
|
||||
this(dexFile, new StringIdItem(dexFile, value));
|
||||
}
|
||||
|
||||
protected int getAlignment() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public int getWordCount() {
|
||||
String type = this.toString();
|
||||
/**
|
||||
* 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 getRegisterCount() {
|
||||
String type = this.getTypeDescriptor();
|
||||
/** Only the long and double primitive types are 2 words,
|
||||
* everything else is a single word
|
||||
*/
|
||||
@ -80,17 +72,21 @@ public class TypeIdItem extends IndexedItem<TypeIdItem> {
|
||||
return ItemType.TYPE_TYPE_ID_ITEM;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type.getReference().toString();
|
||||
public String getConciseIdentity() {
|
||||
return "type_id_item: " + getTypeDescriptor();
|
||||
}
|
||||
|
||||
public String getTypeDescriptor() {
|
||||
return typeDescriptorReferenceField.getReference().getStringValue();
|
||||
}
|
||||
|
||||
public int compareTo(TypeIdItem o) {
|
||||
//sort by the index of the StringIdItem
|
||||
return type.compareTo(o.type);
|
||||
return typeDescriptorReferenceField.compareTo(o.typeDescriptorReferenceField);
|
||||
}
|
||||
|
||||
public String toShorty() {
|
||||
String type = toString();
|
||||
String type = getTypeDescriptor();
|
||||
if (type.length() > 1) {
|
||||
return "L";
|
||||
} else {
|
||||
|
@ -32,17 +32,20 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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 ListSizeField sizeField;
|
||||
private final FieldListField<IndexedItemReference<TypeIdItem>> listField;
|
||||
|
||||
public TypeListItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
|
||||
fields = new Field[] {
|
||||
new ListSizeField(typeList, new IntegerField()),
|
||||
new FieldListField<IndexedItemReference<TypeIdItem>>(typeList) {
|
||||
sizeField = new ListSizeField(typeList, new IntegerField("size")),
|
||||
listField = new FieldListField<IndexedItemReference<TypeIdItem>>(typeList, "type_item") {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public int getWordCount() {
|
||||
public int getRegisterCount() {
|
||||
int wordCount = 0;
|
||||
for (IndexedItemReference<TypeIdItem> typeRef: typeList) {
|
||||
TypeIdItem item = typeRef.getReference();
|
||||
wordCount += item.getWordCount();
|
||||
wordCount += item.getRegisterCount();
|
||||
}
|
||||
return wordCount;
|
||||
}
|
||||
@ -91,6 +92,23 @@ public class TypeListItem extends OffsettedItem<TypeListItem> implements Compara
|
||||
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) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
|
@ -53,7 +53,7 @@ public class Format21c extends Format
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class Format35c extends Format
|
||||
|
||||
if (opcode == FILLED_NEW_ARRAY.value) {
|
||||
//check data for filled-new-array opcode
|
||||
String type = ((TypeIdItem)item).toString();
|
||||
String type = ((TypeIdItem)item).getTypeDescriptor();
|
||||
if (type.charAt(0) != '[') {
|
||||
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) {
|
||||
//check data for invoke-* opcodes
|
||||
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");
|
||||
}
|
||||
} else {
|
||||
|
@ -72,7 +72,7 @@ public class Format3rc extends Format
|
||||
|
||||
if (opcode == FILLED_NEW_ARRAY_RANGE.value) {
|
||||
//check data for filled-new-array/range opcode
|
||||
String type = ((TypeIdItem)item).toString();
|
||||
String type = ((TypeIdItem)item).getTypeDescriptor();
|
||||
if (type.charAt(0) != '[') {
|
||||
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) {
|
||||
//check data for invoke-*/range opcodes
|
||||
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");
|
||||
}
|
||||
} else {
|
||||
|
@ -30,7 +30,7 @@ package org.JesusFreke.dexlib.code;
|
||||
|
||||
import org.JesusFreke.dexlib.*;
|
||||
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> {
|
||||
private DexFile dexFile;
|
||||
@ -143,7 +143,8 @@ public final class Instruction implements Field<Instruction> {
|
||||
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) {
|
||||
//the "special instructions" must be 4 byte aligned
|
||||
out.alignTo(4);
|
||||
|
@ -34,15 +34,14 @@ import org.JesusFreke.dexlib.ByteField;
|
||||
import org.JesusFreke.dexlib.SignedLeb128Field;
|
||||
|
||||
public class AdvanceLine extends CompositeField<AdvanceLine> implements DebugInstruction<AdvanceLine> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField opcodeField;
|
||||
private final SignedLeb128Field lineDeltaField;
|
||||
|
||||
public AdvanceLine() {
|
||||
super("DBG_ADVANCE_LINE");
|
||||
fields = new Field[] {
|
||||
opcodeField = new ByteField((byte)0x02),
|
||||
lineDeltaField = new SignedLeb128Field()
|
||||
opcodeField = new ByteField((byte)0x02, "opcode"),
|
||||
lineDeltaField = new SignedLeb128Field("line_diff")
|
||||
};
|
||||
}
|
||||
|
||||
@ -51,10 +50,6 @@ public class AdvanceLine extends CompositeField<AdvanceLine> implements DebugIns
|
||||
lineDeltaField.cacheValue(lineDelta);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x02;
|
||||
}
|
||||
|
@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
|
||||
import org.JesusFreke.dexlib.*;
|
||||
|
||||
public class AdvancePC extends CompositeField<AdvancePC> implements DebugInstruction<AdvancePC> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField opcodeField;
|
||||
private final Leb128Field addressDeltaField;
|
||||
|
||||
public AdvancePC() {
|
||||
super("DBG_ADVANCE_PC");
|
||||
fields = new Field[] {
|
||||
opcodeField = new ByteField((byte)0x01),
|
||||
addressDeltaField = new Leb128Field()
|
||||
opcodeField = new ByteField((byte)0x01, "opcode"),
|
||||
addressDeltaField = new Leb128Field("addr_diff")
|
||||
};
|
||||
}
|
||||
|
||||
@ -48,10 +47,6 @@ public class AdvancePC extends CompositeField<AdvancePC> implements DebugInstruc
|
||||
addressDeltaField.cacheValue(addressDelta);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x01;
|
||||
}
|
||||
|
@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
|
||||
import org.JesusFreke.dexlib.*;
|
||||
|
||||
public class EndLocal extends CompositeField<EndLocal> implements DebugInstruction<EndLocal> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField opcode;
|
||||
private final Leb128Field registerNumber;
|
||||
|
||||
public EndLocal() {
|
||||
super("DBG_END_LOCAL");
|
||||
fields = new Field[] {
|
||||
opcode = new ByteField((byte)0x05),
|
||||
registerNumber = new Leb128Field()
|
||||
opcode = new ByteField((byte)0x05, "opcode"),
|
||||
registerNumber = new Leb128Field("register_num")
|
||||
};
|
||||
}
|
||||
|
||||
@ -48,10 +47,6 @@ public class EndLocal extends CompositeField<EndLocal> implements DebugInstructi
|
||||
this.registerNumber.cacheValue(registerNumber);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x05;
|
||||
}
|
||||
|
@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
|
||||
import org.JesusFreke.dexlib.ByteField;
|
||||
|
||||
public class EndSequence extends CompositeField<EndSequence> implements DebugInstruction<EndSequence> {
|
||||
private final Field[] fields;
|
||||
|
||||
public EndSequence() {
|
||||
super("DBG_END_SEQUENCE");
|
||||
fields = new Field[] {
|
||||
new ByteField((byte)0x00)
|
||||
new ByteField((byte)0x00, "opcode")
|
||||
};
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x00;
|
||||
}
|
||||
|
@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
|
||||
import org.JesusFreke.dexlib.*;
|
||||
|
||||
public class RestartLocal extends CompositeField<RestartLocal> implements DebugInstruction<RestartLocal> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField opcode;
|
||||
private final Leb128Field registerNumber;
|
||||
|
||||
public RestartLocal() {
|
||||
super("DBG_RESTART_LOCAL");
|
||||
fields = new Field[] {
|
||||
opcode = new ByteField((byte)0x06),
|
||||
registerNumber = new Leb128Field()
|
||||
opcode = new ByteField((byte)0x06, "opcode"),
|
||||
registerNumber = new Leb128Field("register_num")
|
||||
};
|
||||
}
|
||||
|
||||
@ -48,10 +47,6 @@ public class RestartLocal extends CompositeField<RestartLocal> implements DebugI
|
||||
this.registerNumber.cacheValue(registerNumber);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x06;
|
||||
}
|
||||
|
@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
|
||||
import org.JesusFreke.dexlib.ByteField;
|
||||
|
||||
public class SetEpilogueBegin extends CompositeField<SetEpilogueBegin> implements DebugInstruction<SetEpilogueBegin> {
|
||||
private final Field[] fields;
|
||||
|
||||
public SetEpilogueBegin() {
|
||||
super("DBG_SET_EPILOGUE_BEGIN");
|
||||
fields = new Field[] {
|
||||
new ByteField((byte)0x08)
|
||||
new ByteField((byte)0x08, "opcode")
|
||||
};
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x08;
|
||||
}
|
||||
|
@ -31,15 +31,15 @@ package org.JesusFreke.dexlib.debug;
|
||||
import org.JesusFreke.dexlib.*;
|
||||
|
||||
public class SetFile extends CompositeField<SetFile> implements DebugInstruction<SetFile> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField opcode;
|
||||
private final IndexedItemReference<StringIdItem> fileName;
|
||||
|
||||
public SetFile(DexFile dexFile) {
|
||||
super("DBG_SET_FILE");
|
||||
fields = new Field[] {
|
||||
opcode = new ByteField((byte)0x09),
|
||||
fileName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field())
|
||||
opcode = new ByteField((byte)0x09, "opcode"),
|
||||
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);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x09;
|
||||
}
|
||||
|
@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
|
||||
import org.JesusFreke.dexlib.ByteField;
|
||||
|
||||
public class SetPrologueEnd extends CompositeField<SetPrologueEnd> implements DebugInstruction<SetPrologueEnd> {
|
||||
private final Field[] fields;
|
||||
|
||||
public SetPrologueEnd() {
|
||||
super("DBG_SET_PROLOGUE_END");
|
||||
fields = new Field[] {
|
||||
new ByteField((byte)0x07)
|
||||
new ByteField((byte)0x07, "opcode")
|
||||
};
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x07;
|
||||
}
|
||||
|
@ -33,21 +33,17 @@ import org.JesusFreke.dexlib.Field;
|
||||
import org.JesusFreke.dexlib.ByteField;
|
||||
|
||||
public class SpecialOpcode extends CompositeField<SpecialOpcode> implements DebugInstruction<SpecialOpcode> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final byte opcode;
|
||||
|
||||
public SpecialOpcode(byte opcode) {
|
||||
super("SPECIAL_OPCODE");
|
||||
this.opcode = opcode;
|
||||
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() {
|
||||
return opcode;
|
||||
}
|
||||
|
@ -31,19 +31,20 @@ package org.JesusFreke.dexlib.debug;
|
||||
import org.JesusFreke.dexlib.*;
|
||||
|
||||
public class StartLocal extends CompositeField<StartLocal> implements DebugInstruction<StartLocal> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField opcodeField;
|
||||
private final SignedLeb128Field registerNumber;
|
||||
private final IndexedItemReference<StringIdItem> localName;
|
||||
private final IndexedItemReference<TypeIdItem> localType;
|
||||
|
||||
public StartLocal(DexFile dexFile) {
|
||||
super("DBG_START_LOCAL");
|
||||
fields = new Field[] {
|
||||
opcodeField = new ByteField((byte)0x03),
|
||||
registerNumber = new SignedLeb128Field(),
|
||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()),
|
||||
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128p1Field()),
|
||||
opcodeField = new ByteField((byte)0x03, "opcode"),
|
||||
registerNumber = new SignedLeb128Field("register_num"),
|
||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||
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);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
return 0x03;
|
||||
}
|
||||
|
@ -31,8 +31,6 @@ package org.JesusFreke.dexlib.debug;
|
||||
import org.JesusFreke.dexlib.*;
|
||||
|
||||
public class StartLocalExtended extends CompositeField<StartLocalExtended> implements DebugInstruction<StartLocalExtended> {
|
||||
private final Field[] fields;
|
||||
|
||||
private final ByteField opcodeField;
|
||||
//TODO: signed or unsigned leb?
|
||||
private final SignedLeb128Field registerNumber;
|
||||
@ -41,12 +39,16 @@ public class StartLocalExtended extends CompositeField<StartLocalExtended> imple
|
||||
private final IndexedItemReference<StringIdItem> signature;
|
||||
|
||||
public StartLocalExtended(DexFile dexFile) {
|
||||
super("DBG_START_LOCAL_EXTENDED");
|
||||
fields = new Field[] {
|
||||
opcodeField = new ByteField((byte)0x04),
|
||||
registerNumber = new SignedLeb128Field(),
|
||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()),
|
||||
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128p1Field()),
|
||||
signature = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field())
|
||||
opcodeField = new ByteField((byte)0x04, "opcode"),
|
||||
registerNumber = new SignedLeb128Field("register_num"),
|
||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||
new Leb128p1Field(null), "name_idx"),
|
||||
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);
|
||||
}
|
||||
|
||||
protected Field[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
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.util.ByteArrayOutput;
|
||||
import org.JesusFreke.dexlib.util.ByteArrayAnnotatedOutput;
|
||||
import org.antlr.runtime.ANTLRInputStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.Token;
|
||||
@ -38,6 +39,7 @@ import org.antlr.runtime.tree.CommonTreeNodeStream;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
|
||||
public class smali
|
||||
{
|
||||
@ -70,7 +72,8 @@ public class smali
|
||||
dexFile.place();
|
||||
try
|
||||
{
|
||||
ByteArrayOutput out = new ByteArrayOutput();
|
||||
ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
|
||||
out.enableAnnotations(120, true);
|
||||
dexFile.writeTo(out);
|
||||
|
||||
byte[] bytes = out.toByteArray();
|
||||
@ -78,6 +81,17 @@ public class smali
|
||||
DexFile.calcSignature(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.write(bytes);
|
||||
|
@ -70,7 +70,7 @@ public class TryListBuilderTest
|
||||
CodeItem.EncodedTypeAddrPair typeAddrPair = encodedCatchHandler.getHandler(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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user