Skip to content

Commit 0d25ee0

Browse files
committed
Add read{S,U}8{be,le}AsBigInt()
See kaitai-io/kaitai_struct#183 The compiler will switch to using only these new `*AsBigInt()` methods for reading 64-bit integers. After that, we will be able to deprecate the legacy `Number` methods (`read{S,U}8{be,le}()`) and eventually remove them.
1 parent 183e099 commit 0d25ee0

1 file changed

Lines changed: 124 additions & 20 deletions

File tree

KaitaiStream.ts

Lines changed: 124 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,21 @@ class KaitaiStream {
242242
}
243243

244244
/**
245-
* Reads a 64-bit big-endian unsigned int from the stream. Note that
246-
* JavaScript does not support 64-bit integers natively, so it will
247-
* automatically upgrade internal representation to use IEEE 754
248-
* double precision float.
245+
* Reads a 64-bit big-endian signed int from the stream and returns it as
246+
* a {@link Number}.
249247
*
250-
* @returns The read number.
248+
* Note that the {@link Number} type in JavaScript cannot accurately represent
249+
* 64-bit integers, as it is an IEEE 754 double-precision floating-point
250+
* number, which has a precision of only 53 bits. Therefore, integers greater
251+
* than {@link Number.MAX_SAFE_INTEGER} (`2**53 - 1` or
252+
* `0x001f_ffff_ffff_ffff`) or less than {@link Number.MIN_SAFE_INTEGER}
253+
* (`-2**53 + 1` or `-0x001f_ffff_ffff_ffff`) will be rounded, with a maximum
254+
* rounding error of +- 512 for values above `2**62` or below `-2**62`. If
255+
* this loss of precision is unacceptable, use {@link readS8beAsBigInt}
256+
* instead.
257+
*
258+
* @returns The 64-bit signed integer read from the stream, potentially rounded.
259+
* @see {@link readS8beAsBigInt}
251260
*/
252261
public readS8be(): number {
253262
this.alignToByte();
@@ -263,6 +272,24 @@ class KaitaiStream {
263272
}
264273
}
265274

275+
/**
276+
* Reads a 64-bit big-endian signed int from the stream and returns it as
277+
* a {@link BigInt}.
278+
*
279+
* Unlike {@link readS8be}, this method returns the exact value without any
280+
* loss of precision. This is made possible by the {@link BigInt} type.
281+
*
282+
* @returns The exact 64-bit signed integer read from the stream.
283+
* @see {@link readS8be}
284+
*/
285+
public readS8beAsBigInt(): bigint {
286+
this.alignToByte();
287+
this.ensureBytesLeft(8);
288+
const v = this._dataView.getBigInt64(this.pos);
289+
this.pos += 8;
290+
return v;
291+
}
292+
266293
// ........................................................................
267294
// Little-endian
268295
// ........................................................................
@@ -294,12 +321,21 @@ class KaitaiStream {
294321
}
295322

296323
/**
297-
* Reads a 64-bit little-endian unsigned int from the stream. Note that
298-
* JavaScript does not support 64-bit integers natively, so it will
299-
* automatically upgrade internal representation to use IEEE 754
300-
* double precision float.
324+
* Reads a 64-bit little-endian signed int from the stream and returns it as
325+
* a {@link Number}.
301326
*
302-
* @returns The read number.
327+
* Note that the {@link Number} type in JavaScript cannot accurately represent
328+
* 64-bit integers, as it is an IEEE 754 double-precision floating-point
329+
* number, which has a precision of only 53 bits. Therefore, integers greater
330+
* than {@link Number.MAX_SAFE_INTEGER} (`2**53 - 1` or
331+
* `0x001f_ffff_ffff_ffff`) or less than {@link Number.MIN_SAFE_INTEGER}
332+
* (`-2**53 + 1` or `-0x001f_ffff_ffff_ffff`) will be rounded, with a maximum
333+
* rounding error of +- 512 for values above `2**62` or below `-2**62`. If
334+
* this loss of precision is unacceptable, use {@link readS8leAsBigInt}
335+
* instead.
336+
*
337+
* @returns The 64-bit signed integer read from the stream, potentially rounded.
338+
* @see {@link readS8leAsBigInt}
303339
*/
304340
public readS8le(): number {
305341
this.alignToByte();
@@ -315,6 +351,24 @@ class KaitaiStream {
315351
}
316352
}
317353

