class ByteStream { constructor(buffer = null) { this.buffer = buffer || Buffer.alloc(0) this.offset = 0 } readUInt8() { if (this.offset >= this.buffer.length) { throw new Error("ByteStream: Cannot read beyond buffer length") } const value = this.buffer.readUInt8(this.offset) this.offset += 1 return value } readUInt16() { if (this.offset + 2 > this.buffer.length) { throw new Error("ByteStream: Cannot read beyond buffer length") } const value = this.buffer.readUInt16BE(this.offset) this.offset += 2 return value } readUInt24() { if (this.offset + 3 > this.buffer.length) { throw new Error("ByteStream: Cannot read beyond buffer length") } const value = (this.buffer.readUInt8(this.offset) << 16) | (this.buffer.readUInt8(this.offset + 1) << 8) | this.buffer.readUInt8(this.offset + 2) this.offset += 3 return value } readUInt32() { if (this.offset + 4 > this.buffer.length) { throw new Error("ByteStream: Cannot read beyond buffer length") } const value = this.buffer.readUInt32BE(this.offset) this.offset += 4 return value } readInt32() { if (this.offset + 4 > this.buffer.length) { throw new Error("ByteStream: Cannot read beyond buffer length") } const value = this.buffer.readInt32BE(this.offset) this.offset += 4 return value } readString() { const length = this.readUInt32() if (length === 0) return "" if (this.offset + length > this.buffer.length) { throw new Error("ByteStream: Cannot read beyond buffer length") } const value = this.buffer.toString("utf8", this.offset, this.offset + length) this.offset += length return value } readBytes(length) { if (this.offset + length > this.buffer.length) { throw new Error("ByteStream: Cannot read beyond buffer length") } const value = this.buffer.slice(this.offset, this.offset + length) this.offset += length return value } writeUInt8(value) { const buf = Buffer.alloc(1) buf.writeUInt8(value, 0) this.buffer = Buffer.concat([this.buffer, buf]) return this } writeUInt16(value) { const buf = Buffer.alloc(2) buf.writeUInt16BE(value, 0) this.buffer = Buffer.concat([this.buffer, buf]) return this } writeUInt24(value) { const buf = Buffer.alloc(3) buf.writeUInt8((value >> 16) & 0xff, 0) buf.writeUInt8((value >> 8) & 0xff, 1) buf.writeUInt8(value & 0xff, 2) this.buffer = Buffer.concat([this.buffer, buf]) return this } writeUInt32(value) { const buf = Buffer.alloc(4) buf.writeUInt32BE(value, 0) this.buffer = Buffer.concat([this.buffer, buf]) return this } writeInt32(value) { const buf = Buffer.alloc(4) buf.writeInt32BE(value, 0) this.buffer = Buffer.concat([this.buffer, buf]) return this } writeString(value) { this.writeUInt32(value.length) if (value.length > 0) { const buf = Buffer.from(value, "utf8") this.buffer = Buffer.concat([this.buffer, buf]) } return this } writeBytes(bytes) { this.buffer = Buffer.concat([this.buffer, bytes]) return this } // Utility methods getBuffer() { return this.buffer } getLength() { return this.buffer.length } getRemainingLength() { return this.buffer.length - this.offset } getOffset() { return this.offset } setOffset(offset) { if (offset < 0 || offset > this.buffer.length) { throw new Error("ByteStream: Invalid offset") } this.offset = offset return this } reset() { this.buffer = Buffer.alloc(0) this.offset = 0 return this } clone() { const cloned = new ByteStream(Buffer.from(this.buffer)) cloned.offset = this.offset return cloned } toHex() { return this.buffer.toString("hex") } static fromHex(hexString) { return new ByteStream(Buffer.from(hexString, "hex")) } } module.exports = ByteStream