home *** CD-ROM | disk | FTP | other *** search
- /*=============================================================================
-
- The INSTALL program source code, object code, sample script files,
- executable program, and documentation are subject to copyright
- protection under the laws of the United States and other countries.
-
- This software is licensed, not sold, and may only be redistributed
- in executable format and only in accordance with the provisions of
- the INSTALL Source Code License Agreement.
-
- INSTALL is Copyright(C) 1987-1990 by Knowledge Dynamics Corp
- Highway Contract 4 Box 185-H, Canyon Lake, TX (USA) 78133-3508
- 512-964-3994 (Voice) 512-964-3958 (24-hr FAX)
-
- All rights reserved worldwide.
-
- ===============================================================================
-
- FILENAME:
- expand.c
-
- AUTHOR:
- eric jon heflin
-
- PUBLIC FUNCTIONS:
- lz_init() - allocate and initializes memory for decompressor
- lz_bye() - free all allocated memory
- expand() - decompress file
-
- LOCAL FUNCTIONS:
- s_read() - reads file into buffer
- s_write() - writes file
- lzd() - data compression routine
- hash_init() - initialize lzw table
- get_code() - reads a code from the internal buffer
- put_char() - puts a character into output buffer
-
- DESCRIPTION:
- This file implements standard Limpel-Ziv-Welch decompression. If you
- plan on making any changes to this file, be advised: This file has been
- subjected to extensive data flow analysis, profiling, and hand
- optimization. Even a minor change could significantly (as in double or
- triple) the execution time of the decompressor.
-
- REVISION HISTORY:
- DATE: AUTHOR: DESCRIPTION OF CHANGES:
- 900102 ejh Cosmetic changes.
-
- ==============================================================================*/
-
- #include "install.h"
-
- #if defined(InstantC)
- #define assert(c) if(!(c)) _()
- #include <sys\types.h>
- #include <sys\stat.h>
- #include <dos.h>
- #include <io.h>
- #include <process.h>
- #elif defined(__TURBOC__)
- #include <sys\types.h>
- #include <sys\stat.h>
- #include <dos.h>
- #include <assert.h>
- #include <alloc.h>
- #include <io.h>
- #include <process.h>
- #elif defined(__MICROSOFTC__)
- #include <sys\types.h>
- #include <sys\stat.h>
- #include <dos.h>
- #include <malloc.h>
- #include <assert.h>
- #include <io.h>
- #include <process.h>
- #elif defined(LATTICE)
- #include <assert.h>
- #include <types.h>
- #include <stat.h>
- #undef LATTICE
- #include <dos.h>
- #define LATTICE
- #endif
- #include <stdio.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <string.h>
-
- /* valid bytes for the 'technique' file header field */
- #define NONE 1 /* file is not compressed */
- #define LZ 2 /* file is compressed using lz coding */
- #define DELETE 9 /* file is marked for deletion */
-
- /* valid actions for s_read & s_write upon failure */
- #define ABORT 1
- #define IGNORE 0
-
- /* max number of an unsigned word on this machine */
- #define MAX_WORD (0xffff)
-
- #define IN_BUF_SIZE (8192)
- #define OUT_BUF_SIZE (8192)
-
- #define INBUFSIZ (IN_BUF_SIZE - 10)
- #define OUTBUFSIZ (OUT_BUF_SIZE - 10)
- #define MEMERR 2
- #define IOERR 1
- #define MAXBITS 13
- #define CLEAR 256 /* clear code */
- #define Z_EOF 257 /* end of file marker */
- #define FIRST_FREE 258 /* first free code */
- #define MAXMAX 8192 /* max code + 1 */
-
- /* interval at which to check ratio */
- #define CHECKGAP 4000
- #define NEXT_USE 1
- #define FIRST_USE 2
- #define FOUND 0
-
- #define STACKSIZE 4000
-
- typedef struct
- {
- word next;
- byte z_ch;
- } element_t;
-
- /* local function protos */
- static int s_read(int file, byte *work_buf, int len, int action);
- static int lzd(project_t *, byte *, int, int, unsigned short, unsigned short);
- static void hash_init(void);
- static word get_code(void);
- static void put_char(project_t *, byte);
-
- /* local vars */
- static unsigned short our_c_crc, our_o_crc;
- static word sp;
- word *stack;
- static byte *out_buf; /* output buffer */
- static byte *in_buf; /* input buffer */
- static element_t *work_buf; /* defined in either main.c or lib.c */
- static word cur_code;
- static word old_code;
- static word in_code;
- static word buf_size; /* sizeof work_buffer */
- static word free_code;
- static int nbits;
- static word max_code;
- static byte fin_char;
- static byte k;
- /* used to mask unneeded bits off a code */
- static word masks[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff};
-
- static file_t *in_file;
- static long written;
-
- /* offset (in bits) within input buffer array */
- static word bit_offset;
- /* offset (in bytes) within output buffer array */
- static word output_offset;
- /* global file handles */
- static int input, output;
- /* TRUE if memory already allocated */
- int done;
-
- /* local macros to implement a 16-bit wide stack */
- #define push(x) {stack[sp++]=(x);if(sp>=STACKSIZE)error("Stack overflow in expand()");}
- #define pop() (stack[--sp])
-
- void lz_init(void)
- { /* lz_init */
- /* size of work_buf */
- if (done)
- error("lz_init: Diagnostic error, memory already allocated");
- work_buf = (element_t *) smart_calloc(MAXMAX + 10, sizeof(element_t), "expand_init: Unable to allocate work_buf");
- buf_size = (MAXMAX + 10) * sizeof(element_t);
- stack = (word *) smart_calloc(sizeof(word), STACKSIZE + 20, "expand_init: Unable to allocate stack");
- out_buf = smart_calloc(1, OUTBUFSIZ, "expand_init: Unable to allocate out_buf");
- in_buf = smart_calloc(1, INBUFSIZ, "expand_init: Unable to allocate in_buf");
- done = TRUE;
- } /* lz_init */
-
-
- void lz_bye(void)
- { /* lz_bye */
- if (work_buf != NULL)
- free(work_buf);
- if (stack != NULL)
- free(stack);
- if (out_buf != NULL)
- free(out_buf);
- if (in_buf != NULL)
- free(in_buf);
- work_buf = NULL;
- stack = NULL;
- out_buf = NULL;
- in_buf = NULL;
- done = FALSE;
- } /* lz_bye */
-
- static int lzd(project_t *project, byte *in_name, int in, int out, unsigned short c_crc, unsigned short o_crc)
- { /* lzd */
- word byte_offset;
- word intrabyte_offset;
- input = in;
- output = out;
- nbits = 9;
- max_code = 512;
- free_code = FIRST_FREE;
- sp = 0;
- bit_offset = 0;
- output_offset = 0;
-
- /* some funcs depend on cleared memory */
- memset(in_buf, 0, INBUFSIZ);
- memset(out_buf, 0, OUTBUFSIZ);
- memset(stack, 0, STACKSIZE);
- memset(work_buf, 0, buf_size);
- our_c_crc = our_o_crc = 0xFFFF;
- if (c_crc)
- ; /* quiet lint */
-
- /* fill buffer before first call to get_code */
- s_read(input, in_buf, INBUFSIZ, IGNORE);
-
- hash_init(); /* initialize work_buf */
-
- loop:
- byte_offset = bit_offset / 8; /* offset w/i in buffer */
- intrabyte_offset = bit_offset % 8; /* offset w/i byte */
- bit_offset += nbits;
-
- assert(nbits>=9&&nbits<=13);
-
- if (byte_offset >= INBUFSIZ - 5)
- {
- #ifdef COMP_CRC
- our_c_crc = updcrc(our_c_crc, in_buf, byte_offset);
- #endif
-
- /* rotate remaining codes in input buffer before next read */
- memcpy(in_buf, in_buf + byte_offset, INBUFSIZ - byte_offset);
- /* read new data */
- s_read(input, in_buf + INBUFSIZ - byte_offset, byte_offset, IGNORE);
- /* update offsets */
- byte_offset = 0;
- bit_offset = intrabyte_offset + nbits;
- }
-
- cur_code = in_buf[byte_offset] | (in_buf[byte_offset + 1] << 8);
-
- if (intrabyte_offset != 0)
- {
- /* shift next_byte right by intrabyte_offset bits */
- /* and shift those bits right into first_word; */
- cur_code = (cur_code >> intrabyte_offset) | ((in_buf[byte_offset + 2]) << (16 - intrabyte_offset));
- }
- cur_code &= masks[nbits];
- if (cur_code == Z_EOF)
- {
- if (output_offset != 0)
- {
- if (written + output_offset > in_file->o_size)
- output_offset = (word) (in_file->o_size - written);
- assert(written+output_offset<=in_file->o_size);
- if (output != -2)
- smart_write(project->out_drive, out_buf, output_offset, output);
- written += output_offset;
- our_o_crc = updcrc(our_o_crc, out_buf, output_offset);
- }
- if (our_o_crc != o_crc)
- {
- wputs(yes_w, "The compressed file %c:%s has been damaged.", project->in_drive, in_name);
- wputs(yes_w, NULL);
- wputs(yes_w, "You may either skip this file and attempt to install the remaining");
- wputs(yes_w, "files or abort the installation process.");
- wputs(yes_w, NULL);
- wputs(yes_w, "Do you wish to skip this file (Y/N)?");
- if (!put_yes(yes_w))
- say_bye();
- else
- {
- sputs(" Skipping: ");
- sputs(in_name);
- sputs("\n");
- }
- return -1;
- }
- #ifdef COMP_CRC
- our_c_crc = updcrc(our_c_crc, in_buf, bit_offset/8+1);
- if(our_c_crc != c_crc)
- error("Compressed input file is corrupted");
- #endif
- return 0;
- }
-
- assert(nbits>=9&&nbits<=13);
-
- if (cur_code == CLEAR)
- {
- hash_init();
- old_code = cur_code = get_code();
- fin_char = k = (byte) old_code;
- put_char(project, k);
- goto loop;
- }
-
- in_code = cur_code;
- if (cur_code >= free_code)
- { /* if code not in table (k<w>k<w>k) */
- cur_code = old_code; /* previous code becomes current */
- push(fin_char);
- }
-
- while (cur_code > 255)
- { /* if code, not character */
- push(work_buf[cur_code].z_ch); /* push suffix char */
- cur_code = work_buf[cur_code].next; /* <w> := <w>.code */
- }
-
- assert(nbits>=9&&nbits<=13);
-
- k = fin_char = (byte) cur_code;
- push(k);
- while (sp != 0)
- {
- if (output_offset >= OUTBUFSIZ)
- {
- /* output buffer is full */
- assert(written+output_offset<=in_file->o_size);
- if (output != -2)
- smart_write(project->out_drive, out_buf, output_offset, output);
- written += output_offset;
- /* calculate new crc based on old crc and new data */
- our_o_crc = updcrc(our_o_crc, out_buf, output_offset);
- /* reset output buffer pointer */
- output_offset = 0;
- }
- assert(output_offset<OUTBUFSIZ);
- /* now place char in output buffer */
- out_buf[output_offset++] = (byte) pop();
- }
-
- assert(nbits>=9&&nbits<=13);
- assert(free_code<=MAXMAX+1);
- work_buf[free_code].z_ch = k; /* save suffix char */
- work_buf[free_code].next = old_code; /* save prefix code */
-
- if (++free_code >= max_code && nbits < MAXBITS)
- {
- /* increase the code size */
- nbits++;
- assert(nbits>=9&&nbits<=13);
- max_code <<= 1; /* double max_code */
- }
-
- old_code = in_code;
-
- assert(nbits>=9&&nbits<=13);
- goto loop;
- } /* lzd */
-
- void expand(project_t *project, file_t *file)
- { /* expand */
- int in = -1, out = -1;
- int l;
- byte out_file[100], temp_file[100];
- byte pa[100], dr[5];
- sp = 0;
-
- in_file = file;
- written = 0l;
-
- if (!file->expand || file->c_size == 0 || file->damaged)
- {
- /* file was not compressed, or is damaged, no work to be done */
- return;
- }
-
- if (!file->abs)
- sprintf(out_file, "%c:%s%s", project->out_drive, project->subdir, file->out_fname);
- else
- strcpy(out_file, file->out_fname);
- parse_file(out_file, dr, pa, NULL, NULL);
- l = strlen(pa);
- if ((l >= 1 && pa[l - 1] != '\\') || l == 0)
- strcat(pa, "\\");
- l = strlen(dr);
- if (!file->abs)
- sprintf(temp_file, "%c:%sTEMP.$$$", project->out_drive, pa);
- else
- {
- if (l > 0)
- sprintf(temp_file, "%c:%sTEMP.$$$", dr[0], pa);
- else
- sprintf(temp_file, "%c:%sTEMP.$$$", project->out_drive, pa);
- }
-
- in = smart_open(temp_file, O_RDONLY | O_BINARY, 0);
-
- if (file->append && exists(out_file))
- {
- /* open file for append access */
- out = smart_open(out_file, O_BINARY | O_APPEND | O_WRONLY, S_IWRITE | S_IREAD);
- smart_seek(out, 0l, SEEK_END, out_file);
- }
- else
- {
- /* erase any existing file */
- if (exists(out_file))
- remove(out_file);
- out = smart_open(out_file, O_BINARY | O_CREAT | O_WRONLY, S_IWRITE | S_IREAD);
- }
- if (lzd(project, file->in_fname, in, out, file->c_crc, file->o_crc) == -1)
- {
- /* damaged file */
- file->damaged = TRUE;
- remove(out_file);
- smart_close(in, temp_file);
- smart_close(out, out_file);
- remove(out_file);
- remove(temp_file);
- return;
- }
- while (chgfilet(out, file->time) == -1)
- {
- byte *s;
- if((s = dosprob(NULL)) != NULL)
- wputs(retry_w, s);
- wputs(retry_w, "Unable to change time/date information: %s", out_file);
- put_retry(retry_w);
- }
-
- smart_close(out, temp_file);
- smart_close(in, out_file);
- remove(temp_file);
- } /* expand */
-
-
- static void hash_init()
- { /* hash_init */
- nbits = 9;
- max_code = 512;
- free_code = FIRST_FREE;
- } /* hash_init */
-
- /*
- * Reads a code from internally managed buffer. The buffer is regarded
- * as a bit-stream of codes potentially interdispursed by lz commands
- * clear and eof.
- */
-
- static word get_code()
- { /* get_code */
- word first_word; /* first 16 bits in buffer */
- word byte_offset;
- byte next_byte; /* next 8 bits in buffer */
- word intrabyte_offset; /* offset within byte */
-
- intrabyte_offset = bit_offset % 8;
- byte_offset = bit_offset / 8;
- bit_offset = bit_offset + nbits;
-
- assert(nbits>=9&&nbits<=13);
-
- if (byte_offset >= INBUFSIZ - 5)
- {
- #ifdef COMP_CRC
- our_c_crc = updcrc(our_c_crc, in_buf, byte_offset);
- #endif
-
- /* rotate remaining codes in input buffer before next read */
- memcpy(in_buf, in_buf + byte_offset, INBUFSIZ - byte_offset);
- /* read new data */
- s_read(input, in_buf + INBUFSIZ - byte_offset, byte_offset, IGNORE);
- /* update offsets */
- byte_offset = 0;
- bit_offset = intrabyte_offset + nbits;
- }
-
- first_word = in_buf[byte_offset];
- first_word = first_word | ((in_buf[byte_offset + 1]) << 8);
- next_byte = in_buf[byte_offset + 2];
- if (intrabyte_offset != 0)
- {
- /* shift next_byte right by intrabyte_offset bits */
- /* and shift those bits right into first_word; */
- first_word = (first_word >> intrabyte_offset) | (((word) next_byte) << (16 - intrabyte_offset));
- }
- return first_word & masks[nbits];
- } /* get_code */
-
-
- static void put_char(project_t *project, byte c)
- { /* put_char */
- if (output_offset >= OUTBUFSIZ)
- {
- /* output buffer is full */
- assert(written+output_offset<=in_file->o_size);
- if (output != -2)
- smart_write(project->out_drive, out_buf, output_offset, output);
- written += output_offset;
- /* calculate new crc based on old crc and new data */
- our_o_crc = updcrc(our_o_crc, out_buf, output_offset);
- /* reset output buffer pointer */
- output_offset = 0;
- }
- assert(output_offset<OUTBUFSIZ);
- /* now place char in output buffer */
- out_buf[output_offset++] = c;
- } /* put_char */
-
- static int s_read(int file, byte *work_buf, int len, int action)
- { /* s_read */
- byte *s;
- word error_code;
- int bytes_read = read(file, work_buf, len);
-
- if (bytes_read < len && action == ABORT)
- {
- if ((s = dosprob(&error_code)) != NULL)
- wputs(error_w, s);
- wputs(error_w, "Unable to read file: %s", file);
- put_error(error_w);
- }
- return bytes_read;
- } /* s_read */
-
- /* end-of-file */
-