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
read(DexBuffer buffer)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"
readMagic()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)
readChecksum()113     private void readChecksum() {
114         checksum = b.readUInt();
115     }
116 
117     // SIGNATURE (20, U_BYTE)
readSignature()118     private void readSignature() {
119         b.readBytes(signature);
120     }
121 
122     // FILE_SIZE (1, U_INT)
readFileSize()123     private void readFileSize() {
124         fileSize = b.readUInt();
125     }
126 
127     // HEADER_SIZE (1, U_INT), //0x70
readHeaderSize()128     private void readHeaderSize() {
129         headerSize = b.readUInt();
130     }
131 
132     // ENDIAN_TAG (1, U_INT), //ENDIAN_CONSTANT
readEndianTag()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 
readSize(int attribute)139     private void readSize(int attribute) {
140         size[attribute] = b.readUInt();
141     }
142 
readOffset(int attribute)143     private void readOffset(int attribute) {
144         off[attribute] = b.readUInt();
145     }
146 
147     // reads the string pool
readStrings()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 
readTypeIds()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 
readProtos()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 
readFields()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 
readMethods()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 
readClasses()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