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