Passed
Push — master ( cd3c12...eac488 )
by Rafael S.
01:51
created

index.js (1 issue)

Severity
1
/*
2
 * byte-data
3
 * Pack and unpack binary data.
4
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
5
 * https://github.com/rochars/byte-data
6
 *
7
 */
8
9
/** @private */
10
const endianness = require("endianness");
11
/** @private */
12
const GenericInteger = require("generic-integer");
13
14
/** @private */
15
let int8 = new Int8Array(4);
16
/** @private */
17
let i32 = new Int32Array(int8.buffer, 0, 1);
18
/** @private */
19
let f32 = new Float32Array(int8.buffer, 0, 1);
20
/** @private */
21
let int8f64 = new Int8Array(8);
22
/** @private */
23
let f64 = new Float64Array(int8f64.buffer);
24
/** @private */
25
let ui32 = new Uint32Array(int8f64.buffer);
26
27
/**
28
 * @type {Function}
29
 * @private
30
 */
31
let reader_;
32
/**
33
 * @type {Function}
34
 * @private
35
 */
36
let writer_;
37
/**
38
 * @type {Object}
39
 * @private
40
 */
41
let gInt_;
42
43
/**
44
 * Write a number or fixed-length string to a byte buffer.
45
 * @param {!number|!string} value The value.
46
 * @param {!Object} type One of the available types.
47
 * @param {!number} base The base of the output. Optional. Default is 10.
48
 *      Possible values are 2, 10 or 16.
49
 * @return {!Array<number|string>}
50
 */
51
function pack(value, type, base=10) {
52
    assureType_(type, base);
53
    if (value.constructor == String) {
54
        return toBytes_(value.slice(0, type["offset"]), type);
55
    }
56
    return toBytes_([value], type);
57
}
58
59
/**
60
 * Read a number or a fixed-length string from a byte buffer.
61
 * @param {!Array<number|string>|!Uint8Array} buffer An array of bytes.
62
 * @param {!Object} type One of the available types.
63
 * @param {!number} base The base of the input. Optional. Default is 10.
64
 *      Possible values are 2, 10 or 16.
65
 * @return {number|string}
66
 */
67
function unpack(buffer, type, base=10) {
68
    assureType_(type, base);
69
    let values = fromBytes_(buffer.slice(0, type["offset"]), type);
70
    if (type["char"]) {
71
        values = values.slice(0, type["offset"]);
72
    } else {
73
        values = values[0];
74
    }
75
    return values;
76
}
77
78
/**
79
 * Write an array of numbers or a string to a byte buffer.
80
 * @param {!Array<number>|string} values The values.
81
 * @param {!Object} type One of the available types.
82
 * @param {!number} base The base of the output. Optional. Default is 10.
83
 *      Possible values are 2, 10 or 16.
84
 * @return {!Array<number|string>}
85
 */
86
function packArray(values, type, base=10) {
87
    assureType_(type, base);
88
    return toBytes_(values, type);
89
}
90
91
/**
92
 * Read an array of numbers or a string from a byte buffer.
93
 * @param {!Array<number|string>|!Uint8Array} buffer The byte array.
94
 * @param {!Object} type One of the available types.
95
 * @param {!number} base The base of the input. Optional. Default is 10.
96
 *      Possible values are 2, 10 or 16.
97
 * @return {!Array<number>|string|number}
98
 */
99
function unpackArray(buffer, type, base=10) {
100
    assureType_(type, base);
101
    return fromBytes_(buffer, type);
102
}
103
104
/**
105
 * Write a struct to a byte buffer.
106
 * A struct is an array of values of not necessarily the same type.
107
 * @param {!Array<number|string>} struct The struct values.
108
 * @param {!Array<!Object>} def The struct type definition.
109
 * @param {!number} base The base of the output. Optional. Default is 10.
110
 *      Possible values are 2, 10 or 16.
111
 * @return {!Array<number|string>}
112
 */
113
function packStruct(struct, def, base=10) {
114
    if (struct.length < def.length) {
115
        return [];
116
    }
117
    let bytes = [];
118
    for (let i = 0; i < def.length; i++) {
119
        bytes = bytes.concat(pack(struct[i], def[i], base));
120
    }
121
    return bytes;
122
}
123
124
/**
125
 * Read a struct from a byte buffer.
126
 * A struct is an array of values of not necessarily the same type.
127
 * @param {!Array<number|string>|!Uint8Array} buffer The byte buffer.
128
 * @param {!Array<!Object>} def The struct type definition.
129
 * @param {!number} base The base of the input. Optional. Default is 10.
130
 *      Possible values are 2, 10 or 16.
131
 * @return {Array<number|string>}
132
 */
