LZW压缩算法源代码

  1. // LZW.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #pragma warning (disable:4996)
  5. /* Basic LZW Data Compression program published in DDJ October 1989 issue.
  6.  * Original Author: Mark R. Nelson
  7.  * Updated by: Shawn M. Regan, January 1990
  8.  * Added: - Method to clear table when compression ratio degrades
  9.  *        - Self adjusting code size capability (up to 14 bits)
  10.  * Updated functions are marked with "MODIFIED". main() has been updated also
  11.  * Compile with -ml (large model) for MAX_BITS == 14 only
  12.  */
  13. #define INIT_BITS       9
  14. #define MAX_BITS        14              /* Do not exceed 14 with this program */
  15. #define HASHING_SHIFT MAX_BITS - 8
  16. #if MAX_BITS == 14                      /* Set the table size. Must be a prime    */
  17.     #define TABLE_SIZE 18041            /* number somewhat larger than 2^MAX_BITS.*/
  18. #elif MAX_BITS == 13
  19.     #define TABLE_SIZE 9029
  20. #else
  21.     #define TABLE_SIZE 5021
  22. #endif
  23. #define CLEAR_TABLE     256             /* Code to flush the string table */
  24. #define TERMINATOR      257             /* To mark EOF Condition, instead of MAX_VALUE */
  25. #define FIRST_CODE      258             /* First available code for code_value table */
  26. #define CHECK_TIME      100             /* Check comp ratio every CHECK_TIME chars input */
  27. #define MAXVAL(n) (( 1 <<( n )) -1)     /* max_value formula macro */
  28. int *currnt_code;                       /* This is the code value array */
  29. unsigned int *prefix_code;              /* This array holds the prefix codes */
  30. unsigned char *append_char;             /* This array holds the appended chars */
  31. unsigned char decode_stack[4000];       /* This array holds the decoded string */
  32. unsigned long bytes_in  = 0;
  33. unsigned long bytes_out = 0;            /* Used to monitor compression ratio */
  34. unsigned long checkpoint= CHECK_TIME;   /* For compression ratio monitoring */
  35. int num_bits            = INIT_BITS;    /* Starting with 9 bit codes */
  36. int max_code            = 0;            /* old MAX_CODE */
  37. void Encode(FILE *input, FILE *output);
  38. void Decode(FILE *input, FILE *output);
  39. void output_code(FILE *output, unsigned int code);
  40. int find_match(int hash_prefix, unsigned int hash_character);
  41. char *decode_string(unsigned char *buffer, unsigned int code);
  42. unsigned int input_code(FILE *input);
  43. int main(int argc, char *argv[]){
  44.     FILE *EncodeFile    = NULL;
  45.     FILE *DecodeFile    = NULL;
  46.     FILE *LZWTempFile   = NULL;
  47.     __try {
  48.         //分配压缩缓冲区
  49.         currnt_code     = (int*)malloc( TABLE_SIZE * sizeof(unsigned int) );
  50.         prefix_code     = (unsigned int*)malloc( TABLE_SIZE * sizeof(unsigned int) );
  51.         append_char     = (unsigned char*)malloc( TABLE_SIZE * sizeof(unsigned char) );
  52.         if ( currnt_code == NULL || prefix_code == NULL || append_char == NULL ){
  53.             __leave;
  54.         }
  55.         if ( argc < 2 ){
  56.             __leave;
  57.         }
  58.         //获取将要压缩的文件名称
  59.         EncodeFile      = fopen( argv[1],   "rb" );
  60.         LZWTempFile     = fopen( "test.lzw","wb" );
  61.         if ( EncodeFile == NULL || LZWTempFile == NULL ){
  62.             __leave;
  63.         }
  64.         max_code        = MAXVAL( num_bits );       /* Initialize max_value & max_code */
  65.         Encode( EncodeFile, LZWTempFile );          /* Call compression routine */
  66.         fclose( LZWTempFile );
  67.         //重新打开压缩数据,还原成原始文件
  68.         LZWTempFile     = fopen( "test.lzw""rb" );
  69.         DecodeFile      = fopen( "test.out""wb" );
  70.         if ( LZWTempFile == NULL || DecodeFile == NULL ){
  71.             __leave;
  72.         }
  73.         num_bits        = INIT_BITS;                /* Re-initialize for expansion */
  74.         max_code        = MAXVAL(num_bits);
  75.         Decode( LZWTempFile, DecodeFile );          /* Call expansion routine */
  76.     }
  77.     __finally {
  78.         if( EncodeFile != NULL ){
  79.             fclose( EncodeFile );
  80.         }
  81.         if( DecodeFile != NULL ){
  82.             fclose( DecodeFile );
  83.         }
  84.         if( LZWTempFile != NULL ){
  85.             fclose( LZWTempFile );
  86.         }
  87.         if( prefix_code != NULL ){
  88.             free( prefix_code );
  89.         }
  90.         if( append_char != NULL ){
  91.             free( append_char );
  92.         }
  93.         if( currnt_code != NULL ){
  94.             free( currnt_code );
  95.         }
  96.     }
  97. }
  98. /* MODIFIED This is the new compression routine. The first two 9-bit codes 
  99.  * have been reserved for communication between the compressor and expander.
  100.  */
  101. void Encode(FILE *input, FILE *output){
  102.     unsigned int next_code      =   FIRST_CODE;
  103.     unsigned int character;
  104.     unsigned int string_code;
  105.     unsigned int index;
  106.     int ratio_new;          /* New compression ratio as a percentage */
  107.     int ratio_old=100;      /* Original ratio at 100% */
  108.     //初始化字符串表。
  109.     for ( int i = 0; i < TABLE_SIZE; i++ ){
  110.         currnt_code[i]      = -1;
  111.     }
  112.     puts( "正在压缩中,请稍后..." );
  113.     //获取原文件第一个字节码
  114.     string_code = getc(input);
  115.     while( ( character = getc(input) ) != (unsigned)EOF ){
  116.         index                       = find_match( string_code, character );
  117.         if( currnt_code[index] != -1 ){
  118.             string_code             = currnt_code[index];
  119.             continue;
  120.         }
  121.         if ((int)next_code <= max_code ) {
  122.             currnt_code[index]      = next_code++;
  123.             prefix_code[index]      = string_code;
  124.             append_char[index]      = character;
  125.         }
  126.         output_code( output, string_code );                 /* Send out current code */
  127.         string_code                 = character;
  128.         if( (int)next_code <= max_code ){                   /* Is table Full? */
  129.             continue;
  130.         }
  131.         if ( num_bits < MAX_BITS ){                         /* Any more bits? */
  132.             max_code                = MAXVAL( ++num_bits ); /* Increment code size then */
  133.         }
  134.         
  135.         if( bytes_in > checkpoint ){                        /* At checkpoint? */
  136.             if ( num_bits == MAX_BITS ){
  137.                 ratio_new   = bytes_out * 100 / bytes_in;   /* New compression ratio */
  138.                 
  139.                 if( ratio_new > ratio_old ){                /* Has ratio degraded? */
  140.                     output_code( output, CLEAR_TABLE );     /* YES,flush string table */ 
  141.                     num_bits    = INIT_BITS;
  142.                     next_code   = FIRST_CODE;               /* Reset to FIRST_CODE */
  143.                     max_code    = MAXVAL(num_bits);         /* Re-Initialize this stuff */
  144.                     bytes_in    = bytes_out = 0;
  145.                     ratio_old   = 100;                      /* Reset compression ratio */
  146.                     forint i = 0;i < TABLE_SIZE; i++ ){   /* Reset code value array */
  147.                         currnt_code[i]  = -1;
  148.                     }
  149.                 }else{                                      /* NO, then save new */
  150.                     ratio_old           = ratio_new;        /* compression ratio */
  151.                 }
  152.             }
  153.             checkpoint= bytes_in + CHECK_TIME;              /* Set new checkpoint */
  154.         }
  155.     }
  156.     output_code( output, string_code );                     /* Output the last code */
  157.     if ( next_code == max_code ){                           /* Handles special case for bit */
  158.         ++num_bits;                                         /* increment on EOF */
  159.     }
  160.     output_code( output, TERMINATOR );                      /* Output the end of buffer code */
  161.     output_code( output, 0 );                               /* Flush the output buffer */
  162.     output_code( output, 0 );
  163.     output_code( output, 0 );
  164.     puts("压缩数据完成,输出数据文件名:test.lzw"); 
  165. }
  166. int find_match(int hash_prefix, unsigned int hash_character){ 
  167.     int offset;
  168.     int index;
  169.     index       = hash_character << (HASHING_SHIFT) ^ hash_prefix; 
  170.     if ( !index ){
  171.         offset  = 1;
  172.     }else{
  173.         offset  = TABLE_SIZE - index;
  174.     }
  175.     whiletrue ){
  176.         if( currnt_code[index] == -1 ){
  177.             return index;
  178.         }
  179.         if( prefix_code[index] == hash_prefix && append_char[index] == hash_character ){
  180.             return index;
  181.         }
  182.         index -= offset;
  183.         if( index < 0 ){
  184.             index += TABLE_SIZE;
  185.         }
  186.     }
  187. }
  188. void Decode(FILE *input, FILE *output){
  189.     unsigned char *string;
  190.     unsigned int next_code=FIRST_CODE;
  191.     unsigned int new_code;
  192.     unsigned int old_code;
  193.     int character           = 0; 
  194.     int clear_flag          = 1;                            /* Need to clear the code value array */
  195.     puts( "正在解压缩中,请稍后..." );
  196.     while( ( new_code = input_code( input ) ) != TERMINATOR ){
  197.         if( clear_flag ){                                   /* Initialize or Re-Initialize */
  198.             clear_flag      = 0;
  199.             old_code        = new_code;                     /* The next three lines have been moved */
  200.             character       = old_code;                     /* from the original */
  201.             putc( old_code, output );
  202.             continue;
  203.         }
  204.         if ( new_code == CLEAR_TABLE ){                     /* Clear string table */
  205.             clear_flag      = 1;
  206.             num_bits        = INIT_BITS;
  207.             next_code       = FIRST_CODE; 
  208.             max_code        = MAXVAL(num_bits);
  209.             continue;
  210.         }
  211.         if( new_code >= next_code ){                        /* Check for string+char+string */
  212.             *decode_stack   = character;
  213.             string          = (unsigned char*)decode_string( decode_stack+1, old_code );
  214.         }else{
  215.             string          = (unsigned char*)decode_string( decode_stack, new_code );
  216.         }
  217.         character           = *string;                      /* Output decoded string in reverse */
  218.         while( string >= decode_stack ){
  219.             putc( *string--, output );
  220.         }
  221.         if( (int)next_code <= max_code ){                   /* Add to string table if not full */
  222.             prefix_code[next_code]      = old_code;
  223.             append_char[next_code++]    = character;
  224.             if( next_code == max_code && num_bits < MAX_BITS ){
  225.                 max_code = MAXVAL( ++num_bits );
  226.             }
  227.         }
  228.         old_code    = new_code;
  229.     }
  230.     puts("解压缩数据完成,输出数据文件名:test.out"); 
  231. }
  232. char *decode_string(unsigned char *buffer, unsigned int code){
  233.     int i   = 0;
  234.     while( code > 255 ){
  235.         *buffer++   = append_char[code];
  236.         code        = prefix_code[code];
  237.         if ( i++ >= 4000 ) {
  238.             puts( "Error during code expansion" );
  239.             exit(1);
  240.         }
  241.     }
  242.     *buffer = code;
  243.     return (char*)buffer;
  244. }
  245. unsigned int input_code(FILE *input){
  246.     unsigned int return_value;
  247.     static int input_bit_count  = 0;
  248.     static unsigned long input_bit_buffer   = 0L;
  249.     while( input_bit_count  <= 24 ){
  250.         input_bit_buffer    |= (unsigned long)getc( input ) << ( 24 - input_bit_count );
  251.         input_bit_count     += 8;
  252.     }
  253.     return_value            =   input_bit_buffer >> (32-num_bits);
  254.     input_bit_buffer        <<= num_bits;
  255.     input_bit_count         -=  num_bits;
  256.     return return_value;
  257. }
  258. void output_code(FILE *output, unsigned int code){
  259.     static int output_bit_count = 0;
  260.     static unsigned long output_bit_buffer  = 0L;
  261.     output_bit_buffer   |= (unsigned long) code << (32 - num_bits - output_bit_count);
  262.     output_bit_count    += num_bits;
  263.     while( output_bit_count >= 8 ){
  264.         putc( output_bit_buffer >> 24, output );
  265.         output_bit_buffer   <<= 8;
  266.         output_bit_count    -=  8;
  267.         bytes_out++;  
  268.     }
  269. }

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值