bireader 1.0.14 → 1.0.17

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.
@@ -1,41 +1,43 @@
1
+ import { buffcheck, arraybuffcheck, extendarray, skip, goto, remove, checkSize, addData, hexDump, XOR, AND, OR, NOT, LSHIFT, RSHIFT, ADD, wbit, rbit, rbyte, wbyte, wint16, rint16, whalffloat, rhalffloat, rint32, wint32, rfloat, wfloat, wint64, rint64, rdfloat, wdfloat, wstring, rstring } from './common';
1
2
  /**
3
+ * Binary reader, includes bitfields and strings
2
4
  *
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 {string} endianness - endianness ```big``` or ```little``` (default ```little```)
5
+ * @param {Buffer|Uint8Array} data - ```Buffer``` or ```Uint8Array```. Always found in ``biwriter.data``
6
+ * @param {number} byteOffset - Byte offset to start reader (default 0)
7
+ * @param {number} bitOffset - Bit offset 0-7 to start reader (default 0)
8
+ * @param {string} endianness - Endianness ```big``` or ```little``` (default ```little```)
9
+ * @param {boolean} strict - Strict mode: if true does not extend supplied array on outside write (default true)
9
10
  */
10
11
  export class bireader {
11
- check_size(read_size, read_bits) {
12
- const new_off = this.offset + (read_size || 0) + Math.ceil((this.bitoffset + (read_bits || 0)) / 8);
13
- if (new_off > this.size) {
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);
16
- }
17
- }
18
12
  isBuffer(obj) {
19
- return (typeof Buffer !== 'undefined' && obj instanceof Buffer);
13
+ return buffcheck(obj);
20
14
  }
21
15
  isBufferOrUint8Array(obj) {
22
- return obj instanceof Uint8Array || this.isBuffer(obj);
16
+ return arraybuffcheck(this, obj);
17
+ }
18
+ extendArray(to_padd) {
19
+ return extendarray(this, to_padd);
20
+ }
21
+ check_size(write_bytes, write_bit, offset) {
22
+ return checkSize(this, write_bytes || 0, write_bit || 0, offset || this.offset);
23
23
  }
24
24
  /**
25
+ * Binary reader, includes bitfields and strings
25
26
  *
26
- * byte reader, includes bitfields and strings
27
- *
28
- * @param {Buffer|Uint8Array} data - ```Buffer``` or ```Uint8Array```
29
- * @param {number} byteOffset - byte offset to start reader, default is 0
30
- * @param {number} bitOffset - bit offset to start reader, 0-7
31
- * @param {string} endianness - endianness ```big``` or ```little``` (default ```little```)
27
+ * @param {Buffer|Uint8Array} data - ```Buffer``` or ```Uint8Array```. Always found in ``biwriter.data``
28
+ * @param {number} byteOffset - Byte offset to start reader (default 0)
29
+ * @param {number} bitOffset - Bit offset 0-7 to start reader (default 0)
30
+ * @param {string} endianness - Endianness ```big``` or ```little``` (default ```little```)
31
+ * @param {boolean} strict - Strict mode: if true does not extend supplied array on outside write (default true)
32
32
  */
