[comp.sources.misc] b{en,de}code

rayan@ai.toronto.edu (Rayan Zachariassen) (01/01/88)

There was some talk about these programs over on comp.mail.misc. They
are used for moving bytes across networks that may mangle the data.
The code is public domain, and this shar is from one of the authors.
#! /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
#	coder.h
#	crctab.c
#	bdecode.c
#	bencode.c
# This archive created: Tue Dec 29 11:52:43 1987
# By:	Ken Lalonde
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
Bencode encodes 3 bytes to 4 characters.  The code set is 64
extremely harmless characters (A-Za-z0-9+-) that should pass through
any network without change.  But just in case, a byte count and cyclic
redundancy check appear after the data.

reggers@uwo.UUCP (Reg Quinton)
watmath!kwlalonde (Ken Lalonde)
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
DESTDIR=/usr/lib/news
# You may need -Dindex=strchr here.
CFLAGS = -O

all:	bdecode bencode

bencode: bencode.o crctab.o
	cc $(CFLAGS) bencode.o crctab.o -o bencode
bdecode: bdecode.o crctab.o
	cc $(CFLAGS) bdecode.o crctab.o -o bdecode
crctab.o: crctab.c
	cc -c $(CFLAGS) -R crctab.c

install: all
	install -s bdecode $(DESTDIR)
	install -s bencode $(DESTDIR)

clean:		
	rm -f bencode bdecode *.o SHAR

shar:
	shar README Makefile coder.h crctab.c bdecode.c bencode.c >SHAR
SHAR_EOF
fi # end of overwriting check
if test -f 'coder.h'
then
	echo shar: will not over-write existing file "'coder.h'"
else
cat << \SHAR_EOF > 'coder.h'
char header[] = "Decode the following with bdecode\n";
char codeset[] =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";

#define ENCODE(c)	codeset[c]

extern short crctab[];
#define CRC(crc, c)	 crc = (crc >> 8) ^ crctab[(crc^c) & 0xff]
SHAR_EOF
fi # end of overwriting check
if test -f 'crctab.c'
then
	echo shar: will not over-write existing file "'crctab.c'"
