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 25package 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 */ 33public final class ByteArray { 34 /** non-null; underlying array */ 35 private final byte[] bytes; 36 37 /** <code>>= 0</code>; start index of the slice (inclusive) */ 38 private final int start; 39 40 /** <code>>= 0, <= 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>>= 0</code>; start index of the slice (inclusive) 49 * @param end <code>>= start, <= 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 >= 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>>= 0</code>; start index of the slice (inclusive) 96 * @param end <code>>= start, <= 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>>= 0, < 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>>= 0, < (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>>= 0, < (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>>= 0, < (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>>= 0, < 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>>= 0, < (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}