diff options
Diffstat (limited to 'dex/src/main/java/com')
-rw-r--r-- | dex/src/main/java/com/android/dex/Dex.java | 367 |
1 files changed, 201 insertions, 166 deletions
diff --git a/dex/src/main/java/com/android/dex/Dex.java b/dex/src/main/java/com/android/dex/Dex.java index bf24998..89edf6e 100644 --- a/dex/src/main/java/com/android/dex/Dex.java +++ b/dex/src/main/java/com/android/dex/Dex.java @@ -56,77 +56,16 @@ public final class Dex { // Provided as a convenience to avoid a memory allocation to benefit Dalvik. // Note: libcore.util.EmptyArray cannot be accessed when this code isn't run on Dalvik. static final short[] EMPTY_SHORT_ARRAY = new short[0]; + private ByteBuffer data; private final TableOfContents tableOfContents = new TableOfContents(); private int nextSectionStart = 0; - - private static abstract class AbstractRandomAccessList<T> - extends AbstractList<T> implements RandomAccess { - } - - private List<String> strings = new AbstractRandomAccessList<String>() { - @Override public String get(int index) { - checkBounds(index, tableOfContents.stringIds.size); - return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM)) - .readString(); - } - @Override public int size() { - return tableOfContents.stringIds.size; - } - }; - - private final List<Integer> typeIds = new AbstractRandomAccessList<Integer>() { - @Override public Integer get(int index) { - checkBounds(index, tableOfContents.typeIds.size); - return open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt(); - } - @Override public int size() { - return tableOfContents.typeIds.size; - } - }; - - private final List<String> typeNames = new AbstractRandomAccessList<String>() { - @Override public String get(int index) { - checkBounds(index, tableOfContents.typeIds.size); - return strings.get(typeIds.get(index)); - } - @Override public int size() { - return tableOfContents.typeIds.size; - } - }; - - private final List<ProtoId> protoIds = new AbstractRandomAccessList<ProtoId>() { - @Override public ProtoId get(int index) { - checkBounds(index, tableOfContents.protoIds.size); - return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index)) - .readProtoId(); - } - @Override public int size() { - return tableOfContents.protoIds.size; - } - }; - - private final List<FieldId> fieldIds = new AbstractRandomAccessList<FieldId>() { - @Override public FieldId get(int index) { - checkBounds(index, tableOfContents.fieldIds.size); - return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index)) - .readFieldId(); - } - @Override public int size() { - return tableOfContents.fieldIds.size; - } - }; - - private final List<MethodId> methodIds = new AbstractRandomAccessList<MethodId>() { - @Override public MethodId get(int index) { - checkBounds(index, tableOfContents.methodIds.size); - return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index)) - .readMethodId(); - } - @Override public int size() { - return tableOfContents.methodIds.size; - } - }; + private final StringTable strings = new StringTable(); + private final TypeIndexToDescriptorIndexTable typeIds = new TypeIndexToDescriptorIndexTable(); + private final TypeIndexToDescriptorTable typeNames = new TypeIndexToDescriptorTable(); + private final ProtoIdTable protoIds = new ProtoIdTable(); + private final FieldIdTable fieldIds = new FieldIdTable(); + private final MethodIdTable methodIds = new MethodIdTable(); /** * Creates a new dex that reads from {@code data}. It is an error to modify @@ -314,31 +253,7 @@ public final class Dex { } public Iterable<ClassDef> classDefs() { - return new Iterable<ClassDef>() { - public Iterator<ClassDef> iterator() { - if (!tableOfContents.classDefs.exists()) { - return Collections.<ClassDef>emptySet().iterator(); - } - return new Iterator<ClassDef>() { - private Dex.Section in = open(tableOfContents.classDefs.off); - private int count = 0; - - public boolean hasNext() { - return count < tableOfContents.classDefs.size; - } - public ClassDef next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - count++; - return in.readClassDef(); - } - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - }; + return new ClassDefIterable(); } public TypeList readTypeList(int offset) { @@ -414,6 +329,113 @@ public final class Dex { open(CHECKSUM_OFFSET).writeInt(computeChecksum()); } + /** + * Look up a field id name index from a field index. Cheaper than: + * {@code fieldIds().get(fieldDexIndex).getNameIndex();} + */ + public int nameIndexFromFieldIndex(int fieldIndex) { + checkBounds(fieldIndex, tableOfContents.fieldIds.size); + int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex); + position += SizeOf.USHORT; // declaringClassIndex + position += SizeOf.USHORT; // typeIndex + return data.getInt(position); // nameIndex + } + + public int findStringIndex(String s) { + return Collections.binarySearch(strings, s); + } + + public int findTypeIndex(String descriptor) { + return Collections.binarySearch(typeNames, descriptor); + } + + public int findFieldIndex(FieldId fieldId) { + return Collections.binarySearch(fieldIds, fieldId); + } + + public int findMethodIndex(MethodId methodId) { + return Collections.binarySearch(methodIds, methodId); + } + + /** + * Look up a field id type index from a field index. Cheaper than: + * {@code fieldIds().get(fieldDexIndex).getTypeIndex();} + */ + public int typeIndexFromFieldIndex(int fieldIndex) { + checkBounds(fieldIndex, tableOfContents.fieldIds.size); + int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex); + position += SizeOf.USHORT; // declaringClassIndex + return data.getShort(position) & 0xFFFF; // typeIndex + } + + /** + * Look up a method id name index from a method index. Cheaper than: + * {@code methodIds().get(methodIndex).getNameIndex();} + */ + public int nameIndexFromMethodIndex(int methodIndex) { + checkBounds(methodIndex, tableOfContents.methodIds.size); + int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); + position += SizeOf.USHORT; // declaringClassIndex + position += SizeOf.USHORT; // protoIndex + return data.getInt(position); // nameIndex + } + + /** + * Look up a parameter type ids from a method index. Cheaper than: + * {@code readTypeList(protoIds.get(methodIds().get(methodDexIndex).getProtoIndex()).getParametersOffset()).getTypes();} + */ + public short[] parameterTypeIndicesFromMethodIndex(int methodIndex) { + checkBounds(methodIndex, tableOfContents.methodIds.size); + int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); + position += SizeOf.USHORT; // declaringClassIndex + int protoIndex = data.getShort(position) & 0xFFFF; + checkBounds(protoIndex, tableOfContents.protoIds.size); + position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex); + position += SizeOf.UINT; // shortyIndex + position += SizeOf.UINT; // returnTypeIndex + int parametersOffset = data.getInt(position); + if (parametersOffset == 0) { + return EMPTY_SHORT_ARRAY; + } + position = parametersOffset; + int size = data.getInt(position); + if (size <= 0) { + throw new AssertionError("Unexpected parameter type list size: " + size); + } + position += SizeOf.UINT; + short[] types = new short[size]; + for (int i = 0; i < size; i++) { + types[i] = data.getShort(position); + position += SizeOf.USHORT; + } + return types; + } + + /** + * Look up a method id return type index from a method index. Cheaper than: + * {@code protoIds().get(methodIds().get(methodDexIndex).getProtoIndex()).getReturnTypeIndex();} + */ + public int returnTypeIndexFromMethodIndex(int methodIndex) { + checkBounds(methodIndex, tableOfContents.methodIds.size); + int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); + position += SizeOf.USHORT; // declaringClassIndex + int protoIndex = data.getShort(position) & 0xFFFF; + checkBounds(protoIndex, tableOfContents.protoIds.size); + position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex); + position += SizeOf.UINT; // shortyIndex + return data.getInt(position); // returnTypeIndex + } + + /** + * Look up a descriptor index from a type index. Cheaper than: + * {@code open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();} + */ + private int descriptorIndexFromTypeIndex(int typeIndex) { + checkBounds(typeIndex, tableOfContents.typeIds.size); + int position = tableOfContents.typeIds.off + (SizeOf.TYPE_ID_ITEM * typeIndex); + return data.getInt(position); + } + public final class Section implements ByteInput, ByteOutput { private final String name; private final ByteBuffer data; @@ -791,84 +813,97 @@ public final class Dex { } } - /** - * Look up a field id name index from a field index. Equivalent to: - * {@code fieldIds().get(fieldDexIndex).getNameIndex();} - */ - public int nameIndexFromFieldIndex(int fieldIndex) { - checkBounds(fieldIndex, tableOfContents.fieldIds.size); - int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex); - position += SizeOf.USHORT; // declaringClassIndex - position += SizeOf.USHORT; // typeIndex - return data.getInt(position); // nameIndex - } + private final class StringTable extends AbstractList<String> implements RandomAccess { + @Override public String get(int index) { + checkBounds(index, tableOfContents.stringIds.size); + return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM)) + .readString(); + } + @Override public int size() { + return tableOfContents.stringIds.size; + } + }; - /** - * Look up a field id type index from a field index. Equivalent to: - * {@code fieldIds().get(fieldDexIndex).getTypeIndex();} - */ - public int typeIndexFromFieldIndex(int fieldIndex) { - checkBounds(fieldIndex, tableOfContents.fieldIds.size); - int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex); - position += SizeOf.USHORT; // declaringClassIndex - return data.getShort(position) & 0xFFFF; // typeIndex - } + private final class TypeIndexToDescriptorIndexTable extends AbstractList<Integer> + implements RandomAccess { + @Override public Integer get(int index) { + return descriptorIndexFromTypeIndex(index); + } + @Override public int size() { + return tableOfContents.typeIds.size; + } + }; - /** - * Look up a method id name index from a method index. Equivalent to: - * {@code methodIds().get(methodIndex).getNameIndex();} - */ - public int nameIndexFromMethodIndex(int methodIndex) { - checkBounds(methodIndex, tableOfContents.methodIds.size); - int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); - position += SizeOf.USHORT; // declaringClassIndex - position += SizeOf.USHORT; // protoIndex - return data.getInt(position); // nameIndex - } + private final class TypeIndexToDescriptorTable extends AbstractList<String> + implements RandomAccess { + @Override public String get(int index) { + return strings.get(descriptorIndexFromTypeIndex(index)); + } + @Override public int size() { + return tableOfContents.typeIds.size; + } + }; - /** - * Lookup a parameter type ids from a method index. Equivalent to: - * {@code readTypeList(protoIds.get(methodIds().get(methodDexIndex).getProtoIndex()).getParametersOffset()).getTypes();} - */ - public short[] parameterTypeIndicesFromMethodIndex(int methodIndex) { - checkBounds(methodIndex, tableOfContents.methodIds.size); - int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); - position += SizeOf.USHORT; // declaringClassIndex - int protoIndex = data.getShort(position) & 0xFFFF; - checkBounds(protoIndex, tableOfContents.protoIds.size); - position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex); - position += SizeOf.UINT; // shortyIndex - position += SizeOf.UINT; // returnTypeIndex - int parametersOffset = data.getInt(position); - if (parametersOffset == 0) { - return EMPTY_SHORT_ARRAY; + private final class ProtoIdTable extends AbstractList<ProtoId> implements RandomAccess { + @Override public ProtoId get(int index) { + checkBounds(index, tableOfContents.protoIds.size); + return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index)) + .readProtoId(); } - position = parametersOffset; - int size = data.getInt(position); - if (size <= 0) { - throw new AssertionError("Unexpected parameter type list size: " + size); + @Override public int size() { + return tableOfContents.protoIds.size; } - position += SizeOf.UINT; - short[] types = new short[size]; - for (int i = 0; i < size; i++) { - types[i] = data.getShort(position); - position += SizeOf.USHORT; + }; + + private final class FieldIdTable extends AbstractList<FieldId> implements RandomAccess { + @Override public FieldId get(int index) { + checkBounds(index, tableOfContents.fieldIds.size); + return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index)) + .readFieldId(); } - return types; - } + @Override public int size() { + return tableOfContents.fieldIds.size; + } + }; - /** - * Look up a method id return type index from a method index. Equivalent to: - * {@code protoIds().get(methodIds().get(methodDexIndex).getProtoIndex()).getReturnTypeIndex();} - */ - public int returnTypeIndexFromMethodIndex(int methodIndex) { - checkBounds(methodIndex, tableOfContents.methodIds.size); - int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); - position += SizeOf.USHORT; // declaringClassIndex - int protoIndex = data.getShort(position) & 0xFFFF; - checkBounds(protoIndex, tableOfContents.protoIds.size); - position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex); - position += SizeOf.UINT; // shortyIndex - return data.getInt(position); // returnTypeIndex - } + private final class MethodIdTable extends AbstractList<MethodId> implements RandomAccess { + @Override public MethodId get(int index) { + checkBounds(index, tableOfContents.methodIds.size); + return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index)) + .readMethodId(); + } + @Override public int size() { + return tableOfContents.methodIds.size; + } + }; + + private final class ClassDefIterator implements Iterator<ClassDef> { + private final Dex.Section in = open(tableOfContents.classDefs.off); + private int count = 0; + + @Override + public boolean hasNext() { + return count < tableOfContents.classDefs.size; + } + @Override + public ClassDef next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + count++; + return in.readClassDef(); + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + + private final class ClassDefIterable implements Iterable<ClassDef> { + public Iterator<ClassDef> iterator() { + return !tableOfContents.classDefs.exists() + ? Collections.<ClassDef>emptySet().iterator() + : new ClassDefIterator(); + } + }; } |