mirror of
https://github.com/revanced/smali.git
synced 2025-05-18 06:57:06 +02:00
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
This commit is contained in:
parent
483ebdf2cc
commit
4b82fba3ba
@ -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) {
|
||||
|
@ -40,39 +40,13 @@ public class OffsettedSection<T extends Item> extends Section<T> {
|
||||
}
|
||||
|
||||
public void readItems(Input in, ReadContext readContext) {
|
||||
SparseArray<T> precreatedItems = (SparseArray<T>)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);
|
||||
|
@ -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<TypeListItem> typeListItems = new SparseArray<TypeListItem>(0);
|
||||
private SparseArray<AnnotationSetRefList> annotationSetRefLists = new SparseArray<AnnotationSetRefList>(0);
|
||||
private SparseArray<AnnotationSetItem> annotationSetItems = new SparseArray<AnnotationSetItem>(0);
|
||||
@ -51,8 +49,8 @@ class ReadContext {
|
||||
private SparseArray<StringDataItem> stringDataItems = new SparseArray<StringDataItem>(0);
|
||||
private SparseArray<DebugInfoItem> debugInfoItems = new SparseArray<DebugInfoItem>(0);
|
||||
private SparseArray<AnnotationItem> annotationItems = new SparseArray<AnnotationItem>(0);
|
||||
private SparseArray<EncodedArrayItem> encodedArrayItems = new SparseArray<EncodedArrayItem>();
|
||||
private SparseArray<AnnotationDirectoryItem> annotationDirectoryItems = new SparseArray<AnnotationDirectoryItem>();
|
||||
private SparseArray<EncodedArrayItem> encodedArrayItems = new SparseArray<EncodedArrayItem>(0);
|
||||
private SparseArray<AnnotationDirectoryItem> annotationDirectoryItems = new SparseArray<AnnotationDirectoryItem>(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<Item> 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<Item> 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<Item> sa = itemsByType[itemType.SectionIndex];
|
||||
|
||||
sa.clear();
|
||||
sa.ensureCapacity(items.size());
|
||||
for (Item item: items) {
|
||||
sa.append(item.getOffset(), item);
|
||||
|
Loading…
x
Reference in New Issue
Block a user