// $Id$
package ch.epfl.lamp.util;
import java.io.*;
/**
* Array of bytes.
*
* @author Michel Schinz
* @version 1.0
*/
public class ByteArray {
protected final static int BYTE_BLOCK_BITS = 8;
protected final static int BYTE_BLOCK_SIZE = 1 << BYTE_BLOCK_BITS;
protected final static int BYTE_BLOCK_MASK = BYTE_BLOCK_SIZE - 1;
protected byte[][] data = new byte[][] { new byte[BYTE_BLOCK_SIZE] };
protected int pos = 0; // The next free position.
protected boolean frozen = false;
public ByteArray() { }
public ByteArray(InputStream stream, int size) throws IOException {
size = pos;
for (int block = 0; size > 0; ++block) {
int sizeToRead = Math.min(BYTE_BLOCK_SIZE, size);
stream.read(data[block], 0, sizeToRead);
size -= sizeToRead;
if (size > 0) addNewBlock();
}
}
public void freeze() { frozen = true; }
public int nextBytePosition() {
return pos;
}
public int getSize() {
return pos;
}
protected void addNewBlock() {
int nextBlockPos = pos >>> BYTE_BLOCK_BITS;
if (nextBlockPos == data.length) {
byte[][] newData = new byte[data.length * 2][];
System.arraycopy(data, 0, newData, 0, data.length);
data = newData;
}
assert data[nextBlockPos] == null : pos + " " + nextBlockPos;
data[nextBlockPos] = new byte[BYTE_BLOCK_SIZE];
}
protected void addByte(int b) {
assert !frozen;
if ((pos & BYTE_BLOCK_MASK) == 0 && pos > 0)
addNewBlock();
int currPos = pos++;
data[currPos >>> BYTE_BLOCK_BITS][currPos & BYTE_BLOCK_MASK] = (byte)b;
}
public void addU1(int i) {
assert i <= 0xFF : i;
addByte(i);
}
public void addU2(int i) {
assert i <= 0xFFFF : i;
addByte(i >>> 8);
addByte(i & 0xFF);
}
public void addU4(int i) {
addByte(i >>> 24);
addByte((i >>> 16) & 0xFF);
addByte((i >>> 8) & 0xFF);
addByte(i & 0xFF);
}
public void putByte(int targetPos, int b) {
assert !frozen;
assert targetPos < pos : targetPos + " >= " + pos;
data[targetPos >>> BYTE_BLOCK_BITS][targetPos & BYTE_BLOCK_MASK] = (byte)b;
}
public void putU2(int targetPos, int i) {
assert i < 0xFFFF : i;
putByte(targetPos, i >>> 8);
putByte(targetPos + 1, i & 0xFF);
}
public void putU4(int targetPos, int i) {
putByte(targetPos, i >>> 24);
putByte(targetPos + 1, (i >>> 16) & 0xFF);
putByte(targetPos + 2, (i >>> 8) & 0xFF);
putByte(targetPos + 3, i & 0xFF);
}
public int getU1(int sourcePos) {
assert sourcePos < pos : sourcePos + " >= " + pos;
return data[sourcePos >>> BYTE_BLOCK_BITS][sourcePos & BYTE_BLOCK_MASK] & 0xFF;
}
public int getU2(int sourcePos) {
return (getU1(sourcePos) << 8) | getU1(sourcePos + 1);
}
public int getU4(int sourcePos) {
return (getU2(sourcePos) << 16) | getU2(sourcePos + 2);
}
public int getS1(int sourcePos) {
assert sourcePos < pos : sourcePos + " >= " + pos;
return data[sourcePos >>> BYTE_BLOCK_BITS][sourcePos & BYTE_BLOCK_MASK];
}
public int getS2(int sourcePos) {
return (getS1(sourcePos) << 8) | getU1(sourcePos + 1);
}
public int getS4(int sourcePos) {
return (getS2(sourcePos) << 16) | getU2(sourcePos + 2);
}
public void writeTo(OutputStream stream) throws IOException {
if (!frozen) freeze();
for (int i = 0; i < data.length && data[i] != null; ++i) {
int len = Math.min(BYTE_BLOCK_SIZE, pos - (i << BYTE_BLOCK_BITS));
stream.write(data[i], 0, len);
}
}
}