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