Files
Descent3/czip/HuffmanAdapt.cpp
Kevin Bentley df209742fc Initial import
2024-04-15 21:43:29 -06:00

298 lines
6.9 KiB
C++

/*
* $Logfile: /DescentIII/Main/czip/HuffmanAdapt.cpp $
* $Revision: 2 $
* $Date: 8/27/98 3:26p $
* $Author: Jeff $
*
* Huffman-Adaptive compression functions
*
* $Log: /DescentIII/Main/czip/HuffmanAdapt.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
#define ESCAPE 257
#define ROOT_NODE 0
#define MAX_WEIGHT 0x8000
//void calculate_rows(tHATree *tree,int node,int level);
//int calculate_columns(tHATree *tree,int node,int starting_guess);
//int find_minimum_column(tHATree *tree,int node,int max_row);
//void rescale_columns(int factor);
/////////////////////////////////////////////
int CZip::ha_CompressFile(tVirtualFile *input,BITFILE *output)
{
int original_pos = VFtell(output->file);
int c;
ha_InitializeTree(&Tree);
while((c=VFgetc(input))!=EOF){
ha_EncodeSymbol(&Tree,c,output);
ha_UpdateModel(&Tree,c);
}
ha_EncodeSymbol(&Tree,END_OF_STREAM,output);
FlushOutputBitFile(output);
int size = VFtell(output->file) - original_pos;
return size;
}
void CZip::ha_PrepareCompress(void)
{
ok_to_raw_write = true;
ha_InitializeTree(&Tree);
}
void CZip::ha_WriteRawByte(ubyte data,BITFILE *output)
{
if(!ok_to_raw_write)
return;
ha_EncodeSymbol(&Tree,data,output);
ha_UpdateModel(&Tree,data);
}
void CZip::ha_CloseRawCompress(BITFILE *output)
{
ha_EncodeSymbol(&Tree,END_OF_STREAM,output);
FlushOutputBitFile(output);
ok_to_raw_write = false;
}
void CZip::ha_ExpandFile(BITFILE *input,tVirtualFile *output)
{
int c;
ha_InitializeTree(&Tree);
while((c=ha_DecodeSymbol(&Tree,input))!=END_OF_STREAM){
if(VFputc(c,output)==EOF){
//fatal error
}
ha_UpdateModel(&Tree,c);
}
}
void CZip::ha_PrepareDecompress(void)
{
ok_to_raw_read = true;
ha_InitializeTree(&Tree);
}
bool CZip::ha_ReadRawByte(ubyte *data,BITFILE *input)
{
if(!ok_to_raw_read)
return false;
int c;
c = ha_DecodeSymbol(&Tree,input);
if(c==END_OF_STREAM){
ok_to_raw_read =false;
return false;
}
ha_UpdateModel(&Tree,c);
*data = c;
return true;
}
void CZip::ha_CloseRawDecompress(void)
{
ok_to_raw_read = false;
}
void CZip::ha_InitializeTree(tHATree *tree)
{
int i;
tree->nodes[ROOT_NODE].child = ROOT_NODE + 1;
tree->nodes[ROOT_NODE].child_is_leaf = false;
tree->nodes[ROOT_NODE].weight = 2;
tree->nodes[ROOT_NODE].parent = -1;
tree->nodes[ROOT_NODE+1].child = END_OF_STREAM;
tree->nodes[ROOT_NODE+1].child_is_leaf = true;
tree->nodes[ROOT_NODE+1].weight = 1;
tree->nodes[ROOT_NODE+1].parent = ROOT_NODE;
tree->leaf[END_OF_STREAM] = ROOT_NODE+1;
tree->nodes[ROOT_NODE+2].child = ESCAPE;
tree->nodes[ROOT_NODE+2].child_is_leaf = true;
tree->nodes[ROOT_NODE+2].weight = 1;
tree->nodes[ROOT_NODE+2].parent = ROOT_NODE;
tree->leaf[ESCAPE] = ROOT_NODE+2;
tree->next_free_node = ROOT_NODE+3;
for(i=0;i<END_OF_STREAM;i++)
tree->leaf[i] = -1;
}
void CZip::ha_EncodeSymbol(tHATree *tree,uint c,BITFILE *output)
{
ulong code;
ulong current_bit;
int code_size;
int current_node;
code = 0;
current_bit = 1;
code_size = 0;
current_node = tree->leaf[c];
if(current_node==-1)
current_node = tree->leaf[ESCAPE];
while(current_node!=ROOT_NODE){
if((current_node&1)==0)
code |= current_bit;
current_bit <<= 1;
code_size++;
current_node = tree->nodes[current_node].parent;
}
OutputBits(output,code,code_size);
if(tree->leaf[c]==-1){
OutputBits(output,(ulong)c,8);
ha_add_new_node(tree,c);
}
}
int CZip::ha_DecodeSymbol(tHATree *tree,BITFILE *input)
{
int current_node;
int c;
current_node = ROOT_NODE;
while(!tree->nodes[current_node].child_is_leaf){
current_node = tree->nodes[current_node].child;
current_node += InputBit(input);
}
c = tree->nodes[current_node].child;
if(c==ESCAPE){
c = (int)InputBits(input,8);
ha_add_new_node(tree,c);
}
return c;
}
void CZip::ha_UpdateModel(tHATree *tree,int c)
{
int current_node;
int new_node;
if(tree->nodes[ROOT_NODE].weight==MAX_WEIGHT)
ha_RebuildTree(tree);
current_node = tree->leaf[c];
while(current_node!=-1){
tree->nodes[current_node].weight++;
for(new_node = current_node;new_node>ROOT_NODE;new_node--){
if(tree->nodes[new_node-1].weight >= tree->nodes[current_node].weight)
break;
}
if(current_node!=new_node){
ha_swap_nodes(tree,current_node,new_node);
current_node = new_node;
}
current_node = tree->nodes[current_node].parent;
}
}
void CZip::ha_RebuildTree(tHATree *tree)
{
int i,j,k;
uint weight;
j = tree->next_free_node - 1;
for(i=j;i>=ROOT_NODE;i--){
if(tree->nodes[i].child_is_leaf){
tree->nodes[j] = tree->nodes[i];
tree->nodes[j].weight = (tree->nodes[j].weight+1)/2;
j--;
}
}
for(i=tree->next_free_node-2;j>=ROOT_NODE;i-=2,j--){
k = i+1;
tree->nodes[j].weight = tree->nodes[i].weight+tree->nodes[k].weight;
weight = tree->nodes[j].weight;
tree->nodes[j].child_is_leaf = false;
for(k=j+1;weight<tree->nodes[k].weight;k++);
k--;
memmove(&tree->nodes[j],&tree->nodes[j+1],(k-j)*sizeof(tHANode));
tree->nodes[k].weight = weight;
tree->nodes[k].child = i;
tree->nodes[k].child_is_leaf = false;
}
for(i=tree->next_free_node-1;i>=ROOT_NODE;i--){
if(tree->nodes[i].child_is_leaf){
k = tree->nodes[i].child;
tree->leaf[k] = i;
}else{
k = tree->nodes[i].child;
tree->nodes[k].parent = tree->nodes[k+1].parent = i;
}
}
}
void CZip::ha_swap_nodes(tHATree *tree,int i,int j)
{
tHANode temp;
if(tree->nodes[i].child_is_leaf)
tree->leaf[tree->nodes[i].child] = j;
else{
tree->nodes[tree->nodes[i].child].parent = j;
tree->nodes[tree->nodes[i].child+1].parent = j;
}
if(tree->nodes[j].child_is_leaf)
tree->leaf[tree->nodes[j].child] = i;
else{
tree->nodes[tree->nodes[j].child].parent = i;
tree->nodes[tree->nodes[j].child+1].parent = i;
}
temp = tree->nodes[i];
tree->nodes[i] = tree->nodes[j];
tree->nodes[i].parent = temp.parent;
temp.parent = tree->nodes[j].parent;
tree->nodes[j] = temp;
}
void CZip::ha_add_new_node(tHATree *tree,int c)
{
int lightest_node,new_node,zero_weight_node;
lightest_node = tree->next_free_node - 1;
new_node = tree->next_free_node;
zero_weight_node = tree->next_free_node + 1;
tree->next_free_node += 2;
tree->nodes[new_node] = tree->nodes[lightest_node];
tree->nodes[new_node].parent = lightest_node;
tree->leaf[tree->nodes[new_node].child] = new_node;
tree->nodes[lightest_node].child = new_node;
tree->nodes[lightest_node].child_is_leaf = false;
tree->nodes[zero_weight_node].child = c;
tree->nodes[zero_weight_node].child_is_leaf = true;
tree->nodes[zero_weight_node].weight = 0;
tree->nodes[zero_weight_node].parent = lightest_node;
tree->leaf[c] = zero_weight_node;
}
//void calculate_rows(tHATree *tree,int node,int level);
//int calculate_columns(tHATree *tree,int node,int starting_guess);
//int find_minimum_column(tHATree *tree,int node,int max_row);
//void rescale_columns(int factor);