/*
 * 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);
}