133
function unpackStruct(buffer, def, base=10) {
134
    if (buffer.length < getStructDefSize_(def)) {
135
        return [];
136
    }
137
    let struct = [];
138
    let j = 0;
139
    for (let i=0; i < def.length; i++) {
140
        struct = struct.concat(
141
                unpack(buffer.slice(j, j + def[i]["offset"]), def[i], base)
142
            );
143
        j += def[i]["offset"];
144
    }
145
    return struct;
146
}
147
148
/**
149
 * Read int values from bytes.
150
 * @param {!Array<number>|!Uint8Array} bytes An array of bytes.
151
 * @param {!number} i The index to read.
152
 * @return {!number}
153
 * @private
154
 */
155
function readInt_(bytes, i) {
156
    return gInt_.read(bytes, i);
157
}
158
159
/**
160
 * Read 1 16-bit float from bytes.
161
 * Thanks https://stackoverflow.com/a/8796597
162
 * @param {!Array<number>|!Uint8Array} bytes An array of bytes.
163
 * @param {!number} i The index to read.
164
 * @return {!number}
165
 * @private
166
 */
167
function read16F_(bytes, i) {
168
    let int = gInt_.read(bytes, i);
169
    let exponent = (int & 0x7C00) >> 10;
170
    let fraction = int & 0x03FF;
171
    let floatValue;
172
    if (exponent) {
173
        floatValue =  Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
174
    } else {
175
        floatValue = 6.103515625e-5 * (fraction / 0x400);
176
    }
177
    return floatValue * (int >> 15 ? -1 : 1);
178
}
179
180
/**
181
 * Read 1 32-bit float from bytes.
182
 * @param {!Array<number>|!Uint8Array} bytes An array of bytes.
183
 * @param {!number} i The index to read.
184
 * @return {!number}
185
 * @private
186
 */
187
function read32F_(bytes, i) {
188
    i32[0] = gInt_.read(bytes, i);
189
    return f32[0];
190
}
191
192
/**
193
 * Read 1 64-bit double from bytes.
194
 * Thanks https://gist.github.com/kg/2192799
195
 * @param {!Array<number>|!Uint8Array} bytes An array of bytes.
196
 * @param {!number} i The index to read.
197
 * @return {!number}
198
 * @private
199
 */
200
function read64F_(bytes, i) {
201
    ui32[0] = gInt_.read(bytes, i);
202
    ui32[1] = gInt_.read(bytes, i + 4);
203
    return f64[0];
204
}
205
206
/**
207
 * Read 1 char from bytes.
208
 * @param {!Array<number>|!Uint8Array} bytes An array of bytes.
209
 * @param {!number} i The index to read.
210
 * @return {!string}
211
 * @private
212
 */
213
function readChar_(bytes, i) {
214
    let chrs = "";
215
    for(let j=0; j < gInt_.offset; j++) {
216
        chrs += String.fromCharCode(bytes[i+j]);
217
    }
218
    return chrs;
219
}
220
221
/**
222
 * Write a integer value to a byte buffer.
223
 * @param {!Array<number>} bytes An array of bytes.
224
 * @param {!number} number The number to write as bytes.
225
 * @param {!number} j The index being written in the byte buffer.
226
 * @return {!number} The next index to write on the byte buffer.
227
 * @private
228
 */
229
function writeInt_(bytes, number, j) {
230
    return gInt_.write(bytes, number, j);
231
}
232
233
/**
234
 * Write one 16-bit float as a binary value.
235
 * @param {!Array<number>} bytes An array of bytes.
236
 * @param {!number} number The number to write as bytes.
237
 * @param {!number} j The index being written in the byte buffer.
238
 * @return {!number} The next index to write on the byte buffer.
239
 * @private
240
 */
241
function write16F_(bytes, number, j) {
242
    f32[0] = number;
243
    let x = i32[0];
244
    let bits = (x >> 16) & 0x8000;
245
    let m = (x >> 12) & 0x07ff;
246
    let e = (x >> 23) & 0xff;
247
    if (e >= 103) {
248
        bits |= ((e - 112) << 10) | (m >> 1);
249
        bits += m & 1;
250
    }
251
    bytes[j++] = bits & 0xFF;
252
    bytes[j++] = bits >>> 8 & 0xFF;
253
    return j;
254
}
255
256
/**
257
 * Write one 32-bit float as a binary value.
258
 * @param {!Array<number>} bytes An array of bytes.
259
 * @param {!number} number The number to write as bytes.
260
 * @param {!number} j The index being written in the byte buffer.
261
 * @return {!number} The next index to write on the byte buffer.
262
 * @private
263
 */
