package io.orprotocol; public class Stream { private byte[] stream; private int readPointer = 0; private int writePointer = 0; public Stream() { this.stream = new byte[0]; } public Stream(byte[] stream) { this.stream = stream; } public byte[] getStream() { return this.stream; } public void setStream(byte[] stream) { this.stream = stream; } public void writeInt8(int value) { int negationBit = value < 0 ? 1 : 0; int int8Value = Math.abs(value) & 0xFF; ensureCapacity(writePointer >> 3); stream[writePointer >> 3] |= (byte)(negationBit << (7 - (writePointer & 7))); writePointer++; for (int i = 0; i < 8; i++) { int bit = (int8Value >> (7 - i)) & 1; ensureCapacity(writePointer >> 3); stream[writePointer >> 3] |= (byte)(bit << (7 - (writePointer & 7))); writePointer++; } } public int readInt8() { int value = 0; int negationBit = (stream[readPointer >> 3] >> (7 - (readPointer & 7))) & 1; readPointer++; for (int i = 0; i < 8; i++) { int bit = (stream[readPointer >> 3] >> (7 - (readPointer & 7))) & 1; value |= bit << (7 - i); readPointer++; } return negationBit == 1 ? -value : value; } public void writeBit(int value) { int bit = value & 1; ensureCapacity(writePointer >> 3); stream[writePointer >> 3] |= (byte)(bit << (7 - (writePointer & 7))); writePointer++; } public int readBit() { int bit = (stream[readPointer >> 3] >> (7 - (readPointer & 7))) & 1; readPointer++; return bit; } public void writeBoolean(boolean value) { writeBit(value ? 1 : 0); } public boolean readBoolean() { return readBit() == 1; } public void writeInt16(int value) { writeInt8(value >> 8); writeInt8(value & 0xFF); } public int readInt16() { int value = readInt8() << 8; return value | readInt8(); } public void writeInt32(int value) { writeInt16(value >> 16); writeInt16(value & 0xFFFF); } public int readInt32() { int value = readInt16() << 16; return value | readInt16(); } public void writeInt64(long value) { int high = (int)(value >> 32); int low = (int)value; writeInt32(high); writeInt32(low); } public long readInt64() { long high = readInt32(); long low = readInt32() & 0xFFFFFFFFL; return (high << 32) | low; } public void writeFloat32(float value) { int floatValue = Float.floatToIntBits(value); writeInt32(floatValue); } public float readFloat32() { int floatValue = readInt32(); return Float.intBitsToFloat(floatValue); } public void writeString(String value) { int length = value.length(); writeInt32(length); for (int i = 0; i < value.length(); i++) { writeInt16(value.charAt(i)); } } public String readString() { int length = readInt32(); // Security fix for string length exceeding stream capacity if (length < 0 || length > (stream.length - (readPointer >> 3))) { System.out.println("Stream readString length invalid: " + length + ", stream length: " + stream.length + ", readPointer: " + readPointer); return ""; } StringBuilder value = new StringBuilder(); for (int i = 0; i < length; i++) { value.append((char)readInt16()); } return value.toString(); } public void writeBytes(byte[] value) { writeInt32(value.length); for (int i = 0; i < value.length; i++) { writeInt8(value[i]); } } public byte[] readBytes() { int length = readInt32(); byte[] value = new byte[length]; for (int i = 0; i < length; i++) { value[i] = (byte)readInt8(); } return value; } public boolean isEmpty() { return this.stream.length == 0; } public int length() { return this.stream.length; } public byte[] getBuffer() { return this.stream; } private void ensureCapacity(int byteIndex) { if (byteIndex >= stream.length) { byte[] newStream = new byte[byteIndex + 1]; System.arraycopy(stream, 0, newStream, 0, stream.length); stream = newStream; } } }