| 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 | } |
jackz / BufferReader.ts
Last active 2 months ago