mirror of
https://github.com/erkyrath/infocom-zcode-terps.git
synced 2026-02-08 09:11:27 +00:00
235 lines
5.6 KiB
C
235 lines
5.6 KiB
C
|
|
/*
|
|
Steps in picture compression (undo in reverse order):
|
|
|
|
1. Each line of the picture is exclusive-or'ed with the previous line.
|
|
|
|
2. A run-length encoding is applied, as follows: byte values 0
|
|
through 15 represent colors; byte values 16 through 127 are repetition
|
|
counts (16 will never actually appear) Thus: 3 occurrences of byte
|
|
value 2 will turn into 2 17 (subtract 15 from the 17 to find that the
|
|
two should be repeated 2 MORE times).
|
|
|
|
3. Optionally, the whole thing is Huffman-coded, using an encoding
|
|
specified in the header file. */
|
|
|
|
#define ULONG unsigned long /* 32 bits */
|
|
#define UWORD unsigned short /* 16 */
|
|
#define UCHAR unsigned char /* 8 */
|
|
|
|
/*------------------------------*/
|
|
/* uncompress_huff */
|
|
/*------------------------------*/
|
|
|
|
/* Uncompress a huffed picture.
|
|
Does all three steps simultaneously--unhuf, then undo rle and xor steps.
|
|
Stores extra line of 0s at beginning of outbuf, for xor step.
|
|
Returns number of decompressed bytes. */
|
|
|
|
ULONG /*int*/ uncompress_huff (inbuf, outbuf, huff_tree, inlen, pic_x)
|
|
unsigned char *inbuf, *outbuf, *huff_tree;
|
|
int pic_x, inlen;
|
|
{
|
|
unsigned char *p = &outbuf[pic_x];
|
|
int j, olen;
|
|
int /*UCHAR*/ chr, cnode = 0, cbit = 128, lastpix;
|
|
unsigned char *p_base = p;
|
|
|
|
olen = (inbuf[0] << 8) | inbuf[1]; /* Actual number of characters resulting from unhuf */
|
|
inbuf += 2;
|
|
for (j = 0; j < pic_x; j++)
|
|
outbuf[j] = 0;
|
|
|
|
chr = *inbuf++; /* Get the first character */
|
|
inlen--; /* etc */
|
|
while (1) {
|
|
if (chr & cbit) /* Proceed with huffman */
|
|
cnode = huff_tree[cnode + 1];
|
|
else
|
|
cnode = huff_tree[cnode];
|
|
|
|
if (cnode < 128)
|
|
cnode *= 2;
|
|
else {
|
|
cnode -= 128; /* this is a terminal */
|
|
|
|
/* here we undo both runlength and xor */
|
|
if (cnode < 16) { /* It's a color id, output/xor it */
|
|
*p++ = cnode ^ *outbuf++;
|
|
lastpix = cnode;
|
|
}
|
|
else { /* Otherwise, run/xor last color id */
|
|
for (j = 0; j < (cnode - 15); j++) {
|
|
*p++ = lastpix ^ *outbuf++;
|
|
}
|
|
}
|
|
if (--olen <= 0) break;
|
|
cnode = 0;
|
|
}
|
|
cbit = cbit >> 1; /* Next bit */
|
|
if (!cbit) { /* If done with this char, go to next */
|
|
if (inlen-- <= 0) break;
|
|
cbit = 128;
|
|
chr = *inbuf++;
|
|
}
|
|
}
|
|
return (p - p_base); /* final outlen */
|
|
}
|
|
|
|
/*------------------------------*/
|
|
/* uncompress_nohuff */
|
|
/*------------------------------*/
|
|
|
|
int uncompress_nohuff (inbuf, outbuf, inlen, pic_x)
|
|
unsigned char *inbuf, *outbuf;
|
|
int pic_x, inlen;
|
|
{
|
|
unsigned char *p = &outbuf[pic_x];
|
|
unsigned char *p_base = p;
|
|
int lastpix, val, j;
|
|
|
|
for (j = 0; j < pic_x; j++)
|
|
outbuf[j] = 0;
|
|
|
|
while (inlen--) {
|
|
val = *inbuf++;
|
|
if (val < 16) {
|
|
lastpix = val;
|
|
*p++ = val ^ *outbuf++;
|
|
}
|
|
else {
|
|
for (j = 0; j < (val - 15); j++) {
|
|
*p++ = lastpix ^ *outbuf++;
|
|
}
|
|
}
|
|
}
|
|
return (p - p_base); /* final outlen */
|
|
}
|
|
|
|
/*------------------------------*/
|
|
/* binary_search */
|
|
/*------------------------------*/
|
|
|
|
/* search a directory for a given id [first word of each entry],
|
|
return ptr, or null if not found */
|
|
|
|
short *binary_search (dir, e_count, e_size /*words*/, id)
|
|
short *dir;
|
|
int e_count, e_size, id;
|
|
{
|
|
register int top, bot, cur;
|
|
register int cid;
|
|
register short *p;
|
|
|
|
bot = 0;
|
|
top = e_count;
|
|
while (top > bot) {
|
|
cur = bot + ((top - bot) >> 1); /* DIV 2, round DOWN */
|
|
p = &dir[cur * e_size];
|
|
|
|
if ((cid = *p) == id)
|
|
return (p);
|
|
|
|
if (cid < id)
|
|
bot = cur + 1;
|
|
else top = cur;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
/** DEAD CALLS **/
|
|
|
|
#define incl_dead 0
|
|
#if incl_dead == 1
|
|
|
|
/* huf is Huffman tree, from header; len is number of bytes; buf1 is
|
|
actual data; buf2 is output data. Returns number of decoded bytes. */
|
|
|
|
int unhuf (huf, len, buf1, buf2)
|
|
unsigned char *huf, *buf1, *buf2;
|
|
int len;
|
|
{
|
|
int olen = 0;
|
|
int chr;
|
|
unsigned char *outbuf;
|
|
int cnode = 0, cbit = 128; /* Node 0 is always the root */
|
|
|
|
outbuf = buf2;
|
|
chr = *buf1++; /* Get a character */
|
|
len--;
|
|
while (1) {
|
|
if (chr & cbit) /* if the bit is one */
|
|
cnode = huf[cnode + 1]; /* then use the right-hand descendant of this node */
|
|
else
|
|
cnode = huf[cnode]; /* otherwise left */
|
|
if (cnode >= 128) { /* if descendant >= 128, it's a terminal */
|
|
*outbuf++ = cnode - 128; /* subtract 128, and dump it out. */
|
|
olen++;
|
|
cnode = 0;
|
|
}
|
|
else /* otherwise, get the byte offset of the new node */
|
|
cnode = 2 * cnode;
|
|
cbit = cbit >> 1; /* and move to the next bit */
|
|
if (!cbit) { /* If we've used up the whole byte, */
|
|
len--; /* get another one, if there are any */
|
|
if (!len) break;
|
|
cbit = 128;
|
|
chr = *buf1++;
|
|
}
|
|
}
|
|
return(olen);
|
|
}
|
|
|
|
/* Undo the run-length encoding.
|
|
buf1 is input, buf2 is output, len is number of bytes in the input,
|
|
The length of the output is known, since it must be the picture size;
|
|
however, we return it anyway for error checking.
|
|
|
|
Currently, we emit 1 byte/pixel, with no row padding.
|
|
[ x is pixels per row, rowBytes is bytes (padded) per row. ]
|
|
*/
|
|
|
|
int uncomp (buf1, buf2, len) /*, x, rowBytes */
|
|
unsigned char *buf1, *buf2;
|
|
int len;
|
|
/* int x, rowBytes; */
|
|
{
|
|
int i, j;
|
|
char chr;
|
|
unsigned char *b2base = buf2;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (buf1[i] < 16)
|
|
/* <16 means this doesn't get changed */
|
|
*buf2++ = chr = buf1[i];
|
|
else {
|
|
/* Otherwise, repeat previous byte n-15 times */
|
|
for (j = 0; j < (buf1[i] - 15); j++)
|
|
*buf2++ = chr;
|
|
}
|
|
}
|
|
return (buf2 - b2base);
|
|
}
|
|
|
|
/* Undo the xor step.
|
|
Buf is input and output; x is picture rowBytes; y is picture y. */
|
|
|
|
void uneor (buf, x, y, step)
|
|
unsigned char *buf;
|
|
int x,y;
|
|
int step; /* either x or 2x */
|
|
{
|
|
int i;
|
|
|
|
/* xor element from next line with element from this line,
|
|
store in next line */
|
|
|
|
for (i = 0; i < (x * y) - step; i++)
|
|
buf[i + step] ^= buf[i];
|
|
}
|
|
|
|
#endif
|
|
|
|
|