/* * l z d c m 2 . c * * Actual decompression code */ #include "lz.h" /* * These global parameters are read from the compressed file. * The decompressor needs them. */ extern short maxbits; /* settable max # bits/code */ extern short block_compress; extern code_int maxmaxcode; /* * Local variables to the decompressor. */ code_int maxcode; int n_bits; flag clear_flg = FALSE; int offset = 0; int size = 0; #if !vax_asm char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; #endif /* * Big data storage stuff */ char_type stack[MAXSTACK]; #define STACK_TOP (&stack[MAXSTACK]) U_short tab_prefix[1<= 0; code--) { tab_prefix[code] = 0; tab_suffix[code] = (char_type)code; } free_ent = ((block_compress != 0) ? FIRST : 256); finchar = oldcode = getcode(); PUT((char) finchar); /* first code must be 8 bits = char */ while ((code = getcode()) != -1) { if ((code == CLEAR) && block_compress != 0) { for (code = 255; code > 0; code -= 4) { tab_prefix[code-3] = 0; tab_prefix[code-2] = 0; tab_prefix[code-1] = 0; tab_prefix[code] = 0; } clear_flg = TRUE; free_ent = FIRST - 1; if ((code = getcode()) == -1 /* O, untimely death! */ || code == CLEAR) { /* Endfile signal */ break; } } incode = code; /* * Special case for KwKwK string. */ if (code >= free_ent) { #ifdef DEBUG if (stp <= stack) { fprintf(stderr, "Stack overflow in KwKwK\n"); abort(); } #endif *--stp = finchar; code = oldcode; } /* * Generate output characters in reverse order */ #ifdef interdata while (((unsigned long)code) >= ((unsigned long)256)) { #else while (code >= 256) { #endif #ifdef DEBUG if (stp <= stack) { fprintf(stderr, "Stack overflow in generate output\n"); abort(); } #endif *--stp = tab_suffix[code]; code = tab_prefix[code]; } #ifdef DEBUG if (stp <= stack) { fprintf(stderr, "Stack overflow final char\n"); abort(); } #endif *--stp = finchar = tab_suffix[code]; /* * And put them out in forward order */ PUTBUF(stp, STACK_TOP - stp); stp = STACK_TOP; /* * Generate the new entry. */ if ((code = free_ent) < maxmaxcode) { tab_prefix[code] = (U_short) oldcode; tab_suffix[code] = finchar; free_ent = code + 1; } /* * Remember previous code. */ oldcode = incode; } LZ_FLUSH(); } /* * getcode() * * Read one code from the standard input. If EOF, return -1. * Inputs: * stdin (via GET) * Outputs: * code or -1 is returned. */ static char_type buf[BITS]; code_int getcode() { /* * On the VAX (4.2 bsd), it is important to have the register * declarations in exactly the order given, or the asm will break. */ register code_int code; register int r_off, bits; register char_type *bp; bp = buf; if (clear_flg || 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++; if (n_bits == maxbits) maxcode = maxmaxcode; /* won't get bigger now */ else maxcode = MAXCODE(n_bits); } if (clear_flg) { maxcode = MAXCODE(n_bits = INIT_BITS); clear_flg = FALSE; } size = GETBUF(buf, n_bits); #ifdef DEBUG if (debug > 2) dumphex(buf, size); #endif if (size <= 0) { return (-1); /* end of file */ } offset = 0; /* * Round size down to integral number of codes */ size = (size << 3) - (n_bits - 1); } r_off = offset; bits = n_bits; #if vax_asm asm("extzv r10,r9,(r8),r11"); #else /* * Get to the first byte. */ bp += (r_off >> 3); r_off &= 7; /* * Get first part (low order bits) */ #if UCHAR code = (*bp++ >> r_off); #else /* * Don't touch the 0xFF. */ code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xFF; #endif 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) { #if UCHAR code |= *bp++ << r_off; #else code |= (*bp++ & 0xFF) << r_off; #endif r_off += 8; bits -= 8; } /* high order bits. */ #if UCHAR code |= (*bp & rmask[bits]) << r_off; #else code |= (*bp & rmask[bits]) << r_off; #endif /* * End of non-vax (Unix) specific code. */ #endif offset += n_bits; return (code); } #ifdef DEBUG printcodes(dumpfd) FILE *dumpfd; /* * Just print out codes from input file. Mostly for debugging. */ { code_int code; int col, bits; col = 0; bits = n_bits = INIT_BITS; maxcode = MAXCODE(n_bits); free_ent = ((block_compress != 0) ? FIRST : 256); while ((code = getcode()) >= 0) { if ((code == CLEAR) && block_compress) { free_ent = FIRST - 1; clear_flg = TRUE; } else if (free_ent < maxmaxcode) free_ent++; if (bits != n_bits) { fprintf(dumpfd, "\nChange to %d bits\n", n_bits); bits = n_bits; col = 0; } fprintf(dumpfd, "%5d%c", code, (col += 6) >= 74 ? (col = 0, '\n') : ' '); } putc('\n', dumpfd); } dump_tab(dumpfd) FILE *dumpfd; /* * dump string table */ { register char_type *stp; /* Stack pointer */ register int i; register int ent; stp = STACK_TOP; fprintf(dumpfd, "%d %s in string table\n", free_ent, (free_ent == 1) ? "entry" : "entries"); for (i = 0; i < free_ent; i++) { if (isascii(tab_suffix[i]) && isprint(tab_suffix[i])) { fprintf(dumpfd, "%5d: %5d/'%c' \"", i, tab_prefix[i], tab_suffix[i]); } else { fprintf(dumpfd, "%5d: %5d/\\%03o \"", i, tab_prefix[i], tab_suffix[i]); } for (ent = i;;) { *--stp = tab_suffix[ent]; if (ent < FIRST) break; ent = tab_prefix[ent]; } putc('"', dumpfd); while (stp < STACK_TOP) { ent = *stp++ & 0xFF; if (isascii(ent) && isprint(ent)) putc(ent, dumpfd); else { switch (ent) { case '\n': fputs("\\n", dumpfd); break; case '\t': fputs("\\t", dumpfd); break; case '\b': fputs("\\b", dumpfd); break; case '\f': fputs("\\f", dumpfd); break; case '\r': fputs("\\r", dumpfd); break; default: fprintf(dumpfd, "\x%02X", ent); break; } } } fputs("\"\n", dumpfd); stp = STACK_TOP; } } static FILE *foo_fd = NULL; dumphex(buffer, count) register char_type *buffer; register int count; { if (foo_fd == NULL && (foo_fd = fopen("lzdcmp.dmp", "w")) == NULL) abort(); fprintf(foo_fd, "%2d:", count); while (--count >= 0) { fprintf(foo_fd, " %02x", *buffer++ & 0xFF); } fprintf(foo_fd, "\n"); } dumptext(buffer, count) register char_type *buffer; int count; { register int c; if (foo_fd == NULL && (foo_fd = fopen("lzdcmp.dmp", "w")) == NULL) abort(); fprintf(foo_fd, "%2d: \"", count); while (--count >= 0) { c = *buffer++ & 0xFF; if (isascii(c) && isprint(c)) putc(c, foo_fd); else { switch (c) { case '\n': fputs("\\n", foo_fd); break; case '\t': fputs("\\t", foo_fd); break; case '\b': fputs("\\b", foo_fd); break; case '\f': fputs("\\f", foo_fd); break; case '\r': fputs("\\r", foo_fd); break; default: fprintf(foo_fd, "<\x%02X>", c); break; } } } fputs("\"\n", foo_fd); } #endif