@@ -33,8 +33,8 @@ public KaitaiStream(byte[] bytes) : base(new MemoryStream(bytes))
33
33
{
34
34
}
35
35
36
- private ulong Bits = 0 ;
37
36
private int BitsLeft = 0 ;
37
+ private ulong Bits = 0 ;
38
38
39
39
static readonly bool IsLittleEndian = BitConverter . IsLittleEndian ;
40
40
@@ -283,8 +283,8 @@ public double ReadF8le()
283
283
284
284
public void AlignToByte ( )
285
285
{
286
- Bits = 0 ;
287
286
BitsLeft = 0 ;
287
+ Bits = 0 ;
288
288
}
289
289
290
290
/// <summary>
@@ -293,30 +293,33 @@ public void AlignToByte()
293
293
/// <returns></returns>
294
294
public ulong ReadBitsIntBe ( int n )
295
295
{
296
+ ulong res = 0 ;
297
+
296
298
int bitsNeeded = n - BitsLeft ;
299
+ BitsLeft = - bitsNeeded & 7 ; // `-bitsNeeded mod 8`
300
+
297
301
if ( bitsNeeded > 0 )
298
302
{
299
303
// 1 bit => 1 byte
300
304
// 8 bits => 1 byte
301
305
// 9 bits => 2 bytes
302
- int bytesNeeded = ( ( bitsNeeded - 1 ) / 8 ) + 1 ;
306
+ int bytesNeeded = ( ( bitsNeeded - 1 ) / 8 ) + 1 ; // `ceil(bitsNeeded / 8)`
303
307
byte [ ] buf = ReadBytes ( bytesNeeded ) ;
304
- for ( int i = 0 ; i < buf . Length ; i ++ )
308
+ for ( int i = 0 ; i < bytesNeeded ; i ++ )
305
309
{
306
- Bits <<= 8 ;
307
- Bits |= buf [ i ] ;
308
- BitsLeft += 8 ;
310
+ res = res << 8 | buf [ i ] ;
309
311
}
312
+
313
+ ulong newBits = res ;
314
+ res = res >> BitsLeft | Bits << bitsNeeded ;
315
+ Bits = newBits ; // will be masked at the end of the function
316
+ }
317
+ else
318
+ {
319
+ res = Bits >> - bitsNeeded ; // shift unneeded bits out
310
320
}
311
321
312
- // raw mask with required number of 1s, starting from lowest bit
313
- ulong mask = GetMaskOnes ( n ) ;
314
- // shift "bits" to align the highest bits with the mask & derive reading result
315
- int shiftBits = BitsLeft - n ;
316
- ulong res = ( Bits >> shiftBits ) & mask ;
317
- // clear top bits that we've just read => AND with 1s
318
- BitsLeft -= n ;
319
- mask = GetMaskOnes ( BitsLeft ) ;
322
+ ulong mask = ( 1UL << BitsLeft ) - 1 ; // `BitsLeft` is in range 0..7, so `(1UL << 64)` does not have to be considered
320
323
Bits &= mask ;
321
324
322
325
return res ;
@@ -334,41 +337,46 @@ public ulong ReadBitsInt(int n)
334
337
/// <returns></returns>
335
338
public ulong ReadBitsIntLe ( int n )
336
339
{
340
+ ulong res = 0 ;
337
341
int bitsNeeded = n - BitsLeft ;
338
342
339
343
if ( bitsNeeded > 0 )
340
344
{
341
345
// 1 bit => 1 byte
342
346
// 8 bits => 1 byte
343
347
// 9 bits => 2 bytes
344
- int bytesNeeded = ( ( bitsNeeded - 1 ) / 8 ) + 1 ;
348
+ int bytesNeeded = ( ( bitsNeeded - 1 ) / 8 ) + 1 ; // `ceil(bitsNeeded / 8)`
345
349
byte [ ] buf = ReadBytes ( bytesNeeded ) ;
346
- for ( int i = 0 ; i < buf . Length ; i ++ )
350
+ for ( int i = 0 ; i < bytesNeeded ; i ++ )
347
351
{
348
- ulong v = ( ulong ) ( ( ulong ) buf [ i ] << BitsLeft ) ;
349
- Bits |= v ;
350
- BitsLeft += 8 ;
352
+ res |= ( ( ulong ) buf [ i ] ) << ( i * 8 ) ;
351
353
}
352
- }
353
354
354
- // raw mask with required number of 1s, starting from lowest bit
355
- ulong mask = GetMaskOnes ( n ) ;
356
-
357
- // derive reading result
358
- ulong res = ( Bits & mask ) ;
355
+ // NB: in C#, bit shift operators on left-hand operand of type `ulong` work
356
+ // as if the right-hand operand were subjected to `& 63` (`& 0b11_1111`) (see
357
+ // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#shift-count-of-the-shift-operators),
358
+ // so `res >> 64` is equivalent to `res >> 0` (but we don't want that)
359
+ ulong newBits = bitsNeeded < 64 ? res >> bitsNeeded : 0 ;
360
+ res = res << BitsLeft | Bits ;
361
+ Bits = newBits ;
362
+ }
363
+ else
364
+ {
365
+ res = Bits ;
366
+ Bits >>= n ;
367
+ }
359
368
360
- // remove bottom bits that we've just read by shifting
361
- Bits >>= n ;
362
- BitsLeft -= n ;
369
+ BitsLeft = - bitsNeeded & 7 ; // `-bitsNeeded mod 8`
363
370
371
+ if ( n < 64 )
372
+ {
373
+ ulong mask = ( 1UL << n ) - 1 ;
374
+ res &= mask ;
375
+ }
376
+ // if `n == 64`, do nothing
364
377
return res ;
365
378
}
366
379
367
- private static ulong GetMaskOnes ( int n )
368
- {
369
- return n == 64 ? 0xffffffffffffffffUL : ( 1UL << n ) - 1 ;
370
- }
371
-
372
380
#endregion
373
381
374
382
#region Byte arrays
0 commit comments