Home | History | Annotate | Download | only in reader
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package dex.reader;
     18 
     19 import dex.structure.DexFile;
     20 
     21 import java.util.Arrays;
     22 
     23 public final class DexFileReader {
     24 
     25     // DEX constants
     26     private int ENDIAN_CONSTANT = 0x12345678;
     27     @SuppressWarnings("unused")
     28     private int REVERSE_ENDIAN_CONSTANT = 0x78563412;
     29     private final byte[] REF_MAGIC = new byte[] {
     30             0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00};
     31 
     32     // Header values
     33     private DexBuffer b;
     34     private byte[] magic = new byte[8];
     35     @SuppressWarnings("unused")
     36     private int checksum = 0;
     37     private byte[] signature = new byte[20];
     38     @SuppressWarnings("unused")
     39     private int fileSize = 0;
     40     @SuppressWarnings("unused")
     41     private int headerSize = 0;
     42     private int endianTag = 0;
     43 
     44     // Indices of offset and size items
     45     private static final int LINK = 0;
     46     private static final int MAP = 1; // no size!
     47     private static final int STRING_IDS = 2;
     48     private static final int TYPE_IDS = 3;
     49     private static final int PROTO_IDS = 4;
     50     private static final int FIELD_IDS = 5;
     51     private static final int METHOD_IDS = 6;
     52     private static final int CLASS_DEFS = 7;
     53     private static final int DATA = 8;
     54 
     55     private int[] size = new int[9];
     56     private int[] off = new int[9];
     57 
     58 
     59     //
     60     private String[] stringPool;
     61     private int[] typeIds; // values are index of stringPool
     62     private ProtIdItem[] protoIdItems;
     63     private FieldIdItem[] fieldIdItems;
     64     private MethodsIdItem[] methodIdItems;
     65     private ClassDefItem[] classDefItems;
     66 
     67     // starting buffer at zero
     68     public DexFile read(DexBuffer buffer) {
     69         this.b = buffer;
     70         readMagic();
     71         readChecksum();
     72         readSignature();
     73         readFileSize();
     74         readHeaderSize();
     75         readEndianTag();
     76         readSize(LINK);
     77         readOffset(LINK);
     78         readOffset(MAP);
     79         readSize(STRING_IDS);
     80         readOffset(STRING_IDS);
     81         readSize(TYPE_IDS);
     82         readOffset(TYPE_IDS);
     83         readSize(PROTO_IDS);
     84         readOffset(PROTO_IDS);
     85         readSize(FIELD_IDS);
     86         readOffset(FIELD_IDS);
     87         readSize(METHOD_IDS);
     88         readOffset(METHOD_IDS);
     89         readSize(CLASS_DEFS);
     90         readOffset(CLASS_DEFS);
     91         readSize(DATA);
     92         readOffset(DATA);
     93         // from now on, index is not automatically on the desired position
     94         readStrings();
     95         readTypeIds();
     96         readProtos();
     97         readFields();
     98         readMethods();
     99         readClasses();
    100 
    101         return new DexFileImpl(b.createCopy(), stringPool, typeIds,
    102                 protoIdItems, fieldIdItems, methodIdItems, classDefItems);
    103     }
    104 
    105     // MAGIC (8, U_BYTE)
    106     // "dex\n035\0"
    107     private void readMagic() {
    108         b.readBytes(magic);
    109         assert Arrays.equals(magic, REF_MAGIC) : "Not a DEX file";
    110     }
    111 
    112     // CHECKSUM (1, U_INT)
    113     private void readChecksum() {
    114         checksum = b.readUInt();
    115     }
    116 
    117     // SIGNATURE (20, U_BYTE)
    118     private void readSignature() {
    119         b.readBytes(signature);
    120     }
    121 
    122     // FILE_SIZE (1, U_INT)
    123     private void readFileSize() {
    124         fileSize = b.readUInt();
    125     }
    126 
    127     // HEADER_SIZE (1, U_INT), //0x70
    128     private void readHeaderSize() {
    129         headerSize = b.readUInt();
    130     }
    131 
    132     // ENDIAN_TAG (1, U_INT), //ENDIAN_CONSTANT
    133     private void readEndianTag() {
    134         endianTag = b.readUInt();
    135         // FIXME Support for big endian encoded dex files
    136         assert endianTag == ENDIAN_CONSTANT : "Byteorder NOT in little endian";
    137     }
    138 
    139     private void readSize(int attribute) {
    140         size[attribute] = b.readUInt();
    141     }
    142 
    143     private void readOffset(int attribute) {
    144         off[attribute] = b.readUInt();
    145     }
    146 
    147     // reads the string pool
    148     private void readStrings() {
    149         int nStrings = size[STRING_IDS];
    150         b.setPosition(off[STRING_IDS]); // the first string offset is here
    151         int[] stringDataOffsets = new int[nStrings];
    152 
    153         for (int i = 0; i < stringDataOffsets.length; i++) {
    154             stringDataOffsets[i] = b.readUInt();
    155         }
    156 
    157         stringPool = new String[nStrings];
    158         for (int i = 0; i < stringDataOffsets.length; i++) {
    159             b.setPosition(stringDataOffsets[i]); // set buffer to offset
    160             // Position
    161             int lenght = b.readUleb128(); // read uleb128
    162             byte[] values = new byte[lenght];
    163             b.readBytes(values);
    164             stringPool[i] = new String(values);
    165         }
    166     }
    167 
    168     private void readTypeIds() {
    169         int nTypes = size[TYPE_IDS];
    170         b.setPosition(off[TYPE_IDS]); // the first element is here
    171         typeIds = new int[nTypes];
    172 
    173         for (int i = 0; i < typeIds.length; i++) {
    174             typeIds[i] = b.readUInt();
    175         }
    176     }
    177 
    178     static class ProtIdItem {
    179         public int shorty_idx;
    180         public int return_type_idx;
    181         public int parameter_off;
    182     }
    183 
    184     private void readProtos() {
    185         int nProtos = size[PROTO_IDS];
    186         b.setPosition(off[PROTO_IDS]);
    187         protoIdItems = new ProtIdItem[nProtos];
    188 
    189         ProtIdItem item = null;
    190         for (int i = 0; i < protoIdItems.length; i++) {
    191             item = new ProtIdItem();
    192             item.shorty_idx = b.readUInt();
    193             item.return_type_idx = b.readUInt();
    194             item.parameter_off = b.readUInt();
    195             protoIdItems[i] = item;
    196         }
    197     }
    198 
    199     static class FieldIdItem {
    200         public int class_idx; // defining class : index of type_ids
    201         public int type_idx; // type of field : index of type_ids
    202         public int name_idx; // name of field : index into string id (or
    203         // directly stringpool)
    204     }
    205 
    206     private void readFields() {
    207         int nFields = size[FIELD_IDS];
    208         b.setPosition(off[FIELD_IDS]);
    209         fieldIdItems = new FieldIdItem[nFields];
    210 
    211         FieldIdItem item = null;
    212         for (int i = 0; i < fieldIdItems.length; i++) {
    213             item = new FieldIdItem();
    214             item.class_idx = b.readUShort();
    215             item.type_idx = b.readUShort();
    216             item.name_idx = b.readUInt();
    217             fieldIdItems[i] = item;
    218         }
    219     }
    220 
    221     static class MethodsIdItem {
    222         public int class_idx; // defining class : index of typeIds
    223         public int proto_idx; // proto of method : index of protoIdItems
    224         public int name_idx; // name of method : index into string id (or
    225         // directly stringpool)
    226     }
    227 
    228     private void readMethods() {
    229         int nMethods = size[METHOD_IDS];
    230         b.setPosition(off[METHOD_IDS]);
    231         methodIdItems = new MethodsIdItem[nMethods];
    232 
    233         MethodsIdItem item = null;
    234         for (int i = 0; i < methodIdItems.length; i++) {
    235             item = new MethodsIdItem();
    236             item.class_idx = b.readUShort();
    237             item.proto_idx = b.readUShort();
    238             item.name_idx = b.readUInt();
    239             methodIdItems[i] = item;
    240         }
    241     }
    242 
    243     public static class ClassDefItem {
    244         public int class_idx;
    245         public int access_flags;
    246         public int superclass_idx;
    247         public int interfaces_off;
    248         public int source_file_idx;
    249         public int annotations_off;
    250         public int class_data_off;
    251         public int static_values_off;
    252     }
    253 
    254     private void readClasses() {
    255         int nClassDefs = size[CLASS_DEFS];
    256         b.setPosition(off[CLASS_DEFS]);
    257         classDefItems = new ClassDefItem[nClassDefs];
    258 
    259         ClassDefItem item = null;
    260         for (int i = 0; i < classDefItems.length; i++) {
    261             item = new ClassDefItem();
    262             item.class_idx = b.readUInt();
    263             item.access_flags = b.readUInt();
    264             item.superclass_idx = b.readUInt();
    265             item.interfaces_off = b.readUInt();
    266             item.source_file_idx = b.readUInt();
    267             item.annotations_off = b.readUInt();
    268             item.class_data_off = b.readUInt();
    269             item.static_values_off = b.readUInt();
    270             classDefItems[i] = item;
    271         }
    272     }
    273 }
    274