bsnes/snesreader/unrar/unpack20.cpp

395 lines
7.8 KiB
C++
Executable File

// #included by unpack.cpp
#ifdef RAR_COMMON_HPP
#include "rar.hpp"
// Presumably these optimizations give similar speedup as those for CopyString in unpack.cpp
void Unpack::CopyString20(unsigned int Length,unsigned int Distance)
{
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
LastLength=Length;
DestUnpSize-=Length;
unsigned UnpPtr = this->UnpPtr; // cache in register
byte* const Window = this->Window; // cache in register
unsigned int DestPtr=UnpPtr-Distance;
if (UnpPtr<MAXWINSIZE-300 && DestPtr<MAXWINSIZE-300)
{
this->UnpPtr += Length;
if ( Distance < Length ) // can't use memcpy when source and dest overlap
{
Window[UnpPtr++]=Window[DestPtr++];
Window[UnpPtr++]=Window[DestPtr++];
while (Length>2)
{
Length--;
Window[UnpPtr++]=Window[DestPtr++];
}
}
else
{
memcpy( &Window[UnpPtr], &Window[DestPtr], Length );
}
}
else
{
while (Length--)
{
Window[UnpPtr]=Window[DestPtr++ & MAXWINMASK];
UnpPtr=(UnpPtr+1) & MAXWINMASK;
}
this->UnpPtr = UnpPtr;
}
}
void Unpack::Unpack20(bool Solid)
{
const
static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
const
static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
const
static int DDecode[]={0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
const
static unsigned char DBits[]= {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
const
static unsigned char SDDecode[]={0,4,8,16,32,64,128,192};
const
static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6};
unsigned int Bits;
if (Suspended)
UnpPtr=WrPtr;
else
{
UnpInitData(Solid);
if (!UnpReadBuf())
return;
if (!Solid)
if (!ReadTables20())
return;
--DestUnpSize;
}
while (is64plus(DestUnpSize))
{
UnpPtr&=MAXWINMASK;
if (InAddr>ReadTop-30)
if (!UnpReadBuf())
break;
if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr)
{
OldUnpWriteBuf();
if (Suspended)
return;
}
if (UnpAudioBlock)
{
int AudioNumber=DecodeNumber((struct Decode *)&MD[UnpCurChannel]);
if (AudioNumber==256)
{
if (!ReadTables20())
break;
continue;
}
Window[UnpPtr++]=DecodeAudio(AudioNumber);
if (++UnpCurChannel==UnpChannels)
UnpCurChannel=0;
--DestUnpSize;
continue;
}
int Number=DecodeNumber((struct Decode *)&LD);
if (Number<256)
{
Window[UnpPtr++]=(byte)Number;
--DestUnpSize;
continue;
}
if (Number>269)
{
int Length=LDecode[Number-=270]+3;
if ((Bits=LBits[Number])>0)
{
Length+=getbits()>>(16-Bits);
addbits(Bits);
}
int DistNumber=DecodeNumber((struct Decode *)&DD);
unsigned int Distance=DDecode[DistNumber]+1;
if ((Bits=DBits[DistNumber])>0)
{
Distance+=getbits()>>(16-Bits);
addbits(Bits);
}
if (Distance>=0x2000)
{
Length++;
if (Distance>=0x40000L)
Length++;
}
CopyString20(Length,Distance);
continue;
}
if (Number==269)
{
if (!ReadTables20())
break;
continue;
}
if (Number==256)
{
CopyString20(LastLength,LastDist);
continue;
}
if (Number<261)
{
unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3];
int LengthNumber=DecodeNumber((struct Decode *)&RD);
int Length=LDecode[LengthNumber]+2;
if ((Bits=LBits[LengthNumber])>0)
{
Length+=getbits()>>(16-Bits);
addbits(Bits);
}
if (Distance>=0x101)
{
Length++;
if (Distance>=0x2000)
{
Length++;
if (Distance>=0x40000)
Length++;
}
}
CopyString20(Length,Distance);
continue;
}
if (Number<270)
{
unsigned int Distance=SDDecode[Number-=261]+1;
if ((Bits=SDBits[Number])>0)
{
Distance+=getbits()>>(16-Bits);
addbits(Bits);
}
CopyString20(2,Distance);
continue;
}
}
ReadLastTables();
OldUnpWriteBuf();
}
bool Unpack::ReadTables20()
{
byte BitLength[BC20];
unsigned char Table[MC20*4];
int TableSize,N,I;
if (InAddr>ReadTop-25)
if (!UnpReadBuf())
return(false);
unsigned int BitField=getbits();
UnpAudioBlock=(BitField & 0x8000);
if (!(BitField & 0x4000))
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
addbits(2);
if (UnpAudioBlock)
{
UnpChannels=((BitField>>12) & 3)+1;
if (UnpCurChannel>=UnpChannels)
UnpCurChannel=0;
addbits(2);
TableSize=MC20*UnpChannels;
}
else
TableSize=NC20+DC20+RC20;
for (I=0;I<BC20;I++)
{
BitLength[I]=(byte)(getbits() >> 12);
addbits(4);
}
MakeDecodeTables(BitLength,(struct Decode *)&BD,BC20);
I=0;
while (I<TableSize)
{
if (InAddr>ReadTop-5)
if (!UnpReadBuf())
return(false);
int Number=DecodeNumber((struct Decode *)&BD);
if (Number<16)
{
Table[I]=(Number+UnpOldTable20[I]) & 0xf;
I++;
}
else
if (Number==16)
{
N=(getbits() >> 14)+3;
addbits(2);
while (N-- > 0 && I<TableSize)
{
Table[I]=Table[I-1];
I++;
}
}
else
{
if (Number==17)
{
N=(getbits() >> 13)+3;
addbits(3);
}
else
{
N=(getbits() >> 9)+11;
addbits(7);
}
while (N-- > 0 && I<TableSize)
Table[I++]=0;
}
}
if (InAddr>ReadTop)
return(true);
if (UnpAudioBlock)
for (I=0;I<UnpChannels;I++)
MakeDecodeTables(&Table[I*MC20],(struct Decode *)&MD[I],MC20);
else
{
MakeDecodeTables(&Table[0],(struct Decode *)&LD,NC20);
MakeDecodeTables(&Table[NC20],(struct Decode *)&DD,DC20);
MakeDecodeTables(&Table[NC20+DC20],(struct Decode *)&RD,RC20);
}
memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20));
return(true);
}
void Unpack::ReadLastTables()
{
if (ReadTop>=InAddr+5)
if (UnpAudioBlock)
{
if (DecodeNumber((struct Decode *)&MD[UnpCurChannel])==256)
ReadTables20();
}
else
if (DecodeNumber((struct Decode *)&LD)==269)
ReadTables20();
}
void Unpack::UnpInitData20(int Solid)
{
if (!Solid)
{
UnpAudioBlock=UnpChannelDelta=UnpCurChannel=0;
UnpChannels=1;
memset(AudV,0,sizeof(AudV));
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
memset(MD,0,sizeof(MD));
}
}
byte Unpack::DecodeAudio(int Delta)
{
struct AudioVariables *V=&AudV[UnpCurChannel];
V->ByteCount++;
V->D4=V->D3;
V->D3=V->D2;
V->D2=V->LastDelta-V->D1;
V->D1=V->LastDelta;
int PCh=8*V->LastChar+V->K1*V->D1+V->K2*V->D2+V->K3*V->D3+V->K4*V->D4+V->K5*UnpChannelDelta;
PCh=(PCh>>3) & 0xFF;
unsigned int Ch=PCh-Delta;
int D=((signed char)Delta)<<3;
V->Dif[0]+=abs(D);
V->Dif[1]+=abs(D-V->D1);
V->Dif[2]+=abs(D+V->D1);
V->Dif[3]+=abs(D-V->D2);
V->Dif[4]+=abs(D+V->D2);
V->Dif[5]+=abs(D-V->D3);
V->Dif[6]+=abs(D+V->D3);
V->Dif[7]+=abs(D-V->D4);
V->Dif[8]+=abs(D+V->D4);
V->Dif[9]+=abs(D-UnpChannelDelta);
V->Dif[10]+=abs(D+UnpChannelDelta);
UnpChannelDelta=V->LastDelta=(signed char)(Ch-V->LastChar);
V->LastChar=Ch;
if ((V->ByteCount & 0x1F)==0)
{
unsigned int MinDif=V->Dif[0],NumMinDif=0;
V->Dif[0]=0;
for (int I=1;I<sizeof(V->Dif)/sizeof(V->Dif[0]);I++)
{
if (V->Dif[I]<MinDif)
{
MinDif=V->Dif[I];
NumMinDif=I;
}
V->Dif[I]=0;
}
switch(NumMinDif)
{
case 1:
if (V->K1>=-16)
V->K1--;
break;
case 2:
if (V->K1<16)
V->K1++;
break;
case 3:
if (V->K2>=-16)
V->K2--;
break;
case 4:
if (V->K2<16)
V->K2++;
break;
case 5:
if (V->K3>=-16)
V->K3--;
break;
case 6:
if (V->K3<16)
V->K3++;
break;
case 7:
if (V->K4>=-16)
V->K4--;
break;
case 8:
if (V->K4<16)
V->K4++;
break;
case 9:
if (V->K5>=-16)
V->K5--;
break;
case 10:
if (V->K5<16)
V->K5++;
break;
}
}
return((byte)Ch);
}
#endif