home *** CD-ROM | disk | FTP | other *** search
- /* This is an adaptation of the decompress part of the widespread net
- * "compress" program. It is specifically designed for the IBM PC and
- * clones and probably has to be compiled with the Microsoft C
- * compiler (quick C won't do, it doesn't support the "huge" model).
- *
- * Parts written (other parts plagarized) by Tom Horsley
- * (tahorsley@ssd.harris.com)
- * Dec 1988.
- */
- #include <stdio.h>
- #include <fcntl.h>
- #include <malloc.h>
-
- /* Magic number stored in first two bytes.
- */
- unsigned char magic_header[] = { "\037\235" }; /* 1F 9D */
-
- /* Defines for third byte of header */
- #define BIT_MASK 0x1f /* Max number of bits in codes */
- #define BLOCK_MASK 0x80 /* This bit set if should recognize CLEAR code */
-
- /* Space to use for input file buffer.
- */
- #define MAXBUF 4096
-
- /* a codebuf struct is used to interface with the xcode() routine.
- */
- struct codebuf {
- void (*codep)();
- unsigned char * bufp;
- } cb;
-
- /* a codesize struct is used for advancing from one size code to
- * the next.
- */
- struct codesize {
- void (*initp)(struct codebuf *);
- int n_bits;
- long int maxcode;
- void (*origp)();
- };
-
- extern void init9(struct codebuf *);
- extern void init10(struct codebuf *);
- extern void init11(struct codebuf *);
- extern void init12(struct codebuf *);
- extern void init13(struct codebuf *);
- extern void init14(struct codebuf *);
- extern void init15(struct codebuf *);
- extern void init16(struct codebuf *);
- extern unsigned int xcode(struct codebuf *);
-
- /* vartab tracks the variable size codes. For each size code the
- * initialization routine, code size, largest code, and assembly state
- * information is recorded.
- *
- * To advance to next sized code, read codes at current size while not
- * at the original state, then call init routine for next size (and
- * record initial state info).
- */
- struct codesize vartab [] = {
- { init9, 9, 0x1ffL, 0 },
- { init10, 10, 0x3ffL, 0 },
- { init11, 11, 0x7ffL, 0 },
- { init12, 12, 0xfffL, 0 },
- { init13, 13, 0x1fffL, 0 },
- { init14, 14, 0x3fffL, 0 },
- { init15, 15, 0x7fffL, 0 },
- { init16, 16, 0x10000L, 0 }
- };
-
- /* Record current entry in vartab.
- */
- int curvartab = 0;
-
- #ifdef DEBUG
- long bytes_out = 0;
- #endif
-
-
- /* buf is the input file buffer. Also used to store the initial help
- * message you get with the -H option.
- */
- unsigned char buf[MAXBUF] = "\
- u16 - 16 bit LZW uncompress for the IBM PC\n\
- u16 [-H] [files...]\n\
- \n\
- -H\tPrint this message and exit.\n\
- \n\
- Uncompresses each input file and writes result to stdout. With no\n\
- input file specified, reads stdin. Probably requires 270-280K of free\n\
- memory to run.\n\
- \n\
- Written for the IBM PC by tahorsley@ssd.harris.com (Tom Horsley).\n\
- \n\
- NOTE: this is kind of like zcat, but it does not try to stick any .Z's\n\
- on the ends of file names.\n"
- ;
-
- /* Number of bytes of file data resident in buf.
- */
- int bufsize = 0;
-
- /* Address of first byte in buffer past end of file
- * (only set when the last buffer is read).
- */
- char * eofmark = NULL;
-
- /* Address of byte near end of buffer (used to determine
- * when to read additional data).
- */
- char * endbuf;
-
-
- /* Flag data read from file.
- */
- int block_compress;
- int maxbits;
-
- /* State variables controlling decompression
- */
- #define FIRST 257 /* first free entry */
-
- #define CLEAR 256 /* table clear output code */
-
- int clear_flg = 0;
-
- long free_ent = 0;
-
- long maxcode;
-
- #define FAR far
-
- char FAR * de_stack;
-
- /* tabprefix is the only real fly in the ointment, it needs to be a
- * huge array, but could probably be changed to a couple of far arrays
- * with the resulting additional complications in the tab_prefixof()
- * macro.
- */
- unsigned int huge * tabprefix;
-
- unsigned char FAR * tabsuffix;
-
- #define tab_prefixof(_i) tabprefix[_i]
-
- #define tab_suffixof(_i) tabsuffix[_i]
-
- long maxmaxcode = 65536L;
-
- /* ReadBuf reads some data into the buffer following the data already
- * in the buffer (if any). It tries to fill it up, and sets the end of
- * file flag if it can't.
- */
- void
- ReadBuf()
- {
- int cursize;
- int want;
-
- while ((eofmark == NULL) && ((want = MAXBUF - bufsize) > 0)) {
- cursize = read(fileno(stdin), &buf[bufsize], want);
- if (cursize < 0) {
- perror("u16");
- exit(1);
- } else if (cursize == 0) {
- eofmark = &buf[bufsize];
- } else {
- bufsize += cursize;
- }
- }
- if (eofmark == NULL) {
- endbuf = &buf[bufsize] - 32;
- } else {
- endbuf = eofmark;
- }
- }
-
- /* getcode deals with buffer filling, switching code size, and calling
- * the assembler unpacking routines.
- */
- long int
- getcode()
- {
- int leftover;
-
- if (cb.bufp >= endbuf) {
- if (eofmark != NULL) {
- return(-1L);
- } else {
- /* move the un-read data to the top of the buffer, then read
- * some additional data.
- */
- leftover = &buf[bufsize] - cb.bufp;
- memmove(&buf[0], cb.bufp, leftover);
- cb.bufp = &buf[0];
- bufsize = leftover;
- ReadBuf();
- }
- }
- if (clear_flg > 0 || free_ent > maxcode) {
- /* If the next entry will be too big for the current code, or we
- * have recieved a clear code then flush the current size code
- * and advance to next size.
- */
- while (cb.codep != vartab[curvartab].origp) xcode(&cb);
- if (cb.bufp >= endbuf) return(-1L);
- if (clear_flg > 0) {
- curvartab = 0;
- clear_flg = 0;
- } else {
- ++curvartab;
- if (curvartab > (16 - 9)) {
- #ifdef DEBUG
- fputs("Attempt to overflow 16 bit codes.\n",stderr);
- #endif
- curvartab = 16 - 9;
- }
- }
- (*vartab[curvartab].initp)(&cb);
- vartab[curvartab].origp = cb.codep;
- maxcode = vartab[curvartab].maxcode;
- #ifdef DEBUG
- fprintf(stderr,
- "switching to %d bit codes, bytes_out = %ld, free_ent = %ld\n",
- vartab[curvartab].n_bits,bytes_out, free_ent);
- #endif
- }
- return (long)(xcode(&cb));
- }
-
- /* Decompress stdin to stdout. This routine adapts to the codes in
- * the file building the "string" table on-the-fly; requiring no table
- * to be stored in the compressed file.
- *
- * This routine taken practically verbatim from the net compress
- * program:
- *
- * $Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $
- *
- * compress.c - File compression ala IEEE Computer, June 1984.
- *
- * Authors:
- * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!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)
- */
- int
- decompress() {
- register unsigned char FAR * stackp;
- register int finchar;
- register long code, oldcode, incode;
- #ifdef DEBUG
- long stacksize = 0;
- #endif
-
- /* No buffering on stdin, we do all our own buffering.
- */
- setvbuf(stdin, NULL, _IONBF, 0);
-
- /* Operate in the binary file domain, don't want DOS screwing
- * around with '\r''s.
- */
- setmode(fileno(stdin), O_BINARY);
- setmode(fileno(stdout), O_BINARY);
-
- /* Read the iniital buffer worth of data and check magic numbers
- * and flags.
- */
- ReadBuf();
- if (bufsize < 3) {
- fputs("u16: Missing file header.\n",stderr);
- return 1;
- }
- if (memcmp(buf,magic_header,2) != 0) {
- fputs("u16: Bad magic number.\n",stderr);
- return 1;
- }
- block_compress = buf[2] & BLOCK_MASK;
- maxbits = buf[2] & BIT_MASK;
- if (maxbits > 16) {
- fputs("u16: Cannot decompress, compressed with more than 16 bits.\n",
- stderr);
- return 1;
- }
-
- /* Initialize the xcode routine to start reading 9 bit codes at the
- * third byte of the initial buffer.
- */
- cb.bufp = &buf[3];
- init9(&cb);
- vartab[0].origp = cb.codep;
- curvartab = 0;
-
- /*
- * initialize the first 256 entries in the table.
- */
- maxcode = vartab[0].maxcode;
- for ( code = 255; code >= 0; code-- ) {
- tab_prefixof(code) = 0;
- tab_suffixof(code) = (unsigned char)code;
- }
- free_ent = ((block_compress) ? FIRST : 256 );
-
- finchar = oldcode = getcode();
- if(oldcode == -1) /* EOF already? */
- return; /* Get out of here */
- putchar((char)finchar ); /* first code must be 8 bits = char */
- #ifdef DEBUG
- ++bytes_out;
- #endif
- if(ferror(stdout)) { /* Crash if can't write */
- perror("u16");
- exit(1);
- }
- stackp = de_stack;
-
- while ( (code = getcode()) > -1 ) {
-
- if ( (code == CLEAR) && block_compress ) {
- #ifdef DEBUG
- fprintf(stderr,
- "Input CLEAR code bytes_out = %ld, free_ent = %ld\n",
- bytes_out, free_ent);
- #endif
- 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 ) {
- #ifdef DEBUG
- ++stacksize;
- if (stacksize >= 65536L) {
- fputs("stacksize overflow.\n",stderr);
- exit(1);
- }
- #endif
- *stackp++ = finchar;
- code = oldcode;
- }
-
- /* Generate output characters in reverse order
- */
- while ( code >= 256 ) {
- #ifdef DEBUG
- ++stacksize;
- if (stacksize >= 65536L) {
- fputs("stacksize overflow.\n",stderr);
- exit(1);
- }
- if ((code < 0) || (code >= 65536L)) {
- fprintf(stderr,"bad subscript, code = %ld\n",code);
- }
- #endif
- *stackp++ = tab_suffixof(code);
- code = tab_prefixof(code);
- }
- #ifdef DEBUG
- ++stacksize;
- if (stacksize >= 65536L) {
- fputs("stacksize overflow.\n",stderr);
- exit(1);
- }
- if ((code < 0) || (code >= 65536L)) {
- fprintf(stderr,"bad subscript, code = %ld\n",code);
- }
- #endif
- *stackp++ = finchar = tab_suffixof(code);
- #ifdef DEBUG
- if (stacksize > 65536L) {
- fprintf(stderr,"stacksize reached %ld\n",stacksize);
- }
- #endif
-
- /* And put them out in forward order
- */
- do {
- putchar ( *--stackp );
- #ifdef DEBUG
- ++bytes_out;
- --stacksize;
- #endif
- } while ( stackp > de_stack );
-
- #ifdef DEBUG
- if (stacksize != 0) {
- fprintf(stderr,"stacksize = %ld, not empty!\n",stacksize);
- }
- #endif
-
- /* Generate the new entry.
- */
- if ( (code=free_ent) < maxmaxcode ) {
- #ifdef DEBUG
- if ((code < 0) || (code >= 65536L)) {
- fprintf(stderr,"bad subscript, code = %ld\n",code);
- }
- #endif
- tab_prefixof(code) = (unsigned short)oldcode;
- tab_suffixof(code) = finchar;
- free_ent = code+1;
- }
-
- /* Remember previous code.
- */
- oldcode = incode;
- }
- fflush( stdout );
- if(ferror(stdout)) {
- perror("u16");
- return 1;
- }
- return 0;
- }
-
- /* 16 bit uncompress optimized for 8086 architecture. The getcode
- * routine is in 8086 assembler optimized for extracting the variable
- * sized code rapidly.
- */
- void
- main(argc, argv)
- int argc;
- char * argv[];
- {
- int errors = 0;
-
- /* Process options (only supports -H)
- */
- --argc;
- ++argv;
- while ((argc > 0) && (argv[0][0] == '-')) {
- if (argv[0][1] == 'H') {
- fputs(buf,stderr);
- exit(0);
- } else {
- fputs("u16: unrecognized option ",stderr);
- fputs(argv[0],stderr);
- fputs("\n",stderr);
- fputs("usage: u16 [-H] [files...]\n",stderr);
- exit(1);
- }
- --argc;
- ++argv;
- }
-
- /* Allocate a large buffer for stdout (speeds up the program by a
- * fair percentage).
- */
- setvbuf(stdout, NULL, _IOFBF, MAXBUF);
-
- /* Allocate space for tables
- */
- de_stack = (unsigned char FAR *)halloc(65536L, sizeof(unsigned char));
- tabprefix = (unsigned int huge *)halloc(65536L, sizeof(unsigned int));
- tabsuffix = (unsigned char FAR *)halloc(65536L, sizeof(unsigned char));
- if ((de_stack == NULL) || (tabprefix == NULL) || (tabsuffix == NULL)) {
- fputs("u16: out of memory.\n",stderr);
- exit(1);
- }
-
- if (argc == 0) {
- /* Just decompress stdin
- */
- if (decompress()) {
- ++errors;
- fputs("u16: error decompressing stdin.\n",stderr);
- }
- } else {
- while (argc > 0) {
- if (freopen(argv[0], "r", stdin) == NULL) {
- fputs("u16: cannot read ",stderr);
- fputs(argv[0],stderr);
- fputs("\n",stderr);
- ++errors;
- } else {
- if (decompress()) {
- fputs("u16: error in ",stderr);
- fputs(argv[0],stderr);
- fputs("\n",stderr);
- ++errors;
- }
- fclose(stdin);
- }
- --argc;
- ++argv;
- }
- }
- #ifdef DEBUG
- fprintf(stderr,"Total bytes out = %ld\n",bytes_out);
- #endif
- exit(errors);
- }
-