1 | var Buffer = require('buffer').Buffer;
|
---|
2 |
|
---|
3 | function OffsetBuffer() {
|
---|
4 | this.offset = 0;
|
---|
5 | this.size = 0;
|
---|
6 | this.buffers = [];
|
---|
7 | }
|
---|
8 | module.exports = OffsetBuffer;
|
---|
9 |
|
---|
10 | OffsetBuffer.prototype.isEmpty = function isEmpty() {
|
---|
11 | return this.size === 0;
|
---|
12 | };
|
---|
13 |
|
---|
14 | OffsetBuffer.prototype.clone = function clone(size) {
|
---|
15 | var r = new OffsetBuffer();
|
---|
16 | r.offset = this.offset;
|
---|
17 | r.size = size;
|
---|
18 | r.buffers = this.buffers.slice();
|
---|
19 | return r;
|
---|
20 | };
|
---|
21 |
|
---|
22 | OffsetBuffer.prototype.toChunks = function toChunks() {
|
---|
23 | if (this.size === 0)
|
---|
24 | return [];
|
---|
25 |
|
---|
26 | // We are going to slice it anyway
|
---|
27 | if (this.offset !== 0) {
|
---|
28 | this.buffers[0] = this.buffers[0].slice(this.offset);
|
---|
29 | this.offset = 0;
|
---|
30 | }
|
---|
31 |
|
---|
32 | var chunks = [ ];
|
---|
33 | var off = 0;
|
---|
34 | for (var i = 0; off <= this.size && i < this.buffers.length; i++) {
|
---|
35 | var buf = this.buffers[i];
|
---|
36 | off += buf.length;
|
---|
37 |
|
---|
38 | // Slice off last buffer
|
---|
39 | if (off > this.size) {
|
---|
40 | buf = buf.slice(0, buf.length - (off - this.size));
|
---|
41 | this.buffers[i] = buf;
|
---|
42 | }
|
---|
43 |
|
---|
44 | chunks.push(buf);
|
---|
45 | }
|
---|
46 |
|
---|
47 | // If some buffers were skipped - trim length
|
---|
48 | if (i < this.buffers.length)
|
---|
49 | this.buffers.length = i;
|
---|
50 |
|
---|
51 | return chunks;
|
---|
52 | };
|
---|
53 |
|
---|
54 | OffsetBuffer.prototype.toString = function toString(enc) {
|
---|
55 | return this.toChunks().map(function(c) {
|
---|
56 | return c.toString(enc);
|
---|
57 | }).join('');
|
---|
58 | };
|
---|
59 |
|
---|
60 | OffsetBuffer.prototype.use = function use(buf, off, n) {
|
---|
61 | this.buffers = [ buf ];
|
---|
62 | this.offset = off;
|
---|
63 | this.size = n;
|
---|
64 | };
|
---|
65 |
|
---|
66 | OffsetBuffer.prototype.push = function push(data) {
|
---|
67 | // Ignore empty writes
|
---|
68 | if (data.length === 0)
|
---|
69 | return;
|
---|
70 |
|
---|
71 | this.size += data.length;
|
---|
72 | this.buffers.push(data);
|
---|
73 | };
|
---|
74 |
|
---|
75 | OffsetBuffer.prototype.has = function has(n) {
|
---|
76 | return this.size >= n;
|
---|
77 | };
|
---|
78 |
|
---|
79 | OffsetBuffer.prototype.skip = function skip(n) {
|
---|
80 | if (this.size === 0)
|
---|
81 | return;
|
---|
82 |
|
---|
83 | this.size -= n;
|
---|
84 |
|
---|
85 | // Fast case, skip bytes in a first buffer
|
---|
86 | if (this.offset + n < this.buffers[0].length) {
|
---|
87 | this.offset += n;
|
---|
88 | return;
|
---|
89 | }
|
---|
90 |
|
---|
91 | var left = n - (this.buffers[0].length - this.offset);
|
---|
92 | this.offset = 0;
|
---|
93 |
|
---|
94 | for (var shift = 1; left > 0 && shift < this.buffers.length; shift++) {
|
---|
95 | var buf = this.buffers[shift];
|
---|
96 | if (buf.length > left) {
|
---|
97 | this.offset = left;
|
---|
98 | break;
|
---|
99 | }
|
---|
100 | left -= buf.length;
|
---|
101 | }
|
---|
102 | this.buffers = this.buffers.slice(shift);
|
---|
103 | };
|
---|
104 |
|
---|
105 | OffsetBuffer.prototype.copy = function copy(target, targetOff, off, n) {
|
---|
106 | if (this.size === 0)
|
---|
107 | return;
|
---|
108 | if (off !== 0)
|
---|
109 | throw new Error('Unsupported offset in .copy()');
|
---|
110 |
|
---|
111 | var toff = targetOff;
|
---|
112 | var first = this.buffers[0];
|
---|
113 | var toCopy = Math.min(n, first.length - this.offset);
|
---|
114 | first.copy(target, toff, this.offset, this.offset + toCopy);
|
---|
115 |
|
---|
116 | toff += toCopy;
|
---|
117 | var left = n - toCopy;
|
---|
118 | for (var i = 1; left > 0 && i < this.buffers.length; i++) {
|
---|
119 | var buf = this.buffers[i];
|
---|
120 | var toCopy = Math.min(left, buf.length);
|
---|
121 |
|
---|
122 | buf.copy(target, toff, 0, toCopy);
|
---|
123 |
|
---|
124 | toff += toCopy;
|
---|
125 | left -= toCopy;
|
---|
126 | }
|
---|
127 | };
|
---|
128 |
|
---|
129 | OffsetBuffer.prototype.take = function take(n) {
|
---|
130 | if (n === 0)
|
---|
131 | return new Buffer(0);
|
---|
132 |
|
---|
133 | this.size -= n;
|
---|
134 |
|
---|
135 | // Fast cases
|
---|
136 | var first = this.buffers[0].length - this.offset;
|
---|
137 | if (first === n) {
|
---|
138 | var r = this.buffers.shift();
|
---|
139 | if (this.offset !== 0) {
|
---|
140 | r = r.slice(this.offset);
|
---|
141 | this.offset = 0;
|
---|
142 | }
|
---|
143 | return r;
|
---|
144 | } else if (first > n) {
|
---|
145 | var r = this.buffers[0].slice(this.offset, this.offset + n);
|
---|
146 | this.offset += n;
|
---|
147 | return r;
|
---|
148 | }
|
---|
149 |
|
---|
150 | // Allocate and fill buffer
|
---|
151 | var out = new Buffer(n);
|
---|
152 | var toOff = 0;
|
---|
153 | var startOff = this.offset;
|
---|
154 | for (var i = 0; toOff !== n && i < this.buffers.length; i++) {
|
---|
155 | var buf = this.buffers[i];
|
---|
156 | var toCopy = Math.min(buf.length - startOff, n - toOff);
|
---|
157 |
|
---|
158 | buf.copy(out, toOff, startOff, startOff + toCopy);
|
---|
159 | if (startOff + toCopy < buf.length) {
|
---|
160 | this.offset = startOff + toCopy;
|
---|
161 | break;
|
---|
162 | } else {
|
---|
163 | toOff += toCopy;
|
---|
164 | startOff = 0;
|
---|
165 | }
|
---|
166 | }
|
---|
167 |
|
---|
168 | this.buffers = this.buffers.slice(i);
|
---|
169 | if (this.buffers.length === 0)
|
---|
170 | this.offset = 0;
|
---|
171 |
|
---|
172 | return out;
|
---|
173 | };
|
---|
174 |
|
---|
175 | OffsetBuffer.prototype.peekUInt8 = function peekUInt8() {
|
---|
176 | return this.buffers[0][this.offset];
|
---|
177 | };
|
---|
178 |
|
---|
179 | OffsetBuffer.prototype.readUInt8 = function readUInt8() {
|
---|
180 | this.size -= 1;
|
---|
181 | var first = this.buffers[0];
|
---|
182 | var r = first[this.offset];
|
---|
183 | if (++this.offset === first.length) {
|
---|
184 | this.offset = 0;
|
---|
185 | this.buffers.shift();
|
---|
186 | }
|
---|
187 |
|
---|
188 | return r;
|
---|
189 | };
|
---|
190 |
|
---|
191 | OffsetBuffer.prototype.readUInt16LE = function readUInt16LE() {
|
---|
192 | var first = this.buffers[0];
|
---|
193 | this.size -= 2;
|
---|
194 |
|
---|
195 | var r;
|
---|
196 | var shift;
|
---|
197 |
|
---|
198 | // Fast case - first buffer has all bytes
|
---|
199 | if (first.length - this.offset >= 2) {
|
---|
200 | r = first.readUInt16LE(this.offset);
|
---|
201 | shift = 0;
|
---|
202 | this.offset += 2;
|
---|
203 |
|
---|
204 | // One byte here - one byte there
|
---|
205 | } else {
|
---|
206 | r = first[this.offset] | (this.buffers[1][0] << 8);
|
---|
207 | shift = 1;
|
---|
208 | this.offset = 1;
|
---|
209 | }
|
---|
210 |
|
---|
211 | if (this.offset === this.buffers[shift].length) {
|
---|
212 | this.offset = 0;
|
---|
213 | shift++;
|
---|
214 | }
|
---|
215 | if (shift !== 0)
|
---|
216 | this.buffers = this.buffers.slice(shift);
|
---|
217 |
|
---|
218 | return r;
|
---|
219 | };
|
---|
220 |
|
---|
221 | OffsetBuffer.prototype.readUInt24LE = function readUInt24LE() {
|
---|
222 | var first = this.buffers[0];
|
---|
223 |
|
---|
224 | var r;
|
---|
225 | var shift;
|
---|
226 | var firstHas = first.length - this.offset;
|
---|
227 |
|
---|
228 | // Fast case - first buffer has all bytes
|
---|
229 | if (firstHas >= 3) {
|
---|
230 | r = first.readUInt16LE(this.offset) | (first[this.offset + 2] << 16);
|
---|
231 | shift = 0;
|
---|
232 | this.offset += 3;
|
---|
233 |
|
---|
234 | // First buffer has 2 of 3 bytes
|
---|
235 | } else if (firstHas >= 2) {
|
---|
236 | r = first.readUInt16LE(this.offset) | (this.buffers[1][0] << 16);
|
---|
237 | shift = 1;
|
---|
238 | this.offset = 1;
|
---|
239 |
|
---|
240 | // Slow case: First buffer has 1 of 3 bytes
|
---|
241 | } else {
|
---|
242 | r = first[this.offset];
|
---|
243 | this.offset = 0;
|
---|
244 | this.buffers.shift();
|
---|
245 | this.size -= 1;
|
---|
246 |
|
---|
247 | r |= this.readUInt16LE() << 8;
|
---|
248 | return r;
|
---|
249 | }
|
---|
250 |
|
---|
251 | this.size -= 3;
|
---|
252 | if (this.offset === this.buffers[shift].length) {
|
---|
253 | this.offset = 0;
|
---|
254 | shift++;
|
---|
255 | }
|
---|
256 | if (shift !== 0)
|
---|
257 | this.buffers = this.buffers.slice(shift);
|
---|
258 |
|
---|
259 | return r;
|
---|
260 | };
|
---|
261 |
|
---|
262 | OffsetBuffer.prototype.readUInt32LE = function readUInt32LE() {
|
---|
263 | var first = this.buffers[0];
|
---|
264 |
|
---|
265 | var r;
|
---|
266 | var shift;
|
---|
267 | var firstHas = first.length - this.offset;
|
---|
268 |
|
---|
269 | // Fast case - first buffer has all bytes
|
---|
270 | if (firstHas >= 4) {
|
---|
271 | r = first.readUInt32LE(this.offset);
|
---|
272 | shift = 0;
|
---|
273 | this.offset += 4;
|
---|
274 |
|
---|
275 | // First buffer has 3 of 4 bytes
|
---|
276 | } else if (firstHas >= 3) {
|
---|
277 | r = (first.readUInt16LE(this.offset) |
|
---|
278 | (first[this.offset + 2] << 16)) +
|
---|
279 | (this.buffers[1][0] * 0x1000000);
|
---|
280 | shift = 1;
|
---|
281 | this.offset = 1;
|
---|
282 |
|
---|
283 | // Slow case: First buffer has 2 of 4 bytes
|
---|
284 | } else if (firstHas >= 2) {
|
---|
285 | r = first.readUInt16LE(this.offset);
|
---|
286 | this.offset = 0;
|
---|
287 | this.buffers.shift();
|
---|
288 | this.size -= 2;
|
---|
289 |
|
---|
290 | r += this.readUInt16LE() * 0x10000;
|
---|
291 | return r;
|
---|
292 |
|
---|
293 | // Slow case: First buffer has 1 of 4 bytes
|
---|
294 | } else {
|
---|
295 | r = first[this.offset];
|
---|
296 | this.offset = 0;
|
---|
297 | this.buffers.shift();
|
---|
298 | this.size -= 1;
|
---|
299 |
|
---|
300 | r += this.readUInt24LE() * 0x100;
|
---|
301 | return r;
|
---|
302 | }
|
---|
303 |
|
---|
304 | this.size -= 4;
|
---|
305 | if (this.offset === this.buffers[shift].length) {
|
---|
306 | this.offset = 0;
|
---|
307 | shift++;
|
---|
308 | }
|
---|
309 | if (shift !== 0)
|
---|
310 | this.buffers = this.buffers.slice(shift);
|
---|
311 |
|
---|
312 | return r;
|
---|
313 | };
|
---|
314 |
|
---|
315 | OffsetBuffer.prototype.readUInt16BE = function readUInt16BE() {
|
---|
316 | var r = this.readUInt16LE();
|
---|
317 |
|
---|
318 | return ((r & 0xff) << 8) | (r >> 8);
|
---|
319 | };
|
---|
320 |
|
---|
321 | OffsetBuffer.prototype.readUInt24BE = function readUInt24BE() {
|
---|
322 | var r = this.readUInt24LE();
|
---|
323 |
|
---|
324 | return ((r & 0xff) << 16) | (((r >> 8) & 0xff) << 8) | (r >> 16);
|
---|
325 | };
|
---|
326 |
|
---|
327 | OffsetBuffer.prototype.readUInt32BE = function readUInt32BE() {
|
---|
328 | var r = this.readUInt32LE();
|
---|
329 |
|
---|
330 | return (((r & 0xff) << 24) |
|
---|
331 | (((r >>> 8) & 0xff) << 16) |
|
---|
332 | (((r >>> 16) & 0xff) << 8) |
|
---|
333 | (r >>> 24)) >>> 0;
|
---|
334 | };
|
---|
335 |
|
---|
336 | // Signed number APIs
|
---|
337 |
|
---|
338 | function signedInt8(num) {
|
---|
339 | if (num >= 0x80)
|
---|
340 | return -(0xff ^ num) - 1;
|
---|
341 | else
|
---|
342 | return num;
|
---|
343 | }
|
---|
344 |
|
---|
345 | OffsetBuffer.prototype.peekInt8 = function peekInt8() {
|
---|
346 | return signedInt8(this.peekUInt8());
|
---|
347 | };
|
---|
348 |
|
---|
349 | OffsetBuffer.prototype.readInt8 = function readInt8() {
|
---|
350 | return signedInt8(this.readUInt8());
|
---|
351 | };
|
---|
352 |
|
---|
353 | function signedInt16(num) {
|
---|
354 | if (num >= 0x8000)
|
---|
355 | return -(0xffff ^ num) - 1;
|
---|
356 | else
|
---|
357 | return num;
|
---|
358 | }
|
---|
359 |
|
---|
360 | OffsetBuffer.prototype.readInt16BE = function readInt16BE() {
|
---|
361 | return signedInt16(this.readUInt16BE());
|
---|
362 | };
|
---|
363 |
|
---|
364 | OffsetBuffer.prototype.readInt16LE = function readInt16LE() {
|
---|
365 | return signedInt16(this.readUInt16LE());
|
---|
366 | };
|
---|
367 |
|
---|
368 | function signedInt24(num) {
|
---|
369 | if (num >= 0x800000)
|
---|
370 | return -(0xffffff ^ num) - 1;
|
---|
371 | else
|
---|
372 | return num;
|
---|
373 | }
|
---|
374 |
|
---|
375 | OffsetBuffer.prototype.readInt24BE = function readInt24BE() {
|
---|
376 | return signedInt24(this.readUInt24BE());
|
---|
377 | };
|
---|
378 |
|
---|
379 | OffsetBuffer.prototype.readInt24LE = function readInt24LE() {
|
---|
380 | return signedInt24(this.readUInt24LE());
|
---|
381 | };
|
---|
382 |
|
---|
383 | function signedInt32(num) {
|
---|
384 | if (num >= 0x80000000)
|
---|
385 | return -(0xffffffff ^ num) - 1;
|
---|
386 | else
|
---|
387 | return num;
|
---|
388 | }
|
---|
389 |
|
---|
390 | OffsetBuffer.prototype.readInt32BE = function readInt32BE() {
|
---|
391 | return signedInt32(this.readUInt32BE());
|
---|
392 | };
|
---|
393 |
|
---|
394 | OffsetBuffer.prototype.readInt32LE = function readInt32LE() {
|
---|
395 | return signedInt32(this.readUInt32LE());
|
---|
396 | };
|
---|