macutils/macunpack/de_compress.c

226 lines
5.1 KiB
C

#include "de_compress.h"
#include <stdlib.h>
#include "macunpack.h"
#ifdef SIT
#define DECOMPRESS
#endif /* SIT */
#ifdef LZC
#define DECOMPRESS
#endif /* LZC */
#ifdef DECOMPRESS
#include "globals.h"
#include "../fileio/wrfile.h"
/* Written to allow for bits to be upto 16, MacCompress can use 16 bits */
#define BITS 16
#define HSIZE 69001 /* 95% occupancy */
#define INIT_BITS 9 /* initial number of bits/code */
static int n_bits; /* number of bits/code */
static int maxbits; /* user settable max # bits/code */
static int32_t maxcode; /* maximum code, given n_bits */
static int32_t maxmaxcode; /* should NEVER generate this code */
# define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
static int32_t htab [HSIZE];
static unsigned short codetab [HSIZE];
#define tab_prefixof(i) codetab[i]
#define tab_suffixof(i) ((unsigned char *)(htab))[i]
#define de_stack ((unsigned char *)&tab_suffixof(1<<BITS))
static int32_t free_ent = 0; /* first unused entry */
static int32_t getcode(void);
static int clear_flg = 0;
/*
* the next two codes should not be changed lightly, as they must not
* lie within the contiguous general code space.
*/
#define FIRST 257 /* first free entry */
#define CLEAR 256 /* table clear output code */
static int toread;
void de_compress(uint32_t ibytes, int mb)
{
register unsigned char *stackp;
register int finchar;
register int32_t code, oldcode, incode;
toread = ibytes;
maxbits = mb;
maxmaxcode = 1 << maxbits;
maxcode = MAXCODE(n_bits = INIT_BITS);
for(code = 255; code >= 0; code--) {
tab_prefixof(code) = 0;
tab_suffixof(code) = (unsigned char)code;
}
free_ent = FIRST;
finchar = oldcode = getcode();
if(oldcode == -1) { /* EOF already? */
return; /* Get out of here */
}
/* first code must be 8 bits = char */
*out_ptr++ = (char)finchar;
stackp = de_stack;
while((code = getcode()) > -1) {
if(code == CLEAR) {
for(code = 255; code >= 0; code--) {
tab_prefixof(code) = 0;
}
clear_flg = 1;
free_ent = FIRST - 1;
if((code = getcode()) == -1) { /* O, untimely death! */
break;
}
}
incode = code;
/*
* Special case for KwKwK string.
*/
if(code >= free_ent) {
*stackp++ = finchar;
code = oldcode;
}
/*
* Generate output characters in reverse order
*/
while(code >= 256) {
*stackp++ = tab_suffixof(code);
code = tab_prefixof(code);
}
*stackp++ = finchar = tab_suffixof(code);
/*
* And put them out in forward order
*/
do {
*out_ptr++ = (char)*--stackp;
} while(stackp > de_stack);
/*
* Generate the new entry.
*/
if((code=free_ent) < maxmaxcode) {
tab_prefixof(code) = (unsigned short)oldcode;
tab_suffixof(code) = finchar;
free_ent = code+1;
}
/*
* Remember previous code.
*/
oldcode = incode;
}
return;
}
static unsigned char rmask[9] =
{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
static int get_core_bytes;
static char *core_ptr;
static int file_bytes(char *buf, int length);
static int core_bytes(char *buf, int length);
static int32_t
getcode (void)
{
register int32_t code;
static int offset = 0, size = 0;
static unsigned char buf[BITS];
register int r_off, bits;
register unsigned char *bp = buf;
if(clear_flg > 0 || offset >= size || free_ent > maxcode) {
/*
* If the next entry will be too big for the current code
* size, then we must increase the size. This implies reading
* a new buffer full, too.
*/
if(free_ent > maxcode) {
n_bits++;
if(n_bits == maxbits) {
maxcode = maxmaxcode; /* won't get any bigger now */
} else {
maxcode = MAXCODE(n_bits);
}
}
if(clear_flg > 0) {
maxcode = MAXCODE (n_bits = INIT_BITS);
clear_flg = 0;
}
if(toread == 0) {
return -1;
}
if(get_core_bytes) {
size = core_bytes((char *)buf, (n_bits < toread ? n_bits : toread));
} else {
size = file_bytes((char *)buf, (n_bits < toread ? n_bits : toread));
}
toread -= size;
if(size <= 0) {
(void)fprintf(stderr, "Premature EOF\n");
#ifdef SCAN
do_error("macunpack: Premature EOF");
#endif /* SCAN */
exit(1);
}
offset = 0;
/* Round size down to integral number of codes */
size = (size << 3) - (n_bits - 1);
}
r_off = offset;
bits = n_bits;
/*
* Get to the first byte.
*/
bp += (r_off >> 3);
r_off &= 7;
/* Get first part (low order bits) */
code = (*bp++ >> r_off);
bits -= (8 - r_off);
r_off = 8 - r_off; /* now, offset into code word */
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
if(bits >= 8) {
code |= *bp++ << r_off;
r_off += 8;
bits -= 8;
}
/* high order bits. */
code |= (*bp & rmask[bits]) << r_off;
offset += n_bits;
return code;
}
static int
file_bytes (char *buf, int length)
{
return fread(buf, 1, length, infp);
}
static int
core_bytes (char *buf, int length)
{
int i;
for(i = 0; i < length; i++) {
*buf++ = *core_ptr++;
}
return length;
}
void core_compress(char* ptr)
{
core_ptr = ptr;
get_core_bytes = ptr != NULL;
}
#else /* DECOMPRESS */
int decompress; /* keep lint and some compilers happy */
#endif /* DECOMPRESS */