33
- constructor(data, byteOffset, bitOffset, endianness) {
33
+ constructor(data, byteOffset, bitOffset, endianness, strict) {
34
34
  this.endian = "little";
35
35
  this.offset = 0;
36
36
  this.bitoffset = 0;
37
37
  this.size = 0;
38
+ this.strict = false;
38
39
  this.errorDump = true;
40
+ this.data = [];
39
41
  if (endianness != undefined && typeof endianness != "string") {
40
42
  throw new Error("Endian must be big or little");
41
43
  }
@@ -54,6 +56,14 @@ export class bireader {
54
56
  if (bitOffset != undefined) {
55
57
  this.bitoffset = bitOffset % 8;
56
58
  }
59
+ if (typeof strict == "boolean") {
60
+ this.strict = strict;
61
+ }
62
+ else {
63
+ if (strict != undefined) {
64
+ throw new Error("Strict mode must be true of false");
65
+ }
66
+ }
57
67
  if (data == undefined) {
58
68
  throw new Error("Data required");
59
69
  }
@@ -118,126 +128,98 @@ export class bireader {
118
128
  le() {
119
129
  this.endianness("little");
120
130
  }
131
+ //
132
+ // move from current position
133
+ //
121
134
  /**
122
- * Move current read byte or bit position
135
+ * Offset current byte or bit position
136
+ * Note: Will extend array if strict mode is off and outside of max size
123
137
  *
124
- * @param {number} bytes - bytes to skip
125
- * @param {number} bits - bits to skip
138
+ * @param {number} bytes - Bytes to skip
139
+ * @param {number} bits - Bits to skip (0-7)
126
140
  */
127
141
  skip(bytes, bits) {
128
- this.check_size(bytes || 0);
129
- if ((((bytes || 0) + this.offset) + Math.ceil((this.bitoffset + (bits || 0)) / 8)) > this.size) {
130
- this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
131
- throw new Error("Seek outside of size of data: " + this.size);
132
- }
133
- this.bitoffset += (bits || 0) % 8;
134
- this.offset += (bytes || 0);
142
+ return skip(this, bytes, bits);
135
143
  }
136
144
  /**
137
- * Move current read byte or bit position
145
+ * Offset current byte or bit position
146
+ * Note: Will extend array if strict mode is off and outside of max size
138
147
  *
139
- * @param {number} bytes - bytes to skip
140
- * @param {number} bits - bits to skip
148
+ * @param {number} bytes - Bytes to skip
149
+ * @param {number} bits - Bits to skip (0-7)
141
150
  */
142
- fskip(bytes, bits) {
151
+ jump(bytes, bits) {
143
152
  this.skip(bytes, bits);
144
153
  }
154
+ //
155
+ // directly set current position
156
+ //
145
157
  /**
146
- * Change current byte or bit read position
158
+ * Change position directly to address
159
+ * Note: Will extend array if strict mode is off and outside of max size
147
160
  *
148
- * @param {number} byte - byte to jump to
149
- * @param {number} bit - bit to jump to (0-7)
161
+ * @param {number} byte - byte to set to
162
+ * @param {number} bit - bit to set to (0-7)
150
163
  */
151
164
  goto(byte, bit) {
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);
156
- }
157
- this.offset = byte;
158
- this.bitoffset = (bit || 0) % 8;
165
+ return goto(this, byte, bit);
159
166
  }
160
167
  /**
161
- * Change current byte or bit read position
168
+ * Change position directly to address
169
+ * Note: Will extend array if strict mode is off and outside of max size
162
170
  *
163
- * @param {number} byte - byte to jump to
164
- * @param {number} bit - bit to jump to (0-7)
171
+ * @param {number} byte - byte to set to
172
+ * @param {number} bit - bit to set to (0-7)
165
173
  */
166
174
  seek(byte, bit) {
167
- this.goto(byte, bit);
168
- }
169
- /**
170
- * Change current byte or bit read position
171
- *
172
- * @param {number} byte - byte to jump to
173
- * @param {number} bit - bit to jump to (0-7)
174
- */
175
- fseek(byte, bit) {
176
- this.goto(byte, bit);
175
+ return this.goto(byte, bit);
177
176
  }
178
177
  /**
179
- * Change current byte or bit read position
178
+ * Change position directly to address
179
+ * Note: Will extend array if strict mode is off and outside of max size
180
180
  *
181
- * @param {number} byte - byte to jump to
182
- * @param {number} bit - bit to jump to (0-7)
183
- */
184
- jump(byte, bit) {
185
- this.goto(byte, bit);
186
- }
187
- /**
188
- * Change current byte or bit read position
189
- *
190
- * @param {number} byte - byte to jump to
191
- * @param {number} bit - bit to jump to (0-7)
181
+ * @param {number} byte - byte to set to
182
+ * @param {number} bit - bit to set to (0-7)
192
183
  */
193
184
  pointer(byte, bit) {
194
- this.goto(byte, bit);
185
+ return this.goto(byte, bit);
195
186
  }
196
187
  /**
197
- * Change current byte or bit read position
188
+ * Change position directly to address
189
+ * Note: Will extend array if strict mode is off and outside of max size
198
190
  *
199
- * @param {number} byte - byte to jump to
200
- * @param {number} bit - bit to jump to (0-7)
191
+ * @param {number} byte - byte to set to
192
+ * @param {number} bit - bit to set to (0-7)
201
193
  */
202
194
  warp(byte, bit) {
203
- this.goto(byte, bit);
204
- }
205
- /**
206
- * Change current byte or bit read position
207
- *
208
- * @param {number} byte - byte to jump to
209
- * @param {number} bit - bit to jump to (0-7)
210
- */
211
- fsetpos(byte, bit) {
212
- this.goto(byte, bit);
195
+ return this.goto(byte, bit);
213
196
  }
197
+ //
198
+ //go to start
199
+ //
214
200
  /**
215
- * Set offset to start of file
201
+ * Set byte and bit position to start of data
216
202
  */
217
203
  rewind() {
218
204
  this.offset = 0;
219
205
  this.bitoffset = 0;
220
206
  }
221
207
  /**
222
- * Set offset to start of file
208
+ * Set byte and bit position to start of data
223
209
  */
224
210
  gotostart() {
225
211
  this.offset = 0;
226
212
  this.bitoffset = 0;
227
213
  }
228
- /**
229
- * Set offset to start of file
230
- */
231
- tostart() {
232
- this.offset = 0;
233
- this.bitoffset = 0;
234
- }
214
+ //
215
+ //get position
216
+ //
235
217
  /**
236
218
  * Get the current byte position
237
219
  *
238
220
  * @return {number} current byte position
239
221
  */
240
- ftell() {
222
+ tell() {
241
223
  return this.offset;
242
224
  }
243
225
  /**
@@ -245,7 +227,7 @@ export class bireader {
245
227
  *
246
228
  * @return {number} current byte position
247
229
  */
248
- tell() {
230
+ getOffset() {
249
231
  return this.offset;
250
232
  }
251
233
  /**
@@ -253,113 +235,530 @@ export class bireader {
253
235
  *
254
236
  * @return {number} current byte position
255
237
  */
256
- fgetpos() {
238
+ saveOffset() {
257
239
  return this.offset;
258
240
  }
259
241
  /**
260
- * Get the current byte position
242
+ * Get the current bit position (0-7)
261
243
  *
262
- * @return {number} current byte position
244
+ * @return {number} current bit position
263
245
  */
264
- saveOffset() {
265
- return this.offset;
246
+ tellB() {
247
+ return this.bitoffset;
266
248
  }
267
249
  /**
268
- * Truncates array from start to current position unless supplied
269
- * Note: Does not affect supplied data
270
- * @param {number} startOffset - Start location, default 0
271
- * @param {number} endOffset - end location, default current write position
272
- * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
250
+ * Get the current bit position (0-7)
251
+ *
252
+ * @return {number} current bit position
253
+ */
254
+ getOffsetBit() {
255
+ return this.bitoffset;
256
+ }
257
+ /**
258
+ * Get the current bit position (0-7)
259
+ *
260
+ * @return {number} current bit position
261
+ */
262
+ saveOffsetAbsBit() {
263
+ return (this.offset * 8) + this.bitoffset;
264
+ }
265
+ /**
266
+ * Get the current absolute bit position (from start of data)
267
+ *
268
+ * @return {number} current absolute bit position
269
+ */
270
+ tellAbsB() {
271
+ return (this.offset * 8) + this.bitoffset;
272
+ }
273
+ /**
274
+ * Get the current absolute bit position (from start of data)
275
+ *
276
+ * @return {number} current absolute bit position
277
+ */
278
+ getOffsetAbsBit() {
279
+ return (this.offset * 8) + this.bitoffset;
280
+ }
281
+ /**
282
+ * Get the current absolute bit position (from start of data)
283
+ *
284
+ * @return {number} current absolute bit position
273
285
  */
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);
286
+ saveOffsetBit() {
287
+ return (this.offset * 8) + this.bitoffset;
288
+ }
289
+ //
290
+ //strict mode change
291
+ //
292
+ /**
293
+ * Disallows extending data if position is outside of max size
294
+ */
295
+ restrict() {
296
+ this.strict = true;
297
+ }
298
+ /**
299
+ * Allows extending data if position is outside of max size
300
+ */
301
+ unrestrict() {
302
+ this.strict = false;
303
+ }
304
+ //
305
+ //math
306
+ //
307
+ /**
308
+ * XOR data
309
+ *
310
+ * @param {number|string|Uint8Array|Buffer} xorKey - Value, string or array to XOR
311
+ * @param {number} startOffset - Start location (default current byte position)
312
+ * @param {number} endOffset - End location (default end of data)
313
+ * @param {boolean} consume - Move current position to end of data (default false)
314
+ */
315
+ xor(xorKey, startOffset, endOffset, consume) {
316
+ var XORKey = xorKey;
317
+ if (typeof xorKey == "number") {
318
+ //pass
319
+ }
320
+ else if (typeof xorKey == "string") {
321
+ //pass
322
+ }
323
+ else if (this.isBufferOrUint8Array(XORKey)) {
324
+ //pass
325
+ }
326
+ else {
327
+ throw new Error("XOR must be a number, string, Uint8Array or Buffer");
278
328
  }
279
- return this.data.slice(startOffset || 0, endOffset || this.offset);
329
+ return XOR(this, xorKey, startOffset || this.offset, endOffset || this.size, consume || false);
280
330
  }
281
331
  /**
282
- * Truncates array from start to current position unless supplied
283
- * Note: Does not affect supplied data
284
- * @param {number} startOffset - Start location, default 0
285
- * @param {number} endOffset - end location, default current write position
286
- * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
332
+ * XOR data
333
+ *
334
+ * @param {number|string|Uint8Array|Buffer} xorKey - Value, string or array to XOR
335
+ * @param {number} length - Length in bytes to XOR from curent position (default 1 byte for value, length of string or array for Uint8Array or Buffer)
336
+ * @param {boolean} consume - Move current position to end of data (default false)
287
337
  */
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);
338
+ xorThis(xorKey, length, consume) {
339
+ var Length = length || 1;
340
+ var XORKey = xorKey;
341
+ if (typeof xorKey == "number") {
342
+ Length = length || 1;
343
+ }
344
+ else if (typeof xorKey == "string") {
345
+ const encoder = new TextEncoder().encode(xorKey);
346
+ XORKey = encoder;
347
+ Length = length || encoder.length;
348
+ }
349
+ else if (this.isBufferOrUint8Array(XORKey)) {
350
+ Length = length || xorKey.length;
351
+ }
352
+ else {
353
+ throw new Error("XOR must be a number, string, Uint8Array or Buffer");
292
354
  }
293
- return this.data.slice(startOffset || 0, endOffset || this.offset);
355
+ return XOR(this, XORKey, this.offset, this.offset + Length, consume || false);
294
356
  }
295
357
  /**
296
- * Truncates array from start to current position unless supplied
297
- * Note: Does not affect supplied data
298
- * @param {number} startOffset - Start location, default 0
299
- * @param {number} endOffset - end location, default current write position
300
- * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
358
+ * OR data
359
+ *
360
+ * @param {number|string|Uint8Array|Buffer} orKey - Value, string or array to OR
361
+ * @param {number} startOffset - Start location (default current byte position)
362
+ * @param {number} endOffset - End location (default end of data)
363
+ * @param {boolean} consume - Move current position to end of data (default false)
301
364
  */
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);
365
+ or(orKey, startOffset, endOffset, consume) {
366
+ var ORKey = orKey;
367
+ if (typeof orKey == "number") {
368
+ //pass
306
369
  }
307
- return this.data.slice(startOffset || 0, endOffset || this.offset);
370
+ else if (typeof orKey == "string") {
371
+ //pass
372
+ }
373
+ else if (this.isBufferOrUint8Array(ORKey)) {
374
+ //pass
375
+ }
376
+ else {
377
+ throw new Error("OR must be a number, string, Uint8Array or Buffer");
378
+ }
379
+ return OR(this, orKey, startOffset || this.offset, endOffset || this.size, consume || false);
308
380
  }
309
381
  /**
310
- * Truncates array from start to current position unless supplied
311
- * Note: Does not affect supplied data
312
- * @param {number} startOffset - Start location, default 0
313
- * @param {number} endOffset - end location, default current write position
314
- * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
382
+ * OR data
383
+ *
384
+ * @param {number|string|Uint8Array|Buffer} orKey - Value, string or array to OR
385
+ * @param {number} length - Length in bytes to OR from curent position (default 1 byte for value, length of string or array for Uint8Array or Buffer)
386
+ * @param {boolean} consume - Move current position to end of data (default false)
315
387
  */
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);
388
+ orThis(orKey, length, consume) {
389
+ var Length = length || 1;
390
+ var ORKey = orKey;
391
+ if (typeof orKey == "number") {
392
+ Length = length || 1;
320
393
  }
321
- return this.data.slice(startOffset || 0, endOffset || this.offset);
394
+ else if (typeof orKey == "string") {
395
+ const encoder = new TextEncoder().encode(orKey);
396
+ ORKey = encoder;
397
+ Length = length || encoder.length;
398
+ }
399
+ else if (this.isBufferOrUint8Array(ORKey)) {
400
+ Length = length || orKey.length;
401
+ }
402
+ else {
403
+ throw new Error("OR must be a number, string, Uint8Array or Buffer");
404
+ }
405
+ return OR(this, ORKey, this.offset, this.offset + Length, consume || false);
322
406
  }
323
407
  /**
324
- * Extract array from current position to length supplied
325
- * Note: Does not affect supplied data
326
- * @param {number} length - length of data to copy from current offset
327
- * @param {number} consume - moves offset to end of length
328
- * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
408
+ * AND data
409
+ *
410
+ * @param {number|string|Uint8Array|Buffer} andKey - Value, string or array to AND
411
+ * @param {number} startOffset - Start location (default current byte position)
412
+ * @param {number} endOffset - End location (default end of data)
413
+ * @param {boolean} consume - Move current position to end of data (default false)
329
414
  */
330
- extract(length, consume) {
331
- if (this.offset + (length || 0) > this.size) {
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);
415
+ and(andKey, startOffset, endOffset, consume) {
416
+ var ANDKey = andKey;
417
+ if (typeof andKey == "number") {
418
+ //pass
419
+ }
420
+ else if (typeof andKey == "string") {
421
+ //pass
334
422
  }
335
- const extract = this.data.slice(this.offset, Number(this.offset + (length || 0)));
336
- if (consume) {
337
- this.offset += length;
423
+ else if (this.isBufferOrUint8Array(ANDKey)) {
424
+ //pass
338
425
  }
339
- return extract;
426
+ else {
427
+ throw new Error("AND must be a number, string, Uint8Array or Buffer");
428
+ }
429
+ return AND(this, andKey, startOffset || this.offset, endOffset || this.size, consume || false);
430
+ }
431
+ /**
432
+ * AND data
433
+ *
434
+ * @param {number|string|Uint8Array|Buffer} andKey - Value, string or array to AND
435
+ * @param {number} length - Length in bytes to AND from curent position (default 1 byte for value, length of string or array for Uint8Array or Buffer)
436
+ * @param {boolean} consume - Move current position to end of data (default false)
437
+ */
438
+ andThis(andKey, length, consume) {
439
+ var Length = length || 1;
440
+ var ANDKey = andKey;
441
+ if (typeof andKey == "number") {
442
+ Length = length || 1;
443
+ }
444
+ else if (typeof andKey == "string") {
445
+ const encoder = new TextEncoder().encode(andKey);
446
+ ANDKey = encoder;
447
+ Length = length || encoder.length;
448
+ }
449
+ else if (this.isBufferOrUint8Array(ANDKey)) {
450
+ Length = length || andKey.length;
451
+ }
452
+ else {
453
+ throw new Error("XOR must be a number, string, Uint8Array or Buffer");
454
+ }
455
+ return AND(this, ANDKey, this.offset, this.offset + Length, consume || false);
456
+ }
457
+ /**
458
+ * Not data
459
+ *
460
+ * @param {number} startOffset - Start location (default current byte position)
461
+ * @param {number} endOffset - End location (default end of data)
462
+ * @param {boolean} consume - Move current position to end of data (default false)
463
+ */
464
+ not(startOffset, endOffset, consume) {
465
+ return NOT(this, startOffset || this.offset, endOffset || this.size, consume || false);
466
+ }
467
+ /**
468
+ * Not data
469
+ *
470
+ * @param {number} length - Length in bytes to NOT from curent position (default 1 byte for value, length of string or array for Uint8Array or Buffer)
471
+ * @param {boolean} consume - Move current position to end of data (default false)
472
+ */
473
+ notThis(length, consume) {
474
+ return NOT(this, this.offset, this.offset + (length || 1), consume || false);
475
+ }
476
+ /**
477
+ * Left shift data
478
+ *
479
+ * @param {number} shiftValue - Value to left shift
480
+ * @param {number} startOffset - Start location (default current byte position)
481
+ * @param {number} endOffset - End location (default end of data)
482
+ * @param {boolean} consume - Move current position to end of data (default false)
483
+ */
484
+ lShift(shiftValue, startOffset, endOffset, consume) {
485
+ if (typeof shiftValue != "number") {
486
+ throw new Error("Shift value must be a number");
487
+ }
488
+ return LSHIFT(this, shiftValue, startOffset || this.offset, endOffset || this.size, consume || false);
489
+ }
490
+ /**
491
+ * Left shift data
492
+ *
493
+ * @param {number} shiftValue - Value to left shift
494
+ * @param {number} length - Length in bytes to left shift from curent position (default 1 byte for value, length of string or array for Uint8Array or Buffer)
495
+ * @param {boolean} consume - Move current position to end of data (default false)
496
+ */
497
+ lShiftThis(shiftValue, length, consume) {
498
+ var Length = length || 1;
499
+ if (typeof shiftValue != "number") {
500
+ throw new Error("Shift value must be a number");
501
+ }
502
+ return LSHIFT(this, shiftValue, this.offset, this.offset + Length, consume || false);
503
+ }
504
+ /**
505
+ * Right shift data
506
+ *
507
+ * @param {number} shiftValue - Value to right shift
508
+ * @param {number} startOffset - Start location (default current byte position)
509
+ * @param {number} endOffset - End location (default end of data)
510
+ * @param {boolean} consume - Move current position to end of data (default false)
511
+ */
512
+ rShift(shiftValue, startOffset, endOffset, consume) {
513
+ if (typeof shiftValue != "number") {
514
+ throw new Error("Shift value must be a number");
515
+ }
516
+ return RSHIFT(this, shiftValue, startOffset || this.offset, endOffset || this.size, consume || false);
517
+ }
518
+ /**
519
+ * Right shift data
520
+ *
521
+ * @param {number} shiftValue - Value to right shift
522
+ * @param {number} length - Length in bytes to right shift from curent position (default 1 byte for value, length of string or array for Uint8Array or Buffer)
523
+ * @param {boolean} consume - Move current position to end of data (default false)
524
+ */
525
+ rShiftThis(shiftValue, length, consume) {
526
+ var Length = length || 1;
527
+ if (typeof shiftValue != "number") {
528
+ throw new Error("Shift value must be a number");
529
+ }
530
+ return RSHIFT(this, shiftValue, this.offset, this.offset + Length, consume || false);
531
+ }
532
+ /**
533
+ * Add value to data
534
+ *
535
+ * @param {number} addValue - Value to add
536
+ * @param {number} startOffset - Start location (default current byte position)
537
+ * @param {number} endOffset - End location (default end of data)
538
+ * @param {boolean} consume - Move current position to end of data (default false)
539
+ */
540
+ add(addValue, startOffset, endOffset, consume) {
541
+ if (typeof addValue != "number") {
542
+ throw new Error("Add value must be a number");
543
+ }
544
+ return ADD(this, addValue, startOffset || this.offset, endOffset || this.size, consume || false);
545
+ }
546
+ /**
547
+ * Add value to data
548
+ *
549
+ * @param {number} addValue - Value to add
550
+ * @param {number} length - Length in bytes to add from curent position (default 1 byte for value, length of string or array for Uint8Array or Buffer)
551
+ * @param {boolean} consume - Move current position to end of data (default false)
552
+ */
553
+ addThis(addValue, length, consume) {
554
+ var Length = length || 1;
555
+ if (typeof addValue != "number") {
556
+ throw new Error("Add value must be a number");
557
+ }
558
+ return ADD(this, addValue, this.offset, this.offset + Length, consume || false);
559
+ }
560
+ //
561
+ //remove part of data
562
+ //
563
+ /**
564
+ * Deletes part of data from start to current byte position unless supplied, returns removed
565
+ * Note: Errors in strict mode
566
+ *
567
+ * @param {number} startOffset - Start location (default 0)
568
+ * @param {number} endOffset - End location (default current position)
569
+ * @param {boolean} consume - Move position to end of removed data (default false)
570
+ * @returns {Buffer|Uint8Array} Removed data as ``Buffer`` or ``Uint8Array``
571
+ */
572
+ delete(startOffset, endOffset, consume) {
573
+ return remove(this, startOffset || 0, endOffset || this.offset, consume || false, true);
574
+ }
575
+ /**
576
+ * Deletes part of data from start to current byte position unless supplied, returns removed
577
+ * Note: Errors in strict mode
578
+ *
579
+ * @param {number} startOffset - Start location (default 0)
580
+ * @param {number} endOffset - End location (default current position)
581
+ * @param {boolean} consume - Move position to end of removed data (default false)
582
+ * @returns {Buffer|Uint8Array} Removed data as ``Buffer`` or ``Uint8Array``
583
+ */
584
+ clip(startOffset, endOffset, consume) {
585
+ return remove(this, startOffset || 0, endOffset || this.offset, consume || false, true);
586
+ }
587
+ /**
588
+ * Deletes part of data from current byte position to supplied length, returns removed
589
+ * Note: Errors in strict mode
590
+ *
591
+ * @param {number} length - Length of data in bytes to remove
592
+ * @param {boolean} consume - Move position to end of removed data (default false)
593
+ * @returns {Buffer|Uint8Array} Removed data as ``Buffer`` or ``Uint8Array``
594
+ */
595
+ crop(length, consume) {
596
+ return remove(this, this.offset, this.offset + (length || 0), consume || false, true);
340
597
  }
341
598
  /**
342
- * Extract array from current position to length supplied
599
+ * Deletes part of data from current position to supplied length, returns removed
600
+ * Note: Only works in strict mode
601
+ *
602
+ * @param {number} length - Length of data in bytes to remove
603
+ * @param {boolean} consume - Move position to end of removed data (default false)
604
+ * @returns {Buffer|Uint8Array} Removed data as ``Buffer`` or ``Uint8Array``
605
+ */
606
+ drop(length, consume) {
607
+ return remove(this, this.offset, this.offset + (length || 0), consume || false, true);
608
+ }
609
+ //
610
+ //copy out
611
+ //
612
+ /**
613
+ * Returns part of data from current byte position to end of data unless supplied
614
+ *
615
+ * @param {number} startOffset - Start location (default current position)
616
+ * @param {number} endOffset - End location (default end of data)
617
+ * @param {boolean} consume - Move position to end of lifted data (default false)
618
+ * @param {number} fillValue - Byte value to to fill returned data (does NOT fill unless supplied)
619
+ * @returns {Buffer|Uint8Array} Selected data as ```Uint8Array``` or ```Buffer```
620
+ */
621
+ lift(startOffset, endOffset, consume, fillValue) {
622
+ return remove(this, startOffset || this.offset, endOffset || this.size, consume || false, false, fillValue);
623
+ }
624
+ /**
625
+ * Returns part of data from current byte position to end of data unless supplied
626
+ *
627
+ * @param {number} startOffset - Start location (default current position)
628
+ * @param {number} endOffset - End location (default end of data)
629
+ * @param {boolean} consume - Move position to end of lifted data (default false)
630
+ * @param {number} fillValue - Byte value to to fill returned data (does NOT fill unless supplied)
631
+ * @returns {Buffer|Uint8Array} Selected data as ```Uint8Array``` or ```Buffer```
632
+ */
633
+ fill(startOffset, endOffset, consume, fillValue) {
634
+ return remove(this, startOffset || this.offset, endOffset || this.size, consume || false, false, fillValue);
635
+ }
636
+ /**
637
+ * Extract data from current position to length supplied
343
638
  * Note: Does not affect supplied data
344
- * @param {number} length - length of data to copy from current offset
345
- * @param {number} consume - moves offset to end of length
346
- * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
639
+ *
640
+ * @param {number} length - Length of data in bytes to copy from current offset
641
+ * @param {number} consume - Moves offset to end of length
642
+ * @returns {Buffer|Uint8Array} Selected data as ```Uint8Array``` or ```Buffer```
347
643
  */
348
- wrap(length, consume) {
349
- return this.extract(length, consume);
644
+ extract(length, consume) {
645
+ return remove(this, this.offset, length || 0, consume || false, false);
350
646
  }
351
647
  /**
352
- * Extract array from current position to length supplied
648
+ * Extract data from current position to length supplied
353
649
  * Note: Does not affect supplied data
354
- * @param {number} length - length of data to copy from current offset
355
- * @param {number} consume - moves offset to end of length
356
- * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
650
+ *
651
+ * @param {number} length - Length of data in bytes to copy from current offset
652
+ * @param {number} consume - Moves offset to end of length
653
+ * @returns {Buffer|Uint8Array} Selected data as ```Uint8Array``` or ```Buffer```
654
+ */
655
+ slice(length, consume) {
656
+ return remove(this, this.offset, length || 0, consume || false, false);
657
+ }
658
+ /**
659
+ * Extract data from current position to length supplied
660
+ * Note: Does not affect supplied data
661
+ *
662
+ * @param {number} length - Length of data in bytes to copy from current offset
663
+ * @param {number} consume - Moves offset to end of length
664
+ * @returns {Buffer|Uint8Array} Selected data as ```Uint8Array``` or ```Buffer```
665
+ */
666
+ wrap(length, consume) {
667
+ return remove(this, this.offset, length || 0, consume || false, false);
668
+ }
669
+ //
670
+ //insert
671
+ //
672
+ /**
673
+ * Inserts data into data
674
+ * Note: Must be same data type as supplied data. Errors on strict mode.
675
+ *
676
+ * @param {Buffer|Uint8Array} data - ```Uint8Array``` or ```Buffer``` to add to data
677
+ * @param {boolean} consume - Move current byte position to end of data (default false)
678
+ * @param {number} offset - Byte position to add at (defaults to current position)
679
+ */
680
+ insert(data, consume, offset) {
681
+ return addData(this, data, consume || false, offset || this.offset);
682
+ }
683
+ /**
684
+ * Inserts data into data
685
+ * Note: Must be same data type as supplied data. Errors on strict mode.
686
+ *
687
+ * @param {Buffer|Uint8Array} data - ```Uint8Array``` or ```Buffer``` to add to data
688
+ * @param {boolean} consume - Move current byte position to end of data (default false)
689
+ * @param {number} offset - Byte position to add at (defaults to current position)
690
+ */
691
+ place(data, consume, offset) {
692
+ return addData(this, data, consume || false, offset || this.offset);
693
+ }
694
+ /**
695
+ * Replaces data in data
696
+ * Note: Must be same data type as supplied data. Errors on strict mode.
697
+ *
698
+ * @param {Buffer|Uint8Array} data - ```Uint8Array``` or ```Buffer``` to replace in data
699
+ * @param {boolean} consume - Move current byte position to end of data (default false)
700
+ * @param {number} offset - Offset to add it at (defaults to current position)
701
+ */
702
+ replace(data, consume, offset) {
703
+ return addData(this, data, consume || false, offset || this.offset, true);
704
+ }
705
+ /**
706
+ * Replaces data in data
707
+ * Note: Must be same data type as supplied data. Errors on strict mode.
708
+ *
709
+ * @param {Buffer|Uint8Array} data - ```Uint8Array``` or ```Buffer``` to replace in data
710
+ * @param {boolean} consume - Move current byte position to end of data (default false)
711
+ * @param {number} offset - Offset to add it at (defaults to current position)
712
+ */
713
+ overwrite(data, consume, offset) {
714
+ return addData(this, data, consume || false, offset || this.offset, true);
715
+ }
716
+ /**
717
+ * Adds data to start of supplied data
718
+ * Note: Must be same data type as supplied data. Errors on strict mode.
719
+ *
720
+ * @param {Buffer|Uint8Array} data - ```Uint8Array``` or ```Buffer``` to add to data
721
+ * @param {boolean} consume - Move current write position to end of data (default false)
722
+ */
723
+ unshift(data, consume) {
724
+ return addData(this, data, consume || false, 0);
725
+ }
726
+ /**
727
+ * Adds data to start of supplied data
728
+ * Note: Must be same data type as supplied data. Errors on strict mode.
729
+ *
730
+ * @param {Buffer|Uint8Array} data - ```Uint8Array``` or ```Buffer``` to add to data
731
+ * @param {boolean} consume - Move current write position to end of data (default false)
357
732
  */
358
- lift(length, consume) {
359
- return this.extract(length, consume);
733
+ prepend(data, consume) {
734
+ return addData(this, data, consume || false, 0);
360
735
  }
361
736
  /**
737
+ * Adds data to end of supplied data
738
+ * Note: Must be same data type as supplied data. Errors on strict mode.
739
+ *
740
+ * @param {Buffer|Uint8Array} data - ```Uint8Array``` or ```Buffer``` to add to data
741
+ * @param {boolean} consume - Move current write position to end of data (default false)
742
+ */
743
+ push(data, consume) {
744
+ return addData(this, data, consume || false, this.size);
745
+ }
746
+ /**
747
+ * Adds data to end of supplied data
748
+ * Note: Must be same data type as supplied data. Errors on strict mode.
749
+ *
750
+ * @param {Buffer|Uint8Array} data - ```Uint8Array``` or ```Buffer``` to add to data
751
+ * @param {boolean} consume - Move current write position to end of data (default false)
752
+ */
753
+ append(data, consume) {
754
+ return addData(this, data, consume || false, this.size);
755
+ }
756
+ //
757
+ //finishing
758
+ //
759
+ /**
362
760
  * Returns current data
761
+ *
363
762
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
364
763
  */
365
764
  get() {
@@ -367,245 +766,81 @@ export class bireader {
367
766
  }
368
767
  /**
369
768
  * Returns current data
769
+ *
370
770
  * @returns {Buffer|Uint8Array} ``Buffer`` or ``Uint8Array``
371
771
  */
372
772
  return() {
373
773
  return this.data;
374
774
  }
375
775
  /**
376
- * removes reading data
776
+ * removes data
377
777
  */
378
778
  end() {
379
- this.data = [];
779
+ this.data = undefined;
380
780
  }
381
781
  /**
382
- * removes reading data
782
+ * removes data
383
783
  */
384
784
  close() {
385
- this.data = [];
785
+ this.data = undefined;
386
786
  }
387
787
  /**
388
- * removes reading data
788
+ * removes data
389
789
  */
390
790
  done() {
391
- this.data = [];
791
+ this.data = undefined;
392
792
  }
393
793
  /**
394
- * removes reading data
794
+ * removes data
395
795
  */
396
796
  finished() {
397
- this.data = [];
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;
797
+ this.data = undefined;
410
798
  }
411
799
  /**
412
800
  * Console logs data as hex dump
413
801
  *
414
- * @param {object} options - options object
802
+ * @param {object} options
415
803
  * ```javascript
416
804
  * {
417
805
  * 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
806
+ * startByte: 0, // byte to start dump (default current byte position)
807
+ * supressUnicode: false // Supress unicode character preview for even columns
420
808
  * }
421
809
  * ```
422
810
  */
423
811
  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"));
812
+ return hexDump(this, options);
813
+ }
814
+ /**
815
+ * Turn hexdump on error off (default on)
816
+ */
817
+ errorDumpOff() {
818
+ this.errorDump = false;
819
+ }
820
+ /**
821
+ * Turn hexdump on error on (default on)
822
+ */
823
+ errorDumpOn() {
824
+ this.errorDump = true;
604
825
  }
605
826
  //
606
827
  //bit reader
607
828
  //
608
829
  /**
830
+ *
831
+ * Write bits, must have at least value and number of bits
832
+ *
833
+ * ``Note``: When returning to a byte write, remaining bits are skipped
834
+ *
835
+ * @param {number} value - value as int
836
+ * @param {number} bits - number of bits to write
837
+ * @param {boolean} unsigned - if value is unsigned
838
+ * @param {string} endian - ``big`` or ``little``
839
+ */
840
+ writeBit(value, bits, unsigned, endian) {
841
+ return wbit(this, value, bits, unsigned, endian);
842
+ }
843
+ /**
609
844
  * Bit field reader
610
845
  *
611
846
  * Note: When returning to a byte read, remaining bits are dropped
@@ -616,48 +851,7 @@ export class bireader {
616
851
  * @returns number
617
852
  */
618
853
  readBit(bits, unsigned, endian) {
619
- if (bits == undefined || typeof bits != "number") {
620
- throw new Error("Enter number of bits to read");
621
- }
622
- if (bits <= 0 || bits > 32) {
623
- throw new Error('Bit length must be between 1 and 32.');
624
- }
625
- const size_needed = ((((bits - 1) + this.bitoffset) / 8) + this.offset);
626
- if (bits <= 0 || size_needed > this.size) {
627
- this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
628
- throw new Error("Invalid number of bits to read: " + size_needed + " of " + this.size);
629
- }
630
- var off_in_bits = (this.offset * 8) + this.bitoffset;
631
- var value = 0;
632
- for (var i = 0; i < bits;) {
633
- var remaining = bits - i;
634
- var bitOffset = off_in_bits & 7;
635
- var currentByte = this.data[off_in_bits >> 3];
636
- var read = Math.min(remaining, 8 - bitOffset);
637
- var mask, readBits;
638
- if ((endian != undefined ? endian : this.endian) == "big") {
639
- mask = ~(0xFF << read);
640
- readBits = (currentByte >> (8 - read - bitOffset)) & mask;
641
- value <<= read;
642
- value |= readBits;
643
- }
644
- else {
645
- mask = ~(0xFF << read);
646
- readBits = (currentByte >> bitOffset) & mask;
647
- value |= readBits << i;
648
- }
649
- off_in_bits += read;
650
- i += read;
651
- }
652
- this.offset = this.offset + Math.floor(((bits) + this.bitoffset) / 8); //end byte
653
- this.bitoffset = ((bits) + this.bitoffset) % 8;
654
- if (unsigned == true || bits <= 7) {
655
- return value >>> 0;
656
- }
657
- if (bits !== 32 && value & (1 << (bits - 1))) {
658
- value |= -1 ^ ((1 << bits) - 1);
659
- }
660
- return value;
854
+ return rbit(this, bits, unsigned, endian);
661
855
  }
662
856
  /**
663
857
  * Bit field reader
@@ -670,7 +864,7 @@ export class bireader {
670
864
  * @returns number
671
865
  */
672
866
  bit(bits, unsigned, endian) {
673
- return this.readBit(bits, unsigned, endian);
867
+ return this.bit(bits, unsigned, endian);
674
868
  }
675
869
  /**
676
870
  * Bit field reader
@@ -678,10 +872,11 @@ export class bireader {
678
872
  * Note: When returning to a byte read, remaining bits are dropped
679
873
  *
680
874
  * @param {boolean} unsigned - if the value is unsigned
875
+ * @param {string} endian - ``big`` or ``little`
681
876
  * @returns number
682
877
  */
683
- bit1(unsigned) {
684
- return this.bit(1, unsigned);
878
+ bit1(unsigned, endian) {
879
+ return this.bit(1, unsigned, endian);
685
880
  }
686
881
  /**
687
882
  * Bit field reader
@@ -2697,7 +2892,7 @@ export class bireader {
2697
2892
  * @returns number
2698
2893
  */
2699
2894
  readUBitBE(bits) {
2700
- return this.readBit(bits, true, "big");
2895
+ return this.bit(bits, true, "big");
2701
2896
  }
2702
2897
  /**
2703
2898
  * Bit field reader
@@ -2708,7 +2903,7 @@ export class bireader {
2708
2903
  * @returns number
2709
2904
  */
2710
2905
  ubitbe(bits) {
2711
- return this.readBit(bits, true, "big");
2906
+ return this.bit(bits, true, "big");
2712
2907
  }
2713
2908
  /**
2714
2909
  * Bit field reader
@@ -2720,7 +2915,7 @@ export class bireader {
2720
2915
  * @returns number
2721
2916
  */
2722
2917
  readBitBE(bits, unsigned) {
2723
- return this.readBit(bits, unsigned, "big");
2918
+ return this.bit(bits, unsigned, "big");
2724
2919
  }
2725
2920
  /**
2726
2921
  * Bit field reader
@@ -2732,7 +2927,7 @@ export class bireader {
2732
2927
  * @returns number
2733
2928
  */
2734
2929
  bitbe(bits, unsigned) {
2735
- return this.readBit(bits, unsigned, "big");
2930
+ return this.bit(bits, unsigned, "big");
2736
2931
  }
2737
2932
  /**
2738
2933
  * Bit field reader
@@ -2743,7 +2938,7 @@ export class bireader {
2743
2938
  * @returns number
2744
2939
  */
2745
2940
  readUBitLE(bits) {
2746
- return this.readBit(bits, true, "little");
2941
+ return this.bit(bits, true, "little");
2747
2942
  }
2748
2943
  /**
2749
2944
  * Bit field reader
@@ -2754,7 +2949,7 @@ export class bireader {
2754
2949
  * @returns number
2755
2950
  */
2756
2951
  ubitle(bits) {
2757
- return this.readBit(bits, true, "little");
2952
+ return this.bit(bits, true, "little");
2758
2953
  }
2759
2954
  /**
2760
2955
  * Bit field reader
@@ -2766,7 +2961,7 @@ export class bireader {
2766
2961
  * @returns number
2767
2962
  */
2768
2963
  readBitLE(bits, unsigned) {
2769
- return this.readBit(bits, unsigned, "little");
2964
+ return this.bit(bits, unsigned, "little");
2770
2965
  }
2771
2966
  /**
2772
2967
  * Bit field reader
@@ -2778,7 +2973,7 @@ export class bireader {
2778
2973
  * @returns number
2779
2974
  */
2780
2975
  bitle(bits, unsigned) {
2781
- return this.readBit(bits, unsigned, "little");
2976
+ return this.bit(bits, unsigned, "little");
2782
2977
  }
2783
2978
  //
2784
2979
  //byte read
@@ -2790,15 +2985,16 @@ export class bireader {
2790
2985
  * @returns number
2791
2986
  */
2792
2987
  readByte(unsigned) {
2793
- this.check_size(1);
2794
- var read = this.data[this.offset];
2795
- this.offset += 1;
2796
- if (unsigned == true) {
2797
- return read & 0xFF;
2798
- }
2799
- else {
2800
- return read > 127 ? read - 256 : read;
2801
- }
2988
+ return rbyte(this, unsigned);
2989
+ }
2990
+ /**
2991
+ * Write byte
2992
+ *
2993
+ * @param {number} value - value as int
2994
+ * @param {boolean} unsigned - if the value is unsigned
2995
+ */
2996
+ writeByte(value, unsigned) {
2997
+ return wbyte(this, value, unsigned);
2802
2998
  }
2803
2999
  /**
2804
3000
  * Read byte
@@ -2853,21 +3049,17 @@ export class bireader {
2853
3049
  * @returns number
2854
3050
  */
2855
3051
  readInt16(unsigned, endian) {
2856
- this.check_size(2);
2857
- var read;
2858
- if ((endian != undefined ? endian : this.endian) == "little") {
2859
- read = (this.data[this.offset + 1] << 8) | this.data[this.offset];
2860
- }
2861
- else {
2862
- read = (this.data[this.offset] << 8) | this.data[this.offset + 1];
2863
- }
2864
- this.offset += 2;
2865
- if (unsigned == undefined || unsigned == false) {
2866
- return read & 0x8000 ? -(0x10000 - read) : read;
2867
- }
2868
- else {
2869
- return read & 0xFFFF;
2870
- }
3052
+ return rint16(this, unsigned, endian);
3053
+ }
3054
+ /**
3055
+ * Write int16
3056
+ *
3057
+ * @param {number} value - value as int
3058
+ * @param {boolean} unsigned - if the value is unsigned
3059
+ * @param {string} endian - ``big`` or ``little`
3060
+ */
3061
+ writeInt16(value, unsigned, endian) {
3062
+ return wint16(this, value, unsigned, endian);
2871
3063
  }
2872
3064
  /**
2873
3065
  * Read short
@@ -3077,34 +3269,16 @@ export class bireader {
3077
3269
  * @returns number
3078
3270
  */
3079
3271
  readHalfFloat(endian) {
3080
- this.check_size(2);
3081
- var uint16Value = this.readInt16(true, (endian != undefined ? endian : this.endian));
3082
- const sign = (uint16Value & 0x8000) >> 15;
3083
- const exponent = (uint16Value & 0x7C00) >> 10;
3084
- const fraction = uint16Value & 0x03FF;
3085
- let floatValue;
3086
- if (exponent === 0) {
3087
- if (fraction === 0) {
3088
- floatValue = (sign === 0) ? 0 : -0; // +/-0
3089
- }
3090
- else {
3091
- // Denormalized number
3092
- floatValue = (sign === 0 ? 1 : -1) * Math.pow(2, -14) * (fraction / 0x0400);
3093
- }
3094
- }
3095
- else if (exponent === 0x1F) {
3096
- if (fraction === 0) {
3097
- floatValue = (sign === 0) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
3098
- }
3099
- else {
3100
- floatValue = Number.NaN;
3101
- }
3102
- }
3103
- else {
3104
- // Normalized number
3105
- floatValue = (sign === 0 ? 1 : -1) * Math.pow(2, exponent - 15) * (1 + fraction / 0x0400);
3106
- }
3107
- return floatValue;
3272
+ return rhalffloat(this, endian);
3273
+ }
3274
+ /**
3275
+ * Writes half float
3276
+ *
3277
+ * @param {number} value - value as int
3278
+ * @param {string} endian - ``big`` or ``little`
3279
+ */
3280
+ writeHalfFloat(value, endian) {
3281
+ return whalffloat(this, value, endian);
3108
3282
  }
3109
3283
  /**
3110
3284
  * Read half float
@@ -3183,21 +3357,17 @@ export class bireader {
3183
3357
  * @returns number
3184
3358
  */
3185
3359
  readInt32(unsigned, endian) {
3186
- this.check_size(4);
3187
- var read;
3188
- if ((endian != undefined ? endian : this.endian) == "little") {
3189
- read = ((this.data[this.offset + 3] << 24) | (this.data[this.offset + 2] << 16) | (this.data[this.offset + 1] << 8) | this.data[this.offset]);
3190
- }
3191
- else {
3192
- read = (this.data[this.offset] << 24) | (this.data[this.offset + 1] << 16) | (this.data[this.offset + 2] << 8) | this.data[this.offset + 3];
3193
- }
3194
- this.offset += 4;
3195
- if (unsigned == undefined || unsigned == false) {
3196
- return read;
3197
- }
3198
- else {
3199
- return read >>> 0;
3200
- }
3360
+ return rint32(this, unsigned, endian);
3361
+ }
3362
+ /**
3363
+ * Write int32
3364
+ *
3365
+ * @param {number} value - value as int
3366
+ * @param {boolean} unsigned - if the value is unsigned
3367
+ * @param {string} endian - ``big`` or ``little`
3368
+ */
3369
+ writeInt32(value, unsigned, endian) {
3370
+ return wint32(this, value, unsigned, endian);
3201
3371
  }
3202
3372
  /**
3203
3373
  * Read 32 bit integer
@@ -3449,28 +3619,16 @@ export class bireader {
3449
3619
  * @returns number
3450
3620
  */
3451
3621
  readFloat(endian) {
3452
- this.check_size(4);
3453
- var uint32Value = this.readInt32(true, (endian == undefined ? this.endian : endian));
3454
- // Check if the value is negative (i.e., the most significant bit is set)
3455
- const isNegative = (uint32Value & 0x80000000) !== 0 ? 1 : 0;
3456
- // Extract the exponent and fraction parts
3457
- const exponent = (uint32Value >> 23) & 0xFF;
3458
- const fraction = uint32Value & 0x7FFFFF;
3459
- // Calculate the float value
3460
- let floatValue;
3461
- if (exponent === 0) {
3462
- // Denormalized number (exponent is 0)
3463
- floatValue = Math.pow(-1, isNegative) * Math.pow(2, -126) * (fraction / Math.pow(2, 23));
3464
- }
3465
- else if (exponent === 0xFF) {
3466
- // Infinity or NaN (exponent is 255)
3467
- floatValue = fraction === 0 ? (isNegative ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY) : Number.NaN;
3468
- }
3469
- else {
3470
- // Normalized number
3471
- floatValue = Math.pow(-1, isNegative) * Math.pow(2, exponent - 127) * (1 + fraction / Math.pow(2, 23));
3472
- }
3473
- return floatValue;
3622
+ return rfloat(this, endian);
3623
+ }
3624
+ /**
3625
+ * Write float
3626
+ *
3627
+ * @param {number} value - value as int
3628
+ * @param {string} endian - ``big`` or ``little`
3629
+ */
3630
+ writeFloat(value, endian) {
3631
+ return wfloat(this, value, endian);
3474
3632
  }
3475
3633
  /**
3476
3634
  * Read float
@@ -3523,39 +3681,17 @@ export class bireader {
3523
3681
  * @returns number
3524
3682
  */
3525
3683
  readInt64(unsigned, endian) {
3526
- this.check_size(8);
3527
- // Convert the byte array to a BigInt
3528
- let value = BigInt(0);
3529
- if ((endian == undefined ? this.endian : endian) == "little") {
3530
- for (let i = 0; i < 8; i++) {
3531
- value = value | BigInt(this.data[this.offset]) << BigInt(8 * i);
3532
- this.offset += 1;
3533
- }
3534
- if (unsigned == undefined || unsigned == false) {
3535
- if (value & (BigInt(1) << BigInt(63))) {
3536
- value -= BigInt(1) << BigInt(64);
3537
- }
3538
- return value;
3539
- }
3540
- else {
3541
- return value;
3542
- }
3543
- }
3544
- else {
3545
- for (let i = 0; i < 8; i++) {
3546
- value = (value << BigInt(8)) | BigInt(this.data[this.offset]);
3547
- this.offset += 1;
3548
- }
3549
- if (unsigned == undefined || unsigned == false) {
3550
- if (value & (BigInt(1) << BigInt(63))) {
3551
- value -= BigInt(1) << BigInt(64);
3552
- }
3553
- return value;
3554
- }
3555
- else {
3556
- return value;
3557
- }
3558
- }
3684
+ return rint64(this, unsigned, endian);
3685
+ }
3686
+ /**
3687
+ * Write 64 bit integer
3688
+ *
3689
+ * @param {number} value - value as int
3690
+ * @param {boolean} unsigned - if the value is unsigned
3691
+ * @param {string} endian - ``big`` or ``little`
3692
+ */
3693
+ writeInt64(value, unsigned, endian) {
3694
+ return wint64(this, value, unsigned, endian);
3559
3695
  }
3560
3696
  /**
3561
3697
  * Read signed 64 bit integer
@@ -3754,34 +3890,17 @@ export class bireader {
3754
3890
  * @returns number
3755
3891
  */
3756
3892
  readDoubleFloat(endian) {
3757
- this.check_size(8);
3758
- var uint64Value = this.readInt64(true, (endian == undefined ? this.endian : endian));
3759
- const sign = (uint64Value & 0x8000000000000000n) >> 63n;
3760
- const exponent = Number((uint64Value & 0x7ff0000000000000n) >> 52n) - 1023;
3761
- const fraction = Number(uint64Value & 0x000fffffffffffffn) / Math.pow(2, 52);
3762
- var floatValue;
3763
- if (exponent == -1023) {
3764
- if (fraction == 0) {
3765
- floatValue = (sign == 0n) ? 0 : -0; // +/-0
3766
- }
3767
- else {
3768
- // Denormalized number
3769
- floatValue = (sign == 0n ? 1 : -1) * Math.pow(2, -1022) * fraction;
3770
- }
3771
- }
3772
- else if (exponent == 1024) {
3773
- if (fraction == 0) {
3774
- floatValue = (sign == 0n) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
3775
- }
3776
- else {
3777
- floatValue = Number.NaN;
3778
- }
3779
- }
3780
- else {
3781
- // Normalized number
3782
- floatValue = (sign == 0n ? 1 : -1) * Math.pow(2, exponent) * (1 + fraction);
3783
- }
3784
- return floatValue;
3893
+ return rdfloat(this, endian);
3894
+ }
3895
+ /**
3896
+ * Writes double float
3897
+ *
3898
+ * @param {number} value - value as int
3899
+ * @param {number} offset - byte offset (default last write position)
3900
+ * @param {string} endian - ``big`` or ``little`
3901
+ */
3902
+ writeDoubleFloat(value, endian) {
3903
+ return wdfloat(this, value, endian);
3785
3904
  }
3786
3905
  /**
3787
3906
  * Read double float
@@ -3870,127 +3989,45 @@ export class bireader {
3870
3989
  * @return string
3871
3990
  */
3872
3991
  readString(options) {
3873
- var length = options && options.length;
3874
- var stringType = options && options.stringType || 'utf-8';
3875
- var terminateValue = options && options.terminateValue;
3876
- var lengthReadSize = options && options.lengthReadSize || 1;
3877
- var stripNull = options && options.stripNull || true;
3878
- var encoding = options && options.encoding || 'utf-8';
3879
- var endian = options && options.endian || this.endian;
3880
- var terminate = terminateValue;
3881
- if (length != undefined) {
3882
- this.check_size(length);
3883
- }
3884
- if (typeof terminateValue == "number") {
3885
- terminate = terminateValue & 0xFF;
3886
- }
3887
- else {
3888
- if (terminateValue != undefined) {
3889
- throw new Error("terminateValue must be a number");
3890
- }
3891
- }
3892
- if (stringType == 'utf-8' || stringType == 'utf-16') {
3893
- if (encoding == undefined) {
3894
- if (stringType == 'utf-8') {
3895
- encoding = 'utf-8';
3896
- }
3897
- if (stringType == 'utf-16') {
3898
- encoding = 'utf-16';
3899
- }
3900
- }
3901
- // Read the string as UTF-8 encoded untill 0 or terminateValue
3902
- const encodedBytes = [];
3903
- if (length == undefined && terminateValue == undefined) {
3904
- terminate = 0;
3905
- }
3906
- var read_length = 0;
3907
- if (length != undefined) {
3908
- read_length = length;
3909
- }
3910
- else {
3911
- read_length = this.data.length - this.offset;
3912
- }
3913
- for (let i = 0; i < read_length; i++) {
3914
- if (stringType === 'utf-8') {
3915
- var read = this.readUByte();
3916
- if (read == terminate) {
3917
- break;
3918
- }
3919
- else {
3920
- if (!(stripNull == true && read == 0)) {
3921
- encodedBytes.push(read);
3922
- }
3923
- }
3924
- }
3925
- else {
3926
- var read = this.readInt16(true, endian);
3927
- var read1 = read & 0xFF;
3928
- var read2 = (read >> 8) & 0xFF;
3929
- if (read == terminate) {
3930
- break;
3931
- }
3932
- else {
3933
- if (!(stripNull == true && read == 0)) {
3934
- encodedBytes.push(read1);
3935
- encodedBytes.push(read2);
3936
- }
3937
- }
3938
- }
3939
- }
3940
- return new TextDecoder(encoding).decode(new Uint8Array(encodedBytes));
3941
- }
3942
- else if (stringType == 'pascal' || stringType == 'wide-pascal') {
3943
- if (encoding == undefined) {
3944
- if (stringType == 'pascal') {
3945
- encoding = 'utf-8';
3946
- }
3947
- if (stringType == 'wide-pascal') {
3948
- encoding = 'utf-16';
3949
- }
3950
- }
3951
- var maxBytes;
3952
- if (lengthReadSize == 1) {
3953
- maxBytes = this.readUByte();
3954
- }
3955
- else if (lengthReadSize == 2) {
3956
- maxBytes = this.readInt16(true, endian);
3957
- }
3958
- else if (lengthReadSize == 4) {
3959
- maxBytes = this.readInt32(true, endian);
3960
- }
3961
- else {
3962
- this.errorDump ? "[Error], hexdump:\n" + this.hexdump() : "";
3963
- throw new Error("Invalid length read size: " + lengthReadSize);
3964
- }
3965
- // Read the string as Pascal or Delphi encoded
3966
- const encodedBytes = [];
3967
- for (let i = 0; i < maxBytes; i++) {
3968
- if (stringType == 'wide-pascal') {
3969
- const read = this.readInt16(true, endian);
3970
- if (!(stripNull == true && read == 0)) {
3971
- encodedBytes.push(read);
3972
- }
3973
- }
3974
- else {
3975
- const read = this.readUByte();
3976
- if (!(stripNull == true && read == 0)) {
3977
- encodedBytes.push(read);
3978
- }
3979
- }
3980
- }
3981
- var str_return;
3982
- if (stringType == 'wide-pascal') {
3983
- str_return = new TextDecoder(encoding).decode(new Uint16Array(encodedBytes));
3984
- }
3985
- else {
3986
- str_return = new TextDecoder(encoding).decode(new Uint8Array(encodedBytes));
3987
- }
3988
- return str_return;
3989
- }
3990
- else {
3991
- throw new Error('Unsupported string type: ' + stringType);
3992
- }
3992
+ return rstring(this, options);
3993
+ }
3994
+ /**
3995
+ * Writes string, use options object for different types
3996
+ *
3997
+ *
3998
+ * @param {string} string - text string
3999
+ * @param {object} options - options:
4000
+ * ```javascript
4001
+ * {
4002
+ * length: string.length, //for fixed length, non-terminate value utf strings
4003
+ * stringType: "utf-8", //utf-8, utf-16, pascal or wide-pascal
4004
+ * terminateValue: 0x00, // only with stringType: "utf"
4005
+ * lengthWriteSize: 1, //for pascal strings. 1, 2 or 4 byte length write size
4006
+ * encoding: "utf-8", //TextEncoder accepted types
4007
+ * endian: "little", //for wide-pascal and utf-16
4008
+ * }
4009
+ * ```
4010
+ */
4011
+ writeString(string, options) {
4012
+ return wstring(this, string, options);
3993
4013
  }
4014
+ /**
4015
+ * Reads string, use options object for different types
4016
+ *
4017
+ * @param {object} options
4018
+ * ```javascript
4019
+ * {
4020
+ * length: number, //for fixed length, non-terminate value utf strings
4021
+ * stringType: "utf-8", //utf-8, utf-16, pascal or wide-pascal
4022
+ * terminateValue: 0x00, // only for non-fixed length utf strings
4023
+ * lengthReadSize: 1, //for pascal strings. 1, 2 or 4 byte length read size
4024
+ * stripNull: true, // removes 0x00 characters
4025
+ * encoding: "utf-8", //TextEncoder accepted types
4026
+ * endian: "little", //for wide-pascal and utf-16
4027
+ * }
4028
+ * ```
4029
+ * @return string
4030
+ */
3994
4031
  string(options) {
3995
4032
  return this.readString(options);
3996
4033
  }