/*
 * 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 */
