/* >c.Boo
 *
 * Desktop Application to de-boo ibmpc files.
 *
 * (c) John Gordon (3 November 1990)
 * 
 * Notice: This software is public domain. It may be copied and distributed
 *         freely provided it is kept as a complete package. No profit is to
 *         be made from the distribution of this software. No guarantees are
 *         given with this software, and no responsibility is taken
 *         for any damage caused by the author or any other person - keep
 *         backups of your boo format files!
 *
 *         It may be possible to contact me at ukc as jg2@uk.ac.ukc (or
 *         more reliably J.Gordon@uk.ac.ukc since the login changes every
 *         so often...). If not post to the net and if I see it I'll reply!
 */

/***********************   INCLUDES   **********************/

/* Standard C libraries */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* RISC_OSlib functions */

#include "wimp.h"
#include "wimpt.h"
#include "win.h"
#include "baricon.h"
#include "event.h"
#include "werr.h"
#include "res.h"
#include "resspr.h"
#include "template.h"
#include "dbox.h"
#include "dboxquery.h"
#include "menu.h"
#include "xferrecv.h"
#include "visdelay.h"

/*********************** DEFINITIONS **********************/

/* Fields for the main dialogue box */

#define FInputFile  0
#define FOutputFile 1
#define FOk         2
#define FCancel     3

/* Menu Options */

#define MInfo 1
#define MQuit 2

/* Fields for the proginfo dialogue box */

#define FVersionString 4

/* Misc defines */

#define NAMELENGTH 100
#define fixchr(x) ((x)-'0')
#define NULLCHR fixchr('~')

/********************* GLOBALS *************************/

BOOL boo_active = FALSE;
char infile[NAMELENGTH], outfile[NAMELENGTH];
FILE *ifp, *ofp;

static char *boo_Version_String = "0.1 (3 Nov 1990)";

/*********************  CODE  *************************/

/* Very simple filename conversion function */

static void boo_convertname(char *fname)
{

/* Following rules apply to the conversion:

                   Up to 6 chars. from the main part of the name
                   Underscore character ("_")
                   Up to 3 characters from the extension

   Note: it is assumed that only a filename, and not a pathname, is supplied.
*/

   int i,j,k;
   char tempname[11];

   for (i=0;i<=6;i++)
   {
      if (fname[i] != '.')        /* Copy up to 6 characters */
         tempname[i] = fname[i];
      else
         break;                   /* if name less than 6 then get out */
   }
   j=i;
   tempname[j++]='_';             /* Put in the underscore character */
   while ((i<strlen(fname)) && (fname[i]!='.')) i++;  /* find separator */
   i++;
   k=j+3;
   for (;j<=k;j++)
   {
      tempname[j]=fname[i];
      if (fname[i++]=='\0')
         break;
   }
   tempname[10]='\0';             /* Add terminator in case */
   strcpy(fname, tempname);
}

/*=======================================================================*/

static void boo_decode(char *inputfile, char *outputfile, dbox db)
{
   dboxquery_REPLY dbr;
   int index, rptcnt, i;
   int a, b, c, d;
   char temp[NAMELENGTH];

/* Check input file */

   if ((ifp=fopen(inputfile, "r"))==NULL)
   {
      werr(FALSE, "Can't open input file");
      return;
   }

/* Read Output filename from input file */

   fgets(temp, NAMELENGTH, ifp);
   if ((temp[strlen(temp)-2]=='\r'))
      temp[strlen(temp)-2]='\0';
   else
      temp[strlen(temp)-1]='\0';
   if (strcmp(outputfile, "")==0)
   {
      strcpy(outputfile, temp);
      boo_convertname(outputfile);       /* convert to adfs filename */

   /* Update the dialogue box */

      dbox_setfield(db, FOutputFile, outputfile);
      dbox_show(db);
   }

/* Check for existence of output file */

   if ((ofp=fopen(outputfile, "r"))!=NULL)
   {  /* File Exists */
      fclose (ofp);
      dbr = dboxquery("File Exists: Overwrite it?");
      if (dbr != dboxquery_YES)
      {
         fclose (ifp);                    /* Close the input file */
         return;                          /* and get out of here */
      }
   }
   if ((ofp=fopen(outputfile, "wb"))==NULL)
   {
      werr(FALSE, "Unable to open output file");
      return;
   }
   else
      visdelay_begin();                   /* This could take some time! */

/* Finally do the decoding! */

   while (fgets(temp, NAMELENGTH, ifp)!=NULL)
   {
      index=0;
      while(index<strlen(temp) && temp[index]!='\r' && temp[index]!='\n')
      {
         if (fixchr(temp[index])==NULLCHR)
         {                        /* This bit copes with null compression */
            index++;
            rptcnt=fixchr(temp[index]);   /* get the repeat count */
            for (i=0;i<rptcnt;i++)
               putc('\0', ofp);
            index++;
         }
         else
         {                          /* Must be a quad for decoding */
            a=fixchr(temp[index++]);
            b=fixchr(temp[index++]);
            c=fixchr(temp[index++]);
            d=fixchr(temp[index++]);

         /* output the bytes */

            putc(((a*4)+(b/16)) & 255, ofp);
            putc(((b*16)+(c/4)) & 255, ofp);
            putc(((c*64)+d) & 255, ofp);
         }
      }
   }
   fclose(ofp);       /* Close the files up when finished! */
   fclose(ifp);
   visdelay_end();    /* Delay is over now so return to pointer */
}

