@@ -53,6 +53,11 @@ public KaitaiStream(byte[] data) : base(new MemoryStream(data))
53
53
/// </summary>
54
54
static readonly bool IsLittleEndian = BitConverter . IsLittleEndian ;
55
55
56
+ static KaitaiStream ( )
57
+ {
58
+ computeSingleRotations ( ) ;
59
+ }
60
+
56
61
#endregion
57
62
58
63
#region Stream positioning
@@ -555,33 +560,98 @@ public byte[] ProcessXor(byte[] data, byte[] key)
555
560
return result ;
556
561
}
557
562
563
+ private static byte [ ] [ ] precomputedSingleRotations ;
564
+
565
+ /// <summary>
566
+ /// Speeds up <c>ProcessRotateLeft</c> by precomputing translations tables.
567
+ /// In effect only when groupSize is 1.
568
+ /// </summary>
569
+ private static void computeSingleRotations ( )
570
+ {
571
+ precomputedSingleRotations = new byte [ 8 ] [ ] ;
572
+ for ( int amount = 1 ; amount < 8 ; amount ++ )
573
+ {
574
+ int anti_amount = 8 - amount ;
575
+ byte [ ] translate = new byte [ 256 ] ;
576
+ for ( int i = 0 ; i < 256 ; i ++ )
577
+ {
578
+ // formula taken from: http://stackoverflow.com/a/812039
579
+ translate [ i ] = ( byte ) ( ( i << amount ) | ( i >> anti_amount ) ) ;
580
+ }
581
+ precomputedSingleRotations [ amount ] = translate ;
582
+ }
583
+ }
584
+
558
585
/// <summary>
559
586
/// Perform circular left rotation shift for a given data by a given amount of bits.
560
587
/// Pass a negative amount to rotate right.
588
+ /// WARNING: May return same byte array if amount is zero (modulo-wise).
561
589
/// </summary>
562
590
/// <param name="data">The data to rotate, as byte array</param>
563
- /// <param name="amount">The amount to rotate by (in bits), as integer</param>
564
- /// <param name="groupSize">The size of group in which rotation happens, as non-negative integer</param>
591
+ /// <param name="amount">The amount to rotate by (in bits), as integer, negative for right rotation </param>
592
+ /// <param name="groupSize">The size of group in which rotation happens, as positive integer</param>
565
593
public byte [ ] ProcessRotateLeft ( byte [ ] data , int amount , int groupSize )
566
594
{
567
- if ( amount > 7 || amount < - 7 ) throw new ArgumentException ( "Rotation of more than 7 cannot be performed." , "amount" ) ;
568
- if ( amount < 0 ) amount += 8 ; // Rotation of -2 is the same as rotation of +6
595
+ if ( groupSize < 1 )
596
+ throw new ArgumentException ( "group size must be at least 1 to be valid" , "groupSize" ) ;
597
+
598
+ amount = Mod ( amount , groupSize * 8 ) ;
599
+ if ( amount == 0 )
600
+ return data ;
569
601
570
- byte [ ] r = new byte [ data . Length ] ;
571
- switch ( groupSize )
602
+ int amount_bytes = amount / 8 ;
603
+ byte [ ] result = new byte [ data . Length ] ;
604
+
605
+ if ( groupSize == 1 )
572
606
{
573
- case 1 :
574
- for ( int i = 0 ; i < data . Length ; i ++ )
607
+ byte [ ] translate = precomputedSingleRotations [ amount ] ;
608
+
609
+ for ( int i = 0 ; i < data . Length ; i ++ )
610
+ {
611
+ result [ i ] = translate [ data [ i ] ] ;
612
+ }
613
+ return result ;
614
+ }
615
+
616
+ if ( data . Length % groupSize != 0 )
617
+ throw new Exception ( "data length must be a multiple of group size" ) ;
618
+
619
+ if ( amount % 8 == 0 )
620
+ {
621
+ int [ ] indices = new int [ groupSize ] ;
622
+ for ( int i = 0 ; i < groupSize ; i ++ )
623
+ {
624
+ indices [ i ] = ( i + amount_bytes ) % groupSize ;
625
+ }
626
+ for ( int i = 0 ; i < data . Length ; i += groupSize )
627
+ {
628
+ for ( int k = 0 ; k < groupSize ; k ++ )
575
629
{
576
- byte bits = data [ i ] ;
577
- // http://stackoverflow.com/a/812039
578
- r [ i ] = ( byte ) ( ( bits << amount ) | ( bits >> ( 8 - amount ) ) ) ;
630
+ result [ i + k ] = data [ i + indices [ k ] ] ;
579
631
}
580
- break ;
581
- default :
582
- throw new NotImplementedException ( string . Format ( "Unable to rotate a group of {0} bytes yet" , groupSize ) ) ;
632
+ }
633
+ return result ;
634
+ }
635
+
636
+ {
637
+ int amount1 = amount % 8 ;
638
+ int amount2 = 8 - amount1 ;
639
+ int [ ] indices1 = new int [ groupSize ] ;
640
+ int [ ] indices2 = new int [ groupSize ] ;
641
+ for ( int i = 0 ; i < groupSize ; i ++ )
642
+ {
643
+ indices1 [ i ] = ( i + amount_bytes ) % groupSize ;
644
+ indices2 [ i ] = ( i + 1 + amount_bytes ) % groupSize ;
645
+ }
646
+ for ( int i = 0 ; i < data . Length ; i += groupSize )
647
+ {
648
+ for ( int k = 0 ; k < groupSize ; k ++ )
649
+ {
650
+ result [ i + k ] = ( byte ) ( ( data [ i + indices1 [ k ] ] << amount1 ) | ( data [ i + indices2 [ k ] ] >> amount2 ) ) ;
651
+ }
652
+ }
653
+ return result ;
583
654
}
584
- return r ;
585
655
}
586
656
587
657
/// <summary>
0 commit comments