[comp.sys.mac.programmer] Text Compression utility

mxmora@unix.SRI.COM (Matt Mora) (03/22/90)

Does anyone have some code that compresses and expands text?
I have a program that needs to use about 200 files that
are between 2k-20k big. The files take up about 1.5 megs.
What I would like to be able to do is read in the compressed
text uncompress it and then display in on the screen.

Does anyone have code that can do this or information
where to get some code?

Thanks






















-- 
___________________________________________________________
Matthew Mora
SRI International                       mxmora@unix.sri.com
___________________________________________________________

gz@spt.entity.com (Gail Zacharias) (03/23/90)

In article <10314@unix.SRI.COM> mxmora@sri-unix.sri.com (Matt Mora) writes:
>Does anyone have some code that compresses and expands text?

Sure.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	makefile.hqx
#	mcompress.c
#	compstream.a
#
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
	echo x - 'README'
	sed 's/^X//' >'README' << 'SHAR_EOF'
XYou should have the following files:
X
Xcompstream.a - (MPW assembler source). A library for doing unix-compatible
X   compression and decompression.  Documentation is near the top of the
X   source.
Xmcompress.c - (MPW C source).  A very simple MPW tool (i.e. no bells and
X   whistles) to demonstrate the use of the compsteam library.  It implements
X   unix-compatible compress/decompress.  'mcompress -H' will print a short
X   help message.
Xmakefile.hqx - a binhex'ed MPW make file for mcompress.
X
X		enjoy,
X		  gz@entity.com
SHAR_EOF
if test 522 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 522 characters)'
fi
fi
if test -f 'makefile.hqx'
then
	echo shar: will not over-write existing file "'makefile.hqx'"
else
	echo x - 'makefile.hqx'
	sed 's/^X//' >'makefile.hqx' << 'SHAR_EOF'
X(This file must be converted with BinHex 4.0)
X
X:#'eKDf9QD@aP!&4&@&40380"!3!!!!$F!!!"I[!kE@0[EA"bCA0c#F3*E@0[EA"
XbCA0c,Q-ZEb"MEfe`Fh4bC@&Y,Q%ZE`d*E'PZDb!YEb"YBfpYF(*PFh-J,@-J*de
X38b!R)#ed)#G08&08*b"YBfpYF(*PFh-ZBbj[)'0[EA"cG(*PB@dZB5j[),B0#5!
XJ)RY$E'PLFQ&bD@9cI805G@jdD@eP,QmL)#*l3daTBR*KFQPPFhe$5@jdCA*QB@0
XP,QmL),B0#5!J)RY$6'PLFQ&bD@9cI90dC%0-D@)ZEb)J)RY$6'PLFQ&bD@9cI80
X6B@jP6'PL,QmL$B60!!!"!!!!!8`!!!"-!!!!-Pd!Q#B!!!)!!!!)!!!0!!!ARb#
Xh!fKN-3!!!!!!!!!!#'eKDf9QD@aPE!)!!!"849K868&$33!!!!!!!!!!!!!!!&4
X&@&40380"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)SMbSJ!!!0`!!!&q!!!!!!!
X#B!!!!!%`!!!!!!!!!!!!"-!!!6!"-!ae!6!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
X!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
X!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%J!#8e[EQ&ME`!!!&!!!6*
XZ!!P0EfjKBfm!!!!"-`!!!!!!!!B!#!!T!!-"8`(p!33!!!&6!IdLL2+L!!!!!!!
X!!!!!!!!!!3!!!!%!!!!"6!!!!%`!!!!b!"45m!Kd!!!!(!!b!!"08&05!!!!#J2
XYrrm!!!!!!"96$Q25:
SHAR_EOF
if test 911 -ne "`wc -c < 'makefile.hqx'`"
then
	echo shar: error transmitting "'makefile.hqx'" '(should have been 911 characters)'
fi
fi
if test -f 'mcompress.c'
then
	echo shar: will not over-write existing file "'mcompress.c'"
else
	echo x - 'mcompress.c'
	sed 's/^X//' >'mcompress.c' << 'SHAR_EOF'
