From 281b510a9c2b4ae914ab28b9a4f4d622e5861da6 Mon Sep 17 00:00:00 2001
From: "JesusFreke@JesusFreke.com"
Date: Tue, 23 Jun 2009 01:44:36 +0000
Subject: [PATCH] - started writing javadoc documentation - cleanup of DexFile,
and related refactoring
git-svn-id: https://smali.googlecode.com/svn/trunk@211 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
---
dexlib/pom.xml | 8 +
.../jf/dexlib/AnnotationDirectoryItem.java | 2 +-
.../java/org/jf/dexlib/AnnotationItem.java | 4 +-
.../java/org/jf/dexlib/AnnotationSetItem.java | 2 +-
.../org/jf/dexlib/AnnotationSetRefList.java | 2 +-
.../java/org/jf/dexlib/ClassDataItem.java | 2 +-
.../main/java/org/jf/dexlib/ClassDefItem.java | 2 +-
.../java/org/jf/dexlib/Code/Instruction.java | 8 +-
.../src/main/java/org/jf/dexlib/CodeItem.java | 2 +-
.../dexlib/Debug/DebugInstructionFactory.java | 2 +-
.../org/jf/dexlib/Debug/RestartLocal.java | 13 +-
.../java/org/jf/dexlib/Debug/StartLocal.java | 2 +-
.../jf/dexlib/Debug/StartLocalExtended.java | 2 +-
.../java/org/jf/dexlib/DebugInfoItem.java | 2 +-
.../src/main/java/org/jf/dexlib/DexFile.java | 458 +++++++++++++++---
.../java/org/jf/dexlib/EncodedArrayItem.java | 4 +-
.../EncodedIndexedItemReference.java | 3 +-
.../main/java/org/jf/dexlib/FieldIdItem.java | 2 +-
.../main/java/org/jf/dexlib/HeaderItem.java | 51 +-
.../main/java/org/jf/dexlib/IndexedItem.java | 3 +-
.../java/org/jf/dexlib/IndexedSection.java | 9 +-
dexlib/src/main/java/org/jf/dexlib/Item.java | 4 +-
.../java/org/jf/dexlib/ItemReference.java | 2 +-
.../src/main/java/org/jf/dexlib/MapField.java | 35 +-
.../src/main/java/org/jf/dexlib/MapItem.java | 53 +-
.../main/java/org/jf/dexlib/MethodIdItem.java | 2 +-
.../java/org/jf/dexlib/OffsettedItem.java | 3 +-
.../java/org/jf/dexlib/OffsettedSection.java | 5 +-
.../main/java/org/jf/dexlib/ProtoIdItem.java | 4 +-
.../src/main/java/org/jf/dexlib/Section.java | 8 +-
.../java/org/jf/dexlib/StringDataItem.java | 8 +-
.../main/java/org/jf/dexlib/StringIdItem.java | 4 +-
.../main/java/org/jf/dexlib/TypeIdItem.java | 2 +-
.../main/java/org/jf/dexlib/TypeListItem.java | 8 +-
dexlib/src/test/java/TryListBuilderTest.java | 36 +-
35 files changed, 565 insertions(+), 192 deletions(-)
diff --git a/dexlib/pom.xml b/dexlib/pom.xml
index e89d0a55..b7c0887d 100644
--- a/dexlib/pom.xml
+++ b/dexlib/pom.xml
@@ -10,6 +10,14 @@
smali-pom
0.91-SNAPSHOT
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
junit
diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java
index f0790644..b485930c 100644
--- a/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java
@@ -54,7 +54,7 @@ public class AnnotationDirectoryItem extends OffsettedItem(
diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java
index b7ab41dc..e2bc94f8 100644
--- a/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java
@@ -35,7 +35,7 @@ public class AnnotationItem extends OffsettedItem {
private final AnnotationEncodedValueSubField annotationField;
public AnnotationItem(DexFile dexFile, int offset) {
- super(offset);
+ super(dexFile, offset);
fields = new Field[] {
visibilityField = new ByteField("visibility"),
@@ -45,7 +45,7 @@ public class AnnotationItem extends OffsettedItem {
public AnnotationItem(DexFile dexFile, AnnotationVisibility visibility,
AnnotationEncodedValueSubField annotation) {
- super(-1);
+ super(dexFile, -1);
fields = new Field[] {
this.visibilityField = new ByteField(visibility.value, "visibility"),
diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java
index 725411c1..48356f07 100644
--- a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java
@@ -39,7 +39,7 @@ public class AnnotationSetItem extends OffsettedItem {
private final FieldListField> annotationsListField;
public AnnotationSetItem(final DexFile dexFile, int offset) {
- super(offset);
+ super(dexFile, offset);
fields = new Field[] {
annotationCountField = new ListSizeField(annotationReferences, new IntegerField("size")),
diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java
index 403f9a7c..d652c5d2 100644
--- a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java
+++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java
@@ -39,7 +39,7 @@ public class AnnotationSetRefList extends OffsettedItem {
private final FieldListField> annotationSetsListField;
public AnnotationSetRefList(final DexFile dexFile, int offset) {
- super(offset);
+ super(dexFile, offset);
fields = new Field[] {
annotationSetCountField = new ListSizeField(annotationSetReferences, new IntegerField("size")),
diff --git a/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java b/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java
index 9b43051d..f74b05c1 100644
--- a/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java
@@ -52,7 +52,7 @@ public class ClassDataItem extends OffsettedItem {
private ClassDefItem parent = null;
public ClassDataItem(final DexFile dexFile, int offset) {
- super(offset);
+ super(dexFile, offset);
fields = new Field[] {
staticFieldsCountField = new ListSizeField(staticFieldList,
diff --git a/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java b/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java
index 837297d3..130398f8 100644
--- a/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java
@@ -50,7 +50,7 @@ public class ClassDefItem extends IndexedItem {
private final DexFile dexFile;
public ClassDefItem(DexFile dexFile, int index) {
- super(index);
+ super(dexFile, index);
this.dexFile = dexFile;
diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Instruction.java b/dexlib/src/main/java/org/jf/dexlib/Code/Instruction.java
index 4a63a2d9..b77ca1cd 100644
--- a/dexlib/src/main/java/org/jf/dexlib/Code/Instruction.java
+++ b/dexlib/src/main/java/org/jf/dexlib/Code/Instruction.java
@@ -161,16 +161,16 @@ public abstract class Instruction {
if (referencedItem != null) {
switch (opcode.referenceType) {
case string:
- clone.referencedItem = dexFile.StringIdsSection.intern(dexFile, (StringIdItem)referencedItem);
+ clone.referencedItem = dexFile.StringIdsSection.intern((StringIdItem)referencedItem);
break;
case type:
- clone.referencedItem = dexFile.TypeIdsSection.intern(dexFile, (TypeIdItem)referencedItem);
+ clone.referencedItem = dexFile.TypeIdsSection.intern((TypeIdItem)referencedItem);
break;
case field:
- clone.referencedItem = dexFile.FieldIdsSection.intern(dexFile, (FieldIdItem)referencedItem);
+ clone.referencedItem = dexFile.FieldIdsSection.intern((FieldIdItem)referencedItem);
break;
case method:
- clone.referencedItem = dexFile.MethodIdsSection.intern(dexFile, (MethodIdItem)referencedItem);
+ clone.referencedItem = dexFile.MethodIdsSection.intern((MethodIdItem)referencedItem);
break;
case none:
break;
diff --git a/dexlib/src/main/java/org/jf/dexlib/CodeItem.java b/dexlib/src/main/java/org/jf/dexlib/CodeItem.java
index 69035079..cf8275e5 100644
--- a/dexlib/src/main/java/org/jf/dexlib/CodeItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/CodeItem.java
@@ -57,7 +57,7 @@ public class CodeItem extends OffsettedItem {
private MethodIdItem parent = null;
public CodeItem(final DexFile dexFile, int offset) {
- super(offset);
+ super(dexFile, offset);
instructionList = new ArrayList();
diff --git a/dexlib/src/main/java/org/jf/dexlib/Debug/DebugInstructionFactory.java b/dexlib/src/main/java/org/jf/dexlib/Debug/DebugInstructionFactory.java
index f01a7127..4b4e2ffd 100644
--- a/dexlib/src/main/java/org/jf/dexlib/Debug/DebugInstructionFactory.java
+++ b/dexlib/src/main/java/org/jf/dexlib/Debug/DebugInstructionFactory.java
@@ -57,7 +57,7 @@ public abstract class DebugInstructionFactory {
case 0x05:
return new EndLocal();
case 0x06:
- return new RestartLocal(dexFile.isForDumping());
+ return new RestartLocal(dexFile);
case 0x07:
return new SetPrologueEnd();
case 0x08:
diff --git a/dexlib/src/main/java/org/jf/dexlib/Debug/RestartLocal.java b/dexlib/src/main/java/org/jf/dexlib/Debug/RestartLocal.java
index 0500e832..9c4e55c1 100644
--- a/dexlib/src/main/java/org/jf/dexlib/Debug/RestartLocal.java
+++ b/dexlib/src/main/java/org/jf/dexlib/Debug/RestartLocal.java
@@ -34,18 +34,23 @@ public class RestartLocal extends CompositeField implements DebugI
private final ByteField opcode;
private final Leb128Field registerNumber;
- public RestartLocal(boolean forDumping) {
+ public RestartLocal(DexFile dexFile) {
super("DBG_RESTART_LOCAL");
fields = new Field[] {
opcode = new ByteField((byte)0x06, "opcode"),
- registerNumber = forDumping?new Leb128Field.PossiblySignedLeb128Field("register_num"):
+ registerNumber = dexFile.getPreserveSignedRegisters()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
new Leb128Field("register_num")
};
}
public RestartLocal(int registerNumber) {
- this(false);
- this.registerNumber.cacheValue(registerNumber);
+ super("DBG_RESTART_LOCAL");
+ fields = new Field[] {
+ this.opcode = new ByteField((byte)0x06, "opcode"),
+ this.registerNumber = new Leb128Field(registerNumber, "register_num")
+ };
+
+
}
public byte getOpcode() {
diff --git a/dexlib/src/main/java/org/jf/dexlib/Debug/StartLocal.java b/dexlib/src/main/java/org/jf/dexlib/Debug/StartLocal.java
index 024d3ac3..cd6fb7db 100644
--- a/dexlib/src/main/java/org/jf/dexlib/Debug/StartLocal.java
+++ b/dexlib/src/main/java/org/jf/dexlib/Debug/StartLocal.java
@@ -40,7 +40,7 @@ public class StartLocal extends CompositeField implements DebugInstr
super("DBG_START_LOCAL");
fields = new Field[] {
opcodeField = new ByteField((byte)0x03, "opcode"),
- registerNumber = dexFile.isForDumping()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
+ registerNumber = dexFile.getPreserveSignedRegisters()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
new Leb128Field("register_num"),
localName = new IndexedItemReference(dexFile.StringIdsSection,
new Leb128p1Field(null), "name_idx"),
diff --git a/dexlib/src/main/java/org/jf/dexlib/Debug/StartLocalExtended.java b/dexlib/src/main/java/org/jf/dexlib/Debug/StartLocalExtended.java
index 0e58b125..c05c7caf 100644
--- a/dexlib/src/main/java/org/jf/dexlib/Debug/StartLocalExtended.java
+++ b/dexlib/src/main/java/org/jf/dexlib/Debug/StartLocalExtended.java
@@ -41,7 +41,7 @@ public class StartLocalExtended extends CompositeField imple
super("DBG_START_LOCAL_EXTENDED");
fields = new Field[] {
opcodeField = new ByteField((byte)0x04, "opcode"),
- registerNumber = dexFile.isForDumping()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
+ registerNumber = dexFile.getPreserveSignedRegisters()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
new Leb128Field("register_num"),
localName = new IndexedItemReference(dexFile.StringIdsSection,
new Leb128p1Field(null), "name_idx"),
diff --git a/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java b/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java
index f8ac7411..82d6c20f 100644
--- a/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java
@@ -52,7 +52,7 @@ public class DebugInfoItem extends OffsettedItem {
private CodeItem parent = null;
public DebugInfoItem(final DexFile dexFile, int offset) {
- super(offset);
+ super(dexFile, offset);
fields = new Field[] {
lineStartField = new Leb128Field("line_start"),
diff --git a/dexlib/src/main/java/org/jf/dexlib/DexFile.java b/dexlib/src/main/java/org/jf/dexlib/DexFile.java
index 3a9e89a6..8ec246e3 100644
--- a/dexlib/src/main/java/org/jf/dexlib/DexFile.java
+++ b/dexlib/src/main/java/org/jf/dexlib/DexFile.java
@@ -38,22 +38,140 @@ import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
-import java.util.List;
import java.util.zip.Adler32;
+ /**
+ * Main use cases
+ *
+ * These are the main use cases that drove the design of this library
+ *
+ *
+ * Annotate an existing dex file - In this case, the intent is to document the structure of
+ * an existing dex file. We want to be able to read in the dex file, and then write out a dex file
+ * that is exactly the same (while adding annotation information to an AnnotatedOutput object)
+ *
+ * Canonicalize an existing dex file - In this case, the intent is to rewrite an existing dex file
+ * so that it is in a canonical form. There is a certain amount of leeway in how various types of
+ * tems in a dex file are ordered or represented. It is sometimes useful to be able to easily
+ * compare a disassebled and reassembled dex file with the original dex file. If both dex-files are
+ * written canonically, they "should" match exactly, barring any explicit changes to the reassembled
+ * file.
+ *
+ * Currently, there are a couple of pieces of information that probably won't match exactly
+ *
+ * - the order of exception handlers in the
EncodedCatchHandlerList
for a method
+ * - the ordering of some of the debug info in the
{@link DebugInfoItem}
for a method
+ *
+ *
+ *
+ * Note that the above discrepancies should typically only be "intra-item" differences. They
+ * shouldn't change the size of the item, or affect how anything else is placed or laid out
+ *
+ * Creating a dex file from scratch - In this case, a blank dex file is created and then classes
+ * are added to it incrementally by calling the {@link Section#intern intern} method of
+ * {@link DexFile#ClassDefsSection}, which will add all the information necessary to represent the given
+ * class. For example, when assembling a dex file from a set of assembly text files.
+ *
+ * In this case, we can choose to write the dex file in a canonical form or not. It is somewhat
+ * slower to write it in a canonical format, due to the extra sorting and calculations that are
+ * required.
+ *
+ *
+ * Reading in the dex file - In this case, the intent is to read in a dex file and expose all the
+ * data to the calling application. For example, when disassembling a dex file into a text based
+ * assembly format, or doing other misc processing of the dex file.
+ *
+ *
+ * Other use cases
+ *
+ * These are other use cases that are possible, but did not drive the design of the library.
+ * No effort was made to test these use cases or ensure that they work. Some of these could
+ * probably be better achieved with a disassemble - modify - reassemble type process, using
+ * smali/baksmali or another assembler/disassembler pair that are compatible with each other
+ *
+ *
+ * - deleting classes/methods/etc. from a dex file
+ * - merging 2 dex files
+ * - splitting a dex file
+ * - moving classes from 1 dex file to another
+ * - removing the debug information from a dex file
+ * - obfustication of a dex file
+ *
+ */
public class DexFile
{
+ /**
+ * A mapping from ItemType to the section that contains items of the given type
+ */
private final HashMap sectionsByType;
+
+ /**
+ * Ordered lists of the indexed and offsetted sections. The order of these lists specifies the order
+ * that the sections will be written in
+ */
private final IndexedSection[] indexedSections;
private final OffsettedSection[] offsettedSections;
- private int fileSize;
- private int dataOffset;
- private int dataSize;
- private boolean forDumping;
+ /**
+ * dalvik had a bug where it wrote the registers for certain types of debug info in a signed leb
+ * format, instead of an unsigned leb format. There are no negative registers of course, but
+ * certain positive values have a different encoding depending on whether they are encoded as
+ * an unsigned leb128 or a signed leb128. Specifically, the signed leb128 is 1 byte longer in some cases.
+ *
+ * This determine whether we should keep any signed registers as signed, or force all register to
+ * unsigned. By default we don't keep track of whether they were signed or not, and write them back
+ * out as unsigned. This option only has an effect when reading an existing dex file. It has no
+ * effect when a dex file is created from scratch
+ *
+ * The 2 main use-cases in play are
+ * 1. Annotate an existing dex file - In this case, preserveSignedRegisters should be false, so that we keep
+ * track of any signed registers and write them back out as signed Leb128 values.
+ *
+ * 2. Canonicalize an existing dex file - In this case, fixRegisters should be true, so that all
+ * registers in the debug info are written as unsigned Leb128 values regardless of how they were
+ * originally encoded
+ */
+ private final boolean preserveSignedRegisters;
+
+ /**
+ * When true, this prevents any sorting of the items during placement of the dex file. This
+ * should *only* be set to true when this dex file was read in from an existing (valid) dex file,
+ * and no modifications were made (i.e. no items added or deleted). Otherwise it is likely that
+ * an invalid dex file will be generated.
+ *
+ * This is useful for the first use case (annotating an existing dex file). This ensures the items
+ * retain the same order as in the original dex file.
+ */
+ private boolean inplace = false;
+
+ /**
+ * When true, this imposes an full ordering on all the items, to force them into a (possibly
+ * arbitrary) canonical order. When false, only the items that the dex format specifies
+ * an order for are sorted. The rest of the items are not ordered.
+ *
+ * This is useful for the second use case (canonicalizing an existing dex file) or possibly for
+ * the third use case (creating a dex file from scratch), if there is a need to write the new
+ * dex file in a canonical form.
+ */
+ private boolean sortAllItems = false;
+
+
+ /**
+ * this is used to access the dex file from within inner classes, when they declare fields or
+ * variable that hide fields on this object
+ */
private final DexFile dexFile = this;
- private DexFile() {
+
+ /**
+ * A private constructor containing common code to initialize the section maps and lists
+ * @param preserveSignedRegisters If true, keep track of any registers in the debug information
+ * that are signed, so they will be written in the same format. See
+ * getPreserveSignedRegisters()
+ */
+ private DexFile(boolean preserveSignedRegisters) {
+ this.preserveSignedRegisters = preserveSignedRegisters;
+
sectionsByType = new HashMap(18);
sectionsByType.put(ItemType.TYPE_ANNOTATION_ITEM, AnnotationsSection);
@@ -94,25 +212,58 @@ public class DexFile
AnnotationsSection,
EncodedArraysSection,
ClassDataSection,
- DebugInfoItemsSection
+ DebugInfoItemsSection
};
}
- public DexFile(File file) {
- this(file, false);
+
+ /**
+ * Construct a new DexFile instance by reading in the given dex file.
+ * @param file The dex file to read in
+ */
+ public DexFile(String file) {
+ this(new File(file), true);
}
- public DexFile(File file, boolean forDumping) {
- this();
- Input in = new ByteArrayInput(FileUtils.readFile(file));
+ /**
+ * Construct a new DexFile instance by reading in the given dex file,
+ * and optionally keep track of any registers in the debug information that are signed,
+ * so they will be written in the same format.
+ * @param file The dex file to read in
+ * @param preserveSignedRegisters If true, keep track of any registers in the debug information
+ * that are signed, so they will be written in the same format. See
+ * getPreserveSignedRegisters()
+ */
+ public DexFile(String file, boolean preserveSignedRegisters) {
+ this(new File(file), preserveSignedRegisters);
+ }
- this.forDumping = forDumping;
+ /**
+ * Construct a new DexFile instead by reading in the given dex file.
+ * @param file The dex file to read in
+ */
+ public DexFile(File file) {
+ this(file, true);
+ }
+
+ /**
+ * Construct a new DexFile instance by reading in the given dex file,
+ * and optionally keep track of any registers in the debug information that are signed,
+ * so they will be written in the same format.
+ * @param file The dex file to read in
+ * @param preserveSignedRegisters If true, keep track of any registers in the debug information
+ * that are signed, so they will be written in the same format.
+ * @see #getPreserveSignedRegisters
+ */
+ public DexFile(File file, boolean preserveSignedRegisters) {
+ this(preserveSignedRegisters);
+
+ Input in = new ByteArrayInput(FileUtils.readFile(file));
HeaderItemSection.readFrom(1, in);
HeaderItem headerItem = HeaderItemSection.items.get(0);
in.setCursor(headerItem.getMapOffset());
-
MapSection.readFrom(1, in);
MapField[] mapEntries = MapSection.items.get(0).getMapEntries();
@@ -121,6 +272,11 @@ public class DexFile
mapMap.put(mapField.getSectionItemType().getMapValue(), mapField);
}
+ /**
+ * This defines the order in which the sections are read in. This is not
+ * necessarily the order in which the appear in the file.
+ */
+ //TODO: do we *need* to read them in a specific order, rather than the order that is in the file?
int[] sectionTypes = new int[] {
ItemType.TYPE_HEADER_ITEM.getMapValue(),
ItemType.TYPE_STRING_ID_ITEM.getMapValue(),
@@ -147,64 +303,169 @@ public class DexFile
if (mapField != null) {
Section section = sectionsByType.get(mapField.getSectionItemType());
if (section != null) {
- in.setCursor(mapField.getSectionOffset());
- section.readFrom(mapField.getSectionSize(), in);
+ in.setCursor(mapField.getCachedSectionOffset());
+ section.readFrom(mapField.getCachedSectionSize(), in);
}
}
}
}
- public static DexFile makeBlankDexFile() {
- DexFile dexFile = new DexFile();
- try
- {
- dexFile.HeaderItemSection.intern(dexFile, new HeaderItem(dexFile, 0));
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
+ /**
+ * Constructs a new, blank dex file. Classes can be added to this dex file by calling
+ * the Section.intern()
method of ClassDefsSection
+ */
+ public DexFile() {
+ this(true);
- dexFile.MapSection.intern(dexFile, MapItem.makeBlankMapItem(dexFile));
- return dexFile;
+ HeaderItemSection.intern(new HeaderItem(dexFile, 0));
+ MapSection.intern(new MapItem(dexFile));
}
+ /**
+ * Convenience method to retrieve the header item
+ * @return the header item
+ */
+ public HeaderItem getHeaderItem() {
+ return HeaderItemSection.getItems().get(0);
+ }
+ /**
+ * Convenience method to retrieve the map item
+ * @return the map item
+ */
+ public MapItem getMapItem() {
+ return MapSection.getItems().get(0);
+ }
+
+ /**
+ * Get the Section
containing items of the same type as the given item
+ * @param item Get the Section
that contains items of this type
+ * @param The specific item subclass - inferred from the passed item
+ * @return the Section
containing items of the same type as the given item
+ */
public Section getSectionForItem(T item) {
return sectionsByType.get(item.getItemType());
}
+ /**
+ * Get the Section
containing items of the given type
+ * @param itemType the type of item
+ * @return the Section
containing items of the given type
+ */
public Section getSectionForType(ItemType itemType) {
return sectionsByType.get(itemType);
}
- public int getFileSize() {
- return fileSize;
+ /**
+ * Get a boolean value indicating whether this dex file preserved any signed
+ * registers in the debug info as it read the dex file in. By default, the dex file
+ * doesn't check whether the registers are encoded as unsigned or signed values.
+ *
+ * This does *not* affect the actual register value that is read in. The value is
+ * read correctly regardless
+ *
+ * This does affect whether any signed registers will retain the same encoding or be
+ * forced to the (correct) unsigned encoding when the dex file is written back out.
+ *
+ * See the discussion about signed register values in the documentation for
+ * DexFile
+ * @return a boolean indicating whether this dex file preserved any signed registers
+ * as it was read in
+ */
+ public boolean getPreserveSignedRegisters() {
+ return preserveSignedRegisters;
}
- public int getDataOffset() {
- return dataOffset;
+ /**
+ * Get a boolean value indicating whether all items should be placed into a
+ * (possibly arbitrary) "canonical" ordering. If false, then only the items
+ * that must be ordered per the dex specification are sorted.
+ *
+ * When true, writing the dex file involves somewhat more overhead
+ *
+ * If both SortAllItems and Inplace are true, Inplace takes precedence
+ * @return a boolean value indicating whether all items should be sorted
+ */
+ public boolean getSortAllItems() {
+ return this.sortAllItems;
}
- public int getDataSize() {
- return dataSize;
+ /**
+ * Set a boolean value indicating whether all items should be placed into a
+ * (possibly arbitrary) "canonical" ordering. If false, then only the items
+ * that must be ordered per the dex specification are sorted.
+ *
+ * When true, writing the dex file involves somewhat more overhead
+ *
+ * If both SortAllItems and Inplace are true, Inplace takes precedence
+ * @param value a boolean value indicating whether all items should be sorted
+ */
+ public void setSortAllItems(boolean value) {
+ this.sortAllItems = value;
}
- public boolean isForDumping() {
- return forDumping;
+ /**
+ * Get a boolean value indicating whether items in this dex file should be
+ * written back out "in-place", or whether the normal layout logic should be
+ * applied.
+ *
+ * This should only be used for a dex file that has been read from an existing
+ * dex file, and no modifications have been made to the dex file. Otherwise,
+ * there is a good chance that the resulting dex file will be invalid due to
+ * items that aren't placed correctly
+ *
+ * If both SortAllItems and Inplace are true, Inplace takes precedence
+ * @return a boolean value indicating whether items in this dex file should be
+ * written back out in-place.
+ */
+ public boolean getInplace() {
+ return this.inplace;
}
- public void place(boolean sort) {
- int offset = 0;
+ /**
+ * Set a boolean value indicating whether items in this dex file should be
+ * written back out "in-place", or whether the normal layout logic should be
+ * applied.
+ *
+ * This should only be used for a dex file that has been read from an existing
+ * dex file, and no modifications have been made to the dex file. Otherwise,
+ * there is a good chance that the resulting dex file will be invalid due to
+ * items that aren't placed correctly
+ *
+ * If both SortAllItems and Inplace are true, Inplace takes precedence
+ * @param value a boolean value indicating whether items in this dex file should be
+ * written back out in-place.
+ */
+ public void setInplace(boolean value) {
+ this.inplace = value;
+ }
- offset = HeaderItemSection.place(offset);
+ /**
+ * This method should be called before writing a dex file. It sorts the sections
+ * as needed or as indicated by getSortAllItems()
and getInplace()
,
+ * and then performs a pass through all of the items, finalizing the position (i.e.
+ * index and/or offset) of each item in the dex file.
+ *
+ * This step is needed primarily so that the indexes and offsets of all indexed and
+ * offsetted items are available when writing references to those items elsewhere.
+ */
+ public void place() {
+ HeaderItem headerItem = getHeaderItem();
+
+ int offset = HeaderItemSection.place(0);
+
+ int dataOffset;
for (IndexedSection indexedSection: indexedSections) {
offset = indexedSection.place(offset);
}
dataOffset = offset;
+ headerItem.setDataOffset(dataOffset);
+ //TODO: if inplace is true, we need to use the order of the sections as they were in the original file
for (OffsettedSection offsettedSection: offsettedSections) {
- if (sort) {
+ if (this.sortAllItems && !this.inplace) {
offsettedSection.sortSection();
}
offset = offsettedSection.place(offset);
@@ -212,12 +473,26 @@ public class DexFile
offset = MapSection.place(offset);
- dataSize = offset - dataOffset;
- fileSize = offset;
+
+ headerItem.setFileSize(offset);
+ headerItem.setDataSize(offset - dataOffset);
}
+ /**
+ * Writes the dex file to the give AnnotatedOutput
object. If
+ * out.Annotates()
is true, then annotations that document the format
+ * of the dex file are written.
+ *
+ * You must call place()
on this dex file, before calling this method
+ * @param out the AnnotatedOutput object to write the dex file and annotations to
+ *
+ * After calling this method, you should call calcSignature()
and
+ * then calcChecksum()
on the resulting byte array, to calculate the
+ * signature and checksum in the header
+ */
public void writeTo(AnnotatedOutput out) {
HeaderItemSection.writeTo(out);
+
for (IndexedSection indexedSection: indexedSections) {
indexedSection.writeTo(out);
}
@@ -229,48 +504,74 @@ public class DexFile
MapSection.writeTo(out);
}
- public final IndexedSection HeaderItemSection = new IndexedSection() {
+ /**
+ * The IndexedSection
containing the sole HeaderItem
item. Use
+ * getHeaderItem()
instead.
+ */
+ public final IndexedSection HeaderItemSection = new IndexedSection(this) {
protected HeaderItem make(int index) {
return new HeaderItem(dexFile, index);
}
};
- public final IndexedSection StringIdsSection = new IndexedSection() {
+ /**
+ * The IndexedSection
containing StringIdItem
items
+ */
+ public final IndexedSection StringIdsSection = new IndexedSection(this) {
protected StringIdItem make(int index) {
return new StringIdItem(dexFile, index);
}
};
- public final IndexedSection TypeIdsSection = new IndexedSection() {
+ /**
+ * The IndexedSection
containing TypeIdItem
items
+ */
+ public final IndexedSection TypeIdsSection = new IndexedSection(this) {
protected TypeIdItem make(int index) {
return new TypeIdItem(dexFile, index);
}
};
- public final IndexedSection ProtoIdsSection = new IndexedSection() {
+ /**
+ * The IndexedSection
containing ProtoIdItem
items
+ */
+ public final IndexedSection ProtoIdsSection = new IndexedSection(this) {
protected ProtoIdItem make(int index) {
return new ProtoIdItem(dexFile, index);
}
};
- public final IndexedSection FieldIdsSection = new IndexedSection() {
+ /**
+ * The IndexedSection
containing FieldIdItem
items
+ */
+ public final IndexedSection FieldIdsSection = new IndexedSection(this) {
protected FieldIdItem make(int index) {
return new FieldIdItem(dexFile, index);
}
};
- public final IndexedSection MethodIdsSection = new IndexedSection() {
+ /**
+ * The IndexedSection
containing MethodIdItem
items
+ */
+ public final IndexedSection MethodIdsSection = new IndexedSection(this) {
protected MethodIdItem make(int index) {
return new MethodIdItem(dexFile, index);
}
};
- public final IndexedSection ClassDefsSection = new IndexedSection() {
+ /**
+ * The IndexedSection
containing ClassDefItem
items
+ */
+ public final IndexedSection ClassDefsSection = new IndexedSection(this) {
protected ClassDefItem make(int index) {
return new ClassDefItem(dexFile, index);
}
public int place(int offset) {
+ if (dexFile.getInplace()) {
+ return super.place(offset);
+ }
+
int ret = ClassDefItem.placeClassDefItems(this, offset);
this.offset = items.get(0).getOffset();
@@ -278,7 +579,11 @@ public class DexFile
}
};
- public final IndexedSection MapSection = new IndexedSection() {
+ /**
+ * The IndexedSection
containing the sole MapItem
. Use
+ * getMapItem()
instead
+ */
+ public final IndexedSection MapSection = new IndexedSection(this) {
protected MapItem make(int index) {
return new MapItem(dexFile, index);
}
@@ -289,64 +594,94 @@ public class DexFile
}
};
- public final OffsettedSection TypeListsSection = new OffsettedSection() {
+ /**
+ * The OffsettedSection
containing TypeListItem
items
+ */
+ public final OffsettedSection TypeListsSection = new OffsettedSection(this) {
protected TypeListItem make(int offset) {
return new TypeListItem(dexFile, offset);
}
};
+ /**
+ * The OffsettedSection
containing AnnotationSetRefList
items
+ */
public final OffsettedSection AnnotationSetRefListsSection =
- new OffsettedSection() {
+ new OffsettedSection(this) {
protected AnnotationSetRefList make(int offset) {
return new AnnotationSetRefList(dexFile, offset);
}
};
+ /**
+ * The OffsettedSection
containing AnnotationSetItem
items
+ */
public final OffsettedSection AnnotationSetsSection =
- new OffsettedSection() {
+ new OffsettedSection(this) {
protected AnnotationSetItem make(int offset) {
return new AnnotationSetItem(dexFile, offset);
}
};
- public final OffsettedSection ClassDataSection = new OffsettedSection() {
+ /**
+ * The OffsettedSection
containing ClassDataItem
items
+ */
+ public final OffsettedSection ClassDataSection = new OffsettedSection(this) {
protected ClassDataItem make(int offset) {
return new ClassDataItem(dexFile, offset);
}
};
- public final OffsettedSection CodeItemsSection = new OffsettedSection() {
+ /**
+ * The OffsettedSection
containing CodeItem
items
+ */
+ public final OffsettedSection CodeItemsSection = new OffsettedSection(this) {
protected CodeItem make(int offset) {
return new CodeItem(dexFile, offset);
}
};
- public final OffsettedSection StringDataSection = new OffsettedSection() {
+ /**
+ * The OffsettedSection
containing StringDataItem
items
+ */
+ public final OffsettedSection StringDataSection = new OffsettedSection(this) {
protected StringDataItem make(int offset) {
- return new StringDataItem(offset);
+ return new StringDataItem(dexFile, offset);
}
};
- public final OffsettedSection DebugInfoItemsSection = new OffsettedSection() {
+ /**
+ * The OffsettedSection
containing DebugInfoItem
items
+ */
+ public final OffsettedSection DebugInfoItemsSection = new OffsettedSection(this) {
protected DebugInfoItem make(int offset) {
return new DebugInfoItem(dexFile, offset);
}
};
- public final OffsettedSection AnnotationsSection = new OffsettedSection() {
+ /**
+ * The OffsettedSection
containing AnnotationItem
items
+ */
+ public final OffsettedSection AnnotationsSection = new OffsettedSection(this) {
protected AnnotationItem make(int offset) {
return new AnnotationItem(dexFile, offset);
}
};
- public final OffsettedSection EncodedArraysSection = new OffsettedSection() {
+ /**
+ * The OffsettedSection
containing EncodedArrayItem
items
+ */
+ public final OffsettedSection EncodedArraysSection = new OffsettedSection(this) {
protected EncodedArrayItem make(int offset) {
return new EncodedArrayItem(dexFile, offset);
}
};
+ /**
+ * The OffsettedSection
containing AnnotationDirectoryItem
items
+ */
public final OffsettedSection AnnotationDirectoriesSection =
- new OffsettedSection() {
+ new OffsettedSection(this) {
protected AnnotationDirectoryItem make(int offset) {
return new AnnotationDirectoryItem(dexFile, offset);
}
@@ -354,8 +689,9 @@ public class DexFile
/**
- * Calculates the signature for the .dex
file in the
- * given array, and modify the array to contain it.
+ * Calculates the signature for the dex file in the given byte array,
+ * and then writes the signature to the appropriate location in the header
+ * containing in the array
*
* @param bytes non-null; the bytes of the file
*/
diff --git a/dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java b/dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java
index 19575dab..5a4c0303 100644
--- a/dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java
@@ -37,7 +37,7 @@ public class EncodedArrayItem extends OffsettedItem {
private final ArrayEncodedValueSubField encodedArray;
public EncodedArrayItem(DexFile dexFile, int offset) {
- super(offset);
+ super(dexFile, offset);
fields = new Field[] {
encodedArray = new ArrayEncodedValueSubField(dexFile)
@@ -45,7 +45,7 @@ public class EncodedArrayItem extends OffsettedItem {
}
public EncodedArrayItem(DexFile dexFile, ArrayList encodedValues) {
- super(0);
+ super(dexFile, 0);
fields = new Field[] {
encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues)
diff --git a/dexlib/src/main/java/org/jf/dexlib/EncodedValue/EncodedIndexedItemReference.java b/dexlib/src/main/java/org/jf/dexlib/EncodedValue/EncodedIndexedItemReference.java
index 999bf8f7..c6726961 100644
--- a/dexlib/src/main/java/org/jf/dexlib/EncodedValue/EncodedIndexedItemReference.java
+++ b/dexlib/src/main/java/org/jf/dexlib/EncodedValue/EncodedIndexedItemReference.java
@@ -100,8 +100,7 @@ public class EncodedIndexedItemReference>
if (item == null) {
return;
}
- T copiedItem = copy.section.intern(dexFile, item);
- copy.item = copiedItem;
+ copy.item = copy.section.intern(item);
}
public T getValue() {
diff --git a/dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java b/dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java
index d466e76c..7564c5d1 100644
--- a/dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java
@@ -34,7 +34,7 @@ public class FieldIdItem extends IndexedItem {
private final IndexedItemReference fieldNameReferenceField;
public FieldIdItem(DexFile dexFile, int index) {
- super(index);
+ super(dexFile, index);
fields = new Field[] {
classTypeReferenceField = new IndexedItemReference(dexFile.TypeIdsSection,
new ShortIntegerField(null), "class_idx"),
diff --git a/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java b/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java
index 67c852d8..120e56e4 100644
--- a/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java
@@ -63,8 +63,8 @@ public class HeaderItem extends IndexedItem {
private final IntegerField dataSizeField;
private final IntegerField dataOffField;
- public HeaderItem(final DexFile file, int index) {
- super(index);
+ public HeaderItem(final DexFile dexFile, int index) {
+ super(dexFile, index);
try
{
@@ -84,64 +84,49 @@ public class HeaderItem extends IndexedItem {
super.writeTo(out);
}
},
- fileSizeField = new IntegerField("file_size") {
- public void writeTo(AnnotatedOutput out) {
- cacheValue(file.getFileSize());
- super.writeTo(out);
- }
- },
+ fileSizeField = new IntegerField("file_size"),
headerSizeField = new IntegerField(HEADER_SIZE,"header_size"),
endianTagField = new IntegerField(ENDIAN_TAG,"endian_tag"),
linkSizeField = new IntegerField(0,"link_size"),
linkOffField = new IntegerField(0,"link_off"),
mapOffField = new IntegerField("map_off") {
public void writeTo(AnnotatedOutput out) {
- cacheValue(file.MapSection.getOffset());
+ cacheValue(dexFile.MapSection.getOffset());
super.writeTo(out);
}
},
StringIdsHeaderField = new SectionHeaderInfo("string_ids") {
protected Section getSection() {
- return file.StringIdsSection;
+ return dexFile.StringIdsSection;
}
},
TypeIdsHeaderField = new SectionHeaderInfo("type_ids") {
protected Section getSection() {
- return file.TypeIdsSection;
+ return dexFile.TypeIdsSection;
}
},
ProtoIdsHeaderField = new SectionHeaderInfo("proto_ids") {
protected Section getSection() {
- return file.ProtoIdsSection;
+ return dexFile.ProtoIdsSection;
}
},
FieldIdsHeaderField = new SectionHeaderInfo("field_ids") {
protected Section getSection() {
- return file.FieldIdsSection;
+ return dexFile.FieldIdsSection;
}
},
MethodIdsHeaderField = new SectionHeaderInfo("method_ids") {
protected Section getSection() {
- return file.MethodIdsSection;
+ return dexFile.MethodIdsSection;
}
},
ClassDefsHeaderField = new SectionHeaderInfo("class_defs") {
protected Section getSection() {
- return file.ClassDefsSection;
+ return dexFile.ClassDefsSection;
}
},
- dataSizeField = new IntegerField("data_size") {
- public void writeTo(AnnotatedOutput out) {
- cacheValue(file.getDataSize());
- super.writeTo(out);
- }
- },
- dataOffField = new IntegerField("data_off") {
- public void writeTo(AnnotatedOutput out) {
- cacheValue(file.getDataOffset());
- super.writeTo(out);
- }
- }
+ dataSizeField = new IntegerField("data_size"),
+ dataOffField = new IntegerField("data_off")
};
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("Error while creating the magic header field.", ex);
@@ -168,4 +153,16 @@ public class HeaderItem extends IndexedItem {
//there is only 1 header item
return 0;
}
+
+ protected void setFileSize(int size) {
+ this.fileSizeField.cacheValue(size);
+ }
+
+ protected void setDataSize(int size) {
+ this.dataSizeField.cacheValue(size);
+ }
+
+ protected void setDataOffset(int offset) {
+ this.dataOffField.cacheValue(offset);
+ }
}
diff --git a/dexlib/src/main/java/org/jf/dexlib/IndexedItem.java b/dexlib/src/main/java/org/jf/dexlib/IndexedItem.java
index 593766c0..f075a52c 100644
--- a/dexlib/src/main/java/org/jf/dexlib/IndexedItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/IndexedItem.java
@@ -29,7 +29,8 @@
package org.jf.dexlib;
public abstract class IndexedItem extends Item {
- protected IndexedItem(int index) {
+ protected IndexedItem(DexFile dexFile, int index) {
+ super(dexFile);
this.index = index;
}
}
\ No newline at end of file
diff --git a/dexlib/src/main/java/org/jf/dexlib/IndexedSection.java b/dexlib/src/main/java/org/jf/dexlib/IndexedSection.java
index 0cd01af1..38e7cfee 100644
--- a/dexlib/src/main/java/org/jf/dexlib/IndexedSection.java
+++ b/dexlib/src/main/java/org/jf/dexlib/IndexedSection.java
@@ -33,7 +33,8 @@ import org.jf.dexlib.Util.Input;
import java.util.Collections;
public abstract class IndexedSection> extends Section {
- public IndexedSection() {
+ public IndexedSection(DexFile dexFile) {
+ super(dexFile);
}
public T getByIndex(int index) {
@@ -61,7 +62,7 @@ public abstract class IndexedSection> extends Section> extends Section implements Comparable {
protected int offset = -1;
protected int index = -1;
+ protected final DexFile dexFile;
protected Field[] fields;
- protected Item() {
+ protected Item(DexFile dexFile) {
+ this.dexFile = dexFile;
}
public boolean isPlaced() {
diff --git a/dexlib/src/main/java/org/jf/dexlib/ItemReference.java b/dexlib/src/main/java/org/jf/dexlib/ItemReference.java
index ea06db43..16e38bab 100644
--- a/dexlib/src/main/java/org/jf/dexlib/ItemReference.java
+++ b/dexlib/src/main/java/org/jf/dexlib/ItemReference.java
@@ -70,7 +70,7 @@ public abstract class ItemReference, S extends ItemReference section = copy.getSection();
- T copiedItem = section.intern(dexFile, referencedItem);
+ T copiedItem = section.intern(referencedItem);
copy.setReference(copiedItem);
}
diff --git a/dexlib/src/main/java/org/jf/dexlib/MapField.java b/dexlib/src/main/java/org/jf/dexlib/MapField.java
index bf1ac1da..3366aa3b 100644
--- a/dexlib/src/main/java/org/jf/dexlib/MapField.java
+++ b/dexlib/src/main/java/org/jf/dexlib/MapField.java
@@ -30,15 +30,14 @@ package org.jf.dexlib;
public class MapField extends CompositeField {
private final ShortIntegerField sectionTypeField;
- private final ShortIntegerField unusedField;
private final SectionHeaderInfo sectionInfoField;
- public MapField(final DexFile dexFile) {
+ protected MapField(final DexFile dexFile) {
super("map_entry");
fields = new Field[] {
//TODO: add an annotation for the item type
sectionTypeField = new ShortIntegerField("type"),
- unusedField = new ShortIntegerField((short)0, "not used"),
+ new ShortIntegerField((short)0, "padding"),
sectionInfoField = new SectionHeaderInfo("section") {
protected Section getSection() {
return dexFile.getSectionForType(getSectionItemType());
@@ -47,24 +46,46 @@ public class MapField extends CompositeField {
};
}
- public MapField(final DexFile dexFile, short sectionType) {
+ protected MapField(final DexFile dexFile, short sectionType) {
this(dexFile);
sectionTypeField.cacheValue(sectionType);
}
-
+
+ /**
+ * Get the ItemType
of the section that this map field represents
+ * @return The ItemType
of the section that this map field represents
+ */
public ItemType getSectionItemType() {
return ItemType.fromInt(sectionTypeField.getCachedValue());
}
+ /**
+ * Get the Section
object that this map field represents
+ * @return The Section
object that this map field represents
+ */
public Section getSection() {
+ Section s;
return sectionInfoField.getSection();
}
- public int getSectionSize() {
+ /**
+ * This returns the cached size of the section that this map field represents. This is used while
+ * reading in the given section, to retrieve the size of the section that is stored in this map
+ * field.
+ *
+ * @return the cached size of the section that this map field represents
+ */
+ protected int getCachedSectionSize() {
return sectionInfoField.getSectionSize();
}
- public int getSectionOffset() {
+ /**
+ * This returns the cached size of the section that this map field represents. This is used while
+ * reading in the given section, to retrieve the offset of the section that is stored in this map
+ * field
+ * @return
+ */
+ protected int getCachedSectionOffset() {
return sectionInfoField.getSectionOffset();
}
}
diff --git a/dexlib/src/main/java/org/jf/dexlib/MapItem.java b/dexlib/src/main/java/org/jf/dexlib/MapItem.java
index 5ba7663d..04bf6cde 100644
--- a/dexlib/src/main/java/org/jf/dexlib/MapItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/MapItem.java
@@ -35,8 +35,8 @@ import java.util.Comparator;
public class MapItem extends IndexedItem {
private ArrayList mapEntries = new ArrayList();
- public MapItem(final DexFile dexFile, int index) {
- super(index);
+ protected MapItem(final DexFile dexFile, int index) {
+ super(dexFile, index);
fields = new Field[] {
new ListSizeField(mapEntries, new IntegerField("size")),
@@ -48,6 +48,29 @@ public class MapItem extends IndexedItem {
};
}
+ protected MapItem(final DexFile dexFile) {
+ this(dexFile, 0);
+
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_HEADER_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_STRING_ID_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_TYPE_ID_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_PROTO_ID_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_FIELD_ID_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_METHOD_ID_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CLASS_DEF_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_STRING_DATA_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ENCODED_ARRAY_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_SET_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_SET_REF_LIST.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_TYPE_LIST.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_DEBUG_INFO_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CODE_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CLASS_DATA_ITEM.getMapValue()));
+ mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_MAP_LIST.getMapValue()));
+ }
+
public int place(int index, int offset) {
//we have to check if there are any empty sections before we place this item,
@@ -72,32 +95,6 @@ public class MapItem extends IndexedItem {
return offset;
}
- public static MapItem makeBlankMapItem(DexFile dexFile) {
- MapItem mapItem = new MapItem(dexFile, 0);
-
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_HEADER_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_STRING_ID_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_TYPE_ID_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_PROTO_ID_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_FIELD_ID_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_METHOD_ID_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CLASS_DEF_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_STRING_DATA_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ENCODED_ARRAY_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_SET_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_SET_REF_LIST.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_TYPE_LIST.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_DEBUG_INFO_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CODE_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CLASS_DATA_ITEM.getMapValue()));
- mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_MAP_LIST.getMapValue()));
-
-
- return mapItem;
- }
-
public MapField[] getMapEntries() {
return mapEntries.toArray(new MapField[1]);
}
diff --git a/dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java b/dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java
index 22cc0fd0..388c188c 100644
--- a/dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java
@@ -34,7 +34,7 @@ public class MethodIdItem extends IndexedItem {
private final IndexedItemReference methodNameReferenceField;
public MethodIdItem(DexFile dexFile, int index) {
- super(index);
+ super(dexFile, index);
fields = new Field[] {
classTypeReferenceField = new IndexedItemReference(dexFile.TypeIdsSection,
new ShortIntegerField(null), "class_idx"),
diff --git a/dexlib/src/main/java/org/jf/dexlib/OffsettedItem.java b/dexlib/src/main/java/org/jf/dexlib/OffsettedItem.java
index db3ee15f..637b9073 100644
--- a/dexlib/src/main/java/org/jf/dexlib/OffsettedItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/OffsettedItem.java
@@ -29,7 +29,8 @@
package org.jf.dexlib;
public abstract class OffsettedItem> extends Item {
- public OffsettedItem(int offset) {
+ public OffsettedItem(DexFile dexFile, int offset) {
+ super(dexFile);
this.offset = offset;
}
}
diff --git a/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java b/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java
index aaa7bbd8..29157448 100644
--- a/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java
+++ b/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java
@@ -37,7 +37,8 @@ import java.util.Comparator;
public abstract class OffsettedSection> extends Section {
protected HashMap itemsByOffset;
- public OffsettedSection() {
+ public OffsettedSection(DexFile dexFile) {
+ super(dexFile);
itemsByOffset = new HashMap();
}
@@ -77,7 +78,7 @@ public abstract class OffsettedSection> extends Secti
protected abstract T make(int offset);
- public T intern(DexFile dexFile, T item) {
+ public T intern(T item) {
T itemToReturn = getInternedItem(item);
if (itemToReturn == null) {
diff --git a/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java b/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java
index d3d67aaa..ae06985c 100644
--- a/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java
@@ -36,7 +36,7 @@ public class ProtoIdItem extends IndexedItem {
private final OffsettedItemReference parametersReferenceField;
public ProtoIdItem(DexFile dexFile, int index) {
- super(index);
+ super(dexFile, index);
fields = new Field[] {
shortyDescriptorReferenceField = new IndexedItemReference(dexFile.StringIdsSection,
new IntegerField(null), "shorty_idx"),
@@ -88,7 +88,7 @@ public class ProtoIdItem extends IndexedItem {
if (typeList == null) {
return 0;
} else {
- return typeList.getCount();
+ return typeList.getTypeCount();
}
}
diff --git a/dexlib/src/main/java/org/jf/dexlib/Section.java b/dexlib/src/main/java/org/jf/dexlib/Section.java
index 07d216a7..c513f49b 100644
--- a/dexlib/src/main/java/org/jf/dexlib/Section.java
+++ b/dexlib/src/main/java/org/jf/dexlib/Section.java
@@ -37,8 +37,9 @@ import java.util.List;
import java.util.Collections;
public abstract class Section {
- protected ArrayList items;
+ protected final ArrayList items;
protected HashMap uniqueItems = null;
+ protected final DexFile dexFile;
/**
* When offset > -1, this section is "placed" at the specified offset. All
@@ -49,7 +50,8 @@ public abstract class Section {
*/
protected int offset = -1;
- public Section() {
+ public Section(DexFile dexFile) {
+ this.dexFile = dexFile;
items = new ArrayList();
}
@@ -136,5 +138,5 @@ public abstract class Section {
Collections.sort(items);
}
- public abstract T intern(DexFile dexFile, T item);
+ public abstract T intern(T item);
}
diff --git a/dexlib/src/main/java/org/jf/dexlib/StringDataItem.java b/dexlib/src/main/java/org/jf/dexlib/StringDataItem.java
index 0d3d7b77..4d6b85f6 100644
--- a/dexlib/src/main/java/org/jf/dexlib/StringDataItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/StringDataItem.java
@@ -37,8 +37,8 @@ public class StringDataItem extends OffsettedItem implements Com
private final Leb128Field stringSize;
private final NullTerminatedByteArrayField stringByteArray;
- public StringDataItem(int offset) {
- super(offset);
+ public StringDataItem(DexFile dexFile, int offset) {
+ super(dexFile, offset);
fields = new Field[] {
stringSize = new Leb128Field("string_length"),
@@ -46,8 +46,8 @@ public class StringDataItem extends OffsettedItem implements Com
};
}
- public StringDataItem(String value) {
- super(-1);
+ public StringDataItem(DexFile dexFile, String value) {
+ super(dexFile, -1);
this.value = value;
diff --git a/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java b/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java
index 95dd4055..6337f926 100644
--- a/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/StringIdItem.java
@@ -34,7 +34,7 @@ public class StringIdItem extends IndexedItem {
private final OffsettedItemReference stringDataReferenceField;
public StringIdItem(DexFile dexFile, int index) {
- super(index);
+ super(dexFile, index);
fields = new Field[] {
stringDataReferenceField = new OffsettedItemReference(dexFile.StringDataSection,
new IntegerField(null), "string_data_off")
@@ -47,7 +47,7 @@ public class StringIdItem extends IndexedItem {
}
public StringIdItem(DexFile dexFile, String value) {
- this(dexFile, new StringDataItem(value));
+ this(dexFile, new StringDataItem(dexFile, value));
}
protected int getAlignment() {
diff --git a/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java b/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java
index 6805f78d..6c3bfb3e 100644
--- a/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java
@@ -32,7 +32,7 @@ public class TypeIdItem extends IndexedItem {
private final IndexedItemReference typeDescriptorReferenceField;
public TypeIdItem(DexFile dexFile, int index) {
- super(index);
+ super(dexFile, index);
fields = new Field[] {
typeDescriptorReferenceField = new IndexedItemReference(dexFile.StringIdsSection,
new IntegerField(null), "descriptor_idx")
diff --git a/dexlib/src/main/java/org/jf/dexlib/TypeListItem.java b/dexlib/src/main/java/org/jf/dexlib/TypeListItem.java
index eaa2ec16..0bc688c4 100644
--- a/dexlib/src/main/java/org/jf/dexlib/TypeListItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/TypeListItem.java
@@ -34,14 +34,13 @@ import java.util.List;
public class TypeListItem extends OffsettedItem {
private final ArrayList> typeList = new ArrayList>();
- private final ListSizeField sizeField;
private final FieldListField> listField;
public TypeListItem(final DexFile dexFile, int offset) {
- super(offset);
+ super(dexFile, offset);
fields = new Field[] {
- sizeField = new ListSizeField(typeList, new IntegerField("size")),
+ new ListSizeField(typeList, new IntegerField("size")),
listField = new FieldListField>(typeList, "type_item") {
protected IndexedItemReference make() {
return new IndexedItemReference(dexFile.TypeIdsSection,
@@ -61,6 +60,7 @@ public class TypeListItem extends OffsettedItem {
}
}
+ //TODO: write a read only List wrapper for List> and return that instead
public List getTypes() {
ArrayList list = new ArrayList(typeList.size());
@@ -80,7 +80,7 @@ public class TypeListItem extends OffsettedItem {
return wordCount;
}
- public int getCount() {
+ public int getTypeCount() {
return typeList.size();
}
diff --git a/dexlib/src/test/java/TryListBuilderTest.java b/dexlib/src/test/java/TryListBuilderTest.java
index 988e446e..55df4f31 100644
--- a/dexlib/src/test/java/TryListBuilderTest.java
+++ b/dexlib/src/test/java/TryListBuilderTest.java
@@ -82,7 +82,7 @@ public class TryListBuilderTest
public void singleTryTest() {
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
@@ -98,7 +98,7 @@ public class TryListBuilderTest
public void singleTryWithCatchAllTest() {
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
@@ -117,7 +117,7 @@ public class TryListBuilderTest
// |-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
@@ -138,7 +138,7 @@ public class TryListBuilderTest
// |-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
@@ -159,7 +159,7 @@ public class TryListBuilderTest
//|-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
tryListBuilder.addHandler(typeIdItem, 5, 10, 101);
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
@@ -179,7 +179,7 @@ public class TryListBuilderTest
//|-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
tryListBuilder.addHandler(typeIdItem, 10, 15, 101);
@@ -201,7 +201,7 @@ public class TryListBuilderTest
//|-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -221,7 +221,7 @@ public class TryListBuilderTest
// |-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -245,7 +245,7 @@ public class TryListBuilderTest
//|-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -268,7 +268,7 @@ public class TryListBuilderTest
// |---|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -291,7 +291,7 @@ public class TryListBuilderTest
//|-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -314,7 +314,7 @@ public class TryListBuilderTest
//|---|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -336,7 +336,7 @@ public class TryListBuilderTest
//|-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -358,7 +358,7 @@ public class TryListBuilderTest
// |---|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -380,7 +380,7 @@ public class TryListBuilderTest
//|-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
@@ -404,7 +404,7 @@ public class TryListBuilderTest
//|--------------------|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
TypeIdItem typeIdItem3= new TypeIdItem(dexFile, "Ljava/lang/Exception3;");
@@ -434,7 +434,7 @@ public class TryListBuilderTest
// |---|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
tryListBuilder.addCatchAllHandler(2, 8, 100);
tryListBuilder.addCatchAllHandler(4, 6, 101);
@@ -454,7 +454,7 @@ public class TryListBuilderTest
//|-----|
TryListBuilder tryListBuilder = new TryListBuilder();
- DexFile dexFile = DexFile.makeBlankDexFile();
+ DexFile dexFile = new DexFile();
tryListBuilder.addCatchAllHandler(4, 6, 100);
tryListBuilder.addCatchAllHandler(2, 8, 101);