354+
/**
355+
* Reads a 64-bit little-endian signed int from the stream and returns it as
356+
* a {@link BigInt}.
357+
*
358+
* Unlike {@link readS8le}, this method returns the exact value without any
359+
* loss of precision. This is made possible by the {@link BigInt} type.
360+
*
361+
* @returns The exact 64-bit signed integer read from the stream.
362+
* @see {@link readS8le}
363+
*/
364+
public readS8leAsBigInt(): bigint {
365+
this.alignToByte();
366+
this.ensureBytesLeft(8);
367+
const v = this._dataView.getBigInt64(this.pos, true);
368+
this.pos += 8;
369+
return v;
370+
}
371+
318372
// ------------------------------------------------------------------------
319373
// Unsigned
320374
// ------------------------------------------------------------------------
@@ -363,12 +417,19 @@ class KaitaiStream {
363417
}
364418

365419
/**
366-
* Reads a 64-bit big-endian unsigned int from the stream. Note that
367-
* JavaScript does not support 64-bit integers natively, so it will
368-
* automatically upgrade internal representation to use IEEE 754
369-
* double precision float.
420+
* Reads a 64-bit big-endian unsigned int from the stream and returns it as
421+
* a {@link Number}.
370422
*
371-
* @returns The read number.
423+
* Note that the {@link Number} type in JavaScript cannot accurately represent
424+
* 64-bit integers, as it is an IEEE 754 double-precision floating-point
425+
* number, which has a precision of only 53 bits. Therefore, integers greater
426+
* than {@link Number.MAX_SAFE_INTEGER} (`2**53 - 1` or
427+
* `0x001f_ffff_ffff_ffff`) will be rounded, with a maximum rounding error of
428+
* +- 1024 for values above `2**63`. If this loss of precision is
429+
* unacceptable, use {@link readU8beAsBigInt} instead.
430+
*
431+
* @returns The 64-bit unsigned integer read from the stream, potentially rounded.
432+
* @see {@link readU8beAsBigInt}
372433
*/
373434
public readU8be(): number {
374435
this.alignToByte();
@@ -378,6 +439,24 @@ class KaitaiStream {
378439
return 0x100000000 * v1 + v2;
379440
}
380441

442+
/**
443+
* Reads a 64-bit big-endian unsigned int from the stream and returns it as
444+
* a {@link BigInt}.
445+
*
446+
* Unlike {@link readU8be}, this method returns the exact value without any
447+
* loss of precision. This is made possible by the {@link BigInt} type.
448+
*
449+
* @returns The exact 64-bit unsigned integer read from the stream.
450+
* @see {@link readU8be}
451+
*/
452+
public readU8beAsBigInt(): bigint {
453+
this.alignToByte();
454+
this.ensureBytesLeft(8);
455+
const v = this._dataView.getBigUint64(this.pos);
456+
this.pos += 8;
457+
return v;
458+
}
459+
381460
// ........................................................................
382461
// Little-endian
383462
// ........................................................................
@@ -409,12 +488,19 @@ class KaitaiStream {
409488
}
410489

411490
/**
412-
* Reads a 64-bit little-endian unsigned int from the stream. Note that
413-
* JavaScript does not support 64-bit integers natively, so it will
414-
* automatically upgrade internal representation to use IEEE 754
415-
* double precision float.
491+
* Reads a 64-bit little-endian unsigned int from the stream and returns it as
492+
* a {@link Number}.
416493
*
417-
* @returns The read number.
494+
* Note that the {@link Number} type in JavaScript cannot accurately represent
495+
* 64-bit integers, as it is an IEEE 754 double-precision floating-point
496+
* number, which has a precision of only 53 bits. Therefore, integers greater
497+
* than {@link Number.MAX_SAFE_INTEGER} (`2**53 - 1` or
498+
* `0x001f_ffff_ffff_ffff`) will be rounded, with a maximum rounding error of
499+
* +- 1024 for values above `2**63`. If this loss of precision is
500+
* unacceptable, use {@link readU8leAsBigInt} instead.
501+
*
502+
* @returns The 64-bit unsigned integer read from the stream, potentially rounded.
503+
* @see {@link readU8leAsBigInt}
418504
*/
419505
public readU8le(): number {
420506
this.alignToByte();
@@ -424,6 +510,24 @@ class KaitaiStream {
424510
return 0x100000000 * v2 + v1;
425511
}
426512

513+
/**
514+
* Reads a 64-bit little-endian unsigned int from the stream and returns it as
515+
* a {@link BigInt}.
516+
*
517+
* Unlike {@link readU8le}, this method returns the exact value without any
518+
* loss of precision. This is made possible by the {@link BigInt} type.
519+
*
520+
* @returns The exact 64-bit unsigned integer read from the stream.
521+
* @see {@link readU8le}
522+
*/
523+
public readU8leAsBigInt(): bigint {
524+
this.alignToByte();
525+
this.ensureBytesLeft(8);
526+
const v = this._dataView.getBigUint64(this.pos, true);
527+
this.pos += 8;
528+
return v;
529+
}
530+
427531
// ========================================================================
428532
// Floating point numbers
429533
// ========================================================================

0 commit comments

Comments
 (0)