home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CDPD Public Domain Collection for CDTV 2
/
CDPD_II_2352.bin
/
scope
/
176-200
/
scopedisk192
/
unzipv3.1
/
unimplod.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-27
|
8KB
|
297 lines
/* ------------------------------------------------------------- */
/*
* Imploding
* ---------
*
* The Imploding algorithm is actually a combination of two distinct
* algorithms. The first algorithm compresses repeated byte sequences
* using a sliding dictionary. The second algorithm is used to compress
* the encoding of the sliding dictionary ouput, using multiple
* Shannon-Fano trees.
*
*/
sf_tree lit_tree;
sf_tree length_tree;
sf_tree distance_tree;
/* s-f storage is shared with that used by other comp. methods */
sf_node *lit_nodes = (sf_node *) followers; /* 2*LITVALS nodes */
sf_node *length_nodes = (sf_node *) suffix_of; /* 2*LENVALS nodes */
sf_node *distance_nodes = (sf_node *) stack; /* 2*DISTVALS nodes */
boolean lit_tree_present;
boolean eightK_dictionary;
int minimum_match_length;
int dict_bits;
#ifdef __TURBOC__
/* v2.0b More local prototypes */
void ReadLengths(sf_tree *tree);
void SortLengths(sf_tree *tree);
void GenerateTrees(sf_tree *tree, sf_node *nodes);
void LoadTree(sf_tree *tree, int treesize, sf_node *nodes);
void LoadTrees(void);
void ReadTree(register sf_node *nodes, int *dest);
#endif
void SortLengths(tree)
sf_tree *tree;
/* Sort the Bit Lengths in ascending order, while retaining the order
of the original lengths stored in the file */
{
register sf_entry *ejm1; /* entry[j - 1] */
register int j;
register sf_entry *entry;
register int i;
sf_entry tmp;
int entries;
unsigned a, b;
entry = &tree->entry[0];
entries = tree->entries;
for (i = 0; ++i < entries; ) {
tmp = entry[i];
b = tmp.BitLength;
j = i;
while ((j > 0)
&& ((a = (ejm1 = &entry[j - 1])->BitLength) >= b)) {
if ((a == b) && (ejm1->Value <= tmp.Value))
break;
*(ejm1 + 1) = *ejm1; /* entry[j] = entry[j - 1] */
--j;
}
entry[j] = tmp;
}
}
/* ----------------------------------------------------------- */
void ReadLengths(tree)
sf_tree *tree;
{
int treeBytes;
int i;
int num, len;
/* get number of bytes in compressed tree */
READBIT(8,treeBytes);
treeBytes++;
i = 0;
tree->MaxLength = 0;
/* High 4 bits: Number of values at this bit length + 1. (1 - 16)
* Low 4 bits: Bit Length needed to represent value + 1. (1 - 16)
*/
while (treeBytes > 0) {
READBIT(4,len); len++;
READBIT(4,num); num++;
while (num > 0) {
if (len > tree->MaxLength)
tree->MaxLength = len;
tree->entry[i].BitLength = len;
tree->entry[i].Value = i;
i++;
num--;
}
treeBytes--;
}
}
/* ----------------------------------------------------------- */
void GenerateTrees(tree, nodes)
sf_tree *tree;
sf_node *nodes;
/* Generate the Shannon-Fano trees */
{
int codelen, i, j, lvlstart, next, parents;
i = tree->entries - 1; /* either 255 or 63 */
lvlstart = next = 1;
/* believe it or not, there may be a 1-bit code */
for (codelen = tree->MaxLength; codelen >= 1; --codelen) {
/* create leaf nodes at level <codelen> */
while ((i >= 0) && (tree->entry[i].BitLength == codelen)) {
nodes[next].left = 0;
nodes[next].right = tree->entry[i].Value;
++next;
--i;
}
/* create parent nodes for all nodes at level <codelen>,
but don't create the root node here */
parents = next;
if (codelen > 1) {
for (j = lvlstart; j <= parents-2; j += 2) {
nodes[next].left = j;
nodes[next].right = j + 1;
++next;
}
}
lvlstart = parents;
}
/* create root node */
nodes[0].left = next - 2;
nodes[0].right = next - 1;
}
/* ----------------------------------------------------------- */
void LoadTree(tree, treesize, nodes)
sf_tree *tree;
int treesize;
sf_node *nodes;
/* allocate and load a shannon-fano tree from the compressed file */
{
tree->entries = treesize;
ReadLengths(tree);
SortLengths(tree);
GenerateTrees(tree, nodes);
}
/* ----------------------------------------------------------- */
void LoadTrees()
{
eightK_dictionary = (lrec.general_purpose_bit_flag & 0x02) != 0; /* bit 1 */
lit_tree_present = (lrec.general_purpose_bit_flag & 0x04) != 0; /* bit 2 */
if (eightK_dictionary)
dict_bits = 7;
else
dict_bits = 6;
if (lit_tree_present) {
minimum_match_length = 3;
LoadTree(&lit_tree,256,lit_nodes);
}
else
minimum_match_length = 2;
LoadTree(&length_tree,64,length_nodes);
LoadTree(&distance_tree,64,distance_nodes);
}
/* ----------------------------------------------------------- */
#ifndef ASM
void ReadTree(nodes, dest)
register sf_node *nodes;
int *dest;
/* read next byte using a shannon-fano tree */
{
register int cur;
register int left;
UWORD b;
for (cur = 0; ; ) {
if ((left = nodes[cur].left) == 0) {
*dest = nodes[cur].right;
return;
}
READBIT(1, b);
cur = (b ? nodes[cur].right : left);
}
}
#endif
/* ----------------------------------------------------------- */
void unImplode()
/* expand imploded data */
{
register int srcix;
register int Length;
register int limit;
int lout;
int Distance;
LoadTrees();
#ifdef DEBUG
printf("\n");
#endif
while ((!zipeof) && ((outpos+outcnt) < ucsize)) {
READBIT(1,lout);
if (lout != 0) { /* encoded data is literal data */
if (lit_tree_present) /* use Literal Shannon-Fano tree */ {
ReadTree(lit_nodes,&lout);
#ifdef DEBUG
printf("lit=%d\n", lout);
#endif
}
else
READBIT(8,lout);
OUTB(lout);
}
else { /* encoded data is sliding dictionary match */
READBIT(dict_bits,Distance);
ReadTree(distance_nodes,&lout);
#ifdef DEBUG
printf("d=%5d (%2d,%3d)", (lout << dict_bits) | Distance, lout,
Distance);
#endif
Distance |= (lout << dict_bits);
/* using the Distance Shannon-Fano tree, read and decode the
upper 6 bits of the Distance value */
ReadTree(length_nodes,&lout);
Length = lout;
#ifdef DEBUG
printf("\tl=%3d\n", Length);
#endif
/* using the Length Shannon-Fano tree, read and decode the
Length value */
if (Length == 63) {
READBIT(8,lout);
Length += lout;
}
Length += minimum_match_length;
/* move backwards Distance+1 bytes in the output stream, and copy
Length characters from this position to the output stream.
(if this position is before the start of the output stream,
then assume that all the data before the start of the output
stream is filled with zeros. Requires initializing outbuf
for each file.) */
srcix = (outcnt - (Distance + 1)) & (OUTBUFSIZ-1);
limit = OUTBUFSIZ - Length;
if ((srcix <= limit) && (outcnt < limit)) {
zmemcpy(outptr, &outbuf[srcix], Length);
outptr += Length;
outcnt += Length;
}
else {
while (Length--) {
OUTB(outbuf[srcix++]);
srcix &= OUTBUFSIZ-1;
}
}
}
}
}