1 /* 2 * Copyright (C) 2016 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 package com.google.android.exoplayer2.util; 17 18 import com.google.android.exoplayer2.C; 19 import java.nio.charset.Charset; 20 21 /** 22 * Wraps a byte array, providing methods that allow it to be read as a bitstream. 23 */ 24 public final class ParsableBitArray { 25 26 public byte[] data; 27 28 // The offset within the data, stored as the current byte offset, and the bit offset within that 29 // byte (from 0 to 7). 30 private int byteOffset; 31 private int bitOffset; 32 private int byteLimit; 33 34 /** Creates a new instance that initially has no backing data. */ ParsableBitArray()35 public ParsableBitArray() { 36 data = Util.EMPTY_BYTE_ARRAY; 37 } 38 39 /** 40 * Creates a new instance that wraps an existing array. 41 * 42 * @param data The data to wrap. 43 */ ParsableBitArray(byte[] data)44 public ParsableBitArray(byte[] data) { 45 this(data, data.length); 46 } 47 48 /** 49 * Creates a new instance that wraps an existing array. 50 * 51 * @param data The data to wrap. 52 * @param limit The limit in bytes. 53 */ ParsableBitArray(byte[] data, int limit)54 public ParsableBitArray(byte[] data, int limit) { 55 this.data = data; 56 byteLimit = limit; 57 } 58 59 /** 60 * Updates the instance to wrap {@code data}, and resets the position to zero. 61 * 62 * @param data The array to wrap. 63 */ reset(byte[] data)64 public void reset(byte[] data) { 65 reset(data, data.length); 66 } 67 68 /** 69 * Sets this instance's data, position and limit to match the provided {@code parsableByteArray}. 70 * Any modifications to the underlying data array will be visible in both instances 71 * 72 * @param parsableByteArray The {@link ParsableByteArray}. 73 */ reset(ParsableByteArray parsableByteArray)74 public void reset(ParsableByteArray parsableByteArray) { 75 reset(parsableByteArray.data, parsableByteArray.limit()); 76 setPosition(parsableByteArray.getPosition() * 8); 77 } 78 79 /** 80 * Updates the instance to wrap {@code data}, and resets the position to zero. 81 * 82 * @param data The array to wrap. 83 * @param limit The limit in bytes. 84 */ reset(byte[] data, int limit)85 public void reset(byte[] data, int limit) { 86 this.data = data; 87 byteOffset = 0; 88 bitOffset = 0; 89 byteLimit = limit; 90 } 91 92 /** 93 * Returns the number of bits yet to be read. 94 */ bitsLeft()95 public int bitsLeft() { 96 return (byteLimit - byteOffset) * 8 - bitOffset; 97 } 98 99 /** 100 * Returns the current bit offset. 101 */ getPosition()102 public int getPosition() { 103 return byteOffset * 8 + bitOffset; 104 } 105 106 /** 107 * Returns the current byte offset. Must only be called when the position is byte aligned. 108 * 109 * @throws IllegalStateException If the position isn't byte aligned. 110 */ getBytePosition()111 public int getBytePosition() { 112 Assertions.checkState(bitOffset == 0); 113 return byteOffset; 114 } 115 116 /** 117 * Sets the current bit offset. 118 * 119 * @param position The position to set. 120 */ setPosition(int position)121 public void setPosition(int position) { 122 byteOffset = position / 8; 123 bitOffset = position - (byteOffset * 8); 124 assertValidOffset(); 125 } 126 127 /** 128 * Skips a single bit. 129 */ skipBit()130 public void skipBit() { 131 if (++bitOffset == 8) { 132 bitOffset = 0; 133 byteOffset++; 134 } 135 assertValidOffset(); 136 } 137 138 /** 139 * Skips bits and moves current reading position forward. 140 * 141 * @param numBits The number of bits to skip. 142 */ skipBits(int numBits)143 public void skipBits(int numBits) { 144 int numBytes = numBits / 8; 145 byteOffset += numBytes; 146 bitOffset += numBits - (numBytes * 8); 147 if (bitOffset > 7) { 148 byteOffset++; 149 bitOffset -= 8; 150 } 151 assertValidOffset(); 152 } 153 154 /** 155 * Reads a single bit. 156 * 157 * @return Whether the bit is set. 158 */ readBit()159 public boolean readBit() { 160 boolean returnValue = (data[byteOffset] & (0x80 >> bitOffset)) != 0; 161 skipBit(); 162 return returnValue; 163 } 164 165 /** 166 * Reads up to 32 bits. 167 * 168 * @param numBits The number of bits to read. 169 * @return An integer whose bottom {@code numBits} bits hold the read data. 170 */ readBits(int numBits)171 public int readBits(int numBits) { 172 if (numBits == 0) { 173 return 0; 174 } 175 int returnValue = 0; 176 bitOffset += numBits; 177 while (bitOffset > 8) { 178 bitOffset -= 8; 179 returnValue |= (data[byteOffset++] & 0xFF) << bitOffset; 180 } 181 returnValue |= (data[byteOffset] & 0xFF) >> (8 - bitOffset); 182 returnValue &= 0xFFFFFFFF >>> (32 - numBits); 183 if (bitOffset == 8) { 184 bitOffset = 0; 185 byteOffset++; 186 } 187 assertValidOffset(); 188 return returnValue; 189 } 190 191 /** 192 * Reads up to 64 bits. 193 * 194 * @param numBits The number of bits to read. 195 * @return A long whose bottom {@code numBits} bits hold the read data. 196 */ readBitsToLong(int numBits)197 public long readBitsToLong(int numBits) { 198 if (numBits <= 32) { 199 return Util.toUnsignedLong(readBits(numBits)); 200 } 201 return Util.toLong(readBits(numBits - 32), readBits(32)); 202 } 203 204 /** 205 * Reads {@code numBits} bits into {@code buffer}. 206 * 207 * @param buffer The array into which the read data should be written. The trailing {@code numBits 208 * % 8} bits are written into the most significant bits of the last modified {@code buffer} 209 * byte. The remaining ones are unmodified. 210 * @param offset The offset in {@code buffer} at which the read data should be written. 211 * @param numBits The number of bits to read. 212 */ readBits(byte[] buffer, int offset, int numBits)213 public void readBits(byte[] buffer, int offset, int numBits) { 214 // Whole bytes. 215 int to = offset + (numBits >> 3) /* numBits / 8 */; 216 for (int i = offset; i < to; i++) { 217 buffer[i] = (byte) (data[byteOffset++] << bitOffset); 218 buffer[i] = (byte) (buffer[i] | ((data[byteOffset] & 0xFF) >> (8 - bitOffset))); 219 } 220 // Trailing bits. 221 int bitsLeft = numBits & 7 /* numBits % 8 */; 222 if (bitsLeft == 0) { 223 return; 224 } 225 // Set bits that are going to be overwritten to 0. 226 buffer[to] = (byte) (buffer[to] & (0xFF >> bitsLeft)); 227 if (bitOffset + bitsLeft > 8) { 228 // We read the rest of data[byteOffset] and increase byteOffset. 229 buffer[to] = (byte) (buffer[to] | ((data[byteOffset++] & 0xFF) << bitOffset)); 230 bitOffset -= 8; 231 } 232 bitOffset += bitsLeft; 233 int lastDataByteTrailingBits = (data[byteOffset] & 0xFF) >> (8 - bitOffset); 234 buffer[to] |= (byte) (lastDataByteTrailingBits << (8 - bitsLeft)); 235 if (bitOffset == 8) { 236 bitOffset = 0; 237 byteOffset++; 238 } 239 assertValidOffset(); 240 } 241 242 /** 243 * Aligns the position to the next byte boundary. Does nothing if the position is already aligned. 244 */ byteAlign()245 public void byteAlign() { 246 if (bitOffset == 0) { 247 return; 248 } 249 bitOffset = 0; 250 byteOffset++; 251 assertValidOffset(); 252 } 253 254 /** 255 * Reads the next {@code length} bytes into {@code buffer}. Must only be called when the position 256 * is byte aligned. 257 * 258 * @see System#arraycopy(Object, int, Object, int, int) 259 * @param buffer The array into which the read data should be written. 260 * @param offset The offset in {@code buffer} at which the read data should be written. 261 * @param length The number of bytes to read. 262 * @throws IllegalStateException If the position isn't byte aligned. 263 */ readBytes(byte[] buffer, int offset, int length)264 public void readBytes(byte[] buffer, int offset, int length) { 265 Assertions.checkState(bitOffset == 0); 266 System.arraycopy(data, byteOffset, buffer, offset, length); 267 byteOffset += length; 268 assertValidOffset(); 269 } 270 271 /** 272 * Skips the next {@code length} bytes. Must only be called when the position is byte aligned. 273 * 274 * @param length The number of bytes to read. 275 * @throws IllegalStateException If the position isn't byte aligned. 276 */ skipBytes(int length)277 public void skipBytes(int length) { 278 Assertions.checkState(bitOffset == 0); 279 byteOffset += length; 280 assertValidOffset(); 281 } 282 283 /** 284 * Reads the next {@code length} bytes as a UTF-8 string. Must only be called when the position is 285 * byte aligned. 286 * 287 * @param length The number of bytes to read. 288 * @return The string encoded by the bytes in UTF-8. 289 */ readBytesAsString(int length)290 public String readBytesAsString(int length) { 291 return readBytesAsString(length, Charset.forName(C.UTF8_NAME)); 292 } 293 294 /** 295 * Reads the next {@code length} bytes as a string encoded in {@link Charset}. Must only be called 296 * when the position is byte aligned. 297 * 298 * @param length The number of bytes to read. 299 * @param charset The character set of the encoded characters. 300 * @return The string encoded by the bytes in the specified character set. 301 */ readBytesAsString(int length, Charset charset)302 public String readBytesAsString(int length, Charset charset) { 303 byte[] bytes = new byte[length]; 304 readBytes(bytes, 0, length); 305 return new String(bytes, charset); 306 } 307 308 /** 309 * Overwrites {@code numBits} from this array using the {@code numBits} least significant bits 310 * from {@code value}. Bits are written in order from most significant to least significant. The 311 * read position is advanced by {@code numBits}. 312 * 313 * @param value The integer whose {@code numBits} least significant bits are written into {@link 314 * #data}. 315 * @param numBits The number of bits to write. 316 */ putInt(int value, int numBits)317 public void putInt(int value, int numBits) { 318 int remainingBitsToRead = numBits; 319 if (numBits < 32) { 320 value &= (1 << numBits) - 1; 321 } 322 int firstByteReadSize = Math.min(8 - bitOffset, numBits); 323 int firstByteRightPaddingSize = 8 - bitOffset - firstByteReadSize; 324 int firstByteBitmask = (0xFF00 >> bitOffset) | ((1 << firstByteRightPaddingSize) - 1); 325 data[byteOffset] = (byte) (data[byteOffset] & firstByteBitmask); 326 int firstByteInputBits = value >>> (numBits - firstByteReadSize); 327 data[byteOffset] = 328 (byte) (data[byteOffset] | (firstByteInputBits << firstByteRightPaddingSize)); 329 remainingBitsToRead -= firstByteReadSize; 330 int currentByteIndex = byteOffset + 1; 331 while (remainingBitsToRead > 8) { 332 data[currentByteIndex++] = (byte) (value >>> (remainingBitsToRead - 8)); 333 remainingBitsToRead -= 8; 334 } 335 int lastByteRightPaddingSize = 8 - remainingBitsToRead; 336 data[currentByteIndex] = 337 (byte) (data[currentByteIndex] & ((1 << lastByteRightPaddingSize) - 1)); 338 int lastByteInput = value & ((1 << remainingBitsToRead) - 1); 339 data[currentByteIndex] = 340 (byte) (data[currentByteIndex] | (lastByteInput << lastByteRightPaddingSize)); 341 skipBits(numBits); 342 assertValidOffset(); 343 } 344 assertValidOffset()345 private void assertValidOffset() { 346 // It is fine for position to be at the end of the array, but no further. 347 Assertions.checkState(byteOffset >= 0 348 && (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0))); 349 } 350 351 } 352