libclamunrar/unpackinline.cpp
d39cb658
 _forceinline void Unpack::InsertOldDist(uint Distance)
 {
   OldDist[3]=OldDist[2];
   OldDist[2]=OldDist[1];
   OldDist[1]=OldDist[0];
   OldDist[0]=Distance;
 }
 
 #ifdef _MSC_VER
 #define FAST_MEMCPY
 #endif
 
 _forceinline void Unpack::CopyString(uint Length,uint Distance)
 {
   size_t SrcPtr=UnpPtr-Distance;
   if (SrcPtr<MaxWinSize-MAX_INC_LZ_MATCH && UnpPtr<MaxWinSize-MAX_INC_LZ_MATCH)
   {
     // If we are not close to end of window, we do not need to waste time
     // to "& MaxWinMask" pointer protection.
 
     byte *Src=Window+SrcPtr;
     byte *Dest=Window+UnpPtr;
     UnpPtr+=Length;
 
 #ifdef FAST_MEMCPY
     if (Distance<Length) // Overlapping strings
 #endif
       while (Length>=8)
       {
         Dest[0]=Src[0];
         Dest[1]=Src[1];
         Dest[2]=Src[2];
         Dest[3]=Src[3];
         Dest[4]=Src[4];
         Dest[5]=Src[5];
         Dest[6]=Src[6];
         Dest[7]=Src[7];
 
         Src+=8;
         Dest+=8;
         Length-=8;
       }
 #ifdef FAST_MEMCPY
     else
       while (Length>=8)
       {
         // In theory we still could overlap here.
         // Supposing Distance == MaxWinSize - 1 we have memcpy(Src, Src + 1, 8).
         // But for real RAR archives Distance <= MaxWinSize - MAX_INC_LZ_MATCH
         // always, so overlap here is impossible.
 
         // This memcpy expanded inline by MSVC. We could also use uint64
         // assignment, which seems to provide about the same speed.
         memcpy(Dest,Src,8); 
 
         Src+=8;
         Dest+=8;
         Length-=8;
       }
 #endif
 
     // Unroll the loop for 0 - 7 bytes left. Note that we use nested "if"s.
     if (Length>0) { Dest[0]=Src[0];
     if (Length>1) { Dest[1]=Src[1];
     if (Length>2) { Dest[2]=Src[2];
     if (Length>3) { Dest[3]=Src[3];
     if (Length>4) { Dest[4]=Src[4];
     if (Length>5) { Dest[5]=Src[5];
     if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s.
   }
   else
     while (Length-- > 0) // Slow copying with all possible precautions.
     {
       Window[UnpPtr]=Window[SrcPtr++ & MaxWinMask];
       // We need to have masked UnpPtr after quit from loop, so it must not
       // be replaced with 'Window[UnpPtr++ & MaxWinMask]'
       UnpPtr=(UnpPtr+1) & MaxWinMask;
     }
 }
 
 
 _forceinline uint Unpack::DecodeNumber(BitInput &Inp,DecodeTable *Dec)
 {
   // Left aligned 15 bit length raw bit field.
   uint BitField=Inp.getbits() & 0xfffe;
 
   if (BitField<Dec->DecodeLen[Dec->QuickBits])
   {
     uint Code=BitField>>(16-Dec->QuickBits);
     Inp.addbits(Dec->QuickLen[Code]);
     return Dec->QuickNum[Code];
   }
 
   // Detect the real bit length for current code.
   uint Bits=15;
   for (uint I=Dec->QuickBits+1;I<15;I++)
     if (BitField<Dec->DecodeLen[I])
     {
       Bits=I;
       break;
     }
 
   Inp.addbits(Bits);
   
   // Calculate the distance from the start code for current bit length.
   uint Dist=BitField-Dec->DecodeLen[Bits-1];
 
   // Start codes are left aligned, but we need the normal right aligned
   // number. So we shift the distance to the right.
   Dist>>=(16-Bits);
 
   // Now we can calculate the position in the code list. It is the sum
   // of first position for current bit length and right aligned distance
   // between our bit field and start code for current bit length.
   uint Pos=Dec->DecodePos[Bits]+Dist;
 
   // Out of bounds safety check required for damaged archives.
   if (Pos>=Dec->MaxNum)
     Pos=0;
 
   // Convert the position in the code list to position in alphabet
   // and return it.
   return Dec->DecodeNum[Pos];
 }
 
 
 _forceinline uint Unpack::SlotToLength(BitInput &Inp,uint Slot)
 {
   uint LBits,Length=2;
   if (Slot<8)
   {
     LBits=0;
     Length+=Slot;
   }
   else
   {
     LBits=Slot/4-1;
     Length+=(4 | (Slot & 3)) << LBits;
   }
 
   if (LBits>0)
   {
     Length+=Inp.getbits()>>(16-LBits);
     Inp.addbits(LBits);
   }
   return Length;
 }