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 androidx.annotation.Nullable; 19 import com.google.android.exoplayer2.C; 20 import java.nio.ByteBuffer; 21 import java.nio.charset.Charset; 22 23 /** 24 * Wraps a byte array, providing a set of methods for parsing data from it. Numerical values are 25 * parsed with the assumption that their constituent bytes are in big endian order. 26 */ 27 public final class ParsableByteArray { 28 29 public byte[] data; 30 31 private int position; 32 private int limit; 33 34 /** Creates a new instance that initially has no backing data. */ ParsableByteArray()35 public ParsableByteArray() { 36 data = Util.EMPTY_BYTE_ARRAY; 37 } 38 39 /** 40 * Creates a new instance with {@code limit} bytes and sets the limit. 41 * 42 * @param limit The limit to set. 43 */ ParsableByteArray(int limit)44 public ParsableByteArray(int limit) { 45 this.data = new byte[limit]; 46 this.limit = limit; 47 } 48 49 /** 50 * Creates a new instance wrapping {@code data}, and sets the limit to {@code data.length}. 51 * 52 * @param data The array to wrap. 53 */ ParsableByteArray(byte[] data)54 public ParsableByteArray(byte[] data) { 55 this.data = data; 56 limit = data.length; 57 } 58 59 /** 60 * Creates a new instance that wraps an existing array. 61 * 62 * @param data The data to wrap. 63 * @param limit The limit to set. 64 */ ParsableByteArray(byte[] data, int limit)65 public ParsableByteArray(byte[] data, int limit) { 66 this.data = data; 67 this.limit = limit; 68 } 69 70 /** Sets the position and limit to zero. */ reset()71 public void reset() { 72 position = 0; 73 limit = 0; 74 } 75 76 /** 77 * Resets the position to zero and the limit to the specified value. If the limit exceeds the 78 * capacity, {@code data} is replaced with a new array of sufficient size. 79 * 80 * @param limit The limit to set. 81 */ reset(int limit)82 public void reset(int limit) { 83 reset(capacity() < limit ? new byte[limit] : data, limit); 84 } 85 86 /** 87 * Updates the instance to wrap {@code data}, and resets the position to zero and the limit to 88 * {@code data.length}. 89 * 90 * @param data The array to wrap. 91 */ 92 public void reset(byte[] data) { 93 reset(data, data.length); 94 } 95 96 /** 97 * Updates the instance to wrap {@code data}, and resets the position to zero. 98 * 99 * @param data The array to wrap. 100 * @param limit The limit to set. 101 */ 102 public void reset(byte[] data, int limit) { 103 this.data = data; 104 this.limit = limit; 105 position = 0; 106 } 107 108 /** 109 * Returns the number of bytes yet to be read. 110 */ 111 public int bytesLeft() { 112 return limit - position; 113 } 114 115 /** 116 * Returns the limit. 117 */ 118 public int limit() { 119 return limit; 120 } 121 122 /** 123 * Sets the limit. 124 * 125 * @param limit The limit to set. 126 */ 127 public void setLimit(int limit) { 128 Assertions.checkArgument(limit >= 0 && limit <= data.length); 129 this.limit = limit; 130 } 131 132 /** 133 * Returns the current offset in the array, in bytes. 134 */ getPosition()135 public int getPosition() { 136 return position; 137 } 138 139 /** 140 * Returns the capacity of the array, which may be larger than the limit. 141 */ capacity()142 public int capacity() { 143 return data.length; 144 } 145 146 /** 147 * Sets the reading offset in the array. 148 * 149 * @param position Byte offset in the array from which to read. 150 * @throws IllegalArgumentException Thrown if the new position is neither in nor at the end of the 151 * array. 152 */ setPosition(int position)153 public void setPosition(int position) { 154 // It is fine for position to be at the end of the array. 155 Assertions.checkArgument(position >= 0 && position <= limit); 156 this.position = position; 157 } 158 159 /** 160 * Moves the reading offset by {@code bytes}. 161 * 162 * @param bytes The number of bytes to skip. 163 * @throws IllegalArgumentException Thrown if the new position is neither in nor at the end of the 164 * array. 165 */ skipBytes(int bytes)166 public void skipBytes(int bytes) { 167 setPosition(position + bytes); 168 } 169 170 /** 171 * Reads the next {@code length} bytes into {@code bitArray}, and resets the position of 172 * {@code bitArray} to zero. 173 * 174 * @param bitArray The {@link ParsableBitArray} into which the bytes should be read. 175 * @param length The number of bytes to write. 176 */ readBytes(ParsableBitArray bitArray, int length)177 public void readBytes(ParsableBitArray bitArray, int length) { 178 readBytes(bitArray.data, 0, length); 179 bitArray.setPosition(0); 180 } 181 182 /** 183 * Reads the next {@code length} bytes into {@code buffer} at {@code offset}. 184 * 185 * @see System#arraycopy(Object, int, Object, int, int) 186 * @param buffer The array into which the read data should be written. 187 * @param offset The offset in {@code buffer} at which the read data should be written. 188 * @param length The number of bytes to read. 189 */ readBytes(byte[] buffer, int offset, int length)190 public void readBytes(byte[] buffer, int offset, int length) { 191 System.arraycopy(data, position, buffer, offset, length); 192 position += length; 193 } 194 195 /** 196 * Reads the next {@code length} bytes into {@code buffer}. 197 * 198 * @see ByteBuffer#put(byte[], int, int) 199 * @param buffer The {@link ByteBuffer} into which the read data should be written. 200 * @param length The number of bytes to read. 201 */ readBytes(ByteBuffer buffer, int length)202 public void readBytes(ByteBuffer buffer, int length) { 203 buffer.put(data, position, length); 204 position += length; 205 } 206 207 /** 208 * Peeks at the next byte as an unsigned value. 209 */ peekUnsignedByte()210 public int peekUnsignedByte() { 211 return (data[position] & 0xFF); 212 } 213 214 /** 215 * Peeks at the next char. 216 */ peekChar()217 public char peekChar() { 218 return (char) ((data[position] & 0xFF) << 8 219 | (data[position + 1] & 0xFF)); 220 } 221 222 /** 223 * Reads the next byte as an unsigned value. 224 */ readUnsignedByte()225 public int readUnsignedByte() { 226 return (data[position++] & 0xFF); 227 } 228 229 /** 230 * Reads the next two bytes as an unsigned value. 231 */ readUnsignedShort()232 public int readUnsignedShort() { 233 return (data[position++] & 0xFF) << 8 234 | (data[position++] & 0xFF); 235 } 236 237 /** 238 * Reads the next two bytes as an unsigned value. 239 */ readLittleEndianUnsignedShort()240 public int readLittleEndianUnsignedShort() { 241 return (data[position++] & 0xFF) | (data[position++] & 0xFF) << 8; 242 } 243 244 /** 245 * Reads the next two bytes as a signed value. 246 */ readShort()247 public short readShort() { 248 return (short) ((data[position++] & 0xFF) << 8 249 | (data[position++] & 0xFF)); 250 } 251 252 /** 253 * Reads the next two bytes as a signed value. 254 */ readLittleEndianShort()255 public short readLittleEndianShort() { 256 return (short) ((data[position++] & 0xFF) | (data[position++] & 0xFF) << 8); 257 } 258 259 /** 260 * Reads the next three bytes as an unsigned value. 261 */ readUnsignedInt24()262 public int readUnsignedInt24() { 263 return (data[position++] & 0xFF) << 16 264 | (data[position++] & 0xFF) << 8 265 | (data[position++] & 0xFF); 266 } 267 268 /** 269 * Reads the next three bytes as a signed value. 270 */ readInt24()271 public int readInt24() { 272 return ((data[position++] & 0xFF) << 24) >> 8 273 | (data[position++] & 0xFF) << 8 274 | (data[position++] & 0xFF); 275 } 276 277 /** 278 * Reads the next three bytes as a signed value in little endian order. 279 */ readLittleEndianInt24()280 public int readLittleEndianInt24() { 281 return (data[position++] & 0xFF) 282 | (data[position++] & 0xFF) << 8 283 | (data[position++] & 0xFF) << 16; 284 } 285 286 /** 287 * Reads the next three bytes as an unsigned value in little endian order. 288 */ readLittleEndianUnsignedInt24()289 public int readLittleEndianUnsignedInt24() { 290 return (data[position++] & 0xFF) 291 | (data[position++] & 0xFF) << 8 292 | (data[position++] & 0xFF) << 16; 293 } 294 295 /** 296 * Reads the next four bytes as an unsigned value. 297 */ readUnsignedInt()298 public long readUnsignedInt() { 299 return (data[position++] & 0xFFL) << 24 300 | (data[position++] & 0xFFL) << 16 301 | (data[position++] & 0xFFL) << 8 302 | (data[position++] & 0xFFL); 303 } 304 305 /** 306 * Reads the next four bytes as an unsigned value in little endian order. 307 */ readLittleEndianUnsignedInt()308 public long readLittleEndianUnsignedInt() { 309 return (data[position++] & 0xFFL) 310 | (data[position++] & 0xFFL) << 8 311 | (data[position++] & 0xFFL) << 16 312 | (data[position++] & 0xFFL) << 24; 313 } 314 315 /** 316 * Reads the next four bytes as a signed value 317 */ readInt()318 public int readInt() { 319 return (data[position++] & 0xFF) << 24 320 | (data[position++] & 0xFF) << 16 321 | (data[position++] & 0xFF) << 8 322 | (data[position++] & 0xFF); 323 } 324 325 /** 326 * Reads the next four bytes as a signed value in little endian order. 327 */ readLittleEndianInt()328 public int readLittleEndianInt() { 329 return (data[position++] & 0xFF) 330 | (data[position++] & 0xFF) << 8 331 | (data[position++] & 0xFF) << 16 332 | (data[position++] & 0xFF) << 24; 333 } 334 335 /** 336 * Reads the next eight bytes as a signed value. 337 */ readLong()338 public long readLong() { 339 return (data[position++] & 0xFFL) << 56 340 | (data[position++] & 0xFFL) << 48 341 | (data[position++] & 0xFFL) << 40 342 | (data[position++] & 0xFFL) << 32 343 | (data[position++] & 0xFFL) << 24 344 | (data[position++] & 0xFFL) << 16 345 | (data[position++] & 0xFFL) << 8 346 | (data[position++] & 0xFFL); 347 } 348 349 /** 350 * Reads the next eight bytes as a signed value in little endian order. 351 */ readLittleEndianLong()352 public long readLittleEndianLong() { 353 return (data[position++] & 0xFFL) 354 | (data[position++] & 0xFFL) << 8 355 | (data[position++] & 0xFFL) << 16 356 | (data[position++] & 0xFFL) << 24 357 | (data[position++] & 0xFFL) << 32 358 | (data[position++] & 0xFFL) << 40 359 | (data[position++] & 0xFFL) << 48 360 | (data[position++] & 0xFFL) << 56; 361 } 362 363 /** 364 * Reads the next four bytes, returning the integer portion of the fixed point 16.16 integer. 365 */ readUnsignedFixedPoint1616()366 public int readUnsignedFixedPoint1616() { 367 int result = (data[position++] & 0xFF) << 8 368 | (data[position++] & 0xFF); 369 position += 2; // Skip the non-integer portion. 370 return result; 371 } 372 373 /** 374 * Reads a Synchsafe integer. 375 * <p> 376 * Synchsafe integers keep the highest bit of every byte zeroed. A 32 bit synchsafe integer can 377 * store 28 bits of information. 378 * 379 * @return The parsed value. 380 */ readSynchSafeInt()381 public int readSynchSafeInt() { 382 int b1 = readUnsignedByte(); 383 int b2 = readUnsignedByte(); 384 int b3 = readUnsignedByte(); 385 int b4 = readUnsignedByte(); 386 return (b1 << 21) | (b2 << 14) | (b3 << 7) | b4; 387 } 388 389 /** 390 * Reads the next four bytes as an unsigned integer into an integer, if the top bit is a zero. 391 * 392 * @throws IllegalStateException Thrown if the top bit of the input data is set. 393 */ readUnsignedIntToInt()394 public int readUnsignedIntToInt() { 395 int result = readInt(); 396 if (result < 0) { 397 throw new IllegalStateException("Top bit not zero: " + result); 398 } 399 return result; 400 } 401 402 /** 403 * Reads the next four bytes as a little endian unsigned integer into an integer, if the top bit 404 * is a zero. 405 * 406 * @throws IllegalStateException Thrown if the top bit of the input data is set. 407 */ readLittleEndianUnsignedIntToInt()408 public int readLittleEndianUnsignedIntToInt() { 409 int result = readLittleEndianInt(); 410 if (result < 0) { 411 throw new IllegalStateException("Top bit not zero: " + result); 412 } 413 return result; 414 } 415 416 /** 417 * Reads the next eight bytes as an unsigned long into a long, if the top bit is a zero. 418 * 419 * @throws IllegalStateException Thrown if the top bit of the input data is set. 420 */ readUnsignedLongToLong()421 public long readUnsignedLongToLong() { 422 long result = readLong(); 423 if (result < 0) { 424 throw new IllegalStateException("Top bit not zero: " + result); 425 } 426 return result; 427 } 428 429 /** 430 * Reads the next four bytes as a 32-bit floating point value. 431 */ readFloat()432 public float readFloat() { 433 return Float.intBitsToFloat(readInt()); 434 } 435 436 /** 437 * Reads the next eight bytes as a 64-bit floating point value. 438 */ readDouble()439 public double readDouble() { 440 return Double.longBitsToDouble(readLong()); 441 } 442 443 /** 444 * Reads the next {@code length} bytes as UTF-8 characters. 445 * 446 * @param length The number of bytes to read. 447 * @return The string encoded by the bytes. 448 */ readString(int length)449 public String readString(int length) { 450 return readString(length, Charset.forName(C.UTF8_NAME)); 451 } 452 453 /** 454 * Reads the next {@code length} bytes as characters in the specified {@link Charset}. 455 * 456 * @param length The number of bytes to read. 457 * @param charset The character set of the encoded characters. 458 * @return The string encoded by the bytes in the specified character set. 459 */ readString(int length, Charset charset)460 public String readString(int length, Charset charset) { 461 String result = new String(data, position, length, charset); 462 position += length; 463 return result; 464 } 465 466 /** 467 * Reads the next {@code length} bytes as UTF-8 characters. A terminating NUL byte is discarded, 468 * if present. 469 * 470 * @param length The number of bytes to read. 471 * @return The string, not including any terminating NUL byte. 472 */ readNullTerminatedString(int length)473 public String readNullTerminatedString(int length) { 474 if (length == 0) { 475 return ""; 476 } 477 int stringLength = length; 478 int lastIndex = position + length - 1; 479 if (lastIndex < limit && data[lastIndex] == 0) { 480 stringLength--; 481 } 482 String result = Util.fromUtf8Bytes(data, position, stringLength); 483 position += length; 484 return result; 485 } 486 487 /** 488 * Reads up to the next NUL byte (or the limit) as UTF-8 characters. 489 * 490 * @return The string not including any terminating NUL byte, or null if the end of the data has 491 * already been reached. 492 */ 493 @Nullable readNullTerminatedString()494 public String readNullTerminatedString() { 495 if (bytesLeft() == 0) { 496 return null; 497 } 498 int stringLimit = position; 499 while (stringLimit < limit && data[stringLimit] != 0) { 500 stringLimit++; 501 } 502 String string = Util.fromUtf8Bytes(data, position, stringLimit - position); 503 position = stringLimit; 504 if (position < limit) { 505 position++; 506 } 507 return string; 508 } 509 510 /** 511 * Reads a line of text. 512 * 513 * <p>A line is considered to be terminated by any one of a carriage return ('\r'), a line feed 514 * ('\n'), or a carriage return followed immediately by a line feed ('\r\n'). The system's default 515 * charset (UTF-8) is used. This method discards leading UTF-8 byte order marks, if present. 516 * 517 * @return The line not including any line-termination characters, or null if the end of the data 518 * has already been reached. 519 */ 520 @Nullable readLine()521 public String readLine() { 522 if (bytesLeft() == 0) { 523 return null; 524 } 525 int lineLimit = position; 526 while (lineLimit < limit && !Util.isLinebreak(data[lineLimit])) { 527 lineLimit++; 528 } 529 if (lineLimit - position >= 3 && data[position] == (byte) 0xEF 530 && data[position + 1] == (byte) 0xBB && data[position + 2] == (byte) 0xBF) { 531 // There's a UTF-8 byte order mark at the start of the line. Discard it. 532 position += 3; 533 } 534 String line = Util.fromUtf8Bytes(data, position, lineLimit - position); 535 position = lineLimit; 536 if (position == limit) { 537 return line; 538 } 539 if (data[position] == '\r') { 540 position++; 541 if (position == limit) { 542 return line; 543 } 544 } 545 if (data[position] == '\n') { 546 position++; 547 } 548 return line; 549 } 550 551 /** 552 * Reads a long value encoded by UTF-8 encoding 553 * 554 * @throws NumberFormatException if there is a problem with decoding 555 * @return Decoded long value 556 */ readUtf8EncodedLong()557 public long readUtf8EncodedLong() { 558 int length = 0; 559 long value = data[position]; 560 // find the high most 0 bit 561 for (int j = 7; j >= 0; j--) { 562 if ((value & (1 << j)) == 0) { 563 if (j < 6) { 564 value &= (1 << j) - 1; 565 length = 7 - j; 566 } else if (j == 7) { 567 length = 1; 568 } 569 break; 570 } 571 } 572 if (length == 0) { 573 throw new NumberFormatException("Invalid UTF-8 sequence first byte: " + value); 574 } 575 for (int i = 1; i < length; i++) { 576 int x = data[position + i]; 577 if ((x & 0xC0) != 0x80) { // if the high most 0 bit not 7th 578 throw new NumberFormatException("Invalid UTF-8 sequence continuation byte: " + value); 579 } 580 value = (value << 6) | (x & 0x3F); 581 } 582 position += length; 583 return value; 584 } 585 586 } 587