[comp.sources.misc] v02i087: "Stripped" 16-bit uncompress

uucpa@gamma.UUCP (UNIX-to-UNIX Copy) (04/04/88)

Submitted-By: "UNIX-to-UNIX Copy" <uucpa@gamma.UUCP>

Archive-Name: ucomp16


comp.sources.misc: Volume 2, Issue 87
Submitted-By: "UNIX-to-UNIX Copy" <uucpa@gamma.UUCP>
Archive-Name: ucomp16

The following is a stripped uncompress derived by rote from
compress 3.x.  I did not keep the proper headers for this file
to give proper credit to the authors since what i was trying to do
was to get the 16 bit decompression on a machine that simply would
not allow the resultant executable size.

MY APLOLOGIES AHEAD OF TIME!!!!!!!!

this conversion should be modified to include the original
notices and things. and is only published to fill the gap
on the smaller machines that can't handle the regular compress
software.

sorry if this Tee 's anyone off.

ron tribble
....mibte!ccd700!ron

echo x - ucomp16.c
sed 's/^X//' >ucomp16.c <<'*-*-END-of-ucomp16.c-*-*'
X#define PBITS 16
X#define BITS PBITS
X
Xunsigned	char magic_header[] = { 
X	"\037\235" };	/* 1F 9D */
X
X/* Defines for third byte of header */
X#define BIT_MASK	0x1f
X#define BLOCK_MASK	0x80
X/* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
Xa fourth header byte (for expansion).
X*/
X#define INIT_BITS 9		/* initial number of bits/code */
X
X#include <stdio.h>
X
Xint n_bits;				/* number of bits/code */
Xint maxbits = BITS;			/* user settable max # bits/code */
Xlong	int maxcode;			/* maximum code, given n_bits */
Xlong	int maxmaxcode = 1 << BITS;	/* should NEVER generate this code */
X# define MAXCODE(n_bits)	((1 << (n_bits)) - 1)
X
X/*
X* One code could conceivably represent (1<<BITS) characters, but
X* to get a code of length N requires an input string of at least
X* N*(N-1)/2 characters.  With 5000 chars in the stack, an input
X* file would have to contain a 25Mb string of a single character.
X* This seems unlikely.
X*/
X# define MAXSTACK    8000		/* size of output stack */
X
Xunsigned short tab_prefix [69001];
Xunsigned	char  	tab_suffix[1<<BITS];	/* last char in this entry */
X
Xlong	int free_ent = 0;			/* first unused entry */
Xint exit_stat = 0;
X
Xlong	int getcode();
X
X/*
X* block compression parameters -- after all codes are used up,
X* and compression rate changes, start over.
X*/
Xint block_compress = BLOCK_MASK;
Xint clear_flg = 0;
X/*
X* the next two codes should not be changed lightly, as they must not
X* lie within the contiguous general code space.
X*/
X#define FIRST	257	/* first free entry */
X#define	CLEAR	256	/* table clear output code */
X
Xmain()
X{
X	if(maxbits < INIT_BITS) maxbits = INIT_BITS;
X	if (maxbits > BITS) maxbits = BITS;
X	maxmaxcode = 1 << maxbits;
X
X	exit_stat = 0;
X	/* Check the magic number */
X	if ((getchar() != (magic_header[0] & 0xFF))
X	    || (getchar() != (magic_header[1] & 0xFF))) {
X		fprintf(stderr,"not in compressed format\n");
X		exit(1);
X	}
X	maxbits = getchar();	/* set -b from file */
X	block_compress = maxbits & BLOCK_MASK;
X	maxbits &= BIT_MASK;
X	maxmaxcode = 1 << maxbits;
X	if(maxbits > BITS) {
X		fprintf(stderr,
X		    "compressed with %d bits, can only handle %d bits\n",
X		    maxbits, BITS);
X		exit(1);
X	}
X	decompress();
X	exit(exit_stat);
X}
Xunsigned	char rmask[9] = {
X	0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
Xdecompress() {
X	register int stack_top = MAXSTACK;
X	register long	int code, oldcode, incode;
X	register int finchar;
X	char stack[MAXSTACK];
X
X	/*
X* As above, initialize the first 256 entries in the table.
X*/
X	maxcode = MAXCODE(n_bits = INIT_BITS);
X	for ( code = 255; code >= 0; code-- ) {
X		tab_prefix[code] = 0;
X		tab_suffix[code] = (unsigned	char)code;
X	}
X	free_ent = ((block_compress) ? FIRST : 256 );
X
X	finchar = oldcode = getcode();
X	putchar( (char)finchar );		/* first code must be 8 bits = char */
X
X	while ( (code = getcode()) != -1 ) {
X
X		if ( (code == CLEAR) && block_compress ) {
X			for ( code = 255; code > 0; code -= 4 ) {
X				tab_prefix [code-3] = 0;
X				tab_prefix [code-2] = 0;
X				tab_prefix [code-1] = 0;
X				tab_prefix [code] = 0;
X			}
X			clear_flg = 1;
X			free_ent = FIRST - 1;
X			if ( (code = getcode ()) == -1 )	/* O, untimely death! */
X				break;
X		}
X		incode = code;
X		/*
X* Special case for KwKwK string.
X*/
X		if ( code >= free_ent ) {
X			stack[--stack_top] = finchar;
X			code = oldcode;
X		}
X
X		/*
X* Generate output characters in reverse order
X*/
X		while ( code >= 256 ) {
X			stack[--stack_top] = tab_suffix[code];
X			code = tab_prefix[code];
X		}
X		stack[--stack_top] = finchar = tab_suffix[code];
X
X		/*
X* And put them out in forward order
X*/
X		for ( ; stack_top < MAXSTACK; stack_top++ )
X			putchar(stack[stack_top]);
X		if (ferror(stdout))
X			writeerr ( );
X		stack_top = MAXSTACK;
X
X		/*
X* Generate the new entry.
X*/
X		if ( (code=free_ent) < maxmaxcode ) {
X			tab_prefix[code] = (unsigned short)oldcode;
X			tab_suffix[code] = finchar;
X			free_ent = code+1;
X		}
X		/*
X* Remember previous code.
X*/
X		oldcode = incode;
X	}
X	fflush( stdout );
X	if(ferror(stdout))
X		writeerr();
X}
X
X
X/*****************************************************************
X* TAG( getcode )
X*
X* Read one code from the standard input.  If EOF, return -1.
X* Inputs:
X* 	stdin
X* Outputs:
X* 	code or -1 is returned.
X*/
X
Xlong	int
Xgetcode() {
X	/*
X* On the VAX, it is important to have the register declarations
X* in exactly the order given, or the asm will break.
X*/
X	register long	int code;
X	static int offset = 0, size = 0;
X	static unsigned	char buf[BITS];
X	register int r_off, bits;
X	register unsigned	char *bp = buf;
X
X	if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) {
X		/*
X* If the next entry will be too big for the current code
X* size, then we must increase the size.  This implies reading
X* a new buffer full, too.
X*/
X		if ( free_ent > maxcode ) {
X			n_bits++;
X			if ( n_bits == maxbits )
X				maxcode = maxmaxcode;	/* won't get any bigger now */
X			else
X				maxcode = MAXCODE(n_bits);
X		}
X		if ( clear_flg > 0) {
X			maxcode = MAXCODE (n_bits = INIT_BITS);
X			clear_flg = 0;
X		}
X		size = fread( buf, 1, n_bits, stdin );
X		if ( size <= 0 )
X			return -1;			/* end of file */
X		offset = 0;
X		/* Round size down to integral number of codes */
X		size = (size << 3) - (n_bits - 1);
X	}
X	r_off = offset;
X	bits = n_bits;
X	/*
X* Get to the first byte.
X*/
X	bp += (r_off >> 3);
X	r_off &= 7;
X	/* Get first part (low order bits) */
X	code = (*bp++ >> r_off);
X	bits -= (8 - r_off);
X	r_off = 8 - r_off;		/* now, offset into code word */
X	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X	if ( bits >= 8 ) {
X		code |= *bp++ << r_off;
X		r_off += 8;
X		bits -= 8;
X	}
X	/* high order bits. */
X	code |= (*bp & rmask[bits]) << r_off;
X	offset += n_bits;
X
X	return code;
X}
X/*****************************************************************
X* TAG( writeerr )
X*
X* Exits with a message.  We only check for write errors often enough
X* to avoid a lot of "file system full" messages, not on every write.
X* ferror() check after fflush will catch any others (I trust).
X*
X*/
X
Xwriteerr()
X{
X	exit ( 1 );
X}
*-*-END-of-ucomp16.c-*-*
exit