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