bireader 1.0.13 → 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 CHANGED
@@ -20,41 +20,154 @@ Supported data types are:
20
20
 
21
21
  Provides both CommonJS and ES modules.
22
22
 
23
- ### Quick Start
23
+ ### Example
24
24
 
25
25
  Import the reader or writer. Create a new parser with the data and start parsing.
26
26
 
27
- Includes all presents for quick parsing or programmable functions (examples below).
27
+ Includes presents for quick parsing or programmable functions (examples below).
28
28
 
29
29
  ```javascript
30
30
  import {bireader, biwriter} from 'bireader';
31
31
 
32
- //example of using mixed preset function naming and programmable calls
33
- function header_read(data){
32
+ //parse a webp file example
33
+ function parse_webp(data){
34
34
  const br = new bireader(data)
35
+ br.hexdump({supressUnicode:true}) //console.log data as hex
36
+
37
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
38
+ // 00000 52 49 46 46 98 3a 00 00 57 45 42 50 56 50 38 58 RIFF.:..WEBPVP8X
39
+ // 00010 0a 00 00 00 10 00 00 00 ff 00 00 ff 00 00 41 4c ..............AL
40
+ // 00020 50 48 26 10 00 00 01 19 45 6d 1b 49 4a 3b cf 0c PH&.....Em.IJ;..
41
+ // 00030 7f c0 7b 60 88 e8 ff 04 80 a2 82 65 56 d2 d2 86 ..{`.......eV...
42
+ // 00040 24 54 61 d0 83 8f 7f 0e 82 b6 6d e3 f0 a7 bd ed $Ta.......m.....
43
+ // 00050 87 10 11 13 40 3b 86 8f 26 4b d6 2a b7 6d 24 39 ....@;..&K.*.m$9
44
+ // 00060 52 4f fe 39 7f 3b 62 4e cc ec 9b 17 31 01 0c 24 RO.9.;bN....1..$
45
+ // 00070 49 89 23 e0 01 ab 52 64 e3 23 fc 61 db 76 cc 91 I.#...Rd.#.a.v..
46
+ // 00080 b6 7d fb 51 48 c5 69 db 4c 1b 63 db b6 ed b9 6d .}.QH.i.L.c....m
47
+ // 00090 db be 87 8d b1 6d db 9e b6 cd a4 d3 ee 24 95 54 .....m.......$.T
48
+ // 000a0 52 b8 8e 65 a9 eb 38 ce ab 52 75 9d 67 ff 75 2f R..e..8..Ru.g.u/
49
+ // 000b0 77 44 40 94 6d 25 6c 74 91 a8 88 86 58 9b da 6e wD@.m%lt....X..n
50
+
35
51
  const header = {}
