/*
 * File: zmr.c
 * Copyright 1988, 2002 Omen Technology Inc All Rights Reserved
 *
 *
 * 
 * This module implements ZMODEM Run Length Encoding, an
 * extension that was not funded by the original Telenet
 * development contract.
 * 
 *  This software may be freely used for educational (didactic
 *  only) purposes.  This software may also be freely used to
 *  support file transfer operations to or from licensed Omen
 *  Technology products.  Use with other commercial or shareware
 *  programs (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION.
 *
 *  Any programs which use part or all of this software must be
 *  provided in source form with this notice intact except by
 *  written permission from Omen Technology Incorporated.
 * 
 * Use of this software for commercial or administrative purposes
 * except when exclusively limited to interfacing Omen Technology
 * products requires a per port license payment of $20.00 US per
 * port (less in quantity).  Use of this code by inclusion,
 * decompilation, reverse engineering or any other means
 * constitutes agreement to these conditions and acceptance of
 * liability to license the materials and payment of reasonable
 * legal costs necessary to enforce this license agreement.
 *
 *
 *		Omen Technology Inc
 *		Post Office Box 1314
 *		Hillsboro OR 97123
 *
 *	This code is made available in the hope it will be useful,
 *	BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
 *	DAMAGES OF ANY KIND.
 *
 *	ZMODEM RLE compression and decompression functions
 */

/* Send data subpacket RLE encoded with 32 bit FCS */
void zsdar32(buf, length, frameend)
char *buf;
{
	register int c, l, n;
	register long crc;

#ifdef DIAGS
	vfile("zsdatr32: %d %X", length, frameend);
#endif
	crc = 0xFFFFFFFFL;  l = *buf++ & 0377;
	for (n = 0; --length >= 0; ++buf) {
		if ((c = *buf & 0377) == l && n < 126 && length>0) {
			++n;  continue;
		}
		switch (n) {
		case 0:
			zsendline(l);
			crc = UPDC32(l, crc);
			if (l == ZRESC) {
				zsendline(0100); crc = UPDC32(0100, crc);
			}
			l = c; break;
		case 1:
			if (l != ZRESC) {
				zsendline(l); zsendline(l);
				crc = UPDC32(l, crc);
				crc = UPDC32(l, crc);
				n = 0; l = c; break;
			}
			/* **** FALL THRU TO **** */
		default:
			zsendline(ZRESC); crc = UPDC32(ZRESC, crc);
			if (l == 040 && n < 34) {
				n += 036;
				zsendline(n); crc = UPDC32(n, crc);
			}
			else {
				n += 0101;
				zsendline(n); crc = UPDC32(n, crc);
				zsendline(l); crc = UPDC32(l, crc);
			}
			n = 0; l = c; break;
		}
	}
	sendline(ZDLE); sendline(frameend);
	crc = UPDC32(frameend, crc);

	crc = ~crc;
	for (length=4; --length >= 0;) {
		zsendline((int)crc);  crc >>= 8;
	}
}


/* Receive data subpacket RLE encoded with 32 bit FCS */
zrdatr32(buf, length)
register char *buf;
{
	register int c;
	register long crc;
	register char *end;
	register int d;

	crc = 0xFFFFFFFFL;  Rxcount = 0;  end = buf + length;
	d = 0;	/* Use for RLE decoder state */
	while (buf <= end) {
		if ((c = zdlread()) & ~0377) {
crcfoo:
			switch (c) {
			case GOTCRCE:
			case GOTCRCG:
			case GOTCRCQ:
			case GOTCRCW:
				d = c;  c &= 0377;
				crc = UPDC32(c, crc);
				if ((c = zdlread()) & ~0377)
					goto crcfoo;
				crc = UPDC32(c, crc);
				if ((c = zdlread()) & ~0377)
					goto crcfoo;
				crc = UPDC32(c, crc);
				if ((c = zdlread()) & ~0377)
					goto crcfoo;
				crc = UPDC32(c, crc);
				if ((c = zdlread()) & ~0377)
					goto crcfoo;
				crc = UPDC32(c, crc);
				if (crc != 0xDEBB20E3) {
#ifdef DIAGS
					zbitch(badcrc);
#endif
					return IZERROR;
				}
				Rxcount = length - (end - buf);
#ifdef DIAGS
				vfile("zrdatr32: %d %s", Rxcount,
				  Zendnames[d-GOTCRCE&3]);
#endif
				return d;
			case GOTCAN:
				zbitch("Sender Canceled");
				return ZCAN;
			case TIMEOUT:
				zbitch("TIMEOUT");
				return c;
			default:
				zbitch("Bad data subpacket");
				return c;
			}
		}
		crc = UPDC32(c, crc);
		switch (d) {
		case 0:
			if (c == ZRESC) {
				d = -1;  continue;
			}
			*buf++ = c;  continue;
		case -1:
			if (c >= 040 && c < 0100) {
				d = c - 035; c = 040;  goto spaces;
			}
			if (c == 0100) {
				d = 0;
				*buf++ = ZRESC;  continue;
			}
			d = c;  continue;
		default:
			d -= 0100;
			if (d < 1)
				goto badpkt;
spaces:
			if ((buf + d) > end)
				goto badpkt;
			while ( --d >= 0)
				*buf++ = c;
			d = 0;  continue;
		}
	}
badpkt:
	zbitch("Data subpacket too long");
	return IZERROR;
}

/* End of izmr.c */
