home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windoware
/
WINDOWARE_1_6.iso
/
source
/
wzun11sr
/
unimplod.c
< prev
next >
Wrap
Text File
|
1991-09-27
|
10KB
|
380 lines
/*---------------------------------------------------------------------------
unimplod.c
The Imploding algorithm is actually a combination of two distinct algor-
ithms. 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.
---------------------------------------------------------------------------*/
#include "unzip.h"
/***********************/
/* UnImplode Defines */
/***********************/
#define LITVALS 256
#define DISTVALS 64
#define LENVALS 64
#define MAXSF LITVALS
/************************/
/* UnImplode Typedefs */
/************************/
typedef struct sf_entry {
byte Value;
byte BitLength;
} sf_entry;
typedef struct sf_tree { /* a shannon-fano "tree" (table) */
sf_entry entry[MAXSF];
int entries;
int MaxLength;
} sf_tree;
typedef struct sf_node { /* node in a true shannon-fano tree */
UWORD left; /* 0 means leaf node */
UWORD right; /* or value if leaf node */
} sf_node;
/********************************/
/* UnImplode Global Variables */
/********************************/
/* s-f storage is shared with that used by other comp. methods */
sf_tree lit_tree;
sf_tree length_tree;
sf_tree distance_tree;
sf_node *lit_nodes = (sf_node *) prefix_of; /* 2*LITVALS nodes */
#ifdef MACOS
sf_node *length_nodes ; /* 2*LENVALS nodes */
sf_node *distance_nodes ; /* 2*DISTVALS nodes */
#else
sf_node *length_nodes = (sf_node *) suffix_of; /* 2*LENVALS nodes */
sf_node *distance_nodes = (sf_node *) stack; /* 2*DISTVALS nodes */
#endif
boolean lit_tree_present;
boolean eightK_dictionary;
int minimum_match_length;
int dict_bits;
/*****************************************/
/* UnImplode Local Function Prototypes */
/*****************************************/
static void LoadTrees __((void));
static void LoadTree __((sf_tree * tree, int treesize, sf_node * nodes));
static void ReadLengths __((sf_tree * tree));
static void SortLengths __((sf_tree * tree));
static void GenerateTrees __((sf_tree * tree, sf_node * nodes));
static void ReadTree __((register sf_node * nodes, int *dest));
/**************************/
/* Function unImplode() */
/**************************/
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)) {
outcnt += Length;
while (Length--)
*outptr++ = outbuf[srcix++];
} else {
while (Length--) {
OUTB(outbuf[srcix++]);
srcix &= OUTBUFSIZ - 1;
}
}
}
}
}
/**************************/
/* Function LoadTrees() */
/**************************/
static 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);
}
/*************************/
/* Function LoadTree() */
/*************************/
static 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);
}
/****************************/
/* Function ReadLengths() */
/****************************/
static 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--;
}
}
/****************************/
/* Function SortLengths() */
/****************************/
static 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;
}
}
/******************************/
/* Function GenerateTrees() */
/******************************/
static 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;
}
/************************/
/* Function ReadTree() */
/************************/
#ifndef ASM
static 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 /* !ASM */