home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
hensa
/
disk
/
archive
/
nspark_1
/
nspark-1.7.5
/
compress.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-25
|
7KB
|
310 lines
/*
* compress/uncompress archive
*
* Authors: Spencer W. Thomas (decvax!utah-cs!thomas)
* Jim McKie (decvax!mcvax!jim)
* Steve Davies (decvax!vax135!petsd!peora!srd)
* Ken Turkowski (decvax!decwrl!turtlevax!ken)
* James A. Woods (decvax!ihnp4!ames!jaw)
* Joe Orost (decvax!vax135!petsd!joe)
*
* NOTE: these functions also support "squash" (which is just a
* 13-bit compress), and "crunch" (which is a 12-bit compress
* with additional run-length encoding). AJD
*
* $Header: compress.c 1.10 95/01/20 $
* $Log: compress.c,v $
* Revision 1.10 95/01/25 12:49:43 arb
* Bug fixes caused by 1.9
*
* Revision 1.9 95/01/06 12:00:06 arb
* Fixes for Alpha.
*
* Revision 1.8 94/02/28 23:57:55 arb
* Fixed number of compression bits for ArcFS format archives
*
* Revision 1.7 93/08/20 11:35:20 arb
* Prevent printing of "uncompressed" etc. if quiet flag is set
*
* Revision 1.6 92/12/07 17:17:28 duplain
* reformatted source.
*
* Revision 1.5 92/11/09 14:48:00 duplain
* Initialised offset and size from getcode() each time uncompress() called.
*
* Revision 1.4 92/11/02 11:43:14 duplain
* Correct comment about crunch/squash in header.
*
* Revision 1.3 92/10/23 14:08:13 duplain
* Minor changes to printf's at end of uncompress.
*
* Revision 1.2 92/10/01 11:20:19 duplain
* Added check for EOF.
*
* Revision 1.1 92/09/29 18:02:14 duplain
* Initial revision
*
*/
#include <stdio.h>
#include "spark.h"
#include "pack.h"
#include "main.h"
#include "crc.h"
#include "io.h"
#include "arcfs.h"
#ifdef UNIX
static char rcsid[] = "$Header: compress.c 1.10 95/01/20 $";
#endif /* UNIX */
#define PBITS 16
#define CRUNCHBITS 12
#define SQUASHBITS 13
#define COMPRESSBITS 16
#define HSIZE 65536
#define INIT_BITS 9 /* initial number of bits/code */
#define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
#define htabof(i) htab[i]
#define codetabof(i) codetab[i]
#define tab_prefixof(i) codetabof(i)
#define tab_suffixof(i) ((char_type *)(htab))[i]
#define de_stack ((char_type *)&tab_suffixof(1<<COMPRESSBITS))
#define FIRST 257 /* first free entry */
#define CLEAR 256 /* table clear output code */
typedef int code_int;
typedef int count_int;
typedef unsigned char char_type;
static int n_bits; /* number of bits/code */
static int maxbits; /* user settable max # bits/code */
static code_int maxcode; /* maximum code, given n_bits */
static code_int maxmaxcode; /* should NEVER generate this code */
static count_int htab[HSIZE];
static unsigned short codetab[HSIZE];
static char_type rmask[9] ={0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
static code_int free_ent; /* first unused entry */
static int clear_flg;
static long readsize; /* number of bytes left to read */
static int offset, size; /* from getcode() */
static code_int getcode P__((FILE *ifp));
Status
uncompress(header, ifp, ofp, type)
Header *header;
FILE *ifp, *ofp;
CompType type;
{
register char_type *stackp;
register int finchar;
register code_int code, oldcode, incode;
char *message;
crc = 0;
clear_flg = 0;
offset = 0;
size = 0;
readsize = header->complen;
if (type == SQUASH)
maxbits = SQUASHBITS;
else {
if (arcfs)
maxbits = arcfs_maxbits;
else
{
maxbits = read_byte(ifp);
readsize--;
}
}
maxmaxcode = 1 << maxbits;
/*
* As above, initialize the first 256 entries in the table.
*/
maxcode = MAXCODE(n_bits = INIT_BITS);
for (code = 255; code >= 0; code--) {
tab_prefixof(code) = 0;
tab_suffixof(code) = (char_type) code;
}
free_ent = FIRST;
finchar = oldcode = getcode(ifp);
if (oldcode == -1) /* EOF already? */
goto compress_exit; /* Get out of here */
/* first code must be 8 bits = char */
if (type == CRUNCH) {
putc_init();
putc_ncr(ofp, finchar);
} else {
if (!testing)
write_byte(ofp, finchar);
calccrc(finchar);
}
stackp = de_stack;
while ((code = getcode(ifp)) != -1) {
if (check_stream(ifp) != FNOERR)
break;
if (code == CLEAR) {
for (code = 255; code >= 0; code--)
tab_prefixof(code) = 0;
clear_flg = 1;
free_ent = FIRST - 1;
if ((code = getcode(ifp)) == -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
*/
while (stackp > de_stack) {
stackp--;
if (type == CRUNCH)
putc_ncr(ofp, *stackp);
else {
if (!testing)
write_byte(ofp, *stackp);
calccrc(*stackp);
}
}
/*
* Generate the new entry.
*/
if ((code = free_ent) < maxmaxcode) {
tab_prefixof(code) = oldcode;
tab_suffixof(code) = finchar;
free_ent = code + 1;
}
/*
* Remember previous code.
*/
oldcode = incode;
}
compress_exit:
if (check_stream(ifp) == FRWERR)
return (RERR);
if (!testing && check_stream(ofp) == FRWERR)
return (WERR);
if ((Halfword)crc != header->crc)
return (CRCERR);
if (testing)
switch(type) {
case COMPRESS:
message = "OK (compressed)";
break;
case CRUNCH:
message = "OK (crunched)";
break;
case SQUASH:
message = "OK (squashed)";
break;
default:
message = "internal error";
break;
}
else
switch(type) {
case COMPRESS:
message = "uncompressed";
break;
case CRUNCH:
message = "uncrunched";
break;
case SQUASH:
message = "unsquashed";
break;
default:
message = "internal error";
break;
}
if (!quiet) printf(message);
return (NOERR);
}
/*
* Read one code from the input. If EOF, return -1.
*/
static code_int
getcode(ifp)
FILE *ifp;
{
register code_int code;
static char_type buf[COMPRESSBITS];
register int r_off, bits;
register char_type *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++;
maxcode = n_bits == maxbits ? maxmaxcode :
MAXCODE(n_bits);
}
if (clear_flg > 0) {
maxcode = MAXCODE(n_bits = INIT_BITS);
clear_flg = 0;
}
if (readsize == 0)
return (-1);
size = readsize < n_bits ? readsize : n_bits;
size = fread(buf, 1, size, ifp);
if (size <= 0)
return (-1); /* end of file */
readsize -= size;
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);
}