Files
failnix/targets/wasm-tacle/sequential/huff_enc/huff_enc.c

590 lines
20 KiB
C
Executable File

/*
This program is part of the TACLeBench benchmark suite.
Version V 2.0
Name: huff_enc
Author: David Bourgin (David.Bourgin@ufrima.imag.fr)
Function: Example of Huffman encoding
Source: ftp://turing.imag.fr/pub/compression/ (1994-09-22)
Original name: codhuff.c
Changes: I/O to char arrays instead of file i/o.
Dynamic memory allocation replaced by array.
Explicit sorting algorithm.
License:
The source code files (codrl1.c, dcodrl1.c, codrle2.c, dcodrle2.c, codrle3.c,
dcodrle3.c, codrle4.c, dcodrle4.c, codhuff.c, dcodhuff.c) are copyrighted.
They have been uploaded on ftp in turing.imag.fr (129.88.31.7):/pub/compression
on 22/5/94 and have been modified on 22/9/94.
(c) David Bourgin - 1994
The source codes I provide have no buggs (!) but being that I make them
available for free I have some notes to make. They can change at any time
without notice. I assume no responsability or liability for any errors or
inaccurracies, make no warranty of any kind (express, implied or statutory)
with respect to this publication and expressly disclaim any and all warranties
of merchantability, fitness for particular purposes. Of course, if you have
some problems to use the information presented here, I will try to help you if
I can.
If you include the source codes in your application, here are the conditions:
- You have to put my name in the header of your source file (not in the
excutable program if you don't want) (this item is a must)
- I would like to see your resulting application, if possible (this item is not
a must, because some applications must remain secret)
- Whenever you gain money with your application, I would like to receive a very
little part in order to be encouraged to update my source codes and to develop
new schemes (this item is not a must)
*/
/*
Declaration of types
*/
typedef struct huff_enc_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 huff_enc_s_tree *left_ptr;
struct huff_enc_s_tree *right_ptr;
} huff_enc_t_tree;
typedef struct {
unsigned char bits[ 32 ];
unsigned int bits_nb;
} huff_enc_t_bin_val;
/*
Forward declaration of functions
*/
void huff_enc_init( void );
int huff_enc_return( void );
void huff_enc_beginning_of_data();
int huff_enc_end_of_data();
int huff_enc_read_byte();
void huff_enc_write_byte( char ch );
void huff_enc_write_bin_val( huff_enc_t_bin_val bin_val );
void huff_enc_fill_encoding( void );
void huff_enc_write_header( huff_enc_t_bin_val codes_table[ 257 ] );
int huff_enc_weighhuff_enc_t_tree_comp( const void *t1, const void *t2 );
void huff_enc_swapi( char *ii, char *ij, unsigned long es );
char *huff_enc_pivot( char *a, unsigned long n, unsigned long es );
void huff_enc_qsort( char *a, unsigned long n, unsigned long es );
huff_enc_t_tree *huff_enc_build_tree_encoding( huff_enc_t_tree heap[ 514 ] );
void huff_enc_encode_codes_table( huff_enc_t_tree *tree,
huff_enc_t_bin_val codes_table[ 257 ], huff_enc_t_bin_val *code_val );
void huff_enc_create_codes_table( huff_enc_t_tree *tree,
huff_enc_t_bin_val codes_table[ 257 ] );
void huff_enc_main();
int main( void );
/*
Declaration of global variables
*/
static int huff_enc_input_pos;
static int huff_enc_output_pos;
static unsigned char huff_enc_output[ 1024 ];
static unsigned char huff_enc_byte_nb_to_write = 0;
static unsigned char huff_enc_val_to_write = 0;
/*
Initialization- and return-value-related functions
*/
#define huff_enc_plaintext_len 600
static const char *huff_enc_plaintext =
"You are doubtless asking \"How can I reduce the data size without losing "
"some informations?\". It's easy to answer to this question. I'll only take "
"an example. I'm sure you have heard about the morse. This system established "
"in the 19th century use a scheme very close to the huffman one. In the morse "
"you encode the letters to transmit with two kinds of signs. If you encode "
"these two sign possibilities in one bit, the symbol 'e' is transmitted in a "
"single bit and the symbols 'y' and 'z' need four bits. Look at the symbols "
"in the text you are reading, you'll fast understand the compression ratio...";
#define huff_enc_encoded_len 419
static unsigned char huff_enc_encoded[ huff_enc_encoded_len ] = {
128, 0, 0, 0, 80, 133, 32, 32, 128, 100, 4, 32, 63, 239, 255, 240,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 7, 167, 21, 129, 232, 69, 120, 132, 217, 20, 162, 19, 164, 39, 133,
252, 138, 105, 20, 194, 19, 129, 240, 172, 138, 248, 150, 11, 11, 240, 201,
68, 64, 114, 53, 17, 42, 37, 195, 128, 212, 116, 194, 41, 98, 52, 51,
12, 132, 112, 244, 3, 36, 33, 52, 39, 135, 164, 33, 62, 156, 87, 14,
110, 22, 87, 50, 85, 198, 99, 142, 140, 194, 81, 78, 158, 84, 129, 254,
129, 248, 110, 179, 159, 192, 145, 133, 184, 184, 28, 210, 96, 146, 73, 10,
226, 21, 83, 152, 74, 13, 111, 132, 199, 202, 219, 241, 74, 193, 167, 105,
222, 31, 147, 6, 55, 31, 129, 40, 232, 52, 153, 160, 148, 18, 36, 197,
45, 216, 202, 86, 30, 31, 177, 90, 133, 138, 248, 23, 81, 195, 160, 100,
215, 93, 50, 185, 225, 251, 23, 6, 230, 225, 229, 112, 71, 80, 96, 141,
205, 176, 230, 85, 196, 9, 24, 93, 90, 121, 225, 76, 68, 152, 63, 25,
107, 140, 101, 204, 214, 77, 26, 194, 96, 18, 48, 77, 210, 137, 1, 253,
4, 230, 248, 56, 240, 224, 111, 163, 95, 10, 12, 223, 7, 234, 167, 129,
40, 36, 96, 135, 125, 245, 250, 2, 198, 120, 127, 0, 145, 133, 213, 167,
135, 149, 195, 67, 235, 108, 9, 24, 87, 17, 102, 152, 37, 4, 222, 131,
188, 144, 73, 36, 128, 73, 20, 81, 152, 177, 133, 248, 28, 165, 131, 120,
127, 240, 242, 184, 104, 125, 109, 129, 35, 30, 4, 145, 65, 202, 88, 9,
138, 103, 44, 205, 100, 167, 24, 152, 11, 24, 51, 37, 66, 9, 24, 31,
174, 202, 212, 49, 152, 18, 96, 155, 208, 119, 146, 45, 97, 48, 56, 28,
194, 90, 224, 204, 144, 232, 176, 36, 96, 126, 187, 43, 83, 12, 121, 129,
209, 96, 197, 35, 2, 54, 176, 249, 92, 208, 204, 145, 188, 41, 170, 180,
71, 16, 36, 96, 126, 187, 43, 83, 19, 0, 145, 129, 100, 209, 15, 43,
135, 55, 6, 238, 180, 194, 90, 17, 229, 115, 21, 168, 251, 140, 131, 162,
217, 166, 93, 22, 4, 140, 31, 91, 166, 55, 25, 202, 192, 111, 20, 171,
207, 39, 192,
};
void huff_enc_init( void )
{
huff_enc_input_pos = 0;
huff_enc_output_pos = 0;
}
int huff_enc_return( void )
{
int i;
_Pragma( "loopbound min 419 max 419" )
for ( i = 0; i < huff_enc_encoded_len; i++ ) {
if ( huff_enc_encoded[ i ] != huff_enc_output[ i ] ) return i + 1;
}
return 0;
}
/*
Input / output functions
*/
void huff_enc_beginning_of_data()
{
huff_enc_input_pos = 0;
}
int huff_enc_end_of_data()
{
return huff_enc_input_pos >= huff_enc_plaintext_len;
}
int huff_enc_read_byte()
{
return huff_enc_plaintext[ huff_enc_input_pos++ ];
}
void huff_enc_write_byte( char ch )
{
huff_enc_output[ huff_enc_output_pos++ ] = ch;
}
void huff_enc_write_bin_val( huff_enc_t_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
*/
{
unsigned char bit_indice;
unsigned char bin_pos = ( bin_val.bits_nb - 1 ) & 7;
unsigned int pos_byte = ( bin_val.bits_nb - 1 ) >> 3;
_Pragma( "loopbound min 1 max 9" )
for ( bit_indice = 1;
bit_indice <= bin_val.bits_nb;
bit_indice++ ) {
/* Watch for the current bit to write */
huff_enc_val_to_write = ( huff_enc_val_to_write << 1 ) |
( ( bin_val.bits[ pos_byte ] >> bin_pos ) & 1 );
/* Move to the next bit to write */
if ( !bin_pos ) {
pos_byte--;
bin_pos = 7;
} else bin_pos--;
if ( huff_enc_byte_nb_to_write == 7 ) {
/* Are already 8 bits written? */
huff_enc_write_byte( huff_enc_val_to_write );
huff_enc_byte_nb_to_write = 0;
huff_enc_val_to_write = 0;
} else /* No, then the next writting will be in the next bit */
huff_enc_byte_nb_to_write++;
}
}
void huff_enc_fill_encoding( void )
/* 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 ( huff_enc_byte_nb_to_write )
huff_enc_write_byte( huff_enc_val_to_write <<
( 8 - huff_enc_byte_nb_to_write ) );
}
void huff_enc_write_header( huff_enc_t_bin_val codes_table[ 257 ] )
/* Returned parameters: None
Action: Writes the header in the stream of codes
Errors: An input/output error could disturb the running of the program
*/
{
unsigned int i, j;
huff_enc_t_bin_val bin_val_to_0;
huff_enc_t_bin_val bin_val_to_1;
huff_enc_t_bin_val bin_val;
/* Is used to send in binary mode via huff_enc_write_bin_val */
*bin_val_to_0.bits = 0;
bin_val_to_0.bits_nb = 1;
*bin_val_to_1.bits = 1;
bin_val_to_1.bits_nb = 1;
_Pragma( "loopbound min 256 max 256" )
for ( i = 0, j = 0; j <= 255; j++ )
if ( codes_table[ j ].bits_nb ) i++;
/* From there, i contains the number of bytes of the several
non 0 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 */
huff_enc_write_bin_val( bin_val_to_0 );
bin_val.bits_nb = 5;
*bin_val.bits = ( unsigned char )( i - 1 );
huff_enc_write_bin_val( bin_val );
bin_val.bits_nb = 8;
_Pragma( "loopbound min 256 max 256" )
for ( j = 0; j <= 255; j++ )
if ( codes_table[ j ].bits_nb ) {
*bin_val.bits = ( unsigned char )j;
huff_enc_write_bin_val( bin_val );
}
} else {
/* Encoding of the appeared bytes with a block of bits */
huff_enc_write_bin_val( bin_val_to_1 );
_Pragma( "loopbound min 256 max 256" )
for ( j = 0; j <= 255; j++ )
if ( codes_table[ j ].bits_nb )
huff_enc_write_bin_val( bin_val_to_1 );
else huff_enc_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 */
_Pragma( "loopbound min 257 max 257" )
for ( i = 0; i <= 256; i++ )
if ( ( j = codes_table[ i ].bits_nb ) != 0 ) {
if ( j < 33 ) {
huff_enc_write_bin_val( bin_val_to_0 );
bin_val.bits_nb = 5;
} else {
huff_enc_write_bin_val( bin_val_to_1 );
bin_val.bits_nb = 8;
}
*bin_val.bits = ( unsigned char )( j - 1 );
huff_enc_write_bin_val( bin_val );
huff_enc_write_bin_val( codes_table[ i ] );
}
}
int huff_enc_weighhuff_enc_t_tree_comp( const void *t1, const void *t2 )
/* 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
*/
{
huff_enc_t_tree *const *tree1 = ( huff_enc_t_tree * const * ) t1;
huff_enc_t_tree *const *tree2 = ( huff_enc_t_tree * const * ) t2;
return ( ( *tree2 )->weight ^ ( *tree1 )->weight )
? ( ( ( *tree2 )->weight < ( *tree1 )->weight ) ? -1 : 1 ) : 0;
}
void huff_enc_swapi( char *ii, char *ij, unsigned long es )
{
char *i, *j, c;
i = ( char * )ii;
j = ( char * )ij;
_Pragma( "loopbound min 8 max 8" )
do {
c = *i;
*i++ = *j;
*j++ = c;
es -= sizeof( char );
} while ( es != 0 );
}
char *huff_enc_pivot( char *a, unsigned long n, unsigned long es )
{
long j;
char *pi, *pj, *pk;
j = n / 6 * es;
pi = a + j; /* 1/6 */
j += j;
pj = pi + j; /* 1/2 */
pk = pj + j; /* 5/6 */
if ( huff_enc_weighhuff_enc_t_tree_comp( pi, pj ) < 0 ) {
if ( huff_enc_weighhuff_enc_t_tree_comp( pi, pk ) < 0 ) {
if ( huff_enc_weighhuff_enc_t_tree_comp( pj, pk ) < 0 )
return pj;
return pk;
}
return pi;
}
if ( huff_enc_weighhuff_enc_t_tree_comp( pj, pk ) < 0 ) {
if ( huff_enc_weighhuff_enc_t_tree_comp( pi, pk ) < 0 )
return pi;
return pk;
}
return pj;
}
void huff_enc_qsort( char *a, unsigned long n, unsigned long es ) //wird insgesamt 648 ausgeführt (rekursion)
{
unsigned long j;
char *pi, *pj, *pn;
unsigned int flowfactdummy = 0;
_Pragma( "loopbound min 0 max 7" )
while ( n > 1 ) {
if ( n > 10 )
pi = huff_enc_pivot( a, n, es );
else
pi = a + ( n >> 1 ) * es;
huff_enc_swapi( a, pi, es );
pi = a;
pn = a + n * es;
pj = pn;
_Pragma( "loopbound min 0 max 109" )
while ( 1 ) {
/* wcc note: this assignment expression was added to avoid assignment of
multiple loop bound annotations to same loop (cf. Ticket #0002323). */
flowfactdummy++;
_Pragma( "loopbound min 1 max 19" )
do {
pi += es;
} while ( pi < pn && huff_enc_weighhuff_enc_t_tree_comp( pi, a ) < 0 );
_Pragma( "loopbound min 1 max 25" )
do {
pj -= es;
} while ( pj > a && huff_enc_weighhuff_enc_t_tree_comp( pj, a ) > 0 );
if ( pj < pi )
break;
huff_enc_swapi( pi, pj, es );
}
huff_enc_swapi( a, pj, es );
j = ( pj - a ) / es;
n = n - j - 1;
if ( j >= n ) {
huff_enc_qsort( a, j, es );
a += ( j + 1 ) * es;
} else {
huff_enc_qsort( a + ( j + 1 )*es, n, es );
n = j;
}
}
}
huff_enc_t_tree *huff_enc_build_tree_encoding( huff_enc_t_tree heap[ 514 ] )
/* Returned parameters: Returns a tree of encoding
Action: Generates an Huffman encoding tree based on the data from
the stream to compress
Errors: None
*/
{
unsigned int i;
unsigned int heap_top = 0;
huff_enc_t_tree *occurrences_table[ 257 ];
huff_enc_t_tree *ptr_fictive_tree;
/* Sets up the occurrences number of all bytes to 0 */
_Pragma( "loopbound min 257 max 257" )
for ( i = 0; i <= 256; i++ ) {
occurrences_table[ i ] = &heap[ heap_top++ ];
occurrences_table[ i ]->byte = i;
occurrences_table[ i ]->weight = 0;
occurrences_table[ i ]->left_ptr = 0;
occurrences_table[ i ]->right_ptr = 0;
}
/* Valids the occurrences of 'occurrences_table' with regard to the data to
compress */
if ( !huff_enc_end_of_data() ) {
_Pragma( "loopbound min 600 max 600" )
while ( !huff_enc_end_of_data() ) {
i = huff_enc_read_byte();
occurrences_table[ i ]->weight++;
}
occurrences_table[ 256 ]->weight = 1;
/* Sorts the occurrences table depending on the weight of each character */
huff_enc_qsort( ( char * )occurrences_table, 257, sizeof( huff_enc_t_tree * ) );
_Pragma( "loopbound min 218 max 218" )
for ( i = 256; ( i != 0 ) && ( !occurrences_table[ i ]->weight ); i-- )
;
i++;
/* From there, 'i' gives the number of different bytes with a 0 occurrence
in the stream to compress */
_Pragma( "loopbound min 38 max 38" )
while ( i > 0 ) {
/* Looks up (i+1)/2 times the occurrence table to link the nodes in an
unique tree */
ptr_fictive_tree = &heap[ heap_top++ ];
ptr_fictive_tree->byte = 257;
ptr_fictive_tree->weight = occurrences_table[ --i ]->weight;
ptr_fictive_tree->left_ptr = occurrences_table[ i ];
if ( i ) {
i--;
ptr_fictive_tree->weight += occurrences_table[ i ]->weight;
ptr_fictive_tree->right_ptr = occurrences_table[ i ];
} else ptr_fictive_tree->right_ptr = 0;
occurrences_table[ i ] = ptr_fictive_tree;
//qsort( ( char * )occurrences_table, i + 1, sizeof( *huff_enc_t_tree ),
//huff_enc_weighhuff_enc_t_tree_comp );
huff_enc_qsort( ( char * )occurrences_table, i + 1,
sizeof( huff_enc_t_tree * ) );
if ( i ) /* Is there an other node in the occurrence tables? */
i++; /* Yes, then takes care to the fictive node */
}
}
return ( *occurrences_table );
}
void huff_enc_encode_codes_table( huff_enc_t_tree *tree,
huff_enc_t_bin_val codes_table[ 257 ],
huff_enc_t_bin_val *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
*/
{
unsigned int i;
huff_enc_t_bin_val tmp_code_val;
if ( tree->byte == 257 ) {
if ( tree->left_ptr != 0 )
/* The sub-trees on left begin with an bit set to 1 */
{
tmp_code_val = *code_val;
_Pragma( "loopbound min 31 max 31" )
for ( i = 31; i > 0; i-- )
code_val->bits[ i ] = ( code_val->bits[ i ] << 1 ) |
( code_val->bits[ i - 1 ] >> 7 );
*code_val->bits = ( *code_val->bits << 1 ) | 1;
code_val->bits_nb++;
huff_enc_encode_codes_table( tree->left_ptr, codes_table, code_val );
*code_val = tmp_code_val;
};
if ( tree->right_ptr != 0 )
/* The sub-trees on right begin with an bit set to 0 */
{
tmp_code_val = *code_val;
_Pragma( "loopbound min 31 max 31" )
for ( i = 31; i > 0; i-- )
code_val->bits[ i ] = ( code_val->bits[ i ] << 1 ) |
( code_val->bits[ i - 1 ] >> 7 );
*code_val->bits <<= 1;
code_val->bits_nb++;
huff_enc_encode_codes_table( tree->right_ptr, codes_table, code_val );
*code_val = tmp_code_val;
};
} else codes_table[ tree->byte ] = *code_val;
}
void huff_enc_create_codes_table( huff_enc_t_tree *tree,
huff_enc_t_bin_val codes_table[ 257 ] )
/* 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
*/
{
unsigned int i, j;
huff_enc_t_bin_val code_val;
_Pragma( "loopbound min 32 max 32" )
for ( i = 0; i < 32; i++ )
code_val.bits[ i ] = 0;
code_val.bits_nb = 0;
_Pragma( "loopbound min 257 max 257" )
for ( j = 0; j < 257; j++ ) {
_Pragma( "loopbound min 32 max 32" )
for ( i = 0; i < 32; i++ )
codes_table[ j ].bits[ i ] = 0;
codes_table[ j ].bits_nb = 0;
}
_Pragma( "marker call_encode" )
_Pragma( "flowrestriction 1*huff_enc_encode_codes_table <= 77*call_encode" )
huff_enc_encode_codes_table( tree, codes_table, &code_val );
}
void _Pragma( "entrypoint" ) huff_enc_main()
/* Returned parameters: None
Action: Compresses with Huffman method all bytes read by the function
'huff_enc_read_byte'
Errors: None
*/
{
huff_enc_t_tree *tree;
huff_enc_t_tree heap[ 514 ];
huff_enc_t_bin_val encoding_table[ 257 ];
unsigned char byte_read;
if ( !huff_enc_end_of_data() ) {
/* Generates only whether there are data */
tree = huff_enc_build_tree_encoding( heap );
/* Creation of the best adapted tree */
huff_enc_create_codes_table( tree, encoding_table );
/* Obtains the binary encoding in an array to speed up the accesses */
huff_enc_write_header( encoding_table );
/* Writes the defintion of the encoding */
huff_enc_beginning_of_data(); /* Real compression of the data */
_Pragma( "loopbound min 600 max 600" )
while ( !huff_enc_end_of_data() ) {
byte_read = huff_enc_read_byte();
huff_enc_write_bin_val( encoding_table[ byte_read ] );
}
huff_enc_write_bin_val( encoding_table[ 256 ] );
/* Code of the end of encoding */
huff_enc_fill_encoding();
/* Fills the last byte before closing file, if any */
}
}
int main( void )
{
huff_enc_init();
huff_enc_main();
return ( huff_enc_return() );
}