- 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:
JesusFreke@JesusFreke.com 2009-05-31 07:08:04 +00:00
parent dbdfc6f468
commit 35329727a4
77 changed files with 3349 additions and 2252 deletions

File diff suppressed because it is too large Load Diff

View File

@ -36,48 +36,50 @@ import java.util.Collections;
//TODO: fix field names in dex-format.html and submit //TODO: fix field names in dex-format.html and submit
public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryItem> { public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryItem> {
private final Field[] fields;
private final ArrayList<FieldAnnotation> fieldAnnotationList = new ArrayList<FieldAnnotation>(); private final ArrayList<FieldAnnotation> fieldAnnotationList = new ArrayList<FieldAnnotation>();
private final ArrayList<MethodAnnotation> methodAnnotationList = new ArrayList<MethodAnnotation>(); private final ArrayList<MethodAnnotation> methodAnnotationList = new ArrayList<MethodAnnotation>();
private final ArrayList<ParameterAnnotation> parameterAnnotationList = new ArrayList<ParameterAnnotation>(); private final ArrayList<ParameterAnnotation> parameterAnnotationList = new ArrayList<ParameterAnnotation>();
private final OffsettedItemReference<AnnotationSetItem> classAnnotations; private final OffsettedItemReference<AnnotationSetItem> classAnnotationsReferenceField;
private final ListSizeField annotatedFieldsCount; private final ListSizeField annotatedFieldsCountField;
private final ListSizeField annotatedMethodsCount; private final ListSizeField annotatedMethodsCountField;
private final ListSizeField annotatedParametersCount; private final ListSizeField annotatedParametersCountField;
private final FieldListField<FieldAnnotation> fieldAnnotations; private final FieldListField<FieldAnnotation> fieldAnnotationListField;
private final FieldListField<MethodAnnotation> methodAnnotations; private final FieldListField<MethodAnnotation> methodAnnotationListField;
private final FieldListField<ParameterAnnotation> parameterAnnotations; private final FieldListField<ParameterAnnotation> parameterAnnotationListField;
public AnnotationDirectoryItem(final DexFile dexFile, int offset) { public AnnotationDirectoryItem(final DexFile dexFile, int offset) {
super(offset); super(offset);
fields = new Field[] { fields = new Field[] {
classAnnotations = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField()), classAnnotationsReferenceField = new OffsettedItemReference<AnnotationSetItem>(
annotatedFieldsCount = new ListSizeField(fieldAnnotationList, new IntegerField()), dexFile.AnnotationSetsSection, new IntegerField(null), "class_annotations_off"),
annotatedMethodsCount = new ListSizeField(methodAnnotationList, new IntegerField()), annotatedFieldsCountField = new ListSizeField(fieldAnnotationList, new IntegerField("fields_size")),
annotatedParametersCount = new ListSizeField(parameterAnnotationList, new IntegerField()), annotatedMethodsCountField = new ListSizeField(methodAnnotationList,
fieldAnnotations = new FieldListField<FieldAnnotation>(fieldAnnotationList) { new IntegerField("annotated_methods_size")),
annotatedParametersCountField = new ListSizeField(parameterAnnotationList,
new IntegerField("annotated_parameters_size")),
fieldAnnotationListField = new FieldListField<FieldAnnotation>(fieldAnnotationList,
"field_annotations") {
protected FieldAnnotation make() { protected FieldAnnotation make() {
return new FieldAnnotation(dexFile); return new FieldAnnotation(dexFile);
} }
}, },
methodAnnotations = new FieldListField<MethodAnnotation>(methodAnnotationList) { methodAnnotationListField = new FieldListField<MethodAnnotation>(methodAnnotationList,
"method_annotations") {
protected MethodAnnotation make() { protected MethodAnnotation make() {
return new MethodAnnotation(dexFile); return new MethodAnnotation(dexFile);
} }
}, },
parameterAnnotations = new FieldListField<ParameterAnnotation>(parameterAnnotationList) { parameterAnnotationListField = new FieldListField<ParameterAnnotation>(parameterAnnotationList,
"parameter_annotations") {
protected ParameterAnnotation make() { protected ParameterAnnotation make() {
return new ParameterAnnotation(dexFile); return new ParameterAnnotation(dexFile);
} }
} }
}; };
} }
public AnnotationDirectoryItem(final DexFile dexFile, public AnnotationDirectoryItem(final DexFile dexFile,
AnnotationSetItem classAnnotations, AnnotationSetItem classAnnotations,
List<FieldAnnotation> fieldAnnotations, List<FieldAnnotation> fieldAnnotations,
@ -85,22 +87,21 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
List<ParameterAnnotation> parameterAnnotations) { List<ParameterAnnotation> parameterAnnotations) {
this(dexFile, -1); this(dexFile, -1);
this.classAnnotations.setReference(classAnnotations); classAnnotationsReferenceField.setReference(classAnnotations);
if (fieldAnnotations != null) { if (fieldAnnotationListField != null) {
this.fieldAnnotationList.addAll(fieldAnnotations); fieldAnnotationList.addAll(fieldAnnotations);
} }
if (methodAnnotations != null) { if (methodAnnotationListField != null) {
this.methodAnnotationList.addAll(methodAnnotations); methodAnnotationList.addAll(methodAnnotations);
} }
if (parameterAnnotations != null) { if (parameterAnnotations != null) {
this.parameterAnnotationList.addAll(parameterAnnotations); parameterAnnotationList.addAll(parameterAnnotations);
} }
} }
@Override
public int place(int index, int offset) public int place(int index, int offset)
{ {
Collections.sort(fieldAnnotationList); Collections.sort(fieldAnnotationList);
@ -113,54 +114,53 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
return 4; return 4;
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM; return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
} }
public String getConciseIdentity() {
return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
}
public static class FieldAnnotation extends CompositeField<FieldAnnotation> public static class FieldAnnotation extends CompositeField<FieldAnnotation>
implements Comparable<FieldAnnotation> { implements Comparable<FieldAnnotation> {
private final Field[] fields; private final IndexedItemReference<FieldIdItem> fieldReferenceField;
private final OffsettedItemReference<AnnotationSetItem> annotationSetReferenceField;
private final IndexedItemReference<FieldIdItem> field;
private final OffsettedItemReference<AnnotationSetItem> annotationSet;
public FieldAnnotation(DexFile dexFile) { public FieldAnnotation(DexFile dexFile) {
super("field_annotation");
fields = new Field[] { fields = new Field[] {
field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection, new IntegerField()), fieldReferenceField = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection,
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField()) new IntegerField(null), "field_idx"),
annotationSetReferenceField = new OffsettedItemReference<AnnotationSetItem>(
dexFile.AnnotationSetsSection, new IntegerField(null), "annotations_off")
}; };
} }
public FieldAnnotation(DexFile dexFile, FieldIdItem field, AnnotationSetItem annotationSet) { public FieldAnnotation(DexFile dexFile, FieldIdItem field, AnnotationSetItem annotationSet) {
this(dexFile); this(dexFile);
this.field.setReference(field); this.fieldReferenceField.setReference(field);
this.annotationSet.setReference(annotationSet); this.annotationSetReferenceField.setReference(annotationSet);
}
protected Field[] getFields() {
return fields;
} }
public int compareTo(FieldAnnotation o) { public int compareTo(FieldAnnotation o) {
return ((Integer)field.getReference().getIndex()).compareTo(o.field.getReference().getIndex()); return ((Integer) fieldReferenceField.getReference().getIndex()).compareTo(
o.fieldReferenceField.getReference().getIndex());
} }
} }
public static class MethodAnnotation extends CompositeField<MethodAnnotation> public static class MethodAnnotation extends CompositeField<MethodAnnotation>
implements Comparable<MethodAnnotation> { implements Comparable<MethodAnnotation> {
private final Field[] fields;
private final IndexedItemReference<MethodIdItem> method; private final IndexedItemReference<MethodIdItem> method;
private final OffsettedItemReference<AnnotationSetItem> annotationSet; private final OffsettedItemReference<AnnotationSetItem> annotationSet;
public MethodAnnotation(DexFile dexFile) { public MethodAnnotation(DexFile dexFile) {
super("method_annotation");
fields = new Field[] { fields = new Field[] {
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()), method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField()) new IntegerField(null), "method_idx"),
annotationSet = new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection,
new IntegerField(null), "annotations_off")
}; };
} }
@ -170,10 +170,6 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
this.annotationSet.setReference(annotationSet); this.annotationSet.setReference(annotationSet);
} }
protected Field[] getFields() {
return fields;
}
public int compareTo(MethodAnnotation o) { public int compareTo(MethodAnnotation o) {
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex()); return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
} }
@ -181,16 +177,16 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
public static class ParameterAnnotation extends CompositeField<ParameterAnnotation> public static class ParameterAnnotation extends CompositeField<ParameterAnnotation>
implements Comparable<ParameterAnnotation> { implements Comparable<ParameterAnnotation> {
private final Field[] fields;
private final IndexedItemReference<MethodIdItem> method; private final IndexedItemReference<MethodIdItem> method;
private final OffsettedItemReference<AnnotationSetRefList> parameterAnnotations; private final OffsettedItemReference<AnnotationSetRefList> parameterAnnotations;
public ParameterAnnotation(DexFile dexFile) { public ParameterAnnotation(DexFile dexFile) {
super("parameter_annotation");
fields = new Field[] { fields = new Field[] {
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, new IntegerField()), method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
new IntegerField(null), "method_idx"),
parameterAnnotations = new OffsettedItemReference<AnnotationSetRefList>( parameterAnnotations = new OffsettedItemReference<AnnotationSetRefList>(
dexFile.AnnotationSetRefListsSection, new IntegerField()) dexFile.AnnotationSetRefListsSection, new IntegerField(null), "annotations_off")
}; };
} }
@ -200,10 +196,6 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
this.parameterAnnotations.setReference(parameterAnnotations); this.parameterAnnotations.setReference(parameterAnnotations);
} }
protected Field[] getFields() {
return fields;
}
public int compareTo(ParameterAnnotation o) { public int compareTo(ParameterAnnotation o) {
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex()); return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
} }

View File

@ -32,17 +32,15 @@ import org.JesusFreke.dexlib.EncodedValue.AnnotationEncodedValueSubField;
import org.JesusFreke.dexlib.ItemType; import org.JesusFreke.dexlib.ItemType;
public class AnnotationItem extends OffsettedItem<AnnotationItem> { public class AnnotationItem extends OffsettedItem<AnnotationItem> {
private final Field[] fields; private final ByteField visibilityField;
private final AnnotationEncodedValueSubField annotationField;
private final ByteField visibility;
private final AnnotationEncodedValueSubField annotation;
public AnnotationItem(DexFile dexFile, int offset) { public AnnotationItem(DexFile dexFile, int offset) {
super(offset); super(offset);
fields = new Field[] { fields = new Field[] {
visibility = new ByteField(), visibilityField = new ByteField("visibility"),
annotation = new AnnotationEncodedValueSubField(dexFile) annotationField = new AnnotationEncodedValueSubField(dexFile)
}; };
} }
@ -51,41 +49,16 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
super(-1); super(-1);
fields = new Field[] { fields = new Field[] {
this.visibility = new ByteField(visibility.value), this.visibilityField = new ByteField(visibility.value, "visibility"),
this.annotation = annotation this.annotationField = annotation
}; };
} }
protected int getAlignment() {
return 1;
}
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_ANNOTATION_ITEM; return ItemType.TYPE_ANNOTATION_ITEM;
} }
public void copyTo(DexFile dexFile, AnnotationItem copy) { public String getConciseIdentity() {
visibility.copyTo(dexFile, copy.visibility); return "annotation_item @0x" + Integer.toHexString(getOffset());
annotation.copyTo(dexFile, copy.annotation);
}
public int hashCode() {
return visibility.hashCode() * 31 + annotation.hashCode();
}
public boolean equals(Object o) {
if (!(o instanceof AnnotationItem)) {
return false;
}
AnnotationItem other = (AnnotationItem)o;
if (!visibility.equals(other.visibility))
return false;
return annotation.equals(other.annotation);
} }
} }

View File

@ -34,23 +34,22 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> { public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
private final Field[] fields;
private final ArrayList<OffsettedItemReference<AnnotationItem>> annotationReferences = private final ArrayList<OffsettedItemReference<AnnotationItem>> annotationReferences =
new ArrayList<OffsettedItemReference<AnnotationItem>>(); new ArrayList<OffsettedItemReference<AnnotationItem>>();
private final ListSizeField annotationCount; private final ListSizeField annotationCountField;
private final FieldListField<OffsettedItemReference<AnnotationItem>> annotations; private final FieldListField<OffsettedItemReference<AnnotationItem>> annotationsListField;
public AnnotationSetItem(final DexFile dexFile, int offset) { public AnnotationSetItem(final DexFile dexFile, int offset) {
super(offset); super(offset);
fields = new Field[] { fields = new Field[] {
annotationCount = new ListSizeField(annotationReferences, new IntegerField()), annotationCountField = new ListSizeField(annotationReferences, new IntegerField("size")),
annotations = new FieldListField<OffsettedItemReference<AnnotationItem>>(annotationReferences) { annotationsListField = new FieldListField<OffsettedItemReference<AnnotationItem>>(
annotationReferences, "annotation") {
protected OffsettedItemReference<AnnotationItem> make() { protected OffsettedItemReference<AnnotationItem> make() {
return new OffsettedItemReference<AnnotationItem>(dexFile.AnnotationsSection, return new OffsettedItemReference<AnnotationItem>(dexFile.AnnotationsSection,
new IntegerField()); new IntegerField(null), "annotation_off");
} }
} }
}; };
@ -60,8 +59,9 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
this(dexFile, -1); this(dexFile, -1);
for (AnnotationItem annotationItem: annotations) { for (AnnotationItem annotationItem: annotations) {
this.annotationReferences.add(new OffsettedItemReference<AnnotationItem>(dexFile, OffsettedItemReference<AnnotationItem> annotationReference = annotationsListField.make();
annotationItem, new IntegerField())); annotationReference.setReference(annotationItem);
this.annotationReferences.add(annotationReference);
} }
} }
@ -69,11 +69,11 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
return 4; return 4;
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_ANNOTATION_SET_ITEM; return ItemType.TYPE_ANNOTATION_SET_ITEM;
} }
public String getConciseIdentity() {
return "annotation_set_item @0x" + Integer.toHexString(getOffset());
}
} }

View File

@ -34,22 +34,22 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> { public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
private final Field[] fields;
private final ArrayList<OffsettedItemReference<AnnotationSetItem>> annotationSetReferences = private final ArrayList<OffsettedItemReference<AnnotationSetItem>> annotationSetReferences =
new ArrayList<OffsettedItemReference<AnnotationSetItem>>(); new ArrayList<OffsettedItemReference<AnnotationSetItem>>();
private final ListSizeField annotationSetCount; private final ListSizeField annotationSetCountField;
private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSets; private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSetsListField;
public AnnotationSetRefList(final DexFile dexFile, int offset) { public AnnotationSetRefList(final DexFile dexFile, int offset) {
super(offset); super(offset);
fields = new Field[] { fields = new Field[] {
annotationSetCount = new ListSizeField(annotationSetReferences, new IntegerField()), annotationSetCountField = new ListSizeField(annotationSetReferences, new IntegerField("size")),
annotationSets = new FieldListField<OffsettedItemReference<AnnotationSetItem>>(annotationSetReferences) { annotationSetsListField = new FieldListField<OffsettedItemReference<AnnotationSetItem>>(
annotationSetReferences, "list") {
protected OffsettedItemReference<AnnotationSetItem> make() { protected OffsettedItemReference<AnnotationSetItem> make() {
return new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection, new IntegerField()); return new OffsettedItemReference<AnnotationSetItem>(dexFile.AnnotationSetsSection,
new IntegerField(null), "annotation_set_ref_item");
} }
} }
}; };
@ -58,8 +58,10 @@ public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
public AnnotationSetRefList(final DexFile dexFile, List<AnnotationSetItem> annotationSets) { public AnnotationSetRefList(final DexFile dexFile, List<AnnotationSetItem> annotationSets) {
this(dexFile, -1); this(dexFile, -1);
for (AnnotationSetItem annotation: annotationSets) { for (AnnotationSetItem annotationSet: annotationSets) {
this.annotationSetReferences.add(new OffsettedItemReference<AnnotationSetItem>(dexFile, annotation, new IntegerField())); OffsettedItemReference<AnnotationSetItem> annotationSetReference = annotationSetsListField.make();
annotationSetReference.setReference(annotationSet);
this.annotationSetReferences.add(annotationSetReference);
} }
} }
@ -67,11 +69,11 @@ public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
return 4; return 4;
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_ANNOTATION_SET_REF_LIST; return ItemType.TYPE_ANNOTATION_SET_REF_LIST;
} }
public String getConciseIdentity() {
return "annotation_set_item @0x" + Integer.toHexString(getOffset());
}
} }

View File

