bireader 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/index.js +6 -0
- package/package.json +34 -0
- package/src/reader.js +913 -0
- package/src/writer.js +524 -0
package/src/reader.js
ADDED
|
@@ -0,0 +1,913 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* byte reader, includes bitfields and strings
|
|
4
|
+
*
|
|
5
|
+
* @param {Buffer|Uint8Array} data - ```Buffer``` or ```Uint8Array```
|
|
6
|
+
* @param {number} byteoffset - byte offset to start reader, default is 0
|
|
7
|
+
* @param {number} bitoffset - bit offset to start reader, 0-7
|
|
8
|
+
* @param endianness - endianness ```big``` or ```little``` (default ```little```)
|
|
9
|
+
* @returns ```number``` or ```string```
|
|
10
|
+
*/
|
|
11
|
+
class bireader {
|
|
12
|
+
endian = "little";
|
|
13
|
+
offset = 0;
|
|
14
|
+
bitoffset = 0;
|
|
15
|
+
size = 0
|
|
16
|
+
data;
|
|
17
|
+
|
|
18
|
+
#check_size = function(read_size){
|
|
19
|
+
if(this.bitoffset != 0){
|
|
20
|
+
//droped bits
|
|
21
|
+
const new_off = Math.ceil(this.bitoffset / 8)
|
|
22
|
+
this.offset = this.offset + new_off
|
|
23
|
+
}
|
|
24
|
+
if((this.offset + read_size) > this.size){
|
|
25
|
+
throw new Error(`Reader reached end of data.`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* byte reader, includes bitfields and strings
|
|
32
|
+
*
|
|
33
|
+
* @param {Buffer|Uint8Array} data - ```Buffer``` or ```Uint8Array```
|
|
34
|
+
* @param {number} byteoffset - byte offset to start reader, default is 0
|
|
35
|
+
* @param {number} bitoffset - bit offset to start reader, 0-7
|
|
36
|
+
* @param endianness - endianness ```big``` or ```little``` (default ```little```)
|
|
37
|
+
* @returns ```number``` or ```string```
|
|
38
|
+
*/
|
|
39
|
+
constructor(data, byteoffset, bitoffset, endianness) {
|
|
40
|
+
if(endianness != undefined && typeof endianness != "string"){
|
|
41
|
+
throw Error("endianness must be big or little")
|
|
42
|
+
}
|
|
43
|
+
if(endianness != undefined && !(endianness == "big" || endianness == "little")){
|
|
44
|
+
throw Error("byteorder must be big or little")
|
|
45
|
+
}
|
|
46
|
+
this.endian = endianness || "little"
|
|
47
|
+
|
|
48
|
+
if(byteoffset != undefined ){
|
|
49
|
+
if(typeof byteoffset == "number"){
|
|
50
|
+
this.offset = Math.round(byteoffset) || 0
|
|
51
|
+
} else {
|
|
52
|
+
throw Error("Byteoffset must be number")
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if(bitoffset!= undefined){
|
|
56
|
+
this.bitoffset = (bitoffset % 8)
|
|
57
|
+
}
|
|
58
|
+
if(data == undefined){
|
|
59
|
+
throw Error("Data required")
|
|
60
|
+
} else {
|
|
61
|
+
this.size = data.length + ((bitoffset || 0) % 8)
|
|
62
|
+
this.data = data
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
endianness = function(order){
|
|
67
|
+
if(order == undefined || typeof order != "string"){
|
|
68
|
+
throw Error("endianness must be big or little")
|
|
69
|
+
}
|
|
70
|
+
if(order != undefined && !(order == "big" || order == "little")){
|
|
71
|
+
throw Error("byteorder must be big or little")
|
|
72
|
+
}
|
|
73
|
+
this.endian = order
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* @param {number} offset - bytes to skip
|
|
79
|
+
*/
|
|
80
|
+
seek = function(offset){
|
|
81
|
+
this.#check_size(offset)
|
|
82
|
+
this.offset += offset
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
*
|
|
87
|
+
* @param {number} offset - byte to jump to
|
|
88
|
+
*/
|
|
89
|
+
goto = function(loc){
|
|
90
|
+
if(loc > this.size){
|
|
91
|
+
throw Error("goto outside of size of data")
|
|
92
|
+
}
|
|
93
|
+
this.offset = loc
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* bit field reader
|
|
99
|
+
*
|
|
100
|
+
* Note: When returning to a byte read, remaining bits are dropped
|
|
101
|
+
*
|
|
102
|
+
* @param {number} numBitsToRead - bits to read
|
|
103
|
+
* @returns number
|
|
104
|
+
*/
|
|
105
|
+
readBit = function(numBitsToRead, endian){
|
|
106
|
+
if(numBitsToRead == undefined || typeof numBitsToRead != "number"){
|
|
107
|
+
throw Error("Enter number of bits to read")
|
|
108
|
+
}
|
|
109
|
+
const size_needed = ((((numBitsToRead-1) + this.bitoffset) / 8) + this.offset)
|
|
110
|
+
if (numBitsToRead <= 0 || size_needed > this.size) {
|
|
111
|
+
throw new Error("Invalid number of bits to read: " + size_needed + " of " + this.size);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let result = "0b";
|
|
115
|
+
let startByteIndex = this.offset //cur byte
|
|
116
|
+
let endByteIndex = this.offset + Math.floor(((numBitsToRead-1) + this.bitoffset) / 8) //end byte
|
|
117
|
+
let bytesToRead = (endByteIndex - startByteIndex) + 1 //at least 1
|
|
118
|
+
let startBitIndex = this.bitoffset
|
|
119
|
+
let endBitIndex = ((numBitsToRead-1) + this.bitoffset)+1
|
|
120
|
+
let bitArray = []
|
|
121
|
+
|
|
122
|
+
let startByteIndexI = endByteIndex
|
|
123
|
+
|
|
124
|
+
//big backwards read
|
|
125
|
+
do {
|
|
126
|
+
var element = this.data[startByteIndexI];
|
|
127
|
+
element = element.toString(2).padStart(8, '0').split('')
|
|
128
|
+
if(endian == "little"){
|
|
129
|
+
element = element.reverse()
|
|
130
|
+
}
|
|
131
|
+
bitArray.push(element)
|
|
132
|
+
startByteIndexI--
|
|
133
|
+
bytesToRead--
|
|
134
|
+
} while (bytesToRead != 0);
|
|
135
|
+
if(endian == "big"){
|
|
136
|
+
bitArray = bitArray.reverse()
|
|
137
|
+
}
|
|
138
|
+
bitArray = bitArray.flat()
|
|
139
|
+
// console.log(bitArray)
|
|
140
|
+
bitArray = bitArray.slice(startBitIndex,endBitIndex)
|
|
141
|
+
|
|
142
|
+
this.offset = this.offset + Math.floor(((numBitsToRead) + this.bitoffset) / 8) //end byte
|
|
143
|
+
this.bitoffset = ((numBitsToRead) + this.bitoffset) % 8
|
|
144
|
+
|
|
145
|
+
result = result + bitArray.join("")
|
|
146
|
+
|
|
147
|
+
return Number(result);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
*
|
|
152
|
+
* bit field reader
|
|
153
|
+
*
|
|
154
|
+
* Note: When returning to a byte read, remaining bits are dropped
|
|
155
|
+
*
|
|
156
|
+
* @param {number} bits - bits to read
|
|
157
|
+
* @returns number
|
|
158
|
+
*/
|
|
159
|
+
bit = function(bits){
|
|
160
|
+
return this.readBit(bits, this.endian)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
*
|
|
165
|
+
* bit field reader
|
|
166
|
+
*
|
|
167
|
+
* Note: When returning to a byte read, remaining bits are dropped
|
|
168
|
+
*
|
|
169
|
+
* @param {number} bits - bits to read
|
|
170
|
+
* @returns number
|
|
171
|
+
*/
|
|
172
|
+
readBitBE = function(bits){
|
|
173
|
+
return this.readBit(bits, "big")
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
*
|
|
178
|
+
* bit field reader
|
|
179
|
+
*
|
|
180
|
+
* Note: When returning to a byte read, remaining bits are dropped
|
|
181
|
+
*
|
|
182
|
+
* @param {number} bits - bits to read
|
|
183
|
+
* @returns number
|
|
184
|
+
*/
|
|
185
|
+
bitbe = function(bits){
|
|
186
|
+
return this.readBit(bits, "big")
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
*
|
|
191
|
+
* bit field reader
|
|
192
|
+
*
|
|
193
|
+
* Note: When returning to a byte read, remaining bits are dropped
|
|
194
|
+
*
|
|
195
|
+
* @param {number} bits - bits to read
|
|
196
|
+
* @returns number
|
|
197
|
+
*/
|
|
198
|
+
bitle = function(bits){
|
|
199
|
+
return this.readBit(bits, "little")
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
*
|
|
204
|
+
* bit field reader
|
|
205
|
+
*
|
|
206
|
+
* Note: When returning to a byte read, remaining bits are dropped
|
|
207
|
+
*
|
|
208
|
+
* @param {number} bits - bits to read
|
|
209
|
+
* @returns number
|
|
210
|
+
*/
|
|
211
|
+
readBitLE = function(bits){
|
|
212
|
+
return this.readBit(bits, "little")
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
//byte read
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @returns number
|
|
219
|
+
*/
|
|
220
|
+
readByte = function(signed){
|
|
221
|
+
this.#check_size(1)
|
|
222
|
+
const read = (this.data[this.offset])
|
|
223
|
+
this.offset += 1
|
|
224
|
+
if(signed){
|
|
225
|
+
return read
|
|
226
|
+
} else {
|
|
227
|
+
return read & 0xFF
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @returns number
|
|
233
|
+
*/
|
|
234
|
+
readUByte = function(){
|
|
235
|
+
return this.readByte(true)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @returns number
|
|
240
|
+
*/
|
|
241
|
+
ubyte = function(){
|
|
242
|
+
return this.readByte(true)
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* @returns number
|
|
246
|
+
*/
|
|
247
|
+
byte = function(){
|
|
248
|
+
return this.readByte(false)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @returns number
|
|
253
|
+
*/
|
|
254
|
+
uint8 = function(){
|
|
255
|
+
return this.readByte(true)
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* @returns number
|
|
259
|
+
*/
|
|
260
|
+
int8 = function(){
|
|
261
|
+
return this.readByte(false)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
//short16 read
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @returns number
|
|
268
|
+
*/
|
|
269
|
+
readInt16LE = function(signed){
|
|
270
|
+
this.#check_size(2)
|
|
271
|
+
const read = (this.data[this.offset + 1] << 8) | this.data[this.offset];
|
|
272
|
+
this.offset += 2
|
|
273
|
+
if(signed){
|
|
274
|
+
return read
|
|
275
|
+
} else {
|
|
276
|
+
return read & 0xFFFF
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @returns number
|
|
282
|
+
*/
|
|
283
|
+
readInt16BE = function(signed){
|
|
284
|
+
this.#check_size(2)
|
|
285
|
+
const read = (this.data[this.offset] << 8) | this.data[this.offset + 1];
|
|
286
|
+
this.offset += 2
|
|
287
|
+
if(signed){
|
|
288
|
+
return read
|
|
289
|
+
} else {
|
|
290
|
+
return read & 0xFFFF
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* @returns number
|
|
296
|
+
*/
|
|
297
|
+
readUInt16 = function(){
|
|
298
|
+
if(this.endian == "little"){
|
|
299
|
+
return this.readInt16LE(true)
|
|
300
|
+
} else {
|
|
301
|
+
return this.readInt16BE(true)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @returns number
|
|
307
|
+
*/
|
|
308
|
+
readInt16 = function(){
|
|
309
|
+
if(this.endian == "little"){
|
|
310
|
+
return this.readInt16LE(false)
|
|
311
|
+
} else {
|
|
312
|
+
return this.readInt16BE(false)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @returns number
|
|
318
|
+
*/
|
|
319
|
+
readUShort = function(){
|
|
320
|
+
return this.readUInt16()
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* @returns number
|
|
325
|
+
*/
|
|
326
|
+
readShort = function(){
|
|
327
|
+
return this.readInt16()
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @returns number
|
|
332
|
+
*/
|
|
333
|
+
ushort = function(){
|
|
334
|
+
return this.readUInt16()
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @returns number
|
|
339
|
+
*/
|
|
340
|
+
short = function (){
|
|
341
|
+
return this.readInt16()
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @returns number
|
|
346
|
+
*/
|
|
347
|
+
uint16 = function(){
|
|
348
|
+
return this.readUInt16()
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @returns number
|
|
353
|
+
*/
|
|
354
|
+
int16 = function (){
|
|
355
|
+
return this.readInt16()
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
//int read
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* @returns number
|
|
362
|
+
*/
|
|
363
|
+
readInt32LE = function(signed){
|
|
364
|
+
this.#check_size(4)
|
|
365
|
+
const read = ((this.data[this.offset + 3] << 24) | (this.data[this.offset + 2] << 16) | (this.data[this.offset + 1] << 8) | this.data[this.offset])
|
|
366
|
+
this.offset += 4
|
|
367
|
+
if(signed){
|
|
368
|
+
return read
|
|
369
|
+
} else {
|
|
370
|
+
return read >>> 0
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @returns number
|
|
376
|
+
*/
|
|
377
|
+
readInt32BE = function(signed){
|
|
378
|
+
this.#check_size(4)
|
|
379
|
+
const read = (this.data[this.offset] << 24) | (this.data[this.offset + 1] << 16) | (this.data[this.offset + 2] << 8) | this.data[this.offset + 3]
|
|
380
|
+
this.offset += 4
|
|
381
|
+
if(signed){
|
|
382
|
+
return read
|
|
383
|
+
} else {
|
|
384
|
+
return read >>> 0
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @returns number
|
|
390
|
+
*/
|
|
391
|
+
readUInt32 = function(){
|
|
392
|
+
if(this.endian == "little"){
|
|
393
|
+
return this.readInt32LE(true)
|
|
394
|
+
} else {
|
|
395
|
+
return this.readInt32BE(true)
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @returns number
|
|
401
|
+
*/
|
|
402
|
+
readInt32 = function(){
|
|
403
|
+
if(this.endian == "little"){
|
|
404
|
+
return this.readInt32LE(false)
|
|
405
|
+
} else {
|
|
406
|
+
return this.readInt32BE(false)
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* @returns number
|
|
412
|
+
*/
|
|
413
|
+
readUInt = function(){
|
|
414
|
+
return this.readUInt32()
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* @returns number
|
|
419
|
+
*/
|
|
420
|
+
readInt = function(){
|
|
421
|
+
return this.readInt32()
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* @returns number
|
|
426
|
+
*/
|
|
427
|
+
int = function(){
|
|
428
|
+
return this.readInt32()
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* @returns number
|
|
433
|
+
*/
|
|
434
|
+
uint = function(){
|
|
435
|
+
return this.readUInt32()
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
//string reader
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* inculde length or reads until 0 byte
|
|
442
|
+
* can include terminate character (as number), defaults to 0
|
|
443
|
+
* @param {number} length - number
|
|
444
|
+
* @param {any} terminateValue - number
|
|
445
|
+
* @returns string
|
|
446
|
+
*/
|
|
447
|
+
string = function(length,terminateValue){
|
|
448
|
+
var terminate = 0
|
|
449
|
+
if(length != undefined){
|
|
450
|
+
this.#check_size(length)
|
|
451
|
+
}
|
|
452
|
+
if(typeof terminateValue == "number"){
|
|
453
|
+
terminate = terminateValue & 0xFF
|
|
454
|
+
}
|
|
455
|
+
if (length === undefined) {
|
|
456
|
+
let currentString = '';
|
|
457
|
+
|
|
458
|
+
for (let i = this.offset; i < this.size; i++) {
|
|
459
|
+
const byte = this.readUByte();
|
|
460
|
+
if (byte != terminate) {
|
|
461
|
+
currentString += String.fromCharCode(byte);
|
|
462
|
+
} else {
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return currentString;
|
|
467
|
+
} else {
|
|
468
|
+
// If a length is specified, read that many bytes
|
|
469
|
+
const string = String.fromCharCode.apply(null, this.data.slice(this.offset, this.offset+length))
|
|
470
|
+
this.offset += length
|
|
471
|
+
return string;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* inculde length or reads until 0 byte
|
|
477
|
+
* can include terminate character (as number), defaults to 0
|
|
478
|
+
* @param {number} length - number
|
|
479
|
+
* @param {any} terminateValue - number
|
|
480
|
+
* @returns string
|
|
481
|
+
*/
|
|
482
|
+
readString = function(length,terminateValue){
|
|
483
|
+
return this.string(length,terminateValue)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* can switch byte order on demand, default to set endianness
|
|
488
|
+
* inculde length in bytes or reads until 0 short
|
|
489
|
+
* can include terminate character (as number), defaults to 0
|
|
490
|
+
* @param {number} byteorder - number
|
|
491
|
+
* @param {number} length - number
|
|
492
|
+
* @param {any} terminateValue - number
|
|
493
|
+
* @returns string
|
|
494
|
+
*/
|
|
495
|
+
string16 = function(byteorder,length,terminateValue){
|
|
496
|
+
var terminate = 0x0000
|
|
497
|
+
if(length != undefined){
|
|
498
|
+
this.#check_size(length)
|
|
499
|
+
}
|
|
500
|
+
if(typeof terminateValue == "number"){
|
|
501
|
+
terminate = terminateValue & 0xFFFF
|
|
502
|
+
}
|
|
503
|
+
if(byteorder != undefined && !(byteorder == "big" || byteorder == "little")){
|
|
504
|
+
throw Error("byteorder must be big or little")
|
|
505
|
+
}
|
|
506
|
+
if (length == undefined) {
|
|
507
|
+
let currentString = '';
|
|
508
|
+
|
|
509
|
+
for (let i = this.offset; i < this.size; i += 2) {
|
|
510
|
+
var short = terminateValue;
|
|
511
|
+
var endian = byteorder || this.endian
|
|
512
|
+
if(endian == "big"){
|
|
513
|
+
short = this.readInt16BE(true)
|
|
514
|
+
}
|
|
515
|
+
if(endian == "little"){
|
|
516
|
+
short = this.readInt16LE(true)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (short != terminate) {
|
|
520
|
+
currentString += String.fromCharCode(short);
|
|
521
|
+
} else {
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return currentString;
|
|
526
|
+
} else {
|
|
527
|
+
let currentString = '';
|
|
528
|
+
|
|
529
|
+
for (let i = 0; i < (length/2); i++) {
|
|
530
|
+
var short = terminateValue;
|
|
531
|
+
var endian = byteorder || this.endian
|
|
532
|
+
if(endian == "big"){
|
|
533
|
+
short = this.readInt16BE(true)
|
|
534
|
+
}
|
|
535
|
+
if(endian == "little"){
|
|
536
|
+
short = this.readInt16LE(true)
|
|
537
|
+
}
|
|
538
|
+
currentString += String.fromCharCode(short);
|
|
539
|
+
}
|
|
540
|
+
return currentString;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* can switch byte order on demand, default to set endianness
|
|
546
|
+
* inculde length in bytes or reads until 0 short
|
|
547
|
+
* can include terminate character (as number), defaults to 0
|
|
548
|
+
* @param {string} byteorder - ```big``` or ```little```
|
|
549
|
+
* @param {number} length - number
|
|
550
|
+
* @param {any} terminateValue - number
|
|
551
|
+
* @returns string
|
|
552
|
+
*/
|
|
553
|
+
read16String = function(byteorder,length,terminateValue){
|
|
554
|
+
return this.string16(byteorder,length,terminateValue)
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* can switch byte order on demand, default to set endianness
|
|
559
|
+
* inculde length in bytes or reads until 0 short
|
|
560
|
+
* can include terminate character (as number), defaults to 0
|
|
561
|
+
* @param {string} byteorder - ```big``` or ```little```
|
|
562
|
+
* @param {number} length - number
|
|
563
|
+
* @param {any} terminateValue - number
|
|
564
|
+
* @returns string
|
|
565
|
+
*/
|
|
566
|
+
readCString = function(byteorder,length,terminateValue){
|
|
567
|
+
return this.string16(byteorder,length,terminateValue)
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* can switch byte order on demand, default to set endianness
|
|
572
|
+
* inculde length in bytes or reads until 0 short
|
|
573
|
+
* can include terminate character (as number), defaults to 0
|
|
574
|
+
* @param {string} byteorder - ```big``` or ```little```
|
|
575
|
+
* @param {number} length - number
|
|
576
|
+
* @param {any} terminateValue - number
|
|
577
|
+
* @returns string
|
|
578
|
+
*/
|
|
579
|
+
cstring = function(byteorder,length,terminateValue){
|
|
580
|
+
return this.string16(byteorder,length,terminateValue)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
//int64 reader
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* @returns number
|
|
587
|
+
*/
|
|
588
|
+
readInt64LE = function(signed) {
|
|
589
|
+
this.#check_size(8)
|
|
590
|
+
|
|
591
|
+
// Convert the byte array to a BigInt
|
|
592
|
+
let value = BigInt(0);
|
|
593
|
+
for (let i = 0; i < 8; i++) {
|
|
594
|
+
value |= BigInt(this.data[this.offset]) << BigInt(8 * i);
|
|
595
|
+
this.offset += 1
|
|
596
|
+
}
|
|
597
|
+
if(signed){
|
|
598
|
+
if (value & (BigInt(1) << BigInt(63))) {
|
|
599
|
+
value -= BigInt(1) << BigInt(64);
|
|
600
|
+
}
|
|
601
|
+
return value;
|
|
602
|
+
} else {
|
|
603
|
+
return value;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* @returns number
|
|
609
|
+
*/
|
|
610
|
+
readInt64BE = function(signed) {
|
|
611
|
+
this.#check_size(8)
|
|
612
|
+
|
|
613
|
+
// Convert the byte array to a BigInt
|
|
614
|
+
let value = BigInt(0);
|
|
615
|
+
for (let i = 0; i < 8; i++) {
|
|
616
|
+
value = (value << BigInt(8)) | BigInt(this.data[this.offset]);
|
|
617
|
+
this.offset += 1
|
|
618
|
+
}
|
|
619
|
+
if(signed){
|
|
620
|
+
if (value & (BigInt(1) << BigInt(63))) {
|
|
621
|
+
value -= BigInt(1) << BigInt(64);
|
|
622
|
+
}
|
|
623
|
+
return value;
|
|
624
|
+
} else {
|
|
625
|
+
return value;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* @returns number
|
|
631
|
+
*/
|
|
632
|
+
readUInt64 = function(){
|
|
633
|
+
if(this.endian == "little"){
|
|
634
|
+
return this.readInt64LE(true)
|
|
635
|
+
} else {
|
|
636
|
+
return this.readInt64BE(true)
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* @returns number
|
|
642
|
+
*/
|
|
643
|
+
readInt64 = function(){
|
|
644
|
+
if(this.endian == "little"){
|
|
645
|
+
return this.readInt32LE(false)
|
|
646
|
+
} else {
|
|
647
|
+
return this.readInt32BE(false)
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* @returns number
|
|
653
|
+
*/
|
|
654
|
+
uint64 = function(){
|
|
655
|
+
if(this.endian == "little"){
|
|
656
|
+
return this.readInt64LE(true)
|
|
657
|
+
} else {
|
|
658
|
+
return this.readInt64BE(true)
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* @returns number
|
|
664
|
+
*/
|
|
665
|
+
int64 = function(){
|
|
666
|
+
if(this.endian == "little"){
|
|
667
|
+
return this.readInt32LE(false)
|
|
668
|
+
} else {
|
|
669
|
+
return this.readInt32BE(false)
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
//float read
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* @returns number
|
|
677
|
+
*/
|
|
678
|
+
readFloat = function(order){
|
|
679
|
+
this.#check_size(4)
|
|
680
|
+
var uint32Value;
|
|
681
|
+
var endian = order == undefined ? this.endian : order
|
|
682
|
+
if(endian == "little"){
|
|
683
|
+
uint32Value = this.readInt32LE(true)
|
|
684
|
+
} else {
|
|
685
|
+
uint32Value = this.readInt32BE(true)
|
|
686
|
+
}
|
|
687
|
+
// Check if the value is negative (i.e., the most significant bit is set)
|
|
688
|
+
const isNegative = (uint32Value & 0x80000000) !== 0;
|
|
689
|
+
|
|
690
|
+
// Extract the exponent and fraction parts
|
|
691
|
+
const exponent = (uint32Value >> 23) & 0xFF;
|
|
692
|
+
const fraction = uint32Value & 0x7FFFFF;
|
|
693
|
+
|
|
694
|
+
// Calculate the float value
|
|
695
|
+
let floatValue;
|
|
696
|
+
|
|
697
|
+
if (exponent === 0) {
|
|
698
|
+
// Denormalized number (exponent is 0)
|
|
699
|
+
floatValue = Math.pow(-1, isNegative) * Math.pow(2, -126) * (fraction / Math.pow(2, 23));
|
|
700
|
+
} else if (exponent === 0xFF) {
|
|
701
|
+
// Infinity or NaN (exponent is 255)
|
|
702
|
+
floatValue = fraction === 0 ? (isNegative ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY) : Number.NaN;
|
|
703
|
+
} else {
|
|
704
|
+
// Normalized number
|
|
705
|
+
floatValue = Math.pow(-1, isNegative) * Math.pow(2, exponent - 127) * (1 + fraction / Math.pow(2, 23));
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
return floatValue;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* @returns number
|
|
713
|
+
*/
|
|
714
|
+
float = function(){
|
|
715
|
+
return this.readFloat()
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* @returns number
|
|
720
|
+
*/
|
|
721
|
+
floatbe = function(){
|
|
722
|
+
return this.readFloat(true)
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* @returns number
|
|
727
|
+
*/
|
|
728
|
+
floatle = function(){
|
|
729
|
+
return this.readFloat(false)
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* @returns number
|
|
734
|
+
*/
|
|
735
|
+
readFloatBE = function(){
|
|
736
|
+
return this.readFloat(true)
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* @returns number
|
|
741
|
+
*/
|
|
742
|
+
readFloatLE = function(){
|
|
743
|
+
return this.readFloat(false)
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
//half float read
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* @returns number
|
|
750
|
+
*/
|
|
751
|
+
readHalfFloat = function(order){
|
|
752
|
+
this.#check_size(2)
|
|
753
|
+
var uint16Value;
|
|
754
|
+
var endian = order == undefined ? this.endian : order
|
|
755
|
+
if(endian == "little"){
|
|
756
|
+
uint16Value = this.readInt16LE(true)
|
|
757
|
+
} else {
|
|
758
|
+
uint16Value = this.readInt16BE(true)
|
|
759
|
+
}
|
|
760
|
+
const sign = (uint16Value & 0x8000) >> 15;
|
|
761
|
+
const exponent = (uint16Value & 0x7C00) >> 10;
|
|
762
|
+
const fraction = uint16Value & 0x03FF;
|
|
763
|
+
|
|
764
|
+
let floatValue;
|
|
765
|
+
|
|
766
|
+
if (exponent === 0) {
|
|
767
|
+
if (fraction === 0) {
|
|
768
|
+
floatValue = (sign === 0) ? 0 : -0; // +/-0
|
|
769
|
+
} else {
|
|
770
|
+
// Denormalized number
|
|
771
|
+
floatValue = (sign === 0 ? 1 : -1) * Math.pow(2, -14) * (fraction / 0x0400);
|
|
772
|
+
}
|
|
773
|
+
} else if (exponent === 0x1F) {
|
|
774
|
+
if (fraction === 0) {
|
|
775
|
+
floatValue = (sign === 0) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
|
|
776
|
+
} else {
|
|
777
|
+
floatValue = Number.NaN;
|
|
778
|
+
}
|
|
779
|
+
} else {
|
|
780
|
+
// Normalized number
|
|
781
|
+
floatValue = (sign === 0 ? 1 : -1) * Math.pow(2, exponent - 15) * (1 + fraction / 0x0400);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
return floatValue;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* @returns number
|
|
789
|
+
*/
|
|
790
|
+
halffloat = function(){
|
|
791
|
+
return this.readHalfFloat()
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* @returns number
|
|
796
|
+
*/
|
|
797
|
+
halffloatbe = function(){
|
|
798
|
+
return this.readHalfFloat(true)
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* @returns number
|
|
803
|
+
*/
|
|
804
|
+
halffloatle = function(){
|
|
805
|
+
return this.readHalfFloat(false)
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* @returns number
|
|
810
|
+
*/
|
|
811
|
+
readHalfFloatBE = function(){
|
|
812
|
+
return this.readHalfFloat(true)
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* @returns number
|
|
817
|
+
*/
|
|
818
|
+
readHalfFloatLE = function(){
|
|
819
|
+
return this.readHalfFloat(false)
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
//doublefloat reader
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* @returns number
|
|
826
|
+
*/
|
|
827
|
+
readDoubleFloat = function(order){
|
|
828
|
+
this.#check_size(8)
|
|
829
|
+
var uint64Value ;
|
|
830
|
+
var endian = order == undefined ? this.endian : order
|
|
831
|
+
if(endian == "little"){
|
|
832
|
+
uint64Value = this.readInt64LE(true)
|
|
833
|
+
} else {
|
|
834
|
+
uint64Value = this.readInt64BE(true)
|
|
835
|
+
}
|
|
836
|
+
const sign = (uint64Value & 0x8000000000000000n) >> 63n;
|
|
837
|
+
const exponent = Number((uint64Value & 0x7FF0000000000000n) >> 52n) - 1023;
|
|
838
|
+
const fraction = Number(uint64Value & 0x000FFFFFFFFFFFFFn) / Math.pow(2, 52);
|
|
839
|
+
|
|
840
|
+
let floatValue;
|
|
841
|
+
|
|
842
|
+
if (exponent == -1023) {
|
|
843
|
+
if (fraction == 0) {
|
|
844
|
+
floatValue = (sign == 0) ? 0 : -0; // +/-0
|
|
845
|
+
} else {
|
|
846
|
+
// Denormalized number
|
|
847
|
+
floatValue = (sign == 0 ? 1 : -1) * Math.pow(2, -1022) * fraction;
|
|
848
|
+
}
|
|
849
|
+
} else if (exponent == 1024) {
|
|
850
|
+
if (fraction == 0) {
|
|
851
|
+
floatValue = (sign == 0) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
|
|
852
|
+
} else {
|
|
853
|
+
floatValue = Number.NaN;
|
|
854
|
+
}
|
|
855
|
+
} else {
|
|
856
|
+
// Normalized number
|
|
857
|
+
floatValue = (sign == 0 ? 1 : -1) * Math.pow(2, exponent) * (1 + fraction);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
return floatValue;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* @returns number
|
|
865
|
+
*/
|
|
866
|
+
doublefloat = function(){
|
|
867
|
+
return this.readDoubleFloat()
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* @returns number
|
|
872
|
+
*/
|
|
873
|
+
doublefloatbe = function(){
|
|
874
|
+
return this.readDoubleFloat(true)
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* @returns number
|
|
879
|
+
*/
|
|
880
|
+
doublefloatle = function(){
|
|
881
|
+
return this.readDoubleFloat(false)
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* @returns number
|
|
886
|
+
*/
|
|
887
|
+
readDoubleFloatBE = function(){
|
|
888
|
+
return this.readDoubleFloat(true)
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* @returns number
|
|
893
|
+
*/
|
|
894
|
+
readDoubleFloatLE = function(){
|
|
895
|
+
return this.readDoubleFloat(false)
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* removes reading data
|
|
900
|
+
*/
|
|
901
|
+
end = function(){
|
|
902
|
+
this.data = []
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* removes reading data
|
|
907
|
+
*/
|
|
908
|
+
close = function(){
|
|
909
|
+
this.data = []
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
module.exports = bireader
|