/*
 * Macintosh font conversion program
 * (C)1987 Rico Mariani
 */

#include <stdio.h>
#include <exec/types.h>
#include <exec/nodes.h>
#include <libraries/diskfont.h>

#define HUNK_HEADER  0x3f3
#define HUNK_CODE    0x3e9
#define HUNK_RELOC32 0x3ec
#define HUNK_END     0x3f2

typedef struct {
	UBYTE FontType;
	UBYTE Padding;
	UWORD FirstChar;
	UWORD LastChar;
	UWORD WidMax;
	WORD  KernMax;
	WORD  NDescent;
	UWORD FRectWidth;
	UWORD FRectHeight;
	UWORD OWTLoc;
	UWORD Ascent;
	UWORD Descent;
	UWORD Leading;
	UWORD RowWords;
} FHEADER;

unsigned char *BitImage;
unsigned short LocTable[260];
unsigned short OWTable[260];
FILE *f;

char *rindex();
void *malloc();

main(argc,argv)
int argc;
char *argv[];
{
	int i,j,c;
	FHEADER h;
	ULONG RowBytes;
	ULONG num_chars, fontName, fontData, fontLoc, fontSpace;
	ULONG fontKern, fontEnd, fontLength;
	ULONG IStart, IEnd, CWidth, OW, Offset, Kern;
	ULONG uc, lock;
	char *s, buf[128];
	WORD entries, size;
	int padbytes;

	if(argc != 2) {
		fprintf(stderr,"Usage: %s fontname\n",argv[0]);
		exit(1);
	}

	s = rindex(argv[1],'.');
	if (!s) {
		fprintf(stderr,"Error fontname must be of the form:\n");
		fprintf(stderr,"\tname.pointsize\n");
		exit(1);
	}

	f = fopen(argv[1],"r");
	if (!f){
		fprintf(stderr,"Error can't open file '%s'\n",argv[1]);
		exit(1);
	}

	fread( &h, sizeof(h), 1, f);

	printf("Font Data for %s:\n",argv[1]);
	*s = '\0'; /* remove the suffix */
	printf("\tChars %d to %d\n",h.FirstChar, h.LastChar);
	printf("\tFont Rectangle (W,H) = (%d,%d)\n" ,
		h.FRectWidth, h.FRectHeight);
	printf("\tAscent = %d,  Descent = %d,  Leading = %d\n",
		h.Ascent, h.Descent, h.Leading);

	RowBytes = 2*h.RowWords;

	BitImage = malloc(h.FRectHeight * RowBytes);
	if (!BitImage) {
		printf("Error, no memory for bit image\n");
		exit(-1);
	}

	fread(BitImage, h.FRectHeight * RowBytes, 1, f);

	for(i = h.FirstChar; i <= h.LastChar+2; i++) {
		uc = fgetc(f);
		LocTable[i] = uc << 8 | fgetc(f);
	}

	for(i = h.FirstChar; i <= h.LastChar+2; i++) {
		uc = fgetc(f);
		OWTable[i] = uc << 8 | fgetc(f);
	}

	fclose(f);

	sprintf(buf,"fonts:%s",argv[1]);
	lock = CreateDir(buf);
	if (lock) UnLock(lock);

	sprintf(buf,"fonts:%s/%d",argv[1],h.FRectHeight);
	f = fopen(buf,"w");
	if (!f) {
		fprintf(stderr,"Error, can't open '%s' for write\n",buf);
		exit(1);
	}

	/* compute offsets into the code hunk */

	num_chars  = h.LastChar - h.FirstChar + 2;
	fontName   = 0x1a;
	fontData   = 0x6e;
	fontLoc    = fontData  + RowBytes * h.FRectHeight;
	fontSpace  = fontLoc   + (num_chars<<2);
	fontKern   = fontSpace + (num_chars<<1);
	fontEnd    = fontKern  + (num_chars<<1);

	/* long word align fontEnd */
	padbytes = 0;
	while (fontEnd & 3) {
		padbytes++;
		fontEnd++;
	}
	fontLength = fontEnd   - 0x3a;	         /* the font: label */

	outL(HUNK_HEADER);
	outL(0);		/* no hunk names */
	outL(1);		/* Size of hunk table */
	outL(0);		/* First Hunk */
	outL(0);		/* Last Hunk */
	outL(fontEnd>>2);	/* Size of Hunk 0 */

	outL(HUNK_CODE);
	outL(fontEnd>>2);	/* Size of this hunk */

	/* now here comes the data for the hunk */
	/* this first part is in case someone tries to run this */

	outW(0x7000);		/* MOVEQ.L #0,D0 */
	outW(0x4e75);		/* RTS */

	outL(0);		/* ln_Succ */
	outL(0);		/* ln_Pred */
	outB(NT_FONT);		/* ln_Type */
	outB(0);		/* ln_Pri  */
	outL(0x1a);		/* ln_Name -- will be relocated */
	outW(DFH_ID);		/* FileID */
	outW(1);		/* Revision */
	outL(0);		/* Segment */

/* fontName: */

	outZ(MAXFONTNAME);	/* output 32 zeros */

/* font: */

	outL(0);		/* ln_Succ */
	outL(0);		/* ln_Pred */
	outB(NT_FONT);		/* ln_Type */
	outB(0);		/* ln_Pri  */
	outL(0x1a);		/* ln_Name -- will be relocated */
	outL(0);		/* mn_ReplyPort */
	outW(fontLength);	/* nm_Length */
	outW(h.FRectHeight);	/* tf_YSize */
	outB(0);		/* tf_Style */
	outB(0x62);		/* tf_Flags */
	outW(h.FRectWidth);	/* tf_XSize */
	outW(h.Ascent);		/* ft_BaseLine */
	outW(1);		/* tf_BoldSmear */
	outW(0);		/* tf_Accessors */
	outB(h.FirstChar);	/* tf_LoChar */
	outB(h.LastChar);	/* tf_HiChar */
	outL(fontData);		/* tf_CharData */
	outW(RowBytes);		/* tf_Modulo */
	outL(fontLoc);		/* tf_CharLoc */
	outL(fontSpace);	/* tf_CharSpace */
	outL(fontKern);		/* tf_CharKern */

/* fontData: */

	fwrite(BitImage, RowBytes * h.FRectHeight, 1, f);

/* fontLoc: */

	/* note that there is an extra character in every font on both  */
	/* that Amiga and the Mac which is used when a character not in */
	/* the font is requested */

	for (i=h.FirstChar; i<= h.LastChar + 1; i++) {
		if (OWTable[i] == -1)
			c = h.LastChar+1;
		else
			c = i;

		IStart = LocTable[c];
		IEnd   = LocTable[c+1];
		outW(IStart);
		outW(IEnd-IStart);
	}

/* fontSpace: */

	for (i=h.FirstChar; i<= h.LastChar+1; i++) {
		OW = OWTable[i];
		if (OWTable[i] == -1) OW = OWTable[h.LastChar+1];

		CWidth = OW & 0xff;
		outW(CWidth);
	}

/* fontKern: */

	for (i=h.FirstChar; i<= h.LastChar+1; i++) {
		OW = OWTable[i];
		if (OWTable[i] == -1) OW = OWTable[h.LastChar+1];

		Offset = OW >> 8;
		Kern = h.KernMax + Offset;
		outW(Kern);

	}

	for (i=0;i<padbytes;i++) outB(0);

/* fontEnd: */

	outL(HUNK_RELOC32);
	outL(6);		/* of relocates number in this hunk */
	outL(0);		/* hunk 0 */
	outL(0x0e);		/* relocate reference to fontName: 1st */
	outL(0x44);		/* relocate reference to fontName: 2nd */
	outL(0x5c);		/* relocate reference to fontData:  */
	outL(0x62);		/* relocate reference to fontLoc:   */
	outL(0x66);		/* relocate reference to fontSpace: */
	outL(0x6a);		/* relocate reference to fontKern:  */
	outL(0);		/* zero to mark end */
	outL(HUNK_END);

	fclose(f);

	sprintf(buf,"fonts:%s.font",argv[1]);
	f = fopen(buf,"r+");
	if (!f) {
		f = fopen(buf,"w+");
		if (!f) {
			fprintf(stderr,"Error, can't create font header\n");
			exit(1);
		}
		outW(0x0f00);	/* font header */
		outW(0x0000);	/* number of font items */
	}

	fseek(f,2,0);

	fread(&entries,2,1,f);

	for (i=0;i<entries;i++) {
		fseek(f, 4+(260*i)+256, 0);
		fread(&size,2,1,f);	/* read in ysize */
		if (size == h.FRectHeight) {
		    printf("Amiga font of this size already exists");
		    printf("... overwritten\n");
		    exit(1);
		}
	}

	fseek(f,2,0);
	outW(++entries);
	fseek(f,0,2);
	sprintf(buf,"%s/%d",argv[1],h.FRectHeight);
	fwrite(buf,strlen(buf),1,f);
	for (i=strlen(buf);i<256;i++) fputc(0,f);
	outW(h.FRectHeight);
	outB(0);
	outB(0x62);
	fclose(f);
}

outB(b)
{
	fputc(b,f);
}

outW(w)
{
	fputc(w>>8,f);
	fputc(w&0xff,f);
}

outL(l)
{
	fwrite(&l,4,1,f);
}

outZ(n)
{
	int i;

	for (i=n;--i>=0;) fputc(0,f);
}
