DexReader.java revision b116cb0ac9c9da172ab8224a7eb762dbbbb9bed1
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    public void setOffset(int offset) { this.offset = offset; }
50
51    public int getStringIdItemOffset(int stringIndex) { return dexBuf.getStringIdItemOffset(stringIndex); }
52    public int getTypeIdItemOffset(int typeIndex) { return dexBuf.getTypeIdItemOffset(typeIndex); }
53    public int getFieldIdItemOffset(int fieldIndex) { return dexBuf.getFieldIdItemOffset(fieldIndex); }
54    public int getMethodIdItemOffset(int methodIndex) { return dexBuf.getMethodIdItemOffset(methodIndex); }
55    public int getProtoIdItemOffset(int methodIndex) { return dexBuf.getProtoIdItemOffset(methodIndex); }
56    public int getClassDefItemOffset(int classIndex) { return dexBuf.getClassDefItemOffset(classIndex); }
57    public String getString(int stringIndex) { return dexBuf.getString(stringIndex); }
58    public String getOptionalString(int stringIndex) { return dexBuf.getOptionalString(stringIndex); }
59    public String getType(int typeIndex) { return dexBuf.getType(typeIndex); }
60    public String getOptionalType(int typeIndex) { return dexBuf.getOptionalType(typeIndex); }
61    public String getField(int fieldIndex) { return dexBuf.getField(fieldIndex); }
62    public String getMethod(int methodIndex) { return dexBuf.getMethod(methodIndex); }
63    public String getReference(int type, int index) { return dexBuf.getReference(type, index); }
64
65    /** {@inheritDoc} */
66    public int readSleb128() {
67        int end = offset;
68        int currentByteValue;
69        int result;
70        byte[] buf = dexBuf.buf;
71
72        result = buf[end++] & 0xff;
73        if (result <= 0x7f) {
74            result = (result << 25) >> 25;
75        } else {
76            currentByteValue = buf[end++] & 0xff;
77            result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
78            if (currentByteValue <= 0x7f) {
79                result = (result << 18) >> 18;
80            } else {
81                currentByteValue = buf[end++] & 0xff;
82                result |= (currentByteValue & 0x7f) << 14;
83                if (currentByteValue <= 0x7f) {
84                    result = (result << 11) >> 11;
85                } else {
86                    currentByteValue = buf[end++] & 0xff;
87                    result |= (currentByteValue & 0x7f) << 21;
88                    if (currentByteValue <= 0x7f) {
89                        result = (result << 4) >> 4;
90                    } else {
91                        currentByteValue = buf[end++] & 0xff;
92                        if (currentByteValue > 0x7f) {
93                            throw new ExceptionWithContext(
94                                    "Invalid sleb128 integer encountered at offset 0x%x", offset);
95                        }
96                        result |= currentByteValue << 28;
97                    }
98                }
99            }
100        }
101
102        offset = end;
103        return result;
104    }
105
106    public int readSmallUleb128() {
107        int end = offset;
108        int currentByteValue;
109        int result;
110        byte[] buf = dexBuf.buf;
111
112        result = buf[end++] & 0xff;
113        if (result > 0x7f) {
114            currentByteValue = buf[end++] & 0xff;
115            result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
116            if (currentByteValue > 0x7f) {
117                currentByteValue = buf[end++] & 0xff;
118                result |= (currentByteValue & 0x7f) << 14;
119                if (currentByteValue > 0x7f) {
120                    currentByteValue = buf[end++] & 0xff;
121                    result |= (currentByteValue & 0x7f) << 21;
122                    if (currentByteValue > 0x7f) {
123                        currentByteValue = buf[end++];
124
125                        // MSB shouldn't be set on last byte
126                        if (currentByteValue < 0) {
127                            throw new ExceptionWithContext(
128                                    "Invalid uleb128 integer encountered at offset 0x%x", offset);
129                        } else if ((currentByteValue & 0xf) > 0x07) {
130                            // we assume most significant bit of the result will not be set, so that it can fit into
131                            // a signed integer without wrapping
132                            throw new ExceptionWithContext(
133                                    "Encountered valid uleb128 that is out of range at offset 0x%x", offset);
134                        }
135                        result |= currentByteValue << 28;
136                    }
137                }
138            }
139        }
140
141        offset = end;
142        return result;
143    }
144
145    public void skipUleb128() {
146        int end = offset;
147        byte currentByteValue;
148        byte[] buf = dexBuf.buf;
149
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) { // if the MSB is set
158                        currentByteValue = buf[end++];
159                        if (currentByteValue < 0) {
160                            throw new ExceptionWithContext(
161                                    "Invalid uleb128 integer encountered at offset 0x%x", offset);
162                        } else if ((currentByteValue & 0xf) > 0x07) {
163                            // we assume most significant bit of the result will not be set, so that it can fit into
164                            // a signed integer without wrapping
165                            throw new ExceptionWithContext(
166                                    "Encountered valid uleb128 that is out of range at offset 0x%x", offset);
167                        }
168                    }
169                }
170            }
171        }
172
173        offset = end;
174    }
175
176    public int readSmallUint() {
177        int o = offset;
178        int result = dexBuf.readSmallUint(o);
179        offset = o + 4;
180        return result;
181    }
182
183    public int readOptionalUint() {
184        int o = offset;
185        int result = dexBuf.readOptionalUint(o);
186        offset = o + 4;
187        return result;
188    }
189
190    public int peekUshort() {
191        return dexBuf.readUshort(offset);
192    }
193
194    public int readUshort() {
195        int o = offset;
196        int result = dexBuf.readUshort(offset);
197        offset = o + 2;
198        return result;
199    }
200
201    public int peekUbyte() {
202        return dexBuf.readUbyte(offset);
203    }
204
205    public int readUbyte() {
206        int o = offset;
207        int result = dexBuf.readUbyte(offset);
208        offset = o + 1;
209        return result;
210    }
211
212    public long readLong() {
213        int o = offset;
214        long result = dexBuf.readLong(offset);
215        offset = o + 8;
216        return result;
217    }
218
219    public int readInt() {
220        int o = offset;
221        int result = dexBuf.readInt(offset);
222        offset = o + 4;
223        return result;
224    }
225
226    public int readShort() {
227        int o = offset;
228        int result = dexBuf.readShort(offset);
229        offset = o + 2;
230        return result;
231    }
232
233    public int readByte() {
234        int o = offset;
235        int result = dexBuf.readByte(offset);
236        offset = o + 1;
237        return result;
238    }
239
240    public void skipByte() { offset++; }
241    public void moveRelative(int i) { offset += i; }
242
243    public int readSmallUint(int offset) { return dexBuf.readSmallUint(offset); }
244    public int readUshort(int offset) { return dexBuf.readUshort(offset); }
245    public int readUbyte(int offset) { return dexBuf.readUbyte(offset); }
246    public long readLong(int offset) { return dexBuf.readLong(offset); }
247    public int readInt(int offset) { return dexBuf.readInt(offset); }
248    public int readShort(int offset) { return dexBuf.readShort(offset); }
249    public int readByte(int offset) { return dexBuf.readByte(offset); }
250
251    public int readSizedInt(int bytes) {
252        int o = offset;
253        byte[] buf = dexBuf.buf;
254
255        int result;
256        switch (bytes) {
257            case 4:
258                result = (buf[o] & 0xff) |
259                         ((buf[o+1] & 0xff) << 8) |
260                         ((buf[o+2] & 0xff) << 16) |
261                         (buf[o+3] << 24);
262                break;
263            case 3:
264                result = (buf[o] & 0xff) |
265                        ((buf[o+1] & 0xff) << 8) |
266                        ((buf[o+2]) << 16);
267                break;
268            case 2:
269                result = (buf[o] & 0xff) |
270                        ((buf[o+1]) << 8);
271                break;
272            case 1:
273                result = buf[o];
274                break;
275            default:
276                throw new ExceptionWithContext("Invalid size %d for sized int at offset 0x%x", bytes, offset);
277        }
278        offset = o + bytes;
279        return result;
280    }
281
282    public int readSizedSmallUint(int bytes) {
283        int o = offset;
284        byte[] buf = dexBuf.buf;
285
286        int result = 0;
287        switch (bytes) {
288            case 4:
289                int b = buf[o+3];
290                if (b < 0) {
291                    throw new ExceptionWithContext(
292                            "Encountered valid sized uint that is out of range at offset 0x%x", offset);
293                }
294                result = b << 24;
295                // fall-through
296            case 3:
297                result |= (buf[o+2] & 0xff) << 16;
298                // fall-through
299            case 2:
300                result |= (buf[o+1] & 0xff) << 8;
301                // fall-through
302            case 1:
303                result |= (buf[o] & 0xff);
304                break;
305            default:
306                throw new ExceptionWithContext("Invalid size %d for sized uint at offset 0x%x", bytes, offset);
307        }
308        offset = o + bytes;
309        return result;
310    }
311
312    public int readSizedRightExtendedInt(int bytes) {
313        int o = offset;
314        byte[] buf = dexBuf.buf;
315
316        int result;
317        switch (bytes) {
318            case 4:
319                result = (buf[o] & 0xff) |
320                         ((buf[o+1] & 0xff) << 8) |
321                         ((buf[o+2] & 0xff) << 16) |
322                         (buf[o+3] << 24);
323                break;
324            case 3:
325                result = (buf[o] & 0xff) << 8 |
326                         ((buf[o+1] & 0xff) << 16) |
327                         (buf[o+2] << 24);
328                break;
329            case 2:
330                result = (buf[o] & 0xff) << 16 |
331                         (buf[o+1] << 24);
332                break;
333            case 1:
334                result = buf[o] << 24;
335                break;
336            default:
337                throw new ExceptionWithContext(
338                        "Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset);
339        }
340        offset = o + bytes;
341        return result;
342    }
343
344    public long readSizedRightExtendedLong(int bytes) {
345        int o = offset;
346        byte[] buf = dexBuf.buf;
347
348        long result;
349        switch (bytes) {
350            case 8:
351                result = (buf[o] & 0xff) |
352                         ((buf[o+1] & 0xff) << 8) |
353                         ((buf[o+2] & 0xff) << 16) |
354                         ((buf[o+3] & 0xffL) << 24) |
355                         ((buf[o+4] & 0xffL) << 32) |
356                         ((buf[o+5] & 0xffL) << 40) |
357                         ((buf[o+6] & 0xffL) << 48) |
358                         (((long)buf[o+7]) << 56);
359                break;
360            case 7:
361                result = ((buf[o] & 0xff)) << 8 |
362                         ((buf[o+1] & 0xff) << 16) |
363                         ((buf[o+2] & 0xffL) << 24) |
364                         ((buf[o+3] & 0xffL) << 32) |
365                         ((buf[o+4] & 0xffL) << 40) |
366                         ((buf[o+5] & 0xffL) << 48) |
367                         (((long)buf[o+6]) << 56);
368                break;
369            case 6:
370                result = ((buf[o] & 0xff)) << 16 |
371                         ((buf[o+1] & 0xffL) << 24) |
372                         ((buf[o+2] & 0xffL) << 32) |
373                         ((buf[o+3] & 0xffL) << 40) |
374                         ((buf[o+4] & 0xffL) << 48) |
375                         (((long)buf[o+5]) << 56);
376                break;
377            case 5:
378                result = ((buf[o] & 0xffL)) << 24 |
379                         ((buf[o+1] & 0xffL) << 32) |
380                         ((buf[o+2] & 0xffL) << 40) |
381                         ((buf[o+3] & 0xffL) << 48) |
382                         (((long)buf[o+4]) << 56);
383                break;
384            case 4:
385                result = ((buf[o] & 0xffL)) << 32 |
386                         ((buf[o+1] & 0xffL) << 40) |
387                         ((buf[o+2] & 0xffL) << 48) |
388                         (((long)buf[o+3]) << 56);
389                break;
390            case 3:
391                result = ((buf[o] & 0xffL)) << 40 |
392                         ((buf[o+1] & 0xffL) << 48) |
393                         (((long)buf[o+2]) << 56);
394                break;
395            case 2:
396                result = ((buf[o] & 0xffL)) << 48 |
397                         (((long)buf[o+1]) << 56);
398                break;
399            case 1:
400                result = ((long)buf[o]) << 56;
401                break;
402            default:
403                throw new ExceptionWithContext(
404                        "Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset);
405        }
406        offset = o + bytes;
407        return result;
408    }
409
410    public long readSizedLong(int bytes) {
411        int o = offset;
412        byte[] buf = dexBuf.buf;
413
414        long result;
415        switch (bytes) {
416            case 8:
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                         ((buf[o+6] & 0xffL) << 48) |
424                         (((long)buf[o+7]) << 56);
425                break;
426            case 7:
427                result = (buf[o] & 0xff) |
428                         ((buf[o+1] & 0xff) << 8) |
429                         ((buf[o+2] & 0xff) << 16) |
430                         ((buf[o+3] & 0xffL) << 24) |
431                         ((buf[o+4] & 0xffL) << 32) |
432                         ((buf[o+5] & 0xffL) << 40) |
433                         ((long)(buf[o+6]) << 48);
434                break;
435            case 6:
436                result = (buf[o] & 0xff) |
437                         ((buf[o+1] & 0xff) << 8) |
438                         ((buf[o+2] & 0xff) << 16) |
439                         ((buf[o+3] & 0xffL) << 24) |
440                         ((buf[o+4] & 0xffL) << 32) |
441                         ((long)(buf[o+5]) << 40);
442                break;
443            case 5:
444                result = (buf[o] & 0xff) |
445                         ((buf[o+1] & 0xff) << 8) |
446                         ((buf[o+2] & 0xff) << 16) |
447                         ((buf[o+3] & 0xffL) << 24) |
448                         ((long)(buf[o+4]) << 32);
449                break;
450            case 4:
451                result = (buf[o] & 0xff) |
452                        ((buf[o+1] & 0xff) << 8) |
453                        ((buf[o+2] & 0xff) << 16) |
454                        (((long)buf[o+3]) << 24);
455                break;
456            case 3:
457                result = (buf[o] & 0xff) |
458                        ((buf[o+1] & 0xff) << 8) |
459                        (buf[o+2] << 16);
460                break;
461            case 2:
462                result = (buf[o] & 0xff) |
463                        (buf[o+1] << 8);
464                break;
465            case 1:
466                result = buf[o];
467                break;
468            default:
469                throw new ExceptionWithContext("Invalid size %d for sized long at offset 0x%x", bytes, offset);
470        }
471
472        offset = o + bytes;
473        return result;
474    }
475}