DexReader.java revision 58f5f0c4173e3e7c0c60712b3b1e9cfa4d90f1d5
1/*
2 * Copyright 2012, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2.dexbacked;
33
34import org.jf.util.ExceptionWithContext;
35
36import javax.annotation.Nonnull;
37
38public class DexReader {
39    @Nonnull private final DexBuffer dexBuf;
40    private int offset;
41
42    public DexReader(@Nonnull DexBuffer dexBuf, int offset) {
43        this.dexBuf = dexBuf;
44        this.offset = offset;
45    }
46
47    @Nonnull public DexBuffer getDexBuffer() { return dexBuf; }
48    public int getOffset() { return offset; }
49
50    public int getStringIdItemOffset(int stringIndex) { return dexBuf.getStringIdItemOffset(stringIndex); }
51    public int getTypeIdItemOffset(int typeIndex) { return dexBuf.getTypeIdItemOffset(typeIndex); }
52    public int getFieldIdItemOffset(int fieldIndex) { return dexBuf.getFieldIdItemOffset(fieldIndex); }
53    public int getMethodIdItemOffset(int methodIndex) { return dexBuf.getMethodIdItemOffset(methodIndex); }
54    public int getProtoIdItemOffset(int methodIndex) { return dexBuf.getProtoIdItemOffset(methodIndex); }
55    public int getClassDefItemOffset(int classIndex) { return dexBuf.getClassDefItemOffset(classIndex); }
56    public String getString(int stringIndex) { return dexBuf.getString(stringIndex); }
57    public String getOptionalString(int stringIndex) { return dexBuf.getOptionalString(stringIndex); }
58    public String getType(int typeIndex) { return dexBuf.getType(typeIndex); }
59    public String getField(int fieldIndex) { return dexBuf.getField(fieldIndex); }
60    public String getMethod(int methodIndex) { return dexBuf.getMethod(methodIndex); }
61    public String getReference(int type, int index) { return dexBuf.getReference(type, index); }
62
63    /** {@inheritDoc} */
64    public int readSleb128() {
65        int end = offset;
66        int currentByteValue;
67        int result;
68        byte[] buf = dexBuf.buf;
69
70        result = buf[end++] & 0xff;
71        if (result <= 0x7f) {
72            result = (result << 25) >> 25;
73        } else {
74            currentByteValue = buf[end++] & 0xff;
75            result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
76            if (currentByteValue <= 0x7f) {
77                result = (result << 18) >> 18;
78            } else {
79                currentByteValue = buf[end++] & 0xff;
80                result |= (currentByteValue & 0x7f) << 14;
81                if (currentByteValue <= 0x7f) {
82                    result = (result << 11) >> 11;
83                } else {
84                    currentByteValue = buf[end++] & 0xff;
85                    result |= (currentByteValue & 0x7f) << 21;
86                    if (currentByteValue <= 0x7f) {
87                        result = (result << 4) >> 4;
88                    } else {
89                        currentByteValue = buf[end++] & 0xff;
90                        if (currentByteValue > 0x7f) {
91                            throw new ExceptionWithContext(
92                                    "Invalid sleb128 integer encountered at offset 0x%x", offset);
93                        }
94                        result |= currentByteValue << 28;
95                    }
96                }
97            }
98        }
99
100        offset = end;
101        return result;
102    }
103
104    public int readSmallUleb128() {
105        int end = offset;
106        int currentByteValue;
107        int result;
108        byte[] buf = dexBuf.buf;
109
110        result = buf[end++] & 0xff;
111        if (result > 0x7f) {
112            currentByteValue = buf[end++] & 0xff;
113            result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
114            if (currentByteValue > 0x7f) {
115                currentByteValue = buf[end++] & 0xff;
116                result |= (currentByteValue & 0x7f) << 14;
117                if (currentByteValue > 0x7f) {
118                    currentByteValue = buf[end++] & 0xff;
119                    result |= (currentByteValue & 0x7f) << 21;
120                    if (currentByteValue > 0x7f) {
121                        currentByteValue = buf[end++];
122
123                        // MSB shouldn't be set on last byte
124                        if (currentByteValue < 0) {
125                            throw new ExceptionWithContext(
126                                    "Invalid uleb128 integer encountered at offset 0x%x", offset);
127                        } else if ((currentByteValue & 0xf) > 0x07) {
128                            // we assume most significant bit of the result will not be set, so that it can fit into
129                            // a signed integer without wrapping
130                            throw new ExceptionWithContext(
131                                    "Encountered valid uleb128 that is out of range at offset 0x%x", offset);
132                        }
133                        result |= currentByteValue << 28;
134                    }
135                }
136            }
137        }
138
139        offset = end;
140        return result;
141    }
142
143    public void skipUleb128() {
144        int end = offset;
145        byte currentByteValue;
146        byte[] buf = dexBuf.buf;
147
148        currentByteValue = buf[end++];
149        if (currentByteValue < 0) { // if the MSB is set
150            currentByteValue = buf[end++];
151            if (currentByteValue < 0) { // if the MSB is set
152                currentByteValue = buf[end++];
153                if (currentByteValue < 0) { // if the MSB is set
154                    currentByteValue = buf[end++];
155                    if (currentByteValue < 0) { // if the MSB is set
156                        currentByteValue = buf[end++];
157                        if (currentByteValue < 0) {
158                            throw new ExceptionWithContext(
159                                    "Invalid uleb128 integer encountered at offset 0x%x", offset);
160                        } else if ((currentByteValue & 0xf) > 0x07) {
161                            // we assume most significant bit of the result will not be set, so that it can fit into
162                            // a signed integer without wrapping
163                            throw new ExceptionWithContext(
164                                    "Encountered valid uleb128 that is out of range at offset 0x%x", offset);
165                        }
166                    }
167                }
168            }
169        }
170
171        offset = end;
172    }
173
174    public int readSmallUint() {
175        int o = offset;
176        int result = dexBuf.readSmallUint(o);
177        offset = o + 4;
178        return result;
179    }
180
181    public int readOptionalUint() {
182        int o = offset;
183        int result = dexBuf.readOptionalUint(o);
184        offset = o + 4;
185        return result;
186    }
187
188    public int readUshort() {
189        int o = offset;
190        int result = dexBuf.readUshort(offset);
191        offset = o + 2;
192        return result;
193    }
194
195    public int readUbyte() {
196        int o = offset;
197        int result = dexBuf.readUbyte(offset);
198        offset = o + 1;
199        return result;
200    }
201
202    public long readLong() {
203        int o = offset;
204        long result = dexBuf.readLong(offset);
205        offset = o + 2;
206        return result;
207    }
208
209    public int readInt() {
210        int o = offset;
211        int result = dexBuf.readInt(offset);
212        offset = o + 4;
213        return result;
214    }
215
216    public int readShort() {
217        int o = offset;
218        int result = dexBuf.readShort(offset);
219        offset = o + 2;
220        return result;
221    }
222
223    public int readByte() {
224        int o = offset;
225        int result = dexBuf.readByte(offset);
226        offset = o + 1;
227        return result;
228    }
229
230    public void skipByte() { offset++; }
231    public void skipBytes(int i) { offset += i; }
232
233    public int readSmallUint(int offset) { return dexBuf.readSmallUint(offset); }
234    public int readUshort(int offset) { return dexBuf.readUshort(offset); }
235    public int readUbyte(int offset) { return dexBuf.readUbyte(offset); }
236    public long readLong(int offset) { return dexBuf.readLong(offset); }
237    public int readInt(int offset) { return dexBuf.readInt(offset); }
238    public int readShort(int offset) { return dexBuf.readShort(offset); }
239    public int readByte(int offset) { return dexBuf.readByte(offset); }
240
241    public int readSizedInt(int bytes) {
242        int o = offset;
243        byte[] buf = dexBuf.buf;
244
245        int result;
246        switch (bytes) {
247            case 4:
248                result = (buf[o] & 0xff) |
249                         ((buf[o+1] & 0xff) << 8) |
250                         ((buf[o+2] & 0xff) << 16) |
251                         (buf[o+3] << 24);
252                break;
253            case 3:
254                result = (buf[o] & 0xff) |
255                        ((buf[o+1] & 0xff) << 8) |
256                        ((buf[o+2]) << 16);
257                break;
258            case 2:
259                result = (buf[o] & 0xff) |
260                        ((buf[o+1]) << 8);
261                break;
262            case 1:
263                result = buf[o];
264                break;
265            default:
266                throw new ExceptionWithContext("Invalid size %d for sized int at offset 0x%x", bytes, offset);
267        }
268        offset = o + bytes;
269        return result;
270    }
271
272    public int readSizedSmallUint(int bytes) {
273        int o = offset;
274        byte[] buf = dexBuf.buf;
275
276        int result = 0;
277        switch (bytes) {
278            case 4:
279                int b = buf[o+3];
280                if (b < 0) {
281                    throw new ExceptionWithContext(
282                            "Encountered valid sized uint that is out of range at offset 0x%x", offset);
283                }
284                result = b << 24;
285                // fall-through
286            case 3:
287                result |= (buf[o+2] & 0xff) << 16;
288                // fall-through
289            case 2:
290                result |= (buf[o+1] & 0xff) << 8;
291                // fall-through
292            case 1:
293                result |= (buf[o] & 0xff);
294                break;
295            default:
296                throw new ExceptionWithContext("Invalid size %d for sized uint at offset 0x%x", bytes, offset);
297        }
298        offset = o + bytes;
299        return result;
300    }
301
302    public int readSizedRightExtendedInt(int bytes) {
303        int o = offset;
304        byte[] buf = dexBuf.buf;
305
306        int result;
307        switch (bytes) {
308            case 4:
309                result = (buf[o] & 0xff) |
310                         ((buf[o+1] & 0xff) << 8) |
311                         ((buf[o+2] & 0xff) << 16) |
312                         (buf[o+3] << 24);
313                break;
314            case 3:
315                result = (buf[o] & 0xff) << 8 |
316                         ((buf[o+1] & 0xff) << 16) |
317                         (buf[o+2] << 24);
318                break;
319            case 2:
320                result = (buf[o] & 0xff) << 16 |
321                         (buf[o+1] << 24);
322                break;
323            case 1:
324                result = buf[o] << 24;
325                break;
326            default:
327                throw new ExceptionWithContext(
328                        "Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset);
329        }
330        offset = o + bytes;
331        return result;
332    }
333
334    public long readSizedRightExtendedLong(int bytes) {
335        int o = offset;
336        byte[] buf = dexBuf.buf;
337
338        long result;
339        switch (bytes) {
340            case 8:
341                result = (buf[o] & 0xff) |
342                         ((buf[o+1] & 0xff) << 8) |
343                         ((buf[o+2] & 0xff) << 16) |
344                         ((buf[o+3] & 0xffL) << 24) |
345                         ((buf[o+4] & 0xffL) << 32) |
346                         ((buf[o+5] & 0xffL) << 40) |
347                         ((buf[o+6] & 0xffL) << 48) |
348                         (((long)buf[o+7]) << 56);
349                break;
350            case 7:
351                result = ((buf[o] & 0xff)) << 8 |
352                         ((buf[o+1] & 0xff) << 16) |
353                         ((buf[o+2] & 0xffL) << 24) |
354                         ((buf[o+3] & 0xffL) << 32) |
355                         ((buf[o+4] & 0xffL) << 40) |
356                         ((buf[o+5] & 0xffL) << 48) |
357                         (((long)buf[o+6]) << 56);
358                break;
359            case 6:
360                result = ((buf[o] & 0xff)) << 16 |
361                         ((buf[o+1] & 0xffL) << 24) |
362                         ((buf[o+2] & 0xffL) << 32) |
363                         ((buf[o+3] & 0xffL) << 40) |
364                         ((buf[o+4] & 0xffL) << 48) |
365                         (((long)buf[o+5]) << 56);
366                break;
367            case 5:
368                result = ((buf[o] & 0xffL)) << 24 |
369                         ((buf[o+1] & 0xffL) << 32) |
370                         ((buf[o+2] & 0xffL) << 40) |
371                         ((buf[o+3] & 0xffL) << 48) |
372                         (((long)buf[o+4]) << 56);
373                break;
374            case 4:
375                result = ((buf[o] & 0xffL)) << 32 |
376                         ((buf[o+1] & 0xffL) << 40) |
377                         ((buf[o+2] & 0xffL) << 48) |
378                         (((long)buf[o+3]) << 56);
379                break;
380            case 3:
381                result = ((buf[o] & 0xffL)) << 40 |
382                         ((buf[o+1] & 0xffL) << 48) |
383                         (((long)buf[o+2]) << 56);
384                break;
385            case 2:
386                result = ((buf[o] & 0xffL)) << 48 |
387                         (((long)buf[o+1]) << 56);
388                break;
389            case 1:
390                result = ((long)buf[o]) << 56;
391                break;
392            default:
393                throw new ExceptionWithContext(
394                        "Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset);
395        }
396        offset = o + bytes;
397        return result;
398    }
399
400    public long readSizedLong(int bytes) {
401        int o = offset;
402        byte[] buf = dexBuf.buf;
403
404        long result;
405        switch (bytes) {
406            case 8:
407                result = (buf[o] & 0xff) |
408                         ((buf[o+1] & 0xff) << 8) |
409                         ((buf[o+2] & 0xff) << 16) |
410                         ((buf[o+3] & 0xffL) << 24) |
411                         ((buf[o+4] & 0xffL) << 32) |
412                         ((buf[o+5] & 0xffL) << 40) |
413                         ((buf[o+6] & 0xffL) << 48) |
414                         (((long)buf[o+7]) << 56);
415                break;
416            case 7:
417                result = (buf[o] & 0xff) |
418                         ((buf[o+1] & 0xff) << 8) |
419                         ((buf[o+2] & 0xff) << 16) |
420                         ((buf[o+3] & 0xffL) << 24) |
421                         ((buf[o+4] & 0xffL) << 32) |
422                         ((buf[o+5] & 0xffL) << 40) |
423                         ((long)(buf[o+6]) << 48);
424                break;
425            case 6:
426                result = (buf[o] & 0xff) |
427                         ((buf[o+1] & 0xff) << 8) |
428                         ((buf[o+2] & 0xff) << 16) |
429                         ((buf[o+3] & 0xffL) << 24) |
430                         ((buf[o+4] & 0xffL) << 32) |
431                         ((long)(buf[o+5]) << 40);
432                break;
433            case 5:
434                result = (buf[o] & 0xff) |
435                         ((buf[o+1] & 0xff) << 8) |
436                         ((buf[o+2] & 0xff) << 16) |
437                         ((buf[o+3] & 0xffL) << 24) |
438                         ((long)(buf[o+4]) << 32);
439                break;
440            case 4:
441                result = (buf[o] & 0xff) |
442                        ((buf[o+1] & 0xff) << 8) |
443                        ((buf[o+2] & 0xff) << 16) |
444                        (((long)buf[o+3]) << 24);
445                break;
446            case 3:
447                result = (buf[o] & 0xff) |
448                        ((buf[o+1] & 0xff) << 8) |
449                        (buf[o+2] << 16);
450                break;
451            case 2:
452                result = (buf[o] & 0xff) |
453                        (buf[o+1] << 8);
454                break;
455            case 1:
456                result = buf[o];
457                break;
458            default:
459                throw new ExceptionWithContext("Invalid size %d for sized long at offset 0x%x", bytes, offset);
460        }
461
462        o += bytes;
463        return result;
464    }
465}