/****** DFont2Obj ****************************************************
*
*   NAME
*       DFont2Obj - create a load file from a LoadSeg'd diskfont image
*
*   A hack, nothing more
*  Copyright (c) 1988 Commodore-Amiga, Inc.
* 
*  Executables based on this information may be used in software
*  for Commodore Amiga computers.  All other rights reserved.
* 
*  This information is provided "as is"; no warranties are made.
*  All use is at your own risk, and no liability or responsibility is assumed.
*********************************************************************/
#include        "exec/types.h"
#include        "exec/nodes.h"
#include        "exec/lists.h"
#include        "exec/memory.h"
#include        "exec/ports.h"
#include	"graphics/gfxbase.h"
#include	"graphics/text.h"
#include	"graphics/view.h"
#include        "libraries/dos.h"
#include	"libraries/diskfont.h"

#include	"stdio.h"

#ifdef	MANX
#include	"functions.h"
#endif

#define	HUNK_DATA	1002
#define	HUNK_RELOC32	1004
#define	HUNK_END	1010
#define	HUNK_HEADER	1011

#ifndef	ColorTextFont
#define	FSB_COLORFONT	6	/* this uses ColorTextFont structure */
#define	FSF_COLORFONT	0x40

/******	ColorTextFont node ******************************************/
/*-----	ctf_Flags --------------------------------------------------*/
#define	CT_COLORMASK	0x000F	/* mask to get to following color styles */
#define	CT_COLORFONT	0x0001	/* color map contains designer's colors */
#define	CT_GREYFONT	0x0002	/* color map describes even-stepped */
				/* brightnesses from low to high */
#define	CTB_MAPCOLOR	0	/* map ctf_FgColor to the rp_FgPen if it's */
#define	CTF_MAPCOLOR	0x0001	/* is a valid color within ctf_Low..ctf_High */

/*-----	ColorTextFont ----------------------------------------------*/
struct ColorTextFont {
    struct TextFont ctf_TF;
    UWORD	ctf_Flags;	/* extended flags */
    UBYTE	ctf_Depth;	/* number of bit planes */
    UBYTE	ctf_FgColor;	/* color that is remapped to FgPen */
    UBYTE	ctf_Low;	/* lowest color represented here */
    UBYTE	ctf_High;	/* highest color represented here */
    UBYTE	ctf_PlanePick;	/* PlanePick ala Images */
    UBYTE	ctf_PlaneOnOff;	/* PlaneOnOff ala Images */
    APTR	ctf_ColorMap;	/* struct ColorMap * for font */
    APTR	ctf_CharData[8]; /*pointers to bit planes ala tf_CharData */
};
#endif

struct ColorTextFont *FindName();
struct GfxBase *OpenLibrary();

ULONG *hunkBase;
FILE *file = 0;

ULONG FindRelocate(hunkNum, relocation, absolute)
ULONG *hunkNum, *relocation, *absolute;
{
    ULONG num;
    ULONG *currHunk;

    if (*absolute == 0) {
	*hunkNum = *relocation = 0xffffffff;
	return(0);
    }
    /* find offset of this absolute and cache in relocation array */
    *relocation = ((ULONG) absolute) - ((ULONG) &hunkBase[1]);
    /* find hunk and offset in hunk that this absolute points to */
    num = 0;
    currHunk = hunkBase;
    while (currHunk) {
	if ((*absolute >= ((ULONG) &currHunk[1])) &&
		(*absolute < (((ULONG) currHunk) + currHunk[-1]))) {
	    *hunkNum = num;
	    return(*absolute - ((ULONG) &currHunk[1]));
	}
	num++;
	currHunk = (ULONG *) (*currHunk<<2);
    }
    printf("ERROR: Could not find address 0x%lx in any hunk\n", *absolute);
    fclose(file);
    exit(20);
}


int GetNum(b)
char *b;
{
    int result, base;

    result = 0;
    base = 10;
    while (*b) {
	result *= base;
	if ((*b >= '0') && (*b <= '9')) result += *b - '0';
	else {
	    if (((*b >= 'a') && (*b <= 'f')) ||
		    ((*b >= 'A') && (*b <= 'F'))) {
		if (base != 16) break;
		result += (*b & 0x1f) + 9;
	    }
	    else if ((*b != 'x') && (*b != '$')) base = 16;
	    else break;
	}
	b++;
    }
    if (*b) {
	printf("ERROR: ill formed number\n");
	return(-1);
    }
    else return(result);
}


