mirror of
https://github.com/kevinbentley/Descent3.git
synced 2026-04-03 17:00:03 -04:00
268 lines
6.2 KiB
C++
268 lines
6.2 KiB
C++
/*
|
|
* $Logfile: /DescentIII/Main/czip/HuffmanBasic.cpp $
|
|
* $Revision: 2 $
|
|
* $Date: 8/27/98 3:26p $
|
|
* $Author: Jeff $
|
|
*
|
|
* Basic Huffman compression functions
|
|
*
|
|
* $Log: /DescentIII/Main/czip/HuffmanBasic.cpp $
|
|
*
|
|
* 2 8/27/98 3:26p Jeff
|
|
* intial creation
|
|
*
|
|
* 1 8/27/98 3:26p Jeff
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "CZip.h"
|
|
|
|
#define END_OF_STREAM 256
|
|
|
|
int CZip::hb_CompressFile(tVirtualFile *input,BITFILE *output)
|
|
{
|
|
ulong *counts;
|
|
tH0Node *nodes;
|
|
tH0Code *codes;
|
|
int root_node;
|
|
|
|
int original_pos = VFtell(output->file);
|
|
|
|
counts = (ulong *) malloc(256*sizeof(ulong));
|
|
if(!counts)
|
|
return -1;
|
|
if((nodes = (tH0Node *) malloc(514*sizeof(tH0Node)))==NULL){
|
|
free(counts);
|
|
return -1;
|
|
}
|
|
if((codes = (tH0Code *) malloc( 257*sizeof(tH0Code)))==NULL){
|
|
free(counts);
|
|
free(nodes);
|
|
return -1;
|
|
}
|
|
|
|
memset(counts,0,256*sizeof(ulong));
|
|
memset(nodes,0,514*sizeof(tH0Node));
|
|
memset(codes,0,257*sizeof(tH0Code));
|
|
|
|
hb_count_bytes( input, counts );
|
|
hb_scale_counts( counts, nodes );
|
|
hb_output_counts( output, nodes );
|
|
root_node = hb_build_tree( nodes );
|
|
hb_convert_tree_to_code( nodes, codes, 0, 0, root_node );
|
|
hb_compress_data( input, output, codes );
|
|
free( counts );
|
|
free( nodes );
|
|
free( codes );
|
|
FlushOutputBitFile(output);
|
|
|
|
int compsize = VFtell(output->file) - original_pos;
|
|
return compsize;
|
|
}
|
|
|
|
bool CZip::hb_ExpandFile(BITFILE *input,tVirtualFile *output)
|
|
{
|
|
tH0Node *nodes;
|
|
int root_node;
|
|
|
|
if ((nodes = (tH0Node *) malloc( 514*sizeof(tH0Node)))==NULL)
|
|
return false;
|
|
memset(nodes,0,sizeof(tH0Node)*514);
|
|
hb_input_counts( input, nodes );
|
|
root_node = hb_build_tree( nodes );
|
|
hb_expand_data( input, output, nodes, root_node );
|
|
free(nodes);
|
|
return true;
|
|
}
|
|
|
|
void CZip::hb_output_counts(BITFILE *output,tH0Node *nodes)
|
|
{
|
|
int first,last,next,i;
|
|
|
|
first = 0;
|
|
while ( first < 255 && nodes[ first ].count == 0 )
|
|
first++;
|
|
|
|
for ( ; first < 256 ; first = next ) {
|
|
last = first + 1;
|
|
for ( ; ; ) {
|
|
for ( ; last < 256 ; last++ )
|
|
if ( nodes[ last ].count == 0 )
|
|
break;
|
|
last--;
|
|
for ( next = last + 1; next < 256 ; next++ )
|
|
if ( nodes[ next ].count != 0 )
|
|
break;
|
|
if ( next > 255 )
|
|
break;
|
|
if ( ( next - last ) > 3 )
|
|
break;
|
|
last = next;
|
|
}
|
|
|
|
if ( VFputc( first, output->file ) != first ){
|
|
//fatal error
|
|
}
|
|
if ( VFputc( last, output->file ) != last ){
|
|
//fatal error
|
|
}
|
|
for ( i = first ; i <= last ; i++ ) {
|
|
if ( VFputc( nodes[ i ].count, output->file ) !=(int) nodes[ i ].count ){
|
|
//fatal error
|
|
}
|
|
}
|
|
}
|
|
if ( VFputc( 0, output->file ) != 0 ){
|
|
//fatal error
|
|
}
|
|
}
|
|
|
|
void CZip::hb_input_counts(BITFILE *input,tH0Node *nodes)
|
|
{
|
|
int first;
|
|
int last;
|
|
int i;
|
|
int c;
|
|
|
|
for ( i = 0 ; i < 256 ; i++ )
|
|
nodes[ i ].count = 0;
|
|
if ( ( first = VFgetc( input->file ) ) == EOF ){
|
|
// fatal_error( "Error reading byte counts\n" );
|
|
}
|
|
if ( ( last = VFgetc( input->file ) ) == EOF ){
|
|
//fatal_error( "Error reading byte counts\n" );
|
|
}
|
|
for ( ; ; ) {
|
|
for ( i = first ; i <= last ; i++ )
|
|
if ( ( c = VFgetc( input->file ) ) == EOF ){
|
|
// fatal_error( "Error reading byte counts\n" );
|
|
} else
|
|
nodes[ i ].count = (unsigned int) c;
|
|
if ( ( first = VFgetc( input->file ) ) == EOF ){
|
|
// fatal_error( "Error reading byte counts\n" );
|
|
}
|
|
if ( first == 0 )
|
|
break;
|
|
if ( ( last = VFgetc( input->file ) ) == EOF ){
|
|
// fatal_error( "Error reading byte counts\n" );
|
|
}
|
|
}
|
|
nodes[ END_OF_STREAM ].count = 1;
|
|
}
|
|
|
|
void CZip::hb_count_bytes(tVirtualFile *input,ulong *counts)
|
|
{
|
|
long input_marker;
|
|
int c;
|
|
|
|
input_marker = VFtell( input );
|
|
while ( ( c = VFgetc( input )) != EOF )
|
|
counts[ c ]++;
|
|
VFseek( input, input_marker, SEEK_SET );
|
|
}
|
|
|
|
void CZip::hb_scale_counts(ulong *counts,tH0Node *nodes)
|
|
{
|
|
ulong max_count;
|
|
int i;
|
|
|
|
max_count = 0;
|
|
for ( i = 0 ; i < 256 ; i++ )
|
|
if ( counts[ i ] > max_count )
|
|
max_count = counts[ i ];
|
|
if ( max_count == 0 ) {
|
|
counts[ 0 ] = 1;
|
|
max_count = 1;
|
|
}
|
|
max_count = max_count / 255;
|
|
max_count = max_count + 1;
|
|
for ( i = 0 ; i < 256 ; i++ ) {
|
|
nodes[ i ].count = (uint) ( counts[ i ] / max_count );
|
|
if ( nodes[ i ].count == 0 && counts[ i ] != 0 )
|
|
nodes[ i ].count = 1;
|
|
}
|
|
nodes[ END_OF_STREAM ].count = 1;
|
|
}
|
|
|
|
int CZip::hb_build_tree(tH0Node *nodes)
|
|
{
|
|
int next_free;
|
|
int i;
|
|
int min_1;
|
|
int min_2;
|
|
|
|
nodes[ 513 ].count = 0xffff;
|
|
for ( next_free = END_OF_STREAM + 1 ; ; next_free++ ) {
|
|
min_1 = 513;
|
|
min_2 = 513;
|
|
for ( i = 0 ; i < next_free ; i++ )
|
|
if ( nodes[ i ].count != 0 ) {
|
|
if ( nodes[ i ].count < nodes[ min_1 ].count ) {
|
|
min_2 = min_1;
|
|
min_1 = i;
|
|
} else if ( nodes[ i ].count < nodes[ min_2 ].count )
|
|
min_2 = i;
|
|
}
|
|
if ( min_2 == 513 )
|
|
break;
|
|
|
|
nodes[ next_free ].count = nodes[ min_1 ].count+ nodes[ min_2 ].count;
|
|
nodes[ min_1 ].saved_count = nodes[ min_1 ].count;
|
|
nodes[ min_1 ].count = 0;
|
|
nodes[ min_2 ].saved_count = nodes[ min_2 ].count;
|
|
nodes[ min_2 ].count = 0;
|
|
nodes[ next_free ].child0 = min_1;
|
|
nodes[ next_free ].child1 = min_2;
|
|
}
|
|
next_free--;
|
|
nodes[ next_free ].saved_count = nodes[ next_free ].count;
|
|
return( next_free );
|
|
}
|
|
|
|
void CZip::hb_convert_tree_to_code(tH0Node *nodes,tH0Code *codes,uint code_so_far,int bits,int node)
|
|
{
|
|
if ( node <= END_OF_STREAM ) {
|
|
codes[ node ].code = code_so_far;
|
|
codes[ node ].code_bits = bits;
|
|
return;
|
|
}
|
|
|
|
code_so_far <<= 1;
|
|
bits++;
|
|
hb_convert_tree_to_code( nodes, codes, code_so_far, bits, nodes[ node ].child0 );
|
|
hb_convert_tree_to_code( nodes, codes, code_so_far | 1,bits, nodes[ node ].child1 );
|
|
}
|
|
|
|
void CZip::hb_compress_data(tVirtualFile *input,BITFILE *output,tH0Code *codes)
|
|
{
|
|
int c;
|
|
while((c=VFgetc(input))!=EOF)
|
|
OutputBits(output,(ulong)codes[c].code,codes[c].code_bits);
|
|
OutputBits(output,(ulong)codes[END_OF_STREAM].code,codes[END_OF_STREAM].code_bits);
|
|
}
|
|
|
|
void CZip::hb_expand_data(BITFILE *input,tVirtualFile *output,tH0Node *nodes,int root_node)
|
|
{
|
|
int node;
|
|
for(;;){
|
|
node = root_node;
|
|
do{
|
|
if(InputBit(input))
|
|
node = nodes[node].child1;
|
|
else
|
|
node = nodes[node].child0;
|
|
}while(node>END_OF_STREAM);
|
|
if(node==END_OF_STREAM)
|
|
break;
|
|
if((VFputc(node,output))!=node){
|
|
//fatal error
|
|
}
|
|
}
|
|
} |