Passed
Push — master ( 786923...ad2d5d )
by Rafael S.
01:25
created

BitReader.read64F   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
nc 1
dl 0
loc 6
rs 9.4285
cc 1
nop 2
1
/**
2
 * type: The Type class.
3
 * Copyright (c) 2017 Rafael da Silva Rocha.
4
 * https://github.com/rochars/byte-data
5
 */
6
7
/** @private */
8
let f32 = new Float32Array(1);
9
/** @private */
10
let i32 = new Int32Array(f32.buffer);
11
/** @private */
12
let f64 = new Float64Array(1);
13
/** @private */
14
let ui32 = new Uint32Array(f64.buffer);
15
16
/**
17
 * Functions to read data from bytes.
18
 * @enum {Function}
19
 */
20
const BitReader = {
21
22
    "read": function(bytes, i, type) {
23
        let num = 0;
24
        let z = 1;
0 ignored issues
show
Unused Code introduced by
The variable z seems to be never used. Consider removing it.
Loading history...
25
        let x = type.offset;
0 ignored issues
show
Unused Code introduced by
The variable x seems to be never used. Consider removing it.
Loading history...
26
        /*
27
        if (type.bits < 33) {
28
            for (let x = type.offset; x > 0; x--) {
29
                if (x > 1) {
30
                    num = bytes[x + i] << ((i - 1) * 8) | num;
31
                } else {
32
                    num = (bytes[i] | num);
33
                }
34
                z++;
35
            }
36
            */
37
        //} else {
38
            num = readBytesAsBits(bytes, i, type.offset);
39
        //}
40
        return num;
41
42
    },
43
44
    /**
45
     * Read 1 16-bit float from from bytes.
46
     * Thanks https://stackoverflow.com/a/8796597
47
     * @param {!Array<number>|Uint8Array} bytes An array of bytes.
48
     * @param {number} i The index to read.
49
     * @return {number}
50
     */
51
    "read16F": function (bytes, i) {
52
        let binary = parseInt(getBinary([bytes[i], bytes[i+1]]), 2);
53
        let exponent = (binary & 0x7C00) >> 10;
54
        let fraction = binary & 0x03FF;
55
        let floatValue;
56
        if (exponent) {
57
            floatValue =  Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
58
        } else {
59
            floatValue = 6.103515625e-5 * (fraction / 0x400);
60
        }
61
        return  floatValue * (binary >> 15 ? -1 : 1);
62
    },
63
64
    /**
65
     * Read 1 32-bit float from from bytes.
66
     * @param {!Array<number>|Uint8Array} bytes An array of bytes.
67
     * @param {number} i The index to read.
68
     * @return {number}
69
     */
70
    "read32F": function (bytes, i) {
71
        i32[0] = BitReader["read"](bytes, i, {"offset": 4});
72
        return f32[0];
73
    },
74
75
    /**
76
     * Read 1 64-bit double from bytes.
77
     * Thanks https://gist.github.com/kg/2192799
78
     * @param {!Array<number>|Uint8Array} bytes An array of bytes.
79
     * @param {number} i The index to read.
80
     * @return {number}
81
     */
82
    "read64F": function (bytes, i) {
83
        let type = {"bits": 32, "offset": 4};
84
        ui32[0] = BitReader["read"](bytes, i, type);
85
        ui32[1] = BitReader["read"](bytes, i + 4, type);
86
        return f64[0];
87
    },
88
89
    /**
90
     * Read 1 char from bytes.
91
     * @param {!Array<number>|Uint8Array} bytes An array of bytes.
92
     * @param {number} i The index to read.
93
     * @param {Object} type The index to read.
94
     * @return {string}
95
     */
96
    "readChar": function (bytes, i, type) {
97
        let chrs = "";
98
        let j = 0;
99
        let len = type.bits / 8;
100
        while(j < len) {
101
            chrs += String.fromCharCode(bytes[i+j]);
102
            j++;
103
        }
104
        return chrs;
105
    }
106
};
107
108
/**
109
 * Functions to write data to bytes.
110
 * @enum {Function}
111
 */