264
function write32F_(bytes, number, j) {
265
    f32[0] = number;
266
    j = gInt_.write(bytes, i32[0], j);
267
    return j;
268
}
269
270
/**
271
 * Write one 64-bit float as a binary value.
272
 * @param {!Array<number>} bytes An array of bytes.
273
 * @param {!number} number The number to write as bytes.
274
 * @param {!number} j The index being written in the byte buffer.
275
 * @return {!number} The next index to write on the byte buffer.
276
 * @private
277
 */
278
function write64F_(bytes, number, j) {
279
    f64[0] = number;
280
    j = gInt_.write(bytes, ui32[0], j);
281
    return gInt_.write(bytes, ui32[1], j);
282
}
283
284
/**
285
 * Write one char as a byte.
286
 * @param {!Array<number>} bytes An array of bytes.
287
 * @param {!string} string The string to write as bytes.
288
 * @param {!number} j The index being written in the byte buffer.
289
 * @return {!number} The next index to write on the byte buffer.
290
 * @private
291
 */
292
function writeChar_(bytes, string, j) {
293
    bytes[j++] = string.charCodeAt(0);
294
    return j;
295
}
296
297
/**
298
 * Get the length in bytes of a struct definition.
299
 * @param {!Array<Object>} def The struct type definition.
300
 * @return {!number} The length of the structure in bytes.
301
 * @private
302
 */
303
function getStructDefSize_(def) {
304
    let bits = 0;
305
    for (let i = 0; i < def.length; i++) {
306
        bits += def[i]["offset"];
307
    }
308
    return bits;
309
}
310
311
/**
312
 * Turn a byte buffer into what the bytes represent.
313
 * @param {!Array<number|string>|!Uint8Array} buffer An array of bytes.
314
 * @param {!Object} type One of the available types.
315
 * @return {!Array<number>|number|string}
316
 * @private
317
 */
318
function fromBytes_(buffer, type) {
319
    if (type["be"]) {
320
        endianness(buffer, type["offset"]);
321
    }
322
    if (type["base"] != 10) {
323
        bytesFromBase_(buffer, type["base"]);
324
    }
325
    return readBytes_(buffer, type);
326
}
327
328
/**
329
 * Turn numbers and strings to bytes.
330
 * @param {!Array<!number|!string>|string} values The data.
331
 * @param {Object} type One of the available types.
332
 * @return {!Array<number|string>} the data as a byte buffer.
333
 * @private
334
 */
335
function toBytes_(values, type) {
336
    let bytes = writeBytes_(values, type);
337
    if (type["be"]) {
338
        endianness(bytes, type["offset"]);
339
    }
340
    if (type["base"] != 10) {
341
        bytes = bytesToBase_(bytes, type["base"]);
342
        formatOutput_(bytes, type);
343
    }
344
    return bytes;
345
}
346
347
/**
348
 * Read values from an array of bytes.
349
 * @param {!Array<!number>|!Uint8Array} bytes An array of bytes.
350
 * @param {!Object} type The type.
351
 * @return {!Array<!number>|string}
352
 * @private
353
 */
354
function readBytes_(bytes, type) {
355
    let values = [];
356
    let i = 0;
357
    let len = bytes.length - (type["offset"] - 1);
358
    while (i < len) {
359
        values.push(reader_(bytes, i));
360
        i += type["offset"];
361
    }
362
    if (type["char"]) {
363
        values = values.join("");
364
    }
365
    return values;
366
}
367
368
/**
369
 * Write values as bytes.
370
 * @param {!Array<number|string>|string} values The data.
371
 * @param {Object} type One of the available types.
372
 * @return {!Array<number>} the bytes.
373
 * @private
374
 */
375
function writeBytes_(values, type) {
0 ignored issues
show
The parameter type is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
376
    let j = 0;
377
    let bytes = [];
378
    for(let i=0; i < values.length; i++) {
379
        j = writer_(bytes, values[i], j);
380
    }
381
    return bytes;
382
}
383
384
/**
385
 * Fill a byte string with zeros on the left.
386
 * @param {!Array<!string>} bytes The bytes.
387
 * @param {!Object} type The type.
388
 * @private
389
 */
390
function formatOutput_(bytes, type) {
391
    let offset = (type["base"] == 2 ? 8 : 2) + 1;
392
    for(let i =0; i < bytes.length; i++) {
393
        bytes[i] = Array(offset - bytes[i].length).join("0") + bytes[i];
394
    }
395
}
396
397
/**
398
 * Turn bytes to base 10 from base 2 or 16.
399
 * @param {!Array<number>|Uint8Array} bytes The bytes as binary or hex strings.
400
 * @param {!number} base The base.
401
 * @private
402
 */
