package tk.amberide.engine.data.io; import java.io.*; import java.util.Arrays; /** * A one-size-fit-all IO stream * * @author Tudor */ public class ByteStream { protected byte[] buffer; protected volatile int _p = 0; public static ByteStream writeStream(int buffer) { ByteStream stream = new ByteStream(); stream.buffer = new byte[buffer];//new DataOutputStream(stream.array = new ByteArrayOutputStream(buffer)); return stream; } public static ByteStream writeStream() { return writeStream(0); } public static ByteStream writeStream(byte[] bytes) { ByteStream stream = new ByteStream(); stream.buffer = bytes; return stream; } public static ByteStream readStream(byte[] bytes, int pos) { ByteStream stream = new ByteStream(); stream._p = 0; stream.buffer = bytes; return stream; } public static ByteStream readStream(byte[] bytes) { return readStream(bytes, 0); } public static ByteStream readStream(File file) { try { return readStream(new FileInputStream(file)); } catch (FileNotFoundException e) { throw new IllegalStateException("stream ended prematurely", e); } } public static ByteStream readStream(InputStream io) { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); byte[] data = new byte[655653]; int nRead; try { while ((nRead = io.read(data, 0, data.length)) != -1) buffer.write(data, 0, nRead); } catch (IOException e) { throw new IllegalStateException("stream ended prematurely", e); } return readStream(buffer.toByteArray()); } public ByteStream writeInt(final int i) { if (_p + 4 > buffer.length) { ensureCapacity(4); } byte[] data = buffer; data[_p++] = (byte) (i >>> 24); data[_p++] = (byte) (i >>> 16); data[_p++] = (byte) (i >>> 8); data[_p++] = (byte) i; return this; } public ByteStream writeLong(final long l) { writeInt((int) (l >>> 32)); writeInt((int) l); return this; } public ByteStream writeDouble(double d) { return writeLong(Double.doubleToLongBits(d)); } public final ByteStream writeUTF(String s) { int charLength = s.length(); int len = _p; if (len + 2 + charLength > buffer.length) { ensureCapacity(charLength + 2); } byte[] data = buffer; buffer[len++] = (byte) (charLength >>> 8); data[len++] = (byte) charLength; _top: for (int i = 0; i < charLength; ++i) { char c; if ((c = s.charAt(i)) <= 0 || c > 127) { int byteLength = i; int j; for (j = i; j < charLength; ++j) { if ((c = s.charAt(j)) > 0 && c <= 127) { ++byteLength; } else if (c > 2047) { byteLength += 3; } else { byteLength += 2; } } data[len++] = (byte) (byteLength >>> 8); data[len++] = (byte) byteLength; if (len + 2 + byteLength > data.length) { ensureCapacity(byteLength + 2); data = buffer; } j = i; while (true) { j++; if (j >= charLength) { break _top; } if ((c = s.charAt(j)) > 0 && c <= 127) { data[len++] = (byte) c; continue; } else if (c > 2047) { data[len++] = (byte) (224 | c >> 12 & 15); data[len++] = (byte) (128 | c >> 6 & 63); } else { data[len++] = (byte) (192 | c >> 6 & 31); } data[len++] = (byte) (128 | c & 63); } } data[len++] = (byte) c; } _p = len; return this; } public ByteStream writeShort(int s) { int length = _p; if (length + 2 > buffer.length) { ensureCapacity(2); } byte[] data = buffer; data[length++] = (byte) (s >>> 8); data[length++] = (byte) s; _p = length; return this; } public ByteStream writeByte(int b) { int length = _p; if (length + 1 > buffer.length) { ensureCapacity(1); } buffer[length++] = (byte) b; _p = length; return this; } public ByteStream writeBytes(byte[] b) { if (b.length > 0) { if (_p + b.length > buffer.length) { ensureCapacity(b.length); } System.arraycopy(b, 0, buffer, _p, b.length); _p += b.length; } return this; } public boolean readBoolean() { return readByte() == 1; } public int readUnsignedByte() { return buffer[_p++]; } public short readShort() { byte[] b = buffer; return (short) (((b[_p++] & 0xFF) << 8) | (b[_p++] & 0xFF)); } public int readUnsignedShort() { byte[] b = buffer; return ((b[_p++] & 0xFF) << 8) | (b[_p++] & 0xFF); } public int readInt() { byte[] b = buffer; return ((b[_p++] & 0xFF) << 24) | ((b[_p++] & 0xFF) << 16) | ((b[_p++] & 0xFF) << 8) | (b[_p++] & 0xFF); } public long readLong() { return (readInt() << 32) | readInt() & 0xFFFFFFFFL; } public float readFloat() { return Float.intBitsToFloat(readInt()); } public double readDouble() { return Double.longBitsToDouble(readLong()); } public byte readByte() { return (byte) (buffer[_p++] & 0xFF); } public String readUTF() { int size = readShort(); int pos = 0; char[] buf = new char[size]; int strLen = 0; while (pos < size) { int c; if ((c = buffer[_p + pos++] & 0xFF) < 0x80) { buf[strLen++] = (char) c; } else { char cc; if (c < 0xE0 && c > 0xBF) { cc = (char) (c & 0x1F); } else { cc = (char) ((c & 0xF) << 0x6 | c & 0x3F); } buf[strLen++] = (char) (cc << 0x6 | c & 0x3F); } } _p += pos; return new String(buf, 0, strLen); } public byte[] read(int n) { byte[] arr = new byte[n]; System.arraycopy(buffer, _p, arr, 0, n); _p += n; return arr; } public byte[] getBuffer() { if (_p < buffer.length) { // This means that extra space has been allocated: // we cannot return this because it is essentially // corrupt. Hence, we truncate the end. byte[] newBuf = new byte[_p]; System.arraycopy(buffer, 0, newBuf, 0, _p); // Set buffer to it so that we essentially return // a pointer. buffer = newBuf; } return buffer; } public void ensureCapacity(int size) { int mul = buffer.length << 1; int ad = _p + size; byte[] newData = new byte[mul > ad ? mul : ad]; System.arraycopy(buffer, 0, newData, 0, _p); buffer = newData; } public int position() { return _p; } public void dump(File f) throws IOException { FileOutputStream fout = new FileOutputStream(f); fout.write(getBuffer()); fout.close(); } public String toString() { return "{ByteStream(" + buffer.length + "):" + Arrays.toString(buffer) + "}"; } }