/**************************************************************************

		    Convert bin -> ascii and vice versa

       Copyright (C) 1994 by Alexandros Loghis,  All Rights Reserved

**************************************************************************/

#include <stdio.h>	/* fprintf, fgets, fopen, fgetc, fputc, feof \
			   remove */
#include <stdlib.h>	/* atoi */
#include <string.h>	/* strcmp */

#include "gfx2grob.h"
#include "PrintMsg.h"
#include "FileStuf.h"
#ifdef AMIGA
#include "IffStuff.h"
#endif
#include "Convert.h"


#define HPLINE		"%%%%HP: T(2)A(R)F(.);" /* first line in ASCII-file */
#define HPLINELEN	sizeof(HPLINE)
#define GROBSTRLEN	sizeof(GROBSTR)
#define HPALIGN		8
#define COMPALIGN	16


u_char ConvertTab[] = { 0x0, 0x8, 0x4, 0xC,
			0x2, 0xA, 0x6, 0xE,
			0x1, 0x9, 0x5, 0xD,
			0x3, 0xB, 0x7, 0xF
		      };


static int GetAndConvNibble(gvType *gv);
static char *GetWord(gvType *gv, char *Buffer, int MaxLen);
static void ConvertFileToBin(gvType *gv);
static void ConvAndPutNibble(gvType *gv, int Index);
static void ConvertFileToAscii(gvType *gv);
#ifdef AMIGA
static void ConvertFileToIff(gvType *gv);
#endif

/*************************************************************************/

static int GetAndConvNibble(gvType *gv)
{
  int x;


  if (EOF != (x = fgetc(gv->Inputfile))) {
    if (x > '9')
      x -= 'A' - 10;
    else
      x -= '0';
  }
  else
    PrintMsg(ERR_READ_S, gv->Options.InputfileName);

  return ((int) ConvertTab[x]);
}

/*************************************************************************/

static char *GetWord(gvType *gv, char *Buffer, int MaxLen)
{
  int x;

  char *b = Buffer;


  while ((x = fgetc(gv->Inputfile)) != ' ') {
    if (x == EOF) PrintMsg(ERR_READ_S, gv->Options.InputfileName);
    if (!--MaxLen) PrintMsg(ERR_WORD_S, gv->Options.InputfileName);
    *Buffer++ = x;
  }
  *Buffer = '\0';

  return (b);
}

/*************************************************************************/

static void ConvertFileToBin(gvType *gv)
{
  char HPline[HPLINELEN + 1],
       Grob[GROBSTRLEN + 1],
       Width[5],
       Height[5];

  int Wi,
      Hi,
      HPWidth,
      CompWidth,
      i,
      j;

  register int hn,	/* high nibble */
	       ln;	/* low	nibble */


  PrintMsg(MSG_SKIPLN);
  if (!fgets(HPline, HPLINELEN + 2, gv->Inputfile))
    PrintMsg(ERR_READ_S, gv->Options.InputfileName);

  if (strcmp(GetWord(gv, Grob, GROBSTRLEN), GROBSTR))
    PrintMsg(ERR_GROB_S, gv->Options.InputfileName);
  Wi = atoi(GetWord(gv, Width, 4));
  Hi = atoi(GetWord(gv, Height, 4));
  PrintMsg(MSG_GPHFORMIS_DD, Wi, Hi);
  gv->Options.Width = Wi;
  gv->Options.Height  = Hi;
  HPWidth   = CALCWIDTH(Wi, HPALIGN);
  CompWidth = CALCWIDTH(Wi, COMPALIGN);

  for (i = 0; i < Hi; i++) {
    for (j = 0; j < (HPWidth / HPALIGN); j++) {
      hn = GetAndConvNibble(gv);
      ln = GetAndConvNibble(gv);
      if (EOF == fputc((hn << 4) + ln, gv->Outputfile))
	PrintMsg(ERR_WRITE_S, gv->Options.OutputfileName);
    }
    for (j = 0; j < (CompWidth - HPWidth) / HPALIGN; j++)
      if (EOF == fputc(0, gv->Outputfile))
	  PrintMsg(ERR_WRITE_S, gv->Options.OutputfileName);
  }
  fgetc(gv->Inputfile);		/* last CR */
  fgetc(gv->Inputfile);		/* to come to EOF */
  if (!feof(gv->Inputfile)) PrintMsg(ERR_EOF_S, gv->Options.InputfileName);
}

