Descent3/czip/HuffmanAdapt.cpp

276 lines
7.3 KiB
C++
Raw Normal View History

2024-04-16 03:43:29 +00:00
/*
2024-04-16 18:56:40 +00:00
* $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 $
*
2024-04-16 03:43:29 +00:00
* 2 8/27/98 3:26p Jeff
* intial creation
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 1 8/27/98 3:26p Jeff
2024-04-16 18:56:40 +00:00
*
* $NoKeywords: $
*/
2024-04-16 03:43:29 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "CZip.h"
2024-04-16 18:56:40 +00:00
#define END_OF_STREAM 256
#define ESCAPE 257
#define ROOT_NODE 0
#define MAX_WEIGHT 0x8000
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// 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);
2024-04-16 03:43:29 +00:00
/////////////////////////////////////////////
2024-04-16 18:56:40 +00:00
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;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void CZip::ha_PrepareCompress(void) {
ok_to_raw_write = true;
ha_InitializeTree(&Tree);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void CZip::ha_WriteRawByte(ubyte data, BITFILE *output) {
if (!ok_to_raw_write)
return;
ha_EncodeSymbol(&Tree, data, output);
ha_UpdateModel(&Tree, data);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void CZip::ha_CloseRawCompress(BITFILE *output) {
ha_EncodeSymbol(&Tree, END_OF_STREAM, output);
FlushOutputBitFile(output);
ok_to_raw_write = false;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
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);
}
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void CZip::ha_PrepareDecompress(void) {
ok_to_raw_read = true;
ha_InitializeTree(&Tree);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
bool CZip::ha_ReadRawByte(ubyte *data, BITFILE *input) {
if (!ok_to_raw_read)
return false;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
int c;
c = ha_DecodeSymbol(&Tree, input);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (c == END_OF_STREAM) {
ok_to_raw_read = false;
return false;
}
ha_UpdateModel(&Tree, c);
*data = c;
return true;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
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;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
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);
}
}
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
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;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
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;
}
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
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;
}
}
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
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;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void CZip::ha_add_new_node(tHATree *tree, int c) {
int lightest_node, new_node, zero_weight_node;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
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;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
tree->nodes[new_node] = tree->nodes[lightest_node];
tree->nodes[new_node].parent = lightest_node;
tree->leaf[tree->nodes[new_node].child] = new_node;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
tree->nodes[lightest_node].child = new_node;
tree->nodes[lightest_node].child_is_leaf = false;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
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;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// 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);