/* atob: version 4.0
 * stream filter to change printable ascii from "btoa" back into 8 bit bytes
 * if bad chars, or Csums do not match: exit(1) [and NO output]
 *
 *  Paul Rutter         Joe Orost
 *  philabs!per         petsd!joe
 */
#define _POSIX_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#if defined(__msdos) || defined(__MSDOS__)
#include <fcntl.h>	/* for setmode O_BINARY */
#endif

#define reg register

#define streq(s0, s1)  strcmp(s0, s1) == 0

#define times85(x)      ((((((x<<2)+x)<<2)+x)<<2)+x)

#if defined(__msdos) || defined(__MSDOS__)
typedef  long s32;
#else
typedef  int s32;
#endif

s32 Ceor = 0;
s32 Csum = 0;
s32 Crot = 0;
s32 word = 0;
s32 bcount = 0;
s32 line = 1;

FILE *tmp_file;

void fatal(s) 
   char *s;
{
  fprintf(stderr, "atob: error -- %s line %d after header\n", s, line);
  exit(1);
}

#define DE(c) ((c) - '!')

void byteout(c) 
  reg c;
{
  Ceor ^= c;
  Csum += c;
  Csum += 1;
  if ((Crot & 0x80000000)) {
    Crot <<= 1;
    Crot += 1;
  } else {
    Crot <<= 1;
  }
  Crot += c;
  putc(c, tmp_file);
}


void decode(c) 
  reg c;
{
  char errbuf[128];

  if (c == 'z') {
    if (bcount != 0) {
      fatal("alignment error");
    } else {
      byteout(0);
      byteout(0);
      byteout(0);
      byteout(0);
    }
  } else if ((c >= '!') && (c < ('!' + 85))) {
    if (bcount == 0) {
      word = DE(c);
      ++bcount;
    } else if (bcount < 4) {
      word = times85(word);
      word += DE(c);
      ++bcount;
    } else {
      word = times85(word) + DE(c);
      byteout((int)((word >> 24) & 255));
      byteout((int)((word >> 16) & 255));
      byteout((int)((word >> 8) & 255));
      byteout((int)(word & 255));
      word = 0;
      bcount = 0;
    }
  } else {
    sprintf(errbuf, "invalid character %d", c);
    fatal(errbuf);
  }
}

int main(argc, argv) 
  int argc;
  char **argv;
{
  reg c;
  reg s32 i;
  char buf[100];
  s32 n1, n2, oeor, osum, orot;

  if (argc != 1) {
    fprintf(stderr,"bad args to %s\n", argv[0]);
    exit(2);
  }
  tmp_file = tmpfile();	/* generates warning on 486 box running ESIX 4.0 */
  if (tmp_file == NULL) {
    fatal("create of temp file failed");
  }

#if defined(__msdos) || defined(__MSDOS__)
   setmode(fileno(tmp_file), O_BINARY);
   setmode(1, O_BINARY);
#endif

  /*search for header line*/
  for (;;) {
    if (fgets(buf, sizeof buf, stdin) == NULL) {
      fatal("no header found");
    }
    if (memcmp(buf, "xbtoa Begin", 11) == 0) {
      break;
    }
  }

  while ((c = getchar()) != EOF) {
    if (isspace(c)) {
      if (c == '\n') line++;
      continue;
    } else if (c == 'x') {
      break;
    } else {
      decode(c);
    }
  }
  if(scanf("btoa End N %ld %lx E %lx S %lx R %lx ",
          &n1,  &n2,  &oeor,  &osum,  &orot) != 5) {
    fatal("invalid trailer");
  }
  if (n1 != n2) {
    fatal("bad trialer bytecount");
  } else if (oeor != Ceor) {
    fatal("bad XOR check");
  } else if (osum != Csum) {
    fatal("bad check sum");
  } else if (orot != Crot) {
    fatal("bad rotate check");
  } else {
    /*copy OK tmp file to stdout*/;
    fseek(tmp_file, 0L, 0);
    for (i = n1; --i >= 0;) {
      putchar(getc(tmp_file));
    }
  }
  return 0;
}