main(argc, argv)
int argc;
char *argv[];
{
    struct GfxBase *GfxBase;
    ULONG temp, temp2;
    ULONG *currHunk;
    struct ColorTextFont *ctf, *ctf2;
    int i, j, k;

    /* relocation information about the pointers in hunk 0	*/
    /* dfh_DF ln_Name, tf_Message mn_Node ln_Name,		*/
    /* tf_CharData, tf_CharLoc, tf_CharSpace, tf_CharKern,	*/
    /* ctf_ColorMap, ctf_ColorMap ColorTable, ctf_CharData[8]	*/
    ULONG hunkNum[16];		/* hunk number to relocate to */
    ULONG relocation[16];	/* offset in hunk */

    GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L);
    if (GfxBase == 0) {
	printf("ERROR: Cannot open \"graphics.library\"\n");
	exit(100);
    }
    if (argc >= 3) {
	file = fopen(argv[1], "w");
	if (file == 0) {
	    printf("ERROR: open failed for font file\n");
	    argc = 0;
	}
    }
    if (argc >= 3) {
      /* see if more than one with this name */
      ctf = FindName(&GfxBase->TextFonts, argv[2]);
      if (ctf) {
        if (FindName(ctf, argv[2])) {
          /* yes: get the one with this size */
          if (argc >= 4) {
            i = GetNum(argv[3]);
            if (i >= 0) {
              while ((ctf) && (ctf->ctf_TF.tf_YSize != i))
                ctf = FindName(ctf, argv[2]);
              if (ctf) {
                /* check for more than one */
                ctf2 = FindName(ctf, argv[2]);
                while ((ctf2) && (ctf2->ctf_TF.tf_YSize != i))
                  ctf2 = FindName(ctf2, argv[2]);
                if (ctf2) {
                  /* yes: get the one with this style */
		  if (argc >= 5) {
		    j = GetNum(argv[4]);
		    if (j >= 0) {
		      ctf = FindName(&GfxBase->TextFonts, argv[2]);
		      while ((ctf) && ((ctf->ctf_TF.tf_YSize != i) ||
			  (ctf->ctf_TF.tf_Style != j)))
			ctf = FindName(ctf, argv[2]);
		      if (ctf) {
			/* check for more than one */
			ctf2 = FindName(ctf, argv[2]);
			while ((ctf2) && ((ctf2->ctf_TF.tf_YSize != i) ||
			    (ctf2->ctf_TF.tf_Style != j)))
			  ctf2 = FindName(ctf2, argv[2]);
			if (ctf2) {
			  /* yes: get the one with this flags */
			  if (argc >= 6) {
			    k = GetNum(argv[5]);
			    if (k >= 0) {
			      ctf = FindName(&GfxBase->TextFonts, argv[2]);
			      while ((ctf) && ((ctf->ctf_TF.tf_YSize != i) ||
				  (ctf->ctf_TF.tf_Style != j) ||
				  (ctf->ctf_TF.tf_Flags != k)))
				ctf = FindName(ctf, argv[2]);
			      if (ctf) {
				/* check for more than one */
				ctf2 = FindName(ctf, argv[2]);
				while ((ctf2) && ((ctf2->ctf_TF.tf_YSize != i)
				    || (ctf->ctf_TF.tf_Style != j) ||
				    (ctf->ctf_TF.tf_Flags != k)))
				  ctf2 = FindName(ctf2, argv[2]);
				if (ctf2) {
				  printf("WARNING: There exists more than one font matching the specification.\n");
				  printf("         The first one found is being used.\n");
                                }
			      }
			      else /* ctf */ {
				printf("ERROR: No font with the specified flags\n");
				argc = 0;
			      }
			    }
			    else /* k */ argc = 0;
			  }
			  else /* argc */ {
			    printf("ERROR: More than one font with the specified name, size, and style\n");
			    argc = 0;
			  }
			}
		      }
		      else /* ctf */ {
		        printf("ERROR: No font with the specified flags\n");
			argc = 0;
		      }
		    }
		    else /* j */ argc = 0;
		  }
		  else /* argc */ {
		    printf("ERROR: More than one font with the specified name, and size\n");
		    argc = 0;
		  }
		}
	      }
	      else /* ctf */ {
		printf("ERROR: No font with the specified size\n");
		argc = 0;
	      }
            }
            else /* i */ argc = 0;
          }
          else /* argc */ {
            printf("ERROR: More than one font with the specified name\n");
            argc = 0;
          }
        }
      }
      else /* ctf */ {
        printf("ERROR: No font with the specified name\n");
        argc = 0;
      }
      CloseLibrary(GfxBase);
    }
    if (argc < 3) {
	printf(
	  "USAGE: DFont2Obj <file> <font-name> [<size>] [<style>] [<flags>]\n");
	if (file) fclose(file);
	exit(5);
    }
    if ((ctf->ctf_TF.tf_Flags & FPF_DISKFONT) == 0) {
	printf("ERROR: font must be a disk font\n");
	fclose(file);
	exit(10);
    }
    printf("\"%s\" Y %ld S $%02lx F $%02lx\n",
	    ctf->ctf_TF.tf_Message.mn_Node.ln_Name, ctf->ctf_TF.tf_YSize,
	    ctf->ctf_TF.tf_Style, ctf->ctf_TF.tf_Flags);
    hunkBase = (ULONG *) ((ULONG) ctf - 62);
