Artifact Content

Not logged in

Artifact 449e48789d18c169961f2a90f78fa9438ec47b41



#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;
}