From 4b82fba3ba46eb3f7169f9db9d3118e7d73c3682 Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Sat, 3 Apr 2010 23:01:41 +0000 Subject: [PATCH] Refactor dexlib so that sections are read in based on the dependency order This allows us to simply the read logic somewhat, getting rid of the concept of a "pre-created" item git-svn-id: https://smali.googlecode.com/svn/trunk@683 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- .../src/main/java/org/jf/dexlib/DexFile.java | 17 ++-- .../java/org/jf/dexlib/OffsettedSection.java | 28 +----- .../main/java/org/jf/dexlib/ReadContext.java | 88 +++++-------------- 3 files changed, 32 insertions(+), 101 deletions(-) diff --git a/dexlib/src/main/java/org/jf/dexlib/DexFile.java b/dexlib/src/main/java/org/jf/dexlib/DexFile.java index f73f419b..06f697d5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/DexFile.java +++ b/dexlib/src/main/java/org/jf/dexlib/DexFile.java @@ -390,7 +390,7 @@ public class DexFile } } - ReadContext readContext = new ReadContext(this); + ReadContext readContext = new ReadContext(); HeaderItem.readFrom(in, 0, readContext); @@ -400,23 +400,24 @@ public class DexFile in.setCursor(mapOffset); MapItem.readFrom(in, 0, readContext); + //the sections are ordered in such a way that the item types Section sections[] = new Section[] { + StringDataSection, StringIdsSection, TypeIdsSection, + TypeListsSection, ProtoIdsSection, FieldIdsSection, MethodIdsSection, - ClassDefsSection, - StringDataSection, - TypeListsSection, - AnnotationSetRefListsSection, + AnnotationsSection, AnnotationSetsSection, - ClassDataSection, - CodeItemsSection, + AnnotationSetRefListsSection, AnnotationDirectoriesSection, DebugInfoItemsSection, - AnnotationsSection, + CodeItemsSection, + ClassDataSection, EncodedArraysSection, + ClassDefsSection }; for (Section section: sections) { diff --git a/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java b/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java index 9fd7d0ad..38a35f04 100644 --- a/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java +++ b/dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java @@ -40,39 +40,13 @@ public class OffsettedSection extends Section { } public void readItems(Input in, ReadContext readContext) { - SparseArray precreatedItems = (SparseArray)readContext.getItemsByType(ItemType); - - assert precreatedItems.size() <= items.size(): "Trying to read " + items.size() + " items, but this section " + - "already contains " + precreatedItems.size() + " items."; - - int precreatedIndex = 0; - int nextPrecreatedOffset = Integer.MAX_VALUE; - - if (precreatedItems.size() > 0) { - nextPrecreatedOffset = precreatedItems.keyAt(0); - } for (int i = 0; i < items.size(); i++) { assert items.get(i) == null; - T item = null; in.alignTo(ItemType.ItemAlignment); - int currentOffset = in.getCursor(); - if (currentOffset == nextPrecreatedOffset) { - item = precreatedItems.valueAt(precreatedIndex++); - if (precreatedIndex < precreatedItems.size()) { - nextPrecreatedOffset = precreatedItems.keyAt(precreatedIndex); - } else { - nextPrecreatedOffset = Integer.MAX_VALUE; - } - } else if (currentOffset > nextPrecreatedOffset) { - //we passed by the next precreated item, something is wrong - throw new RuntimeException("The pre-created item at offset 0x" + Hex.u4(nextPrecreatedOffset) - + " was not read"); - } else { - item = (T)ItemFactory.makeItem(ItemType, DexFile); - } + T item = (T)ItemFactory.makeItem(ItemType, DexFile); items.set(i, item); item.readFrom(in, i, readContext); diff --git a/dexlib/src/main/java/org/jf/dexlib/ReadContext.java b/dexlib/src/main/java/org/jf/dexlib/ReadContext.java index 8653d33f..a25f3a27 100644 --- a/dexlib/src/main/java/org/jf/dexlib/ReadContext.java +++ b/dexlib/src/main/java/org/jf/dexlib/ReadContext.java @@ -28,8 +28,8 @@ package org.jf.dexlib; +import org.jf.dexlib.Util.ExceptionWithContext; import org.jf.dexlib.Util.SparseArray; -import junit.framework.Assert; import java.util.List; @@ -40,9 +40,7 @@ import java.util.List; * that it references, and keeps track of those pre-created items, so the corresponding section * for the pre-created items uses them, instead of creating new items */ -class ReadContext { - private final DexFile dexFile; - +public class ReadContext { private SparseArray typeListItems = new SparseArray(0); private SparseArray annotationSetRefLists = new SparseArray(0); private SparseArray annotationSetItems = new SparseArray(0); @@ -51,8 +49,8 @@ class ReadContext { private SparseArray stringDataItems = new SparseArray(0); private SparseArray debugInfoItems = new SparseArray(0); private SparseArray annotationItems = new SparseArray(0); - private SparseArray encodedArrayItems = new SparseArray(); - private SparseArray annotationDirectoryItems = new SparseArray(); + private SparseArray encodedArrayItems = new SparseArray(0); + private SparseArray annotationDirectoryItems = new SparseArray(0); private SparseArray[] itemsByType = new SparseArray[] { null, //string_id_item @@ -90,11 +88,8 @@ class ReadContext { /** * Creates a new ReadContext instance. - * @param dexFile The dex file that is being read in */ - public ReadContext(DexFile dexFile) { - this.dexFile = dexFile; - + public ReadContext() { for (int i=0; i<18; i++) { sectionSizes[i] = -1; sectionOffsets[i] = -1; @@ -102,78 +97,44 @@ class ReadContext { } /** - * Returns a SparseArray containing the items of the given type - * that have been pre-created while reading in other sections. - * - * If the given ItemType isn't an offsetted item, this method will - * return null - * @param itemType The type of item to get - * @return a SparseArray containing the items of the given type - * that have been pre-created while reading in other sections, or - * null if the ItemType isn't an offsetted item - */ - public SparseArray getItemsByType(ItemType itemType) { - return itemsByType[itemType.SectionIndex]; - } - - /** - * Gets or creates an offsetted item of the specified type for the - * given offset. Multiple calls to this method with the same itemType - * and offset will return the same item. - * - * This method expects that offset will be a valid offset, not - * zero or negative. Use getOptionalOffsetedItemByOffset to handle - * the case of an optional item, where an offset of 0 is used to - * indicate the item isn't present - * - * It should not be assumed that the item that is returned will be - * initialized. It is only guaranteed that the item will be read in - * and initialiazed once the entire dex file has been read in. - * - * Note that it *is* guaranteed that this exact item will be added to - * its corresponding section and read in. In other words, when the - * corresponding section is being read in, it will use any items for - * that have been "pre-created" by this method, and only create - * new items for offsets that haven't been pre-created yet. + * Gets the offsetted item of the specified type for the given offset. This method does not support retrieving an + * optional item where a value of 0 indicates "not present". Use getOptionalOffsettedItemByOffset instead. * * @param itemType The type of item to get * @param offset The offset of the item - * @return an item of the requested type for the given offset + * @return the offsetted item of the specified type at the specified offset */ public Item getOffsettedItemByOffset(ItemType itemType, int offset) { assert !itemType.isIndexedItem(); - if (offset <= 0) { - throw new RuntimeException("Invalid offset " + offset + " for item type " + itemType.TypeName); - } - SparseArray sa = itemsByType[itemType.SectionIndex]; Item item = sa.get(offset); if (item == null) { - item = ItemFactory.makeItem(itemType, dexFile); - sa.put(offset, item); + throw new ExceptionWithContext(String.format("Could not find the %s item at offset %#x", + itemType.TypeName, offset)); } return item; } /** - * This method is similar to getOffsettedItemByOffset, except that it allows - * the offset to be 0, in which case it will simply return null. This method - * should be used for an optional item, where an item offset of 0 indicates - * that the item isn't present + * Gets the optional offsetted item of the specified type for the given offset + * * @param itemType The type of item to get - * @param offset the offset of the item - * @return an item of the requested type for the given offset, or null if - * offset is 0 + * @param offset The offset of the item + * @return the offsetted item of the specified type at the specified offset, or null if the offset is 0 */ public Item getOptionalOffsettedItemByOffset(ItemType itemType, int offset) { assert !itemType.isIndexedItem(); - if (offset == 0) { - return null; - } + assert !itemType.isIndexedItem(); - return getOffsettedItemByOffset(itemType, offset); + SparseArray sa = itemsByType[itemType.SectionIndex]; + Item item = sa.get(offset); + if (item == null && offset != 0) { + throw new ExceptionWithContext(String.format("Could not find the %s item at offset %#x", + itemType.TypeName, offset)); + } + return item; } /** @@ -183,9 +144,6 @@ class ReadContext { * @param sectionOffset the offset of the section */ public void addSection(final ItemType itemType, int sectionSize, int sectionOffset) { - if (!itemType.isIndexedItem()) { - itemsByType[itemType.SectionIndex].ensureCapacity(sectionSize); - } int storedSectionSize = sectionSizes[itemType.SectionIndex]; if (storedSectionSize == -1) { sectionSizes[itemType.SectionIndex] = sectionSize; @@ -207,7 +165,6 @@ class ReadContext { } } - /** * Sets the items for the specified section. This should be called by an offsetted section * after it is finished reading in all its items. @@ -219,7 +176,6 @@ class ReadContext { SparseArray sa = itemsByType[itemType.SectionIndex]; - sa.clear(); sa.ensureCapacity(items.size()); for (Item item: items) { sa.append(item.getOffset(), item);