Home > Zib library에서 사용하는 알고리즘 > Lempel-Ziv 알고리즘 > 예제 소스 보기

 

 

Lempel-Ziv 예제 프로그램

 

 

 

 

////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include         <stdio.h>

#include         <string.h>

 

#define                     HASH_SIZE                256

#define                     QUEUE_SIZE             256

 

#define                     QUEUE_POS(x)         ((x + QUEUE_SIZE) % QUEUE_SIZE )

#define                     QUEUE_EMPTY                    ( front == rear )

#define                     QUEUE_FULL            ( ( ( rear + 1 ) % QUEUE_SIZE ) == front )

 

#define                     MIN_COMPRESS        3

#define                     ESCAPE_CHAR                    (unsigned char)0xCC

 

typedef struct _tagHashList

{

           int pos;

           struct _tagHashList *next;

}HashList;

 

HashList hashList[HASH_SIZE];

char queue[QUEUE_SIZE];

int front;

int rear;

int pattern;

int current;

 

void InitQueue();

int CheckQueue( int _length );

int LempelZivCompress( char *_data, int _dataSize,

                                 char *_compressData, int *_compressSize );

int LempelZivDeCompress( char *_compressData, int _compressSize,

                                 char *_data, int *_dataSize );

int PushQueue( char _data );

int PopQueue();

int compress( char *_data, int _length, int _patter );

void InitHashList();

 

void InitQueue()

{

           front = rear = 0;

}

 

void InitHashList()

{

           int i;

           for ( i = 0; i < HASH_SIZE; i++ )

           {

                     hashList[i].next = 0;

           }

}

 

int PushQueue( char _data )

{

           queue[rear++] = _data;

           rear = rear % QUEUE_SIZE;

           return _data;

}

 

int PopQueue()

{

           char pop = queue[front++];

           front = front % QUEUE_SIZE;

 

           return pop;

}

 

int CheckQueue( int _length )

{

           HashList *tempList;

           int tempPos;

           int i;

           current = QUEUE_POS( rear - _length );

 

           tempList = hashList[ queue[current] ].next;

 

           while( tempList != NULL )

           {

                     tempPos = tempList->pos;

                     for ( i = 1; i < _length; i++ )

                     {

                                if ( queue[ QUEUE_POS( current + i) ] !=

                                          queue[ QUEUE_POS(tempPos + i) ] )

                                          break;

                     }

 

                     if ( i == _length )

                                return tempPos;

 

                     tempList = tempList->next;

           }

 

           return -1;

}

 

int AddHashList( char _data, int _pos )

{

           HashList *newList;

           newList = new HashList;

           if ( newList == NULL )

                     return 0;

 

           newList->pos = _pos;

           newList->next = hashList[(unsigned char)_data].next;

           hashList[(unsigned char)_data].next = newList;

 

           return 1;

}

 

int DelHashList( char _data, int _pos )

{

           HashList *tempList, *saveList;

 

           tempList = hashList[(unsigned char)_data].next;

           saveList = &hashList[(unsigned char)_data];

 

           while( tempList != NULL )

           {

                     if ( tempList->pos == _pos )

                     {

                                break;

                     }

 

                     saveList = tempList;

                     tempList = tempList->next;

           }

 

           if ( tempList )

           {

                     saveList->next = tempList->next;

                     delete tempList;

                     return 1;

           }

 

           return 0;

}

 

int main( int argc, char *argv[] )

{

           char buffer[4096];

           char compbuffer[4096];

           int size;

 

           memset( buffer, 'a', 256 );

           buffer[256] = 'b';

           buffer[257] = ESCAPE_CHAR;

           buffer[258] = 'c';

           buffer[259] = 0;

 

           printf("orig: %s\n", buffer );

           LempelZivCompress( buffer, 259, compbuffer, &size );

 

           memset( buffer, 0, 4096 );

           LempelZivDeCompress( compbuffer, size, buffer, &size );

           buffer[ size ] = 0;

           printf("decomp: %s\n", buffer );

 

 

           return 1;

}

 