112
let BitWriter = {
113
114
    /**
115
     * Write one 64-bit float as a binary value.
116
     * @param {!Array<number>} bytes An array of bytes.
117
     * @param {number} number The number to write as bytes.
118
     * @param {number} j The index being written in the byte buffer.
119
     * @return {number} The next index to write on the byte buffer.
120
     */
121
    "write64F": function(bytes, number, j) {
122
        f64[0] = number;
123
        let type = {bits: 32, offset: 4, lastByteMask:255};
124
        j = BitWriter["write"](bytes, ui32[0], j, type);
125
        return BitWriter["write"](bytes, ui32[1], j, type);
126
    },
127
128
    /**
129
     * Write one 32-bit float as a binary value.
130
     * @param {!Array<number>} bytes An array of bytes.
131
     * @param {number} number The number to write as bytes.
132
     * @param {number} j The index being written in the byte buffer.
133
     * @param {Object} type The type.
134
     * @return {number} The next index to write on the byte buffer.
135
     */
136
    "write32F": function (bytes, number, j, type) {
137
        f32[0] = number;
138
        j = BitWriter["write"](bytes, i32[0], j, type);
139
        return j;
140
    },
141
142
    /**
143
     * Write one 16-bit float as a binary value.
144
     * @param {!Array<number>} bytes An array of bytes.
145
     * @param {number} number The number to write as bytes.
146
     * @param {number} j The index being written in the byte buffer.
147
     * @return {number} The next index to write on the byte buffer.
148
     */
149
    "write16F": function (bytes, number, j) {
150
        f32[0] = number;
151
        let x = i32[0];
152
        let bits = (x >> 16) & 0x8000;
153
        let m = (x >> 12) & 0x07ff;
154
        let e = (x >> 23) & 0xff;
155
        if (e >= 103) {
156
            bits |= ((e - 112) << 10) | (m >> 1);
157
            bits += m & 1;
158
        }
159
        bytes[j++] = bits & 0xFF;
160
        bytes[j++] = bits >>> 8 & 0xFF;
161
        return j;
162
    },
163
    
164
    /**
165
     * Write one char as a byte.
166
     * @param {!Array<number>} bytes An array of bytes.
167
     * @param {string} string The string to write as bytes.
168
     * @param {number} j The index being written in the byte buffer.
169
     * @return {number} The next index to write on the byte buffer.
170
     */
171
    "writeString": function (bytes, string, j) {
172
        bytes[j++] = string.charCodeAt(0);
173
        return j;
174
    },
175
176
    /**
177
     * Write one char as a byte.
178
     * @param {!Array<number>} bytes An array of bytes.
179
     * @param {number} number The number.
180
     * @param {number} j The index being written in the byte buffer.
181
     * @param {Object} type The type.
182
     * @return {number} The next index to write on the byte buffer.
183
     */
184
    "write": function (bytes, number, j, type) {
185
        let mask = 255;
186
        let len = type.offset;
187
        for (let i = 1; i <= len; i++) {
188
            if (i == 1) {
189
                j = writeFirstByte(bytes, number, j, type);
190
            } else {
191
                if (i == len) {
192
                    mask = type.lastByteMask;
193
                }
194
                bytes[j++] = Math.floor(number / Math.pow(2, ((i - 1) * 8))) & mask;
195
            }
196
        }
197
        return j;
198
    }
199
};
200
201
/**
202
 * Write the first byte of a integer number.
203
 * @param {!Array<number>} bytes An array of bytes.
204
 * @param {number} number The number.
205
 * @param {number} j The index being written in the byte buffer.
206
 * @param {Object} type The type.
207
 * @return {number} The next index to write on the byte buffer.
208
 */
209
function writeFirstByte(bytes, number, j, type) {
210
    if (type.offset == 1 && type.bits < 8) {
211
        bytes[j++] = number < 0 ? number + Math.pow(2, type.bits) : number;
212
    } else {
213
        bytes[j++] = number & 255;
214
    }
215
    return j;
216
}
217
218
/**
219
 * A class to represent byte-data types.
220
 */