else
cat << \SHAR_EOF > 'crctab.c'
/* generated using the CRC-16 polynomial x^16 + x^15 + x^2 + 1 = 0120001 */
short crctab[256] = {
	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
	0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
	0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
	0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
	0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
	0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
	0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
	0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
	0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
	0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
	0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
	0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
	0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
	0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
	0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
	0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
	0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
	0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
	0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
	0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
	0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
	0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
	0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
	0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
	0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
	0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
	0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
	0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
	0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
	0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
	0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
SHAR_EOF
fi # end of overwriting check
if test -f 'bdecode.c'
then
	echo shar: will not over-write existing file "'bdecode.c'"
else
cat << \SHAR_EOF > 'bdecode.c'
/*
 * bdecode [file]
 */
#include <stdio.h>
#include "coder.h"
char *myname, *inputfile = "(stdin)";

main(argc, argv) 
	char **argv;
{
	register long word;
	register int c, bcount;
	register FILE *fin = stdin, *fout = stdout;	/* in regs for speed */
	register char *map, *p;
	register long nbytes;
	register int crc;
	long nbytes2;
	int w, crc2;
	char buf[512];
	extern char *index();

	myname = argv[0];
	if (sizeof(word) < 4)
		fprintf(stderr, "%s: word size too small\n", myname), exit(1);
	if (argc > 2)
		fprintf(stderr, "Usage: %s [file]\n", myname), exit(1);
	if (argc == 2) {
		if ((fin = fopen(argv[1], "r")) == NULL) {
			fprintf(stderr, "%s: ", myname);
			perror(argv[1]);
			exit(1);
		}
		inputfile = argv[1];
	}
	/* skip to beginning of encoded data */
	do {
		if (fgets(buf, sizeof buf, fin) == NULL)
			fatal("Missing header");
		/* trim trailing blanks (sigh) */
		p = index(buf, '\n');
		if (p == 0)
			continue;
		while (*--p == ' ')
			;
		p[1] = '\n';
		p[2] = '\0';
	} while (strcmp(buf, header) != 0);
	
	/* define input mapping table */
	map = buf+1;
	for (c = 0; c < 256; c++)
		map[c] = 64;		/* illegal */
	for (c = 0; c < 64; c++)
		map[ENCODE(c)] = c;
	map[EOF] = 65;		/* special cases */
	map['/'] = 66;

	word = 0;
	bcount = 4;
	nbytes = 0;
	crc = 0;
#define PUTC(x)  { c = (x) & 0xff; CRC(crc, c); putc(c, fout); nbytes++; }
	for (;;) {
		c = map[getc(fin)];
		if ((unsigned)c < 64) {
			word <<= 6;
			word |= c;
			if (--bcount == 0) {
				PUTC(word >> 16);
				PUTC(word >>  8);
				PUTC(word);
				word = 0;
				bcount = 4;
			}
			continue;
		}
		switch (c) {

		default:
			/*
			 * Ignore stuff not in the code set.
			 */
			continue;

		case 65:	/* EOF */
			fatal("Unexpected EOF");

		case 66:	/* '/' */
			/* trailer follows: %d%x */
			c = getc(fin);
			if (fscanf(fin, "%x", &w) != 1)
				fatal("Corrupted input (trailer)");
			switch (c) {
			case '2': PUTC(w >> 8);
			case '1': PUTC(w);
			case '0': break;
			default: fatal("Corrupted input (trailer)");
			}
			/*
			 * Byte count and CRC follow.
			 */
			if (fscanf(fin, "%ld%x", &nbytes2, &crc2) != 2)
				fatal("Corrupted input (missing byte count/CRC)");
			if (nbytes2 != nbytes)
				fatal("Corrupted input (byte count is wrong)");
			if (crc2 != (crc & 0xffff))
				fatal("Corrupted input (CRC mismatch)");
			exit(0);
		}
	}
}

fatal(s)
	char *s;
{
	fprintf(stderr, "%s: %s: %s\n", myname, inputfile, s);
	exit(2);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'bencode.c'
then
	echo shar: will not over-write existing file "'bencode.c'"
else
cat << \SHAR_EOF > 'bencode.c'
/*
 * bencode [file]
 */
#include <stdio.h>
#include "coder.h"
#define MAXPERLINE 78		/* max chars/line */
char *myname;

main(argc,argv) 
	char **argv;
{
	register FILE *fin = stdin, *fout = stdout; /* faster in a register */
	register int c, bcount, ccount = MAXPERLINE-1;
	register long word, nbytes;
	register int crc;

	myname = argv[0];
	if (sizeof(word) < 4)
		fprintf(stderr, "%s: word size too small\n", myname), exit(1);
	if (argc == 2 && (fin = fopen(argv[1], "r")) == NULL) {
		fprintf(stderr, "%s: ", myname);
		perror(argv[1]);
		exit(1);
	}
	else if (argc > 2) {
		fprintf(stderr, "Usage: %s [file]\n", myname);
		exit(1);
	}

#define PUTC(c) \
	putc(c, fout); \
	if (--ccount == 0) { \
		putc('\n', fout); \
		ccount = MAXPERLINE-1; \
	}

	fputs(header, fout);
	word = 0;
	bcount = 3;
	crc = 0;
	for (nbytes = 0; (c = getc(fin)) != EOF; nbytes++) {
		CRC(crc, c);
		word <<= 8;
		word |= c;
		if (--bcount == 0) {
			PUTC(ENCODE((word >> 18) & 077));
			PUTC(ENCODE((word >> 12) & 077));
			PUTC(ENCODE((word >>  6) & 077));
			PUTC(ENCODE((word      ) & 077));
			word = 0;
			bcount = 3;
		}
	}
	/*
	 * A trailing / marks end of data.
	 * The last partial encoded word follows in hex,
	 * preceded by a byte count.
	 */
	if (ccount != MAXPERLINE-1)	/* avoid empty lines */
		putc('\n', fout);
	fprintf(fout, "/%d%x\n", 3-bcount, word);
	/*
	 * And finally the byte count and CRC.
	 */
	fprintf(fout, "%ld %x\n", nbytes, crc & 0xffff);
	exit(0);
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0