int compress( char *_data, int _current, int _length, int _pattern )

{

           int ret = 0;

 

           if ( _length > MIN_COMPRESS )

           {

                     *_data++ = ESCAPE_CHAR;

                     *_data++ = _current - _pattern;

                     *_data++ = _length;

 

                     ret = 3;

           }

           else

           {

                     int i;

                     for ( i = 0; i < _length; i++ )

                     {

                                if ( queue[ _pattern + i ] == (char)ESCAPE_CHAR )

                                {

                                          *_data++ = ESCAPE_CHAR;

                                          *_data++ = 0x00;

                                          ret += 2;

                                }

                                else{ *_data++ = queue[ _pattern + i ]; ret++; }

                     }

           }

 

           return ret;

}

 

int LempelZivCompress

(

           char *_data,

           int _dataSize,

           char *_compressData,

           int *_compressSize

)

{

           int i;

           int pattern, matchlength;

          

           pattern = matchlength = 0;

 

           char *writeData = _compressData;

           PushQueue( _data[0] );

           int ret;

          

           i = 0;

           while( i < _dataSize )

           {

                     if ( QUEUE_FULL )

                     {

                                if ( pattern == front )

                                {

                                          ret = compress( writeData, current,

                                                     matchlength, pattern );

                                          writeData += ret;

                                          matchlength = 0;

                                }

 

                                DelHashList( queue[front], front );

                                PopQueue();

                     }

                    

                     if ( matchlength == 0 )

                     {

                                current = QUEUE_POS( rear - 1 );

                                ret = CheckQueue( matchlength + 1 );

                                if ( ret == -1 )

                                {

                                          AddHashList( queue[current], QUEUE_POS(rear-1) );

                                          ret = compress( writeData, current, 1, current );

                                          writeData += ret;

                                          matchlength = 0;

                                }

                                else

                                {

                                          matchlength++;

                                          pattern = ret;

                                }

 

                                PushQueue( _data[++i] );    

                     }

                     else

                     {

                                ret = CheckQueue( matchlength + 1 );

                                if ( ret == -1 )

                                {

                                          ret = compress( writeData, current,

                                                      matchlength, pattern );

                                          writeData += ret;

                                          matchlength = 0;

                                }

                                else

                                {

                                          matchlength++;

                                          PushQueue( _data[++i] );

                                          pattern = ret;

                                }

                     }

           }

 

           compress( writeData, current, matchlength, pattern );

 

           *_compressSize = writeData - _compressData;

           return *_compressSize;

}

 

int LempelZivDeCompress

(

           char *_compressData,

           int _compressSize,

           char *_data,

           int *_dataSize

)

{

           int i;

           int length;

           int pos;

           char *writeData = _data;

 

           InitQueue();

          

           for ( i = 0; i < _compressSize; i++ )

           {

                     if ( _compressData[i] != (char)ESCAPE_CHAR )

                     {

                                PushQueue( _compressData[i] );

                                if ( QUEUE_FULL )

                                {

                                          *writeData++ = (char)PopQueue();

                                }

                     }

                     else

                     {

                                pos = _compressData[++i];

                                if ( pos == (char)0x00 )

                                {

                                          PushQueue( ESCAPE_CHAR );

                                          if ( QUEUE_FULL )

                                          {

                                                     *writeData++ = (char)PopQueue();

                                          }

                                }

                                else

                                {

                                          length = (unsigned char)_compressData[++i];

                                          pos = QUEUE_POS( rear - pos );

                                          for ( int t = 0; t < length; t++ )

                                          {

                                                     PushQueue( queue[pos + t] );

                                                     if ( QUEUE_FULL )

                                                     {

                                                                *writeData++ = (char)PopQueue();

                                                     }

                                          }

                                }

                     }

           }

 

           while( !(QUEUE_EMPTY) )

           {

                     *writeData++ = (char)PopQueue();

           }

 

           *_dataSize = writeData - _data;

           return *_dataSize;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////