Home | History | Annotate | Download | only in dexbacked
      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 
     32 package org.jf.dexlib2.dexbacked;
     33 
     34 import org.jf.util.ExceptionWithContext;
     35 import org.jf.util.Utf8Utils;
     36 
     37 import javax.annotation.Nonnull;
     38 
     39 public 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