mirror of
https://github.com/ShadauxCat/CATSFC.git
synced 2025-04-02 10:41:47 -04:00
177 lines
4.2 KiB
C
177 lines
4.2 KiB
C
/*---------------------------------------------------------------------------
|
|
|
|
unshrink.c
|
|
|
|
Shrinking is a Dynamic Lempel-Ziv-Welch compression algorithm with partial
|
|
clearing.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
|
|
#include "unz.h"
|
|
void flush_stack (int);
|
|
|
|
/*************************************/
|
|
/* UnShrink Defines, Globals, etc. */
|
|
/*************************************/
|
|
|
|
/* MAX_BITS 13 (in unzip.h; defines size of global work area) */
|
|
#define INIT_BITS 9
|
|
#define FIRST_ENT 257
|
|
#define CLEAR 256
|
|
#define GetCode(dest) READBIT(codesize,dest)
|
|
|
|
static void partial_clear ();
|
|
|
|
int codesize, maxcode, maxcodemax, free_ent;
|
|
|
|
|
|
|
|
|
|
/*************************/
|
|
/* Function unShrink() */
|
|
/*************************/
|
|
|
|
void unShrink()
|
|
{
|
|
register int code;
|
|
register int stackp;
|
|
int finchar;
|
|
int oldcode;
|
|
int incode;
|
|
|
|
|
|
/* decompress the file */
|
|
codesize = INIT_BITS;
|
|
maxcode = (1 << codesize) - 1;
|
|
maxcodemax = HSIZE; /* (1 << MAX_BITS) */
|
|
free_ent = FIRST_ENT;
|
|
|
|
code = maxcodemax;
|
|
do {
|
|
prefix_of[code] = -1;
|
|
} while (--code > 255);
|
|
/*
|
|
OvdL: -Ox with SCO's 3.2.0 cc gives
|
|
a. warning: overflow in constant multiplication
|
|
b. segmentation fault (core dumped) when using the executable
|
|
for (code = maxcodemax; code > 255; code--)
|
|
prefix_of[code] = -1;
|
|
*/
|
|
|
|
for (code = 255; code >= 0; code--) {
|
|
prefix_of[code] = 0;
|
|
suffix_of[code] = (byte) code;
|
|
}
|
|
|
|
GetCode(oldcode);
|
|
if (zipeof)
|
|
return;
|
|
finchar = oldcode;
|
|
|
|
stack[0] = finchar;
|
|
flush_stack (1);
|
|
|
|
stackp = HSIZE;
|
|
|
|
while (!zipeof) {
|
|
GetCode(code);
|
|
if (zipeof)
|
|
return;
|
|
|
|
while (code == CLEAR) {
|
|
GetCode(code);
|
|
switch (code) {
|
|
case 1:
|
|
codesize++;
|
|
if (codesize == MAX_BITS)
|
|
maxcode = maxcodemax;
|
|
else
|
|
maxcode = (1 << codesize) - 1;
|
|
break;
|
|
|
|
case 2:
|
|
partial_clear();
|
|
break;
|
|
}
|
|
|
|
GetCode(code);
|
|
if (zipeof)
|
|
return;
|
|
}
|
|
|
|
|
|
/* special case for KwKwK string */
|
|
incode = code;
|
|
if (prefix_of[code] == -1) {
|
|
stack[--stackp] = (byte) finchar;
|
|
code = oldcode;
|
|
}
|
|
/* generate output characters in reverse order */
|
|
while (code >= FIRST_ENT) {
|
|
if (prefix_of[code] == -1) {
|
|
stack[--stackp] = (byte) finchar;
|
|
code = oldcode;
|
|
} else {
|
|
stack[--stackp] = suffix_of[code];
|
|
code = prefix_of[code];
|
|
}
|
|
}
|
|
|
|
finchar = suffix_of[code];
|
|
stack[--stackp] = (byte) finchar;
|
|
|
|
/* and put them out in forward order, block copy */
|
|
flush_stack (HSIZE - stackp);
|
|
stackp = HSIZE;
|
|
|
|
/* generate new entry */
|
|
code = free_ent;
|
|
if (code < maxcodemax) {
|
|
prefix_of[code] = oldcode;
|
|
suffix_of[code] = (byte) finchar;
|
|
|
|
do
|
|
code++;
|
|
while ((code < maxcodemax) && (prefix_of[code] != -1));
|
|
|
|
free_ent = code;
|
|
}
|
|
/* remember previous code */
|
|
oldcode = incode;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************/
|
|
/* Function partial_clear() */
|
|
/******************************/
|
|
|
|
static void partial_clear()
|
|
{
|
|
register int pr;
|
|
register int cd;
|
|
|
|
/* mark all nodes as potentially unused */
|
|
for (cd = FIRST_ENT; cd < free_ent; cd++)
|
|
prefix_of[cd] |= 0x8000;
|
|
|
|
/* unmark those that are used by other nodes */
|
|
for (cd = FIRST_ENT; cd < free_ent; cd++) {
|
|
pr = prefix_of[cd] & 0x7fff; /* reference to another node? */
|
|
if (pr >= FIRST_ENT) /* flag node as referenced */
|
|
prefix_of[pr] &= 0x7fff;
|
|
}
|
|
|
|
/* clear the ones that are still marked */
|
|
for (cd = FIRST_ENT; cd < free_ent; cd++)
|
|
if ((prefix_of[cd] & 0x8000) != 0)
|
|
prefix_of[cd] = -1;
|
|
|
|
/* find first cleared node as next free_ent */
|
|
cd = FIRST_ENT;
|
|
while ((cd < maxcodemax) && (prefix_of[cd] != -1))
|
|
cd++;
|
|
free_ent = cd;
|
|
}
|