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