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

+ * + *
    + *
  1. 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)

  2. + * + *
  3. 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

  4. + * + *
  5. 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.

  6. + * + * + *
  7. 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.

  8. + * + * + *

    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);