#define NAME     "BinHex"
#define REVISION "12"
#define ENDCODE
//#define DEBUG

/* Programmheader

	Name:		BinHex
	Author:		SDI
	Distribution:	PD
	Description:	wandelt Binär in Hex Datei und umgekehrt
	Compileropts:	-
	Linkeropts:	-

 1.0   03.10.95 : erste Version
 1.1   15.10.95 : neu übersetzt
 1.2   05.02.96 : mit verbesserten Includes neu übersetzt
 1.3   06.02.96 : MakeHEX statt MakeBASE
 1.4   10.02.96 : mit eigenem StartUp übersetzt
 1.5   12.03.96 : Fehler mit ONLYDATA behoben, \ Option, Englische Texte
 1.6   04.05.96 : Fehler mit ReadArgs behoben
 1.7   11.05.96 : Option ROWS eingebaut
 1.8   12.05.96 : Option ASMDATA eingebaut
 1.9   11.06.96 : EndCode nach SDI_defines.h
 1.10  16.06.96 : Bug overworked Buffer - corrected
 1.11  06.10.96 : if last char was an \t program hanged - fixed
 1.12  21.11.96 : added option CDATA, same as ASMDATA but for C
*/

#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
#include <dos/dos.h>
#include <exec/memory.h>
#include "SDI_defines.h"
#include "SDI_structures.h"
#include "SDI_ASM_STD_protos.h"
#include "SDI_ASM_protos.h"
#include "SDI_protos.h"
#include "GetLength.c"  // These files are in SDI_functions.o
#include "Eingabe.c"    // remove the lines and build your own
#include "Ausgabe.c"    // makefile
#include "Free.c"       // Add also the other .o files to the
#include "GetPuffer.c"  // makefile to make compilation
#include "PutNum.c"     // succesfull!

struct SDI_InOut	bin		= {0, 0, 0, 0, 0},
			hex		= {0, 0, 0, 0, 0};
struct RDArgs		*rda		= 0;
ULONG			DosVersion	= 37;	// zwingt OS 37 !

#define line		h
#define row		adress

#define PARAM "BIN/A,HEX/A,MAKEBIN/S,ONLYDATA/S,ROWS/N,ASMDATA/S,CDATA/S"

#define NUMPERLINE	(rows<<2)
#define LINESIZE	(rows*(4*(2+1)+1)+8+1+1)
// Reihenanzahl*(4*(2Zahlen+1Asciizeichen)+1Leerzeichen)+8für Adresse+
// 1Leerzeichen+1Return
#define MAINSIZE	(rows*(4*2+1))
#define ASCIIPOS	(MAINSIZE+8+1)
#define RESTSIZE	(NUMPERLINE+8+1+1)

UBYTE GetHEXNum(UBYTE);

