|
Programming Guru
Join Date: Oct 2004
Posts: 1,041
Rep Power: 6 
|
Google is still your god, just search for the right things. I searched for "Huffman code in C++" and found a C implementation of it. Im sure though if you kept looking you could find C++ implementation.
/* 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);
}
__________________
|