#include "CMP_Pub.h" #if defined(D_CMP_LZSS) #include #include "CMP_CPA.h" #include "ErmCmp.h" #include "CMP_File.h" /**************************************************************************/ #define C_CMP_LZSS_INDEX_BIT_COUNT 12 #define C_CMP_LZSS_LENGTH_BIT_COUNT 4 #define C_CMP_LZSS_WINDOW_SIZE ( 1 << C_CMP_LZSS_INDEX_BIT_COUNT ) #define C_CMP_LZSS_RAW_LOOK_AHEAD_SIZE ( 1 << C_CMP_LZSS_LENGTH_BIT_COUNT ) #define C_CMP_LZSS_BREAK_EVEN ( ( 1 + C_CMP_LZSS_INDEX_BIT_COUNT + C_CMP_LZSS_LENGTH_BIT_COUNT ) / 9 ) #define C_CMP_LZSS_LOOK_AHEAD_SIZE ( C_CMP_LZSS_RAW_LOOK_AHEAD_SIZE + C_CMP_LZSS_BREAK_EVEN ) #define C_CMP_LZSS_TREE_ROOT C_CMP_LZSS_WINDOW_SIZE #define C_CMP_LZSS_END_OF_STREAM 0 #define C_CMP_LZSS_UNUSED 0 /**************************************************************************/ #define M_CMP_LZSS_MOD_WINDOW( a ) ( ( a ) & ( C_CMP_LZSS_WINDOW_SIZE - 1 ) ) /**************************************************************************/ unsigned char CMP_LZSS_g_a_ucWindow[C_CMP_LZSS_WINDOW_SIZE]; struct { int parent; int smaller_child; int larger_child; } CMP_LZSS_g_a_stTree[C_CMP_LZSS_WINDOW_SIZE + 1 ]; char *CMP_LZSS_CompressionName = "LZSS method"; /**************************************************************************/ void CMP_LZSS_InitTree( int r ); void CMP_LZSS_ContractNode( int old_node, int new_node ); void CMP_LZSS_ReplaceNode( int old_node, int new_node ); int CMP_LZSS_FindNextNode( int node ); void CMP_LZSS_DeleteString( int p ); int CMP_LZSS_AddString( int new_node, int *match_position ); /**************************************************************************/ void CMP_LZSS_fn_vInitTree( int r ) { CMP_LZSS_g_a_stTree[ C_CMP_LZSS_TREE_ROOT ].larger_child = r; CMP_LZSS_g_a_stTree[ r ].parent = C_CMP_LZSS_TREE_ROOT; CMP_LZSS_g_a_stTree[ r ].larger_child = C_CMP_LZSS_UNUSED; CMP_LZSS_g_a_stTree[ r ].smaller_child = C_CMP_LZSS_UNUSED; } /**************************************************************************/ void CMP_LZSS_fn_vContractNode( int old_node , int new_node ) { CMP_LZSS_g_a_stTree[ new_node ].parent = CMP_LZSS_g_a_stTree[ old_node ].parent; if ( CMP_LZSS_g_a_stTree[ CMP_LZSS_g_a_stTree[ old_node ].parent ].larger_child == old_node ) CMP_LZSS_g_a_stTree[ CMP_LZSS_g_a_stTree[ old_node ].parent ].larger_child = new_node; else CMP_LZSS_g_a_stTree[ CMP_LZSS_g_a_stTree[ old_node ].parent ].smaller_child = new_node; CMP_LZSS_g_a_stTree[ old_node ].parent = C_CMP_LZSS_UNUSED; } /**************************************************************************/ void CMP_LZSS_fn_vReplaceNode( int old_node , int new_node ) { int parent; parent = CMP_LZSS_g_a_stTree[ old_node ].parent; if ( CMP_LZSS_g_a_stTree[ parent ].smaller_child == old_node ) CMP_LZSS_g_a_stTree[ parent ].smaller_child = new_node; else CMP_LZSS_g_a_stTree[ parent ].larger_child = new_node; CMP_LZSS_g_a_stTree[ new_node ] = CMP_LZSS_g_a_stTree[ old_node ]; CMP_LZSS_g_a_stTree[ CMP_LZSS_g_a_stTree[ new_node ].smaller_child ].parent = new_node; CMP_LZSS_g_a_stTree[ CMP_LZSS_g_a_stTree[ new_node ].larger_child ].parent = new_node; CMP_LZSS_g_a_stTree[ old_node ].parent = C_CMP_LZSS_UNUSED; } /**************************************************************************/ int CMP_LZSS_fn_vFindNextNode( int node ) { int next; next = CMP_LZSS_g_a_stTree[ node ].smaller_child; while ( CMP_LZSS_g_a_stTree[ next ].larger_child != C_CMP_LZSS_UNUSED ) next = CMP_LZSS_g_a_stTree[ next ].larger_child; return( next ); } /**************************************************************************/ void CMP_LZSS_fn_vDeleteString( int p ) { int replacement; if ( CMP_LZSS_g_a_stTree[ p ].parent == C_CMP_LZSS_UNUSED ) return; if ( CMP_LZSS_g_a_stTree[ p ].larger_child == C_CMP_LZSS_UNUSED ) CMP_LZSS_fn_vContractNode( p, CMP_LZSS_g_a_stTree[ p ].smaller_child ); else if ( CMP_LZSS_g_a_stTree[ p ].smaller_child == C_CMP_LZSS_UNUSED ) CMP_LZSS_fn_vContractNode( p, CMP_LZSS_g_a_stTree[ p ].larger_child ); else { replacement = CMP_LZSS_fn_vFindNextNode( p ); CMP_LZSS_fn_vDeleteString( replacement ); CMP_LZSS_fn_vReplaceNode( p, replacement ); } } /**************************************************************************/ int CMP_LZSS_fn_vAddString( int new_node , int *match_position ) { int i; int test_node; int delta = 0; int match_length; int *child; if ( new_node == C_CMP_LZSS_END_OF_STREAM ) return( 0 ); test_node = CMP_LZSS_g_a_stTree[ C_CMP_LZSS_TREE_ROOT ].larger_child; match_length = 0; for ( ; ; ) { for ( i = 0 ; i < C_CMP_LZSS_LOOK_AHEAD_SIZE ; i++ ) { delta = CMP_LZSS_g_a_ucWindow[ M_CMP_LZSS_MOD_WINDOW( new_node + i ) ] - CMP_LZSS_g_a_ucWindow[ M_CMP_LZSS_MOD_WINDOW( test_node + i ) ]; if ( delta != 0 ) break; } if ( i >= match_length ) { match_length = i; *match_position = test_node; if ( match_length >= C_CMP_LZSS_LOOK_AHEAD_SIZE ) { CMP_LZSS_fn_vReplaceNode( test_node, new_node ); return( match_length ); } } if ( delta >= 0 ) child = &CMP_LZSS_g_a_stTree[ test_node ].larger_child; else child = &CMP_LZSS_g_a_stTree[ test_node ].smaller_child; if ( *child == C_CMP_LZSS_UNUSED ) { *child = new_node; CMP_LZSS_g_a_stTree[ new_node ].parent = test_node; CMP_LZSS_g_a_stTree[ new_node ].larger_child = C_CMP_LZSS_UNUSED; CMP_LZSS_g_a_stTree[ new_node ].smaller_child = C_CMP_LZSS_UNUSED; return( match_length ); } test_node = *child; } } /**************************************************************************/ void CMP_LZSS_fn_vCompressFile( FILE *input , tdstBitFile *output ) { int i; int c; int look_ahead_bytes; int current_position; int replace_count; int match_length; int match_position; current_position = 1; for ( i = 0 ; i < C_CMP_LZSS_LOOK_AHEAD_SIZE ; i++ ) { if ( ( c = getc( input ) ) == EOF ) break; CMP_LZSS_g_a_ucWindow[ current_position + i ] = (unsigned char) c; } look_ahead_bytes = i; CMP_LZSS_fn_vInitTree( current_position ); match_length = 0; match_position = 0; while ( look_ahead_bytes > 0 ) { if ( match_length > look_ahead_bytes ) match_length = look_ahead_bytes; if ( match_length <= C_CMP_LZSS_BREAK_EVEN ) { replace_count = 1; CMP_fn_vOutputBit( output, 1 ); CMP_fn_vOutputBits( output, (unsigned long) CMP_LZSS_g_a_ucWindow[ current_position ], 8 ); } else { CMP_fn_vOutputBit( output, 0 ); CMP_fn_vOutputBits( output, (unsigned long) match_position, C_CMP_LZSS_INDEX_BIT_COUNT ); CMP_fn_vOutputBits( output, (unsigned long) ( match_length - ( C_CMP_LZSS_BREAK_EVEN + 1 ) ), C_CMP_LZSS_LENGTH_BIT_COUNT ); replace_count = match_length; } for ( i = 0 ; i < replace_count ; i++ ) { CMP_LZSS_fn_vDeleteString( M_CMP_LZSS_MOD_WINDOW( current_position + C_CMP_LZSS_LOOK_AHEAD_SIZE ) ); if ( ( c = getc( input ) ) == EOF ) look_ahead_bytes--; else CMP_LZSS_g_a_ucWindow[ M_CMP_LZSS_MOD_WINDOW( current_position + C_CMP_LZSS_LOOK_AHEAD_SIZE ) ] = (unsigned char) c; current_position = M_CMP_LZSS_MOD_WINDOW( current_position + 1 ); if ( look_ahead_bytes ) match_length = CMP_LZSS_fn_vAddString( current_position, &match_position ); } } CMP_fn_vOutputBit( output, 0 ); CMP_fn_vOutputBits( output, (unsigned long) C_CMP_LZSS_END_OF_STREAM, C_CMP_LZSS_INDEX_BIT_COUNT ); } /**************************************************************************/ void CMP_LZSS_fn_vExpandFile( tdstBitFile *input , FILE *output ) { int i; int current_position; int c; int match_length; int match_position; current_position = 1; for ( ; ; ) { if ( CMP_fn_lInputBit( input ) ) { c = (int) CMP_fn_ulInputBits( input, 8 ); putc( c, output ); CMP_LZSS_g_a_ucWindow[ current_position ] = (unsigned char) c; current_position = M_CMP_LZSS_MOD_WINDOW( current_position + 1 ); } else { match_position = (int) CMP_fn_ulInputBits( input, C_CMP_LZSS_INDEX_BIT_COUNT ); if ( match_position == C_CMP_LZSS_END_OF_STREAM ) break; match_length = (int) CMP_fn_ulInputBits( input, C_CMP_LZSS_LENGTH_BIT_COUNT ); match_length += C_CMP_LZSS_BREAK_EVEN; for ( i = 0 ; i <= match_length ; i++ ) { c = CMP_LZSS_g_a_ucWindow[ M_CMP_LZSS_MOD_WINDOW( match_position + i ) ]; putc( c, output ); CMP_LZSS_g_a_ucWindow[ current_position ] = (unsigned char) c; current_position = M_CMP_LZSS_MOD_WINDOW( current_position + 1 ); } } } } /**************************************************************************/ #endif /* D_CMP_LZSS */