reman3/Rayman_X/cpa/tempgrp/CMP/PC/CMP_LZSS.c

251 lines
8.5 KiB
C

#include "CMP_Pub.h"
#if defined(D_CMP_LZSS)
#include <stdio.h>
#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 */