#ifndef LINT static char sccsid[]="@(#) lzd.c 2.6 88/01/30 20:39:18"; #endif /* LINT */ /*********************************************************************/ /* This file contains two versions of the lzd() decompression routine. The default is to use a fast version coded by Ray Gardner. If the symbol SLOW_LZD is defined, the older slower one is used. I have tested Ray's code and it seems to be portable and reliable. But if you suspect any problems you can define SLOW_LZD for your system in options.h and cause the older code to be used. --R.D. */ /*********************************************************************/ #include "options.h" #include "zoo.h" #include "zooio.h" #include "various.h" #include "zoofns.h" /* function definitions */ #include "zoomem.h" #include "debug.h" #include "assert.h" #include "lzconst.h" #ifndef SLOW_LZD /* Extensive modifications for speed by Ray Gardner ** Public domain by Raymond D. Gardner 9/26/88 ** ** I apologize for the comments being so dense in places as to impair ** readability, but some of the stuff isn't very obvious and needs ** some explaining. I am also sorry for the messy control structure ** (quite a few labels and goto's) and very long lzd() function, but ** I don't know how to do this any other way without loss of speed. ** ** Ray Gardner ** 6374 S. Monaco Ct. ** Englewood, CO 80111 */ #ifdef ANSI_HDRS # include /* to get memcpy */ #else VOIDPTR memcpy(); #endif #define STACKSIZE 4000 /* allows for about 8Mb string in worst case? */ /* stack grows backwards in this version, using pointers, not counters */ static char *stack; static char *stack_pointer; static char *stack_lim; void init_dtab PARMS((void)); unsigned rd_dcode PARMS((void)); /* void wr_dchar (char); */ /* now a macro */ void ad_dcode PARMS((void)); #ifdef FILTER /* to send data back to zoofilt */ extern unsigned int filt_lzd_word; #endif /* FILTER */ void xwr_dchar PARMS ((char)); static int firstchar PARMS ((int)); static void cbfill PARMS ((void)); /* wr_dchar() is a macro for speed */ #define wr_dchar(c) { \ if (outbufp= 9 && nbits <= 13); if (byte_offset >= INBUFSIZ - 5) { int space_left; assert(byte_offset >= INBUFSIZ - 5); debug((printf ("lzd: byte_offset near end of buffer\n"))) bit_offset = ofs_inbyte + nbits; space_left = INBUFSIZ - byte_offset; ptrb = byte_offset + in_buf_adr; /* point to char */ ptra = in_buf_adr; /* we now move the remaining characters down buffer beginning */ debug((printf ("rd_dcode: space_left = %d\n", space_left))) while (space_left > 0) { *ptra++ = *ptrb++; space_left--; } assert(ptra - in_buf_adr == ptrb - (in_buf_adr + byte_offset)); assert(space_left == 0); if (BLOCKREAD (in_f, ptra, byte_offset) == -1) prterror ('f', "I/O error in lzd:rd_dcode.\n"); byte_offset = 0; } ptra = byte_offset + in_buf_adr; /* NOTE: "word = *((int *) ptra)" would not be independent of byte order. */ word = (unsigned char) *ptra; ptra++; word = word | ( ((unsigned char) *ptra) << 8 ); ptra++; nextch = *ptra; if (ofs_inbyte != 0) { /* shift nextch right by ofs_inbyte bits */ /* and shift those bits right into word; */ word = (word >> ofs_inbyte) | (((unsigned)nextch) << (16-ofs_inbyte)); } return (word & masks[nbits]); } /* rd_dcode() */ void init_dtab() { nbits = 9; max_code = 512; free_code = FIRST_FREE; } /* By making wr_dchar() a macro and calling this routine only on buffer ** full condition, we save a lot of function call overhead. ** We also use pointers instead of counters for efficiency (in the macro). */ void xwr_dchar (ch) char ch; { if (outbufp >= outbuflim) { /* if buffer full */ if (BLOCKWRITE (out_f, out_buf_adr, outbufp - out_buf_adr) != outbufp - out_buf_adr) prterror ('f', "Write error in lzd:wr_dchar.\n"); addbfcrc(out_buf_adr, outbufp - out_buf_adr); /* update CRC */ outbufp = out_buf_adr; /* restore empty buffer */ } assert(outbufp - out_buf_adr < OUTBUFSIZ); *outbufp++ = ch; } /* wr_dchar() */ /* Code buffer fill routines ** ** We use a separate function for each code size. ** Each function unpacks 8 codes from a packed buffer (f) ** to an unpacked buffer (t) ** A lot of code space, but really speeds up bit picking. */ static unsigned char f[13]; /* must be unsigned for right shifts */ static unsigned t[8]; static void cb9fill () { t[0] = (f[0] ) | ((f[1] & 1) << 8); t[1] = (f[1] >> 1) | ((f[2] & 3) << 7); t[2] = (f[2] >> 2) | ((f[3] & 7) << 6); t[3] = (f[3] >> 3) | ((f[4] & 15) << 5); t[4] = (f[4] >> 4) | ((f[5] & 31) << 4); t[5] = (f[5] >> 5) | ((f[6] & 63) << 3); t[6] = (f[6] >> 6) | ((f[7] & 127) << 2); t[7] = (f[7] >> 7) | ((f[8] ) << 1); } static void cb10fill () { t[0] = (f[0] ) | ((f[1] & 3) << 8); t[1] = (f[1] >> 2) | ((f[2] & 15) << 6); t[2] = (f[2] >> 4) | ((f[3] & 63) << 4); t[3] = (f[3] >> 6) | ((f[4] ) << 2); t[4] = (f[5] ) | ((f[6] & 3) << 8); t[5] = (f[6] >> 2) | ((f[7] & 15) << 6); t[6] = (f[7] >> 4) | ((f[8] & 63) << 4); t[7] = (f[8] >> 6) | ((f[9] ) << 2); } static void cb11fill () { t[0] = (f[0] ) | ((f[1] & 7) << 8); t[1] = (f[1] >> 3) | ((f[2] & 63) << 5); t[2] = (f[2] >> 6) | (f[3] << 2) | ((f[4] & 1) << 10); t[3] = (f[4] >> 1) | ((f[5] & 15) << 7); t[4] = (f[5] >> 4) | ((f[6] & 127) << 4); t[5] = (f[6] >> 7) | (f[7] << 1) | ((f[8] & 3) << 9); t[6] = (f[8] >> 2) | ((f[9] & 31) << 6); t[7] = (f[9] >> 5) | ((f[10] ) << 3); } static void cb12fill () { t[0] = (f[0] ) | ((f[1] & 15) << 8); t[1] = (f[1] >> 4) | ((f[2] ) << 4); t[2] = (f[3] ) | ((f[4] & 15) << 8); t[3] = (f[4] >> 4) | ((f[5] ) << 4); t[4] = (f[6] ) | ((f[7] & 15) << 8); t[5] = (f[7] >> 4) | ((f[8] ) << 4); t[6] = (f[9] ) | ((f[10] & 15) << 8); t[7] = (f[10] >> 4) | ((f[11] ) << 4); } static void cb13fill () { t[0] = (f[0] ) | ((f[1] & 31) << 8); t[1] = (f[1] >> 5) | (f[2] << 3) | ((f[3] & 3) << 11); t[2] = (f[3] >> 2) | ((f[4] & 127) << 6); t[3] = (f[4] >> 7) | (f[5] << 1) | ((f[6] & 15) << 9); t[4] = (f[6] >> 4) | (f[7] << 4) | ((f[8] & 1) << 12); t[5] = (f[8] >> 1) | ((f[9] & 63) << 7); t[6] = (f[9] >> 6) | (f[10] << 2) | ((f[11] & 7) << 10); t[7] = (f[11] >> 3) | (f[12] << 5); } /* vector of code buffer fill routines */ void (*cbfillvec[]) PARMS ((void)) = { 0, 0, 0, 0, 0, 0, 0, 0, 0, cb9fill, cb10fill, cb11fill, cb12fill, cb13fill }; /* cbfill -- main code buffer fill routine ** ** moves data from inbuf[] to f[] ** then calls via vector to unpack to t[] ** then moves from t[] to codebuf[] ** A lot of moving around, but still faster than a lot of shifting and ** masking via variables (at least on a micro -- don't know about VAXen) ** Uses memcpy() for block move */ static void cbfill () { char *inbp; inbp = in_buf_adr + bit_offset / 8; codebufp = codebuf; while ( codebufp < codebuflim ) { memcpy((VOIDPTR) f, inbp, nbits); (*cbfillvec[nbits])(); memcpy((VOIDPTR) codebufp, (VOIDPTR) t, 8 * sizeof(unsigned int)); inbp += nbits; codebufp += 8; } bit_offset += nbits * CODEBUF_SIZE; } /* The following is used in the KwKwK case because it's a pretty rare ** case, and doing it this way avoids the overhead of remembering the ** "finchar" (first input character) of every string */ static int firstchar(code) /* find first character of a code */ int code; { while ( code > 255 ) code = head[code]; return code; } int lzd(input_f, output_f) BLOCKFILE input_f, output_f; /* input & output files */ { in_f = input_f; /* make it avail to other fns */ out_f = output_f; /* ditto */ nbits = 9; max_code = 512; free_code = FIRST_FREE; bit_offset = 0; outbuflim = out_buf_adr + OUTBUFSIZ; /* setup out buffer limit */ outbufguard = outbuflim - 12; /* for checking avail. room in outbuf */ /* note must allow for as many characters as we special-case (8) */ /* used 12 for extra fudge factor (Rahul does it, so I can too) */ outbufp = out_buf_adr; /* setup output buffer ptr */ codebufp = codebuflim = &codebuf[CODEBUF_SIZE]; /* code buf ptr & limit */ *codebuflim = CLEAR; /* phony CLEAR sentinel past end of code buffer */ if (BLOCKREAD (in_f, in_buf_adr, INBUFSIZ) == -1) /* fill input buffer */ return(IOERR); if (memflag == 0) { head = (int *) ealloc((MAXMAX+10) * sizeof(int)); tail = (char *) ealloc((MAXMAX+10) * sizeof(char)); stack = (char *) ealloc (sizeof (unsigned) * STACKSIZE + 20); memflag++; } stack_pointer = stack_lim = stack + STACKSIZE; /* setup stack ptr, limit*/ init_dtab(); /* initialize table */ loop: cur_code = *codebufp++; /* get code from code buffer */ goteof: /* special case for CLEAR then Z_EOF, for 0-length files */ if (cur_code == Z_EOF) { debug((printf ("lzd: Z_EOF\n"))) if (outbufp != out_buf_adr) { if (BLOCKWRITE (out_f, out_buf_adr, outbufp - out_buf_adr) != outbufp - out_buf_adr) prterror ('f', "Output error in lzd().\n"); addbfcrc(out_buf_adr, outbufp - out_buf_adr); } #ifdef FILTER /* get next two bytes and put them where zoofilt can find them */ /* nbits known to be in range 9..13 */ bit_offset = ((bit_offset + 7) / 8) * 8; /* round up to next byte */ filt_lzd_word = rd_dcode(); filt_lzd_word |= (rd_dcode() << nbits); filt_lzd_word &= 0xffff; #endif return (0); } assert(nbits >= 9 && nbits <= 13); if (cur_code == CLEAR) { /* was it sentinel or real CLEAR ? */ if ( codebufp > codebuflim ) { /* it was the sentinel */ if ( bit_offset % 8 == 0 && /* if we're on byte boundary and */ /* codesize won't change before codebuf is filled and */ /* codebuf can be filled without running out of inbuf */ free_code + CODEBUF_SIZE < max_code && bit_offset / 8 + (CODEBUF_SIZE * 13 / 8) < INBUFSIZ - 10 ) { codebufoffset = bit_offset; /* remember where we were when */ cbfill(); /* we filled the code buffer */ codebufp = codebuf; /* setup code buffer pointer */ goto loop; /* now go get codes from code buffer */ } /* otherwise, use rd_dcode to get code */ codebufp = codebuflim; /* reset codebuf ptr to sentinel */ cur_code = rd_dcode(); /* get code via rd_dcode() */ if ( cur_code != CLEAR ) /* if it's not CLEAR */ goto got_code; /* then go handle it */ } else { /* else it's really a CLEAR code, not sentinel */ /* reset bit_offset to get next code in input buf after CLEAR code */ bit_offset = codebufoffset + (codebufp - codebuf) * nbits; } codebufp = codebuflim; /* set code buf ptr to sentinel */ debug((printf ("lzd: CLEAR\n"))) init_dtab(); /* init decompression table, etc. */ old_code = cur_code = rd_dcode(); /* get next code after CLEAR */ if (cur_code == Z_EOF) /* special case for 0-length files */ goto goteof; wr_dchar(cur_code); /* write it out */ goto loop; /* and get next code */ } got_code: /* we got a code and it's not a CLEAR */ if (cur_code == Z_EOF) { debug((printf ("lzd: Z_EOF\n"))) if (outbufp != out_buf_adr) { if (BLOCKWRITE (out_f, out_buf_adr, outbufp - out_buf_adr) != outbufp - out_buf_adr) prterror ('f', "Output error in lzd().\n"); addbfcrc(out_buf_adr, outbufp - out_buf_adr); } return (0); } in_code = cur_code; /* save original code */ if (cur_code >= free_code) { /* if code not in table (kkk) */ cur_code = old_code; /* previous code becomes current */ /* push first character of old code */ *--stack_pointer = firstchar(old_code); goto unwind; /* and go "unwind" the current code */ } /* (use general unwind because the stack isn't empty now) */ /* Unwind a code. The basic idea is to use a sort of loop-unrolling ** approach to really speed up the processing by treating the codes ** which represent short strings (the vast majority of codes) as ** special cases. Avoid a lot of stack overflow checking safely. */ if (cur_code > 255) { /* if cur_code is not atomic */ *--stack_pointer = tail[cur_code]; /* push its tail code */ cur_code = head[cur_code]; /* and replace with its head code */ } else { /* else 1-byte string */ if ( outbufp > outbufguard ) /* if outbuf near end, */ goto write_stack; /* write via general routine */ *outbufp++ = cur_code; /* we got space, put char out */ goto add_code; /* add code to table */ } if (cur_code > 255) { /* if cur_code is not atomic */ *--stack_pointer = tail[cur_code]; /* push its tail code */ cur_code = head[cur_code]; /* and replace with its head code */ } else { /* else 2-byte string */ if ( outbufp > outbufguard ) /* if outbuf near end, */ goto write_stack; /* write via general routine */ *outbufp++ = cur_code; /* we got space, put char out, and */ goto move_1_char; /* go move rest of stack to outbuf */ } if (cur_code > 255) { /* if cur_code is not atomic */ *--stack_pointer = tail[cur_code]; /* push its tail code */ cur_code = head[cur_code]; /* and replace with its head code */ } else { /* else 3-byte string */ if ( outbufp > outbufguard ) /* if outbuf near end, */ goto write_stack; /* write via general routine */ *outbufp++ = cur_code; /* we got space, put char out, and */ goto move_2_char; /* go move rest of stack to outbuf */ } /* we handle codes representing strings of 4 thru 8 bytes similarly */ if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 4-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_3_char; } if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 5-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_4_char; } if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 6-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_5_char; } if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 7-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_6_char; } if (cur_code > 255) { *--stack_pointer = tail[cur_code]; cur_code = head[cur_code]; } else { /* 8-byte string */ if ( outbufp > outbufguard ) goto write_stack; *outbufp++ = cur_code; goto move_7_char; } /* Here for KwKwK case and strings longer than 8 bytes */ /* Note we have to check stack here, but not elsewhere */ unwind: while (cur_code > 255) { /* if code, not character */ *--stack_pointer = tail[cur_code]; /* push suffix char */ if (stack_pointer < stack+12) prterror ('f', "Stack overflow in lzd().\n"); cur_code = head[cur_code]; /* head of code is new code */ } /* General routine to write stack with check for output buffer full */ write_stack: assert(nbits >= 9 && nbits <= 13); wr_dchar(cur_code); /* write this code, don't need to stack it first */ while ( stack_pointer < stack_lim ) { wr_dchar(*stack_pointer++); } goto add_code; /* now go add code to table */ /* Here to move strings from stack to output buffer */ /* only if we know we have enough room in output buffer */ /* because (outbufp <= outbufguard) */ move_7_char: *outbufp++ = *stack_pointer++; move_6_char: *outbufp++ = *stack_pointer++; move_5_char: *outbufp++ = *stack_pointer++; move_4_char: *outbufp++ = *stack_pointer++; move_3_char: *outbufp++ = *stack_pointer++; move_2_char: *outbufp++ = *stack_pointer++; move_1_char: *outbufp++ = *stack_pointer++; assert(stack_pointer == stack_lim); /* I haven't tested this! rdg */ /* add_code is now inline to avoid overhead of function call on */ /* each code processed */ add_code: assert(nbits >= 9 && nbits <= 13); assert(free_code <= MAXMAX+1); tail[free_code] = cur_code; /* save suffix char */ head[free_code] = old_code; /* save prefix code */ free_code++; assert(nbits >= 9 && nbits <= 13); if (free_code >= max_code) { if (nbits < MAXBITS) { debug((printf("lzd: nbits was %d\n", nbits))) nbits++; assert(nbits >= 9 && nbits <= 13); debug((printf("lzd: nbits now %d\n", nbits))) max_code = max_code << 1; /* double max_code */ debug((printf("lzd: max_code now %d\n", max_code))) } } old_code = in_code; assert(nbits >= 9 && nbits <= 13); goto loop; } /* lzd() */ #else /* SLOW_LZD defined, so use following instead */ /*********************************************************************/ /* Original slower lzd(). */ /*********************************************************************/ /* Lempel-Ziv decompression. Mostly based on Tom Pfau's assembly language code. The contents of this file are hereby released to the public domain. -- Rahul Dhesi 1986/11/14 */ #define STACKSIZE 4000 struct tabentry { unsigned next; char z_ch; }; void init_dtab PARMS((void)); unsigned rd_dcode PARMS((void)); void wr_dchar PARMS((int)); void ad_dcode PARMS((void)); #ifdef FILTER /* to send data back to zoofilt */ extern unsigned int filt_lzd_word; #endif /* FILTER */ static unsigned stack_pointer = 0; static unsigned *stack; #define push(x) { \ stack[stack_pointer++] = (x); \ if (stack_pointer >= STACKSIZE) \ prterror ('f', "Stack overflow in lzd().\n");\ } #define pop() (stack[--stack_pointer]) extern char *out_buf_adr; /* output buffer */ extern char *in_buf_adr; /* input buffer */ char memflag = 0; /* memory allocated? flag */ extern struct tabentry *table; /* hash table from lzc.c */ static unsigned cur_code; static unsigned old_code; static unsigned in_code; static unsigned free_code; static int nbits; static unsigned max_code; static char fin_char; static char k; static unsigned masks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff }; static unsigned bit_offset; static unsigned output_offset; #ifdef UNBUF_IO #define BLOCKFILE int #define BLOCKREAD read #define BLOCKWRITE blockwrite int read PARMS ((int, VOIDPTR, unsigned)); int write PARMS ((int, VOIDPTR, unsigned)); #else #define BLOCKFILE ZOOFILE #define BLOCKREAD zooread #define BLOCKWRITE zoowrite #endif /* UNBUF_IO */ static BLOCKFILE in_f, out_f; int lzd(input_f, output_f) BLOCKFILE input_f, output_f; /* input & output file handles */ { in_f = input_f; /* make it avail to other fns */ out_f = output_f; /* ditto */ nbits = 9; max_code = 512; free_code = FIRST_FREE; stack_pointer = 0; bit_offset = 0; output_offset = 0; if (BLOCKREAD (in_f, in_buf_adr, INBUFSIZ) == -1) return(IOERR); if (memflag == 0) { table = (struct tabentry *) ealloc((MAXMAX+10) * sizeof(struct tabentry)); stack = (unsigned *) ealloc (sizeof (unsigned) * STACKSIZE + 20); memflag++; } init_dtab(); /* initialize table */ loop: cur_code = rd_dcode(); goteof: /* special case for CLEAR then Z_EOF, for 0-length files */ if (cur_code == Z_EOF) { debug((printf ("lzd: Z_EOF\n"))) if (output_offset != 0) { if (BLOCKWRITE (out_f, out_buf_adr, output_offset) != output_offset) prterror ('f', "Output error in lzd().\n"); addbfcrc(out_buf_adr, output_offset); } #ifdef FILTER /* get next two bytes and put them where zoofilt can find them */ /* nbits known to be in range 9..13 */ bit_offset = ((bit_offset + 7) / 8) * 8; /* round up to next byte */ filt_lzd_word = rd_dcode(); filt_lzd_word |= (rd_dcode() << nbits); filt_lzd_word &= 0xffff; #endif return (0); } assert(nbits >= 9 && nbits <= 13); if (cur_code == CLEAR) { debug((printf ("lzd: CLEAR\n"))) init_dtab(); fin_char = k = old_code = cur_code = rd_dcode(); if (cur_code == Z_EOF) /* special case for 0-length files */ goto goteof; wr_dchar(k); goto loop; } in_code = cur_code; if (cur_code >= free_code) { /* if code not in table (kkk) */ cur_code = old_code; /* previous code becomes current */ push(fin_char); } while (cur_code > 255) { /* if code, not character */ push(table[cur_code].z_ch); /* push suffix char */ cur_code = table[cur_code].next; /* := .code */ } assert(nbits >= 9 && nbits <= 13); k = fin_char = cur_code; push(k); while (stack_pointer != 0) { wr_dchar(pop()); } assert(nbits >= 9 && nbits <= 13); ad_dcode(); old_code = in_code; assert(nbits >= 9 && nbits <= 13); goto loop; } /* lzd() */ /* rd_dcode() reads a code from the input (compressed) file and returns its value. */ unsigned rd_dcode() { register char *ptra, *ptrb; /* miscellaneous pointers */ unsigned word; /* first 16 bits in buffer */ unsigned byte_offset; char nextch; /* next 8 bits in buffer */ unsigned ofs_inbyte; /* offset within byte */ ofs_inbyte = bit_offset % 8; byte_offset = bit_offset / 8; bit_offset = bit_offset + nbits; assert(nbits >= 9 && nbits <= 13); if (byte_offset >= INBUFSIZ - 5) { int space_left; #ifdef CHECK_BREAK check_break(); #endif assert(byte_offset >= INBUFSIZ - 5); debug((printf ("lzd: byte_offset near end of buffer\n"))) bit_offset = ofs_inbyte + nbits; space_left = INBUFSIZ - byte_offset; ptrb = byte_offset + in_buf_adr; /* point to char */ ptra = in_buf_adr; /* we now move the remaining characters down buffer beginning */ debug((printf ("rd_dcode: space_left = %d\n", space_left))) while (space_left > 0) { *ptra++ = *ptrb++; space_left--; } assert(ptra - in_buf_adr == ptrb - (in_buf_adr + byte_offset)); assert(space_left == 0); if (BLOCKREAD (in_f, ptra, byte_offset) == -1) prterror ('f', "I/O error in lzd:rd_dcode.\n"); byte_offset = 0; } ptra = byte_offset + in_buf_adr; /* NOTE: "word = *((int *) ptra)" would not be independent of byte order. */ word = (unsigned char) *ptra; ptra++; word = word | ( ((unsigned char) *ptra) << 8 ); ptra++; nextch = *ptra; if (ofs_inbyte != 0) { /* shift nextch right by ofs_inbyte bits */ /* and shift those bits right into word; */ word = (word >> ofs_inbyte) | (((unsigned)nextch) << (16-ofs_inbyte)); } return (word & masks[nbits]); } /* rd_dcode() */ void init_dtab() { nbits = 9; max_code = 512; free_code = FIRST_FREE; } void wr_dchar (ch) int ch; { if (output_offset >= OUTBUFSIZ) { /* if buffer full */ #ifdef CHECK_BREAK check_break(); #endif if (BLOCKWRITE (out_f, out_buf_adr, output_offset) != output_offset) prterror ('f', "Write error in lzd:wr_dchar.\n"); addbfcrc(out_buf_adr, output_offset); /* update CRC */ output_offset = 0; /* restore empty buffer */ } assert(output_offset < OUTBUFSIZ); out_buf_adr[output_offset++] = ch; /* store character */ } /* wr_dchar() */ /* adds a code to table */ void ad_dcode() { assert(nbits >= 9 && nbits <= 13); assert(free_code <= MAXMAX+1); table[free_code].z_ch = k; /* save suffix char */ table[free_code].next = old_code; /* save prefix code */ free_code++; assert(nbits >= 9 && nbits <= 13); if (free_code >= max_code) { if (nbits < MAXBITS) { debug((printf("lzd: nbits was %d\n", nbits))) nbits++; assert(nbits >= 9 && nbits <= 13); debug((printf("lzd: nbits now %d\n", nbits))) max_code = max_code << 1; /* double max_code */ debug((printf("lzd: max_code now %d\n", max_code))) } } } #endif /* ! SLOW_LZD */