403
function bytesFromBase_(bytes, base) {
404
    for(let i=0; i < bytes.length; i++) {
405
        bytes[i] = parseInt(bytes[i], base);
406
    }
407
}
408
409
/**
410
 * Turn bytes from base 10 to base 2 or 16.
411
 * @param {!Array<string|number>} bytes The bytes.
412
 * @param {!number} base The base.
413
 * @return {!Array<!string>}
414
 * @private
415
 */
416
function bytesToBase_(bytes, base) {
417
    for(let i=0; i < bytes.length; i++) {
418
        bytes[i] = bytes[i].toString(base);
419
    }
420
    return bytes;
421
}
422
423
/**
424
 * @param {!Object} type The type definition.
425
 * @param {!number} base The base.
426
 * @private
427
 */
428
function assureType_(type, base) {
429
    type["offset"] = type["bits"] < 8 ? 1 : Math.ceil(type["bits"] / 8);
430
    type["base"] = base;
431
    setReader_(type);
432
    setWriter_(type);
433
    setGenericInteger_(type);
434
}
435
436
/**
437
 * @param {!Object} type The type definition.
438
 * @private
439
 */
440
function setGenericInteger_(type) {
441
    if (type["float"]) {
442
        if (type["bits"] == 64) {
443
            gInt_ = new GenericInteger(32, false);
444
        } else if(type["bits"] == 32) {
445
            gInt_ = new GenericInteger(32, true);
446
        } else {
447
            gInt_ = new GenericInteger(16, false);
448
        }
449
    } else {
450
        gInt_ = new GenericInteger(type["bits"], type["signed"]);
451
    }
452
}
453
454
/**
455
 * Set the function to read data of this type.
456
 * @param {!Object} type The type definition.
457
 * @private
458
 */
459
function setReader_(type) {
460
    if (type["float"]) {
461
        if (type["bits"] == 16) {
462
            reader_ = read16F_;
463
        } else if(type["bits"] == 32) {
464
            reader_ = read32F_;
465
        } else if(type["bits"] == 64) {
466
            reader_ = read64F_;
467
        }
468
    } else if (type["char"]) {
469
        reader_ = readChar_;
470
    } else {
471
        reader_ = readInt_;
472
    }
473
}
474
475
/**
476
 * Set the function to write data of this type.
477
 * @param {!Object} type The type definition.
478
 * @private
479
 */
480
function setWriter_(type) {
481
    if (type["float"]) {
482
        if (type["bits"] == 16) {
483
            writer_ = write16F_;
484
        } else if(type["bits"] == 32) {
485
            writer_ = write32F_;
486
        } else if(type["bits"] == 64) {
487
            writer_ = write64F_;
488
        }
489
    } else if (type["char"]) {
490
        writer_ = writeChar_;
491
    } else {
492
        writer_ = writeInt_;
493
    }   
494
}
495
496
// interface
497
module.exports.pack = pack;
498
module.exports.unpack = unpack;
499
module.exports.packArray = packArray;
500
module.exports.unpackArray = unpackArray;
501
module.exports.unpackStruct = unpackStruct;
502
module.exports.packStruct = packStruct;
503
504
/** 
505
 * A char.
506
 * @type {Object}
507
 */
508
module.exports.chr = {"bits": 8, "char": true};
509
/**
510
 * A 4-char string
511
 * @type {Object}
512
 */
513
module.exports.fourCC = {"bits": 32, "char": true};
514
/**
515
 * Booleans
516
 * @type {Object}
517
 */
518
module.exports.bool = {"bits": 1};
519
/**
520
 * Signed 2-bit integers
521
 * @type {Object}
522
 */
523
module.exports.int2 = {"bits": 2, "signed": true};
524
/**
525
 * Unsigned 2-bit integers
526
 * @type {Object}
527
 */
528
module.exports.uInt2 = {"bits": 2};
529
/**
530
 * Signed 4-bit integers
531
 * @type {Object}
532
 */
533
module.exports.int4 = {"bits": 4, "signed": true};
534
/**
535
 * Unsigned 4-bit integers
536
 * @type {Object}
537
 */
538
module.exports.uInt4 = {"bits": 4};
539
/**
540
 * Signed 8-bit integers
541
 * @type {Object}
542
 */
543
module.exports.int8 = {"bits": 8, "signed": true};
544
/**
545
 * Unsigned 4-bit integers
546
 * @type {Object}
547
 */
