/*
* Copyright (C) 2014 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 com.google.android.exoplayer.parser.mp4;
import java.nio.ByteBuffer;
/**
* 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.
*/
/* package */ final class ParsableByteArray {
public byte[] data;
private int position;
public ParsableByteArray(int length) {
this.data = new byte[length];
}
public int length() {
return data.length;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public void skip(int bytes) {
position += bytes;
}
public void rewind(int bytes) {
position -= bytes;
}
public void readBytes(byte[] buffer, int offset, int length) {
System.arraycopy(data, position, buffer, offset, length);
position += length;
}
public void readBytes(ByteBuffer buffer, int length) {
buffer.put(data, position, length);
position += length;
}
public int readUnsignedByte() {
int result = shiftIntoInt(data, position, 1);
position += 1;
return result;
}
public int readUnsignedShort() {
int result = shiftIntoInt(data, position, 2);
position += 2;
return result;
}
public long readUnsignedInt() {
long result = shiftIntoLong(data, position, 4);
position += 4;
return result;
}
public int readInt() {
int result = shiftIntoInt(data, position, 4);
position += 4;
return result;
}
public long readLong() {
long result = shiftIntoLong(data, position, 8);
position += 8;
return result;
}
/**
* @return The integer portion of a fixed point 16.16.
*/
public int readUnsignedFixedPoint1616() {
int result = shiftIntoInt(data, position, 2);
position += 4;
return result;
}
/**
* Reads an unsigned integer into an integer. This method is suitable for use when it can be
* assumed that the top bit will always be set to zero.
*
* @throws IllegalArgumentException If the top bit of the input data is set.
*/
public int readUnsignedIntToInt() {
int result = shiftIntoInt(data, position, 4);
position += 4;
if (result < 0) {
throw new IllegalArgumentException("Top bit not zero: " + result);
}
return result;
}
/**
* Reads an unsigned long into a long. This method is suitable for use when it can be
* assumed that the top bit will always be set to zero.
*
* @throws IllegalArgumentException If the top bit of the input data is set.
*/
public long readUnsignedLongToLong() {
long result = shiftIntoLong(data, position, 8);
position += 8;
if (result < 0) {
throw new IllegalArgumentException("Top bit not zero: " + result);
}
return result;
}
private static int shiftIntoInt(byte[] bytes, int offset, int length) {
int result = 0xFF & bytes[offset];
for (int i = offset + 1; i < offset + length; i++) {
result <<= 8;
result |= 0xFF & bytes[i];
}
return result;
}
private static long shiftIntoLong(byte[] bytes, int offset, int length) {
long result = 0xFF & bytes[offset];
for (int i = offset + 1; i < offset + length; i++) {
result <<= 8;
result |= 0xFF & bytes[i];
}
return result;
}
}