jackz revised this gist . Go to revision
No changes
Jackz revised this gist . Go to revision
1 file changed, 91 insertions, 44 deletions
BufferReader.ts
@@ -2,25 +2,33 @@ export default class BufferReader { | |||
2 | 2 | #buffer: Buffer | |
3 | 3 | #offset: number | |
4 | 4 | #length = 0 | |
5 | - | ||
6 | - | static *getBuffers(data: Buffer) { | |
7 | - | let i = 0 | |
8 | - | let reader = new BufferReader(data) | |
9 | - | yield reader | |
10 | - | while(reader.nextBuffer != null) { | |
11 | - | console.log(i++, "got next buffer", reader.nextBuffer.toString('hex')) | |
12 | - | reader = new BufferReader(reader.nextBuffer) | |
13 | - | yield reader | |
14 | - | } | |
15 | - | return null | |
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)) | |
16 | 19 | } | |
17 | 20 | ||
18 | 21 | constructor(data: Buffer) { | |
19 | 22 | if(!data) throw new Error("buffer is null or undefined") | |
20 | - | console.log(data.toString('hex')) | |
23 | + | // console.log(data.byteLength, data.length, data.toString('hex')) | |
21 | 24 | this.#buffer = data | |
22 | 25 | this.#offset = 0 | |
23 | 26 | this.#length = data.byteLength | |
27 | + | ||
28 | + | } | |
29 | + | ||
30 | + | get buffer() { | |
31 | + | return this.#buffer.subarray() | |
24 | 32 | } | |
25 | 33 | ||
26 | 34 | get offset() { | |
@@ -75,43 +83,82 @@ export default class BufferReader { | |||
75 | 83 | return value | |
76 | 84 | } | |
77 | 85 | ||
78 | - | readString(length: number): string { | |
79 | - | const slice = this.#buffer.subarray(this.#offset, this.#offset + length) | |
80 | - | this.#offset += length | |
81 | - | return slice.toString().split("\0").shift(); | |
82 | - | } | |
83 | - | ||
84 | - | readVarString(): string { | |
85 | - | let length = this.readShort() | |
86 | - | return this.readString(length) | |
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") | |
87 | 96 | } | |
88 | - | ||
89 | - | *readRecord() { | |
90 | - | let recordStart: number = null | |
97 | + | ||
98 | + | /// Yields a BufferReader for every record in a packet | |
99 | + | *readRecords() { | |
91 | 100 | while(!this.isEOF) { | |
92 | - | if(this.IsRecordSeparator) { | |
93 | - | if(recordStart != null) { | |
94 | - | // End of record | |
95 | - | yield this.#buffer.subarray(recordStart, this.#offset) | |
96 | - | } | |
97 | - | recordStart = this.#offset + 1 | |
98 | - | } | |
99 | - | this.#offset++; | |
100 | - | } | |
101 | - | // Check to see that we have seen the \n(0xa) character at the end, otherwise this record got truncated: | |
102 | - | if(recordStart != null && this.#curChar == 0xa) { | |
103 | - | yield this.#buffer.subarray(recordStart, this.#offset) | |
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 | |
104 | 105 | } | |
105 | 106 | return null | |
106 | 107 | } | |
107 | 108 | ||
108 | - | get nextBuffer() { | |
109 | - | if(this.#curChar == 0xa && this.#offset + 1 < this.#buffer.length) { | |
110 | - | return this.#buffer.subarray(this.#offset + 1) | |
111 | - | } else { | |
112 | - | return null | |
113 | - | } | |
114 | - | } | |
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 | + | // } | |
115 | 162 | ||
116 | 163 | at(i: number): number { | |
117 | 164 | return this.#buffer.at(i) | |
@@ -121,4 +168,4 @@ export default class BufferReader { | |||
121 | 168 | if(this.#offset == this.#length) return null | |
122 | 169 | return this.readByte() | |
123 | 170 | } | |
124 | - | } | |
171 | + | } |
Jackz revised this gist . Go to revision
1 file changed, 124 insertions
BufferReader.ts(file created)
@@ -0,0 +1,124 @@ | |||
1 | + | export default class BufferReader { | |
2 | + | #buffer: Buffer | |
3 | + | #offset: number | |
4 | + | #length = 0 | |
5 | + | ||
6 | + | static *getBuffers(data: Buffer) { | |
7 | + | let i = 0 | |
8 | + | let reader = new BufferReader(data) | |
9 | + | yield reader | |
10 | + | while(reader.nextBuffer != null) { | |
11 | + | console.log(i++, "got next buffer", reader.nextBuffer.toString('hex')) | |
12 | + | reader = new BufferReader(reader.nextBuffer) | |
13 | + | yield reader | |
14 | + | } | |
15 | + | return null | |
16 | + | } | |
17 | + | ||
18 | + | constructor(data: Buffer) { | |
19 | + | if(!data) throw new Error("buffer is null or undefined") | |
20 | + | console.log(data.toString('hex')) | |
21 | + | this.#buffer = data | |
22 | + | this.#offset = 0 | |
23 | + | this.#length = data.byteLength | |
24 | + | } | |
25 | + | ||
26 | + | get offset() { | |
27 | + | return this.#offset | |
28 | + | } | |
29 | + | ||
30 | + | get length() { | |
31 | + | return this.#length | |
32 | + | } | |
33 | + | ||
34 | + | get isEOF() { | |
35 | + | return this.#offset >= this.#length || this.#curChar == 0xa // new line | |
36 | + | } | |
37 | + | ||
38 | + | get IsRecordSeparator() { | |
39 | + | return this.#curChar === BufferReader.RecordSeparator | |
40 | + | } | |
41 | + | ||
42 | + | get #curChar() { | |
43 | + | return this.#buffer.at(this.#offset) | |
44 | + | } | |
45 | + | ||
46 | + | static get RecordSeparator() { | |
47 | + | return 0x1e | |
48 | + | } | |
49 | + | ||
50 | + | peekByte(): number { | |
51 | + | return this.#buffer.readInt8(this.#offset) | |
52 | + | } | |
53 | + | ||
54 | + | readByte(): number { | |
55 | + | const value = this.#buffer.readInt8(this.#offset) | |
56 | + | this.#offset += 1 | |
57 | + | return value | |
58 | + | } | |
59 | + | ||
60 | + | readShort(): number { | |
61 | + | const value = this.#buffer.readInt16LE(this.#offset) | |
62 | + | this.#offset += 2 | |
63 | + | return value | |
64 | + | } | |
65 | + | ||
66 | + | readInt(): number { | |
67 | + | const value = this.#buffer.readInt32LE(this.#offset) | |
68 | + | this.#offset += 4 | |
69 | + | return value | |
70 | + | } | |
71 | + | ||
72 | + | readFloat(): number { | |
73 | + | const value = this.#buffer.readFloatLE(this.#offset) | |
74 | + | this.#offset += 4 | |
75 | + | return value | |
76 | + | } | |
77 | + | ||
78 | + | readString(length: number): string { | |
79 | + | const slice = this.#buffer.subarray(this.#offset, this.#offset + length) | |
80 | + | this.#offset += length | |
81 | + | return slice.toString().split("\0").shift(); | |
82 | + | } | |
83 | + | ||
84 | + | readVarString(): string { | |
85 | + | let length = this.readShort() | |
86 | + | return this.readString(length) | |
87 | + | } | |
88 | + | ||
89 | + | *readRecord() { | |
90 | + | let recordStart: number = null | |
91 | + | while(!this.isEOF) { | |
92 | + | if(this.IsRecordSeparator) { | |
93 | + | if(recordStart != null) { | |
94 | + | // End of record | |
95 | + | yield this.#buffer.subarray(recordStart, this.#offset) | |
96 | + | } | |
97 | + | recordStart = this.#offset + 1 | |
98 | + | } | |
99 | + | this.#offset++; | |
100 | + | } | |
101 | + | // Check to see that we have seen the \n(0xa) character at the end, otherwise this record got truncated: | |
102 | + | if(recordStart != null && this.#curChar == 0xa) { | |
103 | + | yield this.#buffer.subarray(recordStart, this.#offset) | |
104 | + | } | |
105 | + | return null | |
106 | + | } | |
107 | + | ||
108 | + | get nextBuffer() { | |
109 | + | if(this.#curChar == 0xa && this.#offset + 1 < this.#buffer.length) { | |
110 | + | return this.#buffer.subarray(this.#offset + 1) | |
111 | + | } else { | |
112 | + | return null | |
113 | + | } | |
114 | + | } | |
115 | + | ||
116 | + | at(i: number): number { | |
117 | + | return this.#buffer.at(i) | |
118 | + | } | |
119 | + | ||
120 | + | next(): number | null { | |
121 | + | if(this.#offset == this.#length) return null | |
122 | + | return this.readByte() | |
123 | + | } | |
124 | + | } |