⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 codhuff.c

📁 著名压缩算法的实现
💻 C
字号:
/* File: codhuff.c   Author: David Bourgin (David.Bourgin@ufrima.imag.fr)   Creation date: 7/2/94   Last update: 24/7/95   Purpose: Example of Huffman encoding with a file source to compress.   Attention: The compiler must have been configured for a stack of at least   20 kb.*/#include <stdio.h>/* For routines fgetc,fputc,fwrite and rewind */#include <memory.h>/* For routines memset,memcpy */#include <malloc.h>/* For routines malloc and free */#include <stdlib.h>/* For routines qsort et exit *//* Error codes returned to the caller */#define NO_ERROR      0#define BAD_FILE_NAME 1#define BAD_ARGUMENT  2#define BAD_MEM_ALLOC 3/* Useful constants */#define FALSE 0#define TRUE  1/* Global variables */FILE *source_file,*dest_file;typedef struct s_tree { unsigned int byte;                             /* A byte has to be coded as an unsigned integer to allow a node to have a value over 255 */                        unsigned long int weight;                        struct s_tree *left_ptr,                                      *right_ptr;                      } t_tree,*p_tree;#define BYTE_OF_TREE(ptr_tree)  ((*(ptr_tree)).byte)#define WEIGHT_OF_TREE(ptr_tree)  ((*(ptr_tree)).weight)#define LEFTPTR_OF_TREE(ptr_tree)  ((*(ptr_tree)).left_ptr)#define RIGHTPTR_OF_TREE(ptr_tree)  ((*(ptr_tree)).right_ptr)typedef struct { unsigned char bits[32];                 unsigned int bits_nb;               } t_bin_val;#define BITS_BIN_VAL(bin_val)  ((bin_val).bits)#define BITS_NB_BIN_VAL(bin_val)  ((bin_val).bits_nb)                             /* Being that fgetc=EOF only after any access                                then 'stored_byte_status' is 'TRUE' if a byte has been stored with 'fgetc'                                or 'FALSE' if there's no valid byte not already read and not handled in 'stored_byte_val' */int stored_byte_status=FALSE;int stored_byte_val;/* Pseudo procedures */#define beginning_of_data()  { (void)rewind(source_file); stored_byte_status=FALSE; }#define end_of_data()  (stored_byte_status?FALSE:!(stored_byte_status=((stored_byte_val=fgetc(source_file))!=EOF)))#define read_byte()  (stored_byte_status?stored_byte_status=FALSE,(unsigned char)stored_byte_val:(unsigned char)fgetc(source_file))#define write_byte(byte)  ((void)fputc((byte),dest_file))unsigned char bit_counter_to_write=0;unsigned int val_to_write=0;void write_bin_val(bin_val)/* Returned parameters: None   Action: Writes in the output stream the value binary-coded into 'bin_val'   Errors: An input/output error could disturb the running of the program*/t_bin_val bin_val;{ unsigned char bin_pos,                byte_pos;  byte_pos=(BITS_NB_BIN_VAL(bin_val)+7) >> 3;  bin_pos=BITS_NB_BIN_VAL(bin_val) & 7;  if (bin_pos)     { byte_pos--;       val_to_write=(val_to_write<<bin_pos)|BITS_BIN_VAL(bin_val)[byte_pos];       bit_counter_to_write += bin_pos;       if (bit_counter_to_write>=8)          { bit_counter_to_write -= 8;            write_byte((unsigned char)(val_to_write>>bit_counter_to_write));            val_to_write &= ((1<<bit_counter_to_write)-1);          }     }  while (byte_pos)        { byte_pos--;          val_to_write=(val_to_write<<8)|BITS_BIN_VAL(bin_val)[byte_pos];          write_byte((unsigned char)(val_to_write>>bit_counter_to_write));          val_to_write &= ((1<<bit_counter_to_write)-1);        }}void fill_encoding()/* Returned parameters: None   Action: Fills the last byte to write in the output stream with zero values   Errors: An input/output error could disturb the running of the program*/{ if (bit_counter_to_write)     write_byte(val_to_write << (8-bit_counter_to_write));}void write_header(codes_table)/* Returned parameters: None   Action: Writes the header in the stream of codes   Errors: An input/output error could disturb the running of the program*/t_bin_val codes_table[257];{ register unsigned int i,j;  t_bin_val bin_val_to_0,            bin_val_to_1,            bin_val;         /* Is used to send in binary mode via write_bin_val */  *BITS_BIN_VAL(bin_val_to_0)=0;  BITS_NB_BIN_VAL(bin_val_to_0)=1;  *BITS_BIN_VAL(bin_val_to_1)=1;  BITS_NB_BIN_VAL(bin_val_to_1)=1;  for (i=0,j=0;j<=255;j++)      if BITS_NB_BIN_VAL(codes_table[j])         i++;                             /* From there, i contains the number of bytes of the several non null occurrences to encode */                              /* First part of the header: Specifies the bytes that appear in the source of encoding */  if (i<32)     {                       /* Encoding of the appeared bytes with a block of bytes */       write_bin_val(bin_val_to_0);       BITS_NB_BIN_VAL(bin_val)=5;       *BITS_BIN_VAL(bin_val)=(unsigned char)(i-1);       write_bin_val(bin_val);       BITS_NB_BIN_VAL(bin_val)=8;       for (j=0;j<=255;j++)           if BITS_NB_BIN_VAL(codes_table[j])              { *BITS_BIN_VAL(bin_val)=(unsigned char)j;                write_bin_val(bin_val);              }     }  else {                     /* Encoding of the appeared bytes with a block of bits */         write_bin_val(bin_val_to_1);         for (j=0;j<=255;j++)             if BITS_NB_BIN_VAL(codes_table[j])                write_bin_val(bin_val_to_1);             else write_bin_val(bin_val_to_0);     };                             /* Second part of the header: Specifies the encoding of the bytes (fictive or not) that appear in the source of encoding */  for (i=0;i<=256;i++)      if (j=BITS_NB_BIN_VAL(codes_table[i]))         { if (j<33)              { write_bin_val(bin_val_to_0);                BITS_NB_BIN_VAL(bin_val)=5;              }           else { write_bin_val(bin_val_to_1);                  BITS_NB_BIN_VAL(bin_val)=8;                }           *BITS_BIN_VAL(bin_val)=(unsigned char)(j-1);           write_bin_val(bin_val);           write_bin_val(codes_table[i]);         }}int weight_tree_comp(tree1,tree2)/* Returned parameters: Returns a comparison status   Action: Returns a negative, zero or positive integer depending on the weight   of 'tree2' is less than, equal to, or greater than the weight of 'tree1'   Errors: None*/p_tree *tree1,*tree2;{ return (WEIGHT_OF_TREE(*tree2) ^ WEIGHT_OF_TREE(*tree1))?((WEIGHT_OF_TREE(*tree2)<WEIGHT_OF_TREE(*tree1))?-1:1):0;}void suppress_tree(tree)/* Returned parameters: None   Action: Suppresses the allocated memory for the 'tree'   Errors: None if the tree has been build with dynamical allocations!*/p_tree tree;{ if (tree!=NULL)     { suppress_tree(LEFTPTR_OF_TREE(tree));       suppress_tree(RIGHTPTR_OF_TREE(tree));       free(tree);     }}p_tree build_tree_encoding()/* Returned parameters: Returns a tree of encoding   Action: Generates an Huffman encoding tree based on the data from the stream to compress   Errors: If no memory is available for the allocations then a 'BAD_MEM_ALLOC' exception is raised*/{ register unsigned int i;  p_tree occurrences_table[257],         ptr_fictive_tree;                             /* Sets up the occurrences number of all bytes to 0 */  for (i=0;i<=256;i++)      { if ((occurrences_table[i]=(p_tree)malloc(sizeof(t_tree)))==NULL)           { for (;i;i--)                 free(occurrences_table[i-1]);             exit(BAD_MEM_ALLOC);           }        BYTE_OF_TREE(occurrences_table[i])=i;        WEIGHT_OF_TREE(occurrences_table[i])=0;        LEFTPTR_OF_TREE(occurrences_table[i])=NULL;        RIGHTPTR_OF_TREE(occurrences_table[i])=NULL;      }                             /* Valids the occurrences of 'occurrences_table' with regard to the data to compressr */  if (!end_of_data())     { while (!end_of_data())             { i=read_byte();               WEIGHT_OF_TREE(occurrences_table[i])++;             }       WEIGHT_OF_TREE(occurrences_table[256])=1;                             /* Sorts the occurrences table depending on the weight of each character */       (void)qsort(occurrences_table,257,sizeof(p_tree),weight_tree_comp);       for (i=256;(i!=0)&&(!WEIGHT_OF_TREE(occurrences_table[i]));i--)           free(occurrences_table[i]);       i++;                             /* From there, 'i' gives the number of different bytes with a null occurrence in the stream to compress */       while (i>0)           /* Looks up (i+1)/2 times the occurrence table to link the nodes in an uniq tree */             { if ((ptr_fictive_tree=(p_tree)malloc(sizeof(t_tree)))==NULL)                  { for (i=0;i<=256;i++)                        suppress_tree(occurrences_table[i]);                    exit(BAD_MEM_ALLOC);                  }               BYTE_OF_TREE(ptr_fictive_tree)=257;               WEIGHT_OF_TREE(ptr_fictive_tree)=WEIGHT_OF_TREE(occurrences_table[--i]);               LEFTPTR_OF_TREE(ptr_fictive_tree)=occurrences_table[i];               if (i)                  { i--;                    WEIGHT_OF_TREE(ptr_fictive_tree) += WEIGHT_OF_TREE(occurrences_table[i]);                    RIGHTPTR_OF_TREE(ptr_fictive_tree)=occurrences_table[i];                  }               else RIGHTPTR_OF_TREE(ptr_fictive_tree)=NULL;               occurrences_table[i]=ptr_fictive_tree;               (void)qsort((char *)occurrences_table,i+1,sizeof(p_tree),weight_tree_comp);               if (i)        /* Is there an other node in the occurrence tables? */                  i++;       /* Yes, then takes care to the fictive node */             }     }  return (*occurrences_table);}void encode_codes_table(tree,codes_table,code_val)/* Returned parameters: The data of 'codes_table' can have been modified   Action: Stores the encoding tree as a binary encoding table to speed up the access.   'val_code' gives the encoding for the current node of the tree   Errors: None*/p_tree tree;t_bin_val codes_table[257],          *code_val;{ register unsigned int i;  t_bin_val tmp_code_val;  if (BYTE_OF_TREE(tree)==257)     { if (LEFTPTR_OF_TREE(tree)!=NULL)                             /* The sub-trees on left begin with an bit set to 1 */          { tmp_code_val = *code_val;            for (i=31;i>0;i--)                BITS_BIN_VAL(*code_val)[i]=(BITS_BIN_VAL(*code_val)[i] << 1)|(BITS_BIN_VAL(*code_val)[i-1] >> 7);            *BITS_BIN_VAL(*code_val)=(*BITS_BIN_VAL(*code_val) << 1) | 1;            BITS_NB_BIN_VAL(*code_val)++;            encode_codes_table(LEFTPTR_OF_TREE(tree),codes_table,code_val);            *code_val = tmp_code_val;          };       if (RIGHTPTR_OF_TREE(tree)!=NULL)                             /* The sub-trees on right begin with an bit set to 0 */          { tmp_code_val = *code_val;            for (i=31;i>0;i--)                BITS_BIN_VAL(*code_val)[i]=(BITS_BIN_VAL(*code_val)[i] << 1)|(BITS_BIN_VAL(*code_val)[i-1] >> 7);            *BITS_BIN_VAL(*code_val) <<= 1;            BITS_NB_BIN_VAL(*code_val)++;            encode_codes_table(RIGHTPTR_OF_TREE(tree),codes_table,code_val);            *code_val = tmp_code_val;          };     }  else codes_table[BYTE_OF_TREE(tree)] = *code_val;}void create_codes_table(tree,codes_table)/* Returned parameters: The data in 'codes_table' will be modified   Action: Stores the encoding tree as a binary encoding table to speed up the access by calling encode_codes_table   Errors: None*/p_tree tree;t_bin_val codes_table[257];{ register unsigned int i;  t_bin_val code_val;  (void)memset((char *)&code_val,0,sizeof(code_val));  (void)memset((char *)codes_table,0,257*sizeof(*codes_table));  encode_codes_table(tree,codes_table,&code_val);}void huffmanencoding()/* Returned parameters: None   Action: Compresses with Huffman method all bytes read by the function 'read_byte'   Errors: An input/output error could disturb the running of the program*/{ p_tree tree;  t_bin_val encoding_table[257];  unsigned char byte_read;  if (!end_of_data())                             /* Generates only whether there are data */     { tree=build_tree_encoding();                             /* Creation of the best adapted tree */       create_codes_table(tree,encoding_table);       suppress_tree(tree);                             /* Obtains the binary encoding in an array to speed up the accesses */       write_header(encoding_table);                             /* Writes the defintion of the encoding */       beginning_of_data();  /* Real compression of the data */       while (!end_of_data())             { byte_read=read_byte();               write_bin_val(encoding_table[byte_read]);             }       write_bin_val(encoding_table[256]);                             /* Code of the end of encoding */       fill_encoding();                             /* Fills the last byte before closing file, if any */     }}void help()/* Returned parameters: None   Action: Displays the help of the program and then stops its running   Errors: None*/{ printf("This utility enables you to compress a file by using Huffman method\n");  printf("as given in 'La Video et Les Imprimantes sur PC'\n");  printf("\nUse: codhuff source target\n");  printf("source: Name of the file to compress\n");  printf("target: Name of the compressed file\n");}int main(argc,argv)/* Returned parameters: Returns an error code (0=None)   Action: Main procedure   Errors: Detected, handled and an error code is returned, if any*/int argc;char *argv[];{ if (argc!=3)     { help();       exit(BAD_ARGUMENT);     }  else if ((source_file=fopen(argv[1],"rb"))==NULL)          { help();            exit(BAD_FILE_NAME);          }       else if ((dest_file=fopen(argv[2],"wb"))==NULL)               { help();                 exit(BAD_FILE_NAME);               }            else { huffmanencoding();                   fclose(source_file);                   fclose(dest_file);                 }  printf("Execution of codhuff completed.\n");  return (NO_ERROR);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -