summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Williams <gww@silcom.com>2001-11-07 06:56:00 +0000
committerGeorge Williams <gww@silcom.com>2001-11-07 06:56:00 +0000
commit0bd8f845ad35973e10656118f7a309164695b9c8 (patch)
treeea7995702091bbd5ae4be0afcee9013983881c06
Initial revision
-rw-r--r--fondu.c884
-rw-r--r--macfonts.h73
-rw-r--r--readnfnt.c466
3 files changed, 1423 insertions, 0 deletions
diff --git a/fondu.c b/fondu.c
new file mode 100644
index 0000000..62044fd
--- /dev/null
+++ b/fondu.c
@@ -0,0 +1,884 @@
+/* Copyright (C) 2001 by George Williams */
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+
+ * The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "macfonts.h"
+
+int tolatin1 = false;
+static int force = false, inquire = false, doafm = false;
+
+int getushort(FILE *f) {
+ int ch1 = getc(f);
+ int ch2 = getc(f);
+ if ( ch2==EOF )
+return( EOF );
+return( (ch1<<8)|ch2 );
+}
+
+long getlong(FILE *f) {
+ int ch1 = getc(f);
+ int ch2 = getc(f);
+ int ch3 = getc(f);
+ int ch4 = getc(f);
+ if ( ch4==EOF )
+return( EOF );
+return( (ch1<<24)|(ch2<<16)|(ch3<<8)|ch4 );
+}
+
+int cleanfilename(char *filename) {
+ char *pt, *npt;
+ int ch, exists, ch2;
+
+ for ( ch = *(pt=npt=filename); ch!='\0'; ch = *++pt ) {
+ if ( ch>'!' && ch!='*' && ch!='?' && ch!='/' && ch!='\\' && ch!='[' && ch<0x7f )
+ *npt++ = ch;
+ }
+ *npt = '\0';
+ if ( force && !inquire )
+return( true );
+
+ exists = access(filename,F_OK)==0;
+
+ forever {
+ if ( exists )
+ fprintf( stderr, "%s exists, do you want to overwrite it? (n) ", filename );
+ else if ( inquire )
+ fprintf( stderr, "Write %s? (y) ", filename );
+ else
+return( true );
+ ch = getchar();
+ if ( ch=='y' || ch=='Y' || ch=='n' || ch=='N' || ch==EOF || ch=='\n' ) {
+ if ( ch=='\n' || ch==EOF )
+ ch = exists ? 'n' : 'y';
+ else
+ while ( (ch2=getchar())!='\n' && ch2!=EOF );
+return( ch=='y' || ch=='Y' );
+ } else if ( ch=='=' ) {
+ for ( pt=filename; (ch=getchar())!=EOF && ch!='\n'; )
+ *pt++ = ch;
+return( true );
+ } else {
+ fprintf( stderr, "Please answer with 'y'(es), 'n'(o) or '=new-filename'.\n" );
+ }
+ }
+}
+
+static void mytmpname(char *temp) {
+ static int upos;
+ /* build up a temporary filename that doesn't match anything else */
+
+ forever {
+ sprintf( temp, "fondu%04X-%d", getpid(), ++upos );
+ if ( access(temp,F_OK)==-1 )
+return;
+ }
+}
+
+static FILE *CreateAfmFile(FILE *f,FOND *fond,long styleoff,int style,
+ char *fontname,char *familyname) {
+ char namebuf[300], **strings;
+ int i,cnt, len,j, index;
+ FILE *afm;
+
+ if ( styleoff==0 || style>=48 ) {
+ if ( fond->fondname!=NULL )
+ strcpy(familyname,fond->fondname);
+ else
+ strcpy(familyname,"Nameless");
+ strcpy(fontname,familyname);
+ for ( i=0; styles[i]!=NULL ; ++i )
+ if ( style&(1<<i))
+ strcat(fontname,styles[i]);
+ } else {
+ fseek(f,styleoff+2+4+4,SEEK_SET);
+ index = 0;
+ for ( i=0; i<48; ++i )
+ if ( i==style )
+ index = getc(f);
+ else
+ getc(f);
+ cnt = getushort(f);
+ /* well the docs say that there's a STR255 here, but actually there's */
+ /* a more compressed pascal string */
+ strings = calloc(cnt,sizeof(char *));
+ /* Apple uses a 1based array index, I use a 0based. */
+ for ( i=0; i<cnt; ++i ) {
+ len = getc(f);
+ strings[i] = malloc(len+1);
+ for ( j=0; j<len; ++j )
+ strings[i][j] = getc(f);
+ strings[i][j] = '\0';
+ }
+ strcpy(familyname,strings[0]);
+ strcpy(fontname,familyname);
+ if ( index!=0 ) {
+ char *ctl = strings[index-1];
+ while ( *ctl ) {
+ strcat(fontname,strings[*ctl-1]);
+ ++ctl;
+ }
+ }
+ for ( i=1; i<cnt; ++i )
+ free(strings[i]);
+ free(strings);
+ }
+ strcpy(namebuf,fontname);
+ strcat(namebuf,".afm");
+ if ( !cleanfilename(namebuf))
+return( NULL );
+ afm = fopen( namebuf,"w" );
+ if ( afm==NULL )
+ fprintf( stderr, "Can't open %s\n", namebuf );
+return( afm );
+}
+
+static void MakeAfmFiles(FOND *fond,FILE *f, int styleoff, int isfixed) {
+ long start = ftell(f);
+ int i,j,k;
+ FILE *afm;
+ time_t now;
+ char fontname[256], familyname[256];
+ char buffer[32];
+
+ for ( i=0; i<fond->stylekerncnt; ++i ) {
+ for ( j=fond->stylewidthcnt-1; j>=0; --j )
+ if ( fond->stylekerns[i].style==fond->stylewidths[j].style )
+ break;
+ afm = CreateAfmFile(f,fond,styleoff,fond->stylekerns[i].style,fontname,familyname);
+ if ( afm==NULL )
+ continue;
+ fprintf( afm, "StartFontMetrics 2.0\n" );
+ fprintf( afm, "Comment Caveat: This does not contain all the information generally found in an AFM file\n" );
+ fprintf( afm, "Comment Generated by Fondu from a mac FOND resource\n" );
+ time(&now);
+ fprintf( afm, "Comment Creation Data: %s", ctime(&now) );
+ fprintf( afm, "FontName %s\n", fontname );
+ fprintf( afm, "FamilyName %s\n", familyname );
+ fprintf( afm, "Weight %s\n", ( fond->stylekerns[i].style&sf_bold )?"Bold":"Medium" );
+ if ( !( fond->stylekerns[i].style&sf_italic ))
+ fprintf( afm, "ItalicAngle 0\n" );
+ fprintf( afm, "IsFixedPitch %s\n", isfixed?"true":"false");
+ fprintf( afm, "EncodingScheme MacRoman\n" ); /* I assume */
+ /* I could check to see if there's an offset table, and check it to */
+ /* see if there's a bounding box table and then read that in and */
+ /* convert it and output a proper FontBBox. But it might not be there*/
+ /* and it's a pain, and pfaedit never looks at it anyway */
+ if ( j!=-1 ) {
+ fprintf( afm, "StartCharMetrics %d\n", fond->last-fond->first+1 );
+ for ( k=fond->first; k<=fond->last; ++k ) {
+ const char *name;
+ if ( k<=256 && macnames[k]!=NULL )
+ name = macnames[k];
+ else {
+ sprintf( buffer, "char%04x", k );
+ name = buffer;
+ }
+ fprintf( afm, "C %d ; WX %d ; N %s ;\n", /* No bounding box info */
+ k>=256?-1:k,
+ (fond->stylewidths[j].widthtab[k-fond->first]*1000 + (1<<11))>>12,
+ name );
+ }
+ fprintf( afm, "EndCharMetrics\n" );
+ } else
+ fprintf( afm, "StartCharMetrics 0\nEndCharMetrics\n" );
+ fprintf( afm, "StartKernData\nStartKernPairs %d\n",
+ fond->stylekerns[i].kernpairs );
+ for ( k=0; k<fond->stylekerns[i].kernpairs; ++k ) {
+ const char *name1, *name2;
+ struct kerns *kp = &fond->stylekerns[i].kerns[k];
+ if ( kp->ch1<=256 )
+ name1 = macnames[kp->ch1];
+ else {
+ sprintf( buffer, "char%04x", kp->ch1 );
+ name1 = buffer;
+ }
+ if ( kp->ch2<=256 )
+ name2 = macnames[kp->ch2];
+ else {
+ sprintf( fontname, "char%04x", kp->ch2 );
+ name2 = fontname;
+ }
+ fprintf( afm, "KPX %s %s %d\n", name1, name2, (kp->offset*1000+(1<<11))>>12 );
+ }
+ fprintf( afm, "EndKernPairs\nEndKernData\nEndFontMetrics\n" );
+ fclose( afm );
+ }
+ fseek(f,start,SEEK_SET);
+}
+
+/* There's probably only one fond in the file, but there could be more so be */
+/* prepared... */
+/* I want the fond: */
+/* to get the fractional widths for the SWIDTH entry on bdf */
+/* to get the font name */
+/* to get the font association tables */
+/* to get the style flags */
+/* http://developer.apple.com/techpubs/mac/Text/Text-269.html */
+static FOND *BuildFondList(FILE *f,long rlistpos,int subcnt,long rdata_pos,
+ long name_list) {
+ long here, start = ftell(f);
+ long offset;
+ int rname = -1;
+ char name[300];
+ int ch1, ch2;
+ int i, j, k, cnt, isfixed;
+ FOND *head=NULL, *cur;
+ long widoff, kernoff, styleoff;
+
+ fseek(f,rlistpos,SEEK_SET);
+ for ( i=0; i<subcnt; ++i ) {
+ /* resource id = */ getushort(f);
+ rname = (short) getushort(f);
+ /* flags = */ getc(f);
+ ch1 = getc(f); ch2 = getc(f);
+ offset = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
+ /* mbz = */ getlong(f);
+ here = ftell(f);
+
+ cur = calloc(1,sizeof(FOND));
+ cur->next = head;
+ head = cur;
+
+ if ( rname!=-1 ) {
+ fseek(f,name_list+rname,SEEK_SET);
+ ch1 = getc(f);
+ fread(name,1,ch1,f);
+ name[ch1] = '\0';
+ cur->fondname = strdup(name);
+ }
+
+ offset += 4;
+ fseek(f,offset,SEEK_SET);
+ isfixed = getushort(f)&0x8000?1:0;
+ /* family id = */ getushort(f);
+ cur->first = getushort(f);
+ cur->last = getushort(f);
+/* on a 1 point font... */
+ /* ascent = */ getushort(f);
+ /* descent = */ (short) getushort(f);
+ /* leading = */ getushort(f);
+ /* widmax = */ getushort(f);
+ if ( (widoff = getlong(f))!=0 ) widoff += offset;
+ if ( (kernoff = getlong(f))!=0 ) kernoff += offset;
+ if ( (styleoff = getlong(f))!=0 ) styleoff += offset;
+ for ( j=0; j<9; ++j )
+ getushort(f);
+ /* internal & undefined, for international scripts = */ getlong(f);
+ /* version = */ getushort(f);
+ cur->assoc_cnt = getushort(f)+1;
+ cur->assoc = calloc(cur->assoc_cnt,sizeof(struct assoc));
+ for ( j=0; j<cur->assoc_cnt; ++j ) {
+ cur->assoc[j].size = getushort(f);
+ cur->assoc[j].style = getushort(f);
+ cur->assoc[j].id = getushort(f);
+ }
+ if ( widoff!=0 ) {
+ fseek(f,widoff,SEEK_SET);
+ cnt = getushort(f)+1;
+ cur->stylewidthcnt = cnt;
+ cur->stylewidths = calloc(cnt,sizeof(struct stylewidths));
+ for ( j=0; j<cnt; ++j ) {
+ cur->stylewidths[j].style = getushort(f);
+ cur->stylewidths[j].widthtab = malloc((cur->last-cur->first+1)*sizeof(short));
+ for ( k=cur->first; k<=cur->last; ++k )
+ cur->stylewidths[j].widthtab[k] = getushort(f);
+ }
+ }
+ if ( kernoff!=0 && doafm ) {
+ /* The only point of generating an afm file is to make the kerning*/
+ /* info available to pfaedit. So we only do this if there is kern*/
+ fseek(f,kernoff,SEEK_SET);
+ cnt = getushort(f)+1;
+ cur->stylekerncnt = cnt;
+ cur->stylekerns = calloc(cnt,sizeof(struct stylekerns));
+ for ( j=0; j<cnt; ++j ) {
+ cur->stylekerns[j].style = getushort(f);
+ cur->stylekerns[j].kernpairs = getushort(f);
+ cur->stylekerns[j].kerns = malloc(cur->stylekerns[j].kernpairs*sizeof(struct kerns));
+ for ( k=0; k<=cur->stylekerns[j].kernpairs; ++k ) {
+ cur->stylekerns[j].kerns[k].ch1 = getc(f);
+ cur->stylekerns[j].kerns[k].ch2 = getc(f);
+ cur->stylekerns[j].kerns[k].offset = getushort(f);
+ }
+ }
+ MakeAfmFiles(cur,f,styleoff,isfixed);
+ }
+ fseek(f,here,SEEK_SET);
+ }
+ fseek(f,start,SEEK_SET);
+return( head );
+}
+
+static void SearchPostscriptResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
+ long name_list, FOND *fonds) {
+ long here = ftell(f);
+ long *offsets, lenpos;
+ int rname = -1, tmp;
+ char name[300], newname[300];
+ int ch1, ch2;
+ static int ucnt;
+ int len, type, i, rlen;
+ /* I don't pretend to understand the rational behind the format of a */
+ /* postscript font. It appears to be split up into chunks where the */
+ /* maximum chunk size is 0x800 */
+ char *buffer=NULL;
+ int max = 0;
+ FILE *pfb;
+
+ fseek(f,rlistpos,SEEK_SET);
+ offsets = calloc(subcnt,sizeof(long));
+ for ( i=0; i<subcnt; ++i ) {
+ /* resource id = */ getushort(f);
+ tmp = (short) getushort(f);
+ if ( rname==-1 ) rname = tmp;
+ /* flags = */ getc(f);
+ ch1 = getc(f); ch2 = getc(f);
+ offsets[i] = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
+ /* mbz = */ getlong(f);
+ }
+ mytmpname(name);
+ /* use the temp name until we've read the postscript font to see what it's name really is */
+ if ( rname!=-1 ) {
+ fseek(f,name_list+rname,SEEK_SET);
+ ch1 = getc(f);
+ fread(newname,1,ch1,f);
+ strcpy(newname+ch1,".pfb");
+ } else
+ sprintf(newname,"Untitled-%d.pfb", ++ucnt );
+
+ pfb = fopen( name,"w" );
+ if ( pfb==NULL ) {
+ fprintf( stderr, "Can't open temporary file for postscript output\n", name );
+ fseek(f,here,SEEK_SET );
+ free(offsets);
+return;
+ }
+
+ putc(0x80,pfb);
+ putc(1,pfb);
+ lenpos = ftell(pfb);
+ putc(0,pfb);
+ putc(0,pfb);
+ putc(0,pfb);
+ putc(0,pfb);
+ len = 0; type = 1;
+ for ( i=0; i<subcnt; ++i ) {
+ fseek(f,offsets[i],SEEK_SET);
+ rlen = getlong(f);
+ ch1 = getc(f); ch2 = getc(f);
+ rlen -= 2; /* those two bytes don't count as real data */
+ if ( ch1==type )
+ len += rlen;
+ else {
+ long hold = ftell(pfb);
+ fseek(pfb,lenpos,SEEK_SET);
+ putc(len>>24,pfb);
+ putc((len>>16)&0xff,pfb);
+ putc((len>>8)&0xff,pfb);
+ putc(len&0xff,pfb);
+ fseek(pfb,hold,SEEK_SET);
+ putc(0x80,pfb);
+ putc(ch1,pfb);
+ lenpos = ftell(pfb);
+ putc(0,pfb);
+ putc(0,pfb);
+ putc(0,pfb);
+ putc(0,pfb);
+ type = ch1;
+ len = rlen;
+ }
+ if ( rlen>max ) {
+ free(buffer);
+ max = rlen;
+ if ( max<0x800 ) max = 0x800;
+ buffer=malloc(max);
+ }
+ fread(buffer,1,rlen,f);
+ if ( type==1 ) {
+ int j;
+ char *pt;
+ for ( j=0; j<rlen; ++j ) if ( buffer[j]=='\r' ) buffer[j] = '\n';
+ if ( i==0 && rname==-1 && (pt=strstr(buffer,"/FontName"))!=NULL ) {
+ pt += strlen("/FontName");
+ while ( isspace(*pt) ) ++pt;
+ if ( *pt=='/' ) {
+ char *end = strchr(pt,' ');
+ ch1 = *end; *end='\0';
+ sprintf(newname,"%s.pfb", pt+1 );
+ *end = ch1;
+ }
+ }
+ }
+ fwrite(buffer,1,rlen,pfb);
+ }
+ free(buffer);
+ free(offsets);
+ putc(0x80,pfb);
+ putc(3,pfb);
+ fseek(pfb,lenpos,SEEK_SET);
+ putc(len>>24,pfb);
+ putc((len>>16)&0xff,pfb);
+ putc((len>>8)&0xff,pfb);
+ putc(len&0xff,pfb);
+ fclose(pfb);
+ if ( cleanfilename(newname)) {
+ if ( rename(name,newname)==-1 ) {
+ fprintf( stderr, "Could not create %s\n", newname);
+ unlink(name);
+ }
+ } else
+ unlink(name);
+ fseek(f,here,SEEK_SET);
+}
+
+static int ttfnamefixup(FILE *ttf,char *buffer) {
+ int version, isotf=false;
+ int i,num, nameoffset, stringoffset;
+ int fullval, famval, fullstr, famstr, fulllen, famlen, val, tag;
+ int plat, spec, lang, name, len, off, ch;
+ char *pt;
+
+ rewind(ttf);
+ if ( (version=getlong(ttf))==CHR('O','T','T','O'))
+ isotf = true;
+ else if ( version!=0x10000 )
+return(false); /* Not going to mess with ttc collections, or whatever else this might be */
+
+ num = getushort(ttf);
+ /* srange = */ getushort(ttf);
+ /* esel = */ getushort(ttf);
+ /* rshift = */ getushort(ttf);
+ for ( i=0; i<num; ++i ) {
+ tag = getlong(ttf);
+ /* checksum = */ getlong(ttf);
+ nameoffset = getlong(ttf);
+ /* length =*/ getlong(ttf);
+ if ( tag==CHR('n','a','m','e'))
+ break;
+ }
+ if ( i==num )
+return(false);
+
+ fseek(ttf,nameoffset,SEEK_SET);
+ /* format = */ getushort(ttf);
+ num = getushort(ttf);
+ stringoffset = nameoffset+getushort(ttf);
+ fullval = famval = 0;
+ for ( i=0; i<num; ++i ) {
+ plat = getushort(ttf);
+ spec = getushort(ttf);
+ lang = getushort(ttf);
+ name = getushort(ttf);
+ len = getushort(ttf);
+ off = getushort(ttf);
+ val = 0;
+ if ( plat==0 && /* any unicode semantics will do && */ lang==0 )
+ val = 1;
+ else if ( plat==3 && spec==1 && lang==0x409 )
+ val = 2;
+ if ( name==4 && val>fullval ) {
+ fullval = val;
+ fullstr = off;
+ fulllen = len;
+ if ( val==2 )
+ break;
+ } else if ( name==1 && val>famval ) {
+ famval = val;
+ famstr = off;
+ famlen = len;
+ }
+ }
+ if ( fullval==0 ) {
+ if ( famval==0 )
+return( false );
+ fullstr = famstr;
+ fulllen = famlen;
+ }
+
+ fseek(ttf,stringoffset+fullstr,SEEK_SET);
+ pt = buffer;
+ for ( i=0; i<len/2; ++i ) {
+ /* Ignore high unicode byte */ getc(ttf)/*<<8*/;
+ ch = getc(ttf);
+ /* avoid characters that are hard to manipulate on the command line */
+ if ( ch>'!' && ch!='*' && ch!='?' && ch!='/' && ch!='\\' && ch<0x7f )
+ *pt++ = ch;
+ }
+ strcpy(pt,isotf?".otf":".ttf");
+return( true );
+}
+
+static void ttfnameset(FILE *ttf,char *curname,char *patheticattempt) {
+ char buffer[1024];
+
+ if ( !ttfnamefixup(ttf,buffer))
+ strcpy(buffer,patheticattempt);
+ if ( !cleanfilename(buffer))
+ unlink(curname);
+ else if ( rename(curname, buffer)==-1 ) {
+ fprintf( stderr, "Could not create %s\n", buffer );
+ unlink(curname);
+ }
+}
+
+static void SearchTtfResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
+ long name_list, FOND *fonds) {
+ long here, start = ftell(f);
+ long roff;
+ int rname = -1;
+ char name[300], newname[300];
+ int ch1, ch2;
+ static int ucnt;
+ int len, i, rlen, ilen;
+ /* I think (hope) the sfnt resource is just a copy of the ttf file */
+ char *buffer=NULL;
+ int max = 0;
+ FILE *ttf;
+
+ fseek(f,rlistpos,SEEK_SET);
+ for ( i=0; i<subcnt; ++i ) {
+ rname = (short) getushort(f);
+ /* flags = */ getc(f);
+ ch1 = getc(f); ch2 = getc(f);
+ roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
+ /* mbz = */ getlong(f);
+ here = ftell(f);
+ if ( rname!=-1 ) {
+ fseek(f,name_list+rname,SEEK_SET);
+ ch1 = getc(f);
+ fread(newname,1,ch1,f);
+ strcpy(newname+ch1,".ttf");
+ } else
+ sprintf(newname,"Untitled-%d.ttf", ++ucnt );
+
+ mytmpname(name);
+ ttf = fopen( name,"w+" );
+ if ( ttf==NULL ) {
+ fprintf( stderr, "Can't open temporary file for truetype output.\n" );
+ fseek(f,here,SEEK_SET );
+ continue;
+ }
+
+ fseek(f,roff,SEEK_SET);
+ ilen = rlen = getlong(f);
+ if ( rlen>16*1024 )
+ ilen = 16*1024;
+ if ( ilen>max ) {
+ free(buffer);
+ max = ilen;
+ if ( max<0x800 ) max = 0x800;
+ buffer=malloc(max);
+ }
+ for ( len=0; len<rlen; ) {
+ int temp = ilen;
+ if ( rlen-len<ilen ) temp = rlen-len;
+ temp = fread(buffer,1,temp,f);
+ if ( temp==EOF )
+ break;
+ fwrite(buffer,1,temp,ttf);
+ len += temp;
+ }
+ ttfnameset(ttf,name,newname);
+ fclose(ttf);
+ }
+ fseek(f,start,SEEK_SET);
+}
+
+static int IsResourceFork(FILE *f, long offset) {
+ /* If it is a good resource fork then the first 16 bytes are repeated */
+ /* at the location specified in bytes 4-7 */
+ /* We include an offset because if we are looking at a mac binary file */
+ /* the resource fork will actually start somewhere in the middle of the */
+ /* file, not at the beginning */
+ unsigned char buffer[16], buffer2[16];
+ long rdata_pos, map_pos, type_list, name_list, rpos;
+ unsigned long tag;
+ int i, cnt, subcnt;
+ FOND *fondlist=NULL;
+
+ fseek(f,offset,SEEK_SET);
+ if ( fread(buffer,1,16,f)!=16 )
+return( false );
+ rdata_pos = offset + ((buffer[0]<<24)|(buffer[1]<<16)|(buffer[2]<<8)|buffer[3]);
+ map_pos = offset + ((buffer[4]<<24)|(buffer[5]<<16)|(buffer[6]<<8)|buffer[7]);
+ fseek(f,map_pos,SEEK_SET);
+ buffer2[15] = buffer[15]+1; /* make it be different */
+ if ( fread(buffer2,1,16,f)!=16 )
+return( false );
+ for ( i=0; i<16; ++i )
+ if ( buffer[i]!=buffer2[i] )
+return( false );
+ getlong(f); /* skip the handle to the next resource map */
+ getushort(f); /* skip the file resource number */
+ getushort(f); /* skip the attributes */
+ type_list = map_pos + getushort(f);
+ name_list = map_pos + getushort(f);
+
+ fseek(f,type_list,SEEK_SET);
+ cnt = getushort(f)+1;
+ for ( i=0; i<cnt; ++i ) {
+ tag = getlong(f);
+ subcnt = getushort(f)+1;
+ rpos = type_list+getushort(f);
+ if ( tag==CHR('F','O','N','D'))
+ fondlist = BuildFondList(f,rpos,subcnt,rdata_pos,name_list);
+ }
+
+ fseek(f,type_list,SEEK_SET);
+ cnt = getushort(f)+1;
+ for ( i=0; i<cnt; ++i ) {
+ tag = getlong(f);
+ /* printf( "%c%c%c%c\n", tag>>24, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff );*/
+ subcnt = getushort(f)+1;
+ rpos = type_list+getushort(f);
+ if ( tag==CHR('P','O','S','T')) /* No FOND */
+ SearchPostscriptResources(f,rpos,subcnt,rdata_pos,name_list,fondlist);
+ else if ( tag==CHR('F','O','N','T'))
+ SearchNFNTResources(f,rpos,subcnt,rdata_pos,name_list,fondlist);
+ else if ( tag==CHR('N','F','N','T'))
+ SearchNFNTResources(f,rpos,subcnt,rdata_pos,name_list,fondlist);
+ else if ( tag==CHR('s','f','n','t'))
+ SearchTtfResources(f,rpos,subcnt,rdata_pos,name_list,fondlist);
+ else if ( tag==CHR('F','O','N','D'))
+ /* already parsed */;
+ else
+ /* Ignored */;
+ }
+return( true );
+}
+
+static int IsResourceInBinary(FILE *f) {
+ unsigned char header[128];
+ unsigned long offset;
+
+ if ( fread(header,1,128,f)!=128 )
+return( false );
+ if ( header[0]!=0 || header[74]!=0 || header[82]!=0 || header[1]<=0 ||
+ header[1]>33 || header[63]!=0 || header[2+header[1]]!=0 )
+return( false );
+ offset = (header[0x53]<<24)|(header[0x54]<<16)|(header[0x55]<<8)|header[0x56] ;
+return( IsResourceFork(f,offset));
+}
+
+static int lastch=0, repeat = 0;
+static void outchr(FILE *binary, int ch) {
+ int i;
+
+ if ( repeat ) {
+ if ( ch==0 ) {
+ /* no repeat, output a literal 0x90 (the repeat flag) */
+ lastch=0x90;
+ putc(lastch,binary);
+ } else {
+ for ( i=1; i<ch; ++i )
+ putc(lastch,binary);
+ }
+ repeat = 0;
+ } else if ( ch==0x90 ) {
+ repeat = 1;
+ } else {
+ putc(ch,binary);
+ lastch = ch;
+ }
+}
+
+static int IsResourceInHex(FILE *f) {
+ /* convert file from 6bit to 8bit */
+ /* interesting data is enclosed between two colons */
+ FILE *binary = tmpfile();
+ char *sixbit = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
+ int ch, val, cnt, i, dlen, rlen, ret;
+ char header[20], *pt;
+
+ if ( binary==NULL ) {
+ fprintf( stderr, "can't create temporary file\n" );
+return( false );
+ }
+
+ lastch = repeat = 0;
+ while ( (ch=getc(f))!=':' ); /* There may be comments before file start */
+ cnt = val = 0;
+ while ( (ch=getc(f))!=':' ) {
+ if ( isspace(ch))
+ continue;
+ for ( pt=sixbit; *pt!=ch && *pt!='\0'; ++pt );
+ if ( *pt=='\0' ) {
+ fclose(binary);
+return( false );
+ }
+ val = (val<<6) | (pt-sixbit);
+ if ( ++cnt==4 ) {
+ outchr(binary,(val>>16)&0xff);
+ outchr(binary,(val>>8)&0xff);
+ outchr(binary,val&0xff);
+ val = cnt = 0;
+ }
+ }
+ if ( cnt!=0 ) {
+ if ( cnt==1 )
+ outchr(binary,val<<2);
+ else if ( cnt==2 ) {
+ val<<=4;
+ outchr(binary,(val>>8)&0xff);
+ outchr(binary,val&0xff);
+ } else if ( cnt==3 ) {
+ val<<=6;
+ outchr(binary,(val>>16)&0xff);
+ outchr(binary,(val>>8)&0xff);
+ outchr(binary,val&0xff);
+ }
+ }
+
+ rewind(binary);
+ ch = getc(binary); /* Name length */
+ /* skip name */
+ for ( i=0; i<ch; ++i )
+ getc(binary);
+ if ( getc(binary)!='\0' ) {
+ fclose(binary);
+return( false );
+ }
+ fread(header,1,20,binary);
+ dlen = (header[10]<<24)|(header[11]<<16)|(header[12]<<8)|header[13];
+ rlen = (header[14]<<24)|(header[15]<<16)|(header[16]<<8)|header[17];
+ if ( rlen==0 ) {
+ fclose(binary);
+return( false );
+ }
+
+ ret = IsResourceFork(binary,ftell(binary)+dlen+2);
+ fclose(binary);
+return( ret );
+}
+
+static int IsResourceInFile(char *filename) {
+ FILE *f;
+ char *spt, *pt;
+ int ret;
+
+ f = fopen(filename,"r");
+ if ( f==NULL )
+return( false );
+ spt = strrchr(filename,'/');
+ if ( spt==NULL ) spt = filename;
+ pt = strrchr(spt,'.');
+ if ( pt!=NULL && (pt[1]=='b' || pt[1]=='B') && (pt[2]=='i' || pt[2]=='I') &&
+ (pt[3]=='n' || pt[3]=='N') && pt[4]=='\0' ) {
+ if ( IsResourceInBinary(f)) {
+ fclose(f);
+return( true );
+ }
+ } else if ( pt!=NULL && (pt[1]=='h' || pt[1]=='H') && (pt[2]=='q' || pt[2]=='Q') &&
+ (pt[3]=='x' || pt[3]=='X') && pt[4]=='\0' ) {
+ if ( IsResourceInHex(f)) {
+ fclose(f);
+return( true );
+ }
+ }
+
+ ret = IsResourceFork(f,0);
+ fclose(f);
+return( ret );
+}
+
+static int FindResourceFile(char *filename) {
+ char *spt, *pt, *dpt;
+ char buffer[1400];
+
+ if ( IsResourceInFile(filename))
+return( true );
+
+ /* Well, look in the resource fork directory (if it exists), the resource */
+ /* fork is placed there in a seperate file on non-Mac disks */
+ strcpy(buffer,filename);
+ spt = strrchr(buffer,'/');
+ if ( spt==NULL ) { spt = buffer; pt = filename; }
+ else { ++spt; pt = filename + (spt-buffer); }
+ strcpy(spt,"resource.frk/");
+ strcat(spt,pt);
+ if ( IsResourceInFile(buffer))
+return( true );
+
+ /* however the resource fork does not appear to long names properly */
+ /* names are always lower case 8.3, do some simple things to check */
+ spt = strrchr(buffer,'/')+1;
+ for ( pt=spt; *pt; ++pt )
+ if ( isupper( *pt ))
+ *pt = tolower( *pt );
+ dpt = strchr(spt,'.');
+ if ( dpt==NULL ) dpt = spt+strlen(spt);
+ if ( dpt-spt>8 || strlen(dpt)>4 ) {
+ char exten[8];
+ strncpy(exten,dpt,7);
+ exten[4] = '\0'; /* it includes the dot */
+ if ( dpt-spt>6 )
+ dpt = spt+6;
+ *dpt++ = '~';
+ *dpt++ = '1';
+ strcpy(dpt,exten);
+ }
+return( IsResourceInFile(buffer));
+}
+
+int main(int argc, char **argv) {
+ int i, ret = 0;
+
+ for ( i=1; i<argc; ++i )
+ if ( *argv[i]=='-' ) {
+ char *pt = argv[i];
+ if ( pt[1]=='-' ) ++pt;
+ if (strcmp(pt,"-latin1")==0 )
+ tolatin1 = true;
+ else if (strcmp(pt,"-force")==0 || strcmp(pt,"-f")==0 )
+ force = true;
+ else if (strcmp(pt,"-inquire")==0 || strcmp(pt,"-i")==0 )
+ force = true;
+ else if (strcmp(pt,"-afm")==0 )
+ doafm = true;
+ else {
+ fprintf( stderr, "Usage: %s [-force] [-inquire] [-latin1] [-afm] macfiles\n",
+ argv[0] );
+ fprintf( stderr, " if -force is given you will not be asked about replacing existing files\n" );
+ fprintf( stderr, " if -inquire is given you will be asked about writing each file (whether\n" );
+ fprintf( stderr, "\tit exists or not). -inquire overrides -force.\n" );
+ fprintf( stderr, " if -latin1 is given nfnts will be reencoded to latin1 (else left in mac roman)\n" );
+ fprintf( stderr, " if -afm is given then an incomplete afm file will be generated from any fonds.\n" );
+ fprintf( stderr, " macfile may be a macbinary (.bin), binhex (.hqx) or bare resource fork.\n" );
+ exit(0);
+ }
+ } else if ( !FindResourceFile(argv[i])) {
+ fprintf( stderr, "Can't find an appropriate resource fork in %s\n", argv[i]);
+ ret=1;
+ }
+return( ret );
+}
diff --git a/macfonts.h b/macfonts.h
new file mode 100644
index 0000000..41461d8
--- /dev/null
+++ b/macfonts.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2001 by George Williams */
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+
+ * The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define CHR(ch1,ch2,ch3,ch4) (((ch1)<<24)|((ch2)<<16)|((ch3)<<8)|(ch4))
+#define true 1
+#define false 0
+
+#define forever for (;;)
+
+enum style_flags { sf_bold = 1, sf_italic = 2, sf_underline = 4, sf_outline = 8,
+ sf_shadow = 0x10, sf_condense = 0x20, sf_extend = 0x40 };
+
+typedef struct fond {
+ char *fondname;
+ int first, last;
+ int assoc_cnt;
+ struct assoc {
+ short size, style, id;
+ } *assoc;
+ /* size==0 => scalable */
+ /* style>>8 is the bit depth (0=>1, 1=>2, 2=>4, 3=>8) */
+ /* search order for ID is sfnt, NFNT, FONT */
+ int stylewidthcnt;
+ struct stylewidths {
+ short style;
+ short *widthtab; /* 4.12 fixed number with the width specified as a fraction of an em */
+ } *stylewidths;
+ int stylekerncnt;
+ struct stylekerns {
+ short style;
+ int kernpairs;
+ struct kerns {
+ unsigned char ch1, ch2;
+ short offset; /* 4.12 */
+ } *kerns;
+ } *stylekerns;
+ struct fond *next;
+} FOND;
+
+extern int tolatin1;
+extern const char *macnames[];
+extern const char *styles[];
+
+extern int getushort(FILE *f);
+extern long getlong(FILE *f);
+extern int cleanfilename(char *filename);
+
+extern void SearchNFNTResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
+ long name_list, FOND *fonds);
diff --git a/readnfnt.c b/readnfnt.c
new file mode 100644
index 0000000..c55794d
--- /dev/null
+++ b/readnfnt.c
@@ -0,0 +1,466 @@
+/* Copyright (C) 2001 by George Williams */
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+
+ * The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "macfonts.h"
+
+const char *macnames[] = {
+ NULL, "Eth", "eth", "Lslash", "lslash", "Scaron", "scaron", "Yacute",
+ "yacute", NULL, NULL, "Thorn", "thorn", NULL, "Zcaron", "zcaron",
+ NULL, NULL, NULL, NULL, NULL, "onehalf", "onequarter", "onesuperior",
+ "threequarters", "threesuperior", "twosuperior", "brokenbar", "minus", "multiply", NULL, NULL,
+ "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle",
+ "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash",
+ "zero", "one", "two", "three", "four", "five", "six", "seven",
+ "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question",
+ "at", "A", "B", "C", "D", "E", "F", "G",
+ "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore",
+ "grave", "a", "b", "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l", "m", "n", "o",
+ "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", NULL,
+ "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute",
+ "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave",
+ "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute",
+ "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
+ "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls",
+ "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash",
+ "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", "summation",
+ "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash",
+ "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft",
+ "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde", "Otilde", "OE", "oe",
+ "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge",
+ "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl",
+ "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute",
+ "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
+ "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde",
+ "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron",
+NULL};
+
+static unsigned char mac2iso[] = {
+ 0, 208, 240, 0, 0, 0, 0, 221, 253, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 33, 34, 35, 36, 37, 38, 0, 40, 41, 42, 43, 44, 173, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 0, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0,
+ 196, 197, 199, 201, 209, 214, 220, 225, 224, 226, 228, 227, 229, 231, 233, 232,
+ 234, 235, 237, 236, 238, 239, 241, 243, 242, 244, 246, 245, 250, 249, 251, 252,
+ 0, 176, 162, 163, 0, 0, 0, 223, 174, 169, 0, 180, 168, 0, 198, 216,
+ 0, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 186, 0, 230, 248,
+ 191, 161, 0, 0, 0, 0, 0, 171, 187, 0, 0, 192, 195, 213, 0, 0,
+ 0, 0, 0, 0, 96, 39, 247, 0, 255, 0, 0, 0, 0, 0, 0, 0,
+ 0, 183, 0, 0, 0, 194, 202, 193, 203, 200, 205, 206, 207, 204, 211, 212,
+ 0, 210, 218, 219, 217, 0, 0, 0, 0, 0, 0, 0, 184, 0, 0, 0
+};
+
+static unsigned char iso2mac[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 33, 34, 35, 36, 37, 38, 213, 40, 41, 42, 43, 44, 0, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 212, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 193, 162, 163, 0, 0, 0, 0, 172, 169, 187, 199, 0, 45, 168, 0,
+ 161, 177, 0, 0, 171, 0, 0, 225, 252, 0, 188, 200, 0, 0, 0, 192,
+ 203, 231, 229, 204, 128, 129, 174, 130, 233, 131, 230, 232, 237, 234, 235, 236,
+ 1, 132, 241, 238, 239, 205, 133, 0, 175, 244, 242, 243, 134, 7, 0, 167,
+ 136, 135, 137, 139, 138, 140, 190, 141, 143, 142, 144, 145, 147, 146, 148, 149,
+ 2, 150, 152, 151, 153, 155, 154, 214, 191, 157, 156, 158, 159, 8, 0, 216
+};
+const char *styles[]= { "Bold", "Italic", "Underline", "Outline",
+ "Shadow", "Condensed", "Extended", NULL };
+
+struct MacFontRec {
+ short fontType;
+ short firstChar;
+ short lastChar;
+ short widthMax;
+ short kernMax; /* bb learing */
+ short Descent; /* maximum negative distance below baseline*/
+ short fRectWidth; /* bounding box width */
+ short fRectHeight; /* bounding box height */
+ unsigned short *offsetWidths;/* offset to start of offset/width table */
+ /* 0xffff => undefined, else high byte is offset in locTable, */
+ /* low byte is width */
+ short ascent;
+ short descent;
+ short leading;
+ short rowWords; /* shorts per row */
+ unsigned short *fontImage; /* rowWords*fRectHeight */
+ /* Images for all characters plus one extra for undefined */
+ unsigned short *locs; /* lastchar-firstchar+3 words */
+ /* Horizontal offset to start of n'th character. Note: applies */
+ /* to each row. Missing characters have same loc as following */
+};
+
+typedef struct rect {
+ short left,width, height,bottom;
+} Rect;
+
+static void LoadNFNT(FILE *f,struct MacFontRec *font, long offset) {
+ long here = ftell(f);
+ long baseow;
+ long ow;
+ int i;
+
+ offset += 4; /* skip over the length */
+ fseek(f,offset,SEEK_SET);
+ memset(font,'\0',sizeof(struct MacFontRec));
+ font->fontType = getushort(f);
+ font->firstChar = getushort(f);
+ font->lastChar = getushort(f);
+ font->widthMax = getushort(f);
+ font->kernMax = (short) getushort(f);
+ font->Descent = (short) getushort(f);
+ font->fRectWidth = getushort(f);
+ font->fRectHeight = getushort(f);
+ baseow = ftell(f);
+ ow = getushort(f);
+ font->ascent = getushort(f);
+ font->descent = getushort(f);
+ if ( font->Descent>=0 ) {
+ ow |= (font->Descent<<16);
+ font->Descent = -font->descent; /* Possibly overkill, but should be safe */
+ }
+ font->leading = getushort(f);
+ font->rowWords = getushort(f);
+ font->fontImage = calloc(font->rowWords*font->fRectHeight,sizeof(short));
+ font->locs = calloc(font->lastChar-font->firstChar+3,sizeof(short));
+ font->offsetWidths = calloc(font->lastChar-font->firstChar+3,sizeof(short));
+ for ( i=0; i<font->rowWords*font->fRectHeight; ++i )
+ font->fontImage[i] = getushort(f);
+ for ( i=0; i<font->lastChar-font->firstChar+3; ++i )
+ font->locs[i] = getushort(f);
+ fseek(f,baseow+2*ow,SEEK_SET);
+ for ( i=0; i<font->lastChar-font->firstChar+3; ++i )
+ font->offsetWidths[i] = getushort(f);
+ fseek(f,here,SEEK_SET);
+}
+
+static int FontHasChar(struct MacFontRec *font, int ch ) {
+ if ( ch<font->firstChar || ch>font->lastChar || ch==0 || ch=='\t' || ch=='\r' )
+return( false );
+
+return ( font->offsetWidths[ch-font->firstChar]!=0xffff );
+}
+
+static int GetFontCount(struct MacFontRec *font) {
+ int cnt=0, i;
+
+ for ( i=font->firstChar; i<=font->lastChar; ++i ) {
+ if ( FontHasChar(font,i) )
+ ++cnt;
+ }
+return( cnt );
+}
+
+static int GetFontAvgWidth(struct MacFontRec *font) {
+ int cnt=0, i, wid=0,ch;
+ /* Only average those characters in the encoding */
+
+ for ( i=font->firstChar; i<=font->lastChar; ++i ) {
+ if ( tolatin1 ) {
+ if ( i<256 && mac2iso[i]!=0 )
+ ch = mac2iso[i];
+ else
+ continue;
+ } else
+ ch = i;
+ if ( FontHasChar(font,ch) ) {
+ ++cnt;
+ wid += (font->offsetWidths[ch-font->firstChar]&0xff);
+ }
+ }
+return( cnt>0?wid*10/cnt:0 );
+}
+
+static int AnyBitsSet(unsigned short *pt, int bits, int bite ) {
+ int i;
+
+ for ( i=bits; i<bite; ++i )
+ if ( pt[i>>4]&(1<<(15-(i&15))) )
+return( true );
+
+return( false );
+}
+
+static int GetCharBBox(struct MacFontRec *font, int ch, Rect *bbox ) {
+ unsigned short *widths = font->offsetWidths;
+ unsigned short *locs = font->locs;
+ unsigned short *rows = font->fontImage;
+ int i;
+ int ow;
+
+ ch -= font->firstChar;
+ ow = widths[ch];
+ bbox->left = (ow>>8)+font->kernMax; bbox->width = locs[ch+1]-locs[ch];
+ bbox->height = font->fRectHeight; bbox->bottom = -font->descent;
+ for ( i=0; i<font->fRectHeight; ++i )
+ if ( AnyBitsSet(rows+i*font->rowWords,locs[ch],locs[ch+1]) )
+ break;
+ bbox->height -= i;
+ for ( i=0; i<bbox->height; ++i )
+ if ( AnyBitsSet(rows+(font->fRectHeight-i-1)*font->rowWords,locs[ch],locs[ch+1]) )
+ break;
+ bbox->bottom += i; bbox->height -= i;
+ if ( bbox->height<0 ) bbox->height = 0;
+return( ow&0xff ); /* Width */
+}
+
+static void WriteRow(FILE *bdf,unsigned short *test, int bits, int bite ) {
+ int i;
+ int cnt=0x8, nibble=0;
+ char buffer[80], *pt=buffer;
+
+ for ( i=bits; i<bite; ++i ) {
+ if ( test[i>>4]&(1<<(15-(i&15))) )
+ nibble |= cnt;
+ if ( (cnt>>=1)==0 ) {
+ if ( nibble>=10 )
+ *pt++ = 'A'+nibble-10;
+ else
+ *pt++ = '0'+nibble;
+ cnt=0x8;
+ nibble=0;
+ }
+ }
+ if ( cnt!=0x8 ) {
+ if ( nibble>=10 )
+ *pt++ = 'A'+nibble-10;
+ else
+ *pt++ = '0'+nibble;
+ }
+ if ( (pt-buffer)&1 )
+ *pt++ = '0'; /* pad out to a byte */
+ *pt++ = '\n';
+ *pt = '\0';
+ fputs(buffer,bdf);
+}
+
+static void WriteBitmap(FILE *bdf, struct MacFontRec *font, int ch, Rect *rct ) {
+ unsigned short *locs = font->locs;
+ unsigned short *rows = font->fontImage;
+ int i;
+ int bits, bite;
+ int rowf, rowe;
+
+ ch -= font->firstChar;
+ bits = locs[ch]; bite = locs[ch+1];
+ rowf = font->fRectHeight - (rct->height+font->descent+rct->bottom);
+ rowe = font->fRectHeight-(rct->bottom+font->descent);
+ for ( i=rowf; i<rowe; ++i )
+ WriteRow(bdf,rows+i*font->rowWords,bits,bite);
+}
+
+static void WriteChar(FILE *bdf,struct MacFontRec *font,int enc, int index,
+ int size, FOND *mine, struct assoc *ass) {
+ Rect rct;
+ int width;
+ short *widths = NULL;
+
+ if ( mine!=NULL && ass!=NULL ) {
+ int i;
+ /* I'm ignoring the glyph width table in the nfnt, and just looking at*/
+ /* the family table in the fond */
+ for ( i=0; i<mine->stylewidthcnt; ++i )
+ if ( mine->stylewidths[i].style == ass->style ) {
+ widths = mine->stylewidths[i].widthtab;
+ break;
+ }
+ }
+
+ if ( index==0 )
+ fprintf(bdf,"STARTCHAR .notdef\n");
+ else if ( index<256 && macnames[index]!=NULL )
+ fprintf(bdf,"STARTCHAR %s\n", macnames[index]);
+ else
+ fprintf(bdf,"STARTCHAR char%04x\n", index );
+ width = GetCharBBox(font,index,&rct);
+ fprintf(bdf,"ENCODING %d\n", enc );
+ fprintf(bdf,"SWIDTH %ld 0\n",
+ widths==NULL?width*1000L/size:((widths[index]*1000L+(1<<11))>>12) );
+ fprintf(bdf,"DWIDTH %d 0\n", width );
+ fprintf(bdf,"BBX %d %d %d %d\n", rct.width, rct.height, rct.left, rct.bottom );
+ fprintf(bdf,"BITMAP\n" );
+ WriteBitmap(bdf,font,index,&rct);
+ fprintf(bdf,"ENDCHAR\n" );
+}
+
+static void DumpNFNT2BDF(FILE *bdf,struct MacFontRec *font, char *resname,
+ FOND *mine, struct assoc *ass) {
+ int cnt, avg;
+ int style = ass!=NULL ? ass->style : 0;
+ int size = ass!=NULL ? ass->size : font->fRectHeight;
+ int i;
+
+ cnt = GetFontCount(font);
+ avg = GetFontAvgWidth(font);
+ fprintf(bdf,"STARTFONT 2.1\n");
+ fprintf(bdf, "FONT -Fondu-%s-%s-%s-%s--%d-%d0-75-75-%s-%d-%s-1\n",
+ (mine!=NULL && mine->fondname!=NULL)?mine->fondname:resname,
+ (style&sf_bold)?"Bold":"Medium",
+ (style&sf_italic)?"I":"R",
+ (style&sf_condense)?"Condensed":(style&sf_extend)?"Extended":"Normal",
+ size, (size*72+37)/75,
+ (font->fontType&0xf000)==0xb000?"M":"P",
+ avg,
+ tolatin1?"MacRoman":"ISO8859" );
+
+ fprintf(bdf, "SIZE %d 75 75\n", (size*72+37)/75 );
+ fprintf(bdf, "FONTBOUNDINGBOX %d %d %d %d\n", font->fRectWidth, font->fRectHeight, font->kernMax, -font->descent );
+ fprintf(bdf, "COMMENT Created by Fondu from a mac NFNT/FONT resource\n" );
+ fprintf(bdf, "STARTPROPERTIES 17\n" );
+ fprintf(bdf, "FOUNDRY \"Fondu\"\n" );
+ fprintf(bdf, "FAMILY_NAME \"%s\"\n", mine!=NULL && mine->fondname!=NULL?mine->fondname:resname );
+ fprintf(bdf, "WEIGHT_NAME \"%s\"\n", (style&sf_bold)?"Bold":"Medium" );
+ fprintf(bdf, "SLANT \"%s\"\n", (style&sf_italic)?"I":"R" );
+ fprintf(bdf, "SETWIDTH_NAME \"%s\"\n", (style&sf_condense)?"Condensed":(style&sf_extend)?"Extended":"Normal" );
+ fprintf(bdf, "ADD_STYLE_NAME \"\"\n" );
+ fprintf(bdf, "PIXEL_SIZE %d\n", size );
+ fprintf(bdf, "POINT_SIZE %d0\n", (size*72+37)/75 );
+ fprintf(bdf, "RESOLUTION_X 75\n" );
+ fprintf(bdf, "RESOLUTION_Y 75\n" );
+ fprintf(bdf, "SPACING \"%s\"\n", (font->fontType&0xf000)==0xb000?"M":"P");
+ fprintf(bdf, "AVERAGE_WIDTH %d\n", avg );
+ fprintf(bdf, "CHARSET_REGISTRY \"%s\"\n",tolatin1?"ISO8859":"MacRoman" );
+ fprintf(bdf, "CHARSET_ENCODING \"1\"\n" );
+ fprintf(bdf, "FONT_ASCENT %d\n", font->ascent );
+ fprintf(bdf, "FONT_DESCENT %d\n", font->descent );
+ fprintf(bdf, "FACE_NAME \"" );
+ if ( *resname!='\0' ) {
+ fprintf(bdf, "%s\"\n", resname );
+ } else if ( mine!=NULL && mine->fondname!=NULL ) {
+ fprintf(bdf, "%s", mine->fondname );
+ if ( ass!=NULL ) {
+ for ( i=0; styles[i]!=NULL; ++i )
+ if ( ass->style&(1<<i))
+ fprintf( bdf, "%s", styles[i]);
+ }
+ fprintf( bdf, "\"\n" );
+ } else
+ fprintf( bdf, "nameless\"\n" );
+ fprintf(bdf, "ENDPROPERTIES\n" );
+ fprintf(bdf, "CHARS %d\n", cnt );
+ if ( tolatin1 ) {
+ for ( i=0; i<=255; ++i ) {
+ int ch = iso2mac[i];
+ if ( FontHasChar(font,ch) ) /* character exists */
+ WriteChar(bdf,font,ch,i,size,mine,ass);
+ }
+ for ( i=font->firstChar; i<=font->lastChar; ++i )
+ if ( (i>=256 || mac2iso[i]==0) && FontHasChar(font,i) )
+ WriteChar(bdf,font,-1,i,size,mine,ass);
+ } else {
+ for ( i=font->firstChar; i<=font->lastChar; ++i )
+ if ( FontHasChar(font,i) )
+ WriteChar(bdf,font,i,i,size,mine,ass);
+ }
+ fprintf(bdf, "ENDFONT\n" );
+}
+
+void SearchNFNTResources(FILE *f,long rlistpos,int subcnt,long rdata_pos,
+ long name_list, FOND *fonds) {
+ long here, start = ftell(f);
+ long roff;
+ int rname = -1;
+ char resname[256], name[300];
+ int ch1, ch2;
+ static int ucnt;
+ int i,j;
+ int res_id;
+ FILE *bdf;
+ FOND *mine;
+ struct assoc *ass;
+ struct MacFontRec font;
+
+ fseek(f,rlistpos,SEEK_SET);
+ for ( i=0; i<subcnt; ++i ) {
+ rname = (short) getushort(f);
+ /* flags = */ getc(f);
+ ch1 = getc(f); ch2 = getc(f);
+ roff = rdata_pos+((ch1<<16)|(ch2<<8)|getc(f));
+ /* mbz = */ getlong(f);
+ here = ftell(f);
+ LoadNFNT(f,&font, roff);
+ ass = NULL;
+ for ( mine = fonds; mine!=NULL; mine = mine->next ) {
+ for ( i=0; i<mine->assoc_cnt; ++i )
+ if ( res_id==mine->assoc[i].id ) {
+ ass = &mine->assoc[i];
+ break;
+ }
+ if ( ass!=NULL )
+ break;
+ }
+ resname[0] = '\0';
+ if ( rname!=-1 ) {
+ fseek(f,name_list+rname,SEEK_SET);
+ ch1 = getc(f);
+ fread(resname,1,ch1,f);
+ sprintf( name, "%s-%d.bdf", resname, ass!=NULL?ass->size:font.fRectHeight );
+ } else if ( ass!=NULL ) {
+ if ( mine->fondname==NULL )
+ sprintf( name, "Untitled%d-%d.bdf", ++ucnt, ass->size );
+ else {
+ strcpy( name, mine->fondname );
+ for ( j=0; styles[j]!=NULL; ++j )
+ if ( ass->style&(1<<j))
+ strcat(name,styles[j]);
+ sprintf( name+strlen(name), "-%d.bdf", ass->size );
+ }
+ } else
+ sprintf(name,"Untitled%d-%d.bdf", ++ucnt, font.fRectHeight );
+ fseek(f,here,SEEK_SET);
+ if ( !cleanfilename(name))
+ /* Do Nothing */;
+ else if ( (font.fontType&0xc)!=0 )
+ fprintf( stderr, "The bitmap font %s a depth greater than 1 and is ignored\n", name );
+ else {
+ bdf = fopen( name,"w+" );
+ if ( bdf==NULL )
+ fprintf( stderr, "Can't open %s for output\n", name );
+ else
+ DumpNFNT2BDF(bdf,&font,resname,mine,ass);
+ }
+ free( font.offsetWidths );
+ free( font.fontImage );
+ free( font.locs );
+ }
+ fseek(f,start,SEEK_SET);
+}