void main(void)
{
  struct {
    STRPTR	bin;
    STRPTR	hex;
    LONG	makebin;
    LONG	onlydata;
    LONG	*rows;
    LONG	asmdata;
    LONG	cdata;
    } args = {0, 0, 0, 0, 0, 0, 0};
  UBYTE realmode = 0;
  ULONG h, adress = 0;
  STRPTR strptr;
  UBYTE rows = 5;

  if(!(rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
    End(RETURN_FAIL);

  rda->RDA_ExtHelp =
/*
  "Mit dem Programm können binäre Dateien in Hexadezimal dargestellte "
  "Dateien umgewandelt werden. Diese kann man dann mit einem Editor "
  "bearbeitet und wieder in eine Binärdatei umwandeln. "
  "Das Programm liest aus der Hexdatei alle Hex-Zahlen bis zu einem "
  "Tabulator, dann geht es nach dem nächsten Return weiter. Sie müssen "
  "also nicht darauf achten, wieder die genaue Zeilenlänge zu erhalten. "
  "Zwischen Return und Tabulator dürfen jedoch nur die Zeichen 0-9 und A-F "
  "stehen und zwar in einer geraden Anzahl. Das Leerzeichen ist als "
  "Trenner erlaubt. Nach einem \\ wird alles so übernommen, wie gegeben. "
  "Das ist für Texteingaben sehr nützlich.\n";
*/
  "Use this program to convert binary data into hexadecimal data. This "
  "could be edited with a normal text editor. After that it could again "
  "be made to binary. The program reads in the hexadecimal file all numbers "
  "from line start to next tabulator or return. You don't need to make the "
  "linelength exact as before! Only 0-9 and A-F are allowed in the data part. "
  "Spaces and data after the tabulator are ignored. After a \\ all data is "
  "not converted and taken as given to the binary file (useful for texts).\n";
  if(!ReadArgs(PARAM, (LONG *) &args, rda))
    End(RETURN_FAIL);

  if(args.rows && *args.rows > 0 && *args.rows < 256)
    rows = (UBYTE) *args.rows;

  if(args.asmdata || args.cdata)
    args.onlydata = 1;

  if((args.makebin && (args.asmdata || args.cdata)) ||
  (args.asmdata && args.cdata))
  {
    PrintFault(ERROR_TOO_MANY_ARGS, 0);
    End(RETURN_FAIL);
  }

  if(args.makebin)
  {
    if(
    !(hex.file = Open(args.hex, MODE_OLDFILE)) ||
    !(bin.size = GetLength(args.hex)))
      End(RETURN_FAIL);
    bin.size = (bin.size >> 2) + 1;
    if(bin.size < NUMPERLINE)
      bin.size = NUMPERLINE;
  }
  else
  {
    if(
    !(bin.file = Open(args.bin, MODE_OLDFILE)) ||
    !(bin.size = GetLength(args.bin)))
      End(RETURN_FAIL);
  }

  if((hex.size = bin.size << 2) > (h = AvailMem(MEMF_LARGEST)))
    hex.size = h;
  if(hex.size < LINESIZE)
    hex.size = LINESIZE;
  if(!GetPuffer(&hex))
    End(RETURN_FAIL);

  if(bin.size > (h = AvailMem(MEMF_LARGEST)))
    bin.size = h;
  if(!GetPuffer(&bin))
    End(RETURN_FAIL);

  if(!((args.makebin ? bin.file : hex.file) = 
  Open(args.makebin ? args.bin : args.hex, MODE_NEWFILE)))
    End(RETURN_FAIL);

#ifdef DEBUG
  PutNum((ULONG)bin.file, 10); PutStr(" bin.file\n");
  PutNum((ULONG)bin.buf , 10); PutStr(" bin.buf\n");
  PutNum((ULONG)bin.pos , 10); PutStr(" bin.pos\n");
  PutNum((ULONG)bin.size, 10); PutStr(" bin.size\n");
  PutNum((ULONG)hex.file, 10); PutStr(" hex.file\n");
  PutNum((ULONG)hex.buf , 10); PutStr(" hex.buf\n");
  PutNum((ULONG)hex.pos , 10); PutStr(" hex.pos\n");
  PutNum((ULONG)hex.size, 10); PutStr(" hex.size\n");
#endif

  if(args.makebin)
  {
    Eingabe(&hex); line = row = 1;
    while(hex.count && !CTRL_C)
    {
      if(*hex.pos == '\t')
      {
        while(hex.count && *hex.pos != '\n')
        {
          ++hex.pos;
          if(hex.pos >= hex.buf + hex.count - 2)
            Eingabe(&hex);
        }
      }
      else if(*hex.pos == '\n')
      {
        ++line; row = 1; ++hex.pos; realmode = 0;
      }
      else if(!realmode && *hex.pos == ' ')
      {
        ++hex.pos; ++row;
      }
      else if(*hex.pos == '\\')
      {
        realmode = 1; ++hex.pos;
      }
      else
      {
        if(realmode)
        {
          *(bin.pos++) = *(hex.pos++); ++row;
        }
        else
        {
          if(!SDI_isxdigit(*hex.pos) || !SDI_isxdigit(*(hex.pos+1)))
          {
/*
	    PutStr("Zeile "); PutNum(line, 0);
            PutStr(", Reihe "); PutNum(row, 0); PutStr(" : ");
*/
            PutStr("line "); PutNum(line, 0);
	    PutStr(", row "); PutNum(row, 0); PutStr(" : ");
	    SetIoErr(ERROR_SEEK_ERROR);
            End(RETURN_FAIL);
          }
          *bin.pos = GetHEXNum(*(hex.pos++)) << 4;
          *(bin.pos++) += GetHEXNum(*(hex.pos++));
          row+=2;
        }
      }
      if(hex.pos >= hex.buf + hex.count - 2)
        Eingabe(&hex);
      if(bin.pos >= bin.buf + bin.size)
        Ausgabe(&bin, 0);
    }
    Ausgabe(&bin, 0);
  }
  else
  {
    Eingabe(&bin);
    if(args.cdata)
      Write(hex.file, "ULONG data[] = {\n", 17);
    while(bin.count && !CTRL_C)
    {
      if(args.asmdata)
      {
        *(hex.pos++) = '\t';
        *(hex.pos++) = 'D';
        *(hex.pos++) = 'C';
        *(hex.pos++) = '.';
        *(hex.pos++) = 'L';
        *(hex.pos++) = '\t';
      }
      else if(args.cdata)
      {
	*(hex.pos++) = ' ';
	*(hex.pos++) = ' ';
      }
      strptr = hex.pos + ASCIIPOS;

      for(h = 0; h < NUMPERLINE; ++h, ++bin.pos)
      {
        if(bin.pos < bin.buf + bin.count)
        {
	  if((args.asmdata || args.cdata) && !(h&3))
          {
            if(h)
              *(hex.pos++) = ',';
	    if(args.asmdata)
	      *(hex.pos++) = '$';
	    else
	    {
	      *(hex.pos++) = '0';
	      *(hex.pos++) = 'x';
	    }
          }
	  MakeHEX(hex.pos, 2, *bin.pos);
	  hex.pos += 2;
          if(!args.onlydata)
            *(strptr++) = SDI_isprint(*bin.pos) ? *bin.pos : '.';
        }
	else if(args.onlydata)
	  break;
        else
        {
          *(hex.pos++) = ' '; *(hex.pos++) = ' ';
          *(strptr++) = ' ';
        }
        if(!((h+1 & 3) || args.onlydata))
          *(hex.pos++) = ' ';
      }
      if(!args.onlydata)
      {
        MakeHEX(hex.pos, 8, adress);
        *(hex.pos-1) = '\t'; *(hex.pos+8) = ' ';  *strptr = '\n';
        hex.pos += RESTSIZE;
      }
      else
      {
	if(args.cdata)
	  *(hex.pos++) = ',';
	*(hex.pos++) = '\n';
      }
      adress += NUMPERLINE;
      if(bin.pos >= bin.buf + bin.count - NUMPERLINE)
        Eingabe(&bin);
      if(hex.pos >= hex.buf + hex.size - LINESIZE)
      {
#ifdef DEBUG
  if(hex.pos > hex.buf + hex.size)
    PutStr("Buffer overworked\n");
#endif
        Ausgabe(&hex, 0);
      }
    }
    if(args.cdata)
    {
      *(hex.pos++) = '}';
      *(hex.pos++) = ';';
      *(hex.pos++) = '\n';
    }
    Ausgabe(&hex, 0);
  }

  End(RETURN_OK);
}

UBYTE GetHEXNum(UBYTE h)
{
  if(h > 47 && h < 58)
    return (h - '0');
  else if(h > 64 && h < 71)
    return (h - 'A' + 10);
  else if(h > 96 && h < 103)
    return (h - 'a' + 10);
  return 0;
}

void end(void)
{
  if(bin.file)		Close(bin.file);
  if(hex.file)		Close(hex.file);
  Free(&bin);
  Free(&hex);
  if(rda)
  {
    FreeArgs(rda);
    FreeDosObject(DOS_RDARGS, rda);
  }
}
