BufferReader.ts
· 4.4 KiB · TypeScript
Raw
export default class BufferReader {
#buffer: Buffer
#offset: number
#length = 0
/// Yields BufferReaders, splitting when it hits newline
static *getPackets(data: Buffer) {
let reader = new BufferReader(data)
yield reader
// while(reader.nextBuffer != null) {
// reader = new BufferReader(reader.nextBuffer)
// yield reader
// }
return null
}
static new(size: number) {
return new BufferReader(Buffer.alloc(size))
}
constructor(data: Buffer) {
if(!data) throw new Error("buffer is null or undefined")
// console.log(data.byteLength, data.length, data.toString('hex'))
this.#buffer = data
this.#offset = 0
this.#length = data.byteLength
}
get buffer() {
return this.#buffer.subarray()
}
get offset() {
return this.#offset
}
get length() {
return this.#length
}
get isEOF() {
return this.#offset >= this.#length || this.#curChar == 0xa // new line
}
get IsRecordSeparator() {
return this.#curChar === BufferReader.RecordSeparator
}
get #curChar() {
return this.#buffer.at(this.#offset)
}
static get RecordSeparator() {
return 0x1e
}
peekByte(): number {
return this.#buffer.readInt8(this.#offset)
}
readByte(): number {
const value = this.#buffer.readInt8(this.#offset)
this.#offset += 1
return value
}
readShort(): number {
const value = this.#buffer.readInt16LE(this.#offset)
this.#offset += 2
return value
}
readInt(): number {
const value = this.#buffer.readInt32LE(this.#offset)
this.#offset += 4
return value
}
readFloat(): number {
const value = this.#buffer.readFloatLE(this.#offset)
this.#offset += 4
return value
}
readString(): string {
let start = this.#offset
// Read until null term
while(this.#offset < this.#length) {
if(this.#curChar === 0x0) {
return this.#buffer.subarray(start, this.#offset++).toString()
}
this.#offset++
}
throw new Error("No null term found")
}
/// Yields a BufferReader for every record in a packet
*readRecords() {
while(!this.isEOF) {
const length = this.readByte()
const endRecord = this.#offset + length
yield new BufferReader(this.#buffer.subarray(this.#offset, endRecord))
this.#offset = endRecord + 1
}
return null
}
#expand(newSize?: number) {
if(!newSize) newSize = 2 * this.buffer.length
if(newSize < this.#buffer.length) throw new Error("new size must be greater than the current size")
const newBuffer = Buffer.alloc(newSize)
this.buffer.copy(newBuffer, 0, 0, this.buffer.length)
this.#buffer = newBuffer
this.#length = newSize
}
writeByte(value: number) {
if(this.#offset + 1 >= this.#length) this.#expand()
this.#buffer.writeInt8(value, this.#offset)
this.#offset++
return this
}
writeShort(value: number) {
if(this.#offset + 2 >= this.#length) this.#expand()
this.#buffer.writeInt16LE(value, this.#offset)
this.#offset += 2
return this
}
writeInt(value: number) {
if(this.#offset + 4 >= this.#length) this.#expand()
this.#buffer.writeInt32LE(value, this.#offset)
this.#offset += 4
return this
}
writeFloat(value: number) {
if(this.#offset + 4 >= this.#length) this.#expand()
this.#buffer.writeFloatLE(value, this.#offset)
this.#offset += 4
return this
}
writeString(value: string) {
if(this.#offset + value.length + 1 >= this.#length) this.#expand(this.#length + value.length + 1)
if(value == undefined) value = ""
this.#buffer.write(value + "\0", this.#offset, "ascii")
this.#offset += value.length + 1
return this
}
// get nextBuffer() {
// if(this.#curChar == 0xa && this.#offset + 1 < this.#buffer.length) {
// return this.#buffer.subarray(this.#offset + 1)
// } else {
// return null
// }
// }
at(i: number): number {
return this.#buffer.at(i)
}
next(): number | null {
if(this.#offset == this.#length) return null
return this.readByte()
}
}
| 1 | export default class BufferReader { |
| 2 | #buffer: Buffer |
| 3 | #offset: number |
| 4 | #length = 0 |
| 5 | |
| 6 | /// Yields BufferReaders, splitting when it hits newline |
| 7 | static *getPackets(data: Buffer) { |
| 8 | let reader = new BufferReader(data) |
| 9 | yield reader |
| 10 | // while(reader.nextBuffer != null) { |
| 11 | // reader = new BufferReader(reader.nextBuffer) |
| 12 | // yield reader |
| 13 | // } |
| 14 | return null |
| 15 | } |
| 16 | |
| 17 | static new(size: number) { |
| 18 | return new BufferReader(Buffer.alloc(size)) |
| 19 | } |
| 20 | |
| 21 | constructor(data: Buffer) { |
| 22 | if(!data) throw new Error("buffer is null or undefined") |
| 23 | // console.log(data.byteLength, data.length, data.toString('hex')) |
| 24 | this.#buffer = data |
| 25 | this.#offset = 0 |
| 26 | this.#length = data.byteLength |
| 27 | |
| 28 | } |
| 29 | |
| 30 | get buffer() { |
| 31 | return this.#buffer.subarray() |
| 32 | } |
| 33 | |
| 34 | get offset() { |
| 35 | return this.#offset |
| 36 | } |
| 37 | |
| 38 | get length() { |
| 39 | return this.#length |
| 40 | } |
| 41 | |
| 42 | get isEOF() { |
| 43 | return this.#offset >= this.#length || this.#curChar == 0xa // new line |
| 44 | } |
| 45 | |
| 46 | get IsRecordSeparator() { |
| 47 | return this.#curChar === BufferReader.RecordSeparator |
| 48 | } |
| 49 | |
| 50 | get #curChar() { |
| 51 | return this.#buffer.at(this.#offset) |
| 52 | } |
| 53 | |
| 54 | static get RecordSeparator() { |
| 55 | return 0x1e |
| 56 | } |
| 57 | |
| 58 | peekByte(): number { |
| 59 | return this.#buffer.readInt8(this.#offset) |
| 60 | } |
| 61 | |
| 62 | readByte(): number { |
| 63 | const value = this.#buffer.readInt8(this.#offset) |
| 64 | this.#offset += 1 |
| 65 | return value |
| 66 | } |
| 67 | |
| 68 | readShort(): number { |
| 69 | const value = this.#buffer.readInt16LE(this.#offset) |
| 70 | this.#offset += 2 |
| 71 | return value |
| 72 | } |
| 73 | |
| 74 | readInt(): number { |
| 75 | const value = this.#buffer.readInt32LE(this.#offset) |
| 76 | this.#offset += 4 |
| 77 | return value |
| 78 | } |
| 79 | |
| 80 | readFloat(): number { |
| 81 | const value = this.#buffer.readFloatLE(this.#offset) |
| 82 | this.#offset += 4 |
| 83 | return value |
| 84 | } |
| 85 | |
| 86 | readString(): string { |
| 87 | let start = this.#offset |
| 88 | // Read until null term |
| 89 | while(this.#offset < this.#length) { |
| 90 | if(this.#curChar === 0x0) { |
| 91 | return this.#buffer.subarray(start, this.#offset++).toString() |
| 92 | } |
| 93 | this.#offset++ |
| 94 | } |
| 95 | throw new Error("No null term found") |
| 96 | } |
| 97 | |
| 98 | /// Yields a BufferReader for every record in a packet |
| 99 | *readRecords() { |
| 100 | while(!this.isEOF) { |
| 101 | const length = this.readByte() |
| 102 | const endRecord = this.#offset + length |
| 103 | yield new BufferReader(this.#buffer.subarray(this.#offset, endRecord)) |
| 104 | this.#offset = endRecord + 1 |
| 105 | } |
| 106 | return null |
| 107 | } |
| 108 | |
| 109 | #expand(newSize?: number) { |
| 110 | if(!newSize) newSize = 2 * this.buffer.length |
| 111 | if(newSize < this.#buffer.length) throw new Error("new size must be greater than the current size") |
| 112 | const newBuffer = Buffer.alloc(newSize) |
| 113 | this.buffer.copy(newBuffer, 0, 0, this.buffer.length) |
| 114 | this.#buffer = newBuffer |
| 115 | this.#length = newSize |
| 116 | } |
| 117 | |
| 118 | |
| 119 | writeByte(value: number) { |
| 120 | if(this.#offset + 1 >= this.#length) this.#expand() |
| 121 | this.#buffer.writeInt8(value, this.#offset) |
| 122 | this.#offset++ |
| 123 | return this |
| 124 | } |
| 125 | |
| 126 | writeShort(value: number) { |
| 127 | if(this.#offset + 2 >= this.#length) this.#expand() |
| 128 | this.#buffer.writeInt16LE(value, this.#offset) |
| 129 | this.#offset += 2 |
| 130 | return this |
| 131 | } |
| 132 | |
| 133 | writeInt(value: number) { |
| 134 | if(this.#offset + 4 >= this.#length) this.#expand() |
| 135 | this.#buffer.writeInt32LE(value, this.#offset) |
| 136 | this.#offset += 4 |
| 137 | return this |
| 138 | } |
| 139 | |
| 140 | writeFloat(value: number) { |
| 141 | if(this.#offset + 4 >= this.#length) this.#expand() |
| 142 | this.#buffer.writeFloatLE(value, this.#offset) |
| 143 | this.#offset += 4 |
| 144 | return this |
| 145 | } |
| 146 | |
| 147 | writeString(value: string) { |
| 148 | if(this.#offset + value.length + 1 >= this.#length) this.#expand(this.#length + value.length + 1) |
| 149 | if(value == undefined) value = "" |
| 150 | this.#buffer.write(value + "\0", this.#offset, "ascii") |
| 151 | this.#offset += value.length + 1 |
| 152 | return this |
| 153 | } |
| 154 | |
| 155 | // get nextBuffer() { |
| 156 | // if(this.#curChar == 0xa && this.#offset + 1 < this.#buffer.length) { |
| 157 | // return this.#buffer.subarray(this.#offset + 1) |
| 158 | // } else { |
| 159 | // return null |
| 160 | // } |
| 161 | // } |
| 162 | |
| 163 | at(i: number): number { |
| 164 | return this.#buffer.at(i) |
| 165 | } |
| 166 | |
| 167 | next(): number | null { |
| 168 | if(this.#offset == this.#length) return null |
| 169 | return this.readByte() |
| 170 | } |
| 171 | } |