36
- header.magic = br.cstring({length:4})
37
- const unsigned = header.magic == "foo" ? true : false
38
- header.ver = br.int32(unsigned, unsigned == true : "big" : "little")
39
- br.skip(2) //reserved
40
- if(header.ver == 10){
41
- br.endianness("big")
42
- header.file_size = br.size
43
- header.heigth = br.uint()
44
- header.width = br.quad()
45
- } else if(header.ver < 9) {
46
- br.le()
47
- header.file_size = br.ushort()
48
- header.heigth = br.uword()
49
- header.width = br.uint64()
50
- } else {
51
- throw new Error('Unknown version of ' + header.ver)
52
+ header.magic = br.string({length:4}) //RIFF
53
+ header.size = br.uint32le() //15000
54
+ header.fileSize = header.size + 8 //15008
55
+ header.payload = br.string({length:4}) //WEBP
56
+ header.format = br.string({length:4}) //VP8X
57
+ header.formatChunkSize = br.uint32le() //10
58
+ switch (header.format){
59
+ case "VP8 ":
60
+ header.formatType = "Lossy"
61
+ var read_size = 0
62
+ header.frame_tag = ubit24()
63
+ read_size += 3;
64
+ header.key_frame = header.frame_tag & 0x1;
65
+ header.version = (header.frame_tag >> 1) & 0x7;
66
+ header.show_frame = (header.frame_tag >> 4) & 0x1;
67
+ header.first_part_size = (header.frame_tag >> 5) & 0x7FFFF;
68
+ header.start_code = ubit24() //should be 2752925
69
+ header.horizontal_size_code = ubit16();
70
+ header.width = header.horizontal_size_code & 0x3FFF;
71
+ header.horizontal_scale = header.horizontal_size_code >> 14;
72
+ header.vertical_size_code = ubit16();
73
+ header.height = header.vertical_size_code & 0x3FFF;
74
+ header.vertical_scale = header.vertical_size_code >> 14;
75
+ read_size += 7;
76
+ header.VP8data = br.extract(header.formatChunkSize - read_size, true)
77
+ break;
78
+ case "VP8L":
79
+ header.formatType = "Lossless"
80
+ var read_size = 0
81
+ header.signature = br.ubyte() // should be 47
82
+ read_size += 1;
83
+ header.readWidth = ubit14()
84
+ header.width = header.readWidth+1;
85
+ header.readHeight = ubit14()
86
+ header.height = header.readHeight+1;
87
+ header.alpha_is_used = bit1()
88
+ header.version_number = ubit3()
89
+ read_size += 4;
90
+ header.data = br.extract(header.formatChunkSize - read_size, true)
91
+ break;
92
+ case "VP8X":
93
+ header.formatType = "Extended"
94
+ br.big() //switch to Big Endian bit read
95
+ header.rsv = br.bit2() //Reserved
96
+ header.I = br.bit1() //ICC profile
97
+ header.L = br.bit1() //Alpha
98
+ header.E = br.bit1() //Exif
99
+ header.X = br.bit1() //XMP
100
+ header.A = br.bit1() //Animation
101
+ header.R = br.bit1() //Reserved
102
+ br.little() //return to little
103
+ header.rsv2 = br.ubit24()
104
+ header.widthMinus1 = br.ubit24()
105
+ header.width = header.widthMinus1 + 1
106
+ header.heightMinus1 = br.ubit24()
107
+ header.height = header.heightMinus1 + 1
108
+ if(header.I)
109
+ {
110
+ header.ICCP = br.string({length:4}) // Should be ICCP
111
+ header.ICCPChunkSize = br.uint32()
112
+ header.ICCPData = br.extract(header.ICCPChunkSize, true)
113
+ }
114
+ if(header.L)
115
+ {
116
+ header.ALPH = br.string({length:4}) // Should be ALPH
117
+ header.ALPHChunkSize = br.uint32() //4134
118
+ header.ALPHData = br.extract(header.ALPHChunkSize, true)
119
+ }
120
+ if(header.A)
121
+ {
122
+ header.ANI = br.string({length:4}) // Should be ANIM or ANIF
123
+ header.ANIChunkSize = br.uint32()
124
+ if(header.ANI == "ANIM")
125
+ {
126
+ header.BGColor = br.uint32()
127
+ header.loopCount = br.ushort()
128
+ header.ANIMData = br.extract(header.ANIChunkSize, true)
129
+ } else
130
+ if (header.ANI == "ANIF")
131
+ {
132
+ header.FrameX = br.ubit24()
133
+ header.FrameY = br.ubit24()
134
+ header.readFrameWidth = br.ubit24()
135
+ header.readFrameHeight = br.ubit24()
136
+ header.frameWidth = readFrameWidth + 1
137
+ header.frameHeight = readFrameHeight + 1
138
+ header.duration = br.ubit24()
139
+ header.rsv3 = br.ubit6()
140
+ header.byte.B = br.bit1() //Blending
141
+ header.byte.D = br.bit1() //Disposal
142
+ header.frameData = br.extract(16, true)
143
+ header.ANIFData = br.extract(header.ANIChunkSize, true)
144
+ }
145
+ }
146
+ header.extFormatStr = br.string({length:4})
147
+ header.extChunkSize = br.uint32()
148
+ header.extData = br.extract(header.extChunkSize, true)
149
+ if(header.E)
150
+ {
151
+ header.EXIF = br.string({length:4}) // Should be EXIF
152
+ header.EXIFChunkSize = br.uint32()
153
+ header.EXIFData = br.extract(header.EXIFChunkSize, true)
154
+ }
155
+ if(header.X)
156
+ {
157
+ header.XMP = br.string({length:4}) // Should be XMP
158
+ header.XMPChunkSize = br.uint32()
159
+ header.XMPMetaData = br.extract(header.XMPChunkSize, true)
160
+ }
161
+ break;
162
+ default:
163
+ header.data = br.extract(header.formatChunkSize, true)
164
+ break;
52
165
  }
53
166
  br.finished()
54
167
  return header
55
168
  }
56
169
 
