diff options
author | George Williams <gww@silcom.com> | 2004-05-28 02:47:55 +0000 |
---|---|---|
committer | George Williams <gww@silcom.com> | 2004-05-28 02:47:55 +0000 |
commit | 44d1fe300a104abb076897cc4d61e25ab22a66af (patch) | |
tree | dff7929110b44406297fa663d879b2a95d284027 | |
parent | 2bb9ad2eb10060d99f20376640324e38e1bada13 (diff) |
Real support for afm output.
Ability to find a post resource file given the FOND.
A couple of extra options to fondu.
-rw-r--r-- | Makefile.Mac | 14 | ||||
-rw-r--r-- | Makefile.in | 14 | ||||
-rw-r--r-- | Makefile.unix | 14 | ||||
-rw-r--r-- | fondu.1 | 20 | ||||
-rw-r--r-- | fondu.c | 495 | ||||
-rw-r--r-- | fondups.c | 3075 | ||||
-rw-r--r-- | macfonts.h | 22 | ||||
-rw-r--r-- | psfont.h | 192 | ||||
-rw-r--r-- | showfond.c | 3 |
9 files changed, 3692 insertions, 157 deletions
diff --git a/Makefile.Mac b/Makefile.Mac index ed9713f..41120c1 100644 --- a/Makefile.Mac +++ b/Makefile.Mac @@ -5,22 +5,23 @@ CC = cc # #include, #if, etc. WFLAGS = -Wmissing-prototypes -Wunused -Wimplicit -Wreturn-type -Wparentheses CFLAGS = -g $(WFLAGS) -D__Mac -I/Developer/Headers/FlatCarbon/ -FONDUOBJS = fondu.o readnfnt.o +FONDUOBJS = fondu.o readnfnt.o fondups.o UFONDOBJS = ufond.o ufondbdf.o ufondpfb.o ufondttf.o crctab.o DFONT2RESOBJS = dfont2res.o crctab.o SHOWOBJS = showfond.o TOBINOBJS = tomacbinary.o crctab.o FROMBINOBJS = frommacbinary.o LUMPEROBJS = lumper.o +SETFONDNAMEOBJS = setfondname.o #CORE = /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/CarbonCore CORE = /System/Library/Frameworks/CoreServices.framework/CoreServices bindir = /usr/local/bin -all: fondu ufond showfond dfont2res tobin frombin lumper +all: fondu ufond showfond dfont2res tobin frombin lumper setfondname fondu: $(FONDUOBJS) - $(CC) $(CFLAGS) -o fondu $(FONDUOBJS) $(CORE) + $(CC) $(CFLAGS) -o fondu $(FONDUOBJS) -lm $(CORE) ufond: $(UFONDOBJS) $(CC) $(CFLAGS) -o ufond $(UFONDOBJS) @@ -40,11 +41,14 @@ frombin: $(FROMBINOBJS) lumper: $(LUMPEROBJS) $(CC) $(CFLAGS) -o lumper $(LUMPEROBJS) +setfondname: $(SETFONDNAMEOBJS) + $(CC) $(CFLAGS) -o setfondname $(SETFONDNAMEOBJS) + clean: - -rm -f *.o fondu ufond showfond dfont2res tobin frombin lumper + -rm -f *.o fondu ufond showfond dfont2res tobin frombin lumper setfondname distclean: clean -rm Makefile install: all - cp fondu ufond showfond dfont2res tobin frombin lumper $(bindir) + cp fondu ufond showfond dfont2res tobin frombin lumper setfondname $(bindir) diff --git a/Makefile.in b/Makefile.in index f0dbf33..802295b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,18 +6,19 @@ CC = @CC@ WFLAGS = -Wmissing-prototypes -Wunused -Wimplicit -Wreturn-type -Wparentheses -pedantic CFLAGS = -g $(WFLAGS) -FONDUOBJS = fondu.o readnfnt.o +FONDUOBJS = fondu.o readnfnt.o fondups.o UFONDOBJS = ufond.o ufondbdf.o ufondpfb.o ufondttf.o crctab.o DFONT2RESOBJS = dfont2res.o crctab.o SHOWOBJS = showfond.o TOBINOBJS = tomacbinary.o crctab.o FROMBINOBJS = frommacbinary.o LUMPEROBJS = lumper.o +SETFONDNAMEOBJS = setfondname.o -all: fondu ufond showfond dfont2res tobin frombin lumper +all: fondu ufond showfond dfont2res tobin frombin lumper setfondname fondu: $(FONDUOBJS) - $(CC) $(CFLAGS) -o fondu $(FONDUOBJS) + $(CC) $(CFLAGS) -o fondu $(FONDUOBJS) -lm ufond: $(UFONDOBJS) $(CC) $(CFLAGS) -o ufond $(UFONDOBJS) @@ -37,11 +38,14 @@ frombin: $(FROMBINOBJS) lumper: $(LUMPEROBJS) $(CC) $(CFLAGS) -o lumper $(LUMPEROBJS) +setfondname: $(SETFONDNAMEOBJS) + $(CC) $(CFLAGS) -o setfondname $(SETFONDNAMEOBJS) + clean: - -rm -f *.o fondu ufond showfond dfont2res tobin frombin lumper + -rm -f *.o fondu ufond showfond dfont2res tobin frombin lumper setfondname distclean: clean -rm Makefile install: all - cp fondu ufond showfond dfont2res tobin frombin lumper $(bindir) + cp fondu ufond showfond dfont2res tobin frombin lumper setfondname $(bindir) diff --git a/Makefile.unix b/Makefile.unix index 83a70b3..ffbfb25 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -1,20 +1,21 @@ CC = gcc WFLAGS = -Wmissing-prototypes -Wunused -Wimplicit -Wreturn-type -Wparentheses -pedantic CFLAGS = -g $(WFLAGS) -FONDUOBJS = fondu.o readnfnt.o +FONDUOBJS = fondu.o readnfnt.o fondups.o UFONDOBJS = ufond.o ufondbdf.o ufondpfb.o ufondttf.o crctab.o DFONT2RESOBJS = dfont2res.o crctab.o SHOWOBJS = showfond.o TOBINOBJS = tomacbinary.o crctab.o FROMBINOBJS = frommacbinary.o LUMPEROBJS = lumper.o +SETFONDNAMEOBJS = setfondname.o bindir = /usr/local/bin -all: fondu ufond showfond dfont2res tobin frombin lumper +all: fondu ufond showfond dfont2res tobin frombin lumper setfondname fondu: $(FONDUOBJS) - $(CC) $(CFLAGS) -o fondu $(FONDUOBJS) + $(CC) $(CFLAGS) -o fondu $(FONDUOBJS) -lm ufond: $(UFONDOBJS) $(CC) $(CFLAGS) -o ufond $(UFONDOBJS) @@ -34,11 +35,14 @@ frombin: $(FROMBINOBJS) lumper: $(LUMPEROBJS) $(CC) $(CFLAGS) -o lumper $(LUMPEROBJS) +setfondname: $(SETFONDNAMEOBJS) + $(CC) $(CFLAGS) -o setfondname $(SETFONDNAMEOBJS) + clean: - -rm -f *.o fondu ufond showfond dfont2res tobin frombin lumper + -rm -f *.o fondu ufond showfond dfont2res tobin frombin lumper setfondname distclean: clean -rm Makefile install: all - cp fondu ufond showfond dfont2res tobin frombin lumper $(bindir) + cp fondu ufond showfond dfont2res tobin frombin lumper setfondname $(bindir) @@ -1,12 +1,14 @@ -.TH FONDU 1 "23 October 2002" +.TH FONDU 1 "27 May 2004" .SH NAME fondu \- convert Macintosh font files to UNIX font format .SH SYNOPSIS .B fondu .RB [ \-force ] .RB [ \-inquire ] +.RB [ \-show ] .RB [ \-latin1 ] .RB [ \-afm ] +.RB [ \-trackps ] .BR macfile ... .SH DESCRIPTION The program @@ -36,14 +38,24 @@ or bare resource fork files. Force overwriting of the original file. .TP .B \-inquire -Prompt for input before overwriting files. +Prompt for input before overwriting files. This overrides -force. +.TP +.B \-show +Print out each file as it is created. .TP .BI \-latin1 Recode any macintosh bitmap fonts (NFNTs) from the macintosh roman encoding to latin1. .TP +.BI \-trackps +If the macfiles argument mentions a file containing a FOND, and that FOND +mentions external PostScript resource files, then attempt to open those +PostScript files as well as processing the original file. +.TP .B \-afm -Create an incomplete Adobe Font Metrics (afm) file, -containing font width and kerning information, but lacking character bounding box information. +For any macfile which contains a FOND and points to at least one PostScript +resource file create an Adobe Font Metrics (afm) file. Fondu will merge +width and bounding box information from the PostScript files, and kerning +data from the FOND. .SH AUTHOR George Williams (gww@silcom.com). .LP @@ -31,11 +31,12 @@ #include <sys/types.h> #include <unistd.h> #include <time.h> +#include <math.h> #include "macfonts.h" int tolatin1 = false; -static int force = false, inquire = false, doafm = false; +static int force = false, inquire = false, doafm = false, trackps = false, show=false; int getushort(FILE *f) { int ch1 = getc(f); @@ -55,7 +56,7 @@ return( EOF ); return( (ch1<<24)|(ch2<<16)|(ch3<<8)|ch4 ); } -int cleanfilename(char *filename) { +static int _cleanfilename(char *filename) { char *pt, *npt; int ch, exists, ch2; @@ -77,6 +78,13 @@ return( true ); else return( true ); ch = getchar(); + if ( ch=='q' || ch=='Q' ) +exit(0); + if ( ch=='a' || ch=='A' ) { + force = true; + inquire = false; +return( true ); + } if ( ch=='y' || ch=='Y' || ch=='n' || ch=='N' || ch==EOF || ch=='\n' ) { if ( ch=='\n' || ch==EOF ) ch = exists ? 'n' : 'y'; @@ -88,11 +96,18 @@ return( ch=='y' || ch=='Y' ); *pt++ = ch; return( true ); } else { - fprintf( stderr, "Please answer with 'y'(es), 'n'(o) or '=new-filename'.\n" ); + fprintf( stderr, "Please answer with 'y'(es), 'n'(o), 'q'(uit), 'a'(ll), or '=new-filename'.\n" ); } } } +int cleanfilename(char *filename) { + int ret = _cleanfilename(filename); + if ( ret && show ) + fprintf( stderr, "Creating %s\n", filename ); +return( ret ); +} + static void mytmpname(char *temp) { static int upos; /* build up a temporary filename that doesn't match anything else */ @@ -104,14 +119,87 @@ 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; +/* The mac has rules about what the filename should be for a postscript*/ +/* font. If you deviate from those rules the font will not be found */ +/* The font name must begin with a capital letter */ +/* The filename is designed by modifying the font name */ +/* After the initial capital there can be at most 4 lower case letters (or digits) */ +/* in the filename, any additional lc letters (or digits) in the fontname are ignored */ +/* Every subsequent capital will be followed by at most 2 lc letters */ +/* special characters ("-$", etc.) are removed entirely */ +/* So Times-Bold => TimesBol, HelveticaDemiBold => HelveDemBol */ +static char *FileNameFromPSFontName(char *fontname) { + char *filename = strdup(fontname); + char *pt, *spt, *lcpt; + + for ( pt = filename, spt = fontname; *spt /*&& pt<filename+63-1*/; ++spt ) { + if ( isupper(*spt) || spt==fontname ) { + *pt++ = *spt; + lcpt = (spt==fontname?spt+5:spt+3); + } else if ( (islower(*spt) || isdigit(*spt)) && spt<lcpt ) + *pt++ = *spt; + } + *pt = '\0'; +return( filename ); +} + +static int IsResourceInFile(char *filename,PSFONT *psfont); + +static void ProcessNestedPS( char *fontname, char *origfilename, PSFONT *psfont ) { + char *filename = FileNameFromPSFontName(fontname); + + if ( filename!=NULL && *filename!='\0' ) { + char *dirend = strrchr(origfilename,'/'); + if ( dirend!=NULL ) { + char *newfn = malloc(strlen(filename)+strlen(origfilename)+1); + strcpy(newfn,origfilename); + strcpy(newfn + (dirend-origfilename)+1, filename); + free(filename); + filename = newfn; + } + if ( access(filename,R_OK)==0 ) + IsResourceInFile(filename,psfont); + else { + char *end; + filename = realloc(filename,strlen(filename)+10); + end = filename+strlen(filename); + strcpy(end,".bin"); + if ( access(filename,R_OK)==0 ) + IsResourceInFile(filename,psfont); + else { + strcpy(end,".hqx"); + if ( access(filename,R_OK)==0 ) + IsResourceInFile(filename,psfont); + } + } + } + if ( psfont!=NULL && psfont->fontname==NULL ) { + char *pt = strrchr(filename,'.'); + if ( pt!=NULL ) *pt = '\0'; + fprintf( stderr, "Failed to find file %s when searching for a postscript resource\n", filename ); + } + free(filename); +} + +static FILE *CreateAfmFile(FILE *f,FOND *fond,int style, + char *fontname,char *familyname, PSFONT *psfont, char *origfilename) { + char namebuf[300]; + int i; FILE *afm; - if ( styleoff==0 || style>=48 ) { - if ( fond->fondname!=NULL ) + memset(psfont,0,sizeof(PSFONT)); + if ( !(style&4) && fond->psnames[(style&3)|((style&~7)>>1)]!=NULL ) { + /* postscript name table doesn't include underline styles */ + char *fn = fond->psnames[(style&3)|((style&~7)>>1)]; + strcpy(familyname,fond->family); + strcpy(fontname,fn); + ProcessNestedPS( fn, origfilename, psfont ); + if ( psfont->familyname!=NULL ) + strcpy(familyname,psfont->familyname); /* Different in URW fonts */ + } else { + if ( fond->family!=NULL ) + strcpy(familyname,fond->family); + else if ( fond->fondname!=NULL ) strcpy(familyname,fond->fondname); else strcpy(familyname,"Nameless"); @@ -119,39 +207,6 @@ static FILE *CreateAfmFile(FILE *f,FOND *fond,long styleoff,int style, 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>1 && index-1<cnt ) { - char *ctl = strings[index-1]; - while ( *ctl ) { - if ( *ctl-1<cnt ) - strcat(fontname,strings[*ctl-1]); - ++ctl; - } - } - for ( i=1; i<cnt; ++i ) - free(strings[i]); - free(strings); } strcpy(namebuf,fontname); strcat(namebuf,".afm"); @@ -163,77 +218,159 @@ return( NULL ); return( afm ); } -static void MakeAfmFiles(FOND *fond,FILE *f, int styleoff, int isfixed) { +static void AfmBB(FILE *afm, struct bbglyph *bb,int enc, double em) { + fprintf( afm, "C %d ; WX %d ; ", enc, (int) (bb->hadvance*1000/em) ); + fprintf( afm, "N %s ; B %d %d %d %d ;", + bb->glyphname, + (int) floor(bb->left*1000/em), (int) floor(bb->bottom*1000/em), + (int) ceil(bb->right*1000/em), (int) ceil(bb->top*1000/em) ); + if ( strcmp(bb->glyphname,"fi")==0 ) + fprintf( afm, " L f i ;" ); + else if ( strcmp(bb->glyphname,"fl")==0 ) + fprintf( afm, " L f l ;" ); + else if ( strcmp(bb->glyphname,"ff")==0 ) + fprintf( afm, " L f f ;" ); + putc('\n',afm); +} + +static void MakeAfmFiles(FOND *fond,FILE *f, int isfixed,char *origfilename) { long start = ftell(f); - int i,j,k; + int ii,i,j,k,l,dups; FILE *afm; time_t now; char fontname[256], familyname[256]; char buffer[32]; + PSFONT psfont; - for ( i=0; i<fond->stylekerncnt; ++i ) { - for ( j=fond->stylewidthcnt-1; j>=0; --j ) - if ( fond->stylekerns[i].style==fond->stylewidths[j].style ) + for ( ii=0; ii<48; ++ii ) { + int style = ((ii&3)|((ii&~3)<<1)); + for ( i=fond->stylekerncnt-1; i>=0; --i ) + if ( fond->stylekerns[i].style==style ) break; - afm = CreateAfmFile(f,fond,styleoff,fond->stylekerns[i].style,fontname,familyname); + if ( i==-1 && fond->psnames[ii]==NULL ) + continue; + afm = CreateAfmFile(f,fond,style, + fontname,familyname,&psfont,origfilename); 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" ); + if ( psfont.fontname==NULL ) + 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 ); + if ( psfont.fontname!=NULL ) { + if ( psfont.fullname ) + fprintf( afm, "FullName %s\n", psfont.fullname ); + if ( psfont.weight ) + fprintf( afm, "Weight %s\n", psfont.weight ); + if ( psfont.notice ) + fprintf( afm, "Notice (%s)\n", psfont.notice ); + if ( psfont.version ) + fprintf( afm, "Version (%s)\n", psfont.version ); + fprintf( afm, "ItalicAngle %g\n", psfont.italicangle ); + fprintf( afm, "EncodingScheme %s\n", psfont.isadobestd ? + "AdobeStandardEncoding" : "FontSpecific" ); + fprintf( afm, "FontBBox %g %g %g %g\n", + psfont.fbb[0], psfont.fbb[1], psfont.fbb[2], psfont.fbb[3] ); + if ( psfont.xh!=0 ) + fprintf( afm, "XHeight %d\n", psfont.xh ); + if ( psfont.ch!=0 ) + fprintf( afm, "CapHeight %d\n", psfont.ch ); + if ( psfont.as!=0 ) + fprintf( afm, "Ascender %d\n", psfont.as ); + if ( psfont.ds!=0 ) + fprintf( afm, "Descender %d\n", psfont.ds ); + dups = 0; + for ( k=0; k<256; ++k ) { + if ( strcmp(psfont.glyphs[psfont.encoding[k]].glyphname,".notdef")==0 && psfont.glyphs[0].isref ) + continue; + for ( l=psfont.glyphcnt-1; l>=0; --l ) + if ( strcmp(psfont.glyphs[psfont.encoding[k]].glyphname,psfont.glyphs[l].glyphname)==0 ) + break; + if ( l==-1 ) + continue; + else if ( !psfont.glyphs[l].isref ) + psfont.glyphs[l].isref = true; + else + ++dups; } - 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; + fprintf( afm, "StartCharMetrics %d\n", psfont.glyphcnt+dups ); + psfont.glyphs[0].isref = false; + for ( k=0; k<256; ++k ) { + if ( strcmp(psfont.glyphs[psfont.encoding[k]].glyphname,".notdef")==0 && psfont.glyphs[0].isref ) + continue; + for ( l=psfont.glyphcnt-1; l>=0; --l ) + if ( strcmp(psfont.glyphs[psfont.encoding[k]].glyphname,psfont.glyphs[l].glyphname)==0 ) + break; + if ( l==-1 ) + continue; + AfmBB(afm,&psfont.glyphs[l],k,psfont.em); + psfont.glyphs[l].isref = true; } - if ( name1==NULL ) name1 = ".notdef"; - if ( kp->ch2<=256 ) - name2 = macnames[kp->ch2]; - else { - sprintf( fontname, "char%04x", kp->ch2 ); - name2 = fontname; + for ( l=0; l<psfont.glyphcnt; ++l ) if ( !psfont.glyphs[l].isref ) + AfmBB(afm,&psfont.glyphs[l],-1,psfont.em); + } else { + fprintf( afm, "Weight %s\n", ( style&sf_bold )?"Bold":"Medium" ); + if ( !( style&sf_italic )) + fprintf( afm, "ItalicAngle 0\n" ); + fprintf( afm, "EncodingScheme FontSpecific\n" ); + /* 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 */ + for ( j=fond->stylewidthcnt-1; j>=0; --j ) + if ( style==fond->stylewidths[j].style ) + break; + 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 ); + } + } else + fprintf( afm, "StartCharMetrics 0\n" ); + } + fprintf( afm, "EndCharMetrics\n" ); + if ( i!=-1 ) { + /* kerning data are from the fond. so they are in mac encoding */ + /* the pfb's encoding is irrelevant in this section */ + 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 ( name1==NULL ) name1 = ".notdef"; + if ( kp->ch2<=256 ) + name2 = macnames[kp->ch2]; + else { + sprintf( fontname, "char%04x", kp->ch2 ); + name2 = fontname; + } + if ( name2==NULL ) name2 = ".notdef"; + fprintf( afm, "KPX %s %s %d\n", name1, name2, (kp->offset*1000+(1<<11))>>12 ); } - if ( name2==NULL ) name2 = ".notdef"; - fprintf( afm, "KPX %s %s %d\n", name1, name2, (kp->offset*1000+(1<<11))>>12 ); + fprintf( afm, "EndKernPairs\nEndKernData\n"); } - fprintf( afm, "EndKernPairs\nEndKernData\nEndFontMetrics\n" ); + fprintf( afm, "EndFontMetrics\n" ); fclose( afm ); } fseek(f,start,SEEK_SET); @@ -248,7 +385,7 @@ static void MakeAfmFiles(FOND *fond,FILE *f, int styleoff, int isfixed) { /* 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 name_list,char *origfilename) { long here, start = ftell(f); long offset; int rname = -1; @@ -317,9 +454,7 @@ static FOND *BuildFondList(FILE *f,long rlistpos,int subcnt,long rdata_pos, 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*/ + if ( kernoff!=0 ) { fseek(f,kernoff,SEEK_SET); cnt = getushort(f)+1; cur->stylekerncnt = cnt; @@ -334,8 +469,55 @@ static FOND *BuildFondList(FILE *f,long rlistpos,int subcnt,long rdata_pos, cur->stylekerns[j].kerns[k].offset = getushort(f); } } - MakeAfmFiles(cur,f,styleoff,isfixed); } + if ( styleoff!=0 ) { + unsigned char stringoffsets[48]; + int strcnt, strlen, format; + char **strings, *pt; + fseek(f,styleoff,SEEK_SET); + /* class = */ getushort(f); + /* glyph encoding offset = */ getlong(f); + /* reserved = */ getlong(f); + for ( j=0; j<48; ++j ) + stringoffsets[j] = getc(f); + strcnt = getushort(f); + strings = malloc(strcnt*sizeof(char *)); + for ( j=0; j<strcnt; ++j ) { + strlen = getc(f); + strings[j] = malloc(strlen+2); + strings[j][0] = strlen; + strings[j][strlen+1] = '\0'; + for ( k=0; k<strlen; ++k ) + strings[j][k+1] = getc(f); + } + for ( j=0; j<48; ++j ) { + for ( k=j-1; k>=0; --k ) + if ( stringoffsets[j]==stringoffsets[k] ) + break; + if ( k!=-1 ) + continue; /* this style doesn't exist */ + format = stringoffsets[j]-1; + strlen = strings[0][0]; + if ( format!=0 ) + for ( k=0; k<strings[format][0]; ++k ) + strlen += strings[ strings[format][k+1]-1 ][0]; + pt = cur->psnames[j] = malloc(strlen+1); + strcpy(pt,strings[ 0 ]+1); + pt += strings[ 0 ][0]; + if ( format!=0 ) + for ( k=0; k<strings[format][0]; ++k ) { + strcpy(pt,strings[ strings[format][k+1]-1 ]+1); + pt += strings[ strings[format][k+1]-1 ][0]; + } + *pt = '\0'; + } + cur->family = strdup(strings[0]); + for ( j=0; j<strcnt; ++j ) + free(strings[j]); + free(strings); + } + if ( doafm ) + MakeAfmFiles(cur,f,isfixed,origfilename); fseek(f,here,SEEK_SET); } fseek(f,start,SEEK_SET); @@ -343,7 +525,7 @@ return( head ); } static void SearchPostscriptResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, - long name_list, FOND *fonds) { + long name_list, PSFONT *psfont) { long here = ftell(f); long *offsets, lenpos; int rname = -1, tmp; @@ -380,7 +562,7 @@ static void SearchPostscriptResources(FILE *f,long rlistpos,int subcnt,long rdat } else sprintf(newname,"Untitled-%d.pfb", ++ucnt ); - pfb = fopen( name,"w" ); + pfb = psfont!=NULL ? tmpfile() : fopen( name,"w" ); if ( pfb==NULL ) { fprintf( stderr, "Can't open temporary file for postscript output\n" ); fseek(f,here,SEEK_SET ); @@ -460,14 +642,20 @@ return; putc((len>>8)&0xff,pfb); putc((len>>16)&0xff,pfb); putc(len>>24,pfb); + if ( psfont!=NULL ) { + rewind(pfb); + ParsePfb(pfb,psfont); + } fclose(pfb); - if ( cleanfilename(newname)) { - if ( rename(name,newname)==-1 ) { - fprintf( stderr, "Could not create %s\n", newname); + if ( psfont==NULL ) { + if ( cleanfilename(newname)) { + if ( rename(name,newname)==-1 ) { + fprintf( stderr, "Could not create %s\n", newname); + unlink(name); + } + } else unlink(name); - } - } else - unlink(name); + } fseek(f,here,SEEK_SET); } @@ -662,7 +850,7 @@ exit( 1 ); return( true ); } -static int IsResourceFork(FILE *f, long offset) { +static int IsResourceFork(FILE *f, long offset,char *filename, PSFONT *psfont) { /* 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 */ @@ -673,7 +861,7 @@ static int IsResourceFork(FILE *f, long offset) { long rdata_len, map_len; unsigned long tag; int i, cnt, subcnt; - FOND *fondlist=NULL; + FOND *fondlist=NULL, *fl; fseek(f,offset,SEEK_SET); if ( fread(buffer,1,16,f)!=16 ) @@ -705,14 +893,22 @@ return( false ); 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); + if ( psfont==NULL ) { + 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,filename); + } + + if ( trackps ) { + for ( fl = fondlist; fl!=NULL; fl=fl->next ) + for ( i=0; i<48; ++i ) if ( fl->psnames[i]!=NULL ) + ProcessNestedPS( fl->psnames[i],filename, NULL ); + } } fseek(f,type_list,SEEK_SET); @@ -723,7 +919,9 @@ return( false ); 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); + SearchPostscriptResources(f,rpos,subcnt,rdata_pos,name_list,psfont); + else if ( psfont!=NULL ) + /* No Op */; 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')) @@ -738,10 +936,28 @@ return( false ); return( true ); } -#ifdef __Mac +#ifndef OldMacintosh + /* OS/X and linux with appropriate drivers */ +static int HasResourceFork(char *filename,PSFONT *psfont) { + char *respath = malloc(strlen(filename)+strlen("/rsrc")+1); + FILE *temp; + int ret; + + strcpy(respath,filename); + strcat(respath,"/rsrc"); + temp = fopen(respath,"r"); + free(respath); + if ( temp!=NULL ) { + ret = IsResourceFork(temp,0,filename,psfont); + fclose(temp); + } +return( ret ); +} +#else + /* OS/9 and before */ #include "MacFiles.h" -static int HasResourceFork(char *filename) { +static int HasResourceFork(char *filename,PSFONT *psfont) { /* If we're on a mac, we can try to see if we've got a real resource fork */ FSRef ref; FSSpec spec; @@ -771,13 +987,13 @@ return( 0 ); free(buf); FSClose(res); rewind(temp); - ret = IsResourceFork(temp,0); + ret = IsResourceFork(temp,0,filename,psfont); fclose(temp); return( ret ); } #endif -static int IsResourceInBinary(FILE *f) { +static int IsResourceInBinary(FILE *f,char *filename, PSFONT *psfont) { unsigned char header[128], first[8]; unsigned long offset, dlen, rlen; @@ -803,7 +1019,7 @@ return( MightBeTrueType(f,pos,dlen,(char *) header+2)); } /* 128 bytes for header, then the dlen is padded to a 128 byte boundary */ offset = 128 + ((dlen+127)&~127); -return( IsResourceFork(f,offset)); +return( IsResourceFork(f,offset,filename,psfont)); } static int lastch=0, repeat = 0; @@ -828,7 +1044,7 @@ static void outchr(FILE *binary, int ch) { } } -static int IsResourceInHex(FILE *f) { +static int IsResourceInHex(FILE *f,char *filename, PSFONT *psfont) { /* convert file from 6bit to 8bit */ /* interesting data is enclosed between two colons */ FILE *binary = tmpfile(); @@ -907,13 +1123,13 @@ return( ret ); return( false ); } - ret = IsResourceFork(binary,ftell(binary)+dlen+2); + ret = IsResourceFork(binary,ftell(binary)+dlen+2, filename,psfont); fclose(binary); return( ret ); } -static int IsResourceInFile(char *filename) { +static int IsResourceInFile(char *filename,PSFONT *psfont) { FILE *f; char *spt, *pt; int ret; @@ -926,24 +1142,22 @@ return( false ); 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)) { + if ( IsResourceInBinary(f,filename,psfont)) { 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)) { + if ( IsResourceInHex(f,filename,psfont)) { fclose(f); return( true ); } } - ret = IsResourceFork(f,0); + ret = IsResourceFork(f,0,filename,psfont); fclose(f); -#ifdef __Mac if ( !ret ) - ret = HasResourceFork(filename); -#endif + ret = HasResourceFork(filename,psfont); return( ret ); } @@ -951,7 +1165,7 @@ static int FindResourceFile(char *filename) { char *spt, *pt, *dpt; char buffer[1400]; - if ( IsResourceInFile(filename)) + if ( IsResourceInFile(filename,NULL)) return( true ); /* Well, look in the resource fork directory (if it exists), the resource */ @@ -962,7 +1176,7 @@ return( true ); else { ++spt; pt = filename + (spt-buffer); } strcpy(spt,"resource.frk/"); strcat(spt,pt); - if ( IsResourceInFile(buffer)) + if ( IsResourceInFile(buffer,NULL)) return( true ); /* however the resource fork does not appear to long names properly */ @@ -983,7 +1197,7 @@ return( true ); *dpt++ = '1'; strcpy(dpt,exten); } -return( IsResourceInFile(buffer)); +return( IsResourceInFile(buffer,NULL)); } int main(int argc, char **argv) { @@ -998,16 +1212,23 @@ int main(int argc, char **argv) { 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 ) + inquire = true; + else if (strcmp(pt,"-afm")==0 || strcmp(pt,"-a")==0 ) doafm = true; + else if (strcmp(pt,"-trackps")==0 || strcmp(pt,"-t")==0 ) + trackps = true; + else if (strcmp(pt,"-show")==0 || strcmp(pt,"-s")==0 ) + show = true; else { - fprintf( stderr, "Usage: %s [-force] [-inquire] [-latin1] [-afm] macfiles\n", + fprintf( stderr, "Usage: %s [-force] [-inquire] [-latin1] [-afm] [-trackps] [-show] 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 -show is given you will not be told about each file created.\n" ); fprintf( stderr, " if -latin1 is given nfnts will be reencoded to latin1 (else left in mac roman)\n" ); + fprintf( stderr, " if -trackps is given then any postscript files referenced by a FOND\n" ); + fprintf( stderr, "\twill be loaded and processed.\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); diff --git a/fondups.c b/fondups.c new file mode 100644 index 0000000..2c8d556 --- /dev/null +++ b/fondups.c @@ -0,0 +1,3075 @@ +/* Copyright (C) 2000-2004 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 <unistd.h> +#include "psfont.h" +#include "macfonts.h" +#include <locale.h> +#include <math.h> + +struct fontparse { + FontDict *fd, *mainfd; + /* always in font data */ + unsigned int infi:1; + unsigned int inchars:1; + unsigned int inprivate:1; + unsigned int insubs:1; + unsigned int inmetrics: 1; + unsigned int inmetrics2: 1; + unsigned int inbb: 1; + unsigned int inencoding: 1; + unsigned int multiline: 1; + unsigned int incidsysteminfo: 1; + unsigned int inblendfi:1; + unsigned int inblendprivate:1; + unsigned int skipping_mbf: 1; + unsigned int inblend: 1; + unsigned int iscid: 1; + unsigned int iscff: 1; + unsigned int useshexstrings: 1; + unsigned int doneencoding: 1; + unsigned int ignore: 1; + int instring; + int fdindex; + char **pending_parse; + + unsigned int alreadycomplained: 1; + + char *vbuf, *vmax, *vpt; + int depth; +}; + +static char *copyn(const char *str,long n) { + char *ret; + + if ( str==NULL ) +return( NULL ); + ret = malloc(n+1); + memcpy(ret,str,n); + ret[n]='\0'; +return( ret ); +} + +static char *PSDictHasEntry(struct psdict *dict, char *key) { + int i; + + if ( dict==NULL ) +return( NULL ); + + for ( i=0; i<dict->next; ++i ) + if ( strcmp(dict->keys[i],key)==0 ) +return( dict->values[i] ); + +return( NULL ); +} + +static int PSDictRemoveEntry(struct psdict *dict, char *key) { + int i; + + if ( dict==NULL ) +return( false ); + + for ( i=0; i<dict->next; ++i ) + if ( strcmp(dict->keys[i],key)==0 ) + break; + if ( i==dict->next ) +return( false ); + free( dict->keys[i]); + free( dict->values[i] ); + --dict->next; + while ( i<dict->next ) { + dict->keys[i] = dict->keys[i+1]; + dict->values[i] = dict->values[i+1]; + ++i; + } + +return( true ); +} + +static void copyenc(char *encoding[256],char *std[256]) { + int i; + for ( i=0; i<256; ++i ) + encoding[i] = strdup(std[i]); +} + +char *AdobeStandardEncoding[] = { +/* 0000 */ ".notdef", +/* 0001 */ ".notdef", +/* 0002 */ ".notdef", +/* 0003 */ ".notdef", +/* 0004 */ ".notdef", +/* 0005 */ ".notdef", +/* 0006 */ ".notdef", +/* 0007 */ ".notdef", +/* 0008 */ ".notdef", +/* 0009 */ ".notdef", +/* 000a */ ".notdef", +/* 000b */ ".notdef", +/* 000c */ ".notdef", +/* 000d */ ".notdef", +/* 000e */ ".notdef", +/* 000f */ ".notdef", +/* 0010 */ ".notdef", +/* 0011 */ ".notdef", +/* 0012 */ ".notdef", +/* 0013 */ ".notdef", +/* 0014 */ ".notdef", +/* 0015 */ ".notdef", +/* 0016 */ ".notdef", +/* 0017 */ ".notdef", +/* 0018 */ ".notdef", +/* 0019 */ ".notdef", +/* 001a */ ".notdef", +/* 001b */ ".notdef", +/* 001c */ ".notdef", +/* 001d */ ".notdef", +/* 001e */ ".notdef", +/* 001f */ ".notdef", +/* 0020 */ "space", +/* 0021 */ "exclam", +/* 0022 */ "quotedbl", +/* 0023 */ "numbersign", +/* 0024 */ "dollar", +/* 0025 */ "percent", +/* 0026 */ "ampersand", +/* 0027 */ "quoteright", +/* 0028 */ "parenleft", +/* 0029 */ "parenright", +/* 002a */ "asterisk", +/* 002b */ "plus", +/* 002c */ "comma", +/* 002d */ "hyphen", +/* 002e */ "period", +/* 002f */ "slash", +/* 0030 */ "zero", +/* 0031 */ "one", +/* 0032 */ "two", +/* 0033 */ "three", +/* 0034 */ "four", +/* 0035 */ "five", +/* 0036 */ "six", +/* 0037 */ "seven", +/* 0038 */ "eight", +/* 0039 */ "nine", +/* 003a */ "colon", +/* 003b */ "semicolon", +/* 003c */ "less", +/* 003d */ "equal", +/* 003e */ "greater", +/* 003f */ "question", +/* 0040 */ "at", +/* 0041 */ "A", +/* 0042 */ "B", +/* 0043 */ "C", +/* 0044 */ "D", +/* 0045 */ "E", +/* 0046 */ "F", +/* 0047 */ "G", +/* 0048 */ "H", +/* 0049 */ "I", +/* 004a */ "J", +/* 004b */ "K", +/* 004c */ "L", +/* 004d */ "M", +/* 004e */ "N", +/* 004f */ "O", +/* 0050 */ "P", +/* 0051 */ "Q", +/* 0052 */ "R", +/* 0053 */ "S", +/* 0054 */ "T", +/* 0055 */ "U", +/* 0056 */ "V", +/* 0057 */ "W", +/* 0058 */ "X", +/* 0059 */ "Y", +/* 005a */ "Z", +/* 005b */ "bracketleft", +/* 005c */ "backslash", +/* 005d */ "bracketright", +/* 005e */ "asciicircum", +/* 005f */ "underscore", +/* 0060 */ "quoteleft", +/* 0061 */ "a", +/* 0062 */ "b", +/* 0063 */ "c", +/* 0064 */ "d", +/* 0065 */ "e", +/* 0066 */ "f", +/* 0067 */ "g", +/* 0068 */ "h", +/* 0069 */ "i", +/* 006a */ "j", +/* 006b */ "k", +/* 006c */ "l", +/* 006d */ "m", +/* 006e */ "n", +/* 006f */ "o", +/* 0070 */ "p", +/* 0071 */ "q", +/* 0072 */ "r", +/* 0073 */ "s", +/* 0074 */ "t", +/* 0075 */ "u", +/* 0076 */ "v", +/* 0077 */ "w", +/* 0078 */ "x", +/* 0079 */ "y", +/* 007a */ "z", +/* 007b */ "braceleft", +/* 007c */ "bar", +/* 007d */ "braceright", +/* 007e */ "asciitilde", +/* 007f */ ".notdef", +/* 0080 */ ".notdef", +/* 0081 */ ".notdef", +/* 0082 */ ".notdef", +/* 0083 */ ".notdef", +/* 0084 */ ".notdef", +/* 0085 */ ".notdef", +/* 0086 */ ".notdef", +/* 0087 */ ".notdef", +/* 0088 */ ".notdef", +/* 0089 */ ".notdef", +/* 008a */ ".notdef", +/* 008b */ ".notdef", +/* 008c */ ".notdef", +/* 008d */ ".notdef", +/* 008e */ ".notdef", +/* 008f */ ".notdef", +/* 0090 */ ".notdef", +/* 0091 */ ".notdef", +/* 0092 */ ".notdef", +/* 0093 */ ".notdef", +/* 0094 */ ".notdef", +/* 0095 */ ".notdef", +/* 0096 */ ".notdef", +/* 0097 */ ".notdef", +/* 0098 */ ".notdef", +/* 0099 */ ".notdef", +/* 009a */ ".notdef", +/* 009b */ ".notdef", +/* 009c */ ".notdef", +/* 009d */ ".notdef", +/* 009e */ ".notdef", +/* 009f */ ".notdef", +/* 00a0 */ ".notdef", +/* 00a1 */ "exclamdown", +/* 00a2 */ "cent", +/* 00a3 */ "sterling", +/* 00a4 */ "fraction", +/* 00a5 */ "yen", +/* 00a6 */ "florin", +/* 00a7 */ "section", +/* 00a8 */ "currency", +/* 00a9 */ "quotesingle", +/* 00aa */ "quotedblleft", +/* 00ab */ "guillemotleft", +/* 00ac */ "guilsinglleft", +/* 00ad */ "guilsinglright", +/* 00ae */ "fi", +/* 00af */ "fl", +/* 00b0 */ ".notdef", +/* 00b1 */ "endash", +/* 00b2 */ "dagger", +/* 00b3 */ "daggerdbl", +/* 00b4 */ "periodcentered", +/* 00b5 */ ".notdef", +/* 00b6 */ "paragraph", +/* 00b7 */ "bullet", +/* 00b8 */ "quotesinglbase", +/* 00b9 */ "quotedblbase", +/* 00ba */ "quotedblright", +/* 00bb */ "guillemotright", +/* 00bc */ "ellipsis", +/* 00bd */ "perthousand", +/* 00be */ ".notdef", +/* 00bf */ "questiondown", +/* 00c0 */ ".notdef", +/* 00c1 */ "grave", +/* 00c2 */ "acute", +/* 00c3 */ "circumflex", +/* 00c4 */ "tilde", +/* 00c5 */ "macron", +/* 00c6 */ "breve", +/* 00c7 */ "dotaccent", +/* 00c8 */ "dieresis", +/* 00c9 */ ".notdef", +/* 00ca */ "ring", +/* 00cb */ "cedilla", +/* 00cc */ ".notdef", +/* 00cd */ "hungarumlaut", +/* 00ce */ "ogonek", +/* 00cf */ "caron", +/* 00d0 */ "emdash", +/* 00d1 */ ".notdef", +/* 00d2 */ ".notdef", +/* 00d3 */ ".notdef", +/* 00d4 */ ".notdef", +/* 00d5 */ ".notdef", +/* 00d6 */ ".notdef", +/* 00d7 */ ".notdef", +/* 00d8 */ ".notdef", +/* 00d9 */ ".notdef", +/* 00da */ ".notdef", +/* 00db */ ".notdef", +/* 00dc */ ".notdef", +/* 00dd */ ".notdef", +/* 00de */ ".notdef", +/* 00df */ ".notdef", +/* 00e0 */ ".notdef", +/* 00e1 */ "AE", +/* 00e2 */ ".notdef", +/* 00e3 */ "ordfeminine", +/* 00e4 */ ".notdef", +/* 00e5 */ ".notdef", +/* 00e6 */ ".notdef", +/* 00e7 */ ".notdef", +/* 00e8 */ "Lslash", +/* 00e9 */ "Oslash", +/* 00ea */ "OE", +/* 00eb */ "ordmasculine", +/* 00ec */ ".notdef", +/* 00ed */ ".notdef", +/* 00ee */ ".notdef", +/* 00ef */ ".notdef", +/* 00f0 */ ".notdef", +/* 00f1 */ "ae", +/* 00f2 */ ".notdef", +/* 00f3 */ ".notdef", +/* 00f4 */ ".notdef", +/* 00f5 */ "dotlessi", +/* 00f6 */ ".notdef", +/* 00f7 */ ".notdef", +/* 00f8 */ "lslash", +/* 00f9 */ "oslash", +/* 00fa */ "oe", +/* 00fb */ "germandbls", +/* 00fc */ ".notdef", +/* 00fd */ ".notdef", +/* 00fe */ ".notdef", +/* 00ff */ ".notdef" +}; +static void setStdEnc(char *encoding[256]) { + copyenc(encoding,AdobeStandardEncoding); +} + +static void setLatin1Enc(char *encoding[256]) { + static char *latin1enc[] = { +/* 0000 */ ".notdef", +/* 0001 */ ".notdef", +/* 0002 */ ".notdef", +/* 0003 */ ".notdef", +/* 0004 */ ".notdef", +/* 0005 */ ".notdef", +/* 0006 */ ".notdef", +/* 0007 */ ".notdef", +/* 0008 */ ".notdef", +/* 0009 */ ".notdef", +/* 000a */ ".notdef", +/* 000b */ ".notdef", +/* 000c */ ".notdef", +/* 000d */ ".notdef", +/* 000e */ ".notdef", +/* 000f */ ".notdef", +/* 0010 */ ".notdef", +/* 0011 */ ".notdef", +/* 0012 */ ".notdef", +/* 0013 */ ".notdef", +/* 0014 */ ".notdef", +/* 0015 */ ".notdef", +/* 0016 */ ".notdef", +/* 0017 */ ".notdef", +/* 0018 */ ".notdef", +/* 0019 */ ".notdef", +/* 001a */ ".notdef", +/* 001b */ ".notdef", +/* 001c */ ".notdef", +/* 001d */ ".notdef", +/* 001e */ ".notdef", +/* 001f */ ".notdef", +/* 0020 */ "space", +/* 0021 */ "exclam", +/* 0022 */ "quotedbl", +/* 0023 */ "numbersign", +/* 0024 */ "dollar", +/* 0025 */ "percent", +/* 0026 */ "ampersand", +/* 0027 */ "quoteright", +/* 0028 */ "parenleft", +/* 0029 */ "parenright", +/* 002a */ "asterisk", +/* 002b */ "plus", +/* 002c */ "comma", +/* 002d */ "hyphen", +/* 002e */ "period", +/* 002f */ "slash", +/* 0030 */ "zero", +/* 0031 */ "one", +/* 0032 */ "two", +/* 0033 */ "three", +/* 0034 */ "four", +/* 0035 */ "five", +/* 0036 */ "six", +/* 0037 */ "seven", +/* 0038 */ "eight", +/* 0039 */ "nine", +/* 003a */ "colon", +/* 003b */ "semicolon", +/* 003c */ "less", +/* 003d */ "equal", +/* 003e */ "greater", +/* 003f */ "question", +/* 0040 */ "at", +/* 0041 */ "A", +/* 0042 */ "B", +/* 0043 */ "C", +/* 0044 */ "D", +/* 0045 */ "E", +/* 0046 */ "F", +/* 0047 */ "G", +/* 0048 */ "H", +/* 0049 */ "I", +/* 004a */ "J", +/* 004b */ "K", +/* 004c */ "L", +/* 004d */ "M", +/* 004e */ "N", +/* 004f */ "O", +/* 0050 */ "P", +/* 0051 */ "Q", +/* 0052 */ "R", +/* 0053 */ "S", +/* 0054 */ "T", +/* 0055 */ "U", +/* 0056 */ "V", +/* 0057 */ "W", +/* 0058 */ "X", +/* 0059 */ "Y", +/* 005a */ "Z", +/* 005b */ "bracketleft", +/* 005c */ "backslash", +/* 005d */ "bracketright", +/* 005e */ "asciicircum", +/* 005f */ "underscore", +/* 0060 */ "grave", +/* 0061 */ "a", +/* 0062 */ "b", +/* 0063 */ "c", +/* 0064 */ "d", +/* 0065 */ "e", +/* 0066 */ "f", +/* 0067 */ "g", +/* 0068 */ "h", +/* 0069 */ "i", +/* 006a */ "j", +/* 006b */ "k", +/* 006c */ "l", +/* 006d */ "m", +/* 006e */ "n", +/* 006f */ "o", +/* 0070 */ "p", +/* 0071 */ "q", +/* 0072 */ "r", +/* 0073 */ "s", +/* 0074 */ "t", +/* 0075 */ "u", +/* 0076 */ "v", +/* 0077 */ "w", +/* 0078 */ "x", +/* 0079 */ "y", +/* 007a */ "z", +/* 007b */ "braceleft", +/* 007c */ "bar", +/* 007d */ "braceright", +/* 007e */ "asciitilde", +/* 007f */ ".notdef", +/* 0080 */ ".notdef", +/* 0081 */ ".notdef", +/* 0082 */ ".notdef", +/* 0083 */ ".notdef", +/* 0084 */ ".notdef", +/* 0085 */ ".notdef", +/* 0086 */ ".notdef", +/* 0087 */ ".notdef", +/* 0088 */ ".notdef", +/* 0089 */ ".notdef", +/* 008a */ ".notdef", +/* 008b */ ".notdef", +/* 008c */ ".notdef", +/* 008d */ ".notdef", +/* 008e */ ".notdef", +/* 008f */ ".notdef", +/* 0090 */ "dotlessi", /* Um, Adobe's Latin1 has some extra chars */ +/* 0091 */ "grave", +/* 0092 */ "accute", /* This is a duplicate... */ +/* 0093 */ "circumflex", +/* 0094 */ "tilde", +/* 0095 */ "macron", +/* 0096 */ "breve", +/* 0097 */ "dotaccent", +/* 0098 */ "dieresis", +/* 0099 */ ".notdef", +/* 009a */ "ring", +/* 009b */ "cedilla", +/* 009c */ ".notdef", +/* 009d */ "hungarumlaut", +/* 009e */ "ogonek", +/* 009f */ "caron", +/* 00a0 */ "space", +/* 00a1 */ "exclamdown", +/* 00a2 */ "cent", +/* 00a3 */ "sterling", +/* 00a4 */ "currency", +/* 00a5 */ "yen", +/* 00a6 */ "brokenbar", +/* 00a7 */ "section", +/* 00a8 */ "dieresis", +/* 00a9 */ "copyright", +/* 00aa */ "ordfeminine", +/* 00ab */ "guillemotleft", +/* 00ac */ "logicalnot", +/* 00ad */ "hyphen", +/* 00ae */ "registered", +/* 00af */ "macron", +/* 00b0 */ "degree", +/* 00b1 */ "plusminus", +/* 00b2 */ "twosuperior", +/* 00b3 */ "threesuperior", +/* 00b4 */ "acute", +/* 00b5 */ "mu", +/* 00b6 */ "paragraph", +/* 00b7 */ "periodcentered", +/* 00b8 */ "cedilla", +/* 00b9 */ "onesuperior", +/* 00ba */ "ordmasculine", +/* 00bb */ "guillemotright", +/* 00bc */ "onequarter", +/* 00bd */ "onehalf", +/* 00be */ "threequarters", +/* 00bf */ "questiondown", +/* 00c0 */ "Agrave", +/* 00c1 */ "Aacute", +/* 00c2 */ "Acircumflex", +/* 00c3 */ "Atilde", +/* 00c4 */ "Adieresis", +/* 00c5 */ "Aring", +/* 00c6 */ "AE", +/* 00c7 */ "Ccedilla", +/* 00c8 */ "Egrave", +/* 00c9 */ "Eacute", +/* 00ca */ "Ecircumflex", +/* 00cb */ "Edieresis", +/* 00cc */ "Igrave", +/* 00cd */ "Iacute", +/* 00ce */ "Icircumflex", +/* 00cf */ "Idieresis", +/* 00d0 */ "Eth", +/* 00d1 */ "Ntilde", +/* 00d2 */ "Ograve", +/* 00d3 */ "Oacute", +/* 00d4 */ "Ocircumflex", +/* 00d5 */ "Otilde", +/* 00d6 */ "Odieresis", +/* 00d7 */ "multiply", +/* 00d8 */ "Oslash", +/* 00d9 */ "Ugrave", +/* 00da */ "Uacute", +/* 00db */ "Ucircumflex", +/* 00dc */ "Udieresis", +/* 00dd */ "Yacute", +/* 00de */ "Thorn", +/* 00df */ "germandbls", +/* 00e0 */ "agrave", +/* 00e1 */ "aacute", +/* 00e2 */ "acircumflex", +/* 00e3 */ "atilde", +/* 00e4 */ "adieresis", +/* 00e5 */ "aring", +/* 00e6 */ "ae", +/* 00e7 */ "ccedilla", +/* 00e8 */ "egrave", +/* 00e9 */ "eacute", +/* 00ea */ "ecircumflex", +/* 00eb */ "edieresis", +/* 00ec */ "igrave", +/* 00ed */ "iacute", +/* 00ee */ "icircumflex", +/* 00ef */ "idieresis", +/* 00f0 */ "eth", +/* 00f1 */ "ntilde", +/* 00f2 */ "ograve", +/* 00f3 */ "oacute", +/* 00f4 */ "ocircumflex", +/* 00f5 */ "otilde", +/* 00f6 */ "odieresis", +/* 00f7 */ "divide", +/* 00f8 */ "oslash", +/* 00f9 */ "ugrave", +/* 00fa */ "uacute", +/* 00fb */ "ucircumflex", +/* 00fc */ "udieresis", +/* 00fd */ "yacute", +/* 00fe */ "thorn", +/* 00ff */ "ydieresis" + }; + copyenc(encoding,latin1enc); +} + +char *AdobeExpertEncoding[] = { +/* 0000 */ ".notdef", +/* 0001 */ ".notdef", +/* 0002 */ ".notdef", +/* 0003 */ ".notdef", +/* 0004 */ ".notdef", +/* 0005 */ ".notdef", +/* 0006 */ ".notdef", +/* 0007 */ ".notdef", +/* 0008 */ ".notdef", +/* 0009 */ ".notdef", +/* 000a */ ".notdef", +/* 000b */ ".notdef", +/* 000c */ ".notdef", +/* 000d */ ".notdef", +/* 000e */ ".notdef", +/* 000f */ ".notdef", +/* 0010 */ ".notdef", +/* 0011 */ ".notdef", +/* 0012 */ ".notdef", +/* 0013 */ ".notdef", +/* 0014 */ ".notdef", +/* 0015 */ ".notdef", +/* 0016 */ ".notdef", +/* 0017 */ ".notdef", +/* 0018 */ ".notdef", +/* 0019 */ ".notdef", +/* 001a */ ".notdef", +/* 001b */ ".notdef", +/* 001c */ ".notdef", +/* 001d */ ".notdef", +/* 001e */ ".notdef", +/* 001f */ ".notdef", +/* 0020 */ "space", +/* 0021 */ "exclamsmall", +/* 0022 */ "Hungarumlautsmal", +/* 0023 */ ".notdef", +/* 0024 */ "dollaroldstyle", +/* 0025 */ "dollarsuperior", +/* 0026 */ "ampersandsmall", +/* 0027 */ "Acutesmall", +/* 0028 */ "parenleftsuperior", +/* 0029 */ "parenrightsuperior", +/* 002a */ "twodotenleader", +/* 002b */ "onedotenleader", +/* 002c */ "comma", +/* 002d */ "hyphen", +/* 002e */ "period", +/* 002f */ "fraction", +/* 0030 */ "zerooldstyle", +/* 0031 */ "oneoldstyle", +/* 0032 */ "twooldstyle", +/* 0033 */ "threeoldstyle", +/* 0034 */ "fouroldstyle", +/* 0035 */ "fiveoldstyle", +/* 0036 */ "sixoldstyle", +/* 0037 */ "sevenoldstyle", +/* 0038 */ "eightoldstyle", +/* 0039 */ "nineoldstyle", +/* 003a */ "colon", +/* 003b */ "semicolon", +/* 003c */ "commasuperior", +/* 003d */ "threequartersemdash", +/* 003e */ "periodsuperior", +/* 003f */ "questionsmall", +/* 0040 */ ".notdef", +/* 0041 */ "asuperior", +/* 0042 */ "bsuperior", +/* 0043 */ "centsuperior", +/* 0044 */ "dsuperior", +/* 0045 */ "esuperior", +/* 0046 */ ".notdef", +/* 0047 */ ".notdef", +/* 0048 */ ".notdef", +/* 0049 */ "isuperior", +/* 004a */ ".notdef", +/* 004b */ ".notdef", +/* 004c */ "lsuperior", +/* 004d */ "msuperior", +/* 004e */ "nsuperior", +/* 004f */ "osuperior", +/* 0050 */ ".notdef", +/* 0051 */ ".notdef", +/* 0052 */ "rsuperior", +/* 0053 */ "ssuperior", +/* 0054 */ "tsuperior", +/* 0055 */ ".notdef", +/* 0056 */ "ff", +/* 0057 */ "fi", +/* 0058 */ "fl", +/* 0059 */ "ffi", +/* 005a */ "ffl", +/* 005b */ "parenleftinferior", +/* 005c */ ".notdef", +/* 005d */ "parenrightinferior", +/* 005e */ "Circumflexsmall", +/* 005f */ "hyphensuperior", +/* 0060 */ "Gravesmall", +/* 0061 */ "Asmall", +/* 0062 */ "Bsmall", +/* 0063 */ "Csmall", +/* 0064 */ "Dsmall", +/* 0065 */ "Esmall", +/* 0066 */ "Fsmall", +/* 0067 */ "Gsmall", +/* 0068 */ "Hsmall", +/* 0069 */ "Ismall", +/* 006a */ "Jsmall", +/* 006b */ "Ksmall", +/* 006c */ "Lsmall", +/* 006d */ "Msmall", +/* 006e */ "Nsmall", +/* 006f */ "Osmall", +/* 0070 */ "Psmall", +/* 0071 */ "Qsmall", +/* 0072 */ "Rsmall", +/* 0073 */ "Ssmall", +/* 0074 */ "Tsmall", +/* 0075 */ "Usmall", +/* 0076 */ "Vsmall", +/* 0077 */ "Wsmall", +/* 0078 */ "Xsmall", +/* 0079 */ "Ysmall", +/* 007a */ "Zsmall", +/* 007b */ "colonmonetary", +/* 007c */ "onefitted", +/* 007d */ "rupiah", +/* 007e */ "Tildesmall", +/* 007f */ ".notdef", +/* 0080 */ ".notdef", +/* 0081 */ ".notdef", +/* 0082 */ ".notdef", +/* 0083 */ ".notdef", +/* 0084 */ ".notdef", +/* 0085 */ ".notdef", +/* 0086 */ ".notdef", +/* 0087 */ ".notdef", +/* 0088 */ ".notdef", +/* 0089 */ ".notdef", +/* 008a */ ".notdef", +/* 008b */ ".notdef", +/* 008c */ ".notdef", +/* 008d */ ".notdef", +/* 008e */ ".notdef", +/* 008f */ ".notdef", +/* 0090 */ ".notdef", +/* 0091 */ ".notdef", +/* 0092 */ ".notdef", +/* 0093 */ ".notdef", +/* 0094 */ ".notdef", +/* 0095 */ ".notdef", +/* 0096 */ ".notdef", +/* 0097 */ ".notdef", +/* 0098 */ ".notdef", +/* 0099 */ ".notdef", +/* 009a */ ".notdef", +/* 009b */ ".notdef", +/* 009c */ ".notdef", +/* 009d */ ".notdef", +/* 009e */ ".notdef", +/* 009f */ ".notdef", +/* 00a0 */ ".notdef", +/* 00a1 */ "exclamdownsmall", +/* 00a2 */ "centoldstyle", +/* 00a3 */ "Lslashsmall", +/* 00a4 */ ".notdef", +/* 00a5 */ ".notdef", +/* 00a6 */ "Scaronsmall", +/* 00a7 */ "Zcaronsmall", +/* 00a8 */ "Dieresissmall", +/* 00a9 */ "Brevesmall", +/* 00aa */ "Caronsmall", +/* 00ab */ ".notdef", +/* 00ac */ "Dotaccentsmall", +/* 00ad */ ".notdef", +/* 00ae */ ".notdef", +/* 00af */ "Macronsmall", +/* 00b0 */ ".notdef", +/* 00b1 */ ".notdef", +/* 00b2 */ "figuredash", +/* 00b3 */ "hypheninferior", +/* 00b4 */ ".notdef", +/* 00b5 */ ".notdef", +/* 00b6 */ "Ogoneksmall", +/* 00b7 */ "Ringsmall", +/* 00b8 */ "Cedillasmall", +/* 00b9 */ ".notdef", +/* 00ba */ ".notdef", +/* 00bb */ ".notdef", +/* 00bc */ "onequarter", +/* 00bd */ "onehalf", +/* 00be */ "threequarters", +/* 00bf */ "questiondownsmall", +/* 00c0 */ "oneeighth", +/* 00c1 */ "threeeighths", +/* 00c2 */ "fiveeighths", +/* 00c3 */ "seveneighths", +/* 00c4 */ "onethird", +/* 00c5 */ "twothirds", +/* 00c6 */ ".notdef", +/* 00c7 */ ".notdef", +/* 00c8 */ "zerosuperior", +/* 00c9 */ "onesuperior", +/* 00ca */ "twosuperior", +/* 00cb */ "threesuperior", +/* 00cc */ "foursuperior", +/* 00cd */ "fivesuperior", +/* 00ce */ "sixsuperior", +/* 00cf */ "sevensuperior", +/* 00d0 */ "eightsuperior", +/* 00d1 */ "ninesuperior", +/* 00d2 */ "zeroinferior", +/* 00d3 */ "oneinferior", +/* 00d4 */ "twoinferior", +/* 00d5 */ "threeinferior", +/* 00d6 */ "fourinferior", +/* 00d7 */ "fiveinferior", +/* 00d8 */ "sixinferior", +/* 00d9 */ "seveninferior", +/* 00da */ "eightinferior", +/* 00db */ "nineinferior", +/* 00dc */ "centinferior", +/* 00dd */ "dollarinferior", +/* 00de */ "periodinferior", +/* 00df */ "commainferior", +/* 00e0 */ "Agravesmall", +/* 00e1 */ "Aacutesmall", +/* 00e2 */ "Acircumflexsmall", +/* 00e3 */ "Atildesmall", +/* 00e4 */ "Adieresissmall", +/* 00e5 */ "Aringsmall", +/* 00e6 */ "AEsmall", +/* 00e7 */ "Ccedillasmall", +/* 00e8 */ "Egravesmall", +/* 00e9 */ "Eacutesmall", +/* 00ea */ "Ecircumflexsmall", +/* 00eb */ "Edieresissmall", +/* 00ec */ "Igravesmall", +/* 00ed */ "Iacutesmall", +/* 00ee */ "Icircumflexsmall", +/* 00ef */ "Idieresissmall", +/* 00f0 */ "Ethsmall", +/* 00f1 */ "Ntildesmall", +/* 00f2 */ "Ogravesmall", +/* 00f3 */ "Oacutesmall", +/* 00f4 */ "Ocircumflexsmall", +/* 00f5 */ "Otildesmall", +/* 00f6 */ "Odieresissmall", +/* 00f7 */ "OEsmall", +/* 00f8 */ "Oslashsmall", +/* 00f9 */ "Ugravesmall", +/* 00fa */ "Uacutesmall", +/* 00fb */ "Ucircumflexsmall", +/* 00fc */ "Udieresissmall", +/* 00fd */ "Yacutesmall", +/* 00fe */ "Thornsmall", +/* 00ff */ "Ydieresissmall" +}; + +static struct fontdict *MakeEmptyFont(void) { + struct fontdict *ret; + + ret = calloc(1,sizeof(struct fontdict)); + ret->fontinfo = calloc(1,sizeof(struct fontinfo)); + ret->chars = calloc(1,sizeof(struct pschars)); + ret->private = calloc(1,sizeof(struct private)); + ret->private->subrs = calloc(1,sizeof(struct pschars)); + ret->private->private = calloc(1,sizeof(struct psdict)); + ret->private->leniv = 4; + ret->fontinfo->fstype = -1; +return( ret ); +} + +static struct fontdict *PSMakeEmptyFont(void) { + struct fontdict *ret; + + ret = calloc(1,sizeof(struct fontdict)); + ret->fontinfo = calloc(1,sizeof(struct fontinfo)); + ret->chars = calloc(1,sizeof(struct pschars)); + ret->private = calloc(1,sizeof(struct private)); + ret->private->subrs = calloc(1,sizeof(struct pschars)); + ret->private->private = calloc(1,sizeof(struct psdict)); + ret->private->leniv = 4; + ret->charprocs = calloc(1,sizeof(struct charprocs)); + ret->fontinfo->fstype = -1; +return( ret ); +} + +static char *myfgets(char *str, int len, FILE *file) { + char *pt, *end; + int ch=0; + + for ( pt = str, end = str+len-1; pt<end && (ch=getc(file))!=EOF && ch!='\r' && ch!='\n'; + *pt++ = ch ); + if ( ch=='\n' ) + *pt++ = '\n'; + else if ( ch=='\r' ) { + *pt++ = '\r'; + if ((ch=getc(file))!='\n' ) + ungetc(ch,file); + else + *pt++ = '\n'; + } + if ( pt==str ) +return( NULL ); + *pt = '\0'; +return( str ); +} + +static char *getstring(char *start,FILE *in) { + char *end, *ret; + int parencnt=0, len=0; + char buffer[512]; + + forever { + while ( *start!='\0' && *start!='(' ) ++start; + if ( *start=='\0' ) { + if ( myfgets(buffer,sizeof(buffer),in)==NULL ) +return( strdup("")); + start = buffer; + } else + break; + } + ++start; + ret = NULL; len = 1; + forever { + for ( end = start; *end!='\0' && (*end!=')' || parencnt>0); ++end ) { + if ( *end=='\\' && (end[1]=='(' || end[1]==')')) + ++end; + else if ( *end=='(' ) ++parencnt; + else if ( *end==')' ) --parencnt; + } + if ( end>start ) { + if ( ret==NULL ) + ret = malloc(end-start+1); + else + ret = realloc(ret,len+end-start); + strncpy(ret+len-1,start,end-start); + len += end-start; + ret[len-1] = '\0'; + } + if ( *end!='\0' ) + break; + if ( myfgets(buffer,sizeof(buffer),in)==NULL ) +return( ret ); + start = buffer; + } +return( ret ); +} + +static char *gettoken(char *start) { + char *end, *ret; + + while ( *start!='\0' && *start!='/' ) ++start; + if ( *start=='/' ) ++start; + for ( end = start; *end!='\0' && !isspace(*end) && *end!='[' && *end!='/' && *end!='{' && *end!='(' ; ++end ); + ret = malloc(end-start+1); + if ( end>start ) + strncpy(ret,start,end-start); + ret[end-start] = '\0'; +return( ret ); +} + +static int getbool(char *start) { + + while ( isspace(*start) ) ++start; + if ( *start=='T' || *start=='t' ) +return( 1 ); + +return( 0 ); +} + +static void fillintarray(int *array,char *start,int maxentries) { + int i; + char *end; + + while ( *start!='\0' && *start!='[' && *start!='{' ) ++start; + if ( *start=='[' || *start=='{' ) ++start; + for ( i=0; i<maxentries && *start!=']' && *start!='}'; ++i ) { + array[i] = (int) strtod(start,&end); + if ( start==end ) +return; + start = end; + while ( isspace(*start) ) ++start; + } +} + +static void filldoublearray(double *array,char *start,int maxentries) { + int i; + char *end; + + while ( *start!='\0' && *start!='[' && *start!='{' ) ++start; + if ( *start=='[' || *start=='{' ) ++start; + for ( i=0; i<maxentries && *start!=']' && *start!='}'; ++i ) { + while ( isspace( *start )) ++start; + if ( isdigit(*start) || *start=='-' || *start=='.' ) + array[i] = strtod(start,&end); + else if ( strncmp(start,"div",3)==0 && i>=2 ) { + /* Some of Luc Devroye's fonts have a "div" in the FontMatrix */ + array[i-2] /= array[i-1]; + i -= 2; + end = start+3; + } else +return; + if ( start==end ) +return; + start = end; + while ( isspace(*start) ) ++start; + } +} + +static void InitDict(struct psdict *dict,char *line) { + while ( *line!='/' && *line!='\0' ) ++line; + while ( !isspace(*line) && *line!='\0' ) ++line; + dict->cnt += strtol(line,NULL,10); + if ( dict->next>0 ) { int i; /* Shouldn't happen, but did in a bad file */ + dict->keys = realloc(dict->keys,dict->cnt*sizeof(char *)); + dict->values = realloc(dict->values,dict->cnt*sizeof(char *)); + for ( i=dict->next; i<dict->cnt; ++i ) { + dict->keys[i] = NULL; dict->values[i] = NULL; + } + } else { + dict->keys = calloc(dict->cnt,sizeof(char *)); + dict->values = calloc(dict->cnt,sizeof(char *)); + } +} + +static void InitChars(struct pschars *chars,char *line) { + while ( *line!='/' && *line!='\0' ) ++line; + while ( !isspace(*line) && *line!='\0' ) ++line; + chars->cnt = strtol(line,NULL,10); + if ( chars->cnt>0 ) { + chars->keys = calloc(chars->cnt,sizeof(char *)); + chars->values = calloc(chars->cnt,sizeof(char *)); + chars->lens = calloc(chars->cnt,sizeof(int)); + } +} + +static void InitCharProcs(struct charprocs *cp, char *line) { + while ( *line!='/' && *line!='\0' ) ++line; + while ( !isspace(*line) && *line!='\0' ) ++line; + cp->cnt = strtol(line,NULL,10); + if ( cp->cnt>0 ) { + cp->keys = calloc(cp->cnt,sizeof(char *)); + cp->values = NULL; + } +} + +static int mycmp(char *str,char *within, char *end ) { + while ( within<end ) { + if ( *str!=*within ) +return( *str-*within ); + ++str; ++within; + } +return( *str=='\0'?0:1 ); +} + +static void ContinueValue(struct fontparse *fp, struct psdict *dict, char *line) { + int incomment = false; + + while ( *line ) { + if ( !fp->instring && fp->depth==0 && + (strncmp(line,"def",3)==0 || + strncmp(line,"|-",2)==0 || strncmp(line,"ND",2)==0)) { + while ( 1 ) { + while ( fp->vpt>fp->vbuf+1 && isspace(fp->vpt[-1]) ) + --fp->vpt; + if ( fp->vpt>fp->vbuf+8 && strncmp(fp->vpt-8,"noaccess",8)==0 ) + fp->vpt -= 8; + else if ( fp->vpt>fp->vbuf+8 && strncmp(fp->vpt-8,"readonly",8)==0 ) + fp->vpt -= 8; + else if ( fp->vpt>fp->vbuf+4 && strncmp(fp->vpt-4,"bind",4)==0 ) + fp->vpt -= 4; + else + break; + } + /* In some URW fonts (Nimbus Sans L, n019003l) we get a complex */ + /* expression rather than just an array. This is ok. The expression */ + /* converts itself into an array. We could just truncate to the */ + /* default array, but I don't see any reason to do so */ + if ( fp->pending_parse!=NULL ) { + *fp->pending_parse = copyn(fp->vbuf,fp->vpt-fp->vbuf); + fp->pending_parse = NULL; + } else { + dict->values[dict->next] = copyn(fp->vbuf,fp->vpt-fp->vbuf); + ++dict->next; + } + fp->vpt = fp->vbuf; + fp->multiline = false; +return; + } + if ( fp->vpt>=fp->vmax ) { + int len = fp->vmax-fp->vbuf+1000, off=fp->vpt-fp->vbuf; + fp->vbuf = realloc(fp->vbuf,len); + fp->vpt = fp->vbuf+off; + fp->vmax = fp->vbuf+len; + } + if ( fp->instring ) { + if ( *line==')' ) --fp->instring; + } else if ( incomment ) { + /* Do Nothing */; + } else if ( *line=='(' ) + ++fp->instring; + else if ( *line=='%' ) + incomment = true; + else if ( *line=='[' || *line=='{' ) + ++fp->depth; + else if ( *line=='}' || *line==']' ) + --fp->depth; + *fp->vpt++ = *line++; + } +} + +static void AddValue(struct fontparse *fp, struct psdict *dict, char *line, char *endtok) { + char *pt; + + if ( dict!=NULL ) { + if ( dict->next>=dict->cnt ) { + dict->cnt += 10; + dict->keys = realloc(dict->keys,dict->cnt*sizeof(char *)); + dict->values = realloc(dict->values,dict->cnt*sizeof(char *)); + } + dict->keys[dict->next] = copyn(line+1,endtok-(line+1)); + } + pt = line+strlen(line)-1; + while ( isspace(*endtok)) ++endtok; + while ( pt>endtok && isspace(*pt)) --pt; + ++pt; + if ( strncmp(pt-3,"def",3)==0 ) + pt -= 3; + else if ( strncmp(pt-2,"|-",2)==0 || strncmp(pt-2,"ND",2)==0 ) + pt -= 2; + else { + fp->multiline = true; + ContinueValue(fp,dict,endtok); +return; + } + forever { + while ( pt-1>endtok && isspace(pt[-1])) --pt; + if ( pt-8>endtok && strncmp(pt-8,"noaccess",8)==0 ) + pt -= 8; + else if ( pt-8>endtok && strncmp(pt-8,"readonly",8)==0 ) + pt -= 8; + else if ( pt-4>endtok && strncmp(pt-4,"bind",4)==0 ) + pt -= 4; + else + break; + } + if ( dict!=NULL ) { + dict->values[dict->next] = copyn(endtok,pt-endtok); + ++dict->next; + } else { + *fp->pending_parse = copyn(endtok,pt-endtok); + fp->pending_parse = NULL; + } +} + +static int hex(int ch1, int ch2) { + if ( ch1>='0' && ch1<='9' ) + ch1 -= '0'; + else if ( ch1>='a' ) + ch1 -= 'a'-10; + else + ch1 -= 'A'-10; + if ( ch2>='0' && ch2<='9' ) + ch2 -= '0'; + else if ( ch2>='a' ) + ch2 -= 'a'-10; + else + ch2 -= 'A'-10; +return( (ch1<<4)|ch2 ); +} + +unsigned short r; +#define c1 52845 +#define c2 22719 + +static void initcode(void) { + r = 55665; +} + +static int decode(unsigned char cypher) { + unsigned char plain = ( cypher ^ (r>>8)); + r = (cypher + r) * c1 + c2; +return( plain ); +} + +static void dumpzeros(FILE *out, unsigned char *zeros, int zcnt) { + while ( --zcnt >= 0 ) + fputc(*zeros++,out); +} + +static void decodestr(unsigned char *str, int len) { + unsigned short r = 4330; + unsigned char plain, cypher; + + while ( len-->0 ) { + cypher = *str; + plain = ( cypher ^ (r>>8)); + r = (cypher + r) * c1 + c2; + *str++ = plain; + } +} + +static void findstring(struct fontparse *fp,struct pschars *subrs,int index,char *nametok,char *str) { + char buffer[1024], *bpt, *bs, *end = buffer+sizeof(buffer)-1; + int val; + + while ( isspace(*str)) ++str; + if ( *str=='(' ) { + ++str; + bpt = buffer; + while ( *str!=')' ) { + if ( *str!='\\' ) + val = *str++; + else { + if ( isdigit( *++str )) { + val = *str++-'0'; + if ( isdigit( *str )) { + val = (val<<3) | (*str++-'0'); + if ( isdigit( *str )) + val = (val<<3) | (*str++-'0'); + } + } else + val = *str++; + } + if ( bpt<end ) + *bpt++ = val; + } + decodestr((unsigned char *) buffer,bpt-buffer); + bs = buffer + fp->fd->private->leniv; + subrs->lens[index] = bpt-bs; + subrs->keys[index] = strdup(nametok); + subrs->values[index] = malloc(bpt-bs); + memcpy(subrs->values[index],bs,bpt-bs); + if ( index>=subrs->next ) subrs->next = index+1; + } +} + +static char *rmbinary(char *line) { + char *pt; + + for ( pt=line; *pt; ++pt ) { + if (( *pt<' ' || *pt>=0x7f ) && *pt!='\n' ) { + if ( strlen(pt)>5 ) { + pt[0] = '.'; + pt[1] = '.'; + pt[2] = '.'; + pt[3] = '\n'; + pt[4] = '\0'; + } else { + pt[0] = '\n'; + pt[1] = '\0'; + } + break; + } + } +return( line ); +} + +static void parseline(struct fontparse *fp,char *line,FILE *in) { + char buffer[200], *pt, *endtok; + + while ( *line==' ' || *line=='\t' ) ++line; + if ( line[0]=='%' && !fp->multiline ) +return; + + if ( fp->inencoding && strncmp(line,"dup",3)==0 ) { + /* Metamorphasis has multiple entries on a line */ + while ( strncmp(line,"dup",3)==0 ) { + char *end; + int pos = strtol(line+3,&end,10); + line = end; + while ( isspace( *line )) ++line; + if ( *line=='/' ) ++line; + for ( pt = buffer; !isspace(*line); *pt++ = *line++ ); + *pt = '\0'; + if ( pos>=0 && pos<256 ) + fp->fd->encoding[pos] = strdup(buffer); + while ( isspace(*line)) ++line; + if ( strncmp(line,"put",3)==0 ) line+=3; + while ( isspace(*line)) ++line; + } +return; + } else if ( fp->inencoding && strstr(line,"for")!=NULL && strstr(line,"/.notdef")!=NULL ) { + /* the T1 spec I've got doesn't allow for this, but I've seen it anyway*/ + /* 0 1 255 {1 index exch /.notdef put} for */ + /* 0 1 31 { 1 index exch /.notdef put } bind for */ + int i; + for ( i=0; i<256; ++i ) + if ( fp->fd->encoding[i]==NULL ) + fp->fd->encoding[i] = strdup(".notdef"); +return; + } else if ( fp->inencoding && strstr(line,"Encoding")!=NULL && strstr(line,"put")!=NULL ) { + /* Saw a type 3 font with lines like "Encoding 1 /_a0 put" */ + char *end; + int pos; + while ( isspace(*line)) ++line; + if ( strncmp(line,"Encoding ",9)==0 ) { + line+=9; + pos = strtol(line,&end,10); + line = end; + while ( isspace(*line)) ++line; + if ( *line=='/' ) { + ++line; + for ( pt = buffer; !isspace(*line); *pt++ = *line++ ); + *pt = '\0'; + if ( pos>=0 && pos<256 ) + fp->fd->encoding[pos] = strdup(buffer); + } + } +return; + } else if ( fp->insubs ) { + struct pschars *subrs = fp->fd->private->subrs; + while ( isspace(*line)) ++line; + if ( strncmp(line,"dup ",4)==0 ) { + int i; + char *ept; + for ( line += 4; *line==' '; ++line ); + i = strtol(line,&ept,10); + if ( fp->ignore ) + /* Do Nothing */; + else if ( i<subrs->cnt ) { + findstring(fp,subrs,i,NULL,ept); + } else if ( !fp->alreadycomplained ) { + fprintf( stderr, "Index too big (must be <%d) |%s", subrs->cnt, rmbinary(line)); + fp->alreadycomplained = true; + } + } else if ( strncmp(line, "readonly put", 12)==0 || strncmp(line, "ND", 2)==0 || strncmp(line, "|-", 2)==0 ) { + fp->insubs = false; + fp->ignore = false; + } else if ( *line=='\n' || *line=='\0' ) { + /* Ignore blank lines */; + } else if ( !fp->alreadycomplained ) { + fprintf( stderr, "Didn't understand |%s", rmbinary(line) ); + fp->alreadycomplained = true; + } + } else if ( fp->inchars ) { + struct pschars *chars = fp->fd->chars; + while ( isspace(*line)) ++line; + if ( strncmp(line,"end",3)==0 ) + fp->ignore = fp->inchars = false; + else if ( *line!='\n' || *line=='\0' ) + /* Ignore it */; + else if ( *line!='/' || !(isalpha(line[1]) || line[1]=='.')) { + fprintf( stderr, "No name for CharStrings dictionary |%s", rmbinary(line) ); + fp->alreadycomplained = true; + } else if ( fp->ignore ) { + /* Do Nothing */; + } else if ( chars->next>=chars->cnt ) + fprintf( stderr, "Too many entries in CharStrings dictionary |%s", rmbinary(line) ); + else { + int i = chars->next; + char *namestrt = ++line; + while ( isalnum(*line) || *line=='.' ) ++line; + *line = '\0'; + findstring(fp,chars,i,namestrt,line+1); + } + } + fp->inencoding = 0; + + while ( isspace(*line)) ++line; + endtok = NULL; + if ( *line=='/' ) + for ( endtok=line+1; !isspace(*endtok) && *endtok!='(' && + *endtok!='{' && *endtok!='[' && *endtok!='\0'; ++endtok ); + + if ( strstr(line,"/shareddict")!=NULL && strstr(line,"where")!=NULL ) { + fp->infi = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->inprivate = fp->inblendprivate = fp->inblendfi = false; + fp->skipping_mbf = true; +return; + } + + if ( mycmp("Encoding",line+1,endtok)==0 && !fp->doneencoding ) { + if ( strstr(endtok,"StandardEncoding")!=NULL ) { + setStdEnc(fp->fd->encoding); + fp->fd->isadobestd = true; + } else if ( strstr(endtok,"ISOLatin1Encoding")!=NULL ) { + setLatin1Enc(fp->fd->encoding); + } else { + fp->inencoding = 1; + } + fp->infi = fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->doneencoding = true; + } else if ( mycmp("BoundingBoxes",line+1,endtok)==0 ) { + fp->infi = fp->inprivate = fp->inencoding = fp->inmetrics = fp->inmetrics2 = false; + fp->inbb = true; + } else if ( mycmp("Metrics",line+1,endtok)==0 ) { + fp->infi = fp->inprivate = fp->inbb = fp->inencoding = fp->inmetrics2 = false; + fp->inmetrics = true; + fp->fd->metrics = calloc(1,sizeof(struct psdict)); + fp->fd->metrics->cnt = strtol(endtok,NULL,10); + fp->fd->metrics->keys = malloc(fp->fd->metrics->cnt*sizeof(char *)); + fp->fd->metrics->values = malloc(fp->fd->metrics->cnt*sizeof(char *)); + } else if ( strstr(line,"/Private")!=NULL && strstr(line,"/Blend")!=NULL ) { + fp->infi = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->inprivate = fp->inblendprivate = fp->inblendfi = false; + fp->inblendprivate = 1; + fp->fd->blendprivate = calloc(1,sizeof(struct psdict)); + InitDict(fp->fd->blendprivate,line); +return; + } else if ( strstr(line,"/FontInfo")!=NULL && strstr(line,"/Blend")!=NULL ) { + fp->infi = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->inprivate = fp->inblendprivate = fp->inblendfi = false; + fp->inblendfi = 1; + fp->fd->blendfontinfo = calloc(1,sizeof(struct psdict)); + InitDict(fp->fd->blendfontinfo,line); +return; + } else if ( fp->infi ) { + if ( fp->multiline ) { + ContinueValue(fp,NULL,line); +return; + } + if ( endtok==NULL && strncmp(line,"end", 3)==0 ) { + fp->infi=0; +return; + } else if ( endtok==NULL ) +return; + if ( mycmp("version",line+1,endtok)==0 ) + fp->fd->fontinfo->version = getstring(endtok,in); + else if ( mycmp("Notice",line+1,endtok)==0 ) { + if ( fp->fd->fontinfo->notice!=NULL ) + free(fp->fd->fontinfo->notice); + fp->fd->fontinfo->notice = getstring(endtok,in); + } else if ( mycmp("Copyright",line+1,endtok)==0 ) { /* cff spec allows for copyright and notice */ + if ( fp->fd->fontinfo->notice!=NULL ) + free(fp->fd->fontinfo->notice); + fp->fd->fontinfo->notice = getstring(endtok,in); + } else if ( mycmp("FullName",line+1,endtok)==0 ) { + if ( fp->fd->fontinfo->fullname==NULL ) + fp->fd->fontinfo->fullname = getstring(endtok,in); + else + getstring(endtok,in); + } else if ( mycmp("FamilyName",line+1,endtok)==0 ) + fp->fd->fontinfo->familyname = getstring(endtok,in); + else if ( mycmp("Weight",line+1,endtok)==0 ) + fp->fd->fontinfo->weight = getstring(endtok,in); + else if ( mycmp("ItalicAngle",line+1,endtok)==0 ) + fp->fd->fontinfo->italicangle = strtod(endtok,NULL); + else if ( mycmp("UnderlinePosition",line+1,endtok)==0 ) + fp->fd->fontinfo->underlineposition = strtod(endtok,NULL); + else if ( mycmp("UnderlineThickness",line+1,endtok)==0 ) + fp->fd->fontinfo->underlinethickness = strtod(endtok,NULL); + else if ( mycmp("isFixedPitch",line+1,endtok)==0 ) + fp->fd->fontinfo->isfixedpitch = getbool(endtok); + else if ( mycmp("em",line+1,endtok)==0 ) + fp->fd->fontinfo->em = strtol(endtok,NULL,10); + else if ( mycmp("ascent",line+1,endtok)==0 ) + fp->fd->fontinfo->ascent = strtol(endtok,NULL,10); + else if ( mycmp("descent",line+1,endtok)==0 ) + fp->fd->fontinfo->descent = strtol(endtok,NULL,10); + else if ( mycmp("FSType",line+1,endtok)==0 ) + fp->fd->fontinfo->fstype = strtol(endtok,NULL,10); + else if ( mycmp("BlendDesignPositions",line+1,endtok)==0 ) { + fp->pending_parse = &fp->fd->fontinfo->blenddesignpositions; + AddValue(fp,NULL,line,endtok); + } else if ( mycmp("BlendDesignMap",line+1,endtok)==0 ) { + fp->pending_parse = &fp->fd->fontinfo->blenddesignmap; + AddValue(fp,NULL,line,endtok); + } else if ( mycmp("BlendAxisTypes",line+1,endtok)==0 ) { + fp->pending_parse = &fp->fd->fontinfo->blendaxistypes; + AddValue(fp,NULL,line,endtok); + } else if ( !fp->alreadycomplained ) { + fprintf( stderr, "Didn't understand |%s", rmbinary(line) ); + fp->alreadycomplained = true; + } + } else if ( fp->inblend ) { + if ( endtok==NULL ) { + if ( *line!='/' && strstr(line,"end")!=NULL ) + fp->inblend = false; +return; + } + /* Ignore anything in the blend dict defn */ + } else if ( fp->inblendprivate || fp->inblendfi ) { + struct psdict *subdict = fp->inblendfi ? fp->fd->blendfontinfo : fp->fd->blendprivate; + if ( fp->multiline ) { + ContinueValue(fp,subdict,line); +return; + } else if ( endtok==NULL ) { + if ( *line!='/' && strstr(line,"end")!=NULL ) { + fp->inblendprivate = fp->inblendfi = false; + fp->inprivate = true; + } +return; + } else + AddValue(fp,subdict,line,endtok); + } else if ( fp->inprivate ) { + if ( strstr(line,"/CharStrings")!=NULL && strstr(line,"dict")!=NULL ) { + if ( fp->fd->chars->next==0 ) { + InitChars(fp->fd->chars,line); + fp->ignore = false; + } else { + fp->ignore = true; + fprintf( stderr, "Ignoring duplicate /CharStrings entry\n" ); + } + fp->inchars = 1; + fp->insubs = 0; +return; + } else if ( strstr(line,"/Subrs")!=NULL ) { + if ( fp->fd->private->subrs->next>0 ) { + fp->ignore = true; + fprintf( stderr, "Ignoring duplicate /Subrs entry\n" ); + } else { + InitChars(fp->fd->private->subrs,line); + fp->ignore = false; + } + fp->insubs = 1; + fp->inchars = 0; +return; + } else if ( fp->multiline ) { + ContinueValue(fp,fp->fd->private->private,line); +return; + } + if ( endtok==NULL ) { + char *pt = line; + if ( *pt!='/' ) while ( (pt=strstr(pt,"end"))!=NULL ) { + if ( fp->inchars ) fp->inchars = false; + else fp->inprivate = false; + pt += 3; + } +return; + } + if ( mycmp("ND",line+1,endtok)==0 || mycmp("|-",line+1,endtok)==0 || + mycmp("NP",line+1,endtok)==0 || mycmp("|",line+1,endtok)==0 || + mycmp("RD",line+1,endtok)==0 || mycmp("-|",line+1,endtok)==0 || + mycmp("password",line+1,endtok)==0 || + mycmp("MinFeature",line+1,endtok)==0 ) + /* These conveigh no information, but are required */; + else if ( mycmp("UniqueID",line+1,endtok)==0 ) { + if ( fp->fd->uniqueid==0 ) + fp->fd->uniqueid = strtol(endtok,NULL,10); + } else { + if ( mycmp("lenIV",line+1,endtok)==0 ) + fp->fd->private->leniv = strtol(endtok,NULL,10); /* We need this value */ + AddValue(fp,fp->fd->private->private,line,endtok); + } + } else if ( fp->incidsysteminfo ) { + if ( endtok==NULL && strncmp(line,"end", 3)==0 ) { + fp->incidsysteminfo=0; +return; + } else if ( endtok==NULL ) +return; + if ( mycmp("Registry",line+1,endtok)==0 ) + fp->fd->registry = getstring(endtok,in); + else if ( mycmp("Ordering",line+1,endtok)==0 ) + fp->fd->ordering = getstring(endtok,in); + else if ( mycmp("Supplement",line+1,endtok)==0 ) /* cff spec allows for copyright and notice */ + fp->fd->supplement = strtol(endtok,NULL,0); + } else { + if ( strstr(line,"/Private")!=NULL && strstr(line,"dict")!=NULL ) { + fp->infi = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->inprivate = fp->inblendprivate = fp->inblendfi = false; + if ( strstr(line,"/Blend")!=NULL ) { + fp->inblendprivate = 1; + fp->fd->blendprivate = calloc(1,sizeof(struct psdict)); + InitDict(fp->fd->blendprivate,line); + } else { + fp->inprivate = 1; + InitDict(fp->fd->private->private,line); + } +return; + } else if ( strstr(line,"/FontInfo")!=NULL && strstr(line,"dict")!=NULL ) { + fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->infi = fp->inblendprivate = fp->inblendfi = false; + if ( strstr(line,"/Blend")!=NULL ) { + fp->inblendfi = 1; + fp->fd->blendfontinfo = calloc(1,sizeof(struct psdict)); + InitDict(fp->fd->blendfontinfo,line); + } else { + fp->infi = 1; + } +return; + } else if ( strstr(line,"/Blend")!=NULL && strstr(line,"dict")!=NULL ) { + fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->infi = fp->inblendprivate = fp->inblendfi = false; + fp->inblend = true; +return; + } else if ( strstr(line,"/CharStrings")!=NULL && strstr(line,"dict")!=NULL ) { + if ( fp->fd->chars->next==0 ) { + InitChars(fp->fd->chars,line); + fp->ignore = false; + } else { + fp->ignore = true; + fprintf( stderr, "Ignoring duplicate /CharStrings entry\n" ); + } + fp->inchars = 1; + fp->insubs = 0; + fp->infi = fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->inblendprivate = fp->inblendfi = false; +return; + } else if ( mycmp("/CharProcs",line,endtok)==0 ) { + InitCharProcs(fp->fd->charprocs,line); + fp->infi = fp->inprivate = fp->inbb = fp->inmetrics = fp->inmetrics2 = false; + fp->insubs = 0; +return; + } else if ( strstr(line,"/CIDSystemInfo")!=NULL ) { + fp->incidsysteminfo = 1; +return; + } else if ( fp->inmetrics ) { + if ( endtok!=NULL ) + AddValue(fp,fp->fd->metrics,line,endtok); +return; + } else if ( fp->inbb ) { + /* Ignore it */; +return; + } + + if ( fp->multiline ) { + ContinueValue(fp,NULL,line); +return; + } + + if ( endtok==NULL ) { + if ( fp->skipping_mbf ) + ; + else if ( fp->fdindex!=-1 && strstr(line,"end")!=NULL ) { + if ( ++fp->fdindex>=fp->mainfd->fdcnt ) + fp->fd = fp->mainfd; + else + fp->fd = fp->mainfd->fds[fp->fdindex]; + } +return; + } + if ( mycmp("FontName",line+1,endtok)==0 ) { + if ( fp->fd->fontname==NULL ) + fp->fd->fontname = gettoken(endtok); + else + gettoken(endtok); /* skip it */ + } else if ( mycmp("PaintType",line+1,endtok)==0 ) + fp->fd->painttype = strtol(endtok,NULL,10); + else if ( mycmp("FontType",line+1,endtok)==0 ) + fp->fd->fonttype = strtol(endtok,NULL,10); + else if ( mycmp("FontMatrix",line+1,endtok)==0 ) { + if ( fp->fd->fontmatrix[0]==0 ) + filldoublearray(fp->fd->fontmatrix,endtok,6); + else { + double temp[6]; + filldoublearray(temp,endtok,6); + } + } else if ( mycmp("LanguageLevel",line+1,endtok)==0 ) + fp->fd->languagelevel = strtol(endtok,NULL,10); + else if ( mycmp("WMode",line+1,endtok)==0 ) + fp->fd->wmode = strtol(endtok,NULL,10); + else if ( mycmp("FontBBox",line+1,endtok)==0 ) + filldoublearray(fp->fd->fontbb,endtok,4); + else if ( mycmp("UniqueID",line+1,endtok)==0 ) { + if ( fp->fd->uniqueid==0 ) + fp->fd->uniqueid = strtol(endtok,NULL,10); + } else if ( mycmp("UniqueId",line+1,endtok)==0 ) { + fprintf(stderr,"This font contains a \"UniqueId\" variable, but the correct name for it is\n\t\"UniqueID\" (postscript is case concious)\n" ); + if ( fp->fd->uniqueid==0 ) + fp->fd->uniqueid = strtol(endtok,NULL,10); + } else if ( mycmp("XUID",line+1,endtok)==0 ) { + if ( fp->fd->xuid[0]==0 ) + fillintarray(fp->fd->xuid,endtok,20); + } else if ( mycmp("StrokeWidth",line+1,endtok)==0 ) + fp->fd->strokewidth = strtod(endtok,NULL); + else if ( mycmp("WeightVector",line+1,endtok)==0 ) { + fp->pending_parse = &fp->fd->weightvector; + AddValue(fp,NULL,line,endtok); + } else if ( mycmp("$Blend",line+1,endtok)==0 ) { + fp->pending_parse = &fp->fd->blendfunc; + AddValue(fp,NULL,line,endtok); + } else if ( strstr( line,"/NormalizeDesignVector" )!=NULL ) { + fp->pending_parse = &fp->fd->ndv; + AddValue(fp,NULL,line,endtok); + } else if ( strstr( line,"/ConvertDesignVector" )!=NULL ) { + fp->pending_parse = &fp->fd->cdv; + AddValue(fp,NULL,line,endtok); + } else if ( mycmp("BuildChar",line+1,endtok)==0 ) + /* Do Nothing */; + else if ( mycmp("BuildGlyph",line+1,endtok)==0 ) + /* Do Nothing */; + else if ( mycmp("CIDFontName",line+1,endtok)==0 ) + fp->fd->cidfontname = gettoken(endtok); + else if ( mycmp("CIDFontVersion",line+1,endtok)==0 ) { + fp->fd->cidversion = strtod(endtok,NULL); +#if 0 + if ( fp->fd->fontinfo->version==NULL ) { + char temp[40]; + sprintf(temp,"%f", fp->fd->cidversion); + fp->fd->fontinfo->version = strdup(temp); + } +#endif + } else if ( mycmp("CIDFontType",line+1,endtok)==0 ) + fp->fd->cidfonttype = strtol(endtok,NULL,10); + else if ( mycmp("UIDBase",line+1,endtok)==0 ) + fp->fd->uniqueid = strtol(endtok,NULL,10); + else if ( mycmp("CIDMapOffset",line+1,endtok)==0 ) + fp->fd->mapoffset = strtol(endtok,NULL,10); + else if ( mycmp("FDBytes",line+1,endtok)==0 ) + fp->fd->fdbytes = strtol(endtok,NULL,10); + else if ( mycmp("GDBytes",line+1,endtok)==0 ) + fp->fd->gdbytes = strtol(endtok,NULL,10); + else if ( mycmp("CIDCount",line+1,endtok)==0 ) + fp->fd->cidcnt = strtol(endtok,NULL,10); + else if ( mycmp("FDArray",line+1,endtok)==0 ) { int i; + fp->mainfd = fp->fd; + fp->fd->fdcnt = strtol(endtok,NULL,10); + fp->fd->fds = calloc(fp->fd->fdcnt,sizeof(struct fontdict *)); + for ( i=0; i<fp->fd->fdcnt; ++i ) + fp->fd->fds[i] = MakeEmptyFont(); + fp->fdindex = 0; + fp->fd = fp->fd->fds[0]; + } else if ( mycmp("FontSetInit",line+1,endtok)==0 ) { + fp->iscff = true; + fp->iscid = false; + } else if ( mycmp("CIDInit",line+1,endtok)==0 ) { + fp->iscid = true; + fp->iscff = false; + } else if ( fp->skipping_mbf ) { /* Skip over the makeblendedfont defn in a multimaster font */ + /* Do Nothing */ + } else if ( !fp->alreadycomplained ) { + fprintf( stderr, "Didn't understand |%s", rmbinary(line) ); + fp->alreadycomplained = true; + } + } +} + +static void addinfo(struct fontparse *fp,char *line,char *tok,char *binstart,int binlen,FILE *in) { + char *pt; + + decodestr((unsigned char *) binstart,binlen); + binstart += fp->fd->private->leniv; + binlen -= fp->fd->private->leniv; + + retry: + if ( fp->insubs ) { + struct pschars *chars = /*fp->insubs ?*/ fp->fd->private->subrs /*: fp->fd->private->othersubrs*/; + while ( isspace(*line)) ++line; + if ( strncmp(line,"dup ",4)==0 ) { + int i = strtol(line+4,NULL,10); + if ( fp->ignore ) + /* Do Nothing */; + else if ( i<chars->cnt ) { + if ( chars->values[i]!=NULL ) + fprintf( stderr, "Duplicate definition of subroutine %d\n", i ); + chars->lens[i] = binlen; + chars->values[i] = malloc(binlen); + memcpy(chars->values[i],binstart,binlen); + if ( i>=chars->next ) chars->next = i+1; + } else if ( !fp->alreadycomplained ) { + fprintf( stderr, "Index too big (must be <%d) |%s", chars->cnt, rmbinary(line)); + fp->alreadycomplained = true; + } + } else if ( !fp->alreadycomplained ) { + fprintf( stderr, "Didn't understand |%s", rmbinary(line) ); + fp->alreadycomplained = true; + } + } else if ( fp->inchars ) { + struct pschars *chars = fp->fd->chars; + if ( *tok=='\0' ) + fprintf( stderr, "No name for CharStrings dictionary |%s", rmbinary(line) ); + else if ( fp->ignore ) + /* Do Nothing */; + else if ( chars->next>=chars->cnt ) + fprintf( stderr, "Too many entries in CharStrings dictionary |%s", rmbinary(line) ); + else { + int i = chars->next; + chars->lens[i] = binlen; + chars->keys[i] = strdup(tok); + chars->values[i] = malloc(binlen); + memcpy(chars->values[i],binstart,binlen); + ++chars->next; + } + } else if ( !fp->alreadycomplained ) { + /* Special hacks for known badly formatted fonts */ + if ( strstr(line,"/CharStrings")!=NULL ) { + for ( pt=line; *pt!='/'; ++pt ); + pt = strchr(pt+1,'/'); + if ( pt!=NULL ) + *pt = '\0'; + parseline(fp,line,in); + if ( pt!=NULL ) { + *pt = '/'; + line = pt; + goto retry; + } +return; + } else if ( strstr(line,"/Subrs")!=NULL ) { + pt = strstr(line,"dup"); + if ( pt!=NULL ) + *pt = '\0'; + parseline(fp,line,in); + if ( pt!=NULL ) { + *pt = 'd'; + line = pt; + goto retry; + } +return; + } + fprintf( stderr, "Shouldn't be in addinfo |%s", rmbinary(line) ); + fp->alreadycomplained = true; + } +} + +/* In the book the token which starts a character description is always RD but*/ +/* it's just the name of a subroutine which is defined in the private diction*/ +/* and it could be anything. in one case it was "-|" (hyphen bar) so we can't*/ +/* just look for RD we must be a bit smarter and figure out what the token is*/ +/* (oh. I see now. it's allowed to be either one "RD" or "-|", but nothing else*/ +/* right) */ +/* It's defined as {string currentfile exch readstring pop} so look for that */ +/* Except that in gsf files we've also got "/-!{string currentfile exch readhexstring pop} readonly def" */ +/* NOTE: readhexstring!!! */ +/* And in files generated by GNU fontutils */ +static int glorpline(struct fontparse *fp, FILE *temp, char *rdtok) { + static char *buffer=NULL, *end; + char *pt, *binstart; + int binlen; + int ch; + int innum, val=0, inbinary, cnt=0, inr, wasspace, nownum, nowr, nowspace, sptok; + char *rdline = "{string currentfile exch readstring pop}", *rpt; + char *rdline2 = "{string currentfile exch readhexstring pop}"; + char *tokpt = NULL, *rdpt; + char temptok[255]; + int intok, first; + int wasminus=false, isminus, nibble, firstnibble, inhex; + int willbehex = false; + + ch = getc(temp); + if ( ch==EOF ) +return( 0 ); + ungetc(ch,temp); + + if ( buffer==NULL ) { + buffer = malloc(3000); + end = buffer+3000; + } + innum = inr = 0; wasspace = 0; inbinary = 0; rpt = NULL; rdpt = NULL; + inhex = 0; + pt = buffer; binstart=NULL; binlen = 0; intok=0; sptok=0; first=1; + temptok[0] = '\0'; + while ( (ch=getc(temp))!=EOF ) { + if ( pt>=end ) { + char *old = buffer; + int len = (end-buffer)+2000; + buffer = realloc(buffer,len); + end = buffer+len; + pt = buffer+(pt-old); + if ( binstart!=NULL ) + binstart = buffer+(binstart-old); + } + *pt++ = ch; + isminus = ch=='-' && wasspace; + nownum = nowspace = nowr = 0; + if ( rpt!=NULL && ch!=*rpt && ch=='h' && rpt-rdline>25 && rpt-rdline<30 && + rdline2[rpt-rdline]=='h' ) { + rpt = rdline2 + (rpt-rdline); + willbehex = true; + } + if ( inbinary ) { + if ( --cnt==0 ) + inbinary = 0; + } else if ( inhex ) { + if ( isxdigit(ch)) { + int h; + if ( isdigit(ch)) h = ch-'0'; + else if ( ch>='a' && ch<='f' ) h = ch-'a'+10; + else h = ch-'A'+10; + if ( firstnibble ) { + nibble = h; + --pt; + } else { + pt[-1] = (nibble<<4)|h; + if ( --cnt==0 ) + inbinary = inhex = 0; + } + firstnibble = !firstnibble; + } else { + --pt; + /* skip everything not hex */ + } + } else if ( ch=='/' ) { + intok = 1; + tokpt = temptok; + } else if ( intok && !isspace(ch) && ch!='{' && ch!='[' ) { + *tokpt++ = ch; + } else if ( (intok||sptok) && (ch=='{' || ch=='[')) { + *tokpt = '\0'; + rpt = rdline+1; + intok = sptok = 0; + } else if ( intok ) { + *tokpt = '\0'; + intok = 0; + sptok = 1; + } else if ( sptok && isspace(ch)) { + nowspace = 1; + if ( ch=='\n' || ch=='\r' ) + break; + } else if ( sptok && !isdigit(ch)) + sptok = 0; + else if ( rpt!=NULL && ch==*rpt ) { + if ( *++rpt=='\0' ) { + /* it matched the character definition string so this is the */ + /* token we want to search for */ + strcpy(rdtok,temptok); + fp->useshexstrings = willbehex; + rpt = NULL; + } + } else if ( rpt!=NULL && ch==' ' ) { + /* Extra spaces are ok */ + } else if ( rpt!=NULL ) { + rpt = NULL; + willbehex = false; + } else if ( isdigit(ch)) { + sptok = 0; + nownum = 1; + if ( innum ) + val = 10*val + ch-'0'; + else + val = ch-'0'; + } else if ( isspace(ch)) { + nowspace = 1; + if ( ch=='\n' || ch=='\r' ) + break; + } else if ( wasspace && ch==*rdtok ) { + nowr = 1; + fp->useshexstrings = willbehex; + rdpt = rdtok+1; + } else if ( wasspace && ch=='-' ) { /* fonts produced by type1fix seem to define both "RD" and "-|" which confused me. so just respond to either */ + nowr = 1; + fp->useshexstrings = false; + rdpt = "|"; + } else if ( wasspace && ch=='R' ) { /* fonts produced by type1fix seem to define both "RD" and "-|" which confused me. so just respond to either */ + nowr = 1; + fp->useshexstrings = false; + rdpt = "D"; + } else if ( inr && ch==*rdpt ) { + if ( *++rdpt =='\0' ) { + ch = getc(temp); + *pt++ = ch; + if ( isspace(ch) && val!=0 ) { + inhex = fp->useshexstrings; + inbinary = !fp->useshexstrings; + firstnibble = true; + cnt = val; + binstart = pt; + binlen = val; + } + } else + nowr = 1; + } else if ( wasminus && ch=='!' ) { + ch = getc(temp); + *pt++ = ch; + if ( isspace(ch) && val!=0 ) { + inhex = 1; + cnt = val; + binstart = pt; + binlen = val; + firstnibble = true; + } + } + innum = nownum; wasspace = nowspace; inr = nowr; + wasminus = isminus; + first = 0; + } + *pt = '\0'; + if ( binstart==NULL ) { + parseline(fp,buffer,temp); + } else { + addinfo(fp,buffer,temptok,binstart,binlen,temp); + } +return( 1 ); +} + +static int nrandombytes[4]; +#define EODMARKLEN 16 + +#define bgetc(extra,in) (*(extra)=='\0' ? getc(in) : (unsigned char ) *(extra)++ ) + +static void decrypteexec(FILE *in,FILE *temp, int hassectionheads,char *extra) { + int ch1, ch2, ch3, ch4, binary; + int zcnt; + unsigned char zeros[EODMARKLEN+6+1]; + int sect_len; + + if ( extra==(void *) 5 ) extra = ""; + + while ( (ch1=bgetc(extra,in))!=EOF && isspace(ch1)); + if ( ch1==0200 && hassectionheads ) { + /* skip the 6 byte section header in pfb files that follows eexec */ + ch1 = bgetc(extra,in); + sect_len = bgetc(extra,in); + sect_len |= bgetc(extra,in)<<8; + sect_len |= bgetc(extra,in)<<16; + sect_len |= bgetc(extra,in)<<24; + sect_len -= 3; + ch1 = bgetc(extra,in); + } + ch2 = bgetc(extra,in); ch3 = bgetc(extra,in); ch4 = bgetc(extra,in); + binary = 0; + if ( ch1<'0' || (ch1>'9' && ch1<'A') || ( ch1>'F' && ch1<'a') || (ch1>'f') || + ch2<'0' || (ch2>'9' && ch2<'A') || (ch2>'F' && ch2<'a') || (ch2>'f') || + ch3<'0' || (ch3>'9' && ch3<'A') || (ch3>'F' && ch3<'a') || (ch3>'f') || + ch4<'0' || (ch4>'9' && ch4<'A') || (ch4>'F' && ch4<'a') || (ch4>'f') ) + binary = 1; + if ( ch1==EOF || ch2==EOF || ch3==EOF || ch4==EOF ) { +return; + } + + initcode(); + if ( binary ) { + nrandombytes[0] = decode(ch1); + nrandombytes[1] = decode(ch2); + nrandombytes[2] = decode(ch3); + nrandombytes[3] = decode(ch4); + zcnt = 0; + while (( ch1=bgetc(extra,in))!=EOF ) { + --sect_len; + if ( hassectionheads ) { + if ( sect_len==0 && ch1==0200 ) { + ch1 = bgetc(extra,in); + sect_len = bgetc(extra,in); + sect_len |= bgetc(extra,in)<<8; + sect_len |= bgetc(extra,in)<<16; + sect_len |= bgetc(extra,in)<<24; + sect_len += 1; + if ( ch1=='\1' ) + break; + } else { + dumpzeros(temp,zeros,zcnt); + zcnt = 0; + putc(decode(ch1),temp); + } + } else { + if ( ch1=='0' ) ++zcnt; else {dumpzeros(temp,zeros,zcnt); zcnt = 0; } + if ( zcnt>EODMARKLEN ) + break; + if ( zcnt==0 ) + putc(decode(ch1),temp); + else + zeros[zcnt-1] = decode(ch1); + } + } + } else { + nrandombytes[0] = decode(hex(ch1,ch2)); + nrandombytes[1] = decode(hex(ch3,ch4)); + ch1 = bgetc(extra,in); ch2 = bgetc(extra,in); ch3 = bgetc(extra,in); ch4 = bgetc(extra,in); + nrandombytes[2] = decode(hex(ch1,ch2)); + nrandombytes[3] = decode(hex(ch3,ch4)); + zcnt = 0; + while (( ch1=bgetc(extra,in))!=EOF ) { + while ( ch1!=EOF && isspace(ch1)) ch1 = bgetc(extra,in); + while ( (ch2=bgetc(extra,in))!=EOF && isspace(ch2)); + if ( ch1=='0' && ch2=='0' ) ++zcnt; else { dumpzeros(temp,zeros,zcnt); zcnt = 0;} + if ( zcnt>EODMARKLEN ) + break; + if ( zcnt==0 ) + putc(decode(hex(ch1,ch2)),temp); + else + zeros[zcnt-1] = decode(hex(ch1,ch2)); + } + } + while (( ch1=bgetc(extra,in))=='0' || isspace(ch1) ); + if ( ch1!=EOF ) ungetc(ch1,in); +} + +static void decryptagain(struct fontparse *fp,FILE *temp,char *rdtok) { + while ( glorpline(fp,temp,rdtok)); +} + +static void parsetype3(struct fontparse *fp,FILE *in) { + /*PSFontInterpretPS(in,fp->fd->charprocs);*/ +} + +static unsigned char *readt1str(FILE *temp,int offset,int len,int leniv) { + int i; + unsigned char *str, *pt; + unsigned short r = 4330; + unsigned char plain, cypher; + /* The CID spec doesn't mention this, but the type 1 strings are all */ + /* eexec encrupted (with the nested encryption). Remember leniv varies */ + /* from fd to fd (potentially) */ + /* I'm told (by Ian Kemmish) that leniv==-1 => no eexec encryption */ + + fseek(temp,offset,SEEK_SET); + if ( leniv<0 ) { + str = pt = malloc(len+1); + for (; i<len; ++i ) + *pt++ = getc(temp); + } else { + for ( i=0; i<leniv; ++i ) { + cypher = getc(temp); + plain = ( cypher ^ (r>>8)); + r = (cypher + r) * c1 + c2; + } + str = pt = malloc(len-leniv+1); + for (; i<len; ++i ) { + cypher = getc(temp); + plain = ( cypher ^ (r>>8)); + r = (cypher + r) * c1 + c2; + *pt++ = plain; + } + } + *pt = '\0'; +return( str ); +} + +static void figurecids(struct fontparse *fp,FILE *temp) { + struct fontdict *fd = fp->mainfd; + int i,j,k,val; + int *offsets; + int cidcnt = fd->cidcnt; + int leniv; + /* Some cid formats don't have any of these */ + + fd->cidstrs = malloc(cidcnt*sizeof(unsigned char *)); + fd->cidlens = malloc(cidcnt*sizeof(short)); + fd->cidfds = malloc((cidcnt+1)*sizeof(short)); + offsets = malloc((cidcnt+1)*sizeof(int)); + + fseek(temp,fd->mapoffset,SEEK_SET); + for ( i=0; i<=fd->cidcnt; ++i ) { + for ( j=val=0; j<fd->fdbytes; ++j ) + val = (val<<8) + getc(temp); + fd->cidfds[i] = val; + for ( j=val=0; j<fd->gdbytes; ++j ) + val = (val<<8) + getc(temp); + offsets[i] = val; + if ( i!=0 ) + fd->cidlens[i-1] = offsets[i]-offsets[i-1]; + } + + for ( i=0; i<fd->cidcnt; ++i ) { + if ( fd->cidlens[i]== 0 ) + fd->cidstrs[i] = NULL; + else { + fd->cidstrs[i] = readt1str(temp,offsets[i],fd->cidlens[i], + fd->fds[fd->cidfds[i]]->private->leniv); + fd->cidlens[i] -= fd->fds[fd->cidfds[i]]->private->leniv; + } + } + free(offsets); + + for ( k=0; k<fd->fdcnt; ++k ) { + struct private *private = fd->fds[k]->private; + char *ssubroff = PSDictHasEntry(private->private,"SubrMapOffset"); + char *ssdbytes = PSDictHasEntry(private->private,"SDBytes"); + char *ssubrcnt = PSDictHasEntry(private->private,"SubrCount"); + int subroff, sdbytes, subrcnt; + + if ( ssubroff!=NULL && ssdbytes!=NULL && ssubrcnt!=NULL && + (subroff=strtol(ssubroff,NULL,10))>=0 && + (sdbytes=strtol(ssdbytes,NULL,10))>0 && + (subrcnt=strtol(ssubrcnt,NULL,10))>0 ) { + private->subrs->cnt = subrcnt; + private->subrs->values = calloc(subrcnt,sizeof(char *)); + private->subrs->lens = calloc(subrcnt,sizeof(int)); + leniv = private->leniv; + offsets = malloc((subrcnt+1)*sizeof(int)); + fseek(temp,subroff,SEEK_SET); + for ( i=0; i<=subrcnt; ++i ) { + for ( j=val=0; j<sdbytes; ++j ) + val = (val<<8) + getc(temp); + offsets[i] = val; + if ( i!=0 ) + private->subrs->lens[i-1] = offsets[i]-offsets[i-1]; + } + for ( i=0; i<subrcnt; ++i ) { + private->subrs->values[i] = readt1str(temp,offsets[i], + private->subrs->lens[i],leniv); + } + private->subrs->next = i; + free(offsets); + } + PSDictRemoveEntry(private->private,"SubrMapOffset"); + PSDictRemoveEntry(private->private,"SDBytes"); + PSDictRemoveEntry(private->private,"SubrCount"); + } +} + +static void dodata( struct fontparse *fp, FILE *in, FILE *temp) { + int binary, cnt, len; + int ch, ch2; + char *pt; + char fontsetname[256]; + + while ( (ch=getc(in))!='(' && ch!='/' && ch!=EOF ); + if ( ch=='/' ) { + /* There appears to be no provision for a hex encoding here */ + /* Why can't they use the same format for routines with the same name? */ + binary = true; + for ( pt=fontsetname; (ch=getc(in))!=' ' && ch!=EOF; ) + if ( pt<fontsetname+sizeof(fontsetname)-1 ) + *pt++= ch; + *pt = '\0'; + } else { + if ( (ch=getc(in))=='B' || ch=='b' ) binary = true; + else if ( ch=='H' || ch=='h' ) binary = false; + else { + binary = true; /* Who knows? */ + fprintf( stderr, "Failed to parse the StartData command properly\n" ); + } + fontsetname[0] = '\0'; + } + while ( (ch=getc(in))!=')' && ch!=EOF ); + if ( fscanf( in, "%d", &len )!=1 || len<=0 ) { + len = 0; + fprintf( stderr, "Failed to parse the StartData command properly, bad cnt\n" ); + } + cnt = len; + while ( isspace(ch=getc(in)) ); + ungetc(ch,in); + for ( pt="StartData "; *pt; ++pt ) + getc(in); /* And if it didn't match, what could I do about it? */ + if ( binary ) { + while ( cnt>0 ) { + ch = getc(in); + putc(ch,temp); + --cnt; + } + } else { + while ( cnt>0 ) { + /* Hex data are allowed to contain whitespace */ + while ( isspace(ch=getc(in)) ); + while ( isspace(ch2=getc(in)) ); + ch = hex(ch,ch2); + putc(ch,temp); + --cnt; + } + if ( (ch=getc(in))!='>' ) ungetc(ch,in); + } + rewind(temp); + if ( fp->iscid ) + figurecids(fp,temp); + else { + /*fp->fd->sf = _CFFParse(temp,len,fontsetname);*/ + fp->fd->wascff = true; + } +} + +static void doubledecrypt(struct fontparse *fp,FILE *in, FILE *temp) { + char buffer[256]; + int first, hassectionheads; + char rdtok[20]; + int saw_blend = false; + + strcpy(rdtok,"RD"); + + first = 1; hassectionheads = 0; + while ( myfgets(buffer,sizeof(buffer),in)!=NULL ) { + if ( strstr(buffer, "Blend")!=NULL ) + saw_blend = true; + if ( first && buffer[0]=='\200' ) { + hassectionheads = 1; + fp->fd->wasbinary = true; + parseline(fp,buffer+6,in); + } else if ( strstr(buffer,"CharProcs")!=NULL && strstr(buffer,"begin")!=NULL ) { + parsetype3(fp,in); +return; + } else if ( !fp->iscid ) { + if ( saw_blend ) + parseline(fp,buffer,in); + /* But if it's a multi master font, don't do the special private hack */ + else if ( strstr(buffer,"/CharStrings")!=NULL && strstr(buffer,"begin")!=NULL ) { + /* gsf files are not eexec encoded, but the charstrings are encoded*/ + InitChars(fp->fd->chars,buffer); + fp->inchars = 1; + decryptagain(fp,in,rdtok); +return; + } else if ( strstr(buffer,"/Subrs")!=NULL && strstr(buffer,"array")!=NULL ) { + /* Same case as above */ + InitChars(fp->fd->private->subrs,buffer); + fp->insubs = 1; + decryptagain(fp,in,rdtok); +return; + } else if ( strstr(buffer,"/Private")!=NULL && strstr(buffer,"dict")!=NULL ) { + /* files produced by GNU fontutils have some of the same issues */ + fp->inprivate = 1; + fp->infi = false; + decryptagain(fp,in,rdtok); +return; + } else + parseline(fp,buffer,in); + } else + parseline(fp,buffer,in); + first = 0; + if ( strstr(buffer,"%%BeginData: ")!=NULL ) + break; + if ( strstr(buffer,"currentfile")!=NULL && strstr(buffer, "eexec")!=NULL ) { + fp->skipping_mbf = false; + break; + } + } + + if ( strstr(buffer,"%%BeginData: ")!=NULL ) { + /* used by both CID fonts and CFF fonts (and chameleons, whatever they are) */ + dodata(fp,in,temp); + } else { + decrypteexec(in,temp,hassectionheads,strstr(buffer, "eexec")+5); + rewind(temp); + decryptagain(fp,temp,rdtok); + while ( myfgets(buffer,sizeof(buffer),in)!=NULL ) { + if ( buffer[0]!='\200' || !hassectionheads ) + parseline(fp,buffer,in); + } + } +} + +static FontDict *_ReadPSFont(FILE *in) { + FILE *temp; + struct fontparse fp; + char *oldloc; + + temp = tmpfile(); + if ( temp==NULL ) { + fprintf( stderr, "Cannot open a temporary file\n" ); + fclose(in); +return(NULL); + } + + oldloc = setlocale(LC_NUMERIC,"C"); + memset(&fp,'\0',sizeof(fp)); + fp.fd = fp.mainfd = PSMakeEmptyFont(); + fp.fdindex = -1; + doubledecrypt(&fp,in,temp); + free(fp.vbuf); + setlocale(LC_NUMERIC,oldloc); + + fclose(temp); +return( fp.fd ); +} + + +static void PSCharsFree(struct pschars *chrs) { + int i; + + if ( chrs==NULL ) +return; + for ( i=0; i<chrs->next; ++i ) { + if ( chrs->keys!=NULL ) free(chrs->keys[i]); + free(chrs->values[i]); + } + free(chrs->lens); + free(chrs->keys); + free(chrs->values); + free(chrs); +} + +static void PSDictFree(struct psdict *dict) { + int i; + + if ( dict==NULL ) +return; + for ( i=0; i<dict->next; ++i ) { + if ( dict->keys!=NULL ) free(dict->keys[i]); + free(dict->values[i]); + } + free(dict->keys); + free(dict->values); + free(dict); +} + +static void PrivateFree(struct private *prv) { + PSCharsFree(prv->subrs); +#if 1 + PSDictFree(prv->private); +#else + PSCharsFree(prv->othersubrs); + free(prv->minfeature); + free(prv->nd); + free(prv->np); + free(prv->rd); +#endif + free(prv); +} + +static void FontInfoFree(struct fontinfo *fi) { + free(fi->familyname); + free(fi->fullname); + free(fi->notice); + free(fi->weight); + free(fi->version); + free(fi->blenddesignpositions); + free(fi->blenddesignmap); + free(fi->blendaxistypes); + free(fi); +} + +static void PSFontFree(FontDict *fd) { + int i; + + if ( fd->encoding!=NULL ) + for ( i=0; i<256; ++i ) + free( fd->encoding[i]); + free(fd->fontname); + free(fd->cidfontname); + free(fd->registry); + free(fd->ordering); + FontInfoFree(fd->fontinfo); + PSCharsFree(fd->chars); + PrivateFree(fd->private); + if ( fd->charprocs!=NULL ) { + for ( i=0; i<fd->charprocs->cnt; ++i ) + free(fd->charprocs->keys[i]); + free(fd->charprocs->keys); + free(fd->charprocs->values); + free(fd->charprocs); + } + if ( fd->cidstrs!=NULL ) { + for ( i=0; i<fd->cidcnt; ++i ) + free( fd->cidstrs[i]); + free(fd->cidstrs); + } + free(fd->cidlens); + free(fd->cidfds); + if ( fd->fds!=NULL ) { + for ( i=0; i<fd->fdcnt; ++i ) + PSFontFree(fd->fds[i]); + free(fd->fds); + } + free(fd->blendfunc); + free(fd->weightvector); + free(fd->cdv); + free(fd->ndv); + + PSDictFree(fd->blendprivate); + PSDictFree(fd->blendfontinfo); + + free(fd); +} + +static struct bbglyph *FindAdobeGlyph(PSFONT *psfont,int adobe_enc) { + char *search_name; + struct pschars *chars = psfont->temp; + int i; + + if ( adobe_enc>=256 || adobe_enc<0 ) +return( &psfont->glyphs[0] ); /* Return .notdef */ + search_name = AdobeStandardEncoding[adobe_enc]; + for ( i=0; i<chars->cnt; ++i ) { + if ( strcmp(search_name,chars->keys[i])==0 ) { + if ( psfont->glyphs[i].isref ) +return( NULL ); + +return( &psfont->glyphs[i] ); + } + } + + for ( i=0; i<chars->cnt; ++i ) { + if ( strcmp(".notdef",chars->keys[i])==0 ) +return( &psfont->glyphs[i] ); + } + +return( &psfont->glyphs[0] ); /* Return something. font doesn't even have notdef */ +} + +static void FindBB(PSFONT *psfont, struct bbglyph *bb, unsigned char *type1, int len, + struct pschars *subrs, char *name ) { + double stack[50]; int sp=0, v; /* Type1 stack is about 25 long, Type2 stack is 48 */ + double transient[32]; + struct { double x,y; } current; + double dx, dy, dx2, dy2, dx3, dy3; + /* subroutines may be nested to a depth of 10 */ + struct substate { unsigned char *type1; int len; int subnum; } pcstack[11]; + int pcsp=0; + double pops[30]; + int popsp=0; + int base, polarity; + struct pschars *s; + int first = true; + int lsidebearing; + struct bbglyph *bb1, *bb2; + int offx, offy; + + current.x = current.y = 0; + while ( len>0 ) { + if ( sp>48 ) { + fprintf( stderr, "Stack got too big in %s\n", name ); + sp = 48; + } + base = 0; + --len; + if ( (v = *type1++)>=32 ) { + if ( v<=246) { + stack[sp++] = v - 139; + } else if ( v<=250 ) { + stack[sp++] = (v-247)*256 + *type1++ + 108; + --len; + } else if ( v<=254 ) { + stack[sp++] = -(v-251)*256 - *type1++ - 108; + --len; + } else { + int val = (*type1<<24) | (type1[1]<<16) | (type1[2]<<8) | type1[3]; + stack[sp++] = val; + type1 += 4; + len -= 4; + } + } else if ( v==28 ) { + stack[sp++] = (short) ((type1[0]<<8) | type1[1]); + type1 += 2; + len -= 2; + /* In the Dict tables of CFF, a 5byte fixed value is prefixed by a */ + /* 29 code. In Type2 strings the prefix is 255. */ + } else if ( v==12 ) { + v = *type1++; + --len; + switch ( v ) { + case 0: /* dotsection */ + sp = 0; + break; + case 1: /* vstem3 */ /* specifies three v hints zones at once */ + if ( sp<6 ) fprintf(stderr, "Stack underflow on vstem3 in %s\n", name ); + /* according to the standard, if there is a vstem3 there can't */ + /* be any vstems, so there can't be any confusion about hint order */ + /* so we don't need to worry about unblended stuff */ + sp = 0; + break; + case 2: /* hstem3 */ /* specifies three h hints zones at once */ + if ( sp<6 ) fprintf(stderr, "Stack underflow on hstem3 in %s\n", name ); + sp = 0; + break; + case 6: /* seac */ /* build accented characters */ + seac: + if ( sp<5 ) fprintf(stderr, "Stack underflow on seac in %s\n", name ); + /* stack[0] must be the lsidebearing of the accent. I'm not sure why */ + bb1 = FindAdobeGlyph(psfont,stack[3]); + bb2 = FindAdobeGlyph(psfont,stack[4]); + offx = stack[1] - (stack[0]-lsidebearing); + offy = stack[2]; + if ( bb1==NULL || bb2==NULL ) + bb->isref = true; + else { + bb->top = bb1->top > bb2->top+offy ? bb1->top : bb2->top+offy; + bb->bottom = bb1->bottom < bb2->bottom+offy ? bb1->bottom : bb2->bottom+offy; + bb->right = bb1->right > bb2->right+offx ? bb1->right : bb2->right+offx; + bb->left = bb1->left < bb2->left+offx ? bb1->left : bb2->left+offx; + } + sp = 0; + break; + case 7: /* sbw */ /* generalized width/sidebearing command */ + if ( sp<4 ) fprintf(stderr, "Stack underflow on sbw in %s\n", name ); + lsidebearing = stack[0]; + /* stack[1] is lsidebearing y (only for vertical writing styles, CJK) */ + bb->hadvance = stack[2]; + /* stack[3] is height (for vertical writing styles, CJK) */ + sp = 0; + break; + case 5: case 9: case 14: case 26: + if ( sp<1 ) fprintf(stderr, "Stack underflow on unary operator in %s\n", name ); + switch ( v ) { + case 5: stack[sp-1] = (stack[sp-1]==0); break; /* not */ + case 9: if ( stack[sp-1]<0 ) stack[sp-1]= -stack[sp-1]; break; /* abs */ + case 14: stack[sp-1] = -stack[sp-1]; break; /* neg */ + case 26: stack[sp-1] = sqrt(stack[sp-1]); break; /* sqrt */ + } + break; + case 3: case 4: case 10: case 11: case 12: case 15: case 24: + if ( sp<2 ) fprintf(stderr, "Stack underflow on binary operator in %s\n", name ); + else switch ( v ) { + case 3: /* and */ + stack[sp-2] = (stack[sp-1]!=0 && stack[sp-2]!=0); + break; + case 4: /* and */ + stack[sp-2] = (stack[sp-1]!=0 || stack[sp-2]!=0); + break; + case 10: /* add */ + stack[sp-2] += stack[sp-1]; + break; + case 11: /* sub */ + stack[sp-2] -= stack[sp-1]; + break; + case 12: /* div */ + stack[sp-2] /= stack[sp-1]; + break; + case 24: /* mul */ + stack[sp-2] *= stack[sp-1]; + break; + case 15: /* eq */ + stack[sp-2] = (stack[sp-1]==stack[sp-2]); + break; + } + --sp; + break; + case 22: /* ifelse */ + if ( sp<4 ) fprintf(stderr, "Stack underflow on ifelse in %s\n", name ); + else { + if ( stack[sp-2]>stack[sp-1] ) + stack[sp-4] = stack[sp-3]; + sp -= 3; + } + break; + case 23: /* random */ + /* This function returns something (0,1]. It's not clear to me*/ + /* if rand includes 0 and RAND_MAX or not, but this approach */ + /* should work no matter what */ + do { + stack[sp] = (rand()/(RAND_MAX-1)); + } while ( stack[sp]==0 || stack[sp]>1 ); + ++sp; + break; + case 16: /* callothersubr */ + /* stack[sp-1] is the number of the thing to call in the othersubr array */ + /* stack[sp-2] is the number of args to grab off our stack and put on the */ + /* double postscript stack */ + if ( sp<2 || sp < 2+stack[sp-2] ) { + fprintf(stderr, "Stack underflow on callothersubr in %s\n", name ); + sp = 0; + } else { + int tot = stack[sp-2], k; + popsp = 0; + for ( k=sp-3; k>=sp-2-tot; --k ) + pops[popsp++] = stack[k]; + /* othersubrs 0-3 must be interpretted. 0-2 are Flex, 3 is Hint Replacement */ + /* othersubrs 12,13 are for counter hints. We don't need to */ + /* do anything to ignore them */ + /* Subroutines 14-18 are multiple master blenders. We need */ + /* to pay attention to them too */ + switch ( (int) stack[sp-1] ) { + case 3: { + /* when we weren't capabable of hint replacement we */ + /* punted by putting 3 on the stack (T1 spec page 70) */ + /* subroutine 3 is a noop */ + pops[popsp-1] = 3; + } break; + case 1: { /* Flex */ + } break; + case 2: { + /* No op */; + } break; + case 0: + break; + } + sp = k+1; + } + break; + case 20: /* put */ + if ( sp<2 ) fprintf(stderr, "Too few items on stack for put in %s\n", name ); + else if ( stack[sp-1]<0 || stack[sp-1]>=32 ) fprintf(stderr,"Reference to transient memory out of bounds in put in %s\n", name ); + else { + transient[(int)stack[sp-1]] = stack[sp-2]; + sp -= 2; + } + break; + case 21: /* get */ + if ( sp<1 ) fprintf(stderr, "Too few items on stack for get in %s\n", name ); + else if ( stack[sp-1]<0 || stack[sp-1]>=32 ) fprintf(stderr,"Reference to transient memory out of bounds in put in %s\n", name ); + else + stack[sp-1] = transient[(int)stack[sp-1]]; + break; + case 17: /* pop */ + /* pops something from the postscript stack and pushes it on ours */ + /* used to get a return value from an othersubr call */ + /* Bleah. Adobe wants the pops to return the arguments if we */ + /* don't understand the call. What use is the subroutine then?*/ + if ( popsp<=0 ) + fprintf(stderr, "Pop stack underflow on pop in %s\n", name ); + else + stack[sp++] = pops[--popsp]; + break; + case 18: /* drop */ + if ( sp>0 ) --sp; + break; + case 27: /* dup */ + if ( sp>=1 ) { + stack[sp] = stack[sp-1]; + ++sp; + } + break; + case 28: /* exch */ + if ( sp>=2 ) { + double temp = stack[sp-1]; + stack[sp-1] = stack[sp-2]; stack[sp-2] = temp; + } + break; + case 29: /* index */ + if ( sp>=1 ) { + int index = stack[--sp]; + if ( index<0 || sp<index+1 ) + fprintf( stderr, "Index out of range in %s\n", name ); + else { + stack[sp] = stack[sp-index-1]; + ++sp; + } + } + break; + case 30: /* roll */ + if ( sp>=2 ) { + int j = stack[sp-1], N=stack[sp-2]; + if ( N>sp || j>=N || j<0 || N<0 ) + fprintf( stderr, "roll out of range in %s\n", name ); + else if ( j==0 || N==0 ) + /* No op */; + else { + double *temp = malloc(N*sizeof(double)); + int i; + for ( i=0; i<N; ++i ) + temp[i] = stack[sp-N+i]; + for ( i=0; i<N; ++i ) + stack[sp-N+i] = temp[(i+j)%N]; + free(temp); + } + } + break; + case 33: /* setcurrentpoint */ + if ( sp<2 ) fprintf(stderr, "Stack underflow on setcurrentpoint in %s\n", name ); + else { + current.x = stack[0]; + current.y = stack[1]; + if ( current.y>bb->top ) bb->top = current.y; + if ( current.y<bb->bottom ) bb->bottom = current.y; + if ( current.x>bb->right ) bb->right = current.x; + if ( current.x<bb->left ) bb->left = current.x; + } + sp = 0; + break; + case 34: /* hflex */ + case 35: /* flex */ + case 36: /* hflex1 */ + case 37: /* flex1 */ + sp = 0; + break; + default: + fprintf( stderr, "Uninterpreted opcode 12,%d in %s\n", v, name ); + break; + } + } else switch ( v ) { + case 1: /* hstem */ + case 18: /* hstemhm */ + base = 0; + if ( sp&1 ) { + bb->hadvance = stack[0]; + base=1; + } + if ( sp-base<2 ) + fprintf(stderr, "Stack underflow on hstem in %s\n", name ); + /* stack[0] is absolute y for start of horizontal hint */ + /* (actually relative to the y specified as lsidebearing y in sbw*/ + /* stack[1] is relative y for height of hint zone */ + sp = 0; + break; + case 19: /* hintmask */ + case 20: /* cntrmask */ + /* If there's anything on the stack treat it as a vstem hint */ + base = 0; + case 3: /* vstem */ + case 23: /* vstemhm */ + break; + case 14: /* endchar */ + /* endchar is allowed to terminate processing even within a subroutine */ + pcsp = 0; + if ( sp==4 ) { + /* In Type2 strings endchar has a depreciated function of doing */ + /* a seac (which doesn't exist at all). Except enchar takes */ + /* 4 args and seac takes 5. Bleah */ + stack[4] = stack[3]; stack[3] = stack[2]; stack[2] = stack[1]; stack[1] = stack[0]; + stack[0] = 0; + sp = 5; + goto seac; + } + /* the docs say that endchar must be the last command in a char */ + /* (or the last command in a subroutine which is the last in the */ + /* char) So in theory if there's anything left we should complain*/ + /* In practice though, the EuroFont has a return statement after */ + /* the endchar in a subroutine. So we won't try to catch that err*/ + /* and just stop. */ + /* Adobe says it's not an error, but I can't understand their */ + /* logic */ + goto done; + break; + case 13: /* hsbw (set left sidebearing and width) */ + if ( sp<2 ) fprintf(stderr, "Stack underflow on hsbw in %s\n", name ); + lsidebearing = stack[0]; + current.x = stack[0]; /* sets the current point too */ + bb->hadvance = stack[1]; + sp = 0; + break; + case 9: /* closepath */ + sp = 0; + break; + case 21: /* rmoveto */ + case 22: /* hmoveto */ + case 4: /* vmoveto */ + case 5: /* rlineto */ + case 6: /* hlineto */ + case 7: /* vlineto */ + polarity = 0; + base = 0; + while ( base<sp ) { + dx = dy = 0; + if ( v==5 || v==21 ) { + if ( sp<2 ) fprintf(stderr, "Stack underflow on rlineto/rmoveto in %s\n", name ); + dx = stack[base++]; + dy = stack[base++]; + } else if ( (v==6 && !(polarity&1)) || (v==7 && (polarity&1)) || v==22 ) { + if ( sp<1 ) fprintf(stderr, "Stack underflow on hlineto/hmoveto in %s\n", name ); + dx = stack[base++]; + } else /*if ( (v==7 && !(parity&1)) || (v==6 && (parity&1) || v==4 )*/ { + if ( sp<1 ) fprintf(stderr, "Stack underflow on vlineto/vmoveto in %s\n", name ); + dy = stack[base++]; + } + ++polarity; + current.x += dx; current.y += dy; + if ( first ) { + bb->top = bb->bottom = current.y; + bb->left = bb->right = current.x; + first = false; + } else { + if ( current.y>bb->top ) bb->top = current.y; + if ( current.y<bb->bottom ) bb->bottom = current.y; + if ( current.x>bb->right ) bb->right = current.x; + if ( current.x<bb->left ) bb->left = current.x; + } + } + sp = 0; + break; + case 25: /* rlinecurve */ + base = 0; + while ( sp>base+6 ) { + current.x += stack[base++]; current.y += stack[base++]; + if ( current.y>bb->top ) bb->top = current.y; + if ( current.y<bb->bottom ) bb->bottom = current.y; + if ( current.x>bb->right ) bb->right = current.x; + if ( current.x<bb->left ) bb->left = current.x; + } + case 24: /* rcurveline */ + case 8: /* rrcurveto */ + case 31: /* hvcurveto */ + case 30: /* vhcurveto */ + case 27: /* hhcurveto */ + case 26: /* vvcurveto */ + polarity = 0; + while ( sp>base+2 ) { + dx = dy = dx2 = dy2 = dx3 = dy3 = 0; + if ( v==8 || v==25 || v==24 ) { + if ( sp<6+base ) { + fprintf(stderr, "Stack underflow on rrcurveto in %s\n", name ); + base = sp; + } else { + dx = stack[base++]; + dy = stack[base++]; + dx2 = stack[base++]; + dy2 = stack[base++]; + dx3 = stack[base++]; + dy3 = stack[base++]; + } + } else if ( v==27 ) { /* hhcurveto */ + if ( sp<4+base ) { + fprintf(stderr, "Stack underflow on hhcurveto in %s\n", name ); + base = sp; + } else { + if ( (sp-base)&1 ) dy = stack[base++]; + dx = stack[base++]; + dx2 = stack[base++]; + dy2 = stack[base++]; + dx3 = stack[base++]; + } + } else if ( v==26 ) { /* vvcurveto */ + if ( sp<4+base ) { + fprintf(stderr, "Stack underflow on hhcurveto in %s\n", name ); + base = sp; + } else { + if ( (sp-base)&1 ) dx = stack[base++]; + dy = stack[base++]; + dx2 = stack[base++]; + dy2 = stack[base++]; + dy3 = stack[base++]; + } + } else if ( (v==31 && !(polarity&1)) || (v==30 && (polarity&1)) ) { + if ( sp<4+base ) { + fprintf(stderr, "Stack underflow on hvcurveto in %s\n", name ); + base = sp; + } else { + dx = stack[base++]; + dx2 = stack[base++]; + dy2 = stack[base++]; + dy3 = stack[base++]; + if ( sp==base+1 ) + dx3 = stack[base++]; + } + } else /*if ( (v==30 && !(polarity&1)) || (v==31 && (polarity&1)) )*/ { + if ( sp<4+base ) { + fprintf(stderr, "Stack underflow on vhcurveto in %s\n", name ); + base = sp; + } else { + dy = stack[base++]; + dx2 = stack[base++]; + dy2 = stack[base++]; + dx3 = stack[base++]; + if ( sp==base+1 ) + dy3 = stack[base++]; + } + } + ++polarity; + current.x += dx; current.y += dy; + if ( current.y>bb->top ) bb->top = current.y; + if ( current.y<bb->bottom ) bb->bottom = current.y; + if ( current.x>bb->right ) bb->right = current.x; + if ( current.x<bb->left ) bb->left = current.x; + current.x += dx2; current.y += dy2; + if ( current.y>bb->top ) bb->top = current.y; + if ( current.y<bb->bottom ) bb->bottom = current.y; + if ( current.x>bb->right ) bb->right = current.x; + if ( current.x<bb->left ) bb->left = current.x; + current.x += dx3; current.y += dy3; + if ( current.y>bb->top ) bb->top = current.y; + if ( current.y<bb->bottom ) bb->bottom = current.y; + if ( current.x>bb->right ) bb->right = current.x; + if ( current.x<bb->left ) bb->left = current.x; + } + if ( v==24 ) { + current.x += stack[base++]; current.y += stack[base++]; + if ( current.y>bb->top ) bb->top = current.y; + if ( current.y<bb->bottom ) bb->bottom = current.y; + if ( current.x>bb->right ) bb->right = current.x; + if ( current.x<bb->left ) bb->left = current.x; + } + sp = 0; + break; + case 29: /* callgsubr */ + case 10: /* callsubr */ + /* stack[sp-1] contains the number of the subroutine to call */ + if ( sp<1 ) { + fprintf(stderr, "Stack underflow on callsubr in %s\n", name ); + break; + } else if ( pcsp>10 ) { + fprintf( stderr, "Too many subroutine calls in %s\n", name ); + break; + } + s=subrs; + if ( s==NULL || stack[sp-1]>=s->cnt || stack[sp-1]<0 || + s->values[(int) stack[sp-1]]==NULL ) + fprintf(stderr,"Subroutine number out of bounds in %s\n", name ); + else { + pcstack[pcsp].type1 = type1; + pcstack[pcsp].len = len; + pcstack[pcsp].subnum = stack[sp-1]; + ++pcsp; + type1 = s->values[(int) stack[sp-1]]; + len = s->lens[(int) stack[sp-1]]; + } + if ( --sp<0 ) sp = 0; + break; + case 11: /* return */ + /* return from a subr outine */ + if ( pcsp<1 ) fprintf(stderr, "return when not in subroutine in %s\n", name ); + else { + --pcsp; + type1 = pcstack[pcsp].type1; + len = pcstack[pcsp].len; + } + break; + default: + fprintf( stderr, "Uninterpreted opcode %d in %s\n", v, name ); + break; + } + } + done: + if ( pcsp!=0 ) + fprintf(stderr, "end of subroutine reached with no return in %s\n", name ); +} + + +void ParsePfb(FILE *pfb,PSFONT *psfont) { + FontDict *fd = _ReadPSFont(pfb); + char *pt; + int i,j, anyrefs, attempts; + + memset(psfont,0,sizeof(PSFONT)); + if ( fd==NULL || fd->fontname==NULL ) +return; + psfont->glyphcnt = fd->chars->cnt; + psfont->glyphs = calloc(psfont->glyphcnt,sizeof(struct bbglyph)); + psfont->temp = fd->chars; + for ( i=0; i<256; ++i ) { + for ( j=fd->chars->cnt-1; j>=0; --j ) + if ( strcmp(fd->encoding[i],fd->chars->keys[j])==0 ) + break; + if ( j==-1 ) + for ( j=fd->chars->cnt-1; j>0; --j ) + if ( strcmp(".notdef",fd->chars->keys[j])==0 ) + break; + psfont->encoding[i] = j; + } + psfont->fontname = strdup(fd->fontname); + if ( fd->fontinfo!=NULL ) { + psfont->familyname = strdup(fd->fontinfo->familyname); + psfont->fullname = strdup(fd->fontinfo->fullname); + psfont->weight = strdup(fd->fontinfo->weight); + psfont->notice = strdup(fd->fontinfo->notice); + psfont->version = strdup(fd->fontinfo->version); + psfont->italicangle = fd->fontinfo->italicangle; + } else { + psfont->familyname = strdup(fd->fontname); + if ( (pt = strchr(psfont->familyname,'-'))!=NULL ) + *pt = '\0'; + psfont->fullname = strdup(fd->fontname); + psfont->weight = strdup("Regular"); + } + psfont->isadobestd = fd->isadobestd; + psfont->em = 1000; + if ( fd->fontmatrix[0]!=0 ) + psfont->em = 1.0/fd->fontmatrix[0]; + memcpy(psfont->fbb,fd->fontbb,sizeof(psfont->fbb)); + + anyrefs = true; + for ( i=0; i<psfont->glyphcnt; ++i ) + psfont->glyphs[i].isref = true; + attempts = 0; + while ( anyrefs && attempts<psfont->glyphcnt ) { + anyrefs = false; + for ( i=0; i<psfont->glyphcnt; ++i ) if ( psfont->glyphs[i].isref ) { + psfont->glyphs[i].isref = false; + FindBB(psfont,&psfont->glyphs[i],fd->chars->values[i],fd->chars->lens[i], + fd->private->subrs, fd->chars->keys[i]); + if ( psfont->glyphs[i].isref ) + anyrefs = true; + else + psfont->glyphs[i].glyphname = strdup(fd->chars->keys[i]); + } + ++attempts; + } + for ( i=0; i<psfont->glyphcnt; ++i ) if ( !psfont->glyphs[i].isref ) { + if ( strcmp(psfont->glyphs[i].glyphname,"X")==0 ) + psfont->ch = psfont->glyphs[i].top; + else if ( strcmp(psfont->glyphs[i].glyphname,"x")==0 ) + psfont->xh = psfont->glyphs[i].top; + else if ( strcmp(psfont->glyphs[i].glyphname,"l")==0 ) + psfont->as = psfont->glyphs[i].top; + else if ( strcmp(psfont->glyphs[i].glyphname,"p")==0 ) + psfont->ds = psfont->glyphs[i].bottom; + } + for ( i=0; i<psfont->glyphcnt; ++i ) if ( psfont->glyphs[i].isref ) { + -- psfont->glyphcnt; + memcpy(&psfont->glyphs[i],&psfont->glyphs[i+1],(psfont->glyphcnt-i)*sizeof(struct bbglyph)); + } + PSFontFree(fd); +} @@ -58,9 +58,29 @@ typedef struct fond { short offset; /* 4.12 */ } *kerns; } *stylekerns; + char *psnames[48]; + char *family; struct fond *next; } FOND; +typedef struct PSFONT { + char *fontname, *familyname, *weight, *fullname, *notice, *version; + double italicangle; + double em; + double fbb[4]; + int as, ds, ch, xh; + int isadobestd; + int glyphcnt; + struct bbglyph { + char *glyphname; + int top, bottom, left, right; + int hadvance; + int isref; + } *glyphs; + short encoding[256]; /* glyph ids */ + void *temp; +} PSFONT; + extern int tolatin1; extern const char *macnames[]; extern const char *styles[]; @@ -71,3 +91,5 @@ extern int cleanfilename(char *filename); extern void SearchNFNTResources(FILE *f,long rlistpos,int subcnt,long rdata_pos, long name_list, FOND *fonds); + +extern void ParsePfb(FILE *pfb,PSFONT *psfont); diff --git a/psfont.h b/psfont.h new file mode 100644 index 0000000..0d79d20 --- /dev/null +++ b/psfont.h @@ -0,0 +1,192 @@ +/* Copyright (C) 2000-2004 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. + */ +#ifndef _PSFONT_H_ +#define _PSFONT_H_ + +/* pfb section headers. + There seem to be three and a half of them. the first is a the start of the + file and is 6 bytes long "\200\001x\005\000\000", the second is right after + the newline after eexec and is 6 bytes "\200\002I\224\000\000", the third + is right before the zeros (after the encoded data) and is "\200\001\024\002\000\000" + the last is at the end of file and is only two bytes "\200\003" + I think that the \200 byte indicates a header, the next byte is 1 for ascii, + 2 for binary and 3 for eof, then next 4 bytes are the length (not present + for eof headers) with the first byte the least significant. +*/ + +struct charprocs { + int cnt, next; + char **keys; + void **values; +}; + +struct psdict { + int cnt, next; + char **keys; + char **values; +}; + +struct pschars { + int cnt, next; + char **keys; + unsigned char **values; + int *lens; + int bias; /* for type2 strings */ +}; + +struct fontinfo { + char *familyname; + char *fullname; + char *notice; + char *weight; + char *version; + double italicangle; + unsigned int isfixedpitch:1; + double underlineposition; + double underlinethickness; + int em, ascent, descent; /* Generated by Fontographer (and us) */ + int fstype; /* 2=>no embedding, 4=>print, 8=>edit */ + /* Multiple master */ + char *blenddesignpositions; + char *blenddesignmap; + char *blendaxistypes; +}; + +struct private { + struct psdict *private; + struct pschars *subrs; /* (optional, required if othersubrs is present) */ + /* 0-2 part of Flex, 3 hint replacement, 4 and up for charstrings */ + int leniv; /* (optional) must be 4 for old interpreters (number of rand chars at start of charstrings entries) */ +#if 0 + int bluefuzz; /* (optional) (expand bluezones by this much, def=1) */ + double bluescale; /* (optional) if the current pointsize in pixels is less than this value then do overshoot hinting */ + int blueshift; /* (optional) */ + double bluevalues[14]; /* <=7 pairs of integers, first less than second, (may be empty) */ + /* first pair is baseline overshoots, other pairs above baseline */ + double expansionfactor; /* (optional) only for languagegroup==1 (CJK) */ + double familyblues[14]; /* (optional) bluevalues for family, can override local entry at small pointsizes */ + double familyotherblues[10];/* (optional) otherblues for family */ + unsigned int forcebold:1; /* (optional) */ + int languagegroup; /* (optional) (0=>latin, greek, cyril, etc.), (1=>CJK)*/ + int leniv; /* (optional) must be 4 for old interpreters (number of rand chars at start of charstrings entries) */ + char *minfeature; /* obsolete, required must be {16 16} */ + char *nd; /* "noaccess def" (may also be named "|-") */ + char *np; /* "noaccess put" (may also be named "|") */ + double otherblues[10]; /* (optional) descender blue zones */ + struct pschars *othersubrs; /* (optional) shouldn't contain user defined subs */ + int password; /* obsolete, required must be 5839 */ + char *rd; /* "{string currentfile exch readstring pop}" (may also be named "-|") */ + unsigned int rndstemup:1; /* (optional) obsolete, false if languagegroud==1 */ + double stdhw[1]; /* (optional) dominant horizontal stem width */ + double stdvw[1]; /* (optional) dominant vert */ + double stemsnaph[12]; /* (optional) common h stem widths (at most 12, includes stdhw, sorted by increasing size) */ + double stemsnapv[12]; /* (optional) common v stem widths*/ + struct pschars *subrs; /* (optional, required if othersubrs is present) */ + /* 0-2 part of Flex, 3 hint replacement, 4 and up for charstrings */ + int uniqueid; /* (optional) seems same as fontdict entry. why's it here too? what of XUID? */ +/* CID entries */ + int subrmapoffset; /* Offset to the start of this font's subr strings map */ + int sdbytes; /* bytes in each pointer in the map */ + int subrcnt; /* number of subroutines, number of pointers-1 in the map */ +#endif +}; + +typedef struct fontdict { + int fonttype; + double fontmatrix[6]; + char *fontname; /* (optional) */ + struct fontinfo *fontinfo; + int languagelevel; /* (optional) */ + int wmode; /* (optional) chooses between alternate metric sets */ +/* non-type0 entries */ + int isadobestd; + char *encoding[256]; + double fontbb[4]; + int uniqueid; /* (optional) open range between 4,000,000 and 4,999,999 */ + int xuid[20]; /* (optional) */ +/* Type1 specific values */ + int painttype; /* 0 (filled) 2 (stroked) */ + double strokewidth; /* (optional) only if painttype==2 */ + struct psdict *metrics; /* (optional) */ + struct psdict *metrics2; /* (optional) */ + struct pschars *chars; + struct charprocs *charprocs; + struct private *private; + unsigned int wasbinary: 1; + unsigned int wascff: 1; +/* CID stuff */ + int fdcnt; /* For the underlying dictionaries */ + struct fontdict **fds; + char *cidfontname; + int cidfonttype; + double cidversion; + char *registry; + char *ordering; + int supplement; + int mapoffset; + int fdbytes; + int gdbytes; + int cidcnt; + unsigned char **cidstrs; + short *cidlens; + short *cidfds; +/* CFF stuff */ + struct splinefont *sf; +/* MM stuff */ + char *blendfunc; + char *weightvector; + char *cdv; + char *ndv; + struct psdict *blendprivate; + struct psdict *blendfontinfo; +} FontDict; + +struct cidbytes { + int fdbytes, gdbytes, cidcnt; + int cidmapoffset; + int fdcnt; + struct fddata { + int leniv; + int subrmapoff, sdbytes, subrcnt; + int flexmax; + unsigned int iscjk:1; + struct pschars *subrs; + } *fds; + int *fdind; + int errors; +}; + +struct fd2data { + int defwid, nomwid; /* For Type2 charstrings */ + struct pschars *subrs; + FILE *private; /* Subroutines get stored in the private file immediately after the private dict */ + int eodictmark, fillindictmark; + int privatelen; +}; + +extern char *AdobeStandardEncoding[256]; +#endif @@ -74,7 +74,7 @@ static FOND *BuildFondList(FILE *f,long rlistpos,int subcnt,long rdata_pos, fseek(f,rlistpos,SEEK_SET); for ( i=0; i<subcnt; ++i ) { - printf( "FOND ResId=%d\n", getushort(f)); + printf( "\nFOND ResId=%d\n", getushort(f)); if ( feof(f)) { fprintf(stderr, "EOF found in FOND list after reading %d resources of %d.\n", i, subcnt ); break; @@ -513,6 +513,7 @@ return( false ); *pt++ = ch; } } + *pt = '\0'; /* strcpy(pt,isotf?".otf":".ttf"); */ return( true ); } |