/*====================================================================*/

static void boo_new()
{
   dbox d;
   dbox_field reply;

   if ((d=dbox_new("Main"))==FALSE)
      werr(TRUE, "No Space for !Boo Utility");
   boo_active=TRUE;
   dbox_setfield(d, FInputFile, "");
   dbox_setfield(d, FOutputFile, "");
   dbox_show(d);
   while ((reply=dbox_fillin(d))!=FOk && reply!=FCancel && reply!=dbox_CLOSE);
   if (reply!=FCancel && reply!=dbox_CLOSE)
   {
      dbox_getfield(d, FInputFile, infile, NAMELENGTH);
      dbox_getfield(d, FOutputFile, outfile, NAMELENGTH);
      boo_decode(infile, outfile, d);
   }
   dbox_dispose(&d);
   boo_active=FALSE;
}

/*====================================================================*/

static void boo_iconclick(wimp_i icon)
{
   icon=icon;       /* Shuts the compiler up :-) */
   if (boo_active==FALSE)
      boo_new();
   else
      werr(FALSE, "!Boo already active");
}

/*====================================================================*/

static void boo_infoaboutprog()
{
   dbox d;

   if ((d=dbox_new("ProgInfo"))==FALSE)
      werr(TRUE, "No space for !Boo Utility");
   dbox_setfield(d, FVersionString, boo_Version_String);
   dbox_show(d);
   dbox_fillin(d);
   dbox_dispose(&d);
}

/*========================================================================*/

static void boo_menuproc(void *handle, char *hit)
{
   handle=handle;   /* Guess what this is for ! */
   switch (*hit)
   {
      case MInfo:
                  boo_infoaboutprog();
                  break;
      case MQuit:
                  exit(0);
   }
}

/*======================================================================*/

static void boo_loaddata()
{
   dbox d;
   dbox_field reply;
   char *tempfile;
   int filetype;
   os_filestr file;

   filetype=xferrecv_checkinsert(&tempfile);

/* Check length of filename & make copy for us */

   if (strlen(tempfile) > NAMELENGTH)
   {
      werr(FALSE, "File name is too long");
      return;
   }
   strcpy(infile, tempfile);

/* Check the file type */

   file.action=5;
   file.name=infile;
   if (wimpt_complain(os_file(&file))!=0)
      return;
   switch (file.action)
   {
      case 0: werr (FALSE, "File Not Found");
              return;
      case 2: werr (FALSE, "You can't de-boo a directory");
              return;
   }

/* Create the de-boo dialogue box */

   if ((d=dbox_new("Main"))==FALSE)
      werr(TRUE, "No space for !Boo Utility");
   boo_active=TRUE;
   dbox_setfield(d, FInputFile, infile);
   dbox_setfield(d, FOutputFile, "");
   dbox_show(d);
   while ((reply=dbox_fillin(d))!=FOk && reply!=FCancel && reply!=dbox_CLOSE);
   if (reply!=FCancel && reply!=dbox_CLOSE)
   {
      dbox_getfield(d, FInputFile, infile, NAMELENGTH);
      dbox_getfield(d, FOutputFile, outfile, NAMELENGTH);
      boo_decode(infile, outfile, d);
      xferrecv_insertfileok();
   }
   dbox_dispose(&d);
   boo_active=FALSE;
}

/*====================================================================*/

static void boo_load(wimp_eventstr *e, void *handle)
{
   handle=handle;           /* seen this before ? */
   switch (e->data.msg.hdr.action)
   {
      case wimp_MDATASAVE:        /* import data not supported (yet?) */
                           werr(FALSE, "Data Import Not Supported");
                           return;
      case wimp_MDATALOAD:        /* insert data */
      case wimp_MDATAOPEN:
                           boo_loaddata();
                           break;
   }
}

/*====================================================================*/

static BOOL boo_initialise()
{
   menu boo_menu;

/* initialise RISC_OSlib modules */

   wimpt_init("DeBoo Program");
   res_init("Boo");
   resspr_init();
   template_init();
   dbox_init();
   visdelay_init();

/* Menu Info next */

   if ((boo_menu=menu_new("Boo",">Info,Quit"))==NULL)
      return FALSE; /* Failed to create menu */

/* Now for the icon bar */

   baricon("!Boo", (int)resspr_area(), boo_iconclick);
   if (!event_attachmenu(win_ICONBAR, boo_menu, boo_menuproc, 0))
      return FALSE;  /* Failed to attach menu */

/* Register an event handler for load ops via icon bar */

   win_register_event_handler(win_ICONBARLOAD, boo_load, 0);

/* That's it - ready to go now! */

   return TRUE;
}

/*=====================================================================*/

int main()
{
   if (boo_initialise())
   {
      while (TRUE)
         event_process();
   }
   return 0;
}
