[comp.sys.next] Macintosh Font Resource Converter

mark@monitor.plymouth.mi.us (Mark Harris) (07/26/90)

The following program converts Type 1 fonts from Mac format to NeXT
format.  Type 3 fonts that are sent to the NeXT as text files, along
with their corresponding .afm file, should work fine without conversion.

#!/bin/sh
#
# This shell archive contains the following files:
#     README
#     Makefile
#     mfrc.h
#     mfrc.c
#
# To extract, remove all lines before the '#!/bin/sh' line and after
# the 'exit' line, and run the resulting file through sh.
#
echo x - README 1>&2
sed 's/.//' >README <<'*-*-END-of-README-*-*'
-	"Can I use Adobe postscript fonts I purchased for the
-	Mac and port them over to the cube, and if so, how?
-
-	The answer to this question is, in practice, no."
-					-- NeXT Answers, Apr '90
-
-But now you can, very easily with this program!
-
-Entitled "mfrc", for Macintosh Font Resource Converter, it takes
-Type 1 PostScript fonts and produces a version usable by the NeXT.
-(The fonts must have the accompanying AFM [Adobe Font Metric] file
-for it to be recognized by the cube.)
-
-The font can be transferred from the Macintosh to the NeXT by
-whatever means available; "mfrc" understands the MacBinary format.
-The quickest way to install a font from the Mac is to transfer the
-printer-downloadable version of the font (Macintosh file type
-'LWFN') and the AFM file (type 'TEXT') in MacBinary format.  After
-the transfer, running "mfrc" will convert the downloadable font to
-a standard PostScript font format, and strip the MacBinary header
-off the AFM file.
-
-"mfrc" will also accept files that have been previously converted
-using 'mcvert' or other similar Macintosh file-conversion utilities.
-The AFM file is not required to be present for "mfrc" to run; if
-it is not found, only the font is converted.  No messages or
-warnings about missing AFM files are given.
-
-A sample conversion run might look like this:
-
-	# mkdirs /LocalLibrary/Fonts/{afm,outline}
-
-	% mfrc foo* bar
-	foo: converted to Foo-Roman.
-	foo.afm: File not type LWFN.
-	foodem: converted to Foo-Demi.
-	foodem.afm: File not type LWFN.
-	foodemita: converted to Foo-DemiItalic.
-	foodemita.afm: File not type LWFN.
-	foohea: converted to Foo-Heavy.
-	foohea.afm: File not type LWFN.
-	fooheaita: converted to Foo-HeavyItalic.
-	fooheaita.afm: File not type LWFN.
-	fooita: converted to Foo-Italic.
-	fooita.afm: File not type LWFN.
-	bar: converted to Bar-Medium.
-	% mv [A-Z]*.afm /LocalLibrary/Fonts/afm
-	% mv [A-Z]* /LocalLibrary/Fonts/outline
-	% buildafmdir /LocalLibrary/Fonts
-
-
-"mfrc" Specifics:
-Create /LocalLibrary/Fonts if it does not exist.  If you are not
-the administrator of your NeXT, you can create ~/Fonts, and install
-them there instead.
-
-PostScript font names are automatically extracted from the first
-POST text-resource block.  If a font name definition is not found
-(i.e., a /FontName definition), the existing filename, appended
-with '.psf' is used.  You should determine the correct PostScript
-name and rename any '.psf' files before installing them.
-
-If the file contains a MacBinary header, "mfrc" will only convert
-it if the type is 'LWFN'.  If the MacBinary header has been stripped
-by another utility, "mfrc" will check for POST resources, and will
-give an error if none are found.
-
-The cube will not recognize any fonts until after the 'buildafmdir'
-command has been run.  "The 'buildafmdir' utility lets the AppKit
-know that the fonts in that directory have changes, so that Font
-Panels will show the new font right away." (from the NeXT Manual)
-
-
-"mfrc" Information:
-Program written by Mark Harris -- Documentation by Eddy J. Gurney
-<mark@monitor.plymouth.mi.us>     <eddy@jafus.mi.org>
-                                  Aim your flamethrowers this way,
-                                  not at Mark! (I'm taking the heat)
-
-"mfrc" is Copyright 1990 by Mark Harris.  The program may be
-distributed without charge provided this notice and accompanying
-documentation is included.  No warranties are expressed or implied.
*-*-END-of-README-*-*
echo x - Makefile 1>&2
sed 's/.//' >Makefile <<'*-*-END-of-Makefile-*-*'
-# simple mfrc makefile
-
-LIBS=-lsys_s
-CFLAGS=-O -s
-
-mfrc:	mfrc.c mfrc.h
-	$(CC) $(CFLAGS) -o $@ $*.c $(LIBS)
-
-install: mfrc
-	chown root.wheel mfrc
-	chmod 755 mfrc
-	mv mfrc /usr/local/bin
*-*-END-of-Makefile-*-*
echo x - mfrc.h 1>&2
sed 's/.//' >mfrc.h <<'*-*-END-of-mfrc.h-*-*'
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long ulong;
-
-#define POST_TYPE (('P'<<24)+('O'<<16)+('S'<<8)+'T')
-
-/* Format of a bin file:  (From mcvert by Doug Moore)
-A bin file is composed of 128 byte blocks.  The first block is the
-info_header (see below).  Then comes the data fork, null padded to fill the
-last block.  Then comes the resource fork, padded to fill the last block.  A
-proposal to follow with the text of the Get Info box has not been implemented,
-to the best of my knowledge.  Version, zero1 and zero2 are what the receiving
-program looks at to determine if a MacBinary transfer is being initiated.
-*/ 
-typedef struct {     /* info file header (128 bytes). Unfortunately, these
-                        longs don't align to word boundaries */
-	byte version;           /* there is only a version 0 at this time */
-	byte nlen;              /* Length of filename. */
-	byte name[63];          /* Filename (only 1st nlen are significant)*/
-	byte type[4];           /* File type. */
-	byte auth[4];           /* File creator. */
-	byte flags;             /* file flags: LkIvBnSyBzByChIt */
-	byte zero1;             /* Locked, Invisible,Bundle, System */
-	                        /* Bozo, Busy, Changed, Init */
-	byte icon_vert[2];      /* Vertical icon position within window */
-	byte icon_horiz[2];     /* Horizontal icon postion in window */
-	byte window_id[2];      /* Window or folder ID. */
-	byte protect;           /* = 1 for protected file, 0 otherwise */
-	byte zero2;
-	byte dlen[4];           /* Data Fork length (bytes) -   most sig.  */
-	byte rlen[4];           /* Resource Fork length         byte first */
-	byte ctim[4];           /* File's creation date. */
-	byte mtim[4];           /* File's "last modified" date. */
-	byte ilen[2];           /* GetInfo message length */
-	byte flags2;            /* Finder flags, bits 0-7 */
-	byte unused[14];       
-	byte packlen[4];        /* length of total files when unpacked */
-	byte headlen[2];        /* length of secondary header */
-	byte uploadvers;        /* Version of MacBinary II that the uploading program is written for */
-	byte readvers;          /* Minimum MacBinary II version needed to read this file */
-	byte crc[2];            /* CRC of the previous 124 bytes */
-	byte padding[2];        /* two trailing unused bytes */
-	} info_header;
-
-typedef struct {
-	long  rtype;
-	short nrsc;
-	short offset;
-	} type_info;
-
-typedef struct {
-	short id;
-	short name;
-	long  offset;
-	long  reserved;
-	} ref_list;
-
-#define POST_TEXT 1
-#define POST_DATA 2
-#define POST_END  5
*-*-END-of-mfrc.h-*-*
echo x - mfrc.c 1>&2
sed 's/.//' >mfrc.c <<'*-*-END-of-mfrc.c-*-*'
-#include <stdio.h>
-#include <sys/types.h>
-#include <strings.h>
-#include <ctype.h>
-#include <stdlib.h>
-
-#include "mfrc.h"
-
-int cmpid(rl1,rl2)
-ref_list *rl1, *rl2;
-{
-    return rl1->id - rl2->id;
-}
-
-int main(argc,argv)
-int argc;
-char **argv;
-{
-    char *progname;
-    FILE *fp, *of;
-    info_header infobuf;
-    type_info typbuf;
-    ref_list *rfptr, *rfent;
-    unsigned char *pdata, *cp, *cp2;
-    char onm[BUFSIZ], anm[BUFSIZ];
-    unsigned long rsrc,rsd,rsm;
-    long rslen;
-    unsigned short rstl;
-    short rstypes;
-    int c,len;
-
-    progname = argv[0];
-    if (argc < 2) {
-        fprintf(stderr, "Usage: %s file ...\n", progname);
-        exit(1);
-    }
-
-    while (--argc) {
-        ++argv;
-        fp = fopen(*argv,"r");
-        if (fp == NULL) {
-            perror(*argv);
-            continue;
-        }
-
-        fprintf(stderr,"%s: ",*argv);
-        if (fread(&infobuf,sizeof(info_header),1,fp) < 1 ) {
-            fclose(fp);
-            fprintf(stderr,"No header\n");
-            continue;
-        }
-
-        if (infobuf.version || infobuf.nlen) {
-            rsrc = sizeof(info_header) + (infobuf.dlen[0]<<24) +
-              (infobuf.dlen[1]<<16) + (infobuf.dlen[2]<<8) +
-              infobuf.dlen[3];
-
-            if ((infobuf.type[0]!='L') || (infobuf.type[1]!='W')
-              || (infobuf.type[2]!='F')
-              || (infobuf.type[3]!='N')) {
-                fclose(fp);
-                fprintf(stderr,"File not type LWFN.\n");
-                continue;
-            }
-
-            if (rsrc > sizeof(info_header))
-                fseek(fp,rsrc,SEEK_SET);
-        }
-        else rsrc = 0;
-
-        fread(&rsd,4,1,fp);
-        fread(&rsm,4,1,fp);
-        fseek(fp,rsrc+rsm+24,SEEK_SET);
-        fread(&rstl,2,1,fp);
-        fseek(fp,rsrc+rsm+rstl,SEEK_SET);
-        fread(&rstypes,2,1,fp);
-
-        while (rstypes >= 0) {
-            fread(&typbuf,sizeof(typbuf),1,fp);
-            if (typbuf.rtype == POST_TYPE)
-                break;
-            --rstypes;
-        }
-
-        if (rstypes < 0) {
-            fclose(fp);
-            fprintf(stderr,"No POST resources.\n");
-            continue;
-        }
-
-        /* Read list of POST resources and sort by resource ID */
-        fseek(fp,rsrc+rsm+rstl+typbuf.offset,SEEK_SET);
-        rfptr = (ref_list *)malloc(sizeof(ref_list) * (typbuf.nrsc+1));
-        fread(rfptr,sizeof(ref_list),typbuf.nrsc+1,fp);
-        qsort(rfptr,typbuf.nrsc+1,sizeof(ref_list),cmpid);
-
-        /* Process POST resources */
-        of=NULL;
-        onm[0] = '\0';
-        rfent = rfptr;
-        len=0;
-        while (typbuf.nrsc-- >= 0) {
-            fseek(fp,rsrc+rsd+(rfent->offset & 0xffffff),SEEK_SET);
-            fread(&rslen,4,1,fp);
-            pdata = (unsigned char *)malloc(rslen);
-            fread(pdata,rslen,1,fp);
-            switch (pdata[0]) {
-                case POST_TEXT:
-                    if (!of) {
-                        cp=pdata+2;
-                        while (cp < pdata+rslen) {
-                            if (*cp == '/') {
-                                if (!strncmp((char *)cp,"/FontName",9)) {
-                                    cp += 9;
-                                    if (isspace(*cp)) {
-                                        while (*cp++ != '/');
-                                        cp2=(unsigned char *)onm;
-                                        while (!isspace((char)*cp))
-                                            *cp2++ = *cp++;
-                                        *cp2 = '\0';
-                                        break;
-                                    }
-                                }
-                            }
-                            cp++;
-                        }
-                        if (!onm[0])
-                            sprintf(onm,"%s.psf",*argv);
-                        of=fopen(onm,"w");
-                        if (!of) {
-                            perror(onm);
-                            free(pdata);
-                            fprintf(stderr,"%s: ",*argv);
-                            continue;
-                        }
-                    }
-                    cp=pdata+2;
-                    while (cp < pdata+rslen) {
-                        if (*cp == '\r')
-                            *cp='\n';
-                        cp++;
-                    }
-                    if (len) {
-                        fprintf(of,"\n");
-                        len=0;
-                    }
-                    fwrite(pdata+2,rslen-2,1,of);
-                    break;
-                case POST_DATA:
-                    if (!of) {
-                        fprintf(stderr, "Data before text.\n");
-                        free(pdata);
-                        fprintf(stderr,"%s: ",*argv);
-                        continue;
-                    }
-                    cp=pdata+2;
-                    while (cp < pdata+rslen) {
-                        fprintf(of,"%02x",*cp++);
-                        if (++len > 31) {
-                            fprintf(of,"\n");
-                            len = 0;
-                        }
-                    }
-                    break;
-                case POST_END:
-                    break;
-                default:
-                    fprintf(stderr, "Unknown POST resource type %d.\n",
-                            pdata[0]);
-            } /* end switch */
-            free(pdata);
-            ++rfent;
-        } /* while more POST resources */
-        if (len)
-            fprintf(of,"\n");
-        fclose(of);
-        fclose(fp);
-        free(rfptr);
-
-        /* check for afm file */
-        if (!onm[0]) {
-            fprintf(stderr,"no font data.\n");
-            continue;
-        }
-        fprintf(stderr,"converted to %s.\n",onm);
-        strcpy(anm,*argv);
-        strcat(anm,".afm");
-        fp=fopen(anm,"r");
-        if (!fp)
-            continue;
-
-        if (fread(&infobuf,sizeof(info_header),1,fp) < 1) {
-            fclose(fp);
-            continue;
-        }
-
-        if (infobuf.version || infobuf.nlen) {
-            rslen = (infobuf.dlen[0]<<24) + (infobuf.dlen[1]<<16)
-              + (infobuf.dlen[2]<<8) + infobuf.dlen[3];
-            if (rslen < 1) {
-                fclose(fp);
-                continue;
-            }
-        }
-        else rslen=0;
-
-        strcat(onm,".afm");
-        of=fopen(onm,"w");
-        if (!of) {
-            fclose(fp);
-            continue;
-        }
-        do {
-            c=getc(fp);
-            if (c=='\r')
-                putc('\n',of);
-            else
-                putc(c,of);
-        } while (--rslen);
-        fclose(of);
-        fclose(fp);
-    } /* while more files */
-
-    return 0;
-} /* end main */
*-*-END-of-mfrc.c-*-*
exit