
/* Tiny ABE 'Ascii-Binary Encoding' Decoder for ABE2 (4 sets/64, 85 printables)
   'sort' ALL THE INPUT FILES TOGETHER IF THEY'RE NOT IN ORDER.
   Try to get the full version of this program from various archives.
   This program is mainly meant as a temporary version for Unix users.
   DEFINE THE SYMBOL "msdos" on DOS MACHINES.
   By Brad Templeton.  This code is released to the public domain.  No
   warranties are provided or implied. */


#include <stdio.h>
#include <fcntl.h>		/* to get the MSDOS O_BINARY symbol only */

#define OUR_VERSION 1000
#define MAX_LLEN 80		/* max output line len */
#define NSETS 4			/* number of character sets */
#define SFBYTE 31
#define NUM_SAFE 64
#define CSUM_MOD 65536

/* header characters */
#define CODE_HEAD '"'
#define MAIN_HEAD '#'
#define ismapchar(x) ((x>='.'&&x<='9')||(x>='A'&&x<='Z')||(x>='a'&&x<='z'))

long line_num;
long expected_sum = 0;
extern long atol();
int whatbyte[NSETS][NUM_SAFE];	/* array maps printables to bytes */
char linbuf[MAX_LLEN];		/* input line */

main()
{
	int i, c, len;
	int sum;
	int setby, by;
	char ltype;

	line_num = 1;
#ifdef msdos
	setmode( 1, O_BINARY );		/* make stdout binary on DOS */
#endif

	while( fgets( linbuf, MAX_LLEN, stdin ) ){
		if( linbuf[0] >= 'T' && linbuf[0] <= 'Z' ) {
			ltype = linbuf[4] == linbuf[5] ? linbuf[4] : 0;
			len = strlen(linbuf);
			if( linbuf[len-1] == '\n' )
				linbuf[--len] = 0;
			 else
				continue;	/* line too long */
			sum = 0;
			for( i = 4; i < len; i++ )
				sum += linbuf[i];
			/* bad checksum, not a line for us */
			if( (sum % NUM_SAFE) != bconv(linbuf[3]) )
				continue;
			if( ( (long)(bconv(linbuf[0])-SFBYTE)*NUM_SAFE+
					bconv(linbuf[1]))*NUM_SAFE +
					bconv(linbuf[2]) != line_num++ )
				bomb_out("Sequence");
			if( ltype == MAIN_HEAD ) {
				if( linbuf[6] == 'S' ) {
					int ver;
					ver = atoi(linbuf+7);
					if( ver > OUR_VERSION || ver < 1000 )
						bomb_out( "Version number" );
					if(strcmp(linbuf+len-5,",ABE2") != 0 )
						bomb_out("Bad Encoding Style");
					}
				 else
					if( expected_sum != atol(linbuf+7) )
						bomb_out( "Checksum" );
				}
			else if( ltype == CODE_HEAD ) { /* encoding map */
				int line;
				line = bconv(linbuf[6])*32;
				for( i = 0; i < 16; i++ ) {
					setby = bconv(linbuf[7+2+i*3]);
					for( by = 1; by >= 0; by-- ) {
						whatbyte[setby%4][bconv(linbuf[
							7+i*3+by])] = line+i*2
							+by;
						setby /= NSETS;
						}
					}
				}
			else if( !ltype || ismapchar(ltype)) {
				/* decode a line */
				expected_sum = (expected_sum + sum) % CSUM_MOD;
				for( i = 4; i < len; i++ )
				  switch(c = linbuf[i]){
				    case '+':
				    case ',':
				    case '-':
					putchar(whatbyte[1+c-'+']
							[bconv(linbuf[++i])]);
					break;
				    case '"':
				    case '#':
				    case '$':
				    case '%':
				    case '&':
				    case  39: /* single quote ' */
				    case '(':
				    case ')':
				    case '*':
					putchar(whatbyte[1+(c-'"')/3]
							[bconv(linbuf[++i])]);
					putchar(whatbyte[1+(c-'"')%3]
							[bconv(linbuf[++i])]);
					break;
				    case '_':
					/* act like this is the 7th code */
					c = ':'+7;
					/* fall through */
				    case ':':
				    case ';':
				    case '<':
				    case '=':
				    case '>':
				    case '?':
				    case '@':
					putchar(whatbyte[1+(c-':')/3]
							[bconv(linbuf[++i])]);
					putchar(whatbyte[0][
						bconv(linbuf[++i])]);
					putchar(whatbyte[1+(c-':')%3]
							[bconv(linbuf[++i])]);

					break;
				    default:
					putchar(whatbyte[0][bconv(c)]);
					break;
					}
				}
			}
		}

}
bomb_out(err)
char *err;
{
	fprintf( stderr, "Decode aborted - %s error, Line: %3.3s\n",err,linbuf);
	fprintf(stderr, "Try to sort file or get the advanced DABE decoder.\n");
	exit(1);
}
bconv( n )		/* convert character from 64 set into int */
int n;
{
	return n - (n > '9' ? (n > 'Z' ? 'a'-38 : 'A'-12) : '.');
}
