Passed
Push — master ( eac488...a79360 )
by Rafael S.
02:21
created

lib/io.js   A

Size

Lines of Code 1

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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