DexReader.java revision ebd617800870433d4133a192bac709c645b55a9b
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 readUshort() {
191        int o = offset;
192        int result = dexBuf.readUshort(offset);
193        offset = o + 2;
194        return result;
195    }
196
197    public int readUbyte() {
198        int o = offset;
199        int result = dexBuf.readUbyte(offset);
200        offset = o + 1;
201        return result;
202    }
203
204    public long readLong() {
205        int o = offset;
206        long result = dexBuf.readLong(offset);
207        offset = o + 8;
208        return result;
209    }
210
211    public int readInt() {
212        int o = offset;
213        int result = dexBuf.readInt(offset);
214        offset = o + 4;
215        return result;
216    }
217
218    public int readShort() {
219        int o = offset;
220        int result = dexBuf.readShort(offset);
221        offset = o + 2;
222        return result;
223    }
224
225    public int readByte() {
226        int o = offset;
227        int result = dexBuf.readByte(offset);
228        offset = o + 1;
229        return result;
230    }
231
232    public void skipByte() { offset++; }
233    public void moveRelative(int i) { offset += i; }
234
235    public int readSmallUint(int offset) { return dexBuf.readSmallUint(offset); }
236    public int readUshort(int offset) { return dexBuf.readUshort(offset); }
237    public int readUbyte(int offset) { return dexBuf.readUbyte(offset); }
238    public long readLong(int offset) { return dexBuf.readLong(offset); }
239    public int readInt(int offset) { return dexBuf.readInt(offset); }
240    public int readShort(int offset) { return dexBuf.readShort(offset); }
241    public int readByte(int offset) { return dexBuf.readByte(offset); }
242
243    public int readSizedInt(int bytes) {
244        int o = offset;
245        byte[] buf = dexBuf.buf;
246
247        int result;
248        switch (bytes) {
249            case 4:
250                result = (buf[o] & 0xff) |
251                         ((buf[o+1] & 0xff) << 8) |
252                         ((buf[o+2] & 0xff) << 16) |
253                         (buf[o+3] << 24);
254                break;
255            case 3:
256                result = (buf[o] & 0xff) |
257                        ((buf[o+1] & 0xff) << 8) |
258                        ((buf[o+2]) << 16);
259                break;
260            case 2:
261                result = (buf[o] & 0xff) |
262                        ((buf[o+1]) << 8);
263                break;
264            case 1:
265                result = buf[o];
266                break;
267            default:
268                throw new ExceptionWithContext("Invalid size %d for sized int at offset 0x%x", bytes, offset);
269        }
270        offset = o + bytes;
271        return result;
272    }
273
274    public int readSizedSmallUint(int bytes) {
275        int o = offset;
276        byte[] buf = dexBuf.buf;
277
278        int result = 0;
279        switch (bytes) {
280            case 4:
281                int b = buf[o+3];
282                if (b < 0) {
283                    throw new ExceptionWithContext(
284                            "Encountered valid sized uint that is out of range at offset 0x%x", offset);
285                }
286                result = b << 24;
287                // fall-through
288            case 3:
289                result |= (buf[o+2] & 0xff) << 16;
290                // fall-through
291            case 2:
292                result |= (buf[o+1] & 0xff) << 8;
293                // fall-through
294            case 1:
295                result |= (buf[o] & 0xff);
296                break;
297            default:
298                throw new ExceptionWithContext("Invalid size %d for sized uint at offset 0x%x", bytes, offset);
299        }
300        offset = o + bytes;
301        return result;
302    }
303
304    public int readSizedRightExtendedInt(int bytes) {
305        int o = offset;
306        byte[] buf = dexBuf.buf;
307
308        int result;
309        switch (bytes) {
310            case 4:
311                result = (buf[o] & 0xff) |
312                         ((buf[o+1] & 0xff) << 8) |
313                         ((buf[o+2] & 0xff) << 16) |
314                         (buf[o+3] << 24);
315                break;
316            case 3:
317                result = (buf[o] & 0xff) << 8 |
318                         ((buf[o+1] & 0xff) << 16) |
319                         (buf[o+2] << 24);
320                break;
321            case 2:
322                result = (buf[o] & 0xff) << 16 |
323                         (buf[o+1] << 24);
324                break;
325            case 1:
326                result = buf[o] << 24;
327                break;
328            default:
329                throw new ExceptionWithContext(
330                        "Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset);
331        }
332        offset = o + bytes;
333        return result;
334    }
335
336    public long readSizedRightExtendedLong(int bytes) {
337        int o = offset;
338        byte[] buf = dexBuf.buf;
339
340        long result;
341        switch (bytes) {
342            case 8:
343                result = (buf[o] & 0xff) |
344                         ((buf[o+1] & 0xff) << 8) |
345                         ((buf[o+2] & 0xff) << 16) |
346                         ((buf[o+3] & 0xffL) << 24) |
347                         ((buf[o+4] & 0xffL) << 32) |
348                         ((buf[o+5] & 0xffL) << 40) |
349                         ((buf[o+6] & 0xffL) << 48) |
350                         (((long)buf[o+7]) << 56);
351                break;
352            case 7:
353                result = ((buf[o] & 0xff)) << 8 |
354                         ((buf[o+1] & 0xff) << 16) |
355                         ((buf[o+2] & 0xffL) << 24) |
356                         ((buf[o+3] & 0xffL) << 32) |
357                         ((buf[o+4] & 0xffL) << 40) |
358                         ((buf[o+5] & 0xffL) << 48) |
359                         (((long)buf[o+6]) << 56);
360                break;
361            case 6:
362                result = ((buf[o] & 0xff)) << 16 |
363                         ((buf[o+1] & 0xffL) << 24) |
364                         ((buf[o+2] & 0xffL) << 32) |
365                         ((buf[o+3] & 0xffL) << 40) |
366                         ((buf[o+4] & 0xffL) << 48) |
367                         (((long)buf[o+5]) << 56);
368                break;
369            case 5:
370                result = ((buf[o] & 0xffL)) << 24 |
371                         ((buf[o+1] & 0xffL) << 32) |
372                         ((buf[o+2] & 0xffL) << 40) |
373                         ((buf[o+3] & 0xffL) << 48) |
374                         (((long)buf[o+4]) << 56);
375                break;
376            case 4:
377                result = ((buf[o] & 0xffL)) << 32 |
378                         ((buf[o+1] & 0xffL) << 40) |
379                         ((buf[o+2] & 0xffL) << 48) |
380                         (((long)buf[o+3]) << 56);
381                break;
382            case 3:
383                result = ((buf[o] & 0xffL)) << 40 |
384                         ((buf[o+1] & 0xffL) << 48) |
385                         (((long)buf[o+2]) << 56);
386                break;
387            case 2:
388                result = ((buf[o] & 0xffL)) << 48 |
389                         (((long)buf[o+1]) << 56);
390                break;
391            case 1:
392                result = ((long)buf[o]) << 56;
393                break;
394            default:
395                throw new ExceptionWithContext(
396                        "Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset);
397        }
398        offset = o + bytes;
399        return result;
400    }
401
402    public long readSizedLong(int bytes) {
403        int o = offset;
404        byte[] buf = dexBuf.buf;
405
406        long result;
407        switch (bytes) {
408            case 8:
409                result = (buf[o] & 0xff) |
410                         ((buf[o+1] & 0xff) << 8) |
411                         ((buf[o+2] & 0xff) << 16) |
412                         ((buf[o+3] & 0xffL) << 24) |
413                         ((buf[o+4] & 0xffL) << 32) |
414                         ((buf[o+5] & 0xffL) << 40) |
415                         ((buf[o+6] & 0xffL) << 48) |
416                         (((long)buf[o+7]) << 56);
417                break;
418            case 7:
419                result = (buf[o] & 0xff) |
420                         ((buf[o+1] & 0xff) << 8) |
421                         ((buf[o+2] & 0xff) << 16) |
422                         ((buf[o+3] & 0xffL) << 24) |
423                         ((buf[o+4] & 0xffL) << 32) |
424                         ((buf[o+5] & 0xffL) << 40) |
425                         ((long)(buf[o+6]) << 48);
426                break;
427            case 6:
428                result = (buf[o] & 0xff) |
429                         ((buf[o+1] & 0xff) << 8) |
430                         ((buf[o+2] & 0xff) << 16) |
431                         ((buf[o+3] & 0xffL) << 24) |
432                         ((buf[o+4] & 0xffL) << 32) |
433                         ((long)(buf[o+5]) << 40);
434                break;
435            case 5:
436                result = (buf[o] & 0xff) |
437                         ((buf[o+1] & 0xff) << 8) |
438                         ((buf[o+2] & 0xff) << 16) |
439                         ((buf[o+3] & 0xffL) << 24) |
440                         ((long)(buf[o+4]) << 32);
441                break;
442            case 4:
443                result = (buf[o] & 0xff) |
444                        ((buf[o+1] & 0xff) << 8) |
445                        ((buf[o+2] & 0xff) << 16) |
446                        (((long)buf[o+3]) << 24);
447                break;
448            case 3:
449                result = (buf[o] & 0xff) |
450                        ((buf[o+1] & 0xff) << 8) |
451                        (buf[o+2] << 16);
452                break;
453            case 2:
454                result = (buf[o] & 0xff) |
455                        (buf[o+1] << 8);
456                break;
457            case 1:
458                result = buf[o];
459                break;
460            default:
461                throw new ExceptionWithContext("Invalid size %d for sized long at offset 0x%x", bytes, offset);
462        }
463
464        o += bytes;
465        return result;
466    }
467}