home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 10
/
aminetcdnumber101996.iso
/
Aminet
/
util
/
arc
/
Unrar101.lha
/
sources
/
amiga-gcc
/
UNPACK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-22
|
16KB
|
753 lines
/****** ***** ******
** ** ** ** ** ** unRAR utility version 1.01
****** ******* ****** ~~~~~~~~~~~~~~~~~~~~~~~~~~~
** ** ** ** ** ** FREE portable version
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~
Unpacking algorithm procedures
YOU DO NOT NEED TO CHANGE THERE ANYTHING.
*/
void MakeTbl(); /* Makes Huffman table */
void AddBit(); /* Shift buffer pointer to NBits */
void CopyString(); /* string copy */
void ShortLZ(); /* unpacks short, near and special LZ codes */
void LongLZ(); /* unpacks long and far LZ codes */
void HuffDecode(); /* Huffman decoding */
int UnpWriteBuf(); /* writes output buffer */
int UnpReadBuf(); /* reads output buffer */
void GetFlagsBuf(); /* gets flag byte */
void UnpInitData(); /* reset initial data */
void InitHuff(); /* initializing Huffman tables */
void CorrHuff(); /* Huffman table correction in case of overflow */
void CreateEncTbl(); /* create decoding tables */
void CreateOneTbl(); /* subfunction of previous */
int unpack(); /* unpacking procedure itself */
#define SUSPEND 1
#define SIZE_PBUF 0x2000
#define FIRST 1
#define NEXT 2
#define UNP_MEMORY 0x10010L+sizeof(struct UnpData)+ \
sizeof(struct DecodeTables)+SIZE_PBUF
UWORD hcdsh1[]={ 0x0001,0xa003,0xd004,0xe004,0xf005,0xf806,0xfc07,0xfe08,
0xff08,0xc004,0x8004,0x9005,0x9806,0x9c06,0 };
UWORD hcdsh2[]={ 0x0002,0x4003,0x6003,0xa003,0xd004,0xe004,0xf005,0xf806,
0xfc06,0xc004,0x8004,0x9005,0x9806,0x9c06,0 };
UWORD hcdsh3[]={ 0x0001,0xa004,0xd004,0xe004,0xf005,0xf806,0xfc07,0xfe08,
0xff08,0xc004,0x8004,0x9005,0x9806,0x9c06,0xb004,0 };
UWORD hcdsh4[]={ 0x0002,0x4003,0x6003,0xa004,0xd004,0xe004,0xf005,0xf806,
0xfc06,0xc004,0x8004,0x9005,0x9806,0x9c06,0xb004,0 };
UWORD hcdln0[]={ 0x8001,0x4002,0x2003,0x1004,0x0805,0x0406,0x0207,0x0108,
0x0008,0 };
UWORD hcdln1[258],hcdln2[258];
UWORD hcode0[258],hcode1[258],hcode2[258],hcode3[258],hcode4[258];
struct MakeHuffTabs
{
UWORD *Table;
UBYTE HuffCodeCount[12];
} MakeTab[]={
{hcdln1,{0 ,2 ,1 ,2 ,2 ,4 ,5 ,4 ,4 ,8 ,0 ,224}},
{hcdln2,{0 ,0 ,5 ,2 ,2 ,4 ,5 ,4 ,4 ,8 ,2 ,220}},
{hcode0,{0 ,0 ,0 ,8 ,8 ,8 ,9 ,0 ,0 ,0 ,0 ,224}},
{hcode1,{0 ,0 ,0 ,0 ,4 ,40 ,16 ,16 ,4 ,0 ,47 ,130}},
{hcode2,{0 ,0 ,0 ,0 ,2 ,5 ,46 ,64 ,116 ,24 ,0 ,0 }},
{hcode3,{0 ,0 ,0 ,0 ,0 ,2 ,14 ,202 ,33 ,6 ,0 ,0 }},
{hcode4,{0 ,0 ,0 ,0 ,0 ,0 ,0 ,255 ,2 ,0 ,0 ,0 }}};
SDWORD DestUnpSize=0;
UBYTE FlagBuf;
UWORD InAdr,OutAdr;
unsigned int Suspend=0;
unsigned int NumBit;
unsigned int LCount;
int FlagsCnt;
struct UnpData
{
UWORD ChSet[256];
UBYTE Place[256];
UBYTE NToPl[256];
UBYTE ChSetA[256];
UBYTE PlaceA[256];
UWORD ChSetB[256];
UBYTE PlaceB[256];
UBYTE NToPlB[256];
UWORD ChSetC[256];
UBYTE PlaceC[256];
UBYTE NToPlC[256];
UWORD AvrPlc;
UWORD AvrPlcB;
UWORD AvrLn1;
UWORD AvrLn2;
UWORD AvrLn3;
UBYTE NumHuf;
UBYTE StMode;
UWORD Nhfb;
UWORD Nlzb;
UWORD MaxDist3;
UBYTE Buf60;
UWORD WrAddr;
UWORD SomeRd;
UWORD UnpAllBuf;
UWORD LastDist;
UWORD LastLen;
UWORD OldDist[4];
UWORD OldDistNum;
} *D;
struct DecodeTables
{
UBYTE ECDSH1[256];
UBYTE ECDSH2[256];
UBYTE ECDSH3[256];
UBYTE ECDSH4[256];
UBYTE ECDLN0[256];
UBYTE ECDLN1[4096];
UBYTE ECDLN2[4096];
UBYTE ECODE0[4096];
UBYTE ECODE1[4096];
UBYTE ECODE2[1024];
UBYTE ECODE3[1024];
UBYTE ECODE4[1024];
UBYTE NCDSH1[16];
UBYTE NCDSH2[16];
UBYTE NCDSH3[16];
UBYTE NCDSH4[16];
UBYTE NCDLN0[256];
UBYTE NCDLN1[256];
UBYTE NCDLN2[256];
UBYTE NCODE0[257];
UBYTE NCODE1[257];
UBYTE NCODE2[257];
UBYTE NCODE3[257];
UBYTE NCODE4[257];
} *T;
UBYTE *PackBuf;
HPBYTE UnpBuf;
int (* UnpReadFn)();
int (* UnpWriteFn)();
#define GetField() ((UWORD)((((UDWORD)PackBuf[InAdr] << 16) | \
((UWORD)PackBuf[InAdr+1] << 8) | PackBuf[InAdr+2]) \
>> (8-NumBit)))
void AddBit(NBits)
unsigned int NBits;
{
InAdr += (NumBit+NBits) >> 3;
NumBit = (NumBit+NBits) & 7;
}
void CopyString(Distance,Length)
UWORD Distance;
unsigned int Length;
{
DestUnpSize-=Length;
while (Length--)
{
UnpBuf[OutAdr]=UnpBuf[(UWORD)(OutAdr-Distance)];
OutAdr++;
}
}
int unpack(UnpMem,UnpRead,UnpWrite,Solid)
HPBYTE UnpMem;
int (* UnpRead)();
int (* UnpWrite)();
int Solid;
{
UnpReadFn=UnpRead;
UnpWriteFn=UnpWrite;
UnpBuf=(UBYTE *)UnpMem;
PackBuf=(UBYTE *)(UnpMem+0x10000L+sizeof(struct UnpData)+sizeof(struct DecodeTables));
D=(struct UnpData *)(UnpMem+0x10000L);
if (Suspend)
OutAdr=D->WrAddr;
else
{
UnpInitData(Solid);
if (!Solid)
{
InitHuff();
memset(UnpBuf,0,0x8000);
memset(UnpBuf+0x8000,0,0x8000);
OutAdr=0;
}
else
OutAdr=D->WrAddr;
if (--DestUnpSize < 0)
return(0);
if (UnpReadBuf(FIRST)==-1)
return(-1);
GetFlagsBuf();
FlagsCnt=8;
}
while (DestUnpSize>=0)
{
if (InAdr >= SIZE_PBUF-12)
if (UnpReadBuf(NEXT)==-1)
return(-1);
if ((UWORD)(D->WrAddr - OutAdr) < 0x110 && D->WrAddr!=OutAdr)
{
if (UnpWriteBuf()==-1)
return(-1);
if (Suspend)
return(0);
}
if (D->StMode)
{
HuffDecode();
continue;
}
if (--FlagsCnt < 0)
{
GetFlagsBuf();
FlagsCnt=7;
}
if (FlagBuf >= 0x80)
{
FlagBuf<<=1;
if (D->Nlzb > D->Nhfb)
LongLZ();
else
HuffDecode();
}
else
{
FlagBuf<<=1;
if (--FlagsCnt < 0)
{
GetFlagsBuf();
FlagsCnt=7;
}
if (FlagBuf >= 0x80)
{
FlagBuf<<=1;
if (D->Nlzb > D->Nhfb)
HuffDecode();
else
LongLZ();
}
else
{
FlagBuf<<=1;
ShortLZ();
}
}
}
if (UnpWriteBuf()==-1)
return(-1);
return(0);
}
void ShortLZ()
{
UWORD LengthCode,SaveLength;
UBYTE LastDistance;
UWORD Distance,DistancePlace,Length;
D->NumHuf=0;
LengthCode=GetField();
if (LCount==2)
{
AddBit(1);
if (LengthCode >= 0x8000)
{
CopyString(D->LastDist,D->LastLen);
return;
}
LengthCode <<= 1;
LCount=0;
}
LengthCode >>= 8;
if (D->Buf60==0)
if (D->AvrLn1<37)
{
Length=T->ECDSH1[LengthCode];
AddBit(T->NCDSH1[Length]);
}
else
{
Length=T->ECDSH2[LengthCode];
AddBit(T->NCDSH2[Length]);
}
else
if (D->AvrLn1<37)
{
Length=T->ECDSH3[LengthCode];
AddBit(T->NCDSH3[Length]);
}
else
{
Length=T->ECDSH4[LengthCode];
AddBit(T->NCDSH4[Length]);
}
if (Length >= 9)
{
if (Length == 9)
{
LCount++;
CopyString(D->LastDist,D->LastLen);
return;
}
if (Length == 14)
{
LCount=0;
Length=T->ECDLN2[GetField() >> 4];
AddBit(T->NCDLN2[Length]);
Length+=5;
Distance=(GetField() >> 1) | 0x8000;
AddBit(15);
D->LastLen=Length;
D->LastDist=Distance;
CopyString(Distance,Length);
return;
}
LCount=0;
SaveLength=Length;
Distance=D->OldDist[(D->OldDistNum-(Length-9)) & 3];
Length=T->ECDLN1[GetField() >> 4];
AddBit(T->NCDLN1[Length]);
Length+=2;
if (Length==0x101 && SaveLength==10)
{
D->Buf60 ^= 1;
return;
}
if (Distance > 256)
Length++;
if (Distance > D->MaxDist3)
Length++;
D->OldDist[D->OldDistNum++]=Distance;
D->OldDistNum = D->OldDistNum & 3;
D->LastLen=Length;
D->LastDist=Distance;
CopyString(Distance,Length);
return;
}
LCount=0;
D->AvrLn1 += Length;
D->AvrLn1 -= D->AvrLn1 >> 4;
DistancePlace=T->ECODE2[GetField() >> 6];
AddBit(T->NCODE2[DistancePlace]);
Distance=D->ChSetA[DistancePlace];
if (--DistancePlace != 0xFFFF)
{
D->PlaceA[Distance]--;
LastDistance=D->ChSetA[DistancePlace];
D->PlaceA[LastDistance]++;
D->ChSetA[DistancePlace+1]=LastDistance;
D->ChSetA[DistancePlace]=(UBYTE)Distance;
}
Length+=2;
D->OldDist[D->OldDistNum++] = ++Distance;
D->OldDistNum = D->OldDistNum & 3;
D->LastLen=Length;
D->LastDist=Distance;
CopyString(Distance,Length);
return;
}
void LongLZ()
{
UWORD LengthCode,Length;
UWORD Distance,DistancePlace,NewDistancePlace;
UWORD oldav2,oldav3;
D->NumHuf=0;
D->Nlzb+=16;
if (D->Nlzb > 0xff)
{
D->Nlzb=0x90;
D->Nhfb >>= 1;
}
oldav2=D->AvrLn2;
if (D->AvrLn2 >= 122)
{
Length=T->ECDLN2[GetField() >> 4];
AddBit(T->NCDLN2[Length]);
}
else
if (D->AvrLn2 >= 64)
{
Length=T->ECDLN1[GetField() >> 4];
AddBit(T->NCDLN1[Length]);
}
else
{
LengthCode=GetField();
if (LengthCode < 0x100)
{
Length=LengthCode;
AddBit(16);
}
else
{
Length=T->ECDLN0[LengthCode >> 8];
AddBit(T->NCDLN0[Length]);
}
}
D->AvrLn2 += Length;
D->AvrLn2 -= D->AvrLn2 >> 5;
if (D->AvrPlcB > 0x28ff)
{
DistancePlace=T->ECODE2[GetField() >> 6];
AddBit(T->NCODE2[DistancePlace]);
}
else
if (D->AvrPlcB > 0x6ff)
{
DistancePlace=T->ECODE1[GetField() >> 4];
AddBit(T->NCODE1[DistancePlace]);
}
else
{
DistancePlace=T->ECODE0[GetField() >> 4];
AddBit(T->NCODE0[DistancePlace]);
}
D->AvrPlcB += DistancePlace;
D->AvrPlcB -= D->AvrPlcB >> 8;
while (1)
{
Distance = D->ChSetB[DistancePlace];
NewDistancePlace = D->NToPlB[Distance++ & 0xff]++;
if (!(Distance & 0xff))
{
Distance-=0x100;
CorrHuff(D->ChSetB,D->NToPlB);
}
else
break;
}
D->ChSetB[DistancePlace]=D->ChSetB[NewDistancePlace];
D->ChSetB[NewDistancePlace]=Distance;
Distance=((UWORD)((Distance & ~0xff) | (GetField() >> 8))) >> 1;
AddBit(7);
oldav3=D->AvrLn3;
if (Length!=1 && Length!=4)
if (Length==0 && Distance <= D->MaxDist3)
{
D->AvrLn3++;
D->AvrLn3 -= D->AvrLn3 >> 8;
}
else
if (D->AvrLn3 > 0)
D->AvrLn3--;
Length+=3;
if (Distance >= D->MaxDist3)
Length++;
if (Distance <= 256)
Length+=8;
if (oldav3 > 0xb0 || D->AvrPlc >= 0x2a00 && oldav2 < 0x40)
D->MaxDist3=0x7f00;
else
D->MaxDist3=0x2001;
D->OldDist[D->OldDistNum++]=Distance;
D->OldDistNum = D->OldDistNum & 3;
D->LastLen=Length;
D->LastDist=Distance;
CopyString(Distance,Length);
}
void HuffDecode()
{
UWORD CurByte,BytePlace,NewBytePlace;
UWORD Length,Distance,Code;
Code=GetField();
if (D->AvrPlc > 0x75ff)
{
BytePlace=T->ECODE4[Code>>6];
if (D->StMode && BytePlace==0 && Code > 0xfff)
BytePlace=0x100;
AddBit(T->NCODE4[BytePlace]);
}
else
if (D->AvrPlc > 0x5dff)
{
BytePlace=T->ECODE3[Code>>6];
if (D->StMode && BytePlace==0 && Code > 0xfff)
BytePlace=0x100;
AddBit(T->NCODE3[BytePlace]);
}
else
if (D->AvrPlc > 0x35ff)
{
BytePlace=T->ECODE2[Code>>6];
if (D->StMode && BytePlace==0 && Code > 0xfff)
BytePlace=0x100;
AddBit(T->NCODE2[BytePlace]);
}
else
if (D->AvrPlc > 0x0dff)
{
BytePlace=T->ECODE1[Code>>4];
if (D->StMode && BytePlace==0 && Code > 0xfff)
BytePlace=0x100;
AddBit(T->NCODE1[BytePlace]);
}
else
{
BytePlace=T->ECODE0[Code>>4];
if (D->StMode && BytePlace==0 && Code > 0xfff)
BytePlace=0x100;
AddBit(T->NCODE0[BytePlace]);
}
if (D->StMode)
{
if (--BytePlace==0xFFFF)
{
Code=GetField();
AddBit(1);
if (Code >= 0x8000)
{
D->NumHuf=D->StMode=0;
return;
}
else
{
Length = (Code & 0x4000) ? 4 : 3;
Distance= T->ECODE2[(Code >> 4) & 0x3ff];
AddBit(T->NCODE2[Distance]+1);
Distance = (Distance << 5) | (GetField() >> 11);
AddBit(5);
CopyString(Distance,Length);
return;
}
}
}
else
if (D->NumHuf++ >= 16 && FlagsCnt==0)
D->StMode=1;
D->AvrPlc += BytePlace;
D->AvrPlc -= D->AvrPlc >> 8;
D->Nhfb+=16;
if (D->Nhfb > 0xff)
{
D->Nhfb=0x90;
D->Nlzb >>= 1;
}
UnpBuf[OutAdr++]=(UBYTE)(D->ChSet[BytePlace]>>8);
DestUnpSize--;
while (1)
{
CurByte=D->ChSet[BytePlace];
NewBytePlace=D->NToPl[CurByte++ & 0xff]++;
if ((CurByte & 0xff) > 0xa1)
CorrHuff(D->ChSet,D->NToPl);
else
break;
}
D->ChSet[BytePlace]=D->ChSet[NewBytePlace];
D->ChSet[NewBytePlace]=CurByte;
}
int UnpWriteBuf()
{
if (OutAdr<D->WrAddr)
{
if (UnpWriteFn((UBYTE *)(UnpBuf+D->WrAddr),(UWORD)-D->WrAddr)==-1 ||
UnpWriteFn((UBYTE *)UnpBuf,(UWORD)OutAdr)==-1)
return(-1);
}
else
if (UnpWriteFn((UBYTE *)(UnpBuf+D->WrAddr),(UWORD)(OutAdr-D->WrAddr))==-1)
return(-1);
D->WrAddr=OutAdr;
return(0);
}
int UnpReadBuf(NumBuf)
int NumBuf;
{
int ReadCode;
if (NumBuf==FIRST)
ReadCode=UnpReadFn(PackBuf,SIZE_PBUF);
else
{
memcpy(PackBuf,PackBuf+InAdr,(UWORD)(SIZE_PBUF-InAdr));
ReadCode=UnpReadFn(PackBuf+SIZE_PBUF-InAdr,(UWORD)InAdr);
}
InAdr=0;
if (ReadCode==-1)
return(-1);
return(0);
}
void GetFlagsBuf()
{
UWORD Flags,FlagsPlace,NewFlagsPlace;
FlagsPlace=T->ECODE2[GetField() >> 6];
AddBit(T->NCODE2[FlagsPlace]);
while (1)
{
Flags=D->ChSetC[FlagsPlace];
FlagBuf=(UBYTE)(Flags >> 8);
NewFlagsPlace=D->NToPlC[Flags++ & 0xff]++;
if ((Flags & 0xff) == 0)
{
Flags-=0x100;
CorrHuff(D->ChSetC,D->NToPlC);
}
else
break;
}
D->ChSetC[FlagsPlace]=D->ChSetC[NewFlagsPlace];
D->ChSetC[NewFlagsPlace]=Flags;
}
void UnpInitData(Solid)
int Solid;
{
if (!Solid)
{
memset(D,0,sizeof(struct UnpData));
D->AvrPlc=0x3500;
D->MaxDist3=0x2001;
D->Nhfb=D->Nlzb=0x80;
}
FlagsCnt=0;
FlagBuf=0;
InAdr=0;
NumBit=0;
D->StMode=0;
LCount=0;
}
void InitHuff()
{
UWORD I;
for (I=0;I<256;I++)
{
D->Place[I]=D->PlaceA[I]=D->PlaceB[I]=(UBYTE)I;
D->PlaceC[I]=(UBYTE)(~I+1);
D->ChSet[I]=D->ChSetB[I]=I<<8;
D->ChSetA[I]=(UBYTE)I;
D->ChSetC[I]=(~I+1)<<8;
}
memset(D->NToPl,0,sizeof(D->NToPl));
memset(D->NToPlB,0,sizeof(D->NToPlB));
memset(D->NToPlC,0,sizeof(D->NToPlC));
CorrHuff(D->ChSetB,D->NToPlB);
}
void CorrHuff(CharSet,NumToPlace)
UWORD *CharSet;
UBYTE *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(D->NToPl));
for (I=6;I>=0;I--)
NumToPlace[I]=(7-I)*32;
}
void CreateEncTbl(UnpMem)
HPBYTE UnpMem;
{
T=(struct DecodeTables *)(UnpMem+0x10000L+sizeof(struct UnpData));
CreateOneTbl(hcdsh1,T->ECDSH1,T->NCDSH1,8);
CreateOneTbl(hcdsh2,T->ECDSH2,T->NCDSH2,8);
CreateOneTbl(hcdsh3,T->ECDSH3,T->NCDSH3,8);
CreateOneTbl(hcdsh4,T->ECDSH4,T->NCDSH4,8);
CreateOneTbl(hcdln0,T->ECDLN0,T->NCDLN0,8);
CreateOneTbl(hcdln1,T->ECDLN1,T->NCDLN1,4);
CreateOneTbl(hcdln2,T->ECDLN2,T->NCDLN2,4);
CreateOneTbl(hcode0,T->ECODE0,T->NCODE0,4);
CreateOneTbl(hcode1,T->ECODE1,T->NCODE1,4);
CreateOneTbl(hcode2,T->ECODE2,T->NCODE2,6);
CreateOneTbl(hcode3,T->ECODE3,T->NCODE3,6);
CreateOneTbl(hcode4,T->ECODE4,T->NCODE4,6);
}
void CreateOneTbl(hcd,ecd,ncd,ShiftCount)
UWORD *hcd;
UBYTE *ecd;
UBYTE *ncd;
UBYTE ShiftCount;
{
UWORD I,MaxCode,Code;
for (I=0; hcd[I]; I++)
{
ncd[I]=(UBYTE)(hcd[I] & 0xf);
Code=hcd[I] >> ShiftCount;
MaxCode=1 << (16-ShiftCount-(UBYTE)(hcd[I] & 0xf));
while (MaxCode--)
ecd[Code++]=(UBYTE)I;
}
}
void MakeTbl()
{
UWORD I,J,K,Code;
UWORD *OutTab;
for (I=0;I<sizeof(MakeTab)/sizeof(MakeTab[0]);I++)
{
OutTab=MakeTab[I].Table;
for (Code=J=0;J<12;J++)
for (Code<<=1,K=0;K<MakeTab[I].HuffCodeCount[J];K++)
*(OutTab++)=(Code++ << (4+11-J)) | (J + 1);
*OutTab=0;
}
}