#include "stdafx.h"
#include "LzhDecoder2.h"
void CLzhDecoder2::Unstore()
{
#define UNS_BUFSIZE (32768)
int how_much;
char buf[UNS_BUFSIZE];
if( cmpsize==-1 )
{
while( (how_much=fread(buf,1,UNS_BUFSIZE,in))!=0 )
{
if( how_much==-1 )
break;
fwrite(buf,1,how_much,out);
}
return;
}
while( cmpsize>0 )
{
how_much = cmpsize>UNS_BUFSIZE?UNS_BUFSIZE:cmpsize;
if( 0>=(how_much=fread( buf,1,how_much,in )) )
break;
fwrite( buf,1,how_much,out );
cmpsize -= how_much;
}
}
void CLzhDecoder2::Decode( lzh_method mhd,FILE* infile,DWORD insize,
FILE* outfile,DWORD outsize )
{
in = infile;
cmpsize = insize;
out = outfile;
orisize = outsize;
DWORD dicsiz,dicbit;
// メソッドによっていろいろ切り替え
switch( mhd )
{
case LH0:Unstore(); return;
default: return;
case LH4: np=14,pbit=4,dicbit=12,dicsiz=(1<<dicbit);break;
case LH5: np=14,pbit=4,dicbit=13,dicsiz=(1<<dicbit);break;
case LH6: np=16,pbit=5,dicbit=15,dicsiz=(1<<dicbit);break;
case LH7: np=17,pbit=5,dicbit=16,dicsiz=(1<<dicbit);break;
}
BYTE* text = new BYTE[dicsiz];
memset( text,' ',dicsiz );
init_getbits();
blocksize = 0;
// デコード
DWORD count=0;
loc=0;
int offset=(0x0100-3);
while( count<orisize )
{
int c = Decode_C(mhd);
if( c<=255 )
{
text[loc++] = c;
if( loc==dicsiz )
{
fwrite(text,1,dicsiz,out);
loc = 0;
}
count++;
}
else
{
int j = c - offset;
count += j;
int i = Decode_P(mhd);
if( (i=loc-i-1)<0 )
i += dicsiz;
for( int k=0; k<j; k++ )
{
text[loc++] = text[i];
if( loc>=dicsiz )
{
fwrite( text,1,dicsiz,out );
loc = 0;
}
if( ++i>=(int)dicsiz )
i = 0;
}
}
}
if( loc!=0 )
fwrite( text,1,loc,out );
delete [] text;
}
/**************** LH4-7,ARJ,ZOO ************************/
void CLzhDecoder2::make_table(WORD nchar,BYTE* bitlen,
WORD tablebits,WORD* table)
{
WORD count[17],weight[17],start[17],total,*p;
unsigned int i;
int j,k,l,m,n,avail;
avail = nchar;
for( i=1; i<=16; i++ )
{
count[i] = 0;
weight[i] = 1 << (16 - i);
}
for( i=0; i<nchar; i++ )
count[bitlen[i]]++;
total = 0;
for( i=1; i<=16; i++ )
{
start[i] = total;
total += weight[i] * count[i];
}
if( (total & 0xffff) != 0 )
return;//error("Bad table (5)\n");
m = 16 - tablebits;
for( i=1; i<=tablebits; i++ )
{
start[i] >>= m;
weight[i] >>= m;
}
j = start[tablebits + 1] >> m;
k = 1 << tablebits;
if( j!=0 )
for( i=j; i<(unsigned)k; i++ )
table[i] = 0;
for( j=0; j<nchar; j++ )
{
k = bitlen[j];
if( k==0 )
continue;
l = start[k] + weight[k];
if( k<=tablebits )
{
for( i=start[k]; i<(unsigned)l; i++ )
table[i] = j;
}
else
{
p = &table[(i = start[k]) >> m];
i <<= tablebits;
n = k - tablebits;
while (--n >= 0)
{
if (*p == 0)
{
right[avail] = left[avail] = 0;
*p = avail++;
}
if (i & 0x8000)
p = &right[*p];
else
p = &left[*p];
i <<= 1;
}
*p = j;
}
start[k] = l;
}
}
void CLzhDecoder2::read_pt_len(short nn,short nbit,short i_special)
{
short i, c, n=getbits((BYTE)nbit);
if( n==0 )
{
c = getbits((BYTE)nbit);
for( i=0; i<nn; i++ ) pt_len[i] = 0;
for( i=0; i<256; i++ ) pt_table[i] = c;
}
else
{
short i = 0;
while( i<n )
{
c = bitbuf >> (16-3);
if( c==7 )
{
WORD mask = 1<<(16-4);
while( mask&bitbuf )
{
mask >>= 1;
c++;
}
}
fillbuf( (c<7) ? 3 : c-3 );
pt_len[i++] = (BYTE)c;
if( i==i_special )
{
c = getbits(2);
while( --c>=0 )
pt_len[i++] = 0;
}
}
while( i<nn )
pt_len[i++] = 0;
make_table(nn,pt_len,8,pt_table);
}
}
void CLzhDecoder2::read_c_len()
{
short i, c, n=getbits(CBIT);
if( n==0 )
{
c = getbits(CBIT);
for( i=0; i<NC; i++ ) c_len[i] = 0;
for( i=0; i<4096; i++ ) c_table[i] = c;
}
else
{
short i = 0;
while( i<n )
{
c = pt_table[ bitbuf>>(16-8) ];
if( c>=NT )
{
WORD mask = 1<<(16-9);
do
{
if( bitbuf&mask )c = right[c];
else c = left[c];
mask >>= 1;
}while( c>=NT );
}
fillbuf(pt_len[c]);
if( c<=2 )
{
if( c==0 ) c = 1;
else if( c==1 ) c = getbits(4) + 3;
else c = getbits(CBIT) + 20;
while( --c>=0 )
c_len[i++] = 0;
}
else
c_len[i++] = c-2;
}
while( i<NC )
c_len[i++]=0;
make_table(NC,c_len,12,c_table);
}
}
WORD CLzhDecoder2::decode_c_st1()
{
WORD j,mask;
if( blocksize==0 )
{
blocksize = getbits(16);
read_pt_len(NT,TBIT,3);
read_c_len();
read_pt_len(np,pbit,-1);
}
blocksize--;
j = c_table[ bitbuf>>4 ];
if( j<NC )
fillbuf(c_len[j]);
else
{
fillbuf(12);
mask = 1 << (16-1);
do
{
if( bitbuf&mask ) j = right[j];
else j = left[j];
mask >>= 1;
}while( j>=NC );
fillbuf( c_len[j]-12 );
}
return j;
}
WORD CLzhDecoder2::decode_p_st1()
{
WORD j, mask;
j = pt_table[ bitbuf>>(16-8) ];
if( j<np )
fillbuf(pt_len[j]);
else
{
fillbuf(8);
mask = 1 << (16-1);
do
{
if( bitbuf&mask ) j = right[j];
else j = left[j];
mask >>= 1;
}while( j>=np );
fillbuf(pt_len[j] - 8);
}
if( j!=0 )
j = (1<<(j-1)) + getbits(j-1);
return j;
}
/******************** bit単位のread&write ************************/
void CLzhDecoder2::init_getbits()
{
bitbuf = 0;
subbitbuf = 0;
bitcount = 0;
fillbuf(16);
}
void CLzhDecoder2::fillbuf(BYTE n)
{
while( n>bitcount )
{
n -= bitcount;
bitbuf = (bitbuf<<bitcount) + (subbitbuf>>(8-bitcount));
if( cmpsize!=0 )
{
cmpsize--;
subbitbuf = (BYTE)getc(in);
}
else
subbitbuf = 0;
bitcount = 8;
}
bitcount -= n;
bitbuf = (bitbuf<<n) + (subbitbuf>>(8-n));
subbitbuf <<= n;
}
WORD CLzhDecoder2::getbits(BYTE n)
{
WORD x = bitbuf>>(16-n);
fillbuf(n);
return x;
}