bireader 1.0.12 → 1.0.14
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/README.md +158 -27
- package/lib/cjs/src/reader.js +263 -24
- package/lib/cjs/src/reader.js.map +1 -1
- package/lib/cjs/src/writer.js +257 -13
- package/lib/cjs/src/writer.js.map +1 -1
- package/lib/cjs/types/src/reader.d.ts +45 -10
- package/lib/cjs/types/src/reader.d.ts.map +1 -1
- package/lib/cjs/types/src/writer.d.ts +38 -3
- package/lib/cjs/types/src/writer.d.ts.map +1 -1
- package/lib/esm/src/reader.js +263 -24
- package/lib/esm/src/reader.js.map +1 -1
- package/lib/esm/src/writer.js +257 -13
- package/lib/esm/src/writer.js.map +1 -1
- package/lib/esm/types/src/reader.d.ts +45 -10
- package/lib/esm/types/src/reader.d.ts.map +1 -1
- package/lib/esm/types/src/writer.d.ts +38 -3
- package/lib/esm/types/src/writer.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/esm/src/reader.js
CHANGED
|
@@ -11,7 +11,8 @@ export class bireader {
|
|
|
11
11
|
check_size(read_size, read_bits) {
|
|
12
12
|
const new_off = this.offset + (read_size || 0) + Math.ceil((this.bitoffset + (read_bits || 0)) / 8);
|
|
13
13
|
if (new_off > this.size) {
|
|
14
|
-
|
|
14
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
15
|
+
throw new Error(`Reader reached end of data: reading to ` + new_off + " at " + this.offset + " of " + this.size);
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
isBuffer(obj) {
|
|
@@ -34,6 +35,7 @@ export class bireader {
|
|
|
34
35
|
this.offset = 0;
|
|
35
36
|
this.bitoffset = 0;
|
|
36
37
|
this.size = 0;
|
|
38
|
+
this.errorDump = true;
|
|
37
39
|
if (endianness != undefined && typeof endianness != "string") {
|
|
38
40
|
throw new Error("Endian must be big or little");
|
|
39
41
|
}
|
|
@@ -125,6 +127,7 @@ export class bireader {
|
|
|
125
127
|
skip(bytes, bits) {
|
|
126
128
|
this.check_size(bytes || 0);
|
|
127
129
|
if ((((bytes || 0) + this.offset) + Math.ceil((this.bitoffset + (bits || 0)) / 8)) > this.size) {
|
|
130
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
128
131
|
throw new Error("Seek outside of size of data: " + this.size);
|
|
129
132
|
}
|
|
130
133
|
this.bitoffset += (bits || 0) % 8;
|
|
@@ -146,8 +149,10 @@ export class bireader {
|
|
|
146
149
|
* @param {number} bit - bit to jump to (0-7)
|
|
147
150
|
*/
|
|
148
151
|
goto(byte, bit) {
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
const new_size = (byte + Math.ceil((bit || 0) / 8));
|
|
153
|
+
if (new_size > this.size) {
|
|
154
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
155
|
+
throw new Error("Goto outside of size of data: goto " + new_size + " of " + this.size);
|
|
151
156
|
}
|
|
152
157
|
this.offset = byte;
|
|
153
158
|
this.bitoffset = (bit || 0) % 8;
|
|
@@ -252,6 +257,14 @@ export class bireader {
|
|
|
252
257
|
return this.offset;
|
|
253
258
|
}
|
|
254
259
|
/**
|
|
260
|
+
* Get the current byte position
|
|
261
|
+
*
|
|
262
|
+
* @return {number} current byte position
|
|
263
|
+
*/
|
|
264
|
+
saveOffset() {
|
|
265
|
+
return this.offset;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
255
268
|
* Truncates array from start to current position unless supplied
|
|
256
269
|
* Note: Does not affect supplied data
|
|
257
270
|
* @param {number} startOffset - Start location, default 0
|
|
@@ -259,6 +272,10 @@ export class bireader {
|
|
|
259
272
|
* @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
|
|
260
273
|
*/
|
|
261
274
|
clip(startOffset, endOffset) {
|
|
275
|
+
if ((endOffset || this.offset) > this.size) {
|
|
276
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
277
|
+
throw new Error("End offset outside of data: endOffset" + endOffset + " of " + this.size);
|
|
278
|
+
}
|
|
262
279
|
return this.data.slice(startOffset || 0, endOffset || this.offset);
|
|
263
280
|
}
|
|
264
281
|
/**
|
|
@@ -269,6 +286,10 @@ export class bireader {
|
|
|
269
286
|
* @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
|
|
270
287
|
*/
|
|
271
288
|
crop(startOffset, endOffset) {
|
|
289
|
+
if ((endOffset || this.offset) > this.size) {
|
|
290
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
291
|
+
throw new Error("End offset outside of data: endOffset" + endOffset + " of " + this.size);
|
|
292
|
+
}
|
|
272
293
|
return this.data.slice(startOffset || 0, endOffset || this.offset);
|
|
273
294
|
}
|
|
274
295
|
/**
|
|
@@ -279,6 +300,10 @@ export class bireader {
|
|
|
279
300
|
* @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
|
|
280
301
|
*/
|
|
281
302
|
truncate(startOffset, endOffset) {
|
|
303
|
+
if ((endOffset || this.offset) > this.size) {
|
|
304
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
305
|
+
throw new Error("End offset outside of data: endOffset" + endOffset + " of " + this.size);
|
|
306
|
+
}
|
|
282
307
|
return this.data.slice(startOffset || 0, endOffset || this.offset);
|
|
283
308
|
}
|
|
284
309
|
/**
|
|
@@ -289,43 +314,49 @@ export class bireader {
|
|
|
289
314
|
* @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
|
|
290
315
|
*/
|
|
291
316
|
slice(startOffset, endOffset) {
|
|
317
|
+
if ((endOffset || this.offset) > this.size) {
|
|
318
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
319
|
+
throw new Error("End offset outside of data: endOffset" + endOffset + " of " + this.size);
|
|
320
|
+
}
|
|
292
321
|
return this.data.slice(startOffset || 0, endOffset || this.offset);
|
|
293
322
|
}
|
|
294
323
|
/**
|
|
295
324
|
* Extract array from current position to length supplied
|
|
296
325
|
* Note: Does not affect supplied data
|
|
297
326
|
* @param {number} length - length of data to copy from current offset
|
|
327
|
+
* @param {number} consume - moves offset to end of length
|
|
298
328
|
* @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
|
|
299
329
|
*/
|
|
300
|
-
extract(length) {
|
|
330
|
+
extract(length, consume) {
|
|
301
331
|
if (this.offset + (length || 0) > this.size) {
|
|
302
|
-
|
|
332
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
333
|
+
throw new Error("End offset outside of data: at " + this.offset + " reading " + length + " of" + this.size);
|
|
303
334
|
}
|
|
304
|
-
|
|
335
|
+
const extract = this.data.slice(this.offset, Number(this.offset + (length || 0)));
|
|
336
|
+
if (consume) {
|
|
337
|
+
this.offset += length;
|
|
338
|
+
}
|
|
339
|
+
return extract;
|
|
305
340
|
}
|
|
306
341
|
/**
|
|
307
342
|
* Extract array from current position to length supplied
|
|
308
343
|
* Note: Does not affect supplied data
|
|
309
344
|
* @param {number} length - length of data to copy from current offset
|
|
345
|
+
* @param {number} consume - moves offset to end of length
|
|
310
346
|
* @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
|
|
311
347
|
*/
|
|
312
|
-
wrap(length) {
|
|
313
|
-
|
|
314
|
-
throw new Error("End offset outside of data: " + this.size);
|
|
315
|
-
}
|
|
316
|
-
return this.data.slice(this.offset, this.offset + (length || 0));
|
|
348
|
+
wrap(length, consume) {
|
|
349
|
+
return this.extract(length, consume);
|
|
317
350
|
}
|
|
318
351
|
/**
|
|
319
352
|
* Extract array from current position to length supplied
|
|
320
353
|
* Note: Does not affect supplied data
|
|
321
354
|
* @param {number} length - length of data to copy from current offset
|
|
355
|
+
* @param {number} consume - moves offset to end of length
|
|
322
356
|
* @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
|
|
323
357
|
*/
|
|
324
|
-
lift(length) {
|
|
325
|
-
|
|
326
|
-
throw new Error("End offset outside of data: " + this.size);
|
|
327
|
-
}
|
|
328
|
-
return this.data.slice(this.offset, this.offset + (length || 0));
|
|
358
|
+
lift(length, consume) {
|
|
359
|
+
return this.extract(length, consume);
|
|
329
360
|
}
|
|
330
361
|
/**
|
|
331
362
|
* Returns current data
|
|
@@ -365,6 +396,212 @@ export class bireader {
|
|
|
365
396
|
finished() {
|
|
366
397
|
this.data = [];
|
|
367
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* Turn hexdump on error off, default on
|
|
401
|
+
*/
|
|
402
|
+
errorDumpOff() {
|
|
403
|
+
this.errorDump = false;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Turn hexdump on error on, default on
|
|
407
|
+
*/
|
|
408
|
+
errorDumpOn() {
|
|
409
|
+
this.errorDump = true;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Console logs data as hex dump
|
|
413
|
+
*
|
|
414
|
+
* @param {object} options - options object
|
|
415
|
+
* ```javascript
|
|
416
|
+
* {
|
|
417
|
+
* length: 192, // number of bytes to log, default 192 or end of data
|
|
418
|
+
* startByte: 0, // byte to start dump, default current position
|
|
419
|
+
* supressUnicode: false // Supress unicode character preview for cleaner columns
|
|
420
|
+
* }
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
hexdump(options) {
|
|
424
|
+
var length = options && options.length;
|
|
425
|
+
var startByte = options && options.startByte;
|
|
426
|
+
var supressUnicode = options && options.supressUnicode || false;
|
|
427
|
+
if ((startByte || 0) > this.size) {
|
|
428
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
429
|
+
throw new Error("Hexdump start is outside of data size: " + startByte + " of " + this.size);
|
|
430
|
+
}
|
|
431
|
+
const start = startByte || this.offset;
|
|
432
|
+
const end = Math.min(start + (length || 192), this.size);
|
|
433
|
+
if (start + (length || 0) > this.size) {
|
|
434
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
435
|
+
throw new Error("Hexdump amount is outside of data size: " + (start + (length || 0)) + " of " + end);
|
|
436
|
+
}
|
|
437
|
+
function hex_check(byte, bits) {
|
|
438
|
+
var value = 0;
|
|
439
|
+
for (var i = 0; i < bits;) {
|
|
440
|
+
var remaining = bits - i;
|
|
441
|
+
var bitOffset = 0;
|
|
442
|
+
var currentByte = byte;
|
|
443
|
+
var read = Math.min(remaining, 8 - bitOffset);
|
|
444
|
+
var mask, readBits;
|
|
445
|
+
mask = ~(0xFF << read);
|
|
446
|
+
readBits = (currentByte >> (8 - read - bitOffset)) & mask;
|
|
447
|
+
value <<= read;
|
|
448
|
+
value |= readBits;
|
|
449
|
+
i += read;
|
|
450
|
+
}
|
|
451
|
+
value = value >>> 0;
|
|
452
|
+
return value;
|
|
453
|
+
}
|
|
454
|
+
const rows = [];
|
|
455
|
+
var header = " 0 1 2 3 4 5 6 7 8 9 A B C D E F ";
|
|
456
|
+
var ending = "0123456789ABCDEF";
|
|
457
|
+
var addr = "";
|
|
458
|
+
for (let i = start; i < end; i += 16) {
|
|
459
|
+
addr = i.toString(16).padStart(5, '0');
|
|
460
|
+
var row = this.data?.slice(i, i + 16) || [];
|
|
461
|
+
var hex = Array.from(row, (byte) => byte.toString(16).padStart(2, '0')).join(' ');
|
|
462
|
+
rows.push(`${addr} ${hex.padEnd(47)} `);
|
|
463
|
+
}
|
|
464
|
+
let result = '';
|
|
465
|
+
let make_wide = false;
|
|
466
|
+
let i = start;
|
|
467
|
+
while (i < end) {
|
|
468
|
+
const byte = this.data[i];
|
|
469
|
+
if (byte < 32 || byte == 127) {
|
|
470
|
+
result += '.';
|
|
471
|
+
}
|
|
472
|
+
else if (byte < 127) {
|
|
473
|
+
// Valid UTF-8 start byte or single-byte character
|
|
474
|
+
// Convert the byte to a character and add it to the result
|
|
475
|
+
result += String.fromCharCode(byte);
|
|
476
|
+
}
|
|
477
|
+
else if (supressUnicode) {
|
|
478
|
+
result += '.';
|
|
479
|
+
}
|
|
480
|
+
else if (hex_check(byte, 1) == 0) {
|
|
481
|
+
//Byte 1
|
|
482
|
+
result += String.fromCharCode(byte);
|
|
483
|
+
}
|
|
484
|
+
else if (hex_check(byte, 3) == 6) {
|
|
485
|
+
//Byte 2
|
|
486
|
+
if (i + 1 <= end) {
|
|
487
|
+
//check second byte
|
|
488
|
+
const byte2 = this.data[i + 1];
|
|
489
|
+
if (hex_check(byte2, 2) == 2) {
|
|
490
|
+
const charCode = ((byte & 0x1f) << 6) | (byte2 & 0x3f);
|
|
491
|
+
i++;
|
|
492
|
+
make_wide = true;
|
|
493
|
+
const read = " " + String.fromCharCode(charCode);
|
|
494
|
+
result += read;
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
result += ".";
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
result += ".";
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
else if (hex_check(byte, 4) == 14) {
|
|
505
|
+
//Byte 3
|
|
506
|
+
if (i + 1 <= end) {
|
|
507
|
+
//check second byte
|
|
508
|
+
const byte2 = this.data[i + 1];
|
|
509
|
+
if (hex_check(byte2, 2) == 2) {
|
|
510
|
+
if (i + 2 <= end) {
|
|
511
|
+
//check third byte
|
|
512
|
+
const byte3 = this.data[i + 2];
|
|
513
|
+
if (hex_check(byte3, 2) == 2) {
|
|
514
|
+
const charCode = ((byte & 0x0f) << 12) |
|
|
515
|
+
((byte2 & 0x3f) << 6) |
|
|
516
|
+
(byte3 & 0x3f);
|
|
517
|
+
i += 2;
|
|
518
|
+
make_wide = true;
|
|
519
|
+
const read = " " + String.fromCharCode(charCode);
|
|
520
|
+
result += read;
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
i++;
|
|
524
|
+
result += " .";
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
i++;
|
|
529
|
+
result += " .";
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
result += ".";
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
result += ".";
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
else if (hex_check(byte, 5) == 28) {
|
|
541
|
+
//Byte 4
|
|
542
|
+
if (i + 1 <= end) {
|
|
543
|
+
//check second byte
|
|
544
|
+
const byte2 = this.data[i + 1];
|
|
545
|
+
if (hex_check(byte2, 2) == 2) {
|
|
546
|
+
if (i + 2 <= end) {
|
|
547
|
+
//check third byte
|
|
548
|
+
const byte3 = this.data[i + 2];
|
|
549
|
+
if (hex_check(byte3, 2) == 2) {
|
|
550
|
+
if (i + 3 <= end) {
|
|
551
|
+
//check fourth byte
|
|
552
|
+
const byte4 = this.data[i + 2];
|
|
553
|
+
if (hex_check(byte4, 2) == 2) {
|
|
554
|
+
const charCode = (((byte4 & 0xFF) << 24) | ((byte3 & 0xFF) << 16) | ((byte2 & 0xFF) << 8) | (byte & 0xFF));
|
|
555
|
+
i += 3;
|
|
556
|
+
make_wide = true;
|
|
557
|
+
const read = " " + String.fromCharCode(charCode);
|
|
558
|
+
result += read;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
i += 2;
|
|
562
|
+
result += " .";
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
i += 2;
|
|
567
|
+
result += " .";
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
i++;
|
|
572
|
+
result += " .";
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
i++;
|
|
577
|
+
result += " .";
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
result += ".";
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
result += ".";
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
// Invalid UTF-8 byte, add a period to the result
|
|
590
|
+
result += '.';
|
|
591
|
+
}
|
|
592
|
+
i++;
|
|
593
|
+
}
|
|
594
|
+
const chunks = result.match(new RegExp(`.{1,${16}}`, 'g'));
|
|
595
|
+
chunks?.forEach((self, i) => {
|
|
596
|
+
rows[i] = rows[i] + (make_wide ? "|" + self + "|" : self);
|
|
597
|
+
});
|
|
598
|
+
header = "".padStart(addr.length) + header + (make_wide ? "" : ending);
|
|
599
|
+
rows.unshift(header);
|
|
600
|
+
if (make_wide) {
|
|
601
|
+
rows.push("*Removed character byte header on unicode detection");
|
|
602
|
+
}
|
|
603
|
+
console.log(rows.join("\n"));
|
|
604
|
+
}
|
|
368
605
|
//
|
|
369
606
|
//bit reader
|
|
370
607
|
//
|
|
@@ -387,6 +624,7 @@ export class bireader {
|
|
|
387
624
|
}
|
|
388
625
|
const size_needed = ((((bits - 1) + this.bitoffset) / 8) + this.offset);
|
|
389
626
|
if (bits <= 0 || size_needed > this.size) {
|
|
627
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
390
628
|
throw new Error("Invalid number of bits to read: " + size_needed + " of " + this.size);
|
|
391
629
|
}
|
|
392
630
|
var off_in_bits = (this.offset * 8) + this.bitoffset;
|
|
@@ -413,7 +651,7 @@ export class bireader {
|
|
|
413
651
|
}
|
|
414
652
|
this.offset = this.offset + Math.floor(((bits) + this.bitoffset) / 8); //end byte
|
|
415
653
|
this.bitoffset = ((bits) + this.bitoffset) % 8;
|
|
416
|
-
if (unsigned == true) {
|
|
654
|
+
if (unsigned == true || bits <= 7) {
|
|
417
655
|
return value >>> 0;
|
|
418
656
|
}
|
|
419
657
|
if (bits !== 32 && value & (1 << (bits - 1))) {
|
|
@@ -435,13 +673,13 @@ export class bireader {
|
|
|
435
673
|
return this.readBit(bits, unsigned, endian);
|
|
436
674
|
}
|
|
437
675
|
/**
|
|
438
|
-
* Bit field reader
|
|
439
|
-
*
|
|
440
|
-
* Note: When returning to a byte read, remaining bits are dropped
|
|
441
|
-
*
|
|
442
|
-
* @param {boolean} unsigned - if the value is unsigned
|
|
443
|
-
* @returns number
|
|
444
|
-
*/
|
|
676
|
+
* Bit field reader
|
|
677
|
+
*
|
|
678
|
+
* Note: When returning to a byte read, remaining bits are dropped
|
|
679
|
+
*
|
|
680
|
+
* @param {boolean} unsigned - if the value is unsigned
|
|
681
|
+
* @returns number
|
|
682
|
+
*/
|
|
445
683
|
bit1(unsigned) {
|
|
446
684
|
return this.bit(1, unsigned);
|
|
447
685
|
}
|
|
@@ -3721,6 +3959,7 @@ export class bireader {
|
|
|
3721
3959
|
maxBytes = this.readInt32(true, endian);
|
|
3722
3960
|
}
|
|
3723
3961
|
else {
|
|
3962
|
+
this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
|
|
3724
3963
|
throw new Error("Invalid length read size: " + lengthReadSize);
|
|
3725
3964
|
}
|
|
3726
3965
|
// Read the string as Pascal or Delphi encoded
|