57
- function header_write(size, magic, ver, heigth, width){
170
+ function rite_webp(size, magic, ver, heigth, width){
58
171
  const data = new Uint8Array(size)
59
172
  const bw = new biwriter(data)
60
173
  bw.writeString(magic, {length:4})
@@ -178,13 +291,13 @@ Common functions for setup and movement shared by both (unless indicated).
178
291
  </tr>
179
292
  <tr>
180
293
  <td>Name</td>
181
- <td>extract(<b>length</b>)</td>
182
- <td align="center" rowspan="2"><b>length of data from current position</b></td>
183
- <td rowspan="2">Returns data from current read position to supplied length. <br><b>Note:</b> Does not affect supplied data or current read position.</td>
294
+ <td>extract(<b>length</b>, consume)</td>
295
+ <td align="center" rowspan="2"><b>length of data from current position</b>, consume length and move offset (default false)</td>
296
+ <td rowspan="2">Returns data from current read position to supplied length. <br><b>Note:</b> Does not affect supplied data. Only moves current read position if consume is true.</td>
184
297
  </tr>
185
298
  <tr>
186
299
  <td>Aliases</td>
187
- <td>wrap(<b>length</b>)<br>lift(<b>length</b>)</td>
300
+ <td>wrap(<b>length</b>, consume)<br>lift(<b>length</b>, consume)</td>
188
301
  </tr>
189
302
  <tr>
190
303
  <td>Name</td>
@@ -206,6 +319,24 @@ Common functions for setup and movement shared by both (unless indicated).
206
319
  <td>Aliases</td>
207
320
  <td>close()<br>done()<br>finished()</td>
208
321
  </tr>
322
+ <tr>
323
+ <td>Name</td>
324
+ <td>hexdump({length, startByte, supressUnicode})</td>
325
+ <td align="center">Length of dump, Byte to start the dump, Supress unicode character preview for cleaner columns</td>
326
+ <td >Console logs data. Defaults to current position and 192 bytes in length. Will trigger on error unless turned off (see below)</td>
327
+ </tr>
328
+ <tr>
329
+ <td>Name</td>
330
+ <td>errorDumpOff()</td>
331
+ <td align="center" >None</td>
332
+ <td >Turns hexdump off on error (default true)</td>
333
+ </tr>
334
+ <tr>
335
+ <td>Name</td>
336
+ <td>errorDumpOn()</td>
337
+ <td align="center" rowspan="2">None</td>
338
+ <td rowspan="2">Turns hexdump on on error (default true)</td>
339
+ </tr>
209
340
  </tbody>
210
341
  </table>
211
342
 
@@ -14,7 +14,8 @@ class bireader {
14
14
  check_size(read_size, read_bits) {
15
15
  const new_off = this.offset + (read_size || 0) + Math.ceil((this.bitoffset + (read_bits || 0)) / 8);
16
16
  if (new_off > this.size) {
17
- throw new Error(`Reader reached end of data.`);
17
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
18
+ throw new Error(`Reader reached end of data: reading to ` + new_off + " at " + this.offset + " of " + this.size);
18
19
  }
19
20
  }
20
21
  isBuffer(obj) {
@@ -37,6 +38,7 @@ class bireader {
37
38
  this.offset = 0;
38
39
  this.bitoffset = 0;
39
40
  this.size = 0;
41
+ this.errorDump = true;
40
42
  if (endianness != undefined && typeof endianness != "string") {
41
43
  throw new Error("Endian must be big or little");
42
44
  }
@@ -128,6 +130,7 @@ class bireader {
128
130
  skip(bytes, bits) {
129
131
  this.check_size(bytes || 0);
130
132
  if ((((bytes || 0) + this.offset) + Math.ceil((this.bitoffset + (bits || 0)) / 8)) > this.size) {
133
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
131
134
  throw new Error("Seek outside of size of data: " + this.size);
132
135
  }
133
136
  this.bitoffset += (bits || 0) % 8;
@@ -149,8 +152,10 @@ class bireader {
149
152
  * @param {number} bit - bit to jump to (0-7)
150
153
  */
151
154
  goto(byte, bit) {
152
- if ((byte + Math.ceil((bit || 0) / 8)) > this.size) {
153
- throw new Error("Goto outside of size of data: " + this.size);
155
+ const new_size = (byte + Math.ceil((bit || 0) / 8));
156
+ if (new_size > this.size) {
157
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
158
+ throw new Error("Goto outside of size of data: goto " + new_size + " of " + this.size);
154
159
  }
155
160
  this.offset = byte;
156
161
  this.bitoffset = (bit || 0) % 8;
@@ -270,6 +275,10 @@ class bireader {
270
275
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
271
276
  */
272
277
  clip(startOffset, endOffset) {
278
+ if ((endOffset || this.offset) > this.size) {
279
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
280
+ throw new Error("End offset outside of data: endOffset" + endOffset + " of " + this.size);
281
+ }
273
282
  return this.data.slice(startOffset || 0, endOffset || this.offset);
274
283
  }
275
284
  /**
@@ -280,6 +289,10 @@ class bireader {
280
289
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
281
290
  */
282
291
  crop(startOffset, endOffset) {
292
+ if ((endOffset || this.offset) > this.size) {
293
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
294
+ throw new Error("End offset outside of data: endOffset" + endOffset + " of " + this.size);
295
+ }
283
296
  return this.data.slice(startOffset || 0, endOffset || this.offset);
284
297
  }
285
298
  /**
@@ -290,6 +303,10 @@ class bireader {
290
303
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
291
304
  */
292
305
  truncate(startOffset, endOffset) {
306
+ if ((endOffset || this.offset) > this.size) {
307
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
308
+ throw new Error("End offset outside of data: endOffset" + endOffset + " of " + this.size);
309
+ }
293
310
  return this.data.slice(startOffset || 0, endOffset || this.offset);
294
311
  }
295
312
  /**
@@ -300,43 +317,49 @@ class bireader {
300
317
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
301
318
  */
302
319
  slice(startOffset, endOffset) {
320
+ if ((endOffset || this.offset) > this.size) {
321
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
322
+ throw new Error("End offset outside of data: endOffset" + endOffset + " of " + this.size);
323
+ }
303
324
  return this.data.slice(startOffset || 0, endOffset || this.offset);
304
325
  }
305
326
  /**
306
327
  * Extract array from current position to length supplied
307
328
  * Note: Does not affect supplied data
308
329
  * @param {number} length - length of data to copy from current offset
330
+ * @param {number} consume - moves offset to end of length
309
331
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
310
332
  */
311
- extract(length) {
333
+ extract(length, consume) {
312
334
  if (this.offset + (length || 0) > this.size) {
313
- throw new Error("End offset outside of data: " + this.size);
335
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
336
+ throw new Error("End offset outside of data: at " + this.offset + " reading " + length + " of" + this.size);
337
+ }
338
+ const extract = this.data.slice(this.offset, Number(this.offset + (length || 0)));
339
+ if (consume) {
340
+ this.offset += length;
314
341
  }
315
- return this.data.slice(this.offset, this.offset + (length || 0));
342
+ return extract;
316
343
  }
317
344
  /**
318
345
  * Extract array from current position to length supplied
319
346
  * Note: Does not affect supplied data
320
347
  * @param {number} length - length of data to copy from current offset
348
+ * @param {number} consume - moves offset to end of length
321
349
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
322
350
  */
323
- wrap(length) {
324
- if (this.offset + (length || 0) > this.size) {
325
- throw new Error("End offset outside of data: " + this.size);
326
- }
327
- return this.data.slice(this.offset, this.offset + (length || 0));
351
+ wrap(length, consume) {
352
+ return this.extract(length, consume);
328
353
  }
329
354
  /**
330
355
  * Extract array from current position to length supplied
331
356
  * Note: Does not affect supplied data
332
357
  * @param {number} length - length of data to copy from current offset
358
+ * @param {number} consume - moves offset to end of length
333
359
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
334
360
  */
335
- lift(length) {
336
- if (this.offset + (length || 0) > this.size) {
337
- throw new Error("End offset outside of data: " + this.size);
338
- }
339
- return this.data.slice(this.offset, this.offset + (length || 0));
361
+ lift(length, consume) {
362
+ return this.extract(length, consume);
340
363
  }
341
364
  /**
342
365
  * Returns current data
@@ -376,6 +399,212 @@ class bireader {
376
399
  finished() {
377
400
  this.data = [];
378
401
  }
402
+ /**
403
+ * Turn hexdump on error off, default on
404
+ */
405
+ errorDumpOff() {
406
+ this.errorDump = false;
407
+ }
408
+ /**
409
+ * Turn hexdump on error on, default on
410
+ */
411
+ errorDumpOn() {
412
+ this.errorDump = true;
413
+ }
414
+ /**
415
+ * Console logs data as hex dump
416
+ *
417
+ * @param {object} options - options object
418
+ * ```javascript
419
+ * {
420
+ * length: 192, // number of bytes to log, default 192 or end of data
421
+ * startByte: 0, // byte to start dump, default current position
422
+ * supressUnicode: false // Supress unicode character preview for cleaner columns
423
+ * }
424
+ * ```
425
+ */
426
+ hexdump(options) {
427
+ var length = options && options.length;
428
+ var startByte = options && options.startByte;
429
+ var supressUnicode = options && options.supressUnicode || false;
430
+ if ((startByte || 0) > this.size) {
431
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
432
+ throw new Error("Hexdump start is outside of data size: " + startByte + " of " + this.size);
433
+ }
434
+ const start = startByte || this.offset;
435
+ const end = Math.min(start + (length || 192), this.size);
436
+ if (start + (length || 0) > this.size) {
437
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
438
+ throw new Error("Hexdump amount is outside of data size: " + (start + (length || 0)) + " of " + end);
439
+ }
440
+ function hex_check(byte, bits) {
441
+ var value = 0;
442
+ for (var i = 0; i < bits;) {
443
+ var remaining = bits - i;
444
+ var bitOffset = 0;
445
+ var currentByte = byte;
446
+ var read = Math.min(remaining, 8 - bitOffset);
447
+ var mask, readBits;
448
+ mask = ~(0xFF << read);
449
+ readBits = (currentByte >> (8 - read - bitOffset)) & mask;
450
+ value <<= read;
451
+ value |= readBits;
452
+ i += read;
453
+ }
454
+ value = value >>> 0;
455
+ return value;
456
+ }
457
+ const rows = [];
458
+ var header = " 0 1 2 3 4 5 6 7 8 9 A B C D E F ";
459
+ var ending = "0123456789ABCDEF";
460
+ var addr = "";
461
+ for (let i = start; i < end; i += 16) {
462
+ addr = i.toString(16).padStart(5, '0');
463
+ var row = this.data?.slice(i, i + 16) || [];
464
+ var hex = Array.from(row, (byte) => byte.toString(16).padStart(2, '0')).join(' ');
465
+ rows.push(`${addr} ${hex.padEnd(47)} `);
466
+ }
467
+ let result = '';
468
+ let make_wide = false;
469
+ let i = start;
470
+ while (i < end) {
471
+ const byte = this.data[i];
472
+ if (byte < 32 || byte == 127) {
473
+ result += '.';
474
+ }
475
+ else if (byte < 127) {
476
+ // Valid UTF-8 start byte or single-byte character
477
+ // Convert the byte to a character and add it to the result
478
+ result += String.fromCharCode(byte);
479
+ }
480
+ else if (supressUnicode) {
481
+ result += '.';
482
+ }
483
+ else if (hex_check(byte, 1) == 0) {
484
+ //Byte 1
485
+ result += String.fromCharCode(byte);
486
+ }
487
+ else if (hex_check(byte, 3) == 6) {
488
+ //Byte 2
489
+ if (i + 1 <= end) {
490
+ //check second byte
491
+ const byte2 = this.data[i + 1];
492
+ if (hex_check(byte2, 2) == 2) {
493
+ const charCode = ((byte & 0x1f) << 6) | (byte2 & 0x3f);
494
+ i++;
495
+ make_wide = true;
496
+ const read = " " + String.fromCharCode(charCode);
497
+ result += read;
498
+ }
499
+ else {
500
+ result += ".";
501
+ }
502
+ }
503
+ else {
504
+ result += ".";
505
+ }
506
+ }
507
+ else if (hex_check(byte, 4) == 14) {
508
+ //Byte 3
509
+ if (i + 1 <= end) {
510
+ //check second byte
511
+ const byte2 = this.data[i + 1];
512
+ if (hex_check(byte2, 2) == 2) {
513
+ if (i + 2 <= end) {
514
+ //check third byte
515
+ const byte3 = this.data[i + 2];
516
+ if (hex_check(byte3, 2) == 2) {
517
+ const charCode = ((byte & 0x0f) << 12) |
518
+ ((byte2 & 0x3f) << 6) |
519
+ (byte3 & 0x3f);
520
+ i += 2;
521
+ make_wide = true;
522
+ const read = " " + String.fromCharCode(charCode);
523
+ result += read;
524
+ }
525
+ else {
526
+ i++;
527
+ result += " .";
528
+ }
529
+ }
530
+ else {
531
+ i++;
532
+ result += " .";
533
+ }
534
+ }
535
+ else {
536
+ result += ".";
537
+ }
538
+ }
539
+ else {
540
+ result += ".";
541
+ }
542
+ }
543
+ else if (hex_check(byte, 5) == 28) {
544
+ //Byte 4
545
+ if (i + 1 <= end) {
546
+ //check second byte
547
+ const byte2 = this.data[i + 1];
548
+ if (hex_check(byte2, 2) == 2) {
549
+ if (i + 2 <= end) {
550
+ //check third byte
551
+ const byte3 = this.data[i + 2];
552
+ if (hex_check(byte3, 2) == 2) {
553
+ if (i + 3 <= end) {
554
+ //check fourth byte
555
+ const byte4 = this.data[i + 2];
556
+ if (hex_check(byte4, 2) == 2) {
557
+ const charCode = (((byte4 & 0xFF) << 24) | ((byte3 & 0xFF) << 16) | ((byte2 & 0xFF) << 8) | (byte & 0xFF));
558
+ i += 3;
559
+ make_wide = true;
560
+ const read = " " + String.fromCharCode(charCode);
561
+ result += read;
562
+ }
563
+ else {
564
+ i += 2;
565
+ result += " .";
566
+ }
567
+ }
568
+ else {
569
+ i += 2;
570
+ result += " .";
571
+ }
572
+ }
573
+ else {
574
+ i++;
575
+ result += " .";
576
+ }
577
+ }
578
+ else {
579
+ i++;
580
+ result += " .";
581
+ }
582
+ }
583
+ else {
584
+ result += ".";
585
+ }
586
+ }
587
+ else {
588
+ result += ".";
589
+ }
590
+ }
591
+ else {
592
+ // Invalid UTF-8 byte, add a period to the result
593
+ result += '.';
594
+ }
595
+ i++;
596
+ }
597
+ const chunks = result.match(new RegExp(`.{1,${16}}`, 'g'));
598
+ chunks?.forEach((self, i) => {
599
+ rows[i] = rows[i] + (make_wide ? "|" + self + "|" : self);
600
+ });
601
+ header = "".padStart(addr.length) + header + (make_wide ? "" : ending);
602
+ rows.unshift(header);
603
+ if (make_wide) {
604
+ rows.push("*Removed character byte header on unicode detection");
605
+ }
606
+ console.log(rows.join("\n"));
607
+ }
379
608
  //
380
609
  //bit reader
381
610
  //
@@ -398,6 +627,7 @@ class bireader {
398
627
  }
399
628
  const size_needed = ((((bits - 1) + this.bitoffset) / 8) + this.offset);
400
629
  if (bits <= 0 || size_needed > this.size) {
630
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
401
631
  throw new Error("Invalid number of bits to read: " + size_needed + " of " + this.size);
402
632
  }
403
633
  var off_in_bits = (this.offset * 8) + this.bitoffset;
@@ -424,7 +654,7 @@ class bireader {
424
654
  }
425
655
  this.offset = this.offset + Math.floor(((bits) + this.bitoffset) / 8); //end byte
426
656
  this.bitoffset = ((bits) + this.bitoffset) % 8;
427
- if (unsigned == true) {
657
+ if (unsigned == true || bits <= 7) {
428
658
  return value >>> 0;
429
659
  }
430
660
  if (bits !== 32 && value & (1 << (bits - 1))) {
@@ -446,13 +676,13 @@ class bireader {
446
676
  return this.readBit(bits, unsigned, endian);
447
677
  }
448
678
  /**
449
- * Bit field reader
450
- *
451
- * Note: When returning to a byte read, remaining bits are dropped
452
- *
453
- * @param {boolean} unsigned - if the value is unsigned
454
- * @returns number
455
- */
679
+ * Bit field reader
680
+ *
681
+ * Note: When returning to a byte read, remaining bits are dropped
682
+ *
683
+ * @param {boolean} unsigned - if the value is unsigned
684
+ * @returns number
685
+ */
456
686
  bit1(unsigned) {
457
687
  return this.bit(1, unsigned);
458
688
  }
@@ -3732,6 +3962,7 @@ class bireader {
3732
3962
  maxBytes = this.readInt32(true, endian);
3733
3963
  }
3734
3964
  else {
3965
+ this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
3735
3966
  throw new Error("Invalid length read size: " + lengthReadSize);
3736
3967
  }
3737
3968
  // Read the string as Pascal or Delphi encoded