X/* Copyright 1988, Gail Zacharias.  All rights reserved.
X * Permission is hereby granted to copy, reproduce, redistribute or
X * otherwise use this software provided there is no monetary profit
X * gained specifically from its use or reproduction, it is not sold,
X * rented, traded or otherwise marketed, and this copyright notice 
X * and the software version number is included prominently in any copy
X * made.
X * This is mcompress version 1.0.
X *
X * Send comments, suggestions, bug reports (not bloody likely), feature
X * requests, etc. to gz@entity.com.
X *
X */
X
X/* This program demonstrates the use of the compstream library.  It
X   implements a simple unix-compatible compress/decompress MPW tool.
X   It only handles data forks of files for now.
X */
X
X#include <stdio.h>
X
Xextern long compinit(), uncompinit();
Xextern int compwrite(), uncompread(), compclose(), uncompclose();
X
Xstdwrite (stream, size, buf)
X  FILE *stream;
X  char *buf;
X{
X  return (size == fwrite(buf, 1, size, stream)) ? 0 : -1;
X}
X
Xstdread (stream, size, buf)
X  FILE *stream;
X  char *buf;
X{
X  return fread(buf, 1, size, stream);
X}
X
Xmain (argc, argv)
X  char **argv;
X{
X  int block_compress = 1, nbits = 0, header = 1;
X  int decomp = 0;
X  FILE *inf, *outf;
X  char buf[512];
X  long cstream;
X  int n;
X
X  while (--argc > 0 && **++argv == '-') {
X    char *argp = &argv[0][1];
X    if (!*argp) break;
X    do switch (*argp++) {
X      case 'd': decomp = 1; break;
X      case 'C': block_compress = 0; break;
X      case 'n': header = 0; break;
X      case 'b': if (*argp == '\0') {
X                  if (--argc == 0) goto badarg;
X		  argp = *++argv;
X		}
X		nbits = 0;
X		while ('0' <= *argp && *argp <= '9')
X		  nbits = nbits*10 + (*argp++ - '0');
X		if (*argp || nbits < 9 || nbits > 16) goto badarg;
X		break;
X      /* case 'm': macbinary = 1; break; /* not yet */
X      default: goto badarg;
X    } while (*argp);
X  }
X  if (decomp && (!nbits && !header || nbits && header)) goto badarg;
X  if (argc > 2) goto badarg;
X  if (!nbits) nbits = 16;
X  inf = stdin; outf = stdout;
X  if (argc > 0 && strcmp("-", argv[0])) {
X    if (!(inf = fopen(argv[0], "r"))) {
X      fprintf(stderr, "mcompress: can't open \"%s\" for reading\n", argv[0]);
X      return 1;
X    }
X    if (!decomp && argc == 1) {
X      strcpy(buf, argv[0]);
X      strcat(buf, ".Z");
X      if (outf = fopen(buf, "r")) {
X        fclose(outf);
X	fprintf(stderr, "mcompress: will not overwrite \"%s\"\n", buf);
X	return 1;
X      }
X      argv[1] = buf;
X      argc++;
X    }
X  }
X  if (argc > 1 && strcmp("-", argv[1])) {
X    if (!(outf = fopen(argv[1], "w"))) {
X      fprintf(stderr, "mcompress: can't open \"%s\" for writing\n", argv[1]);
X      return 1;
X    }
X  }
X  if (decomp) {
X    if (header) {
X      if (getc(inf) != 037 || getc(inf) != 0235 || (n = getc(inf)) == EOF) {
X        fprintf(stderr, "mcompress: That's not a compressed file!\n");
X        return 1;
X      }
X      nbits = n & 0x1F;
X      block_compress = n & 0x80;
X    }
X    if (!(cstream = uncompinit(n & 0x1F, n & 0x80, stdread, inf))) {
X      fprintf(stderr, "mcompress: not enough memory\n");
X      return 1;
X    }
X    while ((n=uncompread(cstream, sizeof(buf),  buf)) > 0) fwrite(buf, 1, n, outf);
X    uncompclose(cstream);
X  }
X  else {
X    if (header) {
X      buf[0] = 037;
X      buf[1] = 0235;
X      buf[2] = nbits;
X      if (block_compress) buf[2] |= 0x80;
X      stdwrite(outf, 3, buf);
X    }
X    if (!(cstream = compinit(nbits, block_compress, stdwrite, outf))) {
X      fprintf(stderr, "mcompress: not enough memory\n");
X      return 1;
X    }
X    while ((n=fread(buf, 1, sizeof(buf), inf)) > 0) compwrite(cstream, n, buf);
X    compclose(cstream);
X  }
X  fflush(outf);
X  if (ferror(inf) || ferror(outf)) {
X    fprintf(stderr, "mcompress: I/O error\n");
X    return 2;
X  }
X  if (inf != stdin) fclose(inf);
X  if (outf != stdout) fclose(outf);
X  return 0;
X
Xbadarg:
X  fprintf(stderr, "mcompress v1.0, by gz@entity.com.  Usage:\n\
Xmcompress [-dCnH] [-b maxbits] [inputfile [outputfile]]\n\
X -d = Do decompression rather than compression.\n\
X -b maxbits = max number of bits/code.  Must be between 9 and 16.\n\
X      The default is 16.  Smaller values give worse results but require\n\
X      less memory at runtime.\n\
X      This option cannot be given for decompression unless -n is also specified.\n\
X -C = Do not perform 'block compression' (use only for compatibility with\n\
X      obsolete versions of unix compress).\n\
X -n = Do not create/expect compress file header (for obsolete compatibility)\n\
X      If this option is specified for decompression, -b must also be given.\n\
X -H = show this help message\n\
XIf no files are specified, reads standard input and writes standard output.\n\
XIf inputfile is specified but no outputfile, the output defaults as follows:\n\
X  for compress: the input filename with \".Z\" appended.\n\
X  for decompress: standard output.\n\
XOnly the data fork of the input file is processed.\n\
XNote that unlike the unix version, the input file is NOT deleted.\n\
X\n\
XThis is freeware.  If you paid money for this program, you got ripped off.\n");
X  return 2;
X}
X
SHAR_EOF
if test 5060 -ne "`wc -c < 'mcompress.c'`"
then
	echo shar: error transmitting "'mcompress.c'" '(should have been 5060 characters)'