printf("hunkBase 0x%lx\n", hunkBase);
    /* hunk header */
    temp = HUNK_HEADER;
    fwrite(&temp, 1, 4, file);
    /* resident library names */
    temp = 0;
    fwrite(&temp, 1, 4, file);
    /* table size */
    temp = 1;			/* include the hunk base */
    currHunk = hunkBase;
    while (*currHunk) {
	temp++;
	currHunk = (ULONG *) (*currHunk<<2);
    }
    fwrite(&temp, 1, 4, file);
    /* first hunk (zero) */
    fwrite(currHunk, 1, 4, file);
    /* last hunk (size-1) */
    temp--;
    fwrite(&temp, 1, 4, file);
    /* hunk sizes */
    currHunk = hunkBase;
    do {
	temp = (currHunk[-1]>>2) - 2;
	fwrite(&temp, 1, 4, file);
	currHunk = (ULONG *) (*currHunk<<2);
    }
	while (currHunk);
    /* write first hunk */
    /*   write the hunk start */
    temp = HUNK_DATA;
    fwrite(&temp, 1, 4, file);
    /*   write the hunk size */
    temp = (hunkBase[-1]>>2) - 2;
    fwrite(&temp, 1, 4, file);
    /*   write MOVEQ #100,D0 / RTS */
    temp = 0x70644e75;
    fwrite(&temp, 1, 4, file);
    /*   write dfh_DF ln_Succ, ln_Pred */
    temp = 0;
    for (i = 0; i < 8; i++) fwrite(&temp, 1, 1, file);
    /*   write dfh_DF ln_Type, ln_Pri */
    temp = 0x0c000c00;		/* NT_FONT */
    fwrite(&temp, 1, 2, file);
    /*   write dfh_DF ln_Name */
    temp = 0x1a;		/* 8 + offset(dfh_Name) */
    hunkNum[0] = 0;
    relocation[0] = 0xe;	/* 8 + offset(dfh_DF ... Name) */
    fwrite(&temp, 1, 4, file);
    /*   write dfh_FileID, dfh_Revision */
    temp = 0x0f800000;		/* DFH_ID, revision 0 */
    fwrite(&temp, 1, 4, file);
    /*   write dfh_Segment, dfh_Name */
    temp = 0;
    for (i = 0; i < (4+MAXFONTNAME); i++) fwrite(&temp, 1, 1, file);
    /*   write tf_Message mn_Node ln_Succ, ln_Pred */
    for (i = 0; i < 8; i++) fwrite(&temp, 1, 1, file);
    /*   write tf_Message mn_Node ln_Type, ln_Pri */
    temp = 0x0c000c00;		/* NT_FONT */
    fwrite(&temp, 1, 2, file);
    /*   write tf_Message mn_Node ln_Name */
    temp = 0x1a;		/* 8 + offset(dfh_Name) */
    hunkNum[1] = 0;
    relocation[1] = 0x44;	/* 8 + offset(tf ... Name) */
    fwrite(&temp, 1, 4, file);
    /*   write tf_Message mn_ReplyPort, mn_Length */
    temp = 0;
    fwrite(&temp, 1, 4, file);
    fwrite(&temp, 1, 2, file);
    /*   write tf_YSize thru tf_BoldSmear */
    fwrite(&ctf->ctf_TF.tf_YSize, 1, 10, file);
    /*   write tf_Accessors */
    fwrite(&temp, 1, 2, file);
    /*   write tf_LoChar thru tf_HiChar */
    fwrite(&ctf->ctf_TF.tf_LoChar, 1, 2, file);
    /*   write tf_CharData */
    temp = FindRelocate(hunkNum+2, relocation+2, &ctf->ctf_TF.tf_CharData);
    fwrite(&temp, 1, 4, file);
    /*   write tf_Modulo */
    fwrite(&ctf->ctf_TF.tf_Modulo, 1, 2, file);
    /*   write tf_CharLoc */
    temp = FindRelocate(hunkNum+3, relocation+3, &ctf->ctf_TF.tf_CharLoc);
    fwrite(&temp, 1, 4, file);
    /*   write tf_CharSpace */
    temp = FindRelocate(hunkNum+4, relocation+4, &ctf->ctf_TF.tf_CharSpace);
    fwrite(&temp, 1, 4, file);
    /*   write tf_CharKern */
    temp = FindRelocate(hunkNum+5, relocation+5, &ctf->ctf_TF.tf_CharKern);
    fwrite(&temp, 1, 4, file);
    /*   check for ColorTextFont */
    if (ctf->ctf_TF.tf_Style & FSF_COLORFONT) {
	fwrite(&ctf->ctf_Flags, 1, 8, file);
	/*   ctf_ColorMap */
	temp = FindRelocate(hunkNum+6, relocation+6, &ctf->ctf_ColorMap);
	fwrite(&temp, 1, 4, file);
	if (temp != 0) {
	    if (temp != 0x9a) {
		printf("ERROR: ColorMap not immediately after ColorTextFont\n");
		fclose(file);
		exit(20);
	    }
	    /* ctf_ColorMap ColorTable */
	    temp = FindRelocate(hunkNum+7, relocation+7,
		    &((struct ColorMap *) ctf->ctf_ColorMap)->ColorTable);
	    if (temp != 0xa2) {
		printf("ERROR: ColorTable not immediately after ColorMap\n");
		fclose(file);
		exit(20);
	    }
	}
	else hunkNum[7] = relocation[7] = 0xffffffff;

	/*   ctf_Planes */
	for (i = 0; i < ctf->ctf_Depth; i++) {
	    temp = FindRelocate(hunkNum+i+8, relocation+i+8,
		    &ctf->ctf_CharData[i]);
	    fwrite(&temp, 1, 4, file);
	}
	temp = 0;
	for (; i < 8; i++) {
	    hunkNum[i+8] = relocation[i+8] = 0xffffffff;
	    fwrite(&temp, 1, 4, file);
	}
	temp = sizeof(struct DiskFontHeader) + 8 -
		sizeof(struct TextFont) + sizeof(struct ColorTextFont);
	/* write ctf_ColorMap ColorTable if appropriate */
	if (ctf->ctf_ColorMap) {
	    fwrite(ctf->ctf_ColorMap, 1, 4, file);
	    temp2 = 0xa2;
	    fwrite(&temp2, 1, 4, file);
	    temp += 8;
	}
    }
    else {
	for (i = 6; i < 16; i++) hunkNum[i] = relocation[i] = 0xffffffff;
	temp = sizeof(struct DiskFontHeader) + 8;
    }
    /*   write the rest of this first hunk */
    if (hunkBase[-1] - temp) {
	fwrite(((ULONG) hunkBase) + temp, 1, hunkBase[-1] - temp - 4, file);
    }
    /* write the relocation record for this hunk */
    temp = HUNK_RELOC32;
    fwrite(&temp, 1, 4, file);
    for (;;) {
	/* find the minimum hunk not yet referenced */
	temp = 0xffffffff;
	for (i = 0; i < 15; i++)
	    if (hunkNum[i] < temp) temp = hunkNum[i];
	if (temp == 0xffffffff) break;
	/* count the relocation entries */
	temp2 = 0;
	for (i = 0; i < 15; i++)
	    if (hunkNum[i] == temp) temp2++;
	/* write the offset count */
	fwrite(&temp2, 1, 4, file);
	/* write the hunk number */
	fwrite(&temp, 1, 4, file);
	/* write out all the matching relocation values */
	for (i = 0; i < 15; i++)
	    if (hunkNum[i] == temp) {
		fwrite(relocation+i, 1, 4, file);
		hunkNum[i] = 0xffffffff;
	    }
    }
    /* terminate the relocation record for this hunk */
    temp = 0;
    fwrite(&temp, 1, 4, file);
    /* write the hunk end mark */
    temp = HUNK_END;
    fwrite(&temp, 1, 4, file);
    /* write any other hunks */
    currHunk = (ULONG *) ((*hunkBase)<<2);
    while (currHunk) {
	/* write the hunk start */
	temp = HUNK_DATA;
	fwrite(&temp, 1, 4, file);
	/*   write the hunk size */
	temp = (currHunk[-1]>>2) - 2;
	fwrite(&temp, 1, 4, file);
	/* write the hunk */
	fwrite(&currHunk[1], 1, currHunk[-1] - 8, file);
	/* write the hunk end mark */
	temp = HUNK_END;
	fwrite(&temp, 1, 4, file);
	currHunk = (ULONG *) ((*currHunk)<<2);
    }
    fclose(file);
}
