/*

   ##     #####   ####   #####            ####
  #  #      #    #    #  #    #          #    #
 #    #     #    #    #  #####           #
 ######     #    #    #  #    #   ###    #
 #    #     #    #    #  #    #   ###    #    #
 #    #     #     ####   #####    ###     ####

	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

	Raphael Manfredi (ram) modified this file, in order to produce
	meaningfull error messages (otherwise, fatal() was called, even
	when a temporary file could not be created...); added error().

	RAM also added support for 64 bits platforms.
*/

/*
 * $Id: atob.c,v 2.0.1.1 1993/04/26 11:18:01 ram Exp $
 *
 * $Log: atob.c,v $
 * Revision 2.0.1.1  1993/04/26 11:18:01  ram
 * patch27: added support for 64 bits architecture (tested on Alpha)
 *
 * Revision 2.0  91/02/19  15:49:21  ram
 * Baseline for first official release.
 * 
 */

#include <stdio.h>
#include "../config.h"

/* Provision for 64 bits machines -> remaps long to int. If the machine is
 * ILP 64 (Integer, Long and Pointer types on 64 bits), then everything is fine,
 * since both longs and ints can be used. If the machine is LP 64, then it has
 * a 32 bits arithmetic and long must be used as an int.
 */
#if (BYTEORDER | 0xffff) == 0xffff
typedef long long_t;			/* 32 bits machines */
#else
typedef int long_t;				/* 64 bits, hopefully */
#endif

#define reg register

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

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

long_t Ceor = 0;
long_t Csum = 0;
long_t Crot = 0;
long_t word = 0;
long_t bcount = 0;

fatal() {
  fprintf(stderr, "bad format or Csum to atob\n");
  exit(1);
}

error(s)
char *s;	/* the error message */
{
  fprintf(stderr, "%s\n", s);
  exit(1);
}

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

decode(c) reg c;
{
  if (c == 'z') {
    if (bcount != 0) {
      fatal();
    } 
    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((int) word);
      word += DE(c);
      ++bcount;
    } 
    else {
      word = times85((int) word) + DE(c);
      byteout((int)(((int) word >> 24) & 255));
      byteout((int)(((int) word >> 16) & 255));
      byteout((int)(((int) word >> 8) & 255));
      byteout((int)((int) word & 255));
      word = 0;
      bcount = 0;
    }
  } 
  else {
    fatal();
  }
}

FILE *tmp_file;

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);
}

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

  if (argc != 1) {
    fprintf(stderr,"bad args to %s\n", argv[0]);
    exit(2);
  }
  sprintf(tmp_name, "/usr/tmp/atob.%x", getpid());
  tmp_file = fopen(tmp_name, "w+");
  if (tmp_file == NULL) {
    error("can't create temporary file");
  }
  unlink(tmp_name); /* Make file disappear */
  /*search for header line*/
  for (;;) {
    if (fgets(buf, sizeof buf, stdin) == NULL) {
      error("could not read header line");
    }
    if (streq(buf, "xbtoa Begin\n")) {
      break;
    }
  }

  while ((c = getchar()) != EOF) {
    if (c == '\n') {
      continue;
    } 
    else if (c == 'x') {
      break;
    } 
    else {
      decode(c);
    }
  }
  if (scanf("btoa End N %d %x E %x S %x R %x\n", &n1, &n2, &oeor, &osum, &orot) != 5) {
    error("could not read check sum");
  }
  if ((n1 != n2) || (oeor != Ceor) || (osum != Csum) || (orot != Crot)) {
	fprintf(stderr, "n1: %d, n2: %d\n", n1, n2);
	fprintf(stderr, "oeor: %d, Ceor %d\n", oeor, Ceor);
	fprintf(stderr, "osum: %d, Csum %d\n", osum, Csum);
	fprintf(stderr, "orot: %d, Crot %d\n", orot, Crot);
    error("check sum did not match original");
  } 
  else {
    /*copy OK tmp file to stdout*/;
    fseek(tmp_file, 0L, 0);
    for (i = n1; --i >= 0;) {
      putchar(getc(tmp_file));
    }
  }
  exit(0);
}
