@@ -53,6 +53,11 @@ public KaitaiStream(byte[] data) : base(new MemoryStream(data))
5353 /// </summary>
5454 static readonly bool IsLittleEndian = BitConverter . IsLittleEndian ;
5555
56+ static KaitaiStream ( )
57+ {
58+ computeSingleRotations ( ) ;
59+ }
60+
5661 #endregion
5762
5863 #region Stream positioning
@@ -555,33 +560,98 @@ public byte[] ProcessXor(byte[] data, byte[] key)
555560 return result ;
556561 }
557562
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+
558585 /// <summary>
559586 /// Perform circular left rotation shift for a given data by a given amount of bits.
560587 /// Pass a negative amount to rotate right.
588+ /// WARNING: May return same byte array if amount is zero (modulo-wise).
561589 /// </summary>
562590 /// <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>
565593 public byte [ ] ProcessRotateLeft ( byte [ ] data , int amount , int groupSize )
566594 {
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 ;
569601
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 )
572606 {
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 ++ )
575629 {
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 ] ] ;
579631 }
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 ;
583654 }
584- return r ;
585655 }
586656
587657 /// <summary>
0 commit comments