221
class Type {
222
223
    /**
224
     * @param {Object} options The type definition.
225
     * @param {number} options.bits Number of bits used by data of this type.
226
     * @param {boolean} options.char True for string/char types.
227
     * @param {boolean} options.float True for float types.
228
     *    Available only for 16, 32 and 64-bit data.
229
     * @param {boolean} options.be True for signed types.
230
     * @param {boolean} options.signed True for signed types.
231
     */
232
    constructor(options) {
233
        /**
234
         * The max number of bits used by data of this type.
235
         * @type {number}
236
         */
237
        this.bits = options["bits"];
238
        /**
239
         * If this type represent floating-point values or not.
240
         * @type {boolean}
241
         */
242
        this.char = options["char"];
243
        /**
244
         * If this type it is signed or not.
245
         * @type {boolean}
246
         */
247
        this.float = options["float"];
248
        /**
249
         * If this type is big-endian or not.
250
         * @type {boolean}
251
         */
252
        this.be = options["be"];
253
        /**
254
         * If this type it is signed or not.
255
         * @type {boolean}
256
         */
257
        this.signed = this.float ? true : options["signed"];
258
        /**
259
         * The function to read values of this type from buffers.
260
         * @type {Function}
261
         */
262
        this.reader = null;
263
        /**
264
         * The function to write values of this type to buffers.
265
         * @type {Function}
266
         */
267
        this.writer = null;
268
        /**
269
         * The number of bytes used by data of this type.
270
         * @type {number}
271
         */
272
        this.offset = 0;
273
        /**
274
         * The base used to represent data of this type.
275
         * Default is 10.
276
         * @type {number}
277
         */
278
        this.base = options["base"] ? options["base"] : 10;
279
        /**
280
         * Min value for numbers of this type.
281
         * @type {number}
282
         */
283
        this.min = -Infinity;
284
        /**
285
         * Max value for numbers of this type.
286
         * @type {number}
287
         */
288
        this.max = Infinity;
289
        this.realBits = this.bits;
290
        this.lastByteMask = 255;
291
        this.build_();
292
    }
293
294
    /**
295
     * Sign a number according to the type.
296
     * @param {number} num The number.
297
     * @return {number}
298
     */
299
    sign(num) {
300
        if (num > this.max) {
301
            num -= (this.max * 2) + 2;
302
        }
303
        return num;
304
    }
305
306
    /**
307
     * Limit the value according to the bit depth in case of
308
     * overflow or underflow.
309
     * @param {number} value The data.
310
     * @return {number}
311
     */
312
    overflow(value) {
313
        if (value > this.max) {
314
            value = this.max;
315
        } else if (value < this.min) {
316
            value = this.min;
317
        }
318
        return value;
319
    }
320
321
    /**
322
     * Build the type.
323
     * @private
324
     */
325
    build_() {
326
        this.setRealBits_();
327
        this.setLastByteMask_();
328
        this.offset = this.bits < 8 ? 1 : Math.ceil(this.realBits / 8);
329
        this.setReader_();
330
        this.setWriter_();
331
        if (!this.float) {
332
            this.setMinMax_();
333
        }
334
    }
335
336
    /**
337
     * Set the function to read data of this type.
338
     * @private
339
     */
340
    setReader_() {
341
        if (this.float) {
342
            this.reader = BitReader[
343
                'read' + this.bits + 'F'];
344
        } else if (this.char) {
345
            this.reader = BitReader["readChar"];
346
        } else {
347
            this.reader = BitReader["read"];
348
        }
349
    }
350
351
    /**
352
     * Set the function to write data of this type.
353
     * @private
354
     */
355
    setWriter_() {
356
        if (this.char) {
357
            this.writer = BitWriter["writeString"];
358
        } else if (this.float) {
359
            this.writer = BitWriter[
360
                'write' + this.realBits + 'F'];
361
        } else {
362
            this.writer = BitWriter["write"];      
363
        }
364
    }
365
366
    /**
367
     * Set the minimum and maximum values for the type.
368
     * @private
369
     */
370
    setMinMax_() {
371
        let max = Math.pow(2, this.bits);
372
        if (this.signed) {
373
            this.max = max / 2 -1;
374
            this.min = -max / 2;
375
        } else {
376
            this.max = max - 1;
377
            this.min = 0;
378
        }
379
    }
380
381
    /**
382
     * Set the real bit depth for data with bit count different from the
383
     * standard types (1, 2, 4, 8, 16, 32, 40, 48, 64): the closest bigger
384
     * standard number of bits. The data is then treated as data of the
385
     * standard type on all aspects except for the min and max values.
386
     * Ex: a 11-bit uInt is treated as 16-bit uInt with a max value of 2048.
387
     * @private
388
     */
389
    setRealBits_() {
390
        if (this.bits > 8) {
391
            if (this.bits <= 16) {
392
                this.realBits = 16;
393
            } else if (this.bits <= 24) {
394
                this.realBits = 24;
395
            } else if (this.bits <= 32) {
396
                this.realBits = 32;
397
            } else if (this.bits <= 40) {
398
                this.realBits = 40;
399
            } else if (this.bits <= 48) {
400
                this.realBits = 48;
401
            } else if (this.bits <= 56) {
402
                this.realBits = 56;
403
            } else {
404
                this.realBits = 64;
405
            }
406
        } else {
407
            this.realBits = this.bits;
408
        }
409
    }
410
411
    /**
412
     * Set the mask that should be used when writing the last byte of
413
     * data of the type.
414
     * @private
415
     */
416
    setLastByteMask_() {
417
        let r = 8 - (this.realBits - this.bits);
418
        this.lastByteMask = Math.pow(2, r > 0 ? r : 8) -1;
419
    }
420
}
421
422
/**
423
 * Get a binary string representation of a value described as bytes.
424
 * @param {Array<number>|number} bytes The bytes.
425
 * @return {string}
426
 */
427
function getBinary(bytes) {
428
    let binary = "";
429
    let i = 0;
430
    let bytesLength = bytes.length;
431
    while(i < bytesLength) {
432
        let bits = bytes[i].toString(2);
433
        binary = Array(9 - bits.length).join("0") + bits + binary;
434
        i++;
435
    }
436
    return binary;
437
}
438
439
/**
440
 * Read a group of bytes by turning it to bits.
441
 * @param {!Array<number>|Uint8Array} bytes An array of bytes.
442
 * @param {number} i The index to read.
443
 * @param {number} numBytes The number of bytes
444
 *      (1 for 8-bit, 2 for 16-bit, etc).
445
 * @return {number}
446
 */
447
function readBytesAsBits(bytes, i, numBytes) {
448
    let j = numBytes-1;
449
    let byte = "";
450
    while (j >= 0) {
451
        let bits = bytes[j + i].toString(2);
452
        byte += Array(9 - bits.length).join("0") + bits;
453
        j--;
454
    }
455
    return parseInt(byte, 2);
456
}
457
458
module.exports = Type;
459