/********************************************************************** Encoding and Decoding by Sliding Dictionary. Copyright(C) 1992 by Yoshihiko Mino. **********************************************************************/ #include "lharc.h" #include "slidehuf.h" #include "intrface.h" int unpackable, prev_char; unsigned long origsize, compsize, count; unsigned short dicbit, maxmatch, loc; unsigned char *text; static struct encode_option encode_define[ 2 ] = { #ifdef __STDC__ {(void(*)())output_dyn, /* lh1 */ (void(*)())encode_start_fix, (void(*)())encode_end_dyn}, {(void(*)())output_st1, /* lh4, 5 */ (void(*)())encode_start_st1, (void(*)())encode_end_st1} #else {(int(*)())output_dyn, /* lh1 */ (int(*)())encode_start_fix, (int(*)())encode_end_dyn}, {(int(*)())output_st1, /* lh4, 5 */ (int(*)())encode_start_st1, (int(*)())encode_end_st1} #endif }; static struct decode_option decode_define[ 7 ] = { {decode_c_dyn, decode_p_st0, decode_start_fix}, /* lh1 */ {decode_c_dyn, decode_p_dyn, decode_start_dyn}, /* lh2 */ {decode_c_st0, decode_p_st0, decode_start_st0}, /* lh3 */ {decode_c_st1, decode_p_st1, decode_start_st1}, /* lh4 */ {decode_c_st1, decode_p_st1, decode_start_st1}, /* lh5 */ {decode_c_lzs, decode_p_lzs, decode_start_lzs}, /* lzs */ {decode_c_lz5, decode_p_lz5, decode_start_lz5} /* lz5 */ }; static struct encode_option encode_set; static struct decode_option decode_set; static unsigned char *abuf, *textend, *t0, *t1, *t2; static unsigned short *rlen, *list, *ltop, *freq; static unsigned short dicsiz, dicmask, abufpos, textsiz, pos, mp, ml; static unsigned short top_char, last_char, runlength; static unsigned short remainder, matchlen, matchpos; #define ABUF_SIZE 4096 /* Size of Ahead-read Buffer */ #define HASH_SIZE 0x1100 /* Size of Hash table */ #define HASH1(c1) ( (c1) | 0x1000 ) /* Hashing Func. 1 */ #define HASH2(c1,c2) ( (c1) | ( ((c2) & 0x0f) << 8) ) /* Hashing Func. 2 */ int encode_alloc( method ) int method; { if ( method == 1 ) { encode_set = encode_define[ 0 ]; /* lh1 */ maxmatch = 60; dicbit = 12; } else { encode_set = encode_define[ 1 ]; /* lh4,5 */ maxmatch = MAXMATCH; dicbit = 13; } while ( 1 ) { dicsiz = 1 << dicbit; dicmask = dicsiz - 1; abuf = (unsigned char *)malloc( ABUF_SIZE + maxmatch ); text = (unsigned char *)malloc( dicsiz ); rlen = (unsigned short *)malloc( dicsiz * sizeof(*rlen) ); list = (unsigned short *)malloc( dicsiz * sizeof(*list) ); ltop = (unsigned short *)malloc( HASH_SIZE * sizeof(*ltop) ); freq = (unsigned short *)malloc( HASH_SIZE * sizeof(*freq) ); if ( abuf != NULL && text != NULL && rlen != NULL && list != NULL && ltop != NULL && freq != NULL && ( method <= 1 || alloc_buf() != NULL ) ) break; if ( freq ) free( freq ); if ( ltop ) free( ltop ); if ( list ) free( list ); if ( rlen ) free( rlen ); if ( text ) free( text ); if ( abuf ) free( abuf ); if ( --dicbit < 12 ) exit( 207 ); /* error(MEMOVRERR, NULL); */ } textend = &text[ dicmask ] + 1; if ( method == 5 ) method = dicbit - 8; return method; } static void init_list( void ) { abufpos = textsiz = pos = 0; last_char = top_char = (unsigned short)abuf[ abufpos ]; memset( freq, 0, HASH_SIZE * sizeof(*freq) ); freq[ HASH1( top_char ) ]--; runlength = -1; } static void update_list( void ) { unsigned char c; unsigned short q, h; int n; c = text[ pos ] = abuf[ abufpos ]; if ( ( q = (unsigned short)c ) == last_char ) { freq[ h = HASH1( last_char ) ]++; if ( ++runlength == dicsiz ) --runlength; rlen[ pos ] = runlength; } else { freq[ h = HASH2( last_char, q ) ]++; rlen[ pos ] = runlength = 0; last_char = q; } list[ pos ] = ltop[ h ]; ltop[ h ] = pos; if ( ++pos == dicsiz ) pos = 0; if ( textsiz < dicsiz ) { textsiz++; } else { if ( ( q = (unsigned short)text[ pos ] ) == top_char ) { freq[ HASH1( top_char ) ]--; } else { freq[ HASH2( top_char, q ) ]--; top_char = q; } } remainder--; if ( ++abufpos == ABUF_SIZE ) { bcopy( &abuf[ ABUF_SIZE ], abuf, (int)maxmatch ); n = fread_crc( &abuf[ maxmatch ], ABUF_SIZE, infile ); origsize += n; remainder += n; abufpos = 0; } } static void get_mlen( void ) { unsigned char *t3, *t4; t3 = &text[ ( mp + 1 ) & dicmask ]; t4 = t2; for ( ; t3 != t0 ; ml++ ) { if ( *(t3++) != *(t4++) || ml == maxmatch ) return; if ( t3 == textend ) t3 = text; } for ( t3 = t1 ; ; ml++ ) { if ( *(t3++) != *(t4++) || ml == maxmatch ) return; } } static void get_match( void ) { unsigned char c1, c2, c3; unsigned short hv, fr, r1, r2; t0 = &text[ pos ]; c1 = *( t1 = &abuf[ abufpos ] ); c2 = *( t2 = t1 + 1 ); if ( c1 == c2 ) { for ( r1 = 1; r1 < maxmatch - 1 && *(++t2) == c1 ; r1++ ); if ( last_char == (unsigned short)c1 ) { matchpos = pos - 1; } else { matchlen = 2; hv = HASH1( (unsigned short)c1 ); if ( ( fr = freq[ hv ] ) == 0 ) return; mp = ltop[ hv ]; while( 1 ) { if ( ( r2 = rlen[ mp ] ) > fr ) r2 = fr; if ( r2 >= r1 ) { matchpos = mp - r1; break; } if ( r2 >= matchlen ) { matchpos = mp - r2; matchlen = r2 + 1; } if ( ( fr -= r2 ) == 0 ) return; mp = list[ ( mp - r2 + 1 ) & dicmask ]; } } if ( ( matchlen = r1 + 1 ) == maxmatch ) return; c3 = *( t2++ ); hv = HASH2( (unsigned short)c2, (unsigned short)c3 ); if ( ( fr = freq[ hv ] ) == 0 ) return; mp = ltop[ hv ]; while( 1 ) { if ( text[ mp ] == c3 ) { r2 = rlen[ ( mp - 1 ) & dicmask ]; if ( r2 >= r1 ) { ml = r1 + 2; get_mlen(); if ( ml > matchlen ) { if ( ( ( mp - pos ) & dicmask ) >= r1 ) { matchpos = mp - r1 - 1; if ( ( matchlen = ml ) == maxmatch ) return; } } } } if ( --fr == 0 ) return; mp = list[ mp ]; } } else { t2++; matchlen = 2; hv = HASH2( (unsigned short)c1, (unsigned short)c2 ); if ( ( fr = freq[ hv ] ) == 0 ) return; mp = ltop[ hv ]; while( 1 ) { if ( text[ mp ] == c2 ) { ml = 2; get_mlen(); if ( ml > matchlen ) { matchpos = mp - 1; if ( ( matchlen = ml ) == maxmatch ) return; } } if ( --fr == 0 ) return; mp = list[ mp ]; } } } void encode( interface ) struct interfacing *interface; { infile = interface -> infile; outfile = interface -> outfile; compsize = count = 0L; crc = 0; unpackable = 0; encode_set.encode_start(); origsize = remainder = fread_crc(abuf, ABUF_SIZE+(int)maxmatch, infile); init_list() ; #ifdef DBG printf( "%c", abuf[ abufpos ] ); #endif encode_set.output( abuf[ abufpos ], 0 ); update_list(); count++; while ( remainder > 0 && ! unpackable ) { get_match(); if ( matchlen > remainder ) matchlen = remainder; if ( matchlen < THRESHOLD ) { #ifdef DBG printf( "%c", abuf[ abufpos ] ); #endif encode_set.output( abuf[ abufpos ], 0 ); update_list(); count++; } else { #ifdef DBG printf( "[%d,%d]", matchlen, (pos - matchpos - 1) & dicmask ); #endif encode_set.output( matchlen + UCHAR_MAX + 1 - THRESHOLD , ( pos - matchpos - 1 ) & dicmask ); while ( matchlen-- ) { #ifdef DBG printf( "%c", abuf[ abufpos ] ); #endif update_list(); count++; } } } encode_set.encode_end(); interface -> packed = compsize; interface -> original = origsize; } void decode( interface ) struct interfacing *interface; { int i, j, k, c, offset; infile = interface -> infile; outfile = interface -> outfile; dicbit = interface -> dicbit; origsize = interface -> original; compsize = interface -> packed; decode_set = decode_define[ interface -> method - 1 ]; crc = 0; prev_char = -1; dicsiz = 1 << dicbit; dicmask = dicsiz - 1; text = (unsigned char *)malloc( dicsiz ); if (text == NULL) exit( errno ); /* error(MEMOVRERR, NULL); */ memset( text, ' ', dicsiz ); decode_set.decode_start(); offset = ( interface -> method == 6 ) ? 0x100 - 2 : 0x100 - 3; count = 0L ; loc = 0; while ( count < origsize ) { c = decode_set.decode_c(); if ( c <= UCHAR_MAX ) { text[ loc ] = c; if ( ++loc == dicsiz ) { fwrite_crc( text, dicsiz, outfile ); loc = 0; } count++; } else { j = c - offset; i = ( loc - decode_set.decode_p() - 1 ) & dicmask; count += j; for ( k = 0; k < j; k++ ) { c = text[ (i + k) & dicmask ]; text[ loc ] = c; if ( ++loc == dicsiz ) { fwrite_crc( text, dicsiz, outfile ); loc = 0; } } } } if ( loc != 0 ) { fwrite_crc( text, loc, outfile ); } free(text); }