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