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 +156 -25
- package/lib/cjs/src/reader.js +255 -24
- package/lib/cjs/src/reader.js.map +1 -1
- package/lib/cjs/src/writer.js +249 -13
- package/lib/cjs/src/writer.js.map +1 -1
- package/lib/cjs/types/src/reader.d.ts +39 -10
- package/lib/cjs/types/src/reader.d.ts.map +1 -1
- package/lib/cjs/types/src/writer.d.ts +32 -3
- package/lib/cjs/types/src/writer.d.ts.map +1 -1
- package/lib/esm/src/reader.js +255 -24
- package/lib/esm/src/reader.js.map +1 -1
- package/lib/esm/src/writer.js +249 -13
- package/lib/esm/src/writer.js.map +1 -1
- package/lib/esm/types/src/reader.d.ts +39 -10
- package/lib/esm/types/src/reader.d.ts.map +1 -1
- package/lib/esm/types/src/writer.d.ts +32 -3
- package/lib/esm/types/src/writer.d.ts.map +1 -1
- package/package.json +1 -1
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
|
-
###
|
|
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
|
|
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
|
-
//
|
|
33
|
-
function
|
|
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.
|
|
37
|
-
|
|
38
|
-
header.
|
|
39
|
-
br.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|
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
|
|
182
|
-
<td align="center" rowspan="2"><b>length of data from current position</b
|
|
183
|
-
<td rowspan="2">Returns data from current read position to supplied length. <br><b>Note:</b> Does not affect supplied data
|
|
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
|
|
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
|
|
package/lib/cjs/src/reader.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|