libclamunrar/unpack15.cpp
d39cb658
 #define STARTL1  2
 static unsigned int DecL1[]={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00,
                              0xee00,0xf000,0xf200,0xf200,0xffff};
 static unsigned int PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32};
 
 #define STARTL2  3
 static unsigned int DecL2[]={0xa000,0xc000,0xd000,0xe000,0xea00,0xee00,
                              0xf000,0xf200,0xf240,0xffff};
 static unsigned int PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36};
 
 #define STARTHF0  4
 static unsigned int DecHf0[]={0x8000,0xc000,0xe000,0xf200,0xf200,0xf200,
                               0xf200,0xf200,0xffff};
 static unsigned int PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33};
 
 
 #define STARTHF1  5
 static unsigned int DecHf1[]={0x2000,0xc000,0xe000,0xf000,0xf200,0xf200,
                               0xf7e0,0xffff};
 static unsigned int PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127};
 
 
 #define STARTHF2  5
 static unsigned int DecHf2[]={0x1000,0x2400,0x8000,0xc000,0xfa00,0xffff,
                               0xffff,0xffff};
 static unsigned int PosHf2[]={0,0,0,0,0,0,2,7,53,117,233,0,0};
 
 
 #define STARTHF3  6
 static unsigned int DecHf3[]={0x800,0x2400,0xee00,0xfe80,0xffff,0xffff,
                               0xffff};
 static unsigned int PosHf3[]={0,0,0,0,0,0,0,2,16,218,251,0,0};
 
 
 #define STARTHF4  8
 static unsigned int DecHf4[]={0xff00,0xffff,0xffff,0xffff,0xffff,0xffff};
 static unsigned int PosHf4[]={0,0,0,0,0,0,0,0,0,255,0,0,0};
 
 
 void Unpack::Unpack15(bool Solid)
 {
   UnpInitData(Solid);
   UnpInitData15(Solid);
   UnpReadBuf();
   if (!Solid)
   {
     InitHuff();
     UnpPtr=0;
   }
   else
     UnpPtr=WrPtr;
   --DestUnpSize;
   if (DestUnpSize>=0)
   {
     GetFlagsBuf();
     FlagsCnt=8;
   }
 
   while (DestUnpSize>=0)
   {
     UnpPtr&=MaxWinMask;
 
     if (Inp.InAddr>ReadTop-30 && !UnpReadBuf())
       break;
     if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr)
       UnpWriteBuf20();
     if (StMode)
     {
       HuffDecode();
       continue;
     }
 
     if (--FlagsCnt < 0)
     {
       GetFlagsBuf();
       FlagsCnt=7;
     }
 
     if (FlagBuf & 0x80)
     {
       FlagBuf<<=1;
       if (Nlzb > Nhfb)
         LongLZ();
       else
         HuffDecode();
     }
     else
     {
       FlagBuf<<=1;
       if (--FlagsCnt < 0)
       {
         GetFlagsBuf();
         FlagsCnt=7;
       }
       if (FlagBuf & 0x80)
       {
         FlagBuf<<=1;
         if (Nlzb > Nhfb)
           HuffDecode();
         else
           LongLZ();
       }
       else
       {
         FlagBuf<<=1;
         ShortLZ();
       }
     }
   }
   UnpWriteBuf20();
 }
 
 
 #define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos])
 #define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos])
 
 void Unpack::ShortLZ()
 {
   static unsigned int ShortLen1[]={1,3,4,4,5,6,7,8,8,4,4,5,6,6,4,0};
   static unsigned int ShortXor1[]={0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,
                                    0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0};
   static unsigned int ShortLen2[]={2,3,3,3,4,4,5,6,6,4,4,5,6,6,4,0};
   static unsigned int ShortXor2[]={0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,
                                    0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0};
 
 
   unsigned int Length,SaveLength;
   unsigned int LastDistance;
   unsigned int Distance;
   int DistancePlace;
   NumHuf=0;
 
   unsigned int BitField=Inp.fgetbits();
   if (LCount==2)
   {
     Inp.faddbits(1);
     if (BitField >= 0x8000)
     {
       CopyString15((unsigned int)LastDist,LastLength);
       return;
     }
     BitField <<= 1;
     LCount=0;
   }
 
   BitField>>=8;
 
 //  not thread safe, replaced by GetShortLen1 and GetShortLen2 macro
 //  ShortLen1[1]=ShortLen2[3]=Buf60+3;
 
   if (AvrLn1<37)
   {
     for (Length=0;;Length++)
       if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0)
         break;
     Inp.faddbits(GetShortLen1(Length));
   }
   else
   {
     for (Length=0;;Length++)
       if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0)
         break;
     Inp.faddbits(GetShortLen2(Length));
   }
 
   if (Length >= 9)
   {
     if (Length == 9)
     {
       LCount++;
       CopyString15((unsigned int)LastDist,LastLength);
       return;
     }
     if (Length == 14)
     {
       LCount=0;
       Length=DecodeNum(Inp.fgetbits(),STARTL2,DecL2,PosL2)+5;
       Distance=(Inp.fgetbits()>>1) | 0x8000;
       Inp.faddbits(15);
       LastLength=Length;
       LastDist=Distance;
       CopyString15(Distance,Length);
       return;
     }
 
     LCount=0;
     SaveLength=Length;
     Distance=OldDist[(OldDistPtr-(Length-9)) & 3];
     Length=DecodeNum(Inp.fgetbits(),STARTL1,DecL1,PosL1)+2;
     if (Length==0x101 && SaveLength==10)
     {
       Buf60 ^= 1;
       return;
     }
     if (Distance > 256)
       Length++;
     if (Distance >= MaxDist3)
       Length++;
 
     OldDist[OldDistPtr++]=Distance;
     OldDistPtr = OldDistPtr & 3;
     LastLength=Length;
     LastDist=Distance;
     CopyString15(Distance,Length);
     return;
   }
 
   LCount=0;
   AvrLn1 += Length;
   AvrLn1 -= AvrLn1 >> 4;
 
   DistancePlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff;
   Distance=ChSetA[DistancePlace];
   if (--DistancePlace != -1)
   {
     LastDistance=ChSetA[DistancePlace];
     ChSetA[DistancePlace+1]=LastDistance;
     ChSetA[DistancePlace]=Distance;
   }
   Length+=2;
   OldDist[OldDistPtr++] = ++Distance;
   OldDistPtr = OldDistPtr & 3;
   LastLength=Length;
   LastDist=Distance;
   CopyString15(Distance,Length);
 }
 
 
 void Unpack::LongLZ()
 {
   unsigned int Length;
   unsigned int Distance;
   unsigned int DistancePlace,NewDistancePlace;
   unsigned int OldAvr2,OldAvr3;
 
   NumHuf=0;
   Nlzb+=16;
   if (Nlzb > 0xff)
   {
     Nlzb=0x90;
     Nhfb >>= 1;
   }
   OldAvr2=AvrLn2;
 
   unsigned int BitField=Inp.fgetbits();
   if (AvrLn2 >= 122)
     Length=DecodeNum(BitField,STARTL2,DecL2,PosL2);
   else
     if (AvrLn2 >= 64)
       Length=DecodeNum(BitField,STARTL1,DecL1,PosL1);
     else
       if (BitField < 0x100)
       {
         Length=BitField;
         Inp.faddbits(16);
       }
       else
       {
         for (Length=0;((BitField<<Length)&0x8000)==0;Length++)
           ;
         Inp.faddbits(Length+1);
       }
 
   AvrLn2 += Length;
   AvrLn2 -= AvrLn2 >> 5;
 
   BitField=Inp.fgetbits();
   if (AvrPlcB > 0x28ff)
     DistancePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2);
   else
     if (AvrPlcB > 0x6ff)
       DistancePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1);
     else
       DistancePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0);
 
   AvrPlcB += DistancePlace;
   AvrPlcB -= AvrPlcB >> 8;
   while (1)
   {
     Distance = ChSetB[DistancePlace & 0xff];
     NewDistancePlace = NToPlB[Distance++ & 0xff]++;
     if (!(Distance & 0xff))
       CorrHuff(ChSetB,NToPlB);
     else
       break;
   }
 
   ChSetB[DistancePlace & 0xff]=ChSetB[NewDistancePlace];
   ChSetB[NewDistancePlace]=Distance;
 
   Distance=((Distance & 0xff00) | (Inp.fgetbits() >> 8)) >> 1;
   Inp.faddbits(7);
 
   OldAvr3=AvrLn3;
   if (Length!=1 && Length!=4)
     if (Length==0 && Distance <= MaxDist3)
     {
       AvrLn3++;
       AvrLn3 -= AvrLn3 >> 8;
     }
     else
       if (AvrLn3 > 0)
         AvrLn3--;
   Length+=3;
   if (Distance >= MaxDist3)
     Length++;
   if (Distance <= 256)
     Length+=8;
   if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40)
     MaxDist3=0x7f00;
   else
     MaxDist3=0x2001;
   OldDist[OldDistPtr++]=Distance;
   OldDistPtr = OldDistPtr & 3;
   LastLength=Length;
   LastDist=Distance;
   CopyString15(Distance,Length);
 }
 
 
 void Unpack::HuffDecode()
 {
   unsigned int CurByte,NewBytePlace;
   unsigned int Length;
   unsigned int Distance;
   int BytePlace;
 
   unsigned int BitField=Inp.fgetbits();
 
   if (AvrPlc > 0x75ff)
     BytePlace=DecodeNum(BitField,STARTHF4,DecHf4,PosHf4);
   else
     if (AvrPlc > 0x5dff)
       BytePlace=DecodeNum(BitField,STARTHF3,DecHf3,PosHf3);
     else
       if (AvrPlc > 0x35ff)
         BytePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2);
       else
         if (AvrPlc > 0x0dff)
           BytePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1);
         else
           BytePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0);
   BytePlace&=0xff;
   if (StMode)
   {
     if (BytePlace==0 && BitField > 0xfff)
       BytePlace=0x100;
     if (--BytePlace==-1)
     {
       BitField=Inp.fgetbits();
       Inp.faddbits(1);
       if (BitField & 0x8000)
       {
         NumHuf=StMode=0;
         return;
       }
       else
       {
         Length = (BitField & 0x4000) ? 4 : 3;
         Inp.faddbits(1);
         Distance=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2);
         Distance = (Distance << 5) | (Inp.fgetbits() >> 11);
         Inp.faddbits(5);
         CopyString15(Distance,Length);
         return;
       }
     }
   }
   else
     if (NumHuf++ >= 16 && FlagsCnt==0)
       StMode=1;
   AvrPlc += BytePlace;
   AvrPlc -= AvrPlc >> 8;
   Nhfb+=16;
   if (Nhfb > 0xff)
   {
     Nhfb=0x90;
     Nlzb >>= 1;
   }
 
   Window[UnpPtr++]=(byte)(ChSet[BytePlace]>>8);
   --DestUnpSize;
 
   while (1)
   {
     CurByte=ChSet[BytePlace];
     NewBytePlace=NToPl[CurByte++ & 0xff]++;
     if ((CurByte & 0xff) > 0xa1)
       CorrHuff(ChSet,NToPl);
     else
       break;
   }
 
   ChSet[BytePlace]=ChSet[NewBytePlace];
   ChSet[NewBytePlace]=CurByte;
 }
 
 
 void Unpack::GetFlagsBuf()
 {
   unsigned int Flags,NewFlagsPlace;
   unsigned int FlagsPlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2);
 
   // Our Huffman table stores 257 items and needs all them in other parts
   // of code such as when StMode is on, so the first item is control item.
   // While normally we do not use the last item to code the flags byte here,
   // we need to check for value 256 when unpacking in case we unpack
   // a corrupt archive.
   if (FlagsPlace>=sizeof(ChSetC)/sizeof(ChSetC[0]))
     return;
 
   while (1)
   {
     Flags=ChSetC[FlagsPlace];
     FlagBuf=Flags>>8;
     NewFlagsPlace=NToPlC[Flags++ & 0xff]++;
     if ((Flags & 0xff) != 0)
       break;
     CorrHuff(ChSetC,NToPlC);
   }
 
   ChSetC[FlagsPlace]=ChSetC[NewFlagsPlace];
   ChSetC[NewFlagsPlace]=Flags;
 }
 
 
 void Unpack::UnpInitData15(int Solid)
 {
   if (!Solid)
   {
     AvrPlcB=AvrLn1=AvrLn2=AvrLn3=NumHuf=Buf60=0;
     AvrPlc=0x3500;
     MaxDist3=0x2001;
     Nhfb=Nlzb=0x80;
   }
   FlagsCnt=0;
   FlagBuf=0;
   StMode=0;
   LCount=0;
   ReadTop=0;
 }
 
 
 void Unpack::InitHuff()
 {
   for (unsigned int I=0;I<256;I++)
   {
     ChSet[I]=ChSetB[I]=I<<8;
     ChSetA[I]=I;
     ChSetC[I]=((~I+1) & 0xff)<<8;
   }
   memset(NToPl,0,sizeof(NToPl));
   memset(NToPlB,0,sizeof(NToPlB));
   memset(NToPlC,0,sizeof(NToPlC));
   CorrHuff(ChSetB,NToPlB);
 }
 
 
 void Unpack::CorrHuff(ushort *CharSet,byte *NumToPlace)
 {
   int I,J;
   for (I=7;I>=0;I--)
     for (J=0;J<32;J++,CharSet++)
       *CharSet=(*CharSet & ~0xff) | I;
   memset(NumToPlace,0,sizeof(NToPl));
   for (I=6;I>=0;I--)
     NumToPlace[I]=(7-I)*32;
 }
 
 
 void Unpack::CopyString15(uint Distance,uint Length)
 {
   DestUnpSize-=Length;
   while (Length--)
   {
     Window[UnpPtr]=Window[(UnpPtr-Distance) & MaxWinMask];
     UnpPtr=(UnpPtr+1) & MaxWinMask;
   }
 }
 
 
 uint Unpack::DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab)
 {
   int I;
   for (Num&=0xfff0,I=0;DecTab[I]<=Num;I++)
     StartPos++;
   Inp.faddbits(StartPos);
   return(((Num-(I ? DecTab[I-1]:0))>>(16-StartPos))+PosTab[StartPos]);
 }