@@ -412,40 +412,53 @@ KaitaiStream.prototype.readF8le = function() {
412
412
// ------------------------------------------------------------------------
413
413
414
414
KaitaiStream . prototype . alignToByte = function ( ) {
415
- this . bits = 0 ;
416
415
this . bitsLeft = 0 ;
416
+ this . bits = 0 ;
417
417
} ;
418
418
419
+ /*
420
+ bitsLeft = 3
421
+ \ \ bitsNeeded = 10 -> bytesNeeded = 2
422
+ \ \ / \
423
+ |01101xxx|xxxxxxxx|xx......|
424
+ \ /\ \
425
+ \__ n = 13 _/ \ \
426
+ new bitsLeft = 6
427
+ */
419
428
KaitaiStream . prototype . readBitsIntBe = function ( n ) {
420
429
// JS only supports bit operations on 32 bits
421
430
if ( n > 32 ) {
422
431
throw new Error ( "readBitsIntBe: the maximum supported bit length is 32 (tried to read " + n + " bits)" ) ;
423
432
}
433
+ var res = 0 ;
434
+
424
435
var bitsNeeded = n - this . bitsLeft ;
436
+ this . bitsLeft = - bitsNeeded & 7 ; // `-bitsNeeded mod 8`
437
+
425
438
if ( bitsNeeded > 0 ) {
426
439
// 1 bit => 1 byte
427
440
// 8 bits => 1 byte
428
441
// 9 bits => 2 bytes
429
- var bytesNeeded = Math . ceil ( bitsNeeded / 8 ) ;
442
+ var bytesNeeded = ( ( bitsNeeded - 1 ) >> 3 ) + 1 ; // ` ceil(bitsNeeded / 8)` (NB: `x >> 3` is `floor(x / 8)`)
430
443
var buf = this . readBytes ( bytesNeeded ) ;
431
444
for ( var i = 0 ; i < bytesNeeded ; i ++ ) {
432
- this . bits <<= 8 ;
433
- this . bits |= buf [ i ] ;
434
- this . bitsLeft += 8 ;
445
+ res = res << 8 | buf [ i ] ;
435
446
}
447
+
448
+ var newBits = res ;
449
+ res = res >>> this . bitsLeft | this . bits << bitsNeeded ; // `x << 32` is defined as `x << 0` in JS, but only `0 << 32`
450
+ // can occur here (`n = 32` and `bitsLeft = 0`, this implies
451
+ // `bits = 0` unless changed externally)
452
+ this . bits = newBits ; // will be masked at the end of the function
453
+ } else {
454
+ res = this . bits >>> - bitsNeeded ; // shift unneeded bits out
436
455
}
437
456
438
- // raw mask with required number of 1s, starting from lowest bit
439
- var mask = n === 32 ? 0xffffffff : ( 1 << n ) - 1 ;
440
- // shift this.bits to align the highest bits with the mask & derive reading result
441
- var shiftBits = this . bitsLeft - n ;
442
- var res = ( this . bits >>> shiftBits ) & mask ;
443
- // clear top bits that we've just read => AND with 1s
444
- this . bitsLeft -= n ;
445
- mask = ( 1 << this . bitsLeft ) - 1 ;
457
+ var mask = ( 1 << this . bitsLeft ) - 1 ; // `bitsLeft` is in range 0..7, so `(1 << 32)` does not have to be considered
446
458
this . bits &= mask ;
447
459
448
- return res ;
460
+ // always return an unsigned 32-bit integer
461
+ return res >>> 0 ;
449
462
} ;
450
463
451
464
/**
@@ -455,32 +468,59 @@ KaitaiStream.prototype.readBitsIntBe = function(n) {
455
468
*/
456
469
KaitaiStream . prototype . readBitsInt = KaitaiStream . prototype . readBitsIntBe ;
457
470
471
+ /*
472
+ n = 13 bitsNeeded = 10
473
+ / \
474
+ bitsLeft = 3 ______ __
475
+ \ \ / \ \ \
476
+ |xxx01101|xxxxxxxx|......xx|
477
+ \ /
478
+ new bitsLeft = 6
479
+
480
+ bitsLeft = 7
481
+ \ \
482
+ |01101100|..xxxxx1|........|
483
+ \___/
484
+ n = 5
485
+ */
458
486
KaitaiStream . prototype . readBitsIntLe = function ( n ) {
459
487
// JS only supports bit operations on 32 bits
460
488
if ( n > 32 ) {
461
489
throw new Error ( "readBitsIntLe: the maximum supported bit length is 32 (tried to read " + n + " bits)" ) ;
462
490
}
491
+ var res = 0 ;
463
492
var bitsNeeded = n - this . bitsLeft ;
493
+
464
494
if ( bitsNeeded > 0 ) {
465
- // 1 bit => 1 byte
466
- // 8 bits => 1 byte
467
- // 9 bits => 2 bytes
468
- var bytesNeeded = Math . ceil ( bitsNeeded / 8 ) ;
469
- var buf = this . readBytes ( bytesNeeded ) ;
470
- for ( var i = 0 ; i < bytesNeeded ; i ++ ) {
471
- this . bits |= ( buf [ i ] << this . bitsLeft ) ;
472
- this . bitsLeft += 8 ;
473
- }
495
+ // 1 bit => 1 byte
496
+ // 8 bits => 1 byte
497
+ // 9 bits => 2 bytes
498
+ var bytesNeeded = ( ( bitsNeeded - 1 ) >> 3 ) + 1 ; // `ceil(bitsNeeded / 8)` (NB: `x >> 3` is `floor(x / 8)`)
499
+ var buf = this . readBytes ( bytesNeeded ) ;
500
+ for ( var i = 0 ; i < bytesNeeded ; i ++ ) {
501
+ res |= buf [ i ] << ( i * 8 ) ;
502
+ }
503
+
504
+ // NB: in JavaScript, bit shift operators always shift by modulo 32 of the right-hand operand (see
505
+ // https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-unsignedRightShift),
506
+ // so `res >>> 32` is equivalent to `res >>> 0` (but we don't want that)
507
+ var newBits = bitsNeeded < 32 ? res >>> bitsNeeded : 0 ;
508
+ res = res << this . bitsLeft | this . bits ;
509
+ this . bits = newBits ;
510
+ } else {
511
+ res = this . bits ;
512
+ this . bits >>>= n ;
474
513
}
475
514
476
- // raw mask with required number of 1s, starting from lowest bit
477
- var mask = n === 32 ? 0xffffffff : ( 1 << n ) - 1 ;
478
- // derive reading result
479
- var res = this . bits & mask ;
480
- // remove bottom bits that we've just read by shifting
481
- this . bits >>>= n ;
482
- this . bitsLeft -= n ;
515
+ this . bitsLeft = - bitsNeeded & 7 ; // `-bitsNeeded mod 8`
483
516
517
+ // always return an unsigned 32-bit integer
518
+ if ( n < 32 ) {
519
+ var mask = ( 1 << n ) - 1 ;
520
+ res &= mask ; // this produces a signed 32-bit int, but the sign bit is cleared
521
+ } else {
522
+ res >>>= 0 ;
523
+ }
484
524
return res ;
485
525
} ;
486
526
0 commit comments