/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dex.reader; import dex.structure.DexFile; import java.util.Arrays; public final class DexFileReader { // DEX constants private int ENDIAN_CONSTANT = 0x12345678; @SuppressWarnings("unused") private int REVERSE_ENDIAN_CONSTANT = 0x78563412; private final byte[] REF_MAGIC = new byte[] { 0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00}; // Header values private DexBuffer b; private byte[] magic = new byte[8]; @SuppressWarnings("unused") private int checksum = 0; private byte[] signature = new byte[20]; @SuppressWarnings("unused") private int fileSize = 0; @SuppressWarnings("unused") private int headerSize = 0; private int endianTag = 0; // Indices of offset and size items private static final int LINK = 0; private static final int MAP = 1; // no size! private static final int STRING_IDS = 2; private static final int TYPE_IDS = 3; private static final int PROTO_IDS = 4; private static final int FIELD_IDS = 5; private static final int METHOD_IDS = 6; private static final int CLASS_DEFS = 7; private static final int DATA = 8; private int[] size = new int[9]; private int[] off = new int[9]; // private String[] stringPool; private int[] typeIds; // values are index of stringPool private ProtIdItem[] protoIdItems; private FieldIdItem[] fieldIdItems; private MethodsIdItem[] methodIdItems; private ClassDefItem[] classDefItems; // starting buffer at zero public DexFile read(DexBuffer buffer) { this.b = buffer; readMagic(); readChecksum(); readSignature(); readFileSize(); readHeaderSize(); readEndianTag(); readSize(LINK); readOffset(LINK); readOffset(MAP); readSize(STRING_IDS); readOffset(STRING_IDS); readSize(TYPE_IDS); readOffset(TYPE_IDS); readSize(PROTO_IDS); readOffset(PROTO_IDS); readSize(FIELD_IDS); readOffset(FIELD_IDS); readSize(METHOD_IDS); readOffset(METHOD_IDS); readSize(CLASS_DEFS); readOffset(CLASS_DEFS); readSize(DATA); readOffset(DATA); // from now on, index is not automatically on the desired position readStrings(); readTypeIds(); readProtos(); readFields(); readMethods(); readClasses(); return new DexFileImpl(b.createCopy(), stringPool, typeIds, protoIdItems, fieldIdItems, methodIdItems, classDefItems); } // MAGIC (8, U_BYTE) // "dex\n035\0" private void readMagic() { b.readBytes(magic); assert Arrays.equals(magic, REF_MAGIC) : "Not a DEX file"; } // CHECKSUM (1, U_INT) private void readChecksum() { checksum = b.readUInt(); } // SIGNATURE (20, U_BYTE) private void readSignature() { b.readBytes(signature); } // FILE_SIZE (1, U_INT) private void readFileSize() { fileSize = b.readUInt(); } // HEADER_SIZE (1, U_INT), //0x70 private void readHeaderSize() { headerSize = b.readUInt(); } // ENDIAN_TAG (1, U_INT), //ENDIAN_CONSTANT private void readEndianTag() { endianTag = b.readUInt(); // FIXME Support for big endian encoded dex files assert endianTag == ENDIAN_CONSTANT : "Byteorder NOT in little endian"; } private void readSize(int attribute) { size[attribute] = b.readUInt(); } private void readOffset(int attribute) { off[attribute] = b.readUInt(); } // reads the string pool private void readStrings() { int nStrings = size[STRING_IDS]; b.setPosition(off[STRING_IDS]); // the first string offset is here int[] stringDataOffsets = new int[nStrings]; for (int i = 0; i < stringDataOffsets.length; i++) { stringDataOffsets[i] = b.readUInt(); } stringPool = new String[nStrings]; for (int i = 0; i < stringDataOffsets.length; i++) { b.setPosition(stringDataOffsets[i]); // set buffer to offset // Position int lenght = b.readUleb128(); // read uleb128 byte[] values = new byte[lenght]; b.readBytes(values); stringPool[i] = new String(values); } } private void readTypeIds() { int nTypes = size[TYPE_IDS]; b.setPosition(off[TYPE_IDS]); // the first element is here typeIds = new int[nTypes]; for (int i = 0; i < typeIds.length; i++) { typeIds[i] = b.readUInt(); } } static class ProtIdItem { public int shorty_idx; public int return_type_idx; public int parameter_off; } private void readProtos() { int nProtos = size[PROTO_IDS]; b.setPosition(off[PROTO_IDS]); protoIdItems = new ProtIdItem[nProtos]; ProtIdItem item = null; for (int i = 0; i < protoIdItems.length; i++) { item = new ProtIdItem(); item.shorty_idx = b.readUInt(); item.return_type_idx = b.readUInt(); item.parameter_off = b.readUInt(); protoIdItems[i] = item; } } static class FieldIdItem { public int class_idx; // defining class : index of type_ids public int type_idx; // type of field : index of type_ids public int name_idx; // name of field : index into string id (or // directly stringpool) } private void readFields() { int nFields = size[FIELD_IDS]; b.setPosition(off[FIELD_IDS]); fieldIdItems = new FieldIdItem[nFields]; FieldIdItem item = null; for (int i = 0; i < fieldIdItems.length; i++) { item = new FieldIdItem(); item.class_idx = b.readUShort(); item.type_idx = b.readUShort(); item.name_idx = b.readUInt(); fieldIdItems[i] = item; } } static class MethodsIdItem { public int class_idx; // defining class : index of typeIds public int proto_idx; // proto of method : index of protoIdItems public int name_idx; // name of method : index into string id (or // directly stringpool) } private void readMethods() { int nMethods = size[METHOD_IDS]; b.setPosition(off[METHOD_IDS]); methodIdItems = new MethodsIdItem[nMethods]; MethodsIdItem item = null; for (int i = 0; i < methodIdItems.length; i++) { item = new MethodsIdItem(); item.class_idx = b.readUShort(); item.proto_idx = b.readUShort(); item.name_idx = b.readUInt(); methodIdItems[i] = item; } } public static class ClassDefItem { public int class_idx; public int access_flags; public int superclass_idx; public int interfaces_off; public int source_file_idx; public int annotations_off; public int class_data_off; public int static_values_off; } private void readClasses() { int nClassDefs = size[CLASS_DEFS]; b.setPosition(off[CLASS_DEFS]); classDefItems = new ClassDefItem[nClassDefs]; ClassDefItem item = null; for (int i = 0; i < classDefItems.length; i++) { item = new ClassDefItem(); item.class_idx = b.readUInt(); item.access_flags = b.readUInt(); item.superclass_idx = b.readUInt(); item.interfaces_off = b.readUInt(); item.source_file_idx = b.readUInt(); item.annotations_off = b.readUInt(); item.class_data_off = b.readUInt(); item.static_values_off = b.readUInt(); classDefItems[i] = item; } } }