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
|
};
|