/* This file is macfont.h * * Copyright (C) 1993 by Norman Walsh * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************************************************************/ #include #include "mactypes.h" #include "macio.h" #include "mac2bdf.h" #include "applestd.h" #define PTRSIZE 4 #define MIN(x,y) ((x) > (y) ? (y) : (x)) #define Vers "1.1" extern char *optarg; extern int optind, opterr; int Mac_typeCount; int POSTnum, FONDnum, NFNTnum; RsrcHdrStruct Mac_header; RsrcMapStruct Mac_map; RsrcTypeStruct *Mac_types; RsrcRefStruct **Mac_refs; FILE *input; FILE *output; int rc; char **style_names; char **style_longnames; char *familyname; char *weight; char *encoding_scheme; int debug = 0; void dump_mac_header(RsrcHdrStruct h, RsrcMapStruct m) { printf("Mac header:\t\tMac map:\n"); printf("DataOffset (4): 0x%04x\tNextMap (4) : 0x%04x\n", h.DataOffset, m.NextMap); printf("MapOffset (4): 0x%04x\tFileRef (2) : %4d\n", h.MapOffset, m.FileRef); printf("DataLen (4): %4d\tFileAttr (2) : %4d\n", h.DataLen, m.FileAttr); printf("MapLen (4): %4d\tTypeOffset (2) : %4d\n", h.MapLen, m.TypeOffset); printf("\t\t\tNameOffset (2) : %4d\n", m.NameOffset); printf("\n"); } void dump_mac_info(RsrcTypeStruct t, RsrcRefStruct r) { printf("Mac type:\t\tMac ref:\n"); printf("Name (4) : %c%c%c%c\tIdent (2) : %6d\n", t.Name[0], t.Name[1], t.Name[2], t.Name[3], r.Ident); printf("Count (2) : %4d\tNameOffset (2) : 0x%04x\n", t.Count, r.NameOffset); printf("RefOffset (2) : 0x%04x\tAttr (1) : %d\n", t.RefOffset, r.Attr); printf("\t\t\tDataOffset (2) : 0x%04x\n", r.DataOffset); printf("\n"); } void dump_mac_info2(RsrcRefStruct r) { printf("\t\t\tMac ref:\n"); printf("\t\t\tIdent (2) : %6d\n", r.Ident); printf("\t\t\tNameOffset (2) : 0x%04x\n", r.NameOffset); printf("\t\t\tAttr (1) : %d\n", r.Attr); printf("\t\t\tDataOffset (2) : 0x%04x\n", r.DataOffset); printf("\n"); } void dump_mac_nfnt(RsrcNfntStruct n, int id) { printf("Mac NFNT (%d)\n", id); printf("FontType : %6d\n", n.FontType); printf("FirstChar : %6d\n", n.FirstChar); printf("LastChar : %6d\n", n.LastChar); printf("WidMax : %6d\n", n.WidMax); printf("KernMax : %6d\n", n.KernMax); printf("NDescent : %6d\n", n.NDescent); printf("FRectWidth : %6d\n", n.FRectWidth); printf("FRectHeight : %6d\n", n.FRectHeight); printf("OWTLoc : 0x%04x\n", n.OWTLoc); printf("Ascent : %6d\n", n.Ascent); printf("Descent : %6d\n", n.Descent); printf("Leading : %6d\n", n.Leading); printf("RowWords : %6d\n\n", n.RowWords); } void dump_mac_fond(RsrcFondStruct f, int id) { int count; printf("Mac FOND (%d)\n", id); printf("Flag : %6d\n", f.Flag); printf("FamilyId : %6d\n", f.FamilyId); printf("FirstChar : %6d\n", f.FirstChar); printf("LastChar : %6d\n", f.LastChar); printf("Ascent : %6d\n", f.Ascent); printf("Descent : %6d\n", f.Descent); printf("Leading : %6d\n", f.Leading); printf("WidMax : %6d\n", f.WidMax); printf("WidTblOfs (4) : 0x%04x\n", f.WidTblOfs); printf("KrnTblOfs (4) : 0x%04x\n", f.KrnTblOfs); printf("StyTblOfs (4) : 0x%04x\n", f.StyTblOfs); for (count = 0; count < 9; count++) printf(" FamStyProp %d: %6d\n", count, f.FamStyProp[count]); printf("Intrnatnl (4) : %6d\n", f.Intrnatnl); printf("FontVers : %6d\n", f.FontVers); for (count = 0; count < f.NumFonts; count++) { printf(" ResourceId : %6d\n", f.AssocTable[count].ResourceNumber); printf(" StyleCode : %6d\n", f.AssocTable[count].StyleCode); printf(" PointSize : %6d\n", f.AssocTable[count].PointSize); } printf("\n"); } void write_post(int count, int offset) { int datalen,post_type,filler; int place,hexplace,rowlen,newplace; unsigned char *buffer, *newbuf; char hexdigits[16] = "0123456789ABCDEF"; fseek (input, offset, 0); datalen = read_macint() - 2; post_type = read_macchar(); filler = read_macchar(); while (count > 0 && post_type != 5) { buffer = (char *) malloc(datalen); fread (buffer, 1, datalen, input); switch (post_type) { case 0: /* comment */ break; case 1: /* ASCII text */ newbuf = (char *) malloc(2*datalen); /* 2 is a guesstimate */ for (place = 0, newplace=0; place < datalen; place++) { switch (buffer[place]) { case 13: newbuf[newplace++] = 10; break; case 0251: newbuf[newplace++] = '('; newbuf[newplace++] = 'C'; newbuf[newplace++] = ')'; break; default: newbuf[newplace++] = buffer[place]; break; } } fwrite (newbuf, 1, newplace, output); free(newbuf); break; case 2: /* hexidecimal data */ newbuf = (char *) malloc(3*datalen); /* 3 is overkill */ for (place = 0, hexplace = 0, rowlen = 0; place < datalen; place++) { newbuf[hexplace++] = hexdigits[(buffer[place] >> 4) & 0x0F]; newbuf[hexplace++] = hexdigits[buffer[place] & 0x0F]; rowlen += 2; if (rowlen > 63) { newbuf[hexplace++] = 10; rowlen = 0; } } if (rowlen != 0) newbuf[hexplace++] = 10; fwrite(newbuf, 1, hexplace, output); free(newbuf); break; case 3: /* end-of-file marker */ break; case 4: /* font program is in data fork */ printf("Can't handle POST resources in the data fork.\n"); exit(1); break; case 5: /* end of font program */ break; } free (buffer); datalen = read_macint() - 2; post_type = read_macchar(); filler = read_macchar(); count--; } } float frac2real(int W) { float R; int I; R = (W & 0x0FFF); R = R / 4096.0; W = (W >> 12) & 0x0F; if (W >= 0x08) { W = W ^ 0xFFFF; W = (W + 1) & 0x0F; I = -W; } else I = W; R = R + I; return R; } void get_style_names (int offset, int num_styles) { int count, place, actual, strcnt, namecnt; unsigned char SNT[4096]; unsigned short int SNPos[64]; char *SPtr; char *EncStr; unsigned short int Class; int EncTblOfs; unsigned char StyIdxTbl[48]; char **strings; fseek (input, offset, 0); count = read_macint(); Class = read_macshortint(); EncTblOfs = read_macint(); read_macint(); /* skip the reserved word */ for (count = 0; count < 48; count++) StyIdxTbl[count] = read_macchar() - 1; if (EncTblOfs != 0) { printf("Info: This file contains an encoding table...\n"); } strcnt = read_macshortint(); fread (SNT+2, 1, 126, input); place = 2; SNPos[0] = place; for (count = 1; count < 64; count++) { place = place + SNT[SNPos[count-1]] + 1; SNPos[count] = place; } strings = (char **) malloc (strcnt * PTRSIZE); for (count = 0; count < strcnt; count++) { int slen; char *sptr; slen = SNT[SNPos[count]]; sptr = (char *) malloc(slen+1); strncpy(sptr,&SNT[SNPos[count]+1],slen); *(sptr+slen) = 0; strings[count] = sptr; } familyname = strings[0]; style_names = (char **) malloc((num_styles+1) * PTRSIZE); style_longnames = (char **) malloc((num_styles+1) * PTRSIZE); for (count = 0; count < num_styles; count++) { int slen; char *sptr,*strnum; char *nptr,*lnptr; sptr = strings[0]; slen = strlen(sptr); if (strcnt > 1) { strnum = strings[StyIdxTbl[count]]; while (*strnum) { sptr = strings[*strnum-1]; slen += strlen(sptr); strnum++; } } style_names[count] = (char *) malloc(slen+1); style_longnames[count] = (char *) malloc(slen+1); nptr = style_names[count]; lnptr = style_longnames[count]; sptr = strings[0]; slen = strlen(sptr); strncpy (nptr, sptr, MIN(slen,5)); nptr += MIN(slen,5); *nptr = 0; strcpy (lnptr, sptr); lnptr += slen; *lnptr = 0; if (strcnt > 1) { strnum = strings[StyIdxTbl[count]]; while (*strnum) { sptr = strings[*strnum-1]; slen = strlen(sptr); strncpy (nptr, sptr, MIN(slen,3)); nptr += MIN(slen,3); *nptr = 0; strcpy (lnptr, sptr); lnptr += slen; *lnptr = 0; strnum++; } } } style_names[num_styles] = 0; style_longnames[num_styles] = 0; } void write_kerns(int offset, FILE *afm) { int NumKernTbls, StyleCode, NumKernPairs; int count; unsigned char L1, L2; int Frac; fseek(input, offset, 0); read_macint(); /* skip length, or something? */ NumKernTbls = read_macshortint(); StyleCode = read_macshortint(); NumKernPairs = read_macshortint(); fprintf(afm, "StartKernData\n"); fprintf(afm, "StartKernPairs %d\n", NumKernPairs); for (count = 0; count < NumKernPairs; count++) { L1 = read_macchar(); L2 = read_macchar(); Frac = read_macshortint(); if (encoding[L1] != 0 && encoding[L2] != 0) fprintf(afm, "KPX %s %s %d\n", encoding[L1], encoding[L2], (int) (frac2real(Frac)*1000)); } fprintf(afm, "EndKernPairs\n"); fprintf(afm, "EndKernData\n"); } void write_nfnt(int offset, FontEntryFormat font_entry, char *name,int id, int sequential) { RsrcNfntStruct Nfnt; int datalen; unsigned char *buf; fseek (input, offset, 0); datalen = read_macint(); Nfnt = read_mac_nfnt(); if (debug) dump_mac_nfnt(Nfnt, id); fseek (input, offset, 0); datalen = read_macint(); buf = (char *) malloc (datalen); fread (buf, 1, datalen, input); if (sequential) name = "mf"; FontDump(buf, name, font_entry.StyleCode, font_entry.PointSize); free(buf); return; } void write_fond(int offset, int id, int afmopt, int bdfopt, int sequential) { int fonddatalen,datalen,count,tblcount; unsigned char *buffer; RsrcFondStruct Fond; unsigned short int TableCount, Style, Width; unsigned short int **Widths; unsigned short int *curWidths; FILE *afm; fseek (input, offset, 0); fonddatalen = read_macint(); Fond = read_mac_fond(); if (debug) dump_mac_fond(Fond, id); fseek (input, offset+Fond.WidTblOfs, 0); datalen = read_macshortint(); datalen = read_macshortint(); TableCount = read_macshortint()+1; Widths = (unsigned short int **) malloc (TableCount * PTRSIZE); for (tblcount = 0; tblcount < TableCount; tblcount++) { Style = read_macshortint(); Widths[tblcount] = (unsigned short int *) malloc(256 * 2); curWidths = Widths[tblcount]; for (count = 0; count < 256; count++) { Width = read_macshortint(); curWidths[count] = (frac2real(Width) * 1000); } read_macshortint(); /* discard unused word */ count = read_macshortint(); if (count != 0) printf("Warning: table doesn't conform to spec.\n"); } get_style_names (offset + Fond.StyTblOfs, TableCount); for (tblcount = 0; afmopt && tblcount < TableCount; tblcount++) { char *filename; char *ch; if (sequential) { filename = (char *) malloc(12); sprintf(filename, "macfont.%d", sequential++); } else { filename = (char *) malloc(strlen(style_names[tblcount])+5); strcpy(filename, style_names[tblcount]); strcpy(filename+strlen(style_names[tblcount]),".afm"); for (ch = filename; *ch; ch++) if (*ch < 32 || *ch > 126) *ch = '-'; } fprintf (stderr, "Writing AFM file to %s.\n", filename); afm = fopen(filename, "w"); fprintf (afm, "StartFontMetrics 3.0\n"); fprintf (afm, "Comment Created by MacFont vers %s.\n", Vers); fprintf (afm, "Comment MacFont Copyright (C) 1993 by Norman Walsh\n"); fprintf (afm, "Comment Free software. No warranty.\n"); fprintf (afm, "FontName %s\n", style_names[tblcount]); fprintf (afm, "FullName %s\n", style_longnames[tblcount]); fprintf (afm, "FamilyName %s\n", familyname); fprintf (afm, "Weight %s\n", weight); fprintf (afm, "FontBBox 0 %d %d %d\n", (int) (frac2real(Fond.Descent)*1000), (int) (frac2real(Fond.WidMax)*1000), (int) (frac2real(Fond.Ascent)*1000)); fprintf (afm, "EncodingScheme %s\n", encoding_scheme); fprintf (afm, "StartCharMetrics %d\n", Fond.LastChar-Fond.FirstChar+1); curWidths = Widths[tblcount]; for (count = Fond.FirstChar; count <= Fond.LastChar; count++) { fprintf(afm,"C %3d ; WX %d ; N %s ; B 0 %d %d %d ;\n", count, curWidths[count], encoding[count], (int) (frac2real(Fond.Descent) * 1000), curWidths[count], (int) (frac2real(Fond.Ascent) * 1000)); } fprintf (afm, "EndCharMetrics\n"); if (Fond.KrnTblOfs == 0) { fprintf(afm, "StartKernData\n"); fprintf(afm, "StartKernPairs 0\n"); fprintf(afm, "EndKernPairs\n"); fprintf(afm, "EndKernData\n"); } else write_kerns(offset+Fond.KrnTblOfs,afm); fprintf(afm, "EndFontMetrics\n"); fclose(afm); } if (bdfopt) { RsrcRefStruct *curRef; int refcount; for (count = 0; count < Fond.NumFonts; count++) { curRef = Mac_refs[NFNTnum]; for (refcount = 0; refcount < Mac_types[NFNTnum].Count; refcount++) { if (curRef->Ident == Fond.AssocTable[count].ResourceNumber) write_nfnt(Mac_header.DataOffset + curRef->DataOffset, Fond.AssocTable[count], style_names[Fond.AssocTable[count].StyleCode], curRef->Ident, sequential); curRef++; } } } } int main (int argc, char **argv) { int dump_input = 1; int Mac_typeCount; int count; char outputname[80]; int outputcount = 1; FILE *encinput; char opt; char *optstring = "ap:e:E:dsw:b"; char *pfafile = 0; char *encfile = 0; char *rsrcfile = 0; int pfaopt = 0; int afmopt = 0; int bdfopt = 0; int encopt = 0; int sequential = 0; fprintf (stderr,"MacFont vers %s. Copyright (C) 1993 by Norman Walsh.\n", Vers); fprintf (stderr,"Portions Copyright (C) 1992, 1993, Metis Technology, Inc.\n"); /* ********************************************************************** */ /* Read the command line arguments. This is really crudely done! */ weight = 0; opterr = 0; while ((opt = getopt (argc, argv, optstring)) != EOF) { switch (opt) { case '?': fprintf(stderr,"Invalid option.\n"); exit(1); break; case 'a': afmopt = 1; break; case 'b': bdfopt = 1; break; case 's': sequential = 1; break; case 'p': pfaopt = 1; pfafile = optarg; break; case 'e': encopt = 1; encfile = optarg; break; case 'E': encoding_scheme = optarg; break; case 'w': weight = optarg; break; case 'd': debug = 1; break; } } rsrcfile = argv[optind]; if (!rsrcfile) { fprintf(stderr, "You must supply a resource file.\n"); fprintf(stderr, "\nUsage : %s macfile\n", argv[0]); fprintf(stderr, "Where : macfile is a Macintosh resource fork.\n"); fprintf(stderr, "Options: -a = extract AFM file from FOND.\n"); fprintf(stderr, " -b = extract BDF bitmap fonts from NFNT.\n"); fprintf(stderr, " -p file = extract PFA file from POST into `file'.\n"); fprintf(stderr, " -d = dump resource data (debugging).\n"); fprintf(stderr, " -e file = load encoding vector from `file'.\n"); fprintf(stderr, " -E name = change EncodingScheme name in AFM.\n"); fprintf(stderr, " -s = extract AFM files with sequential names.\n"); fprintf(stderr, " -w wght = change Weight to `wght' in AFM.\n"); exit(1); } if (!weight) weight = "Normal"; input = fopen(rsrcfile,"r"); if (!input) { fprintf (stderr, "Can't open resource file: %s\n", rsrcfile); exit(1); } if (encopt && encfile) { char line[80]; if (!encoding_scheme) encoding_scheme = "FontSpecific"; encinput = fopen(encfile,"r"); if (!encinput) { fprintf (stderr, "Can't open encoding file: %s\n", encfile); exit(1); } for (count = 0; count < 256; count++) { fgets(line, 80, encinput); line[strlen(line)-1] = 0; if (strncmp(line, ".notdef", 7) == 0) encoding[count] = NULL; else { encoding[count] = (char *) malloc(strlen(line)+1); strcpy(encoding[count], line); } } if (debug) { printf("Encoding:\n"); for (count = 0; count < 256; count++) if (encoding[count]) printf("\t%3d `%s'\n", count, encoding[count]); else printf("\t%3d `.notdef'\n", count); } } if (!encoding_scheme) encoding_scheme = "AppleStandard"; /* ********************************************************************** */ /* Read the Mac resource file ... */ Mac_header = read_mac_header(); fseek(input, Mac_header.MapOffset, 0); Mac_map = read_mac_map(); if (debug) dump_mac_header(Mac_header, Mac_map); fseek(input, Mac_header.MapOffset + Mac_map.TypeOffset, 0); Mac_typeCount = read_macshortint()+1; Mac_types = (RsrcTypeStruct *) malloc (Mac_typeCount*sizeof(RsrcTypeStruct)); Mac_refs = (RsrcRefStruct **) malloc (Mac_typeCount*sizeof(RsrcRefStruct)); POSTnum = -1; FONDnum = -1; NFNTnum = -1; for (count = 0; count < Mac_typeCount; count++) { Mac_types[count] = read_mac_type(); if (strncmp (Mac_types[count].Name, "POST", 4) == 0) POSTnum = count; if (strncmp (Mac_types[count].Name, "FOND", 4) == 0) FONDnum = count; if (strncmp (Mac_types[count].Name, "NFNT", 4) == 0) NFNTnum = count; } for (count = 0; count < Mac_typeCount; count++) { RsrcRefStruct *curRef; int ref_count; curRef = (RsrcRefStruct *) malloc(Mac_types[count].Count * sizeof(RsrcRefStruct)); Mac_refs[count] = curRef; fseek(input, Mac_header.MapOffset + Mac_map.TypeOffset + Mac_types[count].RefOffset, 0); for (ref_count = 0; ref_count < Mac_types[count].Count; ref_count++) { *curRef = read_mac_ref(); curRef++; } } if (debug) for (count = 0; count < Mac_typeCount; count++) { RsrcRefStruct *curRef; int ref_count; curRef = Mac_refs[count]; dump_mac_info(Mac_types[count], *curRef++); for (ref_count = 1; ref_count < Mac_types[count].Count; ref_count++) dump_mac_info2(*curRef++); } /* ********************************************************************** */ /* Dump out the POST and FOND resources, as requested */ if (pfaopt) { if (POSTnum >= 0) { RsrcRefStruct *curRef = Mac_refs[POSTnum]; fprintf (stderr, "Writing PFA file to %s.\n", pfafile); sprintf(outputname, pfafile); output = fopen(outputname, "w"); write_post(Mac_types[POSTnum].Count, Mac_header.DataOffset + curRef->DataOffset); fclose(output); } else fprintf (stderr, "No POST found in %s.\n", rsrcfile); } if (afmopt || bdfopt) { if (FONDnum >= 0) { RsrcRefStruct *curRef = Mac_refs[FONDnum]; int refcount; for (refcount = 0; refcount < Mac_types[FONDnum].Count; refcount++) { write_fond(Mac_header.DataOffset + curRef->DataOffset, curRef->Ident, afmopt, bdfopt, sequential); curRef++; } } else fprintf (stderr, "No metrics or bitmaps found in %s.\n", rsrcfile); } exit (0); }