@ -28,21 +28,16 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Output;
public class ByteField extends CachedIntegerValueField { public class ByteField extends CachedIntegerValueField {
protected byte value; public ByteField(String fieldName) {
super(fieldName);
public ByteField() {
} }
public ByteField(byte value) { public ByteField(byte value, String fieldName) {
this.value = value; super(value, fieldName);
}
public void writeTo(Output out) {
out.writeByte(value);
} }
public void readFrom(Input in) { public void readFrom(Input in) {
@ -53,11 +48,7 @@ public class ByteField extends CachedIntegerValueField {
return offset + 1; return offset + 1;
} }
public int getCachedValue() { public void writeValue(Output out) {
return value; out.writeByte(value);
}
public void cacheValue(int value) {
this.value = (byte)value;
} }
} }

View File

@ -28,25 +28,64 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
public abstract class CachedIntegerValueField implements Field<CachedIntegerValueField> { import org.JesusFreke.dexlib.util.AnnotatedOutput;
public abstract int getCachedValue(); import org.JesusFreke.dexlib.util.Output;
public abstract void cacheValue(int value);
public void copyTo(DexFile dexFile, CachedIntegerValueField copy) { public abstract class CachedIntegerValueField<T extends CachedIntegerValueField>
copy.cacheValue(getCachedValue()); implements Field<T> {
private final String fieldName;
protected int value;
protected CachedIntegerValueField(String fieldName) {
this.fieldName = fieldName;
}
protected CachedIntegerValueField(int value, String fieldName) {
this(fieldName);
this.value = value;
}
public void copyTo(DexFile dexFile, T copy) {
copy.value = value;
} }
public int hashCode() { public int hashCode() {
return ((Integer)getCachedValue()).hashCode(); return value;
}
protected abstract void writeValue(Output out);
public void writeTo(AnnotatedOutput out) {
if (fieldName != null) {
out.annotate(fieldName + ": 0x" + Integer.toHexString(getCachedValue()));
}
writeValue(out);
} }
public boolean equals(Object o) { public boolean equals(Object o) {
if (getClass() != o.getClass()) { //TODO: check if this returns false if o is a different subclass
if (!this.getClass().isInstance(o)) {
return false; return false;
} }
CachedIntegerValueField other = (CachedIntegerValueField)o; T other = (T)o;
return getCachedValue() == other.getCachedValue(); return getCachedValue() == other.getCachedValue();
} }
/**
* This method returns the integer value that has been cached. This
* value is either the value that the field was constructed with, the
* value that was read via <code>readFrom</code>, or the value that was
* cached when <code>place</code> was called
* @return the cached value
*/
public int getCachedValue() {
return value;
}
public void cacheValue(int value) {
this.value = value;
}
} }

View File

@ -29,55 +29,55 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.ItemType; import org.JesusFreke.dexlib.ItemType;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.*;
import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AccessFlags;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
public class ClassDataItem extends OffsettedItem<ClassDataItem> { public class ClassDataItem extends OffsettedItem<ClassDataItem> {
private final Field[] fields;
private final ArrayList<EncodedField> staticFieldList = new ArrayList<EncodedField>(); private final ArrayList<EncodedField> staticFieldList = new ArrayList<EncodedField>();
private final ArrayList<EncodedField> instanceFieldList = new ArrayList<EncodedField>(); private final ArrayList<EncodedField> instanceFieldList = new ArrayList<EncodedField>();
private final ArrayList<EncodedMethod> directMethodList = new ArrayList<EncodedMethod>(); private final ArrayList<EncodedMethod> directMethodList = new ArrayList<EncodedMethod>();
private final ArrayList<EncodedMethod> virtualMethodList = new ArrayList<EncodedMethod>(); private final ArrayList<EncodedMethod> virtualMethodList = new ArrayList<EncodedMethod>();
private final ListSizeField staticFieldsCount; private final ListSizeField staticFieldsCountField;
private final ListSizeField instanceFieldsCount; private final ListSizeField instanceFieldsCountField;
private final ListSizeField directMethodsCount; private final ListSizeField directMethodsCountField;
private final ListSizeField virtualMethodsCount; private final ListSizeField virtualMethodsCountField;
private final EncodedMemberList<EncodedField> staticFields; private final EncodedMemberList<EncodedField> staticFieldsListField;
private final EncodedMemberList<EncodedField> instanceFields; private final EncodedMemberList<EncodedField> instanceFieldsListField;
private final EncodedMemberList<EncodedMethod> directMethods; private final EncodedMemberList<EncodedMethod> directMethodsListField;
private final EncodedMemberList<EncodedMethod> virtualMethods; private final EncodedMemberList<EncodedMethod> virtualMethodsListField;
public ClassDataItem(final DexFile dexFile, int offset) { public ClassDataItem(final DexFile dexFile, int offset) {
super(offset); super(offset);
fields = new Field[] { fields = new Field[] {
staticFieldsCount = new ListSizeField(staticFieldList, new Leb128Field()), staticFieldsCountField = new ListSizeField(staticFieldList,
instanceFieldsCount = new ListSizeField(instanceFieldList, new Leb128Field()), new Leb128Field("static_fields_size")),
directMethodsCount = new ListSizeField(directMethodList, new Leb128Field()), instanceFieldsCountField = new ListSizeField(instanceFieldList,
virtualMethodsCount = new ListSizeField(virtualMethodList, new Leb128Field()), new Leb128Field("instance_fields_size")),
staticFields = new EncodedMemberList<EncodedField>(staticFieldList) { directMethodsCountField = new ListSizeField(directMethodList,
new Leb128Field("direct_methods_size")),
virtualMethodsCountField = new ListSizeField(virtualMethodList,
new Leb128Field("virtual_methods_size")),
staticFieldsListField = new EncodedMemberList<EncodedField>(staticFieldList, "static_fields") {
protected EncodedField make(EncodedField previousField) { protected EncodedField make(EncodedField previousField) {
return new EncodedField(dexFile, previousField); return new EncodedField(dexFile, previousField);
} }
}, },
instanceFields = new EncodedMemberList<EncodedField>(instanceFieldList) { instanceFieldsListField = new EncodedMemberList<EncodedField>(instanceFieldList, "instance_fields") {
protected EncodedField make(EncodedField previousField) { protected EncodedField make(EncodedField previousField) {
return new EncodedField(dexFile, previousField); return new EncodedField(dexFile, previousField);
} }
}, },
directMethods = new EncodedMemberList<EncodedMethod>(directMethodList) { directMethodsListField = new EncodedMemberList<EncodedMethod>(directMethodList, "direct_methods") {
protected EncodedMethod make(EncodedMethod previousMethod) { protected EncodedMethod make(EncodedMethod previousMethod) {
return new EncodedMethod(dexFile, previousMethod); return new EncodedMethod(dexFile, previousMethod);
} }
}, },
virtualMethods = new EncodedMemberList<EncodedMethod>(virtualMethodList) { virtualMethodsListField = new EncodedMemberList<EncodedMethod>(virtualMethodList, "virtual_methods") {
protected EncodedMethod make(EncodedMethod previousMethod) { protected EncodedMethod make(EncodedMethod previousMethod) {
return new EncodedMethod(dexFile, previousMethod); return new EncodedMethod(dexFile, previousMethod);
} }
@ -112,19 +112,29 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
private static abstract class EncodedMember<T extends EncodedMember<T>> extends CompositeField<T> implements Field<T>, Comparable<T> private static abstract class EncodedMember<T extends EncodedMember<T>> extends CompositeField<T> implements Field<T>, Comparable<T>
{ {
public EncodedMember(String fieldName) {
super(fieldName);
}
protected abstract void setPreviousMember(T previousMember); protected abstract void setPreviousMember(T previousMember);
} }
private static abstract class EncodedMemberList<T extends EncodedMember<T>> implements Field<EncodedMemberList<T>> { private static abstract class EncodedMemberList<T extends EncodedMember<T>> implements Field<EncodedMemberList<T>> {
private final ArrayList<T> list; private final ArrayList<T> list;
private final String fieldName;
public EncodedMemberList(ArrayList<T> list) { public EncodedMemberList(ArrayList<T> list, String fieldName) {
this.list = list; this.list = list;
this.fieldName = fieldName;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.annotate(0, fieldName + ":");
int i=0;
for (T field: list) { for (T field: list) {
out.annotate(0, "[0x" + Integer.toHexString(i) + "]");
field.writeTo(out); field.writeTo(out);
i++;
} }
} }
@ -196,13 +206,12 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
} }
public static class EncodedField extends EncodedMember<EncodedField> { public static class EncodedField extends EncodedMember<EncodedField> {
private final Field[] fields;
private final IndexedItemReference<FieldIdItem> field; private final IndexedItemReference<FieldIdItem> field;
private final Leb128DeltaField fieldIndexField; private final Leb128DeltaField fieldIndexField;
private final Leb128Field accessFlags; private final Leb128Field accessFlags;
public EncodedField(DexFile dexFile, final EncodedField previousField) { public EncodedField(DexFile dexFile, final EncodedField previousField) {
super("encoded_field");
Leb128DeltaField previousIndexField = null; Leb128DeltaField previousIndexField = null;
if (previousField != null) { if (previousField != null) {
previousIndexField = previousField.fieldIndexField; previousIndexField = previousField.fieldIndexField;
@ -211,16 +220,17 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
fields = new Field[] { fields = new Field[] {
field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection, field = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection,
fieldIndexField = new Leb128DeltaField(previousIndexField)), fieldIndexField = new Leb128DeltaField(previousIndexField, null), "field_idx_diff"),
accessFlags = new Leb128Field() accessFlags = new Leb128Field("access_flags")
}; };
} }
public EncodedField(DexFile dexFile, FieldIdItem field, int accessFlags) { public EncodedField(DexFile dexFile, FieldIdItem field, int accessFlags) {
super("encoded_field");
fields = new Field[] { fields = new Field[] {
this.field = new IndexedItemReference<FieldIdItem>(dexFile, field, this.field = new IndexedItemReference<FieldIdItem>(dexFile, field,
fieldIndexField = new Leb128DeltaField(null)), fieldIndexField = new Leb128DeltaField(null), "field_idx_diff"),
this.accessFlags = new Leb128Field(accessFlags) this.accessFlags = new Leb128Field(accessFlags, "access_flags")
}; };
} }
@ -232,10 +242,6 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
} }
} }
protected Field[] getFields() {
return fields;
}
public int compareTo(EncodedField other) public int compareTo(EncodedField other)
{ {
return field.getReference().compareTo(other.field.getReference()); return field.getReference().compareTo(other.field.getReference());
@ -251,14 +257,13 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
} }
public static class EncodedMethod extends EncodedMember<EncodedMethod> { public static class EncodedMethod extends EncodedMember<EncodedMethod> {
private final Field[] fields;
private final IndexedItemReference<MethodIdItem> method; private final IndexedItemReference<MethodIdItem> method;
private final Leb128DeltaField methodIndexField; private final Leb128DeltaField methodIndexField;
private final Leb128Field accessFlags; private final Leb128Field accessFlags;
private final OffsettedItemReference<CodeItem> codeItem; private final OffsettedItemReference<CodeItem> codeItem;
public EncodedMethod(DexFile dexFile, final EncodedMethod previousMethod) { public EncodedMethod(DexFile dexFile, final EncodedMethod previousMethod) {
super("encedod_method");
Leb128DeltaField previousIndexField = null; Leb128DeltaField previousIndexField = null;
if (previousMethod != null) { if (previousMethod != null) {
previousIndexField = previousMethod.methodIndexField; previousIndexField = previousMethod.methodIndexField;
@ -266,18 +271,21 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
fields = new Field[] { fields = new Field[] {
method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, method = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection,
methodIndexField = new Leb128DeltaField(previousIndexField)), methodIndexField = new Leb128DeltaField(previousIndexField, null), "method_idx_diff"),
accessFlags = new Leb128Field(), accessFlags = new Leb128Field("access_flags"),
codeItem = new OffsettedItemReference<CodeItem>(dexFile.CodeItemsSection, new Leb128Field()) codeItem = new OffsettedItemReference<CodeItem>(dexFile.CodeItemsSection,
new Leb128Field(null), "code_off")
}; };
} }
public EncodedMethod(DexFile dexFile, MethodIdItem methodIdItem, int accessFlags, CodeItem codeItem) { public EncodedMethod(DexFile dexFile, MethodIdItem methodIdItem, int accessFlags, CodeItem codeItem) {
super("encoded_method");
fields = new Field[] { fields = new Field[] {
this.method = new IndexedItemReference<MethodIdItem>(dexFile, methodIdItem, this.method = new IndexedItemReference<MethodIdItem>(dexFile, methodIdItem,
methodIndexField = new Leb128DeltaField(null)), methodIndexField = new Leb128DeltaField(null), "method_idx_diff"),
this.accessFlags = new Leb128Field(accessFlags), this.accessFlags = new Leb128Field(accessFlags, "access_flags"),
this.codeItem = new OffsettedItemReference<CodeItem>(dexFile, codeItem, new Leb128Field()) this.codeItem = new OffsettedItemReference<CodeItem>(dexFile, codeItem,
new Leb128Field(null), "code_off")
}; };
} }
@ -289,10 +297,6 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
} }
} }
protected Field[] getFields() {
return fields;
}
public int compareTo(EncodedMethod other) public int compareTo(EncodedMethod other)
{ {
return method.getReference().compareTo(other.method.getReference()); return method.getReference().compareTo(other.method.getReference());
@ -310,42 +314,51 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
* item encodes the value as per normal * item encodes the value as per normal
*/ */
protected static class Leb128DeltaField extends Leb128Field { protected static class Leb128DeltaField extends Leb128Field {
private Leb128DeltaField previousField; private Leb128DeltaField previousField = null;
public Leb128DeltaField(Leb128DeltaField previousField) { public Leb128DeltaField(String fieldName) {
super(fieldName);
}
public void readFrom(Input in) {
super.readFrom(in);
value += getPreviousValue();
}
public int place(int offset) {
return offset + Leb128Utils.unsignedLeb128Size(value - getPreviousValue());
}
private int getPreviousValue() {
if (previousField == null) {
return 0;
}
return previousField.value;
}
public void writeValue(Output out) {
out.writeUnsignedLeb128(value - getPreviousValue());
}
public Leb128DeltaField(Leb128DeltaField previousField, String fieldName) {
super(fieldName);
this.previousField = previousField; this.previousField = previousField;
} }
public void setPreviousField(Leb128DeltaField previousField) { public void setPreviousField(Leb128DeltaField previousField) {
this.previousField = previousField; this.previousField = previousField;
} }
public int getCachedValue() {
if (previousField != null) {
return previousField.getCachedValue() + super.getCachedValue();
} else {
return super.getCachedValue();
}
}
public void cacheValue(int value) {
if (previousField != null) {
super.cacheValue(value - previousField.getCachedValue());
} else {
super.cacheValue(value);
}
}
} }
protected int getAlignment() { protected int getAlignment() {
return 1; return 1;
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_CLASS_DATA_ITEM; return ItemType.TYPE_CLASS_DATA_ITEM;
} }
public String getConciseIdentity() {
return "class_data_item @0x" + Integer.toHexString(getOffset());
}
} }

View File

@ -37,16 +37,14 @@ import java.util.HashMap;
import java.util.ArrayList; import java.util.ArrayList;
public class ClassDefItem extends IndexedItem<ClassDefItem> { public class ClassDefItem extends IndexedItem<ClassDefItem> {
private final Field[] fields; private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
private final IntegerField accessFlagsField;
private final IndexedItemReference<TypeIdItem> classType; private final IndexedItemReference<TypeIdItem> superclassTypeReferenceField;
private final IntegerField accessFlags; private final OffsettedItemReference<TypeListItem> classInterfacesListReferenceField;
private final IndexedItemReference<TypeIdItem> superclassType; private final IndexedItemReference<StringIdItem> sourceFileReferenceField;
private final OffsettedItemReference<TypeListItem> classInterfacesList; private final OffsettedItemReference<AnnotationDirectoryItem> classAnnotationsReferenceField;
private final IndexedItemReference<StringIdItem> sourceFile; private final OffsettedItemReference<ClassDataItem> classDataReferenceField;
private final OffsettedItemReference<AnnotationDirectoryItem> classAnnotations; private final OffsettedItemReference<EncodedArrayItem> staticFieldInitialValuesReferenceField;
private final OffsettedItemReference<ClassDataItem> classData;
private final OffsettedItemReference<EncodedArrayItem> staticFieldInitialValues;
private ArrayList<EncodedValue> staticFieldInitialValuesList; private ArrayList<EncodedValue> staticFieldInitialValuesList;
@ -58,14 +56,22 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
this.dexFile = dexFile; this.dexFile = dexFile;
fields = new Field[] { fields = new Field[] {
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()), classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
accessFlags = new IntegerField(), new IntegerField(null), "class_idx"),
superclassType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()), //TODO: add annotated output showing the flags
classInterfacesList = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection, new IntegerField()), accessFlagsField = new IntegerField("access_flags:"),
sourceFile = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()), superclassTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
classAnnotations = new OffsettedItemReference<AnnotationDirectoryItem>(dexFile.AnnotationDirectoriesSection, new IntegerField()), new IntegerField(null), "superclass_idx"),
classData = new OffsettedItemReference<ClassDataItem>(dexFile.ClassDataSection, new IntegerField()), classInterfacesListReferenceField = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection,
staticFieldInitialValues = new OffsettedItemReference<EncodedArrayItem>(dexFile.EncodedArraysSection, new IntegerField()) new IntegerField(null), "interfaces_off"),
sourceFileReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
new IntegerField(null), "source_file_off"),
classAnnotationsReferenceField = new OffsettedItemReference<AnnotationDirectoryItem>(
dexFile.AnnotationDirectoriesSection, new IntegerField(null), "annotations_off"),
classDataReferenceField = new OffsettedItemReference<ClassDataItem>(dexFile.ClassDataSection,
new IntegerField(null), "class_data_off"),
staticFieldInitialValuesReferenceField = new OffsettedItemReference<EncodedArrayItem>(
dexFile.EncodedArraysSection, new IntegerField(null), "static_values_off")
}; };
} }
@ -76,36 +82,30 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
TypeListItem implementsList, TypeListItem implementsList,
StringIdItem source, StringIdItem source,
ClassDataItem classDataItem) { ClassDataItem classDataItem) {
super(-1); this(dexFile, -1);
this.dexFile = dexFile; classTypeReferenceField.setReference(classType);
accessFlagsField.cacheValue(accessFlags);
fields = new Field[] { superclassTypeReferenceField.setReference(superType);
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new IntegerField()), classInterfacesListReferenceField.setReference(implementsList);
this.accessFlags = new IntegerField(accessFlags), sourceFileReferenceField.setReference(source);
superclassType = new IndexedItemReference<TypeIdItem>(dexFile, superType, new IntegerField()), classDataReferenceField.setReference(classDataItem);
classInterfacesList = new OffsettedItemReference<TypeListItem>(dexFile, implementsList, new IntegerField()),
sourceFile = new IndexedItemReference<StringIdItem>(dexFile, source, new IntegerField()),
classAnnotations = new OffsettedItemReference<AnnotationDirectoryItem>(dexFile.AnnotationDirectoriesSection, new IntegerField()),
classData = new OffsettedItemReference<ClassDataItem>(dexFile, classDataItem, new IntegerField()),
staticFieldInitialValues = new OffsettedItemReference<EncodedArrayItem>(dexFile.EncodedArraysSection, new IntegerField())
};
} }
public TypeIdItem getSuperclass() { public TypeIdItem getSuperclass() {
return superclassType.getReference(); return superclassTypeReferenceField.getReference();
} }
public TypeIdItem getClassType() { public TypeIdItem getClassTypeReferenceField() {
return classType.getReference(); return classTypeReferenceField.getReference();
} }
protected int getAlignment() { protected int getAlignment() {
return 4; return 4;
} }
protected Field[] getFields() { public TypeIdItem getClassType() {
return fields; return classTypeReferenceField.getReference();
} }
public ItemType getItemType() { public ItemType getItemType() {
@ -113,15 +113,15 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
} }
public String getClassName() { public String getClassName() {
return classType.getReference().toString(); return classTypeReferenceField.getReference().getTypeDescriptor();
} }
public String toString() { public String getConciseIdentity() {
return getClassName(); return "class_def_item: " + getClassName();
} }
public int hashCode() { public int hashCode() {
return classType.getReference().hashCode(); return classTypeReferenceField.getReference().hashCode();
} }
public boolean equals(Object o) { public boolean equals(Object o) {
@ -129,7 +129,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
return false; return false;
} }
ClassDefItem other = (ClassDefItem)o; ClassDefItem other = (ClassDefItem)o;
return classType.equals(other.classType); return classTypeReferenceField.equals(other.classTypeReferenceField);
} }
public int compareTo(ClassDefItem o) { public int compareTo(ClassDefItem o) {
@ -145,7 +145,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
throw new RuntimeException("Initial values are only allowed for static fields."); throw new RuntimeException("Initial values are only allowed for static fields.");
} }
ClassDataItem classDataItem = this.classData.getReference(); ClassDataItem classDataItem = this.classDataReferenceField.getReference();
int fieldIndex = classDataItem.addField(encodedField); int fieldIndex = classDataItem.addField(encodedField);
if (initialValue != null) { if (initialValue != null) {
@ -153,13 +153,14 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
staticFieldInitialValuesList = new ArrayList<EncodedValue>(); staticFieldInitialValuesList = new ArrayList<EncodedValue>();
EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, staticFieldInitialValuesList); EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, staticFieldInitialValuesList);
staticFieldInitialValues.setReference(encodedArrayItem); staticFieldInitialValuesReferenceField.setReference(encodedArrayItem);
} }
//All static fields before this one must have an initial value. Add any default values as needed //All static fields before this one must have an initial value. Add any default values as needed
for (int i=staticFieldInitialValuesList.size(); i < fieldIndex; i++) { for (int i=staticFieldInitialValuesList.size(); i < fieldIndex; i++) {
ClassDataItem.EncodedField staticField = classDataItem.getStaticFieldAtIndex(i); ClassDataItem.EncodedField staticField = classDataItem.getStaticFieldAtIndex(i);
EncodedValueSubField subField = TypeUtils.makeDefaultValueForType(dexFile, staticField.getField().getFieldType().toString()); EncodedValueSubField subField = TypeUtils.makeDefaultValueForType(dexFile,
staticField.getField().getFieldType().getTypeDescriptor());
EncodedValue encodedValue = new EncodedValue(dexFile, subField); EncodedValue encodedValue = new EncodedValue(dexFile, subField);
staticFieldInitialValuesList.add(i, encodedValue); staticFieldInitialValuesList.add(i, encodedValue);
} }
@ -169,7 +170,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
} }
public void setAnnotations(AnnotationDirectoryItem annotations) { public void setAnnotations(AnnotationDirectoryItem annotations) {
this.classAnnotations.setReference(annotations); this.classAnnotationsReferenceField.setReference(annotations);
} }
public static int placeClassDefItems(IndexedSection<ClassDefItem> section, int offset) { public static int placeClassDefItems(IndexedSection<ClassDefItem> section, int offset) {
@ -192,7 +193,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
this.section = section; this.section = section;
for (ClassDefItem classDefItem: section.items) { for (ClassDefItem classDefItem: section.items) {
TypeIdItem typeIdItem = classDefItem.classType.getReference(); TypeIdItem typeIdItem = classDefItem.classTypeReferenceField.getReference();
classDefsByType.put(typeIdItem, classDefItem); classDefsByType.put(typeIdItem, classDefItem);
} }
} }
@ -212,14 +213,14 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
private void placeClass(ClassDefItem classDefItem) { private void placeClass(ClassDefItem classDefItem) {
if (!classDefItem.isPlaced()) { if (!classDefItem.isPlaced()) {
TypeIdItem superType = classDefItem.superclassType.getReference(); TypeIdItem superType = classDefItem.superclassTypeReferenceField.getReference();
ClassDefItem superClassDefItem = classDefsByType.get(superType); ClassDefItem superClassDefItem = classDefsByType.get(superType);
if (superClassDefItem != null) { if (superClassDefItem != null) {
placeClass(superClassDefItem); placeClass(superClassDefItem);
} }
TypeListItem interfaces = classDefItem.classInterfacesList.getReference(); TypeListItem interfaces = classDefItem.classInterfacesListReferenceField.getReference();
if (interfaces != null) { if (interfaces != null) {
for (TypeIdItem interfaceType: interfaces.getTypes()) { for (TypeIdItem interfaceType: interfaces.getTypes()) {

View File

@ -32,28 +32,27 @@ import org.JesusFreke.dexlib.code.Instruction;
import org.JesusFreke.dexlib.code.Opcode; import org.JesusFreke.dexlib.code.Opcode;
import org.JesusFreke.dexlib.ItemType; import org.JesusFreke.dexlib.ItemType;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.AnnotatedOutput;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.HashMap; import java.util.HashMap;
public class CodeItem extends OffsettedItem<CodeItem> { public class CodeItem extends OffsettedItem<CodeItem> {
private final Field[] fields;
private final ArrayList<Instruction> instructionList; private final ArrayList<Instruction> instructionList;
private final ArrayList<TryItem> tryItems = new ArrayList<TryItem>(); private final ArrayList<TryItem> tryItems = new ArrayList<TryItem>();
private final ArrayList<EncodedCatchHandler> catchHandlerList = new ArrayList<EncodedCatchHandler>(); private final ArrayList<EncodedCatchHandler> catchHandlerList = new ArrayList<EncodedCatchHandler>();
private final ShortIntegerField registersCount; private final ShortIntegerField registersCountField;
private final ShortIntegerField inArgumentCount; private final ShortIntegerField inArgumentCountField;
private final ShortIntegerField outArgumentCount; private final ShortIntegerField outArgumentCountField;
private final ListSizeField triesCount; private final ListSizeField triesCountField;
private final OffsettedItemReference<DebugInfoItem> debugInfo; private final OffsettedItemReference<DebugInfoItem> debugInfoReferenceField;
private final IntegerField instructionsSize; private final IntegerField instructionsSizeField;
private final InstructionListField instructionListField; private final InstructionListField instructionListField;
private final PaddingField padding; private final PaddingField paddingField;
private final FieldListField<TryItem> tries; private final FieldListField<TryItem> triesListField;
private final EncodedCatchHandlerList catchHandlers; private final EncodedCatchHandlerList catchHandlersListField;
public CodeItem(final DexFile dexFile, int offset) { public CodeItem(final DexFile dexFile, int offset) {
super(offset); super(offset);
@ -61,37 +60,36 @@ public class CodeItem extends OffsettedItem<CodeItem> {
instructionList = new ArrayList<Instruction>(); instructionList = new ArrayList<Instruction>();
fields = new Field[] { fields = new Field[] {
registersCount = new ShortIntegerField(), registersCountField = new ShortIntegerField("registers_size"),
inArgumentCount = new ShortIntegerField(), inArgumentCountField = new ShortIntegerField("ins_size"),
outArgumentCount = new ShortIntegerField(), outArgumentCountField = new ShortIntegerField("outs_size"),
triesCount = new ListSizeField(tryItems, new ShortIntegerField()), triesCountField = new ListSizeField(tryItems, new ShortIntegerField("tries_size")),
debugInfo = new OffsettedItemReference<DebugInfoItem>(dexFile.DebugInfoItemsSection, new IntegerField()), debugInfoReferenceField = new OffsettedItemReference<DebugInfoItem>(dexFile.DebugInfoItemsSection,
instructionsSize = new IntegerField(), new IntegerField(null), "debug_off"),
instructionsSizeField = new IntegerField("insns_size"),
instructionListField = new InstructionListField(dexFile), instructionListField = new InstructionListField(dexFile),
padding = new PaddingField(), paddingField = new PaddingField(),
tries = new FieldListField<TryItem>(tryItems) { triesListField = new FieldListField<TryItem>(tryItems, "try_item") {
protected TryItem make() { protected TryItem make() {
return new TryItem(catchHandlers); return new TryItem(catchHandlersListField);
} }
}, },
catchHandlers = new EncodedCatchHandlerList(dexFile) catchHandlersListField = new EncodedCatchHandlerList(dexFile)
}; };
} }
public CodeItem(final DexFile dexFile, public CodeItem(final DexFile dexFile,
int registersCount, int registersCount,
int inArguments, int inArguments,
ArrayList<Instruction> instructions, List<Instruction> instructions,
DebugInfoItem debugInfo, DebugInfoItem debugInfo,
List<TryItem> tries, List<TryItem> tries,
List<EncodedCatchHandler> handlers) { List<EncodedCatchHandler> handlers) {
super(-1); this(dexFile, 0);
this.instructionList = new ArrayList<Instruction>(instructions); instructionList.addAll(instructions);
this.instructionListField = new InstructionListField(dexFile); instructionsSizeField.cacheValue(instructionListField.getInstructionWordCount());
if (tries != null) { if (tries != null) {
tryItems.addAll(tries); tryItems.addAll(tries);
@ -103,22 +101,10 @@ public class CodeItem extends OffsettedItem<CodeItem> {
throw new RuntimeException("The handlers parameter must be null if the tries parameter is null"); throw new RuntimeException("The handlers parameter must be null if the tries parameter is null");
} }
fields = new Field[] { registersCountField.cacheValue(registersCount);
this.registersCount = new ShortIntegerField(registersCount), inArgumentCountField.cacheValue(inArguments);
this.inArgumentCount = new ShortIntegerField(inArguments), outArgumentCountField.cacheValue(instructionListField.getOutArguments());
this.outArgumentCount = new ShortIntegerField(instructionListField.getOutArguments()), debugInfoReferenceField.setReference(debugInfo);
this.triesCount = new ListSizeField(tryItems, new ShortIntegerField(0)),
this.debugInfo = new OffsettedItemReference<DebugInfoItem>(dexFile, debugInfo, new IntegerField()),
this.instructionsSize = new IntegerField(instructionListField.getInstructionWordCount()),
instructionListField,
this.padding = new PaddingField(),
this.tries = new FieldListField<TryItem>(tryItems) {
protected TryItem make() {
return new TryItem(catchHandlers);
}
},
this.catchHandlers = new EncodedCatchHandlerList(dexFile)
};
} }
protected int getAlignment() { protected int getAlignment() {
@ -131,48 +117,43 @@ public class CodeItem extends OffsettedItem<CodeItem> {
public void copyTo(DexFile dexFile, CodeItem copy) public void copyTo(DexFile dexFile, CodeItem copy)
{ {
Field[] fields = getFields();
Field[] fieldsCopy = copy.getFields();
for (int i = 0; i < fields.length-2; i++) { for (int i = 0; i < fields.length-2; i++) {
fields[i].copyTo(dexFile, fieldsCopy[i]); fields[i].copyTo(dexFile, copy.fields[i]);
} }
//we need to do this in reverse order, so when the tries are copied, //we need to do this in reverse order, so when the tries are copied,
//the catchHandler copies will already exist //the catchHandler copies will already exist
catchHandlers.copyTo(dexFile, copy.catchHandlers); catchHandlersListField.copyTo(dexFile, copy.catchHandlersListField);
tries.copyTo(dexFile, copy.tries); triesListField.copyTo(dexFile, copy.triesListField);
} }
public Field[] getFields() { public String getConciseIdentity() {
return fields; //TODO: should mention the method name here
return "code_item @0x" + Integer.toHexString(getOffset());
} }
public static class TryItem extends CompositeField<TryItem> { public static class TryItem extends CompositeField<TryItem> {
private final Field[] fields;
private final IntegerField startAddr; private final IntegerField startAddr;
private final ShortIntegerField insnCount; private final ShortIntegerField insnCount;
private final EncodedCatchHandlerReference encodedCatchHandlerReference; private final EncodedCatchHandlerReference encodedCatchHandlerReference;
public TryItem(EncodedCatchHandlerList encodedCatchHandlerList) { public TryItem(EncodedCatchHandlerList encodedCatchHandlerList) {
super("try_item");
fields = new Field[] { fields = new Field[] {
startAddr = new IntegerField(), startAddr = new IntegerField("start_addr"),
insnCount = new ShortIntegerField(), insnCount = new ShortIntegerField("insn_count"),
encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandlerList) encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandlerList)
}; };
} }
public TryItem(int startAddr, int insnCount, EncodedCatchHandler encodedCatchHandler) { public TryItem(int startAddr, int insnCount, EncodedCatchHandler encodedCatchHandler) {
super("try_item");
fields = new Field[] { fields = new Field[] {
this.startAddr = new IntegerField(startAddr), this.startAddr = new IntegerField(startAddr, "start_addr"),
this.insnCount = new ShortIntegerField(insnCount), this.insnCount = new ShortIntegerField(insnCount, "insn_count"),
this.encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandler) this.encodedCatchHandlerReference = new EncodedCatchHandlerReference(encodedCatchHandler)
}; };
} }
protected Field[] getFields() {
return fields;
}
public int getStartAddress() { public int getStartAddress() {
return startAddr.getCachedValue(); return startAddr.getCachedValue();
} }
@ -191,10 +172,12 @@ public class CodeItem extends OffsettedItem<CodeItem> {
private EncodedCatchHandler encodedCatchHandler; private EncodedCatchHandler encodedCatchHandler;
public EncodedCatchHandlerReference(EncodedCatchHandlerList encodedCatchHandlerList) { public EncodedCatchHandlerReference(EncodedCatchHandlerList encodedCatchHandlerList) {
super("encoded_catch_handler");
this.encodedCatchHandlerList = encodedCatchHandlerList; this.encodedCatchHandlerList = encodedCatchHandlerList;
} }
public EncodedCatchHandlerReference(EncodedCatchHandler encodedCatchHandler) { public EncodedCatchHandlerReference(EncodedCatchHandler encodedCatchHandler) {
super("encoded_catch_handler");
this.encodedCatchHandlerList = null; this.encodedCatchHandlerList = null;
this.encodedCatchHandler = encodedCatchHandler; this.encodedCatchHandler = encodedCatchHandler;
} }
@ -212,7 +195,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
public void copyTo(DexFile dexFile, CachedIntegerValueField _copy) { public void copyTo(DexFile dexFile, CachedIntegerValueField _copy) {
EncodedCatchHandlerReference copy = (EncodedCatchHandlerReference)_copy; EncodedCatchHandlerReference copy = (EncodedCatchHandlerReference)_copy;
EncodedCatchHandler copiedItem = copy.getEncodedCatchHandlerList().getByOffset( EncodedCatchHandler copiedItem = copy.getEncodedCatchHandlerList().getByOffset(
encodedCatchHandler.getOffsetInList()); encodedCatchHandler.getOffsetInList());
@ -220,7 +202,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
cacheValue(encodedCatchHandler.getOffsetInList()); cacheValue(encodedCatchHandler.getOffsetInList());
super.writeTo(out); super.writeTo(out);
@ -252,18 +234,17 @@ public class CodeItem extends OffsettedItem<CodeItem> {
itemsByOffset.put(offset, encodedCatchHandler); itemsByOffset.put(offset, encodedCatchHandler);
} }
return encodedCatchHandler; return encodedCatchHandler;
} }
public EncodedCatchHandlerList(DexFile dexFile) { public EncodedCatchHandlerList(final DexFile dexFile) {
super("encoded_catch_handler_list");
this.dexFile = dexFile; this.dexFile = dexFile;
}
private final ListSizeField sizeField; fields = new Field[] {
private final FieldListField<EncodedCatchHandler> listField; sizeField = new ListSizeField(catchHandlerList, new Leb128Field("size")),
listField = new FieldListField<EncodedCatchHandler>(catchHandlerList, "encoded_catch_handler") {
private final Field[] fields = new Field[] {
sizeField = new ListSizeField(catchHandlerList, new Leb128Field()),
listField = new FieldListField<EncodedCatchHandler>(catchHandlerList) {
protected EncodedCatchHandler make() { protected EncodedCatchHandler make() {
return new EncodedCatchHandler(dexFile, 0); return new EncodedCatchHandler(dexFile, 0);
} }
@ -287,7 +268,11 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
} }
} }
}; };
}
private final ListSizeField sizeField;
private final FieldListField<EncodedCatchHandler> listField;
public void readFrom(Input in) { public void readFrom(Input in) {
if (tryItems.size() > 0) { if (tryItems.size() > 0) {
@ -296,7 +281,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
if (fieldPresent) { if (fieldPresent) {
super.writeTo(out); super.writeTo(out);
} }
@ -314,10 +299,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
} }
protected Field[] getFields() {
return fields;
}
public void copyTo(DexFile dexFile, EncodedCatchHandlerList copy) { public void copyTo(DexFile dexFile, EncodedCatchHandlerList copy) {
super.copyTo(dexFile, copy); super.copyTo(dexFile, copy);
copy.fieldPresent = fieldPresent; copy.fieldPresent = fieldPresent;
@ -329,7 +310,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
public static class EncodedCatchHandler extends CompositeField<EncodedCatchHandler> { public static class EncodedCatchHandler extends CompositeField<EncodedCatchHandler> {
public final Field[] fields;
private ArrayList<EncodedTypeAddrPair> list; private ArrayList<EncodedTypeAddrPair> list;
boolean hasCatchAll = false; boolean hasCatchAll = false;
private int baseOffset = 0; private int baseOffset = 0;
@ -341,11 +321,12 @@ public class CodeItem extends OffsettedItem<CodeItem> {
private int offset; private int offset;
public EncodedCatchHandler(final DexFile dexFile, int offset) { public EncodedCatchHandler(final DexFile dexFile, int offset) {
super("encoded_catch_handler");
this.offset = offset; this.offset = offset;
list = new ArrayList<EncodedTypeAddrPair>(); list = new ArrayList<EncodedTypeAddrPair>();
fields = new Field[] { fields = new Field[] {
size = new ListSizeField(list, new SignedLeb128Field() { size = new ListSizeField(list, new SignedLeb128Field("size") {
public void readFrom(Input in) { public void readFrom(Input in) {
super.readFrom(in); super.readFrom(in);
hasCatchAll = (getCachedValue() <= 0); hasCatchAll = (getCachedValue() <= 0);
@ -355,19 +336,19 @@ public class CodeItem extends OffsettedItem<CodeItem> {
super.cacheValue(value * (hasCatchAll?-1:1)); super.cacheValue(value * (hasCatchAll?-1:1));
}}) }})
, ,
handlers = new FieldListField<EncodedTypeAddrPair>(list) { handlers = new FieldListField<EncodedTypeAddrPair>(list, "encoded_type_addr_pair") {
protected EncodedTypeAddrPair make() { protected EncodedTypeAddrPair make() {
return new EncodedTypeAddrPair(dexFile); return new EncodedTypeAddrPair(dexFile);
} }
}, },
catchAllAddress = new Leb128Field() { catchAllAddress = new Leb128Field("catch_all_addr") {
public void readFrom(Input in) { public void readFrom(Input in) {
if (hasCatchAll) { if (hasCatchAll) {
super.readFrom(in); super.readFrom(in);
} }
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
if (hasCatchAll) { if (hasCatchAll) {
super.writeTo(out); super.writeTo(out);
} }
@ -393,10 +374,6 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
} }
protected Field[] getFields() {
return fields;
}
public int getOffsetInList() { public int getOffsetInList() {
return offset-baseOffset; return offset-baseOffset;
} }
@ -434,35 +411,30 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
public static class EncodedTypeAddrPair extends CompositeField<EncodedTypeAddrPair> { public static class EncodedTypeAddrPair extends CompositeField<EncodedTypeAddrPair> {
public final Field[] fields; public final IndexedItemReference<TypeIdItem> typeReferenceField;
public final Leb128Field handlerAddressField;
public final IndexedItemReference<TypeIdItem> type;
public final Leb128Field handlerAddress;
public EncodedTypeAddrPair(DexFile dexFile) { public EncodedTypeAddrPair(DexFile dexFile) {
super("encoded_type_addr_pair");
fields = new Field[] { fields = new Field[] {
type = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128Field()), typeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
handlerAddress = new Leb128Field() new Leb128Field(null), "type_idx"),
handlerAddressField = new Leb128Field("addr")
}; };
} }
public EncodedTypeAddrPair(DexFile dexFile, TypeIdItem type, int handlerOffset) { public EncodedTypeAddrPair(DexFile dexFile, TypeIdItem type, int handlerOffset) {
fields = new Field[] { this(dexFile);
this.type = new IndexedItemReference<TypeIdItem>(dexFile, type, new Leb128Field()), typeReferenceField.setReference(type);
this.handlerAddress = new Leb128Field(handlerOffset) handlerAddressField.cacheValue(handlerOffset);
};
} }
protected Field[] getFields() { public TypeIdItem getTypeReferenceField() {
return fields; return typeReferenceField.getReference();
}
public TypeIdItem getType() {
return type.getReference();
} }
public int getHandlerAddress() { public int getHandlerAddress() {
return handlerAddress.getCachedValue(); return handlerAddressField.getCachedValue();
} }
} }
@ -473,18 +445,18 @@ public class CodeItem extends OffsettedItem<CodeItem> {
this.dexFile = dexFile; this.dexFile = dexFile;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
int startPosition = out.getCursor(); int startPosition = out.getCursor();
for (Instruction instruction: instructionList) { for (Instruction instruction: instructionList) {
instruction.writeTo(out); instruction.writeTo(out);
} }
if ((out.getCursor() - startPosition) != (instructionsSize.getCachedValue() * 2)) { if ((out.getCursor() - startPosition) != (instructionsSizeField.getCachedValue() * 2)) {
throw new RuntimeException("Did not write the expected amount of bytes"); throw new RuntimeException("Did not write the expected amount of bytes");
} }
} }
public void readFrom(Input in) { public void readFrom(Input in) {
int numBytes = instructionsSize.getCachedValue() * 2; int numBytes = instructionsSizeField.getCachedValue() * 2;
int startPosition = in.getCursor(); int startPosition = in.getCursor();
do { do {
@ -499,7 +471,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
public int place(int offset) { public int place(int offset) {
return offset + (instructionsSize.getCachedValue() * 2); return offset + (instructionsSizeField.getCachedValue() * 2);
} }
public void copyTo(DexFile dexFile, InstructionListField copy) { public void copyTo(DexFile dexFile, InstructionListField copy) {
@ -539,7 +511,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) { if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
isStatic = true; isStatic = true;
} }
int paramWordCount = methodIdItem.getParameterWordCount(isStatic); int paramWordCount = methodIdItem.getParameterRegisterCount(isStatic);
if (maxParamWordCount < paramWordCount) { if (maxParamWordCount < paramWordCount) {
maxParamWordCount = paramWordCount; maxParamWordCount = paramWordCount;
@ -556,10 +528,10 @@ public class CodeItem extends OffsettedItem<CodeItem> {
} }
private boolean needsAlign() { private boolean needsAlign() {
return (triesCount.getCachedValue() > 0) && (instructionsSize.getCachedValue() % 2 == 1); return (triesCountField.getCachedValue() > 0) && (instructionsSizeField.getCachedValue() % 2 == 1);
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
if (needsAlign()) { if (needsAlign()) {
out.writeShort(0); out.writeShort(0);
} }

View File

@ -28,53 +28,58 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public abstract class CompositeField<T extends CompositeField<T>> implements Field<T> { public abstract class CompositeField<T extends CompositeField<T>> implements Field<T> {
/** protected Field[] fields;
* Every instance of a specific subclass should return an array with the same structure, private final String fieldName;
* in other words have the same size, and the same type of field at each position.
* @return An array of fields that represents the sub-fields that make up this CompositeField
*/
protected abstract Field[] getFields();
public void writeTo(Output out) { /**
for (Field field: getFields()) { * Every instance of a specific subclass have a field array with the same structure.
* In other words have the same size, and the same type of field at each position.
*/
public CompositeField(String fieldName){
this.fieldName = fieldName;
}
public void writeTo(AnnotatedOutput out) {
out.annotate(0, fieldName + ":");
out.indent();
for (Field field: fields) {
field.writeTo(out); field.writeTo(out);
} }
out.deindent();
} }
public void readFrom(Input in) { public void readFrom(Input in) {
for (Field field: getFields()) { for (Field field: fields) {
field.readFrom(in); field.readFrom(in);
} }
} }
public int place(int offset) { public int place(int offset) {
for (Field field: getFields()) { for (Field field: fields) {
offset = field.place(offset); offset = field.place(offset);
} }
return offset; return offset;
} }
public void copyTo(DexFile dexFile, T copy) { public void copyTo(DexFile dexFile, T copy) {
Field[] fields = getFields();
Field[] copyFields = copy.getFields();
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
/** /**
* This assumes that the fields will be the same for every instance * This assumes that the fields will be the same for every instance
* of a specific concrete subclass. By making this assumption, every subclass is * of a specific concrete subclass. By making this assumption, every subclass is
* prevented from having to implement copyTo * prevented from having to implement copyTo
*/ */
fields[i].copyTo(dexFile, copyFields[i]); fields[i].copyTo(dexFile, copy.fields[i]);
} }
} }
public int hashCode() { public int hashCode() {
int h = 1; int h = 1;
for (Field field: getFields()) { for (Field field: fields) {
h = h * 31 + field.hashCode(); h = h * 31 + field.hashCode();
} }
return h; return h;
@ -86,13 +91,11 @@ public abstract class CompositeField<T extends CompositeField<T>> implements Fie
} }
CompositeField other = (CompositeField)o; CompositeField other = (CompositeField)o;
Field[] fields = getFields(); if (fields.length != other.fields.length) {
Field[] otherFields = other.getFields();
if (fields.length != otherFields.length) {
return false; return false;
} }
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
if (!fields[i].equals(otherFields[i])) { if (!fields[i].equals(other.fields[i])) {
return false; return false;
} }
} }

View File

@ -32,15 +32,13 @@ import org.JesusFreke.dexlib.ItemType;
import org.JesusFreke.dexlib.debug.DebugInstructionFactory; import org.JesusFreke.dexlib.debug.DebugInstructionFactory;
import org.JesusFreke.dexlib.debug.EndSequence; import org.JesusFreke.dexlib.debug.EndSequence;
import org.JesusFreke.dexlib.debug.DebugInstruction; import org.JesusFreke.dexlib.debug.DebugInstruction;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DebugInfoItem extends OffsettedItem<DebugInfoItem> { public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
private final Field[] fields;
private final ArrayList<IndexedItemReference<StringIdItem>> parameterNames = private final ArrayList<IndexedItemReference<StringIdItem>> parameterNames =
new ArrayList<IndexedItemReference<StringIdItem>>(); new ArrayList<IndexedItemReference<StringIdItem>>();
@ -55,11 +53,13 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
super(offset); super(offset);
fields = new Field[] { fields = new Field[] {
lineStartField = new Leb128Field(), lineStartField = new Leb128Field("line_start"),
parameterNamesSizeField = new ListSizeField(parameterNames, new Leb128Field()), parameterNamesSizeField = new ListSizeField(parameterNames, new Leb128Field("parameters_size")),
parameterNamesField = new FieldListField<IndexedItemReference<StringIdItem>>(parameterNames) { parameterNamesField = new FieldListField<IndexedItemReference<StringIdItem>>(
parameterNames, "parameter_names") {
protected IndexedItemReference<StringIdItem> make() { protected IndexedItemReference<StringIdItem> make() {
return new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()); return new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
new Leb128p1Field(null), "parameter_name");
} }
}, },
debugInstructionListField = new DebugInstructionList(dexFile) debugInstructionListField = new DebugInstructionList(dexFile)
@ -75,25 +75,22 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
this.lineStartField.cacheValue(lineStart); this.lineStartField.cacheValue(lineStart);
for (StringIdItem parameterName: parameterNames) { for (StringIdItem parameterName: parameterNames) {
this.parameterNames.add(new IndexedItemReference<StringIdItem>(dexFile, parameterName, IndexedItemReference<StringIdItem> parameterReference = parameterNamesField.make();
new Leb128p1Field())); parameterReference.setReference(parameterName);
this.parameterNames.add(parameterReference);
} }
this.instructionFields.addAll(debugInstructions); this.instructionFields.addAll(debugInstructions);
} }
protected int getAlignment() {
return 1;
}
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_DEBUG_INFO_ITEM; return ItemType.TYPE_DEBUG_INFO_ITEM;
} }
public String getConciseIdentity() {
return "debug_info_item @0x" + Integer.toHexString(getOffset());
}
private class DebugInstructionList implements Field<DebugInstructionList> { private class DebugInstructionList implements Field<DebugInstructionList> {
private final DexFile dexFile; private final DexFile dexFile;
private final ArrayList<DebugInstruction> list; private final ArrayList<DebugInstruction> list;
@ -103,7 +100,7 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
list = instructionFields; list = instructionFields;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
for (DebugInstruction debugInstruction: list) { for (DebugInstruction debugInstruction: list) {
debugInstruction.writeTo(out); debugInstruction.writeTo(out);
} }

View File

@ -28,10 +28,7 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.*;
import org.JesusFreke.dexlib.util.ByteArrayInput;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.FileUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.ArrayList; import java.util.ArrayList;
@ -176,7 +173,7 @@ public class DexFile
fileSize = offset; fileSize = offset;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
HeaderItemSection.writeTo(out); HeaderItemSection.writeTo(out);
for (IndexedSection indexedSection: indexedSections) { for (IndexedSection indexedSection: indexedSections) {
indexedSection.writeTo(out); indexedSection.writeTo(out);
@ -189,29 +186,6 @@ public class DexFile
MapSection.writeTo(out); MapSection.writeTo(out);
} }
public ClassDefItem getClassByName(String className) {
for (ClassDefItem classDefItem: ClassDefsSection.items) {
if (classDefItem.getClassName().equals(className)) {
return classDefItem;
}
}
throw new RuntimeException("class not found");
}
public MethodIdItem[] getMethodsByClass(TypeIdItem classType) {
ArrayList<MethodIdItem> methods = new ArrayList<MethodIdItem>();
for (MethodIdItem methodIdItem: MethodIdsSection.items) {
if (methodIdItem.getClassType() == classType) {
methods.add(methodIdItem);
}
}
return methods.toArray(new MethodIdItem[0]);
}
public final IndexedSection<HeaderItem> HeaderItemSection = new IndexedSection<HeaderItem>() { public final IndexedSection<HeaderItem> HeaderItemSection = new IndexedSection<HeaderItem>() {
protected HeaderItem make(int index) { protected HeaderItem make(int index) {
try { try {

View File

@ -32,13 +32,11 @@ import org.JesusFreke.dexlib.ItemType;
import org.JesusFreke.dexlib.EncodedValue.ArrayEncodedValueSubField; import org.JesusFreke.dexlib.EncodedValue.ArrayEncodedValueSubField;
import org.JesusFreke.dexlib.EncodedValue.EncodedValue; import org.JesusFreke.dexlib.EncodedValue.EncodedValue;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.AnnotatedOutput;
import java.util.ArrayList; import java.util.ArrayList;
public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> { public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
private final Field[] fields;
private final ArrayEncodedValueSubField encodedArray; private final ArrayEncodedValueSubField encodedArray;
public EncodedArrayItem(DexFile dexFile, int offset) { public EncodedArrayItem(DexFile dexFile, int offset) {
@ -50,7 +48,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
} }
public EncodedArrayItem(DexFile dexFile, ArrayList<EncodedValue> encodedValues) { public EncodedArrayItem(DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
super(-1); super(0);
fields = new Field[] { fields = new Field[] {
encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues) encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues)
@ -65,7 +63,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
return super.place(index, offset); return super.place(index, offset);
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
super.writeTo(out); super.writeTo(out);
} }
@ -73,10 +71,6 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
return 1; return 1;
} }
protected Field[] getFields() {
return fields;
}
public int getOffset() { public int getOffset() {
return super.getOffset(); return super.getOffset();
} }
@ -88,4 +82,8 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_ENCODED_ARRAY_ITEM; return ItemType.TYPE_ENCODED_ARRAY_ITEM;
} }
public String getConciseIdentity() {
return "encoded_array @0x" + Integer.toHexString(getOffset());
}
} }

View File

@ -31,26 +31,24 @@ package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
public class AnnotationElement extends CompositeField<AnnotationElement> { public class AnnotationElement extends CompositeField<AnnotationElement> {
private Field[] fields;
private final IndexedItemReference<StringIdItem> elementName; private final IndexedItemReference<StringIdItem> elementName;
private final EncodedValue encodedValue; private final EncodedValue encodedValue;
public AnnotationElement(final DexFile dexFile) { public AnnotationElement(final DexFile dexFile) {
super("annotation_element");
fields = new Field[] { fields = new Field[] {
elementName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128Field()), elementName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
new Leb128Field(null), "element_name"),
encodedValue = new EncodedValue(dexFile) encodedValue = new EncodedValue(dexFile)
}; };
} }
public AnnotationElement(final DexFile dexFile, StringIdItem elementName, EncodedValue encodedValue) { public AnnotationElement(final DexFile dexFile, StringIdItem elementName, EncodedValue encodedValue) {
super("annotation_element");
fields = new Field[] { fields = new Field[] {
this.elementName = new IndexedItemReference<StringIdItem>(dexFile, elementName, new Leb128Field()), this.elementName = new IndexedItemReference<StringIdItem>(dexFile, elementName,
new Leb128Field(null), "element_name"),
this.encodedValue = encodedValue this.encodedValue = encodedValue
}; };
} }
protected Field[] getFields() {
return fields;
}
} }

View File

@ -36,7 +36,6 @@ import java.util.List;
public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEncodedValueSubField> public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEncodedValueSubField>
implements EncodedValueSubField<AnnotationEncodedValueSubField> { implements EncodedValueSubField<AnnotationEncodedValueSubField> {
private final Field[] fields;
private final ArrayList<AnnotationElement> annotationElementList = new ArrayList<AnnotationElement>(); private final ArrayList<AnnotationElement> annotationElementList = new ArrayList<AnnotationElement>();
private final IndexedItemReference<TypeIdItem> annotationType; private final IndexedItemReference<TypeIdItem> annotationType;
@ -44,10 +43,12 @@ public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEnc
private final FieldListField<AnnotationElement> annotationElements; private final FieldListField<AnnotationElement> annotationElements;
public AnnotationEncodedValueSubField(final DexFile dexFile) { public AnnotationEncodedValueSubField(final DexFile dexFile) {
super("encoded_annotation");
fields = new Field[] { fields = new Field[] {
annotationType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128Field()), annotationType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
annotationCount = new ListSizeField(annotationElementList, new Leb128Field()), new Leb128Field(null), "type_idx"),
annotationElements = new FieldListField<AnnotationElement>(annotationElementList) { annotationCount = new ListSizeField(annotationElementList, new Leb128Field("size")),
annotationElements = new FieldListField<AnnotationElement>(annotationElementList, "elements") {
protected AnnotationElement make() { protected AnnotationElement make() {
return new AnnotationElement(dexFile); return new AnnotationElement(dexFile);
} }
@ -62,10 +63,6 @@ public class AnnotationEncodedValueSubField extends CompositeField<AnnotationEnc
this.annotationElementList.addAll(annotationElements); this.annotationElementList.addAll(annotationElements);
} }
protected Field[] getFields() {
return fields;
}
public void setInitialValueArg(byte valueArg) { public void setInitialValueArg(byte valueArg) {
//valueArg is ignored for annotations //valueArg is ignored for annotations
} }

View File

@ -36,14 +36,15 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
implements EncodedValueSubField<ArrayEncodedValueSubField> implements EncodedValueSubField<ArrayEncodedValueSubField>
{ {
private final Field[] fields;
private final ArrayList<EncodedValue> encodedValues; private final ArrayList<EncodedValue> encodedValues;
public ArrayEncodedValueSubField(final DexFile dexFile) { public ArrayEncodedValueSubField(final DexFile dexFile) {
super("encoded_array");
encodedValues = new ArrayList<EncodedValue>(); encodedValues = new ArrayList<EncodedValue>();
fields = new Field[] { fields = new Field[] {
new ListSizeField(encodedValues, new Leb128Field()), new ListSizeField(encodedValues, new Leb128Field("size")),
new FieldListField<EncodedValue>(encodedValues) { new FieldListField<EncodedValue>(encodedValues, "values") {
protected EncodedValue make() { protected EncodedValue make() {
return new EncodedValue(dexFile); return new EncodedValue(dexFile);
} }
@ -52,11 +53,13 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
} }
public ArrayEncodedValueSubField(final DexFile dexFile, ArrayList<EncodedValue> encodedValues) { public ArrayEncodedValueSubField(final DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
super("encoded_array");
this.encodedValues = encodedValues; this.encodedValues = encodedValues;
fields = new Field[] { fields = new Field[] {
new ListSizeField(this.encodedValues, new Leb128Field()), new ListSizeField(this.encodedValues, new Leb128Field("size")),
new FieldListField<EncodedValue>(encodedValues) { new FieldListField<EncodedValue>(encodedValues, "values") {
protected EncodedValue make() { protected EncodedValue make() {
return new EncodedValue(dexFile); return new EncodedValue(dexFile);
} }
@ -64,10 +67,6 @@ public class ArrayEncodedValueSubField extends CompositeField<ArrayEncodedValueS
}; };
} }
protected Field[] getFields() {
return fields;
}
public void setInitialValueArg(byte valueArg) { public void setInitialValueArg(byte valueArg) {
//valueArg is ignored for arrays //valueArg is ignored for arrays
} }

View File

@ -28,8 +28,8 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class BoolEncodedValueSubField public class BoolEncodedValueSubField
extends SimpleEncodedValueSubField<Boolean, BoolEncodedValueSubField> extends SimpleEncodedValueSubField<Boolean, BoolEncodedValueSubField>
@ -41,7 +41,7 @@ public class BoolEncodedValueSubField
this.value = value; this.value = value;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
} }
public void readFrom(Input in) { public void readFrom(Input in) {

View File

@ -28,8 +28,8 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class ByteEncodedValueSubField public class ByteEncodedValueSubField
extends SimpleEncodedValueSubField<Byte, ByteEncodedValueSubField> extends SimpleEncodedValueSubField<Byte, ByteEncodedValueSubField>
@ -41,7 +41,8 @@ public class ByteEncodedValueSubField
this.value = value; this.value = value;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.annotate(1, "byte" + Integer.toHexString(value) + " " + Integer.toString(value));
out.writeByte(value); out.writeByte(value);
} }

View File

@ -28,9 +28,9 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.EncodedValueUtils; import org.JesusFreke.dexlib.util.EncodedValueUtils;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class CharEncodedValueSubField public class CharEncodedValueSubField
extends SimpleEncodedValueSubField<Character, CharEncodedValueSubField> extends SimpleEncodedValueSubField<Character, CharEncodedValueSubField>
@ -42,8 +42,10 @@ public class CharEncodedValueSubField
this.value = value; this.value = value;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.write(EncodedValueUtils.encodeUnsignedIntegralValue(value)); byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value);
out.annotate(bytes.length, "CharEncodedValueSubField");
out.write(bytes);
} }
public void readFrom(Input in) { public void readFrom(Input in) {

View File

@ -28,9 +28,9 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.EncodedValueUtils; import org.JesusFreke.dexlib.util.EncodedValueUtils;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class DoubleEncodedValueSubField public class DoubleEncodedValueSubField
extends SimpleEncodedValueSubField<Double, DoubleEncodedValueSubField> extends SimpleEncodedValueSubField<Double, DoubleEncodedValueSubField>
@ -42,9 +42,10 @@ public class DoubleEncodedValueSubField
this.value = value; this.value = value;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.write(EncodedValueUtils.encodeRightZeroExtendedValue( byte[] bytes = EncodedValueUtils.encodeRightZeroExtendedValue(Double.doubleToLongBits(value));
Double.doubleToLongBits(value))); out.annotate(bytes.length, "DoubleEncodedValueSubField");
out.write(bytes);
} }
public void readFrom(Input in) { public void readFrom(Input in) {

View File

@ -29,25 +29,25 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.EncodedValueUtils; import org.JesusFreke.dexlib.util.EncodedValueUtils;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
/** TODO: it should be possible to somehow use the IndexedItemReference class */
public class EncodedIndexedItemReference<T extends IndexedItem<T>> public class EncodedIndexedItemReference<T extends IndexedItem<T>>
extends ItemReference<T, EncodedIndexedItemReference<T>>
implements EncodedValueSubField<EncodedIndexedItemReference<T>> { implements EncodedValueSubField<EncodedIndexedItemReference<T>> {
private int initialValueArg; private int initialValueArg;
private ValueType valueType; private ValueType valueType;
private T item = null;
private IndexedSection<T> section;
public EncodedIndexedItemReference(IndexedSection<T> section, ValueType valueType) { public EncodedIndexedItemReference(IndexedSection<T> section, ValueType valueType) {
super(section);
this.valueType = valueType; this.valueType = valueType;
this.section = section;
} }
//TODO: implement support for enum values //TODO: implement support for enum values
public EncodedIndexedItemReference(DexFile dexFile, T item) { public EncodedIndexedItemReference(DexFile dexFile, T item) {
super(dexFile, item);
if (item.getClass() == StringIdItem.class) { if (item.getClass() == StringIdItem.class) {
valueType = ValueType.VALUE_STRING; valueType = ValueType.VALUE_STRING;
} else if (item.getClass() == TypeIdItem.class) { } else if (item.getClass() == TypeIdItem.class) {
@ -57,31 +57,48 @@ public class EncodedIndexedItemReference<T extends IndexedItem<T>>
} else if (item.getClass() == MethodIdItem.class) { } else if (item.getClass() == MethodIdItem.class) {
valueType = ValueType.VALUE_METHOD; valueType = ValueType.VALUE_METHOD;
} }
this.item = item;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
T item = getReference();
if (!item.isPlaced()) { if (!item.isPlaced()) {
throw new RuntimeException("Trying to write a reference to an item that hasn't been placed."); throw new RuntimeException("Trying to write a reference to an item that hasn't been placed.");
} }
out.write(EncodedValueUtils.encodeUnsignedIntegralValue(item.getIndex()));
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(item.getIndex());
if (item != null) {
out.annotate(bytes.length, item.getItemType().getTypeName() + " reference");
} else {
out.annotate(bytes.length, "null reference");
}
out.write(bytes);
} }
public void readFrom(Input in) { public void readFrom(Input in) {
setReference(((IndexedSection<T>)getSection()).getByIndex( item = section.getByIndex(
(int)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(initialValueArg + 1)))); (int)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(initialValueArg + 1)));
} }
public int place(int offset) { public int place(int offset) {
T item = getReference();
if (!item.isPlaced()) { if (!item.isPlaced()) {
throw new RuntimeException("Trying to place a reference to an item that hasn't been placed."); throw new RuntimeException("Trying to place a reference to an item that hasn't been placed.");
} }
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(item.getIndex()); return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(item.getIndex());
} }
public void copyTo(DexFile dexFile, EncodedIndexedItemReference<T> copy) {
if (item == null) {
return;
}
T copiedItem = copy.section.intern(dexFile, item);
copy.item = copiedItem;
}
public T getValue() { public T getValue() {
return getReference(); return item;
} }
public void setInitialValueArg(byte valueArg) public void setInitialValueArg(byte valueArg)
@ -90,7 +107,7 @@ public class EncodedIndexedItemReference<T extends IndexedItem<T>>
} }
public byte getValueArg() { public byte getValueArg() {
return EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(getReference().getIndex()); return EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(item.getIndex());
} }
public ValueType getValueType() { public ValueType getValueType() {

View File

@ -28,13 +28,11 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
public class EncodedValue extends CompositeField<EncodedValue> { public class EncodedValue extends CompositeField<EncodedValue> {
private final Field[] fields;
private class ValueTypeArgField implements Field<ValueTypeArgField> { private class ValueTypeArgField implements Field<ValueTypeArgField> {
private ValueType valueType; private ValueType valueType;
private byte valueArg; private byte valueArg;
@ -46,8 +44,8 @@ public class EncodedValue extends CompositeField<EncodedValue> {
this.valueType = valueType; this.valueType = valueType;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.annotate(1, "valuetype=" + Integer.toString(valueType.getMapValue()) + " valueArg=" + Integer.toString(valueArg));
byte value = (byte)(valueType.getMapValue() | (valueArg << 5)); byte value = (byte)(valueType.getMapValue() | (valueArg << 5));
out.writeByte(value); out.writeByte(value);
} }
@ -102,7 +100,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
this.subField = subField; this.subField = subField;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
subField.writeTo(out); subField.writeTo(out);
} }
@ -147,6 +145,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
private final EncodedValueSubFieldWrapper encodedValue; private final EncodedValueSubFieldWrapper encodedValue;
public EncodedValue(final DexFile dexFile) { public EncodedValue(final DexFile dexFile) {
super("encoded_value");
fields = new Field[] { fields = new Field[] {
valueTypeArg = new ValueTypeArgField(), valueTypeArg = new ValueTypeArgField(),
encodedValue = new EncodedValueSubFieldWrapper(dexFile) encodedValue = new EncodedValueSubFieldWrapper(dexFile)
@ -154,6 +153,7 @@ public class EncodedValue extends CompositeField<EncodedValue> {
} }
public EncodedValue(final DexFile dexFile, EncodedValueSubField subField) { public EncodedValue(final DexFile dexFile, EncodedValueSubField subField) {
super("encoded_value");
fields = new Field[] { fields = new Field[] {
valueTypeArg = new ValueTypeArgField(subField.getValueType()), valueTypeArg = new ValueTypeArgField(subField.getValueType()),
encodedValue = new EncodedValueSubFieldWrapper(dexFile, subField) encodedValue = new EncodedValueSubFieldWrapper(dexFile, subField)
@ -182,8 +182,4 @@ public class EncodedValue extends CompositeField<EncodedValue> {
public byte getValueArg() { public byte getValueArg() {
return valueTypeArg.getValueArg(); return valueTypeArg.getValueArg();
} }
protected Field[] getFields() {
return fields;
}
} }

View File

@ -28,9 +28,9 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.EncodedValueUtils; import org.JesusFreke.dexlib.util.EncodedValueUtils;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class FloatEncodedValueSubField public class FloatEncodedValueSubField
extends SimpleEncodedValueSubField<Float, FloatEncodedValueSubField> extends SimpleEncodedValueSubField<Float, FloatEncodedValueSubField>
@ -41,9 +41,10 @@ public class FloatEncodedValueSubField
public FloatEncodedValueSubField(float value) { public FloatEncodedValueSubField(float value) {
this.value = value; this.value = value;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.write(EncodedValueUtils.encodeRightZeroExtendedValue( byte[] bytes = EncodedValueUtils.encodeRightZeroExtendedValue(((long)Float.floatToIntBits(value)) << 32);
((long)Float.floatToIntBits(value)) << 32)); out.annotate(bytes.length, "FloatEncodedValueSubField");
out.write(bytes);
} }
public void readFrom(Input in) { public void readFrom(Input in) {

View File

@ -28,9 +28,9 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.EncodedValueUtils; import org.JesusFreke.dexlib.util.EncodedValueUtils;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class IntEncodedValueSubField public class IntEncodedValueSubField
extends SimpleEncodedValueSubField<Integer, IntEncodedValueSubField> extends SimpleEncodedValueSubField<Integer, IntEncodedValueSubField>
@ -42,8 +42,10 @@ public class IntEncodedValueSubField
this.value = value; this.value = value;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.write(EncodedValueUtils.encodeSignedIntegralValue(value)); byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
out.annotate(bytes.length, "IntEncodedValueSubField");
out.write(bytes);
} }
public void readFrom(Input in) { public void readFrom(Input in) {

View File

@ -28,9 +28,9 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.EncodedValueUtils; import org.JesusFreke.dexlib.util.EncodedValueUtils;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class LongEncodedValueSubField public class LongEncodedValueSubField
extends SimpleEncodedValueSubField<Long, LongEncodedValueSubField> extends SimpleEncodedValueSubField<Long, LongEncodedValueSubField>
@ -42,8 +42,10 @@ public class LongEncodedValueSubField
this.value = value; this.value = value;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.write(EncodedValueUtils.encodeSignedIntegralValue(value)); byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
out.annotate(bytes.length, "LongEncodedValueSubField");
out.write(bytes);
} }
public void readFrom(Input in) { public void readFrom(Input in) {

View File

@ -28,8 +28,8 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class NullEncodedValueSubField public class NullEncodedValueSubField
extends SimpleEncodedValueSubField<Object, NullEncodedValueSubField> extends SimpleEncodedValueSubField<Object, NullEncodedValueSubField>
@ -37,7 +37,7 @@ public class NullEncodedValueSubField
public NullEncodedValueSubField() { public NullEncodedValueSubField() {
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
} }
public void readFrom(Input in) { public void readFrom(Input in) {

View File

@ -28,9 +28,9 @@
package org.JesusFreke.dexlib.EncodedValue; package org.JesusFreke.dexlib.EncodedValue;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.EncodedValueUtils; import org.JesusFreke.dexlib.util.EncodedValueUtils;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class ShortEncodedValueSubField public class ShortEncodedValueSubField
extends SimpleEncodedValueSubField<Short, ShortEncodedValueSubField> extends SimpleEncodedValueSubField<Short, ShortEncodedValueSubField>
@ -42,8 +42,10 @@ public class ShortEncodedValueSubField
this.value = value; this.value = value;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.write(EncodedValueUtils.encodeSignedIntegralValue(value)); byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
out.annotate(bytes.length, "ShortEncodedValueSubField");
out.write(bytes);
} }
public void readFrom(Input in) { public void readFrom(Input in) {

View File

@ -30,9 +30,10 @@ package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public interface Field<T extends Field> { public interface Field<T extends Field> {
public void writeTo(Output out); public void writeTo(AnnotatedOutput out);
public void readFrom(Input in); public void readFrom(Input in);
public int place(int offset); public int place(int offset);
public void copyTo(DexFile dexFile, T copy); public void copyTo(DexFile dexFile, T copy);

View File

@ -28,31 +28,28 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.ItemType;
public class FieldIdItem extends IndexedItem<FieldIdItem> { public class FieldIdItem extends IndexedItem<FieldIdItem> {
private final Field[] fields; private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
private final IndexedItemReference<TypeIdItem> fieldTypeReferenceField;
private final IndexedItemReference<TypeIdItem> classType; private final IndexedItemReference<StringIdItem> fieldNameReferenceField;
private final IndexedItemReference<TypeIdItem> fieldType;
private final IndexedItemReference<StringIdItem> fieldName;
public FieldIdItem(DexFile dexFile, int index) { public FieldIdItem(DexFile dexFile, int index) {
super(index); super(index);
fields = new Field[] { fields = new Field[] {
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()), classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
fieldType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()), new ShortIntegerField(null), "class_idx"),
fieldName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()) fieldTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
new ShortIntegerField(null), "type_idx"),
fieldNameReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
new IntegerField(null), "parameters_off")
}; };
} }
public FieldIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem fieldName, TypeIdItem fieldType) { public FieldIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem fieldName, TypeIdItem fieldType) {
super(-1); this(dexFile, -1);
fields = new Field[] { classTypeReferenceField.setReference(classType);
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new ShortIntegerField()), fieldTypeReferenceField.setReference(fieldType);
this.fieldType = new IndexedItemReference<TypeIdItem>(dexFile, fieldType, new ShortIntegerField()), fieldNameReferenceField.setReference(fieldName);
this.fieldName = new IndexedItemReference<StringIdItem>(dexFile, fieldName, new IntegerField())
};
} }
public FieldIdItem(DexFile dexFile, TypeIdItem classType, String fieldName, TypeIdItem fieldType) { public FieldIdItem(DexFile dexFile, TypeIdItem classType, String fieldName, TypeIdItem fieldType) {
@ -63,34 +60,35 @@ public class FieldIdItem extends IndexedItem<FieldIdItem> {
return 4; return 4;
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_FIELD_ID_ITEM; return ItemType.TYPE_FIELD_ID_ITEM;
} }
public String toString() { public String getConciseIdentity() {
return classType.toString() + " - " + fieldName.toString(); String parentClass = classTypeReferenceField.getReference().getTypeDescriptor();
//strip off the leading L and trailing ;
parentClass = parentClass.substring(1, parentClass.length() - 1);
return parentClass + "/" + fieldNameReferenceField.getReference().getStringValue() +
":" + fieldTypeReferenceField.getReference().getTypeDescriptor();
} }
public int compareTo(FieldIdItem o) { public int compareTo(FieldIdItem o) {
int result = classType.compareTo(o.classType); int result = classTypeReferenceField.compareTo(o.classTypeReferenceField);
if (result != 0) { if (result != 0) {
return result; return result;
} }
result = fieldName.compareTo(o.fieldName); result = fieldNameReferenceField.compareTo(o.fieldNameReferenceField);
if (result != 0) { if (result != 0) {
return result; return result;
} }
return fieldType.compareTo(o.fieldType); return fieldTypeReferenceField.compareTo(o.fieldTypeReferenceField);
} }
public TypeIdItem getFieldType() { public TypeIdItem getFieldType() {
return fieldType.getReference(); return fieldTypeReferenceField.getReference();
} }
} }

View File

@ -28,21 +28,30 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
import java.util.ArrayList; import java.util.ArrayList;
public abstract class FieldListField<T extends Field> implements Field<FieldListField<T>> { public abstract class FieldListField<T extends Field> implements Field<FieldListField<T>> {
final ArrayList<T> list; final ArrayList<T> list;
private final String fieldName;
public FieldListField(ArrayList<T> list) { public FieldListField(ArrayList<T> list, String fieldName) {
this.list = list; this.list = list;
this.fieldName = fieldName;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
for (Field field: list) { if (list.size() > 0) {
field.writeTo(out); int i=0;
for (Field field: list) {
out.annotate(0, fieldName + "[" + Integer.toString(i) + "]");
out.indent();
field.writeTo(out);
out.deindent();
i++;
}
} }
} }

View File

@ -28,27 +28,34 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.ByteArray; import org.JesusFreke.dexlib.util.ByteArray;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class FixedByteArrayField implements Field<FixedByteArrayField> { public class FixedByteArrayField implements Field<FixedByteArrayField> {
protected byte[] value; protected byte[] value;
private final String fieldName;
public FixedByteArrayField(int size) { public FixedByteArrayField(int size, String fieldName) {
value = new byte[size]; value = new byte[size];
this.fieldName = fieldName;
} }
public FixedByteArrayField(byte[] bytes) { public FixedByteArrayField(byte[] bytes, String fieldName) {
this.value = bytes.clone(); this.value = bytes.clone();
this.fieldName = fieldName;
} }
public FixedByteArrayField(ByteArray byteArray) { public FixedByteArrayField(ByteArray byteArray, String fieldName) {
value = new byte[byteArray.size()]; value = new byte[byteArray.size()];
byteArray.getBytes(value, 0); byteArray.getBytes(value, 0);
this.fieldName = fieldName;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
if (fieldName != null) {
out.annotate(fieldName);
}
out.write(value); out.write(value);
} }

View File

@ -29,7 +29,7 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.ItemType; import org.JesusFreke.dexlib.ItemType;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.AnnotatedOutput;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -46,103 +46,97 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
/** the endianness tag */ /** the endianness tag */
private static final int ENDIAN_TAG = 0x12345678; private static final int ENDIAN_TAG = 0x12345678;
private final Field[] fields; private final FixedByteArrayField magicField;
private final IntegerField checksumField;
protected Field[] getFields() { private final FixedByteArrayField signatureField;
return fields; private final IntegerField fileSizeField;
} private final IntegerField headerSizeField;
private final IntegerField endianTagField;
private final FixedByteArrayField magic; private final IntegerField linkSizeField;
private final IntegerField checksum; private final IntegerField linkOffField;
private final FixedByteArrayField signature; private final IntegerField mapOffField;
private final IntegerField fileSize; private final SectionHeaderInfo StringIdsHeaderField;
private final IntegerField headerSize; private final SectionHeaderInfo TypeIdsHeaderField;
private final IntegerField endianTag; private final SectionHeaderInfo ProtoIdsHeaderField;
private final IntegerField linkSize; private final SectionHeaderInfo FieldIdsHeaderField;
private final IntegerField linkOff; private final SectionHeaderInfo MethodIdsHeaderField;
private final IntegerField mapOff; private final SectionHeaderInfo ClassDefsHeaderField;
private final SectionHeaderInfo StringIdsInfo; private final IntegerField dataSizeField;
private final SectionHeaderInfo TypeIdsInfo; private final IntegerField dataOffField;
private final SectionHeaderInfo ProtoIdsInfo;
private final SectionHeaderInfo FieldIdsInfo;
private final SectionHeaderInfo MethodIdsInfo;
private final SectionHeaderInfo ClassDefsInfo;
private final IntegerField dataSize;
private final IntegerField dataOff;
public HeaderItem(final DexFile file, int index) throws UnsupportedEncodingException { public HeaderItem(final DexFile file, int index) throws UnsupportedEncodingException {
super(index); super(index);
fields = new Field[] { fields = new Field[] {
magic = new FixedByteArrayField(MAGIC.getBytes("US-ASCII")), magicField = new FixedByteArrayField(MAGIC.getBytes("US-ASCII"), "magic"),
checksum = new IntegerField() { checksumField = new IntegerField("checksum") {
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
cacheValue(0); cacheValue(0);
super.writeTo(out); super.writeTo(out);
} }
}, },
signature = new FixedByteArrayField(20) { signatureField = new FixedByteArrayField(20, "signature") {
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
for (int i = 0; i < value.length; i++) { for (int i = 0; i < value.length; i++) {
value[i] = 0; value[i] = 0;
} }
super.writeTo(out); super.writeTo(out);
} }
}, },
fileSize = new IntegerField() { fileSizeField = new IntegerField("file_size") {
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
cacheValue(file.getFileSize()); cacheValue(file.getFileSize());
super.writeTo(out); super.writeTo(out);
} }
}, },
headerSize = new IntegerField(HEADER_SIZE), headerSizeField = new IntegerField(HEADER_SIZE,"header_size"),
endianTag = new IntegerField(ENDIAN_TAG), endianTagField = new IntegerField(ENDIAN_TAG,"endian_tag"),
linkSize = new IntegerField(0), linkSizeField = new IntegerField(0,"link_size"),
linkOff = new IntegerField(0), linkOffField = new IntegerField(0,"link_off"),
mapOff = new IntegerField() { mapOffField = new IntegerField("map_off") {
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
cacheValue(file.MapSection.getOffset()); cacheValue(file.MapSection.getOffset());
super.writeTo(out); super.writeTo(out);
} }
}, },
StringIdsInfo = new SectionHeaderInfo() { StringIdsHeaderField = new SectionHeaderInfo("string_ids") {
protected Section getSection() { protected Section getSection() {
return file.StringIdsSection; return file.StringIdsSection;
} }
}, },
TypeIdsInfo = new SectionHeaderInfo() { TypeIdsHeaderField = new SectionHeaderInfo("type_ids") {
protected Section getSection() { protected Section getSection() {
return file.TypeIdsSection; return file.TypeIdsSection;
} }
}, },
ProtoIdsInfo = new SectionHeaderInfo() { ProtoIdsHeaderField = new SectionHeaderInfo("proto_ids") {
protected Section getSection() { protected Section getSection() {
return file.ProtoIdsSection; return file.ProtoIdsSection;
} }
}, },
FieldIdsInfo = new SectionHeaderInfo() { FieldIdsHeaderField = new SectionHeaderInfo("field_ids") {
protected Section getSection() { protected Section getSection() {
return file.FieldIdsSection; return file.FieldIdsSection;
} }
}, },
MethodIdsInfo = new SectionHeaderInfo() { MethodIdsHeaderField = new SectionHeaderInfo("method_ids") {
protected Section getSection() { protected Section getSection() {
return file.MethodIdsSection; return file.MethodIdsSection;
} }
}, },
ClassDefsInfo = new SectionHeaderInfo() { ClassDefsHeaderField = new SectionHeaderInfo("class_defs") {
protected Section getSection() { protected Section getSection() {
return file.ClassDefsSection; return file.ClassDefsSection;
} }
}, },
dataSize = new IntegerField() { dataSizeField = new IntegerField("data_size") {
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
cacheValue(file.getDataSize()); cacheValue(file.getDataSize());
super.writeTo(out); super.writeTo(out);
} }
}, },
dataOff = new IntegerField() { dataOffField = new IntegerField("data_off") {
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
cacheValue(file.getDataOffset()); cacheValue(file.getDataOffset());
super.writeTo(out); super.writeTo(out);
} }
@ -151,7 +145,7 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
} }
public int getMapOffset() { public int getMapOffset() {
return mapOff.getCachedValue(); return mapOffField.getCachedValue();
} }
protected int getAlignment() { protected int getAlignment() {
@ -162,6 +156,10 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
return ItemType.TYPE_HEADER_ITEM; return ItemType.TYPE_HEADER_ITEM;
} }
public String getConciseIdentity() {
return "header_item";
}
public int compareTo(HeaderItem o) { public int compareTo(HeaderItem o) {
//there is only 1 header item //there is only 1 header item
return 0; return 0;

View File

@ -29,18 +29,7 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
public abstract class IndexedItem<T extends IndexedItem> extends Item<T> implements Comparable<T> { public abstract class IndexedItem<T extends IndexedItem> extends Item<T> implements Comparable<T> {
private int index;
protected IndexedItem(int index) { protected IndexedItem(int index) {
this.index = index; this.index = index;
} }
}
public int place(int index, int offset) {
this.index = index;
return super.place(index, offset);
}
public int getIndex() {
return index;
}
}

View File

@ -28,49 +28,41 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class IndexedItemReference<T extends IndexedItem<T>> extends public class IndexedItemReference<T extends IndexedItem<T>> extends
ItemReference<T,IndexedItemReference<T>> implements Comparable<IndexedItemReference<T>> { ItemReference<T,IndexedItemReference<T>> implements Comparable<IndexedItemReference<T>> {
private final CachedIntegerValueField underlyingField;
public IndexedItemReference(IndexedSection<T> section, CachedIntegerValueField underlyingField) { public IndexedItemReference(IndexedSection<T> section, CachedIntegerValueField underlyingField,
super(section); String fieldName) {
this.underlyingField = underlyingField; super(section, underlyingField, fieldName);
} }
public IndexedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField) { public IndexedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField,
super(dexFile, item); String fieldName) {
this.underlyingField = underlyingField; super(dexFile, item, underlyingField, fieldName);
}
public void writeTo(Output out) {
T item = getReference();
if (item != null && !item.isPlaced()) {
throw new RuntimeException("Trying to write a reference to an item that hasn't been placed.");
}
underlyingField.writeTo(out);
}
public void readFrom(Input in) {
underlyingField.readFrom(in);
if (underlyingField.getCachedValue() != -1) {
setReference(getSection().getByIndex(underlyingField.getCachedValue()));
}
} }
public IndexedSection<T> getSection() { public IndexedSection<T> getSection() {
return (IndexedSection<T>)super.getSection(); return (IndexedSection<T>)super.getSection();
} }
public int place(int offset) { protected int getReferenceValue() {
if (getReference() != null) { T item = getReference();
underlyingField.cacheValue(getReference().getIndex()); if (item == null) {
return -1;
} else { } else {
underlyingField.cacheValue(-1); return item.getIndex();
}
}
protected T getReferencedItem(int referenceValue) {
if (referenceValue == -1) {
return null;
} else {
return getSection().getByIndex(referenceValue);
} }
return underlyingField.place(offset);
} }
public int compareTo(IndexedItemReference<T> o) { public int compareTo(IndexedItemReference<T> o) {

View File

@ -28,21 +28,16 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Output;
public class IntegerField extends CachedIntegerValueField { public class IntegerField extends CachedIntegerValueField<IntegerField> {
protected int value = 0; public IntegerField(String fieldName) {
super(fieldName);
public IntegerField() {
} }
public IntegerField(int value) { public IntegerField(int value, String fieldName) {
this.value = value; super(value, fieldName);
}
public void writeTo(Output out) {
out.writeInt(value);
} }
public void readFrom(Input in) { public void readFrom(Input in) {
@ -53,18 +48,7 @@ public class IntegerField extends CachedIntegerValueField {
return offset + 4; return offset + 4;
} }
/** protected void writeValue(Output out) {
* This method returns the integer value that has been cached. This out.writeInt(value);
* value is either the value that the field was constructed with, the
* value that was read via <code>readFrom</code>, or the value that was
* cached when <code>place</code> was called
* @return the cached value
*/
public int getCachedValue() {
return value;
}
public void cacheValue(int value) {
this.value = value;
} }
} }

View File

@ -30,18 +30,18 @@ package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
import org.JesusFreke.dexlib.ItemType; import org.JesusFreke.dexlib.ItemType;
public abstract class Item<T extends Item> { public abstract class Item<T extends Item> {
private int offset = -1; protected int offset = -1;
protected int index = -1;
protected Field[] fields;
protected Item() { protected Item() {
} }
protected Item(int offset) {
this.offset = offset;
}
public boolean isPlaced() { public boolean isPlaced() {
return offset > -1; return offset > -1;
} }
@ -53,10 +53,9 @@ public abstract class Item<T extends Item> {
public int place(int index, int offset) { public int place(int index, int offset) {
offset = alignOffset(offset); offset = alignOffset(offset);
this.index = index;
this.offset = offset; this.offset = offset;
Field[] fields = getFields();
for (Field field: fields) { for (Field field: fields) {
offset = field.place(offset); offset = field.place(offset);
} }
@ -64,23 +63,30 @@ public abstract class Item<T extends Item> {
} }
public void readFrom(Input in) { public void readFrom(Input in) {
for (Field field: getFields()) { for (Field field: fields) {
field.readFrom(in); field.readFrom(in);
} }
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.alignTo(getAlignment()); out.alignTo(getAlignment());
out.annotate(0, "[0x" + Integer.toHexString(this.getIndex()) + "] " + this.getItemType().getTypeName() );
out.indent();
if (out.getCursor() != offset) { if (out.getCursor() != offset) {
throw new RuntimeException("Item is being written somewhere other than where it was placed"); throw new RuntimeException("Item is being written somewhere other than where it was placed");
} }
for (Field field: getFields()) { for (Field field: fields) {
field.writeTo(out); field.writeTo(out);
} }
out.deindent();
} }
protected abstract int getAlignment(); protected int getAlignment() {
return 1;
}
protected int alignOffset(int offset) { protected int alignOffset(int offset) {
int mask = getAlignment() - 1; int mask = getAlignment() - 1;
@ -88,49 +94,57 @@ public abstract class Item<T extends Item> {
return (offset + mask) & ~mask; return (offset + mask) & ~mask;
} }
protected int getOffset() { public int getOffset() {
return offset; return offset;
} }
protected abstract Field[] getFields(); public int getIndex() {
return index;
}
public abstract ItemType getItemType(); public abstract ItemType getItemType();
public void copyTo(DexFile dexFile, T copy) { public void copyTo(DexFile dexFile, T copy) {
Field[] fields = getFields();
Field[] fieldsCopy = copy.getFields();
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
fields[i].copyTo(dexFile, fieldsCopy[i]); fields[i].copyTo(dexFile, copy.fields[i]);
} }
} }
public int hashCode() { public int hashCode() {
int h = 1; int h = 1;
for (Field field: getFields()) { for (Field field: fields) {
h = h*31 + field.hashCode(); h = h*31 + field.hashCode();
} }
return h; return h;
} }
public boolean equals(Object o) { public boolean equals(Object o) {
if (!(o instanceof Item)) { if (!this.getClass().isInstance(o)) {
return false; return false;
} }
Item other = (Item)o; Item other = (Item)o;
Field[] fields = getFields();
Field[] otherFields = other.getFields();
if (fields.length != otherFields.length) { if (fields.length != other.fields.length) {
return false; return false;
} }
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
if (!fields[i].equals(otherFields[i])) { if (!fields[i].equals(other.fields[i])) {
return false; return false;
} }
} }
return true; return true;
} }
/**
* Returns a concise string value that conveys the identity of this item
* @return A concise string value that conveys the identity of this item
*/
public abstract String getConciseIdentity();
public String toString() {
return getConciseIdentity();
}
} }

View File

@ -28,19 +28,28 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
import org.JesusFreke.dexlib.util.Input;
public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T,S>> implements Field<S> { public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T,S>> implements Field<S> {
private T item = null; private T item = null;
private Section<T> section; private Section<T> section;
private final CachedIntegerValueField underlyingField;
private final String fieldName;
public ItemReference(Section<T> section) { public ItemReference(Section<T> section, CachedIntegerValueField underlyingField, String fieldName) {
this.section = section; this.section = section;
this.underlyingField = underlyingField;
this.fieldName = fieldName;
} }
public ItemReference(DexFile dexFile, T item) { public ItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField, String fieldName) {
if (item != null) { if (item != null) {
section = dexFile.getSectionForItem(item); section = dexFile.getSectionForItem(item);
this.item = item; this.item = item;
} }
this.underlyingField = underlyingField;
this.fieldName = fieldName;
} }
public T getReference() { public T getReference() {
@ -65,6 +74,34 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
copy.setReference(copiedItem); copy.setReference(copiedItem);
} }
public void writeTo(AnnotatedOutput out) {
T item = getReference();
if (item != null) {
if (!item.isPlaced()) {
throw new RuntimeException("Trying to write reference to an item that hasn't been placed.");
}
}
//in some cases, we have to re-cache the value here, because the exact offset wasn't known yet
//during placement. Luckily, all variable sized reference offsets (Leb128) are known at placement,
//so this won't change the size of anything
underlyingField.cacheValue(getReferenceValue());
String annotation = fieldName + ": 0x" + Integer.toHexString(underlyingField.getCachedValue());
if (item != null) {
annotation += " (" + item.getConciseIdentity() + ")";
}
out.annotate(annotation);
underlyingField.writeTo(out);
}
public void readFrom(Input in) {
underlyingField.readFrom(in);
setReference(getReferencedItem(underlyingField.getCachedValue()));
}
public int hashCode() { public int hashCode() {
if (item == null) { if (item == null) {
return 0; return 0;
@ -84,4 +121,20 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
return other.item == null; return other.item == null;
} }
} }
public int place(int offset) {
/**
* We need to cache the reference value so that the underlying field can calculate its length.
* Sometimes this value isn't correct, but the order that items are placed is such that
* the value is correct for any references using a variable sized field (i.e. leb128) to
* store the reference. For non-variable sized fields, it doesn't matter if the value is
* correct or not. We'll get the correct value for these in writeTo(), just before it is
* written
*/
underlyingField.cacheValue(getReferenceValue());
return underlyingField.place(offset);
}
protected abstract int getReferenceValue();
protected abstract T getReferencedItem(int referenceValue);
} }

View File

@ -28,22 +28,17 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Leb128Utils; import org.JesusFreke.dexlib.util.Leb128Utils;
import org.JesusFreke.dexlib.util.Output;
public class Leb128Field extends CachedIntegerValueField { public class Leb128Field extends CachedIntegerValueField {
protected int value; public Leb128Field(String fieldName) {
super(fieldName);
public Leb128Field() {
} }
public Leb128Field(int value) { public Leb128Field(int value, String fieldName) {
this.value = value; super(value, fieldName);
}
public void writeTo(Output out) {
out.writeUnsignedLeb128(value);
} }
public void readFrom(Input in) { public void readFrom(Input in) {
@ -54,11 +49,7 @@ public class Leb128Field extends CachedIntegerValueField {
return offset + Leb128Utils.unsignedLeb128Size(value); return offset + Leb128Utils.unsignedLeb128Size(value);
} }
public int getCachedValue() { public void writeValue(Output out) {
return value; out.writeUnsignedLeb128(value);
}
public void cacheValue(int value) {
this.value = value;
} }
} }

View File

@ -28,22 +28,17 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Leb128Utils; import org.JesusFreke.dexlib.util.Leb128Utils;
import org.JesusFreke.dexlib.util.Output;
public class Leb128p1Field extends CachedIntegerValueField { public class Leb128p1Field extends CachedIntegerValueField {
protected int value; public Leb128p1Field(String fieldName) {
super(fieldName);
public Leb128p1Field() {
} }
public Leb128p1Field(int value) { public Leb128p1Field(int value, String fieldName) {
this.value = value; super(value, fieldName);
}
public void writeTo(Output out) {
out.writeUnsignedLeb128(value + 1);
} }
public void readFrom(Input in) { public void readFrom(Input in) {
@ -54,11 +49,7 @@ public class Leb128p1Field extends CachedIntegerValueField {
return offset + Leb128Utils.unsignedLeb128Size(value + 1); return offset + Leb128Utils.unsignedLeb128Size(value + 1);
} }
public int getCachedValue() { public void writeValue(Output out) {
return value; out.writeUnsignedLeb128(value + 1);
}
public void cacheValue(int value) {
this.value = value;
} }
} }

View File

@ -29,11 +29,11 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.AnnotatedOutput;
import java.util.ArrayList; import java.util.ArrayList;
public class ListSizeField extends CachedIntegerValueField { public class ListSizeField implements Field<ListSizeField> {
private final ArrayList<?> list; private final ArrayList<?> list;
private final CachedIntegerValueField underlyingField; private final CachedIntegerValueField underlyingField;
@ -42,13 +42,14 @@ public class ListSizeField extends CachedIntegerValueField {
this.underlyingField = underlyingField; this.underlyingField = underlyingField;
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
underlyingField.writeTo(out); underlyingField.writeTo(out);
} }
public void readFrom(Input in) { public void readFrom(Input in) {
underlyingField.readFrom(in); underlyingField.readFrom(in);
/** the absolute value operation is needed for the case when a list sized is /**
* the absolute value operation is needed for the case when a list size is
* encoded as the absolute value of a signed integer * encoded as the absolute value of a signed integer
*/ */
int listSize = Math.abs(underlyingField.getCachedValue()); int listSize = Math.abs(underlyingField.getCachedValue());
@ -65,6 +66,10 @@ public class ListSizeField extends CachedIntegerValueField {
return underlyingField.place(offset); return underlyingField.place(offset);
} }
public void copyTo(DexFile dexFile, ListSizeField copy) {
//nothing to do, the value is retrieved from the list
}
public int getCachedValue() { public int getCachedValue() {
return underlyingField.getCachedValue(); return underlyingField.getCachedValue();
} }

View File

@ -29,32 +29,20 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.ItemType; import org.JesusFreke.dexlib.ItemType;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class MapField extends CompositeField<MapField> { public class MapField extends CompositeField<MapField> {
private final Field[] fields; private final ShortIntegerField sectionTypeField;
private final ShortIntegerField unusedField;
public ItemType getSectionItemType() { private final SectionHeaderInfo sectionInfoField;
return ItemType.fromInt(sectionType.getCachedValue());
}
public int getSectionSize() {
return sectionInfo.getSectionSize();
}
public int getSectionOffset() {
return sectionInfo.getSectionOffset();
}
private final ShortIntegerField sectionType;
private final ShortIntegerField unused;
private final SectionHeaderInfo sectionInfo;
public MapField(final DexFile dexFile) { public MapField(final DexFile dexFile) {
super("map_entry");
fields = new Field[] { fields = new Field[] {
sectionType = new ShortIntegerField(), //TODO: add an annotation for the item type
unused = new ShortIntegerField((short)0), sectionTypeField = new ShortIntegerField("type"),
sectionInfo = new SectionHeaderInfo() { unusedField = new ShortIntegerField((short)0, "not used"),
sectionInfoField = new SectionHeaderInfo("section") {
protected Section getSection() { protected Section getSection() {
return dexFile.getSectionForType(getSectionItemType()); return dexFile.getSectionForType(getSectionItemType());
} }
@ -63,26 +51,19 @@ public class MapField extends CompositeField<MapField> {
} }
public MapField(final DexFile dexFile, short sectionType) { public MapField(final DexFile dexFile, short sectionType) {
fields = new Field[] { this(dexFile);
this.sectionType = new ShortIntegerField(sectionType), sectionTypeField.cacheValue(sectionType);
this.unused = new ShortIntegerField((short)0), }
this.sectionInfo = new SectionHeaderInfo() {
protected Section getSection() { public ItemType getSectionItemType() {
return dexFile.getSectionForType(getSectionItemType()); return ItemType.fromInt(sectionTypeField.getCachedValue());
}
}
};
} }
public int place(int offset) { public int getSectionSize() {
return super.place(offset); return sectionInfoField.getSectionSize();
} }
public void writeTo(Output out) { public int getSectionOffset() {
super.writeTo(out); return sectionInfoField.getSectionOffset();
}
protected Field[] getFields() {
return fields;
} }
} }

View File

@ -29,22 +29,21 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.ItemType; import org.JesusFreke.dexlib.ItemType;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.AnnotatedOutput;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
public class MapItem extends IndexedItem<MapItem> { public class MapItem extends IndexedItem<MapItem> {
private final Field[] fields;
private ArrayList<MapField> mapEntries = new ArrayList<MapField>(); private ArrayList<MapField> mapEntries = new ArrayList<MapField>();
public MapItem(final DexFile dexFile, int index) { public MapItem(final DexFile dexFile, int index) {
super(index); super(index);
fields = new Field[] { fields = new Field[] {
new ListSizeField(mapEntries, new IntegerField()), new ListSizeField(mapEntries, new IntegerField("size")),
new FieldListField<MapField>(mapEntries) { new FieldListField<MapField>(mapEntries, "map_entry") {
protected MapField make() { protected MapField make() {
return new MapField(dexFile); return new MapField(dexFile);
} }
@ -64,7 +63,7 @@ public class MapItem extends IndexedItem<MapItem> {
return super.place(index, offset); return super.place(index, offset);
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
Collections.sort(mapEntries, new Comparator<MapField>() { Collections.sort(mapEntries, new Comparator<MapField>() {
public int compare(MapField o1, MapField o2) { public int compare(MapField o1, MapField o2) {
@ -108,10 +107,6 @@ public class MapItem extends IndexedItem<MapItem> {
return 4; return 4;
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_MAP_LIST; return ItemType.TYPE_MAP_LIST;
} }
@ -128,6 +123,10 @@ public class MapItem extends IndexedItem<MapItem> {
return getClass() == o.getClass(); return getClass() == o.getClass();
} }
public String getConciseIdentity() {
return "map_item";
}
public int compareTo(MapItem o) { public int compareTo(MapItem o) {
//there is only 1 map item //there is only 1 map item
return 1; return 1;

View File

@ -29,65 +29,60 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
public class MethodIdItem extends IndexedItem<MethodIdItem> { public class MethodIdItem extends IndexedItem<MethodIdItem> {
private final Field[] fields; private final IndexedItemReference<TypeIdItem> classTypeReferenceField;
private final IndexedItemReference<ProtoIdItem> prototypeReferenceField;
private final IndexedItemReference<TypeIdItem> classType; private final IndexedItemReference<StringIdItem> methodNameReferenceField;
private final IndexedItemReference<ProtoIdItem> prototype;
private final IndexedItemReference<StringIdItem> methodName;
public MethodIdItem(DexFile dexFile, int index) { public MethodIdItem(DexFile dexFile, int index) {
super(index); super(index);
fields = new Field[] { fields = new Field[] {
classType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()), classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
prototype = new IndexedItemReference<ProtoIdItem>(dexFile.ProtoIdsSection, new ShortIntegerField()), new ShortIntegerField(null), "class_idx"),
methodName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()) prototypeReferenceField = new IndexedItemReference<ProtoIdItem>(dexFile.ProtoIdsSection,
new ShortIntegerField(null), "proto_idx"),
methodNameReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
new IntegerField(null), "name_idx")
}; };
} }
public MethodIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem methodName, ProtoIdItem prototype) { public MethodIdItem(DexFile dexFile, TypeIdItem classType, StringIdItem methodName, ProtoIdItem prototype) {
super(-1); this(dexFile, -1);
fields = new Field[] { classTypeReferenceField.setReference(classType);
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new ShortIntegerField()), prototypeReferenceField.setReference(prototype);
this.prototype = new IndexedItemReference<ProtoIdItem>(dexFile, prototype, new ShortIntegerField()), methodNameReferenceField.setReference(methodName);
this.methodName = new IndexedItemReference<StringIdItem>(dexFile, methodName, new IntegerField())
};
} }
public MethodIdItem(DexFile dexFile, TypeIdItem classType, String methodName, ProtoIdItem prototype) {
this(dexFile, classType, new StringIdItem(dexFile, methodName), prototype);
}
protected int getAlignment() { protected int getAlignment() {
return 4; return 4;
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_METHOD_ID_ITEM; return ItemType.TYPE_METHOD_ID_ITEM;
} }
public TypeIdItem getClassType() { public String getConciseIdentity() {
return classType.getReference(); return "method_id_item: " + getMethodString();
}
private String cachedMethodString = null;
public String getMethodString() {
if (cachedMethodString == null) {
String parentClass = classTypeReferenceField.getReference().getTypeDescriptor();
//strip the leading L and trailing ;
parentClass = parentClass.substring(1, parentClass.length() - 1);
cachedMethodString = parentClass + methodNameReferenceField.getReference().getStringValue() +
prototypeReferenceField.getReference().getPrototypeString();
}
return cachedMethodString;
} }
public String getMethodName() { public String getMethodName() {
return methodName.getReference().toString(); return methodNameReferenceField.getReference().getStringValue();
} }
public void setClassType(TypeIdItem newClassType) { public int getParameterRegisterCount(boolean isStatic) {
classType.setReference(newClassType); return prototypeReferenceField.getReference().getParameterRegisterCount() + (isStatic?0:1);
}
public String toString() {
return classType.getReference().toString() + " - " + methodName.getReference().toString();
}
public int getParameterWordCount(boolean isStatic) {
return prototype.getReference().getParameterWordCount() + (isStatic?0:1);
} }
/** /**
@ -95,20 +90,20 @@ public class MethodIdItem extends IndexedItem<MethodIdItem> {
* @return The number of parameters, not including the "this" parameter, if any * @return The number of parameters, not including the "this" parameter, if any
*/ */
public int getParameterCount() { public int getParameterCount() {
return prototype.getReference().getParameterCount(); return prototypeReferenceField.getReference().getParameterCount();
} }
public int compareTo(MethodIdItem o) { public int compareTo(MethodIdItem o) {
int result = classType.compareTo(o.classType); int result = classTypeReferenceField.compareTo(o.classTypeReferenceField);
if (result != 0) { if (result != 0) {
return result; return result;
} }
result = methodName.compareTo(o.methodName); result = methodNameReferenceField.compareTo(o.methodNameReferenceField);
if (result != 0) { if (result != 0) {
return result; return result;
} }
return prototype.compareTo(o.prototype); return prototypeReferenceField.compareTo(o.prototypeReferenceField);
} }
} }

View File

@ -28,26 +28,31 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.ByteArray; import org.JesusFreke.dexlib.util.ByteArray;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class NullTerminatedByteArrayField implements Field<NullTerminatedByteArrayField> { public class NullTerminatedByteArrayField implements Field<NullTerminatedByteArrayField> {
protected byte[] value; protected byte[] value;
private final String fieldName;
public NullTerminatedByteArrayField() { public NullTerminatedByteArrayField(String fieldName) {
this.fieldName = fieldName;
} }
public NullTerminatedByteArrayField(byte[] value) { public NullTerminatedByteArrayField(byte[] value, String fieldName) {
this(fieldName);
this.value = value.clone(); this.value = value.clone();
} }
public NullTerminatedByteArrayField(ByteArray byteArray) { public NullTerminatedByteArrayField(ByteArray byteArray, String fieldName) {
this(fieldName);
value = new byte[byteArray.size()]; value = new byte[byteArray.size()];
byteArray.getBytes(value, 0); byteArray.getBytes(value, 0);
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.annotate(fieldName);
out.write(value); out.write(value);
out.writeByte(0); out.writeByte(0);
} }

View File

@ -29,8 +29,7 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
public abstract class OffsettedItem<T extends OffsettedItem<T>> extends Item<T> { public abstract class OffsettedItem<T extends OffsettedItem<T>> extends Item<T> {
public OffsettedItem(int offset) { public OffsettedItem(int offset) {
super(offset); this.offset = offset;
} }
} }

View File

@ -28,56 +28,41 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public class OffsettedItemReference<T extends OffsettedItem<T>> extends public class OffsettedItemReference<T extends OffsettedItem<T>> extends
ItemReference<T,OffsettedItemReference<T>> { ItemReference<T,OffsettedItemReference<T>> {
private final CachedIntegerValueField underlyingField;
public OffsettedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField,
public OffsettedItemReference(OffsettedSection<T> section, CachedIntegerValueField underlyingField) { String fieldName) {
super(section); super(dexFile, item, underlyingField, fieldName);
this.underlyingField = underlyingField; }
public OffsettedItemReference(OffsettedSection<T> section, CachedIntegerValueField underlyingField,
String fieldName) {
super(section, underlyingField, fieldName);
} }
public OffsettedItemReference(DexFile dexFile, T item, CachedIntegerValueField underlyingField) {
super(dexFile, item);
this.underlyingField = underlyingField;
}
public OffsettedSection<T> getSection() { public OffsettedSection<T> getSection() {
return (OffsettedSection<T>)super.getSection(); return (OffsettedSection<T>)super.getSection();
} }
public void writeTo(Output out) { protected int getReferenceValue() {
T item = getReference(); T item = getReference();
if (item != null && !item.isPlaced()) {
throw new RuntimeException("Trying to write reference to an item that hasn't been placed.");
}
//TODO: this is a hack to force it to reload the correct offset value
if (item == null) { if (item == null) {
underlyingField.cacheValue(0); return 0;
} else { } else {
underlyingField.cacheValue(item.getOffset()); return item.getOffset();
}
underlyingField.writeTo(out);
}
public void readFrom(Input in) {
underlyingField.readFrom(in);
if (underlyingField.getCachedValue() != 0) {
setReference(getSection().getByOffset(underlyingField.getCachedValue()));
} }
} }
public int place(int offset) { protected T getReferencedItem(int referenceValue) {
if (getReference() != null) { if (referenceValue == 0) {
underlyingField.cacheValue(getReference().getOffset()); return null;
} else {
underlyingField.cacheValue(0);
} }
return underlyingField.place(offset); return getSection().getByOffset(referenceValue);
} }
} }

View File

@ -33,40 +33,41 @@ import org.JesusFreke.dexlib.ItemType;
import java.util.ArrayList; import java.util.ArrayList;
public class ProtoIdItem extends IndexedItem<ProtoIdItem> { public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
private final Field[] fields; private final IndexedItemReference<StringIdItem> shortyDescriptorReferenceField;
private final IndexedItemReference<TypeIdItem> returnTypeReferenceField;
private final IndexedItemReference<StringIdItem> shortyDescriptor; private final OffsettedItemReference<TypeListItem> parametersReferenceField;
private final IndexedItemReference<TypeIdItem> returnType;
private final OffsettedItemReference<TypeListItem> parameters;
public ProtoIdItem(DexFile dexFile, int index) { public ProtoIdItem(DexFile dexFile, int index) {
super(index); super(index);
fields = new Field[] { fields = new Field[] {
shortyDescriptor = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()), shortyDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
returnType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new IntegerField()), new IntegerField(null), "shorty_idx"),
parameters = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection, new IntegerField()) returnTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
new IntegerField(null), "return_type_idx"),
parametersReferenceField = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection,
new IntegerField(null), "parameters_off")
}; };
} }
public ProtoIdItem(DexFile dexFile, TypeIdItem returnType, ArrayList<TypeIdItem> parameters) public ProtoIdItem(DexFile dexFile, TypeIdItem returnType, ArrayList<TypeIdItem> parameters)
{ {
super(-1); this(dexFile, -1);
StringIdItem stringIdItem = new StringIdItem(dexFile, createShortyDescriptor(returnType, parameters)); shortyDescriptorReferenceField.setReference(
TypeListItem typeListItem = new TypeListItem(dexFile, parameters); new StringIdItem(dexFile, createShortyDescriptor(returnType, parameters)));
returnTypeReferenceField.setReference(returnType);
fields = new Field[] { if (parameters != null && parameters.size() > 0) {
this.shortyDescriptor = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField()), parametersReferenceField.setReference(new TypeListItem(dexFile, parameters));
this.returnType = new IndexedItemReference<TypeIdItem>(dexFile, returnType, new IntegerField()), }
this.parameters = new OffsettedItemReference<TypeListItem>(dexFile, typeListItem, new IntegerField())
};
} }
private String createShortyDescriptor(TypeIdItem returnType, ArrayList<TypeIdItem> parameters) { private String createShortyDescriptor(TypeIdItem returnType, ArrayList<TypeIdItem> parameters) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(returnType.toShorty()); sb.append(returnType.toShorty());
for (TypeIdItem typeIdItem: parameters) { if (parameters != null) {
sb.append(typeIdItem.toShorty()); for (TypeIdItem typeIdItem: parameters) {
sb.append(typeIdItem.toShorty());
}
} }
return sb.toString(); return sb.toString();
} }
@ -75,18 +76,17 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
return 4; return 4;
} }
public int getParameterWordCount() { public int getParameterRegisterCount() {
TypeListItem typeList = parameters.getReference(); TypeListItem typeList = parametersReferenceField.getReference();
if (typeList == null) { if (typeList == null) {
return 0; return 0;
} else { } else {
return typeList.getWordCount(); return typeList.getRegisterCount();
} }
} }
public int getParameterCount() { public int getParameterCount() {
TypeListItem typeList = parameters.getReference(); TypeListItem typeList = parametersReferenceField.getReference();
if (typeList == null) { if (typeList == null) {
return 0; return 0;
} else { } else {
@ -94,29 +94,44 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
} }
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_PROTO_ID_ITEM; return ItemType.TYPE_PROTO_ID_ITEM;
} }
public int compareTo(ProtoIdItem o) { public int compareTo(ProtoIdItem o) {
int result = returnType.compareTo(o.returnType); int result = returnTypeReferenceField.compareTo(o.returnTypeReferenceField);
if (result != 0) { if (result != 0) {
return result; return result;
} }
TypeListItem thisParameters = parameters.getReference(); TypeListItem thisParameters = parametersReferenceField.getReference();
if (thisParameters == null) { if (thisParameters == null) {
return -1; return -1;
} }
return thisParameters.compareTo(o.parameters.getReference()); return thisParameters.compareTo(o.parametersReferenceField.getReference());
} }
public String toString() { public String getConciseIdentity() {
return shortyDescriptor.toString(); return "proto_id_item: " + getPrototypeString();
}
private String cachedPrototypeString = null;
public String getPrototypeString() {
if (cachedPrototypeString == null) {
StringBuilder sb = new StringBuilder();
TypeListItem parameterList = this.parametersReferenceField.getReference();
if (parameterList != null) {
for (TypeIdItem type: parameterList.getTypes()) {
sb.append(type.getTypeDescriptor());
}
}
cachedPrototypeString = "(" + sb.toString() + ")" +
this.returnTypeReferenceField.getReference().getTypeDescriptor();
}
return cachedPrototypeString;
} }
} }

View File

@ -30,6 +30,7 @@ package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -56,14 +57,14 @@ public abstract class Section<T extends Item> {
for (int i=0; i < items.size(); i++) { for (int i=0; i < items.size(); i++) {
T item = items.get(i); T item = items.get(i);
if (item == null) { if (item == null) {
items.remove(i--); throw new RuntimeException("This section contains a null item");
continue;
} }
offset = item.place(i, offset); offset = item.place(i, offset);
if (i == 0) { if (i == 0) {
/** if this item type has an alignment requirement, /**
* if this item type has an alignment requirement,
* then item.getOffset() may be different than the * then item.getOffset() may be different than the
* offset before item.place was called, so we have * offset that was passed in to this method, so we have
* to initialize the section offset to the actual * to initialize the section offset to the actual
* (post-alignment) offset of the first item * (post-alignment) offset of the first item
*/ */
@ -80,21 +81,24 @@ public abstract class Section<T extends Item> {
} }
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
for (int i = 0; i < size(); i++) { for (int i = 0; i < size(); i++) {
T item = items.get(i); T item = items.get(i);
if (item == null) { if (item == null) {
throw new RuntimeException("Cannot write section because all items haven't been initialized"); throw new RuntimeException("Cannot write section because all items haven't been initialized");
} }
item.writeTo(out); item.writeTo(out);
out.annotate(0, " ");
} }
out.annotate(0, " ");
} }
public abstract void readFrom(int size, Input in); public abstract void readFrom(int size, Input in);
protected void setSize(int size) { protected void setSize(int size) {
if (items.size() > size) { if (items.size() > size) {
throw new RuntimeException("This section contains references to items beyond the size of the section"); throw new RuntimeException("There are references elsewhere to items in this section, that are " +
"beyond the end of the section");
} }
items.ensureCapacity(size); items.ensureCapacity(size);

View File

@ -28,56 +28,44 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.AnnotatedOutput;
public abstract class SectionHeaderInfo implements Field<SectionHeaderInfo> { public abstract class SectionHeaderInfo extends CompositeField<SectionHeaderInfo> {
private int sectionSize; private final String sectionName;
private int sectionOffset;
public SectionHeaderInfo() { private final IntegerField sectionSizeField;
private final IntegerField sectionOffsetField;
public SectionHeaderInfo(String sectionName) {
super(sectionName);
fields = new Field[] {
sectionSizeField = new IntegerField(sectionName + "_size"),
sectionOffsetField = new IntegerField(sectionName + "_off")
};
this.sectionName = sectionName;
} }
protected abstract Section getSection(); protected abstract Section getSection();
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
Section section = getSection(); Section section = getSection();
if (!section.isPlaced()) { if (!section.isPlaced()) {
throw new RuntimeException("Trying to write a reference to a section that hasn't been placed."); throw new RuntimeException("Trying to write a reference to a section that hasn't been placed.");
} }
sectionSize = section.size(); sectionSizeField.cacheValue(section.size());
sectionOffset = section.getOffset(); sectionOffsetField.cacheValue(section.getOffset());
out.writeInt(sectionSize); super.writeTo(out);
out.writeInt(sectionOffset);
}
public void readFrom(Input in) {
sectionSize = in.readInt();
sectionOffset = in.readInt();
} }
public int getSectionSize() { public int getSectionSize() {
return sectionSize; return sectionSizeField.getCachedValue();
} }
public int getSectionOffset() { public int getSectionOffset() {
return sectionOffset; return sectionOffsetField.getCachedValue();
}
public int place(int offset) {
Section section = getSection();
sectionSize = section.size();
sectionOffset = section.getOffset();
return offset+8;
}
public void copyTo(DexFile dexFile, SectionHeaderInfo copy) {
/**
* do nothing. the section size and offset are dynamically generated
* when the copy is written
*/
} }
} }

View File

@ -28,21 +28,16 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Output;
public class ShortIntegerField extends CachedIntegerValueField { public class ShortIntegerField extends CachedIntegerValueField {
protected int value = 0; public ShortIntegerField(String fieldName) {
super(fieldName);
public ShortIntegerField() {
} }
public ShortIntegerField(int value) { public ShortIntegerField(int value, String fieldName) {
this.value = value; super(value, fieldName);
}
public void writeTo(Output out) {
out.writeShort(value);
} }
public void readFrom(Input in) { public void readFrom(Input in) {
@ -53,18 +48,7 @@ public class ShortIntegerField extends CachedIntegerValueField {
return offset + 2; return offset + 2;
} }
/** protected void writeValue(Output out) {
* This method returns the short integer value that has been cached. This out.writeShort(value);
* value is either the value that the field was constructed with, the
* value that was read via <code>readFrom</code>, or the value that was
* cached when <code>place</code> was called
* @return the cached value
*/
public int getCachedValue() {
return value;
}
public void cacheValue(int value) {
this.value = (short)value;
} }
} }

View File

@ -28,22 +28,17 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
import org.JesusFreke.dexlib.util.Output;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Leb128Utils; import org.JesusFreke.dexlib.util.Leb128Utils;
import org.JesusFreke.dexlib.util.Output;
public class SignedLeb128Field extends CachedIntegerValueField { public class SignedLeb128Field extends CachedIntegerValueField {
protected int value; public SignedLeb128Field(String fieldName) {
super(fieldName);
public SignedLeb128Field() {
} }
public SignedLeb128Field(int value) { public SignedLeb128Field(int value, String fieldName) {
this.value = value; super(value, fieldName);
}
public void writeTo(Output out) {
out.writeSignedLeb128(value);
} }
public void readFrom(Input in) { public void readFrom(Input in) {
@ -54,11 +49,7 @@ public class SignedLeb128Field extends CachedIntegerValueField {
return offset + Leb128Utils.signedLeb128Size(value); return offset + Leb128Utils.signedLeb128Size(value);
} }
public int getCachedValue() { public void writeValue(Output out) {
return value; out.writeSignedLeb128(value);
}
public void cacheValue(int value) {
this.value = value;
} }
} }

View File

@ -32,8 +32,6 @@ import org.JesusFreke.dexlib.util.ByteArray;
import org.JesusFreke.dexlib.util.Utf8Utils; import org.JesusFreke.dexlib.util.Utf8Utils;
public class StringDataItem extends OffsettedItem<StringDataItem> implements Comparable<StringDataItem> { public class StringDataItem extends OffsettedItem<StringDataItem> implements Comparable<StringDataItem> {
private final Field[] fields;
private String value = null; private String value = null;
private final Leb128Field stringSize; private final Leb128Field stringSize;
@ -43,8 +41,8 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
super(offset); super(offset);
fields = new Field[] { fields = new Field[] {
stringSize = new Leb128Field(), stringSize = new Leb128Field("string_length"),
stringByteArray = new NullTerminatedByteArrayField() stringByteArray = new NullTerminatedByteArrayField("data")
}; };
} }
@ -54,32 +52,28 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
this.value = value; this.value = value;
fields = new Field[] { fields = new Field[] {
stringSize = new Leb128Field(value.length()), stringSize = new Leb128Field(value.length(), "string_length"),
stringByteArray = new NullTerminatedByteArrayField(Utf8Utils.stringToUtf8Bytes(value)) stringByteArray = new NullTerminatedByteArrayField(Utf8Utils.stringToUtf8Bytes(value), "data")
}; };
} }
public Field[] getFields() {
return fields;
}
public int getAlignment() {
return 1;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_STRING_DATA_ITEM; return ItemType.TYPE_STRING_DATA_ITEM;
} }
public String toString() { public String getStringValue() {
if (value == null) { if (value == null) {
value = Utf8Utils.utf8BytesToString(new ByteArray(((NullTerminatedByteArrayField)fields[1]).value)); value = Utf8Utils.utf8BytesToString(new ByteArray(((NullTerminatedByteArrayField)fields[1]).value));
} }
return value; return value;
}
public String getConciseIdentity() {
return "string_data_item: " + getStringValue();
} }
public int compareTo(StringDataItem o) { public int compareTo(StringDataItem o) {
return toString().compareTo(o.toString()); return getStringValue().compareTo(o.getStringValue());
} }
} }

View File

@ -29,23 +29,19 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
public class StringIdItem extends IndexedItem<StringIdItem> { public class StringIdItem extends IndexedItem<StringIdItem> {
private final Field[] fields; private final OffsettedItemReference<StringDataItem> stringDataReferenceField;
private final OffsettedItemReference<StringDataItem> stringData;
public StringIdItem(DexFile dexFile, int index) { public StringIdItem(DexFile dexFile, int index) {
super(index); super(index);
fields = new Field[] { fields = new Field[] {
stringData = new OffsettedItemReference<StringDataItem>(dexFile.StringDataSection, new IntegerField()) stringDataReferenceField = new OffsettedItemReference<StringDataItem>(dexFile.StringDataSection,
new IntegerField(null), "string_data_off")
}; };
} }
public StringIdItem(DexFile dexFile, StringDataItem stringDataItem) { public StringIdItem(DexFile dexFile, StringDataItem stringDataItem) {
super(-1); this(dexFile, -1);
stringDataReferenceField.setReference(stringDataItem);
fields = new Field[] {
stringData = new OffsettedItemReference<StringDataItem>(dexFile, stringDataItem, new IntegerField())
};
} }
public StringIdItem(DexFile dexFile, String value) { public StringIdItem(DexFile dexFile, String value) {
@ -56,20 +52,20 @@ public class StringIdItem extends IndexedItem<StringIdItem> {
return 4; return 4;
} }
protected Field[] getFields() {
return fields;
}
public ItemType getItemType() { public ItemType getItemType() {
return ItemType.TYPE_STRING_ID_ITEM; return ItemType.TYPE_STRING_ID_ITEM;
} }
public String toString() { public String getConciseIdentity() {
return stringData.getReference().toString(); return "string_id_item: " + getStringValue();
}
public String getStringValue() {
return stringDataReferenceField.getReference().getStringValue();
} }
public int compareTo(StringIdItem o) { public int compareTo(StringIdItem o) {
//sort by the string value //sort by the string value
return toString().compareTo(o.toString()); return getStringValue().compareTo(o.getStringValue());
} }
} }

View File

@ -29,43 +29,35 @@
package org.JesusFreke.dexlib; package org.JesusFreke.dexlib;
public class TypeIdItem extends IndexedItem<TypeIdItem> { public class TypeIdItem extends IndexedItem<TypeIdItem> {
private final Field[] fields; private final IndexedItemReference<StringIdItem> typeDescriptorReferenceField;
private final IndexedItemReference<StringIdItem> type;
public TypeIdItem(DexFile dexFile, int index) { public TypeIdItem(DexFile dexFile, int index) {
super(index); super(index);
fields = new Field[] { fields = new Field[] {
type = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()) typeDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
new IntegerField(null), "descriptor_idx")
}; };
} }
public TypeIdItem(DexFile dexFile, StringIdItem stringIdItem) { public TypeIdItem(DexFile dexFile, StringIdItem stringIdItem) {
super(-1); this(dexFile, -1);
fields = new Field[] { typeDescriptorReferenceField.setReference(stringIdItem);
type = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField())
};
} }
public TypeIdItem(DexFile dexFile, String value) { public TypeIdItem(DexFile dexFile, String value) {
super(-1); this(dexFile, new StringIdItem(dexFile, value));
StringDataItem stringDataItem = new StringDataItem(value);
StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem);
fields = new Field[] {
type = new IndexedItemReference<StringIdItem>(dexFile, stringIdItem, new IntegerField())
};
} }
protected int getAlignment() { protected int getAlignment() {
return 4; return 4;
} }
protected Field[] getFields() { /**
return fields; * Returns the number of 2-byte registers that an instance of this type requires
} * @return The number of 2-byte registers that an instance of this type requires
*/
public int getWordCount() { public int getRegisterCount() {
String type = this.toString(); String type = this.getTypeDescriptor();
/** Only the long and double primitive types are 2 words, /** Only the long and double primitive types are 2 words,
* everything else is a single word * everything else is a single word
*/ */
@ -80,17 +72,21 @@ public class TypeIdItem extends IndexedItem<TypeIdItem> {
return ItemType.TYPE_TYPE_ID_ITEM; return ItemType.TYPE_TYPE_ID_ITEM;
} }
public String toString() { public String getConciseIdentity() {
return type.getReference().toString(); return "type_id_item: " + getTypeDescriptor();
}
public String getTypeDescriptor() {
return typeDescriptorReferenceField.getReference().getStringValue();
} }
public int compareTo(TypeIdItem o) { public int compareTo(TypeIdItem o) {
//sort by the index of the StringIdItem //sort by the index of the StringIdItem
return type.compareTo(o.type); return typeDescriptorReferenceField.compareTo(o.typeDescriptorReferenceField);
} }
public String toShorty() { public String toShorty() {
String type = toString(); String type = getTypeDescriptor();
if (type.length() > 1) { if (type.length() > 1) {
return "L"; return "L";
} else { } else {

View File

@ -32,17 +32,20 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class TypeListItem extends OffsettedItem<TypeListItem> implements Comparable<TypeListItem> { public class TypeListItem extends OffsettedItem<TypeListItem> implements Comparable<TypeListItem> {
private final Field[] fields;
private final ArrayList<IndexedItemReference<TypeIdItem>> typeList = new ArrayList<IndexedItemReference<TypeIdItem>>(); private final ArrayList<IndexedItemReference<TypeIdItem>> typeList = new ArrayList<IndexedItemReference<TypeIdItem>>();
private final ListSizeField sizeField;
private final FieldListField<IndexedItemReference<TypeIdItem>> listField;
public TypeListItem(final DexFile dexFile, int offset) { public TypeListItem(final DexFile dexFile, int offset) {
super(offset); super(offset);
fields = new Field[] { fields = new Field[] {
new ListSizeField(typeList, new IntegerField()), sizeField = new ListSizeField(typeList, new IntegerField("size")),
new FieldListField<IndexedItemReference<TypeIdItem>>(typeList) { listField = new FieldListField<IndexedItemReference<TypeIdItem>>(typeList, "type_item") {
protected IndexedItemReference<TypeIdItem> make() { protected IndexedItemReference<TypeIdItem> make() {
return new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new ShortIntegerField()); return new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
new ShortIntegerField(null), "type_idx");
} }
} }
}; };
@ -52,7 +55,9 @@ public class TypeListItem extends OffsettedItem<TypeListItem> implements Compara
this(dexFile, 0); this(dexFile, 0);
for (TypeIdItem typeIdItem: types) { for (TypeIdItem typeIdItem: types) {
typeList.add(new IndexedItemReference<TypeIdItem>(dexFile, typeIdItem, new ShortIntegerField())); IndexedItemReference<TypeIdItem> typeReference = listField.make();
typeReference.setReference(typeIdItem);
typeList.add(typeReference);
} }
} }
@ -66,15 +71,11 @@ public class TypeListItem extends OffsettedItem<TypeListItem> implements Compara
return list; return list;
} }
public Field[] getFields() { public int getRegisterCount() {
return fields;
}
public int getWordCount() {
int wordCount = 0; int wordCount = 0;
for (IndexedItemReference<TypeIdItem> typeRef: typeList) { for (IndexedItemReference<TypeIdItem> typeRef: typeList) {
TypeIdItem item = typeRef.getReference(); TypeIdItem item = typeRef.getReference();
wordCount += item.getWordCount(); wordCount += item.getRegisterCount();
} }
return wordCount; return wordCount;
} }
@ -91,6 +92,23 @@ public class TypeListItem extends OffsettedItem<TypeListItem> implements Compara
return ItemType.TYPE_TYPE_LIST; return ItemType.TYPE_TYPE_LIST;
} }
public String getConciseIdentity() {
return "type_list: " + getTypeListString();
}
private String cachedTypeListString = null;
public String getTypeListString() {
if (cachedTypeListString == null) {
StringBuilder sb = new StringBuilder();
for (IndexedItemReference<TypeIdItem> typeReference: typeList) {
sb.append(typeReference.getReference().getTypeDescriptor());
}
cachedTypeListString = sb.toString();
}
return cachedTypeListString;
}
public int compareTo(TypeListItem o) { public int compareTo(TypeListItem o) {
if (o == null) { if (o == null) {
return 1; return 1;

View File

@ -53,7 +53,7 @@ public class Format21c extends Format
throw new RuntimeException("The register number must be less than v256"); throw new RuntimeException("The register number must be less than v256");
} }
if (opcode == Opcode.NEW_INSTANCE.value && ((TypeIdItem)item).toString().charAt(0) != 'L') { if (opcode == Opcode.NEW_INSTANCE.value && ((TypeIdItem)item).getTypeDescriptor().charAt(0) != 'L') {
throw new RuntimeException("Only class references can be used with the new-instance opcode"); throw new RuntimeException("Only class references can be used with the new-instance opcode");
} }

View File

@ -69,7 +69,7 @@ public class Format35c extends Format
if (opcode == FILLED_NEW_ARRAY.value) { if (opcode == FILLED_NEW_ARRAY.value) {
//check data for filled-new-array opcode //check data for filled-new-array opcode
String type = ((TypeIdItem)item).toString(); String type = ((TypeIdItem)item).getTypeDescriptor();
if (type.charAt(0) != '[') { if (type.charAt(0) != '[') {
throw new RuntimeException("The type must be an array type"); throw new RuntimeException("The type must be an array type");
} }
@ -79,7 +79,7 @@ public class Format35c extends Format
} else if (opcode >= INVOKE_VIRTUAL.value && opcode <= INVOKE_INTERFACE.value) { } else if (opcode >= INVOKE_VIRTUAL.value && opcode <= INVOKE_INTERFACE.value) {
//check data for invoke-* opcodes //check data for invoke-* opcodes
MethodIdItem methodIdItem = (MethodIdItem)item; MethodIdItem methodIdItem = (MethodIdItem)item;
if (methodIdItem.getParameterWordCount(opcode == INVOKE_STATIC.value) != regCount) { if (methodIdItem.getParameterRegisterCount(opcode == INVOKE_STATIC.value) != regCount) {
throw new RuntimeException("regCount does not match the number of arguments of the method"); throw new RuntimeException("regCount does not match the number of arguments of the method");
} }
} else { } else {

View File

@ -72,7 +72,7 @@ public class Format3rc extends Format
if (opcode == FILLED_NEW_ARRAY_RANGE.value) { if (opcode == FILLED_NEW_ARRAY_RANGE.value) {
//check data for filled-new-array/range opcode //check data for filled-new-array/range opcode
String type = ((TypeIdItem)item).toString(); String type = ((TypeIdItem)item).getTypeDescriptor();
if (type.charAt(0) != '[') { if (type.charAt(0) != '[') {
throw new RuntimeException("The type must be an array type"); throw new RuntimeException("The type must be an array type");
} }
@ -82,7 +82,7 @@ public class Format3rc extends Format
} else if (opcode >= INVOKE_VIRTUAL_RANGE.value && opcode <= INVOKE_INTERFACE_RANGE.value) { } else if (opcode >= INVOKE_VIRTUAL_RANGE.value && opcode <= INVOKE_INTERFACE_RANGE.value) {
//check data for invoke-*/range opcodes //check data for invoke-*/range opcodes
MethodIdItem methodIdItem = (MethodIdItem)item; MethodIdItem methodIdItem = (MethodIdItem)item;
if (methodIdItem.getParameterWordCount(opcode == INVOKE_STATIC.value) != regCount) { if (methodIdItem.getParameterRegisterCount(opcode == INVOKE_STATIC.value) != regCount) {
throw new RuntimeException("regCount does not match the number of arguments of the method"); throw new RuntimeException("regCount does not match the number of arguments of the method");
} }
} else { } else {

View File

@ -30,7 +30,7 @@ package org.JesusFreke.dexlib.code;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
import org.JesusFreke.dexlib.util.Input; import org.JesusFreke.dexlib.util.Input;
import org.JesusFreke.dexlib.util.Output; import org.JesusFreke.dexlib.util.AnnotatedOutput;
public final class Instruction implements Field<Instruction> { public final class Instruction implements Field<Instruction> {
private DexFile dexFile; private DexFile dexFile;
@ -143,7 +143,8 @@ public final class Instruction implements Field<Instruction> {
bytes = in.readBytes(opcode.numBytes); bytes = in.readBytes(opcode.numBytes);
} }
public void writeTo(Output out) { public void writeTo(AnnotatedOutput out) {
out.annotate(bytes.length, "instruction");
if (bytes[0] == 0 && bytes[1] > 0) { if (bytes[0] == 0 && bytes[1] > 0) {
//the "special instructions" must be 4 byte aligned //the "special instructions" must be 4 byte aligned
out.alignTo(4); out.alignTo(4);

View File

@ -34,15 +34,14 @@ import org.JesusFreke.dexlib.ByteField;
import org.JesusFreke.dexlib.SignedLeb128Field; import org.JesusFreke.dexlib.SignedLeb128Field;
public class AdvanceLine extends CompositeField<AdvanceLine> implements DebugInstruction<AdvanceLine> { public class AdvanceLine extends CompositeField<AdvanceLine> implements DebugInstruction<AdvanceLine> {
private final Field[] fields;
private final ByteField opcodeField; private final ByteField opcodeField;
private final SignedLeb128Field lineDeltaField; private final SignedLeb128Field lineDeltaField;
public AdvanceLine() { public AdvanceLine() {
super("DBG_ADVANCE_LINE");
fields = new Field[] { fields = new Field[] {
opcodeField = new ByteField((byte)0x02), opcodeField = new ByteField((byte)0x02, "opcode"),
lineDeltaField = new SignedLeb128Field() lineDeltaField = new SignedLeb128Field("line_diff")
}; };
} }
@ -51,10 +50,6 @@ public class AdvanceLine extends CompositeField<AdvanceLine> implements DebugIns
lineDeltaField.cacheValue(lineDelta); lineDeltaField.cacheValue(lineDelta);
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x02; return 0x02;
} }

View File

@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
public class AdvancePC extends CompositeField<AdvancePC> implements DebugInstruction<AdvancePC> { public class AdvancePC extends CompositeField<AdvancePC> implements DebugInstruction<AdvancePC> {
private final Field[] fields;
private final ByteField opcodeField; private final ByteField opcodeField;
private final Leb128Field addressDeltaField; private final Leb128Field addressDeltaField;
public AdvancePC() { public AdvancePC() {
super("DBG_ADVANCE_PC");
fields = new Field[] { fields = new Field[] {
opcodeField = new ByteField((byte)0x01), opcodeField = new ByteField((byte)0x01, "opcode"),
addressDeltaField = new Leb128Field() addressDeltaField = new Leb128Field("addr_diff")
}; };
} }
@ -48,10 +47,6 @@ public class AdvancePC extends CompositeField<AdvancePC> implements DebugInstruc
addressDeltaField.cacheValue(addressDelta); addressDeltaField.cacheValue(addressDelta);
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x01; return 0x01;
} }

View File

@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
public class EndLocal extends CompositeField<EndLocal> implements DebugInstruction<EndLocal> { public class EndLocal extends CompositeField<EndLocal> implements DebugInstruction<EndLocal> {
private final Field[] fields;
private final ByteField opcode; private final ByteField opcode;
private final Leb128Field registerNumber; private final Leb128Field registerNumber;
public EndLocal() { public EndLocal() {
super("DBG_END_LOCAL");
fields = new Field[] { fields = new Field[] {
opcode = new ByteField((byte)0x05), opcode = new ByteField((byte)0x05, "opcode"),
registerNumber = new Leb128Field() registerNumber = new Leb128Field("register_num")
}; };
} }
@ -48,10 +47,6 @@ public class EndLocal extends CompositeField<EndLocal> implements DebugInstructi
this.registerNumber.cacheValue(registerNumber); this.registerNumber.cacheValue(registerNumber);
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x05; return 0x05;
} }

View File

@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
import org.JesusFreke.dexlib.ByteField; import org.JesusFreke.dexlib.ByteField;
public class EndSequence extends CompositeField<EndSequence> implements DebugInstruction<EndSequence> { public class EndSequence extends CompositeField<EndSequence> implements DebugInstruction<EndSequence> {
private final Field[] fields;
public EndSequence() { public EndSequence() {
super("DBG_END_SEQUENCE");
fields = new Field[] { fields = new Field[] {
new ByteField((byte)0x00) new ByteField((byte)0x00, "opcode")
}; };
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x00; return 0x00;
} }

View File

@ -31,15 +31,14 @@ package org.JesusFreke.dexlib.debug;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
public class RestartLocal extends CompositeField<RestartLocal> implements DebugInstruction<RestartLocal> { public class RestartLocal extends CompositeField<RestartLocal> implements DebugInstruction<RestartLocal> {
private final Field[] fields;
private final ByteField opcode; private final ByteField opcode;
private final Leb128Field registerNumber; private final Leb128Field registerNumber;
public RestartLocal() { public RestartLocal() {
super("DBG_RESTART_LOCAL");
fields = new Field[] { fields = new Field[] {
opcode = new ByteField((byte)0x06), opcode = new ByteField((byte)0x06, "opcode"),
registerNumber = new Leb128Field() registerNumber = new Leb128Field("register_num")
}; };
} }
@ -48,10 +47,6 @@ public class RestartLocal extends CompositeField<RestartLocal> implements DebugI
this.registerNumber.cacheValue(registerNumber); this.registerNumber.cacheValue(registerNumber);
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x06; return 0x06;
} }

View File

@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
import org.JesusFreke.dexlib.ByteField; import org.JesusFreke.dexlib.ByteField;
public class SetEpilogueBegin extends CompositeField<SetEpilogueBegin> implements DebugInstruction<SetEpilogueBegin> { public class SetEpilogueBegin extends CompositeField<SetEpilogueBegin> implements DebugInstruction<SetEpilogueBegin> {
private final Field[] fields;
public SetEpilogueBegin() { public SetEpilogueBegin() {
super("DBG_SET_EPILOGUE_BEGIN");
fields = new Field[] { fields = new Field[] {
new ByteField((byte)0x08) new ByteField((byte)0x08, "opcode")
}; };
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x08; return 0x08;
} }

View File

@ -31,15 +31,15 @@ package org.JesusFreke.dexlib.debug;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
public class SetFile extends CompositeField<SetFile> implements DebugInstruction<SetFile> { public class SetFile extends CompositeField<SetFile> implements DebugInstruction<SetFile> {
private final Field[] fields;
private final ByteField opcode; private final ByteField opcode;
private final IndexedItemReference<StringIdItem> fileName; private final IndexedItemReference<StringIdItem> fileName;
public SetFile(DexFile dexFile) { public SetFile(DexFile dexFile) {
super("DBG_SET_FILE");
fields = new Field[] { fields = new Field[] {
opcode = new ByteField((byte)0x09), opcode = new ByteField((byte)0x09, "opcode"),
fileName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()) fileName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
new Leb128p1Field(null), "name_idx")
}; };
} }
@ -48,10 +48,6 @@ public class SetFile extends CompositeField<SetFile> implements DebugInstruction
this.fileName.setReference(fileName); this.fileName.setReference(fileName);
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x09; return 0x09;
} }

View File

@ -33,18 +33,13 @@ import org.JesusFreke.dexlib.Field;
import org.JesusFreke.dexlib.ByteField; import org.JesusFreke.dexlib.ByteField;
public class SetPrologueEnd extends CompositeField<SetPrologueEnd> implements DebugInstruction<SetPrologueEnd> { public class SetPrologueEnd extends CompositeField<SetPrologueEnd> implements DebugInstruction<SetPrologueEnd> {
private final Field[] fields;
public SetPrologueEnd() { public SetPrologueEnd() {
super("DBG_SET_PROLOGUE_END");
fields = new Field[] { fields = new Field[] {
new ByteField((byte)0x07) new ByteField((byte)0x07, "opcode")
}; };
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x07; return 0x07;
} }

View File

@ -33,21 +33,17 @@ import org.JesusFreke.dexlib.Field;
import org.JesusFreke.dexlib.ByteField; import org.JesusFreke.dexlib.ByteField;
public class SpecialOpcode extends CompositeField<SpecialOpcode> implements DebugInstruction<SpecialOpcode> { public class SpecialOpcode extends CompositeField<SpecialOpcode> implements DebugInstruction<SpecialOpcode> {
private final Field[] fields;
private final byte opcode; private final byte opcode;
public SpecialOpcode(byte opcode) { public SpecialOpcode(byte opcode) {
super("SPECIAL_OPCODE");
this.opcode = opcode; this.opcode = opcode;
fields = new Field[] { fields = new Field[] {
new ByteField(opcode) //TODO: annotate the line and address delta
new ByteField(opcode, "opcode")
}; };
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return opcode; return opcode;
} }

View File

@ -31,19 +31,20 @@ package org.JesusFreke.dexlib.debug;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
public class StartLocal extends CompositeField<StartLocal> implements DebugInstruction<StartLocal> { public class StartLocal extends CompositeField<StartLocal> implements DebugInstruction<StartLocal> {
private final Field[] fields;
private final ByteField opcodeField; private final ByteField opcodeField;
private final SignedLeb128Field registerNumber; private final SignedLeb128Field registerNumber;
private final IndexedItemReference<StringIdItem> localName; private final IndexedItemReference<StringIdItem> localName;
private final IndexedItemReference<TypeIdItem> localType; private final IndexedItemReference<TypeIdItem> localType;
public StartLocal(DexFile dexFile) { public StartLocal(DexFile dexFile) {
super("DBG_START_LOCAL");
fields = new Field[] { fields = new Field[] {
opcodeField = new ByteField((byte)0x03), opcodeField = new ByteField((byte)0x03, "opcode"),
registerNumber = new SignedLeb128Field(), registerNumber = new SignedLeb128Field("register_num"),
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()), localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128p1Field()), new Leb128p1Field(null), "name_idx"),
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
new Leb128p1Field(null), "type_idx"),
}; };
} }
@ -54,10 +55,6 @@ public class StartLocal extends CompositeField<StartLocal> implements DebugInstr
this.localType.setReference(localType); this.localType.setReference(localType);
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x03; return 0x03;
} }

View File

@ -31,8 +31,6 @@ package org.JesusFreke.dexlib.debug;
import org.JesusFreke.dexlib.*; import org.JesusFreke.dexlib.*;
public class StartLocalExtended extends CompositeField<StartLocalExtended> implements DebugInstruction<StartLocalExtended> { public class StartLocalExtended extends CompositeField<StartLocalExtended> implements DebugInstruction<StartLocalExtended> {
private final Field[] fields;
private final ByteField opcodeField; private final ByteField opcodeField;
//TODO: signed or unsigned leb? //TODO: signed or unsigned leb?
private final SignedLeb128Field registerNumber; private final SignedLeb128Field registerNumber;
@ -41,12 +39,16 @@ public class StartLocalExtended extends CompositeField<StartLocalExtended> imple
private final IndexedItemReference<StringIdItem> signature; private final IndexedItemReference<StringIdItem> signature;
public StartLocalExtended(DexFile dexFile) { public StartLocalExtended(DexFile dexFile) {
super("DBG_START_LOCAL_EXTENDED");
fields = new Field[] { fields = new Field[] {
opcodeField = new ByteField((byte)0x04), opcodeField = new ByteField((byte)0x04, "opcode"),
registerNumber = new SignedLeb128Field(), registerNumber = new SignedLeb128Field("register_num"),
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()), localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, new Leb128p1Field()), new Leb128p1Field(null), "name_idx"),
signature = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new Leb128p1Field()) localType = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
new Leb128p1Field(null), "type_idx"),
signature = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
new Leb128p1Field(null), "sig_idx")
}; };
} }
@ -59,10 +61,6 @@ public class StartLocalExtended extends CompositeField<StartLocalExtended> imple
this.signature.setReference(signature); this.signature.setReference(signature);
} }
protected Field[] getFields() {
return fields;
}
public byte getOpcode() { public byte getOpcode() {
return 0x04; return 0x04;
} }

View File

@ -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 &gt;= 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 &gt;= 1; the maximum width
*/
public int getAnnotationWidth();
public void setIndentAmount(int indentAmount);
public void indent();
public void deindent();
}

View File

@ -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;
/** &gt;= 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;
/** &gt;= 40 (if used); the desired maximum annotation width */
private int annotationWidth;
/**
* &gt;= 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 &gt;= 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 &gt;= 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 {
/** &gt;= 0; start of annotated range (inclusive) */
private final int start;
/**
* &gt;= 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 &gt;= 0; start of annotated range
* @param end &gt;= 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 &gt;= 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 &gt;= start; the end
*/
public void setEndIfUnset(int end) {
if (this.end == Integer.MAX_VALUE) {
this.end = end;
}
}
/**
* Sets the end as given.
*
* @param end &gt;= 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;
}
}
}

View 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;
/** &gt; 0; the maximum output width */
private final int width;
/** &gt; 0; the maximum indent */
private final int maxIndent;
/** &gt;= 0; current output column (zero-based) */
private int column;
/** whether indent spaces are currently being collected */
private boolean collectingIndent;
/** &gt;= 0; current indent amount */
private int indent;
/**
* Constructs an instance.
*
* @param out non-null; writer to send final output to
* @param width &gt;= 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 &gt;= 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;
}
}

View 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;
/** &gt; 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 &gt; 0; width of the first column
* @param spacer non-null; spacer string
* @param s2 non-null; second string
* @param width2 &gt; 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 &gt; 0; width of the left column, in characters
* @param rightWidth &gt; 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 &gt;= 1; width of the left column, in characters
* @param rightWidth &gt;= 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 &gt;= 0; the number of spaces to write
*/
private static void writeSpaces(Writer out, int amt) throws IOException {
while (amt > 0) {
out.write(' ');
amt--;
}
}
}

View File

@ -30,6 +30,7 @@ package org.JesusFreke.smali;
import org.JesusFreke.dexlib.DexFile; import org.JesusFreke.dexlib.DexFile;
import org.JesusFreke.dexlib.util.ByteArrayOutput; import org.JesusFreke.dexlib.util.ByteArrayOutput;
import org.JesusFreke.dexlib.util.ByteArrayAnnotatedOutput;
import org.antlr.runtime.ANTLRInputStream; import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.Token; import org.antlr.runtime.Token;
@ -38,6 +39,7 @@ import org.antlr.runtime.tree.CommonTreeNodeStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileWriter;
public class smali public class smali
{ {
@ -70,7 +72,8 @@ public class smali
dexFile.place(); dexFile.place();
try try
{ {
ByteArrayOutput out = new ByteArrayOutput(); ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
out.enableAnnotations(120, true);
dexFile.writeTo(out); dexFile.writeTo(out);
byte[] bytes = out.toByteArray(); byte[] bytes = out.toByteArray();
@ -78,6 +81,17 @@ public class smali
DexFile.calcSignature(bytes); DexFile.calcSignature(bytes);
DexFile.calcChecksum(bytes); DexFile.calcChecksum(bytes);
out.finishAnnotating();
FileWriter fileWriter = new FileWriter("classes.dump");
out.writeAnnotationsTo(fileWriter);
fileWriter.flush();
fileWriter.close();
FileOutputStream fileOutputStream = new FileOutputStream("classes.dex"); FileOutputStream fileOutputStream = new FileOutputStream("classes.dex");
fileOutputStream.write(bytes); fileOutputStream.write(bytes);

View File

@ -70,7 +70,7 @@ public class TryListBuilderTest
CodeItem.EncodedTypeAddrPair typeAddrPair = encodedCatchHandler.getHandler(i); CodeItem.EncodedTypeAddrPair typeAddrPair = encodedCatchHandler.getHandler(i);
Handler handler = handlers[i]; Handler handler = handlers[i];
Assert.assertTrue(typeAddrPair.getType().toString().compareTo(handler.type) == 0); Assert.assertTrue(typeAddrPair.getTypeReferenceField().toString().compareTo(handler.type) == 0);
Assert.assertTrue(typeAddrPair.getHandlerAddress() == handler.handlerAddress); Assert.assertTrue(typeAddrPair.getHandlerAddress() == handler.handlerAddress);
} }
} }