548
module.exports.uInt8 = {"bits": 8};
549
// LE
550
/**
551
 * Signed 16-bit integers little-endian
552
 * @type {Object}
553
 */
554
module.exports.int16  = {"bits": 16, "signed": true};
555
/**
556
 * Unsigned 16-bit integers little-endian
557
 * @type {Object}
558
 */
559
module.exports.uInt16 = {"bits": 16};
560
/**
561
 * Half-precision floating-point numbers little-endian
562
 * @type {Object}
563
 */
564
module.exports.float16 = {"bits": 16, "float": true};
565
/**
566
 * Signed 24-bit integers little-endian
567
 * @type {Object}
568
 */
569
module.exports.int24 = {"bits": 24, "signed": true};
570
/**
571
 * Unsigned 24-bit integers little-endian
572
 * @type {Object}
573
 */
574
module.exports.uInt24 = {"bits": 24};
575
/**
576
 * Signed 32-bit integers little-endian
577
 * @type {Object}
578
 */
579
module.exports.int32 = {"bits": 32, "signed": true};
580
/**
581
 * Unsigned 32-bit integers little-endian
582
 * @type {Object}
583
 */
584
module.exports.uInt32 = {"bits": 32};
585
/**
586
 * Single-precision floating-point numbers little-endian
587
 * @type {Object}
588
 */
589
module.exports.float32 = {"bits": 32, "float": true};
590
/**
591
 * Signed 40-bit integers little-endian
592
 * @type {Object}
593
 */
594
module.exports.int40 = {"bits": 40, "signed": true};
595
/**
596
 * Unsigned 40-bit integers little-endian
597
 * @type {Object}
598
 */
599
module.exports.uInt40 = {"bits": 40};
600
/**
601
 * Signed 48-bit integers little-endian
602
 * @type {Object}
603
 */
604
module.exports.int48 = {"bits": 48, "signed": true};
605
/**
606
 * Unsigned 48-bit integers little-endian
607
 * @type {Object}
608
 */
609
module.exports.uInt48 = {"bits": 48};
610
/**
611
 * Double-precision floating-point numbers little-endian
612
 * @type {Object}
613
 */
614
module.exports.float64 = {"bits": 64, "float": true};
615
// BE
616
/**
617
 * Signed 16-bit integers big-endian
618
 * @type {Object}
619
 */
620
module.exports.int16BE  = {"bits": 16, "signed": true, "be": true};
621
/**
622
 * Unsigned 16-bit integers big-endian
623
 * @type {Object}
624
 */
625
module.exports.uInt16BE = {"bits": 16, "be": true};
626
/**
627
 * Half-precision floating-point numbers big-endian
628
 * @type {Object}
629
 */
630
module.exports.float16BE = {"bits": 16, "float": true, "be": true};
631
/**
632
 * Signed 24-bit integers big-endian
633
 * @type {Object}
634
 */
635
module.exports.int24BE = {"bits": 24, "signed": true, "be": true};
636
/**
637
 * Unsigned 24-bit integers big-endian
638
 * @type {Object}
639
 */
640
module.exports.uInt24BE = {"bits": 24, "be": true};
641
/**
642
 * Signed 32-bit integers big-endian
643
 * @type {Object}
644
 */
645
module.exports.int32BE = {"bits": 32, "signed": true, "be": true};
646
/**
647
 * Unsigned 32-bit integers big-endian
648
 * @type {Object}
649
 */
650
module.exports.uInt32BE = {"bits": 32, "be": true};
651
/**
652
 * Single-precision floating-point numbers big-endian
653
 * @type {Object}
654
 */
655
module.exports.float32BE = {"bits": 32, "float": true, "be": true};
656
/**
657
 * Signed 40-bit integers big-endian
658
 * @type {Object}
659
 */
660
module.exports.int40BE = {"bits": 40, "signed": true, "be": true};
661
/**
662
 * Unsigned 40-bit integers big-endian
663
 * @type {Object}
664
 */
665
module.exports.uInt40BE = {"bits": 40, "be": true};
666
/**
667
 * Signed 48-bit integers big-endian
668
 * @type {Object}
669
 */
670
module.exports.int48BE = {"bits": 48, "signed": true, "be": true};
671
/**
672
 * Unsigned 48-bit integers big-endian
673
 * @type {Object}
674
 */
675
module.exports.uInt48BE = {"bits": 48, "be": true};
676
/**
677
 * Double-precision floating-point numbers big-endian
678
 * @type {Object}
679
 */
680
module.exports.float64BE = {"bits": 64, "float": true, "be": true};
681