fi
fi
if test -f 'compstream.a'
then
	echo shar: will not over-write existing file "'compstream.a'"
else
	echo x - 'compstream.a'
	sed 's/^X//' >'compstream.a' << 'SHAR_EOF'
X;; Copyright 1988, Gail Zacharias.  All rights reserved.
X;; Permission is hereby granted to copy, reproduce, redistribute or
X;; otherwise use this software provided there is no monetary profit
X;; gained specifically from its use or reproduction, it is not sold,
X;; rented, traded or otherwise marketed, and this copyright notice 
X;; and the software version number is included prominently in any copy
X;; made.
X;; This is compstream version 1.1.
X;;
X;; Send comments, suggestions, bug reports (not bloody likely), feature
X;; requests, etc. to gz@entity.com.
X;;
X
X	load 'FlowCtlMacs.d'
X	case object
X
X	export	(compinit, compwrite, compclose):code
X	export	(uncompinit, uncompread, uncompclose):code
X
X; This is a library for use with MPW C programs.  It implements compression
X; and uncompression compatible with the unix compress/uncompress programs.
X; (But note that the unix programs create files with a 3 byte header which
X; is NOT handled by this library.  It's up to the caller to take care of
X; any headers).
X;
X;The compress module consists of three functions:
X;(1) long compinit (maxbits, block_compress, outputfn, param)
X;   int maxbits, block_compress;
X;   int (*outputfn)();
X;   long param;
X;This function allocates and initializes a compress stream and returns a
X;'stream handle', or 0 if it can't allocate enough memory for its data
X;structures (in which case MemErr contains the error code).
X;maxbits must be an integer between 9 and 16.  Larger values result in
X;  better compression but require more memory.
X;block_compress should be non-zero to do 'block compression'.  This is
X; almost always a win, so use it.  It requires no extra memory.
X;outputfn should be the function to do actual I/O.  It must be a function
X; of 3 arguments:
X;    int outputfn(param, size, buffer)
X;       long param;
X;       int size;
X;       char *buffer;
X;  param will be the same param argument that was passed to compinit.
X;  The function should output the size bytes in buffer, and return a
X;  non-negative value if successful, or a negative value if an error
X;  occured.  The outputfn will not be called again after it returns
X;  an error.
X;(2) int compwrite (cstream, size, buffer)
X;      long cstream;
X;      int size;
X;      char *buffer;
X; This function adds the size bytes in buffer to the compress stream.  cstream
X; is the stream handle returned by compinit.  compwrite returns a non-negative
X; value if successful or a negative value if an error occured.  The value is
X; actually the same as the value of last call to outputfn.  Note that compwrite
X; does buffering and so the calls to compwrite and outputfn are not precisely
X; synchronized - a given call to compwrite might call outputfn several times or
X; it might not call it at all.  Once outputfn returns an error, compwrite will
X; continue to return that error and never call outputfn again.
X;(3) int compclose (cstream)
X;      long cstream;
X; This function writes out any remaining characters in the stream buffer and
X; frees its data structures.  It returns an error code like compwrite.
X
X;The uncompress module consists of three functions:
X;(1) long uncompinit (maxbits, block_compress, inputfn, param)
X;   int maxbits, block_compress;
X;   int (*inputfn)();
X;   long param;
X;This function allocates and initializes an uncompress stream and returns a
X;'stream handle', or 0 if it can't allocate enough memory for its data
X;structures (in which case MemErr contains the error code).
X;maxbits and block_compress must be the values which were used by compress.
X;inputfn should be the function to do actual I/O.  It must be a function
X; of 3 arguments:
X;    int inputfn(param, size, buffer)
X;       long param;
X;       int size;
X;       char *buffer;
X;  param will be the same param argument that was passed to compinit.
X;  The function should try to read size bytes into buffer, and return
X;  the number of bytes actually read.  A negative value means an error
X;  occured, zero means end of file (no more bytes to be read).  The inputfn
X;  will not be called again after it returns a non-positive value.
X;(2) int uncompread (cstream, size, buffer)
X;      long cstream;
X;      int size;
X;      char *buffer;
X; This function stores (at most) size bytes into buffer.  cstream is the
X; stream handle returned by uncompinit.  uncompread returns the number of
X; bytes read, or a non-positive value if there are no more bytes (in which case
X; the value is actually the value returned by the last call to the inputfn).
X; Note that uncompread does buffering and so the calls to uncompread and
X; inputfn are not precisely synchronized - a given call to uncompread might
X; call inputfn several times or it might not call it at all.  Once inputfn
X; returns a non-positive value, uncompread will continue to return that value
X; and never call inputfn again.
X;(3) int uncompclose (cstream)
X;      long cstream;
X; This function frees the data structures used by the stream.  It currently
X; always returns 0 (no errors are possible).
X
X; Edit history
X; 6/3/88 gz	1.1 Started edit history.  Fix in < 16 bit compression.
X
XMemErr	   equ	$220
X_NewPtr    opword $A100+30
X_DisposPtr opword $A000+31
X_Debugger  opword $A9FF
X
X
Xcompress proc
X
XBUFSIZE	equ	512		;Output buffer size.
X
XCHECK_DIST equ	10000
X
Xh		equ	d2
Xh2		equ	d3
Xch		equ	d4
Xlastcode	equ	d5
Xncodes		equ	d6
Xinpos		equ	d7
X
Xcodeptr		equ	a1	;must be a1 (see write8codes)
Xchtab		equ	a2
Xlasttab		equ	a3
Xcodetab		equ	a4
X
Xmyregs		reg	d2-d7/a0-a4
Xmyregsz		equ	44
Xhisregs		reg	d2-d7/a2-a4/a6
Xhisregsz	equ	40	
X
Xfprec	record	0
Xhsize		ds.l	1
Xhshift		ds.w	1
Xrd_cnt		ds.l	1
Xrd_ptr		ds.l	1
Xwr_cnt		ds.w	1
Xwr_ptr		ds.l	1
Xwr_param	ds.l	1
Xwr_fn		ds.l	1
Xwr_error	ds.l	1
Xoutpos		ds.l	1
Xcd_cnt		ds.w	1
Xcd_buf		ds.w	9
Xcheckpos	ds.l	1
Xratio		ds.l	1
Xcodesz		ds.w	1
Xcodelim		ds.l	1
Xmaxcodelim	ds.l	1
Xsavedregs	ds.b	myregsz
Xwr_buf		ds.b	BUFSIZE
Xfprecsz		equ	*
X	endr
X
X	macro
X	writecode.&sz &code
X	subq.w #1,cd_cnt(a6)
X	if# mi then.s
X	  bsr.&default(&sz,'w') write8codes
X	endif#
X	move.w &code,-(codeptr)
X	endm
X
X	macro
X	getchar.&sz &ch,&eoflab
X	subq.l #1,rd_cnt(a6)
X	if# ge then.s
X	  move.l rd_ptr(a6),a0
X	  moveq #0,&ch
X	  move.b (a0)+,&ch
X	  move.l a0,rd_ptr(a6)
X	else#.s
X	  bsr filbuf
X	  move.l d0,&ch
X	  bmi.&default(&sz,'w') &eoflab
X	endif#
X	addq.l #1,inpos
X	endm
X
X	with fprec
X
X;compinit (maxbits, block_compress, outputfn, param)
X	export compinit
Xcompinit
X	move.l #fprecsz,d0
X	_NewPtr
X	if# ne then.s
X	  moveq #0,d0
X	  rts
X	endif#
X	movem.l hisregs,-(sp)
X	move.l a0,a6
X	move.l hisregsz+16(sp),wr_param(a6)
X	move.l hisregsz+12(sp),wr_fn(a6)
X	clr.l wr_error(a6)
X	lea wr_buf(a6),a0
X	move.l a0,wr_ptr(a6)
X	move.w #BUFSIZE,wr_cnt(a6)
X	move.l hisregsz+4(sp),d0	;maxbits
X	moveq #9,d1
X	if# d0 lt.l d1 then.s
X	  move.l d1,d0
X	endif#
X	moveq #16,d1
X	if# d0 gt.l d1 then.s
X	  move.l d1,d0
X	endif#
X	moveq #1,d1
X	lsl.l d0,d1
X	move.l d1,maxcodelim(a6)
X	subq.w #8,d0
X	move.w d0,hshift(a6)
X	lsl.w #2,d0
X	lea hsizes(pc),a0
X	move.l -4(a0,d0.w),hsize(a6)
X	move.l hsize(a6),d1
X	move.l d1,d0
X	_NewPtr
X	bne @memer1
X	move.l a0,chtab
X	add.l d1,d1
X	move.l d1,d0
X	_NewPtr
X	bne @memer2
X	move.l a0,lasttab
X	move.l d1,d0
X	_NewPtr
X	bne @memer3
X	move.l a0,codetab
X	clr.l ratio(a6)
X	moveq #0,inpos
X	move.l #3,outpos(a6)
X	move.l #CHECK_DIST,checkpos(a6)
X	move.w #9,codesz(a6)
X	move.l #$200,codelim(a6)
X	move.l #257,ncodes
X	tst.l hisregsz+8(sp)		;block_compress
X	if# eq then.s
X	  subq.l #1,ncodes
X	  move.l #-1,checkpos(a6)
X	endif#
X	move.l codetab,a0
X	moveq #0,d0
X	move.l hsize(a6),d1
X	lsr.l #1,d1
X	bra.s *+4
X	move.l d0,(a0)+
X	dbf d1,*-2
X	move.w d0,(a0)
X	move.w #8,cd_cnt(a6)
X	lea cd_buf+16(a6),codeptr
X
X	move.l a6,d0
X	bsr filret
X	move.l d0,lastcode
X	bmi @done
X	addq.l #1,inpos
X
X@loop	getchar ch,@done
X	move.l ch,h
X	move.w hshift(a6),d0
X	lsl.w d0,h
X	eor.w lastcode,h
X	move.l h,h2
X	add.l h2,h2
X	move.w 0(codetab,h2.l),d0
X	if# ne then.s
X	  if# ch eq.b 0(chtab,h.l) then.s
X	   if# lastcode eq.w 0(lasttab,h2.l) then.s
X	    move.w d0,lastcode
X	    bra.s @loop
X	   endif#
X	  endif#
X	  moveq #1,d1
X	  tst.l h
X	  if# ne then.s
X	    move.l hsize(a6),d1
X	    sub.l h,d1
X	  endif#
X@search	  sub.l d1,h
X	  if# mi then.s
X	    add.l hsize(a6),h
X	  endif#
X	  move.l h,h2
X	  add.l h2,h2
X	  move.w 0(codetab,h2.l),d0
X	  if# ne then.s
X	    if# ch eq.b 0(chtab,h.l) then.s
X	     if# lastcode eq.w 0(lasttab,h2.l) then.s
X	      move.w d0,lastcode
X	      bra.s @loop
X	     endif#
X	    endif#
X	    ;;This imitates what looks to me like bug in unix compress,
X	    ;;just to stay exactly compatible...
X	    tst.b 0(chtab,h.l)
X	    bne.s @search
X	    tst.w 0(lasttab,h2.l)
X	    bne.s @search
X	  endif#
X	endif#
X	writecode lastcode
X	if# ncodes eq.l codelim(a6) then.s
X	   bsr write8codes
X	   addq.w #1,cd_cnt(a6)
X	   addq.w #1,codesz(a6)
X	   move.l codelim(a6),d0
X	   add.l d0,d0
X	   if# d0 eq.l maxcodelim(a6) then.s
X	     addq.l #1,d0
X	   endif#
X	   move.l d0,codelim(a6)
X	endif#
X	if# ncodes lt.l maxcodelim(a6) then.s
X	  move.w ncodes,0(codetab,h2.l)
X	  move.b ch,0(chtab,h.l)
X	  move.w lastcode,0(lasttab,h2.l)
X	  addq.l #1,ncodes
X	else#.s
X	  if# inpos cc.l checkpos(a6) then.s
X	    move.l inpos,d0
X	    add.l #CHECK_DIST,d0
X	    move.l d0,checkpos(a6)
X	    move.l inpos,d1
X	    moveq #8,d2
X	    sub.w cd_cnt(a6),d2
X	    mulu codesz(a6),d2
X	    lsr.w #3,d2
X	    add.l outpos(a6),d2
X	    bsr ScaledQuo
X	    if# d0 hi.l ratio(a6) then.s
X	      move.l d0,ratio(a6)
X	    else#.s
X	      writecode #256
X	      bsr write8codes
X	      addq.w #1,cd_cnt(a6)
X	      clr.l ratio(a6)
X	      move.l codetab,a0
X	      moveq #0,d0
X	      move.l hsize(a6),d1
X	      lsr.l #1,d1
X	      bra.s *+4
X	      move.l d0,(a0)+
X	      dbf d1,*-2
X	      move.w d0,(a0)
X	      move.l #257,ncodes
X	      move.w #9,codesz(a6)
X	      move.l #$200,codelim(a6)
X	    endif#
X	  endif#
X	endif#
X	move.l ch,lastcode
X	bra @loop
X
X@done	writecode lastcode
X	bsr forcebuf
X	move.l codetab,a0
X	_DisposPtr
X@memer3	move.w MemErr,-(sp)
X	move.l lasttab,a0
X	_DisposPtr
X	move.w (sp)+,MemErr
X@memer2	move.w MemErr,-(sp)
X	move.l chtab,a0
X	_DisposPtr
X	move.w (sp)+,MemErr
X@memer1	move.l wr_error(a6),-(sp)
X	move.w MemErr,-(sp)
X	move.l a6,a0
X	_DisposPtr
X	move.w (sp)+,MemErr
X	move.l (sp)+,d0
X	movem.l (sp)+,hisregs
X	rts
X
Xhsizes:
X	dc.l	887		;9
X	dc.l	1559		;10
X	dc.l	2801		;11
X	dc.l	5003		;12
X	dc.l	9001		;13
X	dc.l	18013		;14
X	dc.l	35023		;15
X	dc.l	69001		;16
X
X;256*(D1/D2) -> D0
XScaledQuo:
X	if# d1 ls.l #$FFFFFF then.s
X	  lsl.l #8,d1
X	else#.s
X	  lsr.l #8,d2
X	  if# eq then.s
X	    moveq #-1,d0
X	    rts
X	  endif#
X	endif#
X	if# d2 ls.l #$FFFF then.s
X	  swap d1
X	  moveq #0,d0
X	  move.w d1,d0
X	  divu d2,d0
X	  swap d0
X	  move.w d0,d1
X	  swap d1
X	  divu d2,d1
X	  move.w d1,d0
X	  rts
X	endif#
X	moveq #0,d0
X	move.w d1,d0
X	swap d0
X	clr.w d1
X	swap d1
X	move.l d2,a0
X	moveq #16-1,d2
X@next	add.l d0,d0
X	addx.l d1,d1
X	if# a0 ls.l d1 then.s
X	  sub.l a0,d1
X	  addq.w #1,d0
X	endif#
X	dbf d2,@next
X	rts
X
Xforcebuf:  ;clobbers codeptr(=a1) and ncodes
X	move.w cd_cnt(a6),ncodes
X	cmp.w #8,ncodes
X	if# ne then.s
X	  subq.w #1,cd_cnt(a6)
X	  if# pl then.s
X	    clr.w -(codeptr)
X	  endif#
X	  bsr.s write8codes
X	  mulu codesz(a6),ncodes	;Correction for really < 8 codes...
X	  lsr.w #3,ncodes
X	  sub.l ncodes,outpos(a6)
X	  add.w ncodes,wr_cnt(a6)
X	  sub.l ncodes,wr_ptr(a6)
X	endif#
X	tst.l wr_error(a6)
X	if# pl then.s
X	  pea wr_buf(a6)
X	  move.l wr_ptr(a6),d0
X	  sub.l (sp),d0
X	  move.l d0,-(sp)
X	  move.l wr_param(a6),-(sp)
X	  move.l wr_fn(a6),a0
X	  jsr (a0)
X	  lea 12(sp),sp
X	  move.l d0,wr_error(a6)
X	endif#
X	rts
X
X;assumes codeptr = a1
Xwrite8codes:
X	movem.l d2-d4,-(sp)
X@rewr	moveq #0,d3
X	move.w codesz(a6),d3
X	move.l wr_ptr(a6),a0
X	add.l d3,wr_ptr(a6)
X	sub.w d3,wr_cnt(a6)
X	if# mi then.s
X	  add.w wr_cnt(a6),d3
X	  pea wr_buf(a6)
X	  move.l (sp),wr_ptr(a6)
X	  lea BUFSIZE,a0
X	  move.w a0,wr_cnt(a6)
X	  sub.w d3,a0
X	  move.l a0,-(sp)
X	  move.l wr_param(a6),-(sp)
X	  tst.l wr_error(a6)
X	  if# pl then.s
X	    move.l wr_fn(a6),a0
X	    jsr (a0)
X	    move.l d0,wr_error(a6)
X	  endif#
X	  lea 12(sp),sp
X	  bra.s @rewr
X	endif#
X	add.l d3,outpos(a6)
X	moveq #0,d1		;d1 = leftover byte
X	moveq #0,d2		;d2 = # bits in this byte
X	subq.w #8,d3		;d3 = codesz - 8
X	moveq #8-1,d4		;d4 = count
X	lea cd_buf+16(a6),codeptr
X@loop	moveq #0,d0
X	move.w -(codeptr),d0
X	lsl.l d2,d0
X	or.b d1,d0
X	add.w d3,d2
X	subq.w #8,d2
X	if# mi then.s
X	  addq.w #8,d2
X	  move.w d0,(codeptr)+
X	  move.b -(codeptr),(a0)+
X	  move.b -(codeptr),d1
X	else#.s
X	  move.l d0,(codeptr)+
X	  move.b -(codeptr),(a0)+
X	  move.b -(codeptr),(a0)+
X	  move.b -(codeptr),d1
X	  subq #1,codeptr
X	endif#
X	dbf d4,@loop
X	lea cd_buf+16(a6),codeptr
X	move.w #8-1,cd_cnt(a6)
X	movem.l (sp)+,d2-d4
X	rts
X
X;compwrite(cstream, size, buf)
X	export compwrite
Xcompwrite:
X	movem.l hisregs,-(sp)
X	move.l hisregsz+4(sp),a6		;cstream
X	movem.l savedregs(a6),myregs
X	move.l a0,-(sp)
X	move.l wr_error(a6),d0
X	bmi.s filret
X	move.l hisregsz+4+12(sp),a0		;buf
X	move.l hisregsz+4+8(sp),d0		;size
X	subq.l #1,d0
X	blt.s filbuf
X	move.l d0,rd_cnt(a6)
X	moveq #0,d0
X	move.b (a0)+,d0
X	move.l a0,rd_ptr(a6)
X	rts
Xfilbuf	move.l wr_error(a6),d0
Xfilret	move.l (sp)+,a0
X	movem.l myregs,savedregs(a6)
X	movem.l (sp)+,hisregs
X	rts
X
X;compclose(cstream)
X	export compclose
Xcompclose:
X	move.l 4(sp),d0
X	if# eq then.s
X	  rts
X	endif#
X	movem.l hisregs,-(sp)
X	move.l d0,a6
X	movem.l savedregs(a6),myregs
X	moveq #-1,d0
X	jmp (a0)
X
X	endwith
X	endproc
X
Xuncompress proc
X
XBUFSIZE	equ	512
X
XSTRSIZE	equ	8000
X
Xlastchar	equ	d2
Xlastcode	equ	d3
Xncodes		equ	d4
Xcodelim		equ	d5
Xcodesz		equ	d6
Xreadcnt		equ	d7
Xcodeptr		equ	a1
Xstrptr		equ	a2
Xchartab		equ	a3
Xcodetab		equ	a4
X
Xmyregs		reg	d1-d7/a0-a4
Xmyregsz		equ	48
Xhisregs		reg	d2-d7/a2-a4/a6
Xhisregsz	equ	40	
X
Xfprec	record	0
Xcodebuf		ds.w	9
Xstrend		ds.l	1
Xmaxcodelim	ds.l	1
Xrd_param	ds.l	1
Xrd_fn		ds.l	1
Xrd_ptr		ds.l	1
Xrd_cnt		ds.w	1
Xrd_error	ds.l	1
Xwr_cnt		ds.l	1
Xwr_ptr		ds.l	1
Xtempbuf		ds.b	16
Xsavedregs	ds.b	myregsz
Xrd_buf		ds.b	BUFSIZE
Xfprecsz		equ	*
X	endr
X
X	with fprec
X
X	macro
X	readcode.&sz &dreg,&eoflab
X	sub.w codesz,readcnt
X	if# mi then.s
X	  bsr.&default(&sz,'w') read8codes
X	  bmi.&default(&sz,'w') &eoflab
X	endif#
X	moveq #0,&dreg
X	move.w -(codeptr),&dreg
X	endm
X
X	macro
X	putchar
X	subq.l #1,wr_cnt(a6)
X	if# ge then.s
X	  move.l wr_ptr(a6),a0
X	  move.b d1,(a0)+
X	  move.l a0,wr_ptr(a6)
X	else#.s
X	  bsr flsbuf
X	endif#
X	endm
X
X
X;uncompinit (maxbits, block_compress, inputfn, param)
X	export uncompinit
Xuncompinit
X	move.l #fprecsz,d0
X	_NewPtr
X	if# ne then.s
X	  moveq #0,d0
X	  rts
X	endif#
X	movem.l hisregs,-(sp)
X	move.l a0,a6
X	move.l hisregsz+16(sp),rd_param(a6)
X	move.l hisregsz+12(sp),rd_fn(a6)
X	clr.w rd_cnt(a6)
X	move.l #1,rd_error(a6)
X	move.l hisregsz+4(sp),d0	;maxbits
X	moveq #9,d1
X	if# d0 lt.l d1 then.s
X	  move.l d1,d0
X	endif#
X	moveq #16,d1
X	if# d0 gt.l d1 then.s
X	  move.l d1,d0
X	endif#
X	moveq #1,d1
X	lsl.l d0,d1
X	move.l d1,maxcodelim(a6)
X	sub.l #256,d1
X	move.l d1,d0
X	_NewPtr
X	bne memer1
X	lea -256(a0),chartab
X	move.l d1,d0
X	add.l d0,d0
X	_NewPtr
X	bne memer2
X	lea -512(a0),codetab
X	move.l #STRSIZE,d0
X	_NewPtr
X	bne memer3
X	lea STRSIZE(a0),strptr
X	move.l strptr,strend(a6)
X
X	moveq #9,codesz
X	move.l #$200,codelim
X	moveq #0,readcnt
X
X	move.l #256,ncodes
X	tst.l hisregsz+8(sp)		;block_compress
X	if# ne then.s
X	  addq.l #1,ncodes
X	  bset #31,readcnt		;use high word for flag...
X	endif#
X
X	move.l a6,d0
X	moveq #-1,d1
X	bsr flsret			;Init wr_cnt and wr_ptr.
X
X	readcode lastcode,@done
X	move.b lastcode,lastchar
X
X	move.l lastcode,d1
X	putchar
X
X@loop	readcode d0,@done
X	if# d0 eq.w #256 then.s
X	 tst.l readcnt
X	 if# mi then.s
X	  move.l d0,ncodes
X	  moveq #9,codesz
X	  move.l #$200,codelim
X	  clr.w readcnt
X	  readcode.s d0,@done
X	 endif#
X	endif#
X	move.l d0,d1
X	if# d0 cc.l ncodes then.s
X	  move.b lastchar,-(strptr)
X	  move.l lastcode,d0
X	endif#
X	move.l d0,lastchar
X	bra.s @get
X@getlp	move.l lastchar,d0
X	move.b 0(chartab,d0.l),-(strptr)
X	add.l d0,d0
X	move.w 0(codetab,d0.l),lastchar
X@get	cmp.w #256,lastchar
X	bcc.s @getlp
X
X	if# ncodes lt.l maxcodelim(a6) then.s
X	  move.l ncodes,d0
X	  move.b lastchar,0(chartab,d0.l)
X	  add.l d0,d0
X	  move.w lastcode,0(codetab,d0.l)
X	  addq.l #1,ncodes
X	endif#
X	move.l d1,lastcode
X	if# ncodes eq.l codelim then.s
X	  addq.w #1,codesz
X	  add.l codelim,codelim
X	  if# codelim eq.l maxcodelim(a6) then.s
X	    addq.l #1,codelim		;make it so this never triggers again
X	  endif#
X	  clr.w readcnt
X	endif#
X	move.b lastchar,d1
X	bra.s @put
X@putlp	move.b (strptr)+,d1
X@put	putchar
X	cmp.l strend(a6),strptr
X	bne.s @putlp
X	bra @loop
X
X@done	bsr flush
X	_debugger		;Shouldn't return
X
X;Read 8 codes into codebuf
X;Input: codesz
X;Output: readcnt, codeptr or MI flag set if end of file.
Xread8codes:
X	movem.l d2-d5,-(sp)
X	move.l rd_ptr(a6),a0
X	move.l codesz,d0
X	sub.w d0,rd_cnt(a6)
X	if# lt then.s
X	  bsr.s fillbuf
X	else#.s
X	  add.l d0,rd_ptr(a6)
X	endif#
X	lsl.w #3,d0
X	sub.w codesz,d0
X	bmi.s @ret
X	move.w d0,readcnt
X	moveq #1,d2		;d2 = mask
X	lsl.w codesz,d2
X	subq.w #1,d2
X	move.w codesz,d3	;d3 = codesz - 8
X	subq.w #8,d3
X	lea codebuf+18(a6),codeptr
X	move.w codesz,d4	;d4 = byte count
X	moveq #0,d5		;d5 = # used bits in this byte
X@loop	move.w d5,d1		;save bit count
X	add.w d3,d5
X	move.b (a0)+,-(codeptr)
X	subq #1,d4
X	subq.w #8,d5
X	if# lt then.s
X	  addq.w #8,d5
X	  move.b (a0),-(codeptr)
X	  move.w (codeptr)+,d0
X	  lsr.w d1,d0
X	  and.w d2,d0
X	  move.w d0,-(codeptr)
X	  bra.s @loop
X	endif#
X	move.b (a0)+,-(codeptr)
X	move.b (a0),-(codeptr)
X	subq #1,codeptr
X	move.l (codeptr)+,d0
X	lsr.l d1,d0
X	and.w d2,d0
X	move.w d0,-(codeptr)
X	subq #1,d4
X	bne.s @loop
X	lea codebuf+18(a6),codeptr
X@ret	movem.l (sp)+,d2-d5
X	rts
X
Xfillbuf:
X	lea tempbuf(a6),codeptr		;handy areg....
X	move.w rd_cnt(a6),d1
X	add.w d1,d0
X	bra.s @more
X	 move.b (a0)+,(codeptr)+
X@more	dbf d0,*-2
X	move.l rd_error(a6),d0
X	if# gt then.s
X	  movem.l d1/a1,-(sp)
X	  pea rd_buf(a6)
X	  pea BUFSIZE
X	  move.l rd_param(a6),-(sp)
X	  move.l rd_fn(a6),a0
X	  jsr (a0)
X	  lea 12(sp),sp
X	  movem.l (sp)+,d1/a1
X	  move.l d0,rd_error(a6)
X	endif#
X	if# gt then.s
X	  lea rd_buf(a6),a0
X	  add.w d0,d1
X	  bmi.s @more
X	  sub.w d1,d0
X	  bra.s *+4
X	   move.b (a0)+,(codeptr)+
X	  dbf d0,*-2
X	  move.w d1,rd_cnt(a6)
X	  move.l a0,rd_ptr(a6)
X	else#.s
X	  clr.w rd_cnt(a6)
X	endif#
X	move.l codeptr,d0
X	lea tempbuf(a6),a0
X	sub.l a0,d0
X	rts
X
X;uncompread(cstream, size, buf)
X	export uncompread
Xuncompread:
X	movem.l hisregs,-(sp)
X	move.l hisregsz+4(sp),a6		;cstream
X	movem.l savedregs(a6),myregs
X	move.l a0,-(sp)
X	move.l hisregsz+4+12(sp),a0		;buf
X	move.l hisregsz+4+8(sp),d0		;size
X	tst.l d1				;we doing flush or flsbuf?
X	if# mi then.s
X	  tst.l rd_error(a6)
X	  ble.s flseof
X	else#.s
X	  subq.l #1,d0
X	  blt.s flsbuf
X	  move.b d1,(a0)+
X	endif#
X	move.l a0,wr_ptr(a6)
X	move.l d0,wr_cnt(a6)
X	rts
Xflsbuf:	move.l hisregsz+4+8(sp),d0		;size
Xflsret:	move.l (sp)+,a0
X	movem.l myregs,savedregs(a6)
X	movem.l (sp)+,hisregs
X	rts
X
Xflush	moveq #-1,d1
X	move.l hisregsz+4+8(sp),d0
X	sub.l wr_cnt(a6),d0
X	bne.s flsret
Xflseof:	move.l rd_error(a6),d0
X	bra.s flsret
X
X;uncompclose(cstream)
X	export uncompclose
Xuncompclose:
X	move.l 4(sp),d0
X	if# eq then.s
X	  rts
X	endif#
X	movem.l hisregs,-(sp)
X	move.l d0,a6
X	movem.l savedregs(a6),myregs
X	move.l strend(a6),a0
X	lea -STRSIZE(a0),a0
X	_DisposPtr
Xmemer3	move.w MemErr,-(sp)
X	lea 512(codetab),a0
X	_DisposPtr
X	move.w (sp)+,MemErr
Xmemer2	move.w MemErr,-(sp)
X	lea 256(chartab),a0
X	_DisposPtr
X	move.w (sp)+,MemErr
Xmemer1	move.w MemErr,-(sp)
X	move.l a6,a0
X	_DisposPtr
X	move.w (sp)+,MemErr
X	moveq #0,d0
X	movem.l (sp)+,hisregs
X	rts
X	endwith
X	endproc
X
X
X	end
SHAR_EOF
if test 19133 -ne "`wc -c < 'compstream.a'`"
then
	echo shar: error transmitting "'compstream.a'" '(should have been 19133 characters)'
fi
fi
echo Done
exit 0

--
gz@entity.com					...!mit-eddie!spt!gz
	  Unix: when you can't afford the very best.