home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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.9 95/01/06 $
- * $Log: compress.c,v $
- * 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.9 95/01/06 $";
- #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 Word code_int;
- typedef Word 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);
- }
-