/*************************************************************************/

static void ConvAndPutNibble(gvType *gv, int Index)
{
  int y;


  if ((y = ConvertTab[Index]) > 9)
    y += 'A' - 10;
  else
    y += '0';
  if (EOF == fputc(y, gv->Outputfile))
    PrintMsg(ERR_WRITE_S, gv->Options.OutputfileName);
}

/*************************************************************************/

static void ConvertFileToAscii(gvType *gv)
{
  int HPWidth,
      CompWidth,
      i,
      j;

  register int x;


  if (0 > fprintf(gv->Outputfile, HPLINE"\n"GROBSTR" %d %d ",
		  gv->Options.Width, gv->Options.Height))
    PrintMsg(ERR_WRITE_S, gv->Options.OutputfileName);

  PrintMsg(MSG_GPHFORMIS_DD, gv->Options.Width, gv->Options.Height);

  HPWidth   = CALCWIDTH(gv->Options.Width, HPALIGN);
  CompWidth = CALCWIDTH(gv->Options.Width, COMPALIGN);

  for (i = 0; i < gv->Options.Height; i++) {
    for (j = 0; j < (HPWidth / HPALIGN); j++)
      if (EOF != (x = fgetc(gv->Inputfile))) {
	ConvAndPutNibble(gv, x >> 4);
	ConvAndPutNibble(gv, x & 0x0F);
      }
      else
	PrintMsg(ERR_READ_S, gv->Options.InputfileName);
    for (j = 0; j < (CompWidth - HPWidth) / HPALIGN; j++)
      if (EOF == fgetc(gv->Inputfile))
	PrintMsg(ERR_READ_S, gv->Options.InputfileName);
  }
  fgetc(gv->Inputfile);		/* to come to EOF */
  if (!feof(gv->Inputfile))
    PrintMsg(ERR_EOF_S, gv->Options.InputfileName);
}

/*************************************************************************/

#ifdef AMIGA
static void ConvertFileToIff(gvType *gv)
{
  char *OutputfileNameTmp = gv->Options.OutputfileName;


  if (EOF == fclose(gv->Outputfile))
    PrintMsg(ERR_CLOSE_S, OutputfileNameTmp);

  gv->Options.OutputfileName = TEMPFILENAME;
  if (!(gv->Outputfile = fopen(TEMPFILENAME, "wb")))
    PrintMsg(ERR_OPEN_S, TEMPFILENAME);

  ConvertFileToBin(gv);

  if (EOF == fclose(gv->Inputfile))
    PrintMsg(ERR_CLOSE_S, gv->Options.InputfileName);
  gv->Inputfile = NULL;
  if (EOF == fclose(gv->Outputfile))
    PrintMsg(ERR_CLOSE_S, gv->Options.OutputfileName);
  gv->Outputfile = NULL;

  gv->Options.InputfileName  = TEMPFILENAME;
  gv->Options.OutputfileName = OutputfileNameTmp;

  ConvertBinToIff(gv);
}
#endif

/*************************************************************************/

extern void ConvertFile(gvType *gv)
{
  switch (gv->Options.Option) {

    case OT_TOASCII :
      OpenFiles(gv, "rb", "w");
#ifdef AMIGA
      IffToBin(gv);
#endif
      ConvertFileToAscii(gv);
      break;

    case OT_TOBIN :
      OpenFiles(gv, "r", "wb");
      ConvertFileToBin(gv);
      break;

#ifdef AMIGA
    case OT_TOIFF :
      OpenFiles(gv, "r", "wb");
      ConvertFileToIff(gv);
      break;
#endif
  }
  CloseFiles(gv);
  PrintMsg(MSG_OPSUCCESS);
}
