java.lang.Object
↳androidx.media3.common.util.ParsableByteArray
Gradle dependencies
compile group: 'androidx.media3', name: 'media3-common', version: '1.0.0-alpha03'
- groupId: androidx.media3
- artifactId: media3-common
- version: 1.0.0-alpha03
Artifact androidx.media3:media3-common:1.0.0-alpha03 it located at Google repository (https://maven.google.com/)
Overview
Wraps a byte array, providing a set of methods for parsing data from it. Numerical values are
parsed with the assumption that their constituent bytes are in big endian order.
Summary
Constructors |
---|
public | ParsableByteArray()
Creates a new instance that initially has no backing data. |
public | ParsableByteArray(byte[] data[])
Creates a new instance wrapping data, and sets the limit to data.length. |
public | ParsableByteArray(byte[] data[], int limit)
Creates a new instance that wraps an existing array. |
public | ParsableByteArray(int limit)
Creates a new instance with limit bytes and sets the limit. |
Methods |
---|
public int | bytesLeft()
Returns the number of bytes yet to be read. |
public int | capacity()
Returns the capacity of the array, which may be larger than the limit. |
public void | ensureCapacity(int requiredCapacity)
Ensures the backing array is at least requiredCapacity long. |
public byte[] | getData()
Returns the underlying array. |
public int | getPosition()
Returns the current offset in the array, in bytes. |
public int | limit()
Returns the limit. |
public char | peekChar()
Peeks at the next char. |
public int | peekUnsignedByte()
Peeks at the next byte as an unsigned value. |
public void | readBytes(byte[] buffer[], int offset, int length)
Reads the next length bytes into buffer at offset. |
public void | readBytes(java.nio.ByteBuffer buffer, int length)
Reads the next length bytes into buffer. |
public void | readBytes(ParsableBitArray bitArray, int length)
Reads the next length bytes into bitArray, and resets the position of bitArray to zero. |
public java.lang.String | readDelimiterTerminatedString(char delimiter)
Reads up to the next delimiter byte (or the limit) as UTF-8 characters. |
public double | readDouble()
Reads the next eight bytes as a 64-bit floating point value. |
public float | readFloat()
Reads the next four bytes as a 32-bit floating point value. |
public int | readInt()
Reads the next four bytes as a signed value |
public int | readInt24()
Reads the next three bytes as a signed value. |
public java.lang.String | readLine()
Reads a line of text. |
public int | readLittleEndianInt()
Reads the next four bytes as a signed value in little endian order. |
public int | readLittleEndianInt24()
Reads the next three bytes as a signed value in little endian order. |
public long | readLittleEndianLong()
Reads the next eight bytes as a signed value in little endian order. |
public short | readLittleEndianShort()
Reads the next two bytes as a signed value. |
public long | readLittleEndianUnsignedInt()
Reads the next four bytes as an unsigned value in little endian order. |
public int | readLittleEndianUnsignedInt24()
Reads the next three bytes as an unsigned value in little endian order. |
public int | readLittleEndianUnsignedIntToInt()
Reads the next four bytes as a little endian unsigned integer into an integer, if the top bit
is a zero. |
public int | readLittleEndianUnsignedShort()
Reads the next two bytes as an unsigned value. |
public long | readLong()
Reads the next eight bytes as a signed value. |
public java.lang.String | readNullTerminatedString()
Reads up to the next NUL byte (or the limit) as UTF-8 characters. |
public java.lang.String | readNullTerminatedString(int length)
Reads the next length bytes as UTF-8 characters. |
public short | readShort()
Reads the next two bytes as a signed value. |
public java.lang.String | readString(int length)
Reads the next length bytes as UTF-8 characters. |
public java.lang.String | readString(int length, java.nio.charset.Charset charset)
Reads the next length bytes as characters in the specified java.nio.charset.Charset . |
public int | readSynchSafeInt()
Reads a Synchsafe integer. |
public int | readUnsignedByte()
Reads the next byte as an unsigned value. |
public int | readUnsignedFixedPoint1616()
Reads the next four bytes, returning the integer portion of the fixed point 16.16 integer. |
public long | readUnsignedInt()
Reads the next four bytes as an unsigned value. |
public int | readUnsignedInt24()
Reads the next three bytes as an unsigned value. |
public int | readUnsignedIntToInt()
Reads the next four bytes as an unsigned integer into an integer, if the top bit is a zero. |
public long | readUnsignedLongToLong()
Reads the next eight bytes as an unsigned long into a long, if the top bit is a zero. |
public int | readUnsignedShort()
Reads the next two bytes as an unsigned value. |
public long | readUtf8EncodedLong()
Reads a long value encoded by UTF-8 encoding |
public void | reset(byte[] data[])
Updates the instance to wrap data, and resets the position to zero and the limit to
data.length. |
public void | reset(byte[] data[], int limit)
Updates the instance to wrap data, and resets the position to zero. |
public void | reset(int limit)
Resets the position to zero and the limit to the specified value. |
public void | setLimit(int limit)
Sets the limit. |
public void | setPosition(int position)
Sets the reading offset in the array. |
public void | skipBytes(int bytes)
Moves the reading offset by bytes. |
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructors
public
ParsableByteArray()
Creates a new instance that initially has no backing data.
public
ParsableByteArray(int limit)
Creates a new instance with limit bytes and sets the limit.
Parameters:
limit: The limit to set.
public
ParsableByteArray(byte[] data[])
Creates a new instance wrapping data, and sets the limit to data.length.
Parameters:
data: The array to wrap.
public
ParsableByteArray(byte[] data[], int limit)
Creates a new instance that wraps an existing array.
Parameters:
data: The data to wrap.
limit: The limit to set.
Methods
public void
reset(int limit)
Resets the position to zero and the limit to the specified value. This might replace or wipe
the underlying array, potentially invalidating any local references.
Parameters:
limit: The limit to set.
public void
reset(byte[] data[])
Updates the instance to wrap data, and resets the position to zero and the limit to
data.length.
Parameters:
data: The array to wrap.
public void
reset(byte[] data[], int limit)
Updates the instance to wrap data, and resets the position to zero.
Parameters:
data: The array to wrap.
limit: The limit to set.
public void
ensureCapacity(int requiredCapacity)
Ensures the backing array is at least requiredCapacity long.
position, limit, and all data in the underlying
array (including that beyond ParsableByteArray.limit()) are preserved.
This might replace or wipe the underlying array, potentially invalidating
any local references.
Returns the number of bytes yet to be read.
Returns the limit.
public void
setLimit(int limit)
Sets the limit.
Parameters:
limit: The limit to set.
Returns the current offset in the array, in bytes.
public void
setPosition(int position)
Sets the reading offset in the array.
Parameters:
position: Byte offset in the array from which to read.
Returns the underlying array.
Changes to this array are reflected in the results of the read...() methods.
This reference must be assumed to become invalid when ParsableByteArray.reset(int) or ParsableByteArray.ensureCapacity(int) are called (because the array might get reallocated).
Returns the capacity of the array, which may be larger than the limit.
public void
skipBytes(int bytes)
Moves the reading offset by bytes.
Parameters:
bytes: The number of bytes to skip.
Reads the next length bytes into bitArray, and resets the position of bitArray to zero.
Parameters:
bitArray: The ParsableBitArray into which the bytes should be read.
length: The number of bytes to write.
public void
readBytes(byte[] buffer[], int offset, int length)
Reads the next length bytes into buffer at offset.
Parameters:
buffer: The array into which the read data should be written.
offset: The offset in buffer at which the read data should be written.
length: The number of bytes to read.
See also: arraycopy
public void
readBytes(java.nio.ByteBuffer buffer, int length)
Reads the next length bytes into buffer.
Parameters:
buffer: The java.nio.ByteBuffer
into which the read data should be written.
length: The number of bytes to read.
See also: put
public int
peekUnsignedByte()
Peeks at the next byte as an unsigned value.
Peeks at the next char.
public int
readUnsignedByte()
Reads the next byte as an unsigned value.
public int
readUnsignedShort()
Reads the next two bytes as an unsigned value.
public int
readLittleEndianUnsignedShort()
Reads the next two bytes as an unsigned value.
Reads the next two bytes as a signed value.
public short
readLittleEndianShort()
Reads the next two bytes as a signed value.
public int
readUnsignedInt24()
Reads the next three bytes as an unsigned value.
Reads the next three bytes as a signed value.
public int
readLittleEndianInt24()
Reads the next three bytes as a signed value in little endian order.
public int
readLittleEndianUnsignedInt24()
Reads the next three bytes as an unsigned value in little endian order.
public long
readUnsignedInt()
Reads the next four bytes as an unsigned value.
public long
readLittleEndianUnsignedInt()
Reads the next four bytes as an unsigned value in little endian order.
Reads the next four bytes as a signed value
public int
readLittleEndianInt()
Reads the next four bytes as a signed value in little endian order.
Reads the next eight bytes as a signed value.
public long
readLittleEndianLong()
Reads the next eight bytes as a signed value in little endian order.
public int
readUnsignedFixedPoint1616()
Reads the next four bytes, returning the integer portion of the fixed point 16.16 integer.
public int
readSynchSafeInt()
Reads a Synchsafe integer.
Synchsafe integers keep the highest bit of every byte zeroed. A 32 bit synchsafe integer can
store 28 bits of information.
Returns:
The parsed value.
public int
readUnsignedIntToInt()
Reads the next four bytes as an unsigned integer into an integer, if the top bit is a zero.
public int
readLittleEndianUnsignedIntToInt()
Reads the next four bytes as a little endian unsigned integer into an integer, if the top bit
is a zero.
public long
readUnsignedLongToLong()
Reads the next eight bytes as an unsigned long into a long, if the top bit is a zero.
Reads the next four bytes as a 32-bit floating point value.
public double
readDouble()
Reads the next eight bytes as a 64-bit floating point value.
public java.lang.String
readString(int length)
Reads the next length bytes as UTF-8 characters.
Parameters:
length: The number of bytes to read.
Returns:
The string encoded by the bytes.
public java.lang.String
readString(int length, java.nio.charset.Charset charset)
Reads the next length bytes as characters in the specified java.nio.charset.Charset
.
Parameters:
length: The number of bytes to read.
charset: The character set of the encoded characters.
Returns:
The string encoded by the bytes in the specified character set.
public java.lang.String
readNullTerminatedString(int length)
Reads the next length bytes as UTF-8 characters. A terminating NUL byte is discarded,
if present.
Parameters:
length: The number of bytes to read.
Returns:
The string, not including any terminating NUL byte.
public java.lang.String
readNullTerminatedString()
Reads up to the next NUL byte (or the limit) as UTF-8 characters.
Returns:
The string not including any terminating NUL byte, or null if the end of the data has
already been reached.
public java.lang.String
readDelimiterTerminatedString(char delimiter)
Reads up to the next delimiter byte (or the limit) as UTF-8 characters.
Returns:
The string not including any terminating delimiter byte, or null if the end of the data
has already been reached.
public java.lang.String
readLine()
Reads a line of text.
A line is considered to be terminated by any one of a carriage return ('\r'), a line feed
('\n'), or a carriage return followed immediately by a line feed ('\r\n'). The UTF-8 charset is
used. This method discards leading UTF-8 byte order marks, if present.
Returns:
The line not including any line-termination characters, or null if the end of the data
has already been reached.
public long
readUtf8EncodedLong()
Reads a long value encoded by UTF-8 encoding
Returns:
Decoded long value
Source
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.common.util;
import androidx.annotation.Nullable;
import com.google.common.base.Charsets;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* Wraps a byte array, providing a set of methods for parsing data from it. Numerical values are
* parsed with the assumption that their constituent bytes are in big endian order.
*/
@UnstableApi
public final class ParsableByteArray {
private byte[] data;
private int position;
// TODO(internal b/147657250): Enforce this limit on all read methods.
private int limit;
/** Creates a new instance that initially has no backing data. */
public ParsableByteArray() {
data = Util.EMPTY_BYTE_ARRAY;
}
/**
* Creates a new instance with {@code limit} bytes and sets the limit.
*
* @param limit The limit to set.
*/
public ParsableByteArray(int limit) {
this.data = new byte[limit];
this.limit = limit;
}
/**
* Creates a new instance wrapping {@code data}, and sets the limit to {@code data.length}.
*
* @param data The array to wrap.
*/
public ParsableByteArray(byte[] data) {
this.data = data;
limit = data.length;
}
/**
* Creates a new instance that wraps an existing array.
*
* @param data The data to wrap.
* @param limit The limit to set.
*/
public ParsableByteArray(byte[] data, int limit) {
this.data = data;
this.limit = limit;
}
/**
* Resets the position to zero and the limit to the specified value. This might replace or wipe
* the {@link #getData() underlying array}, potentially invalidating any local references.
*
* @param limit The limit to set.
*/
public void reset(int limit) {
reset(capacity() < limit ? new byte[limit] : data, limit);
}
/**
* Updates the instance to wrap {@code data}, and resets the position to zero and the limit to
* {@code data.length}.
*
* @param data The array to wrap.
*/
public void reset(byte[] data) {
reset(data, data.length);
}
/**
* Updates the instance to wrap {@code data}, and resets the position to zero.
*
* @param data The array to wrap.
* @param limit The limit to set.
*/
public void reset(byte[] data, int limit) {
this.data = data;
this.limit = limit;
position = 0;
}
/**
* Ensures the backing array is at least {@code requiredCapacity} long.
*
* <p>{@link #getPosition() position}, {@link #limit() limit}, and all data in the underlying
* array (including that beyond {@link #limit()}) are preserved.
*
* <p>This might replace or wipe the {@link #getData() underlying array}, potentially invalidating
* any local references.
*/
public void ensureCapacity(int requiredCapacity) {
if (requiredCapacity > capacity()) {
data = Arrays.copyOf(data, requiredCapacity);
}
}
/** Returns the number of bytes yet to be read. */
public int bytesLeft() {
return limit - position;
}
/** Returns the limit. */
public int limit() {
return limit;
}
/**
* Sets the limit.
*
* @param limit The limit to set.
*/
public void setLimit(int limit) {
Assertions.checkArgument(limit >= 0 && limit <= data.length);
this.limit = limit;
}
/** Returns the current offset in the array, in bytes. */
public int getPosition() {
return position;
}
/**
* Sets the reading offset in the array.
*
* @param position Byte offset in the array from which to read.
* @throws IllegalArgumentException Thrown if the new position is neither in nor at the end of the
* array.
*/
public void setPosition(int position) {
// It is fine for position to be at the end of the array.
Assertions.checkArgument(position >= 0 && position <= limit);
this.position = position;
}
/**
* Returns the underlying array.
*
* <p>Changes to this array are reflected in the results of the {@code read...()} methods.
*
* <p>This reference must be assumed to become invalid when {@link #reset} or {@link
* #ensureCapacity} are called (because the array might get reallocated).
*/
public byte[] getData() {
return data;
}
/** Returns the capacity of the array, which may be larger than the limit. */
public int capacity() {
return data.length;
}
/**
* Moves the reading offset by {@code bytes}.
*
* @param bytes The number of bytes to skip.
* @throws IllegalArgumentException Thrown if the new position is neither in nor at the end of the
* array.
*/
public void skipBytes(int bytes) {
setPosition(position + bytes);
}
/**
* Reads the next {@code length} bytes into {@code bitArray}, and resets the position of {@code
* bitArray} to zero.
*
* @param bitArray The {@link ParsableBitArray} into which the bytes should be read.
* @param length The number of bytes to write.
*/
public void readBytes(ParsableBitArray bitArray, int length) {
readBytes(bitArray.data, 0, length);
bitArray.setPosition(0);
}
/**
* Reads the next {@code length} bytes into {@code buffer} at {@code offset}.
*
* @see System#arraycopy(Object, int, Object, int, int)
* @param buffer The array into which the read data should be written.
* @param offset The offset in {@code buffer} at which the read data should be written.
* @param length The number of bytes to read.
*/
public void readBytes(byte[] buffer, int offset, int length) {
System.arraycopy(data, position, buffer, offset, length);
position += length;
}
/**
* Reads the next {@code length} bytes into {@code buffer}.
*
* @see ByteBuffer#put(byte[], int, int)
* @param buffer The {@link ByteBuffer} into which the read data should be written.
* @param length The number of bytes to read.
*/
public void readBytes(ByteBuffer buffer, int length) {
buffer.put(data, position, length);
position += length;
}
/** Peeks at the next byte as an unsigned value. */
public int peekUnsignedByte() {
return (data[position] & 0xFF);
}
/** Peeks at the next char. */
public char peekChar() {
return (char) ((data[position] & 0xFF) << 8 | (data[position + 1] & 0xFF));
}
/** Reads the next byte as an unsigned value. */
public int readUnsignedByte() {
return (data[position++] & 0xFF);
}
/** Reads the next two bytes as an unsigned value. */
public int readUnsignedShort() {
return (data[position++] & 0xFF) << 8 | (data[position++] & 0xFF);
}
/** Reads the next two bytes as an unsigned value. */
public int readLittleEndianUnsignedShort() {
return (data[position++] & 0xFF) | (data[position++] & 0xFF) << 8;
}
/** Reads the next two bytes as a signed value. */
public short readShort() {
return (short) ((data[position++] & 0xFF) << 8 | (data[position++] & 0xFF));
}
/** Reads the next two bytes as a signed value. */
public short readLittleEndianShort() {
return (short) ((data[position++] & 0xFF) | (data[position++] & 0xFF) << 8);
}
/** Reads the next three bytes as an unsigned value. */
public int readUnsignedInt24() {
return (data[position++] & 0xFF) << 16
| (data[position++] & 0xFF) << 8
| (data[position++] & 0xFF);
}
/** Reads the next three bytes as a signed value. */
public int readInt24() {
return ((data[position++] & 0xFF) << 24) >> 8
| (data[position++] & 0xFF) << 8
| (data[position++] & 0xFF);
}
/** Reads the next three bytes as a signed value in little endian order. */
public int readLittleEndianInt24() {
return (data[position++] & 0xFF)
| (data[position++] & 0xFF) << 8
| (data[position++] & 0xFF) << 16;
}
/** Reads the next three bytes as an unsigned value in little endian order. */
public int readLittleEndianUnsignedInt24() {
return (data[position++] & 0xFF)
| (data[position++] & 0xFF) << 8
| (data[position++] & 0xFF) << 16;
}
/** Reads the next four bytes as an unsigned value. */
public long readUnsignedInt() {
return (data[position++] & 0xFFL) << 24
| (data[position++] & 0xFFL) << 16
| (data[position++] & 0xFFL) << 8
| (data[position++] & 0xFFL);
}
/** Reads the next four bytes as an unsigned value in little endian order. */
public long readLittleEndianUnsignedInt() {
return (data[position++] & 0xFFL)
| (data[position++] & 0xFFL) << 8
| (data[position++] & 0xFFL) << 16
| (data[position++] & 0xFFL) << 24;
}
/** Reads the next four bytes as a signed value */
public int readInt() {
return (data[position++] & 0xFF) << 24
| (data[position++] & 0xFF) << 16
| (data[position++] & 0xFF) << 8
| (data[position++] & 0xFF);
}
/** Reads the next four bytes as a signed value in little endian order. */
public int readLittleEndianInt() {
return (data[position++] & 0xFF)
| (data[position++] & 0xFF) << 8
| (data[position++] & 0xFF) << 16
| (data[position++] & 0xFF) << 24;
}
/** Reads the next eight bytes as a signed value. */
public long readLong() {
return (data[position++] & 0xFFL) << 56
| (data[position++] & 0xFFL) << 48
| (data[position++] & 0xFFL) << 40
| (data[position++] & 0xFFL) << 32
| (data[position++] & 0xFFL) << 24
| (data[position++] & 0xFFL) << 16
| (data[position++] & 0xFFL) << 8
| (data[position++] & 0xFFL);
}
/** Reads the next eight bytes as a signed value in little endian order. */
public long readLittleEndianLong() {
return (data[position++] & 0xFFL)
| (data[position++] & 0xFFL) << 8
| (data[position++] & 0xFFL) << 16
| (data[position++] & 0xFFL) << 24
| (data[position++] & 0xFFL) << 32
| (data[position++] & 0xFFL) << 40
| (data[position++] & 0xFFL) << 48
| (data[position++] & 0xFFL) << 56;
}
/** Reads the next four bytes, returning the integer portion of the fixed point 16.16 integer. */
public int readUnsignedFixedPoint1616() {
int result = (data[position++] & 0xFF) << 8 | (data[position++] & 0xFF);
position += 2; // Skip the non-integer portion.
return result;
}
/**
* Reads a Synchsafe integer.
*
* <p>Synchsafe integers keep the highest bit of every byte zeroed. A 32 bit synchsafe integer can
* store 28 bits of information.
*
* @return The parsed value.
*/
public int readSynchSafeInt() {
int b1 = readUnsignedByte();
int b2 = readUnsignedByte();
int b3 = readUnsignedByte();
int b4 = readUnsignedByte();
return (b1 << 21) | (b2 << 14) | (b3 << 7) | b4;
}
/**
* Reads the next four bytes as an unsigned integer into an integer, if the top bit is a zero.
*
* @throws IllegalStateException Thrown if the top bit of the input data is set.
*/
public int readUnsignedIntToInt() {
int result = readInt();
if (result < 0) {
throw new IllegalStateException("Top bit not zero: " + result);
}
return result;
}
/**
* Reads the next four bytes as a little endian unsigned integer into an integer, if the top bit
* is a zero.
*
* @throws IllegalStateException Thrown if the top bit of the input data is set.
*/
public int readLittleEndianUnsignedIntToInt() {
int result = readLittleEndianInt();
if (result < 0) {
throw new IllegalStateException("Top bit not zero: " + result);
}
return result;
}
/**
* Reads the next eight bytes as an unsigned long into a long, if the top bit is a zero.
*
* @throws IllegalStateException Thrown if the top bit of the input data is set.
*/
public long readUnsignedLongToLong() {
long result = readLong();
if (result < 0) {
throw new IllegalStateException("Top bit not zero: " + result);
}
return result;
}
/** Reads the next four bytes as a 32-bit floating point value. */
public float readFloat() {
return Float.intBitsToFloat(readInt());
}
/** Reads the next eight bytes as a 64-bit floating point value. */
public double readDouble() {
return Double.longBitsToDouble(readLong());
}
/**
* Reads the next {@code length} bytes as UTF-8 characters.
*
* @param length The number of bytes to read.
* @return The string encoded by the bytes.
*/
public String readString(int length) {
return readString(length, Charsets.UTF_8);
}
/**
* Reads the next {@code length} bytes as characters in the specified {@link Charset}.
*
* @param length The number of bytes to read.
* @param charset The character set of the encoded characters.
* @return The string encoded by the bytes in the specified character set.
*/
public String readString(int length, Charset charset) {
String result = new String(data, position, length, charset);
position += length;
return result;
}
/**
* Reads the next {@code length} bytes as UTF-8 characters. A terminating NUL byte is discarded,
* if present.
*
* @param length The number of bytes to read.
* @return The string, not including any terminating NUL byte.
*/
public String readNullTerminatedString(int length) {
if (length == 0) {
return "";
}
int stringLength = length;
int lastIndex = position + length - 1;
if (lastIndex < limit && data[lastIndex] == 0) {
stringLength--;
}
String result = Util.fromUtf8Bytes(data, position, stringLength);
position += length;
return result;
}
/**
* Reads up to the next NUL byte (or the limit) as UTF-8 characters.
*
* @return The string not including any terminating NUL byte, or null if the end of the data has
* already been reached.
*/
@Nullable
public String readNullTerminatedString() {
return readDelimiterTerminatedString('\0');
}
/**
* Reads up to the next delimiter byte (or the limit) as UTF-8 characters.
*
* @return The string not including any terminating delimiter byte, or null if the end of the data
* has already been reached.
*/
@Nullable
public String readDelimiterTerminatedString(char delimiter) {
if (bytesLeft() == 0) {
return null;
}
int stringLimit = position;
while (stringLimit < limit && data[stringLimit] != delimiter) {
stringLimit++;
}
String string = Util.fromUtf8Bytes(data, position, stringLimit - position);
position = stringLimit;
if (position < limit) {
position++;
}
return string;
}
/**
* Reads a line of text.
*
* <p>A line is considered to be terminated by any one of a carriage return ('\r'), a line feed
* ('\n'), or a carriage return followed immediately by a line feed ('\r\n'). The UTF-8 charset is
* used. This method discards leading UTF-8 byte order marks, if present.
*
* @return The line not including any line-termination characters, or null if the end of the data
* has already been reached.
*/
@Nullable
public String readLine() {
if (bytesLeft() == 0) {
return null;
}
int lineLimit = position;
while (lineLimit < limit && !Util.isLinebreak(data[lineLimit])) {
lineLimit++;
}
if (lineLimit - position >= 3
&& data[position] == (byte) 0xEF
&& data[position + 1] == (byte) 0xBB
&& data[position + 2] == (byte) 0xBF) {
// There's a UTF-8 byte order mark at the start of the line. Discard it.
position += 3;
}
String line = Util.fromUtf8Bytes(data, position, lineLimit - position);
position = lineLimit;
if (position == limit) {
return line;
}
if (data[position] == '\r') {
position++;
if (position == limit) {
return line;
}
}
if (data[position] == '\n') {
position++;
}
return line;
}
/**
* Reads a long value encoded by UTF-8 encoding
*
* @throws NumberFormatException if there is a problem with decoding
* @return Decoded long value
*/
public long readUtf8EncodedLong() {
int length = 0;
long value = data[position];
// find the high most 0 bit
for (int j = 7; j >= 0; j--) {
if ((value & (1 << j)) == 0) {
if (j < 6) {
value &= (1 << j) - 1;
length = 7 - j;
} else if (j == 7) {
length = 1;
}
break;
}
}
if (length == 0) {
throw new NumberFormatException("Invalid UTF-8 sequence first byte: " + value);
}
for (int i = 1; i < length; i++) {
int x = data[position + i];
if ((x & 0xC0) != 0x80) { // if the high most 0 bit not 7th
throw new NumberFormatException("Invalid UTF-8 sequence continuation byte: " + value);
}
value = (value << 6) | (x & 0x3F);
}
position += length;
return value;
}
}