Home | History | Annotate | Download | only in Util
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * As per the Apache license requirements, this file has been modified
     19  * from its original state.
     20  *
     21  * Such modifications are Copyright (C) 2010 Ben Gruver, and are released
     22  * under the original license
     23  */
     24 
     25 package org.jf.dexlib.Util;
     26 
     27 /**
     28  * Wrapper for a <code>byte[]</code>, which provides read-only access and
     29  * can "reveal" a partial slice of the underlying array.
     30  *
     31  * <b>Note:</b> Multibyte accessors all use big-endian order.
     32  */
     33 public final class ByteArray {
     34     /** non-null; underlying array */
     35     private final byte[] bytes;
     36 
     37     /** <code>&gt;= 0</code>; start index of the slice (inclusive) */
     38     private final int start;
     39 
     40     /** <code>&gt;= 0, &lt;= bytes.length</code>; size computed as
     41      * <code>end - start</code> (in the constructor) */
     42     private final int size;
     43 
     44     /**
     45      * Constructs an instance.
     46      *
     47      * @param bytes non-null; the underlying array
     48      * @param start <code>&gt;= 0</code>; start index of the slice (inclusive)
     49      * @param end <code>&gt;= start, &lt;= bytes.length</code>; end index of
     50      * the slice (exclusive)
     51      */
     52     public ByteArray(byte[] bytes, int start, int end) {
     53         if (bytes == null) {
     54             throw new NullPointerException("bytes == null");
     55         }
     56 
     57         if (start < 0) {
     58             throw new IllegalArgumentException("start < 0");
     59         }
     60 
     61         if (end < start) {
     62             throw new IllegalArgumentException("end < start");
     63         }
     64 
     65         if (end > bytes.length) {
     66             throw new IllegalArgumentException("end > bytes.length");
     67         }
     68 
     69         this.bytes = bytes;
     70         this.start = start;
     71         this.size = end - start;
     72     }
     73 
     74     /**
     75      * Constructs an instance from an entire <code>byte[]</code>.
     76      *
     77      * @param bytes non-null; the underlying array
     78      */
     79     public ByteArray(byte[] bytes) {
     80         this(bytes, 0, bytes.length);
     81     }
     82 
     83     /**
     84      * Gets the size of the array, in bytes.
     85      *
     86      * @return &gt;= 0; the size
     87      */
     88     public int size() {
     89         return size;
     90     }
     91 
     92     /**
     93      * Returns a slice (that is, a sub-array) of this instance.
     94      *
     95      * @param start <code>&gt;= 0</code>; start index of the slice (inclusive)
     96      * @param end <code>&gt;= start, &lt;= size()</code>; end index of
     97      * the slice (exclusive)
     98      * @return non-null; the slice
     99      */
    100     public ByteArray slice(int start, int end) {
    101         checkOffsets(start, end);
    102         return new ByteArray(bytes, start + this.start, end + this.start);
    103     }
    104 
    105     /**
    106      * Returns the offset into the given array represented by the given
    107      * offset into this instance.
    108      *
    109      * @param offset offset into this instance
    110      * @param bytes non-null; (alleged) underlying array
    111      * @return corresponding offset into <code>bytes</code>
    112      * @throws IllegalArgumentException thrown if <code>bytes</code> is
    113      * not the underlying array of this instance
    114      */
    115     public int underlyingOffset(int offset, byte[] bytes) {
    116         if (bytes != this.bytes) {
    117             throw new IllegalArgumentException("wrong bytes");
    118         }
    119 
    120         return start + offset;
    121     }
    122 
    123     /**
    124      * Gets the <code>signed byte</code> value at a particular offset.
    125      *
    126      * @param off <code>&gt;= 0, &lt; size(); offset to fetch
    127      * @return <code>signed byte</code> at that offset
    128      */
    129     public int getByte(int off) {
    130         checkOffsets(off, off + 1);
    131         return getByte0(off);
    132     }
    133 
    134     /**
    135      * Gets the <code>signed short</code> value at a particular offset.
    136      *
    137      * @param off <code>&gt;= 0, &lt; (size() - 1); offset to fetch
    138      * @return <code>signed short</code> at that offset
    139      */
    140     public int getShort(int off) {
    141         checkOffsets(off, off + 2);
    142         return (getByte0(off) << 8) | getUnsignedByte0(off + 1);
    143     }
    144 
    145     /**
    146      * Gets the <code>signed int</code> value at a particular offset.
    147      *
    148      * @param off <code>&gt;= 0, &lt; (size() - 3); offset to fetch
    149      * @return <code>signed int</code> at that offset
    150      */
    151     public int getInt(int off) {
    152         checkOffsets(off, off + 4);
    153         return (getByte0(off) << 24) |
    154             (getUnsignedByte0(off + 1) << 16) |
    155             (getUnsignedByte0(off + 2) << 8) |
    156             getUnsignedByte0(off + 3);
    157     }
    158 
    159     /**
    160      * Gets the <code>signed long</code> value at a particular offset.
    161      *
    162      * @param off <code>&gt;= 0, &lt; (size() - 7); offset to fetch
    163      * @return <code>signed int</code> at that offset
    164      */
    165     public long getLong(int off) {
    166         checkOffsets(off, off + 8);
    167         int part1 = (getByte0(off) << 24) |
    168             (getUnsignedByte0(off + 1) << 16) |
    169             (getUnsignedByte0(off + 2) << 8) |
    170             getUnsignedByte0(off + 3);
    171         int part2 = (getByte0(off + 4) << 24) |
    172             (getUnsignedByte0(off + 5) << 16) |
    173             (getUnsignedByte0(off + 6) << 8) |
    174             getUnsignedByte0(off + 7);
    175 
    176         return (part2 & 0xffffffffL) | ((long) part1) << 32;
    177     }
    178 
    179     /**
    180      * Gets the <code>unsigned byte</code> value at a particular offset.
    181      *
    182      * @param off <code>&gt;= 0, &lt; size(); offset to fetch
    183      * @return <code>unsigned byte</code> at that offset
    184      */
    185     public int getUnsignedByte(int off) {
    186         checkOffsets(off, off + 1);
    187         return getUnsignedByte0(off);
    188     }
    189 
    190     /**
    191      * Gets the <code>unsigned short</code> value at a particular offset.
    192      *
    193      * @param off <code>&gt;= 0, &lt; (size() - 1); offset to fetch
    194      * @return <code>unsigned short</code> at that offset
    195      */
    196     public int getUnsignedShort(int off) {
    197         checkOffsets(off, off + 2);
    198         return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1);
    199     }
    200 
    201     /**
    202      * Copies the contents of this instance into the given raw
    203      * <code>byte[]</code> at the given offset. The given array must be
    204      * large enough.
    205      *
    206      * @param out non-null; array to hold the output
    207      * @param offset non-null; index into <code>out</code> for the first
    208      * byte of output
    209      */
    210     public void getBytes(byte[] out, int offset) {
    211         if ((out.length - offset) < size) {
    212             throw new IndexOutOfBoundsException("(out.length - offset) < " +
    213                                                 "size()");
    214         }
    215 
    216         System.arraycopy(bytes, start, out, offset, size);
    217     }
    218 
    219     /**
    220      * Checks a range of offsets for validity, throwing if invalid.
    221      *
    222      * @param s start offset (inclusive)
    223      * @param e end offset (exclusive)
    224      */
    225     private void checkOffsets(int s, int e) {
    226         if ((s < 0) || (e < s) || (e > size)) {
    227             throw new IllegalArgumentException("bad range: " + s + ".." + e +
    228                                                "; actual size " + size);
    229         }
    230     }
    231 
    232     /**
    233      * Gets the <code>signed byte</code> value at the given offset,
    234      * without doing any argument checking.
    235      *
    236      * @param off offset to fetch
    237      * @return byte at that offset
    238      */
    239     private int getByte0(int off) {
    240         return bytes[start + off];
    241     }
    242 
    243     /**
    244      * Gets the <code>unsigned byte</code> value at the given offset,
    245      * without doing any argument checking.
    246      *
    247      * @param off offset to fetch
    248      * @return byte at that offset
    249      */
    250     private int getUnsignedByte0(int off) {
    251         return bytes[start + off] & 0xff;
    252     }
    253 }