1 /* Copyright (C) 2000-2008 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "fontforgevw.h"
29 #include <utype.h>
30 #include <ustring.h>
31 #include <math.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <gfile.h>
36 #include <time.h>
37 #include "unicoderange.h"
38 #include "psfont.h"
39 
40 #ifdef _WIN32
41 #define MKDIR(A,B) mkdir(A)
42 #else
43 #define MKDIR(A,B) mkdir(A,B)
44 #endif
45 
46 
SFUntickAll(SplineFont * sf)47 void SFUntickAll(SplineFont *sf) {
48     int i;
49 
50     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
51 	sf->glyphs[i]->ticked = false;
52 }
53 
SCBuildDummy(SplineChar * dummy,SplineFont * sf,EncMap * map,int i)54 SplineChar *SCBuildDummy(SplineChar *dummy,SplineFont *sf,EncMap *map,int i) {
55     static char namebuf[100];
56     static Layer layers[2];
57 
58     memset(dummy,'\0',sizeof(*dummy));
59     dummy->color = COLOR_DEFAULT;
60     dummy->layer_cnt = 2;
61     dummy->layers = layers;
62     if ( sf->cidmaster!=NULL ) {
63 	/* CID fonts don't have encodings, instead we must look up the cid */
64 	if ( sf->cidmaster->loading_cid_map )
65 	    dummy->unicodeenc = -1;
66 	else
67 	    dummy->unicodeenc = CID2NameUni(FindCidMap(sf->cidmaster->cidregistry,sf->cidmaster->ordering,sf->cidmaster->supplement,sf->cidmaster),
68 		    i,namebuf,sizeof(namebuf));
69     } else
70 	dummy->unicodeenc = UniFromEnc(i,map->enc);
71 
72     if ( sf->cidmaster!=NULL )
73 	dummy->name = namebuf;
74     else if ( map->enc->psnames!=NULL && i<map->enc->char_cnt &&
75 	    map->enc->psnames[i]!=NULL )
76 	dummy->name = map->enc->psnames[i];
77     else if ( dummy->unicodeenc==-1 )
78 	dummy->name = NULL;
79     else
80 	dummy->name = (char *) StdGlyphName(namebuf,dummy->unicodeenc,sf->uni_interp,sf->for_new_glyphs);
81     if ( dummy->name==NULL ) {
82 	/*if ( dummy->unicodeenc!=-1 || i<256 )
83 	    dummy->name = ".notdef";
84 	else*/ {
85 	    int j;
86 	    sprintf( namebuf, "NameMe.%d", i);
87 	    j=0;
88 	    while ( SFFindExistingSlot(sf,-1,namebuf)!=-1 )
89 		sprintf( namebuf, "NameMe.%d.%d", i, ++j);
90 	    dummy->name = namebuf;
91 	}
92     }
93     dummy->width = dummy->vwidth = sf->ascent+sf->descent;
94     if ( dummy->unicodeenc>0 && dummy->unicodeenc<0x10000 &&
95 	    iscombining(dummy->unicodeenc)) {
96 	/* Mark characters should be 0 width */
97 	dummy->width = 0;
98 	/* Except in monospaced fonts on windows, where they should be the */
99 	/*  same width as everything else */
100     }
101     /* Actually, in a monospace font, all glyphs should be the same width */
102     /*  whether mark or not */
103     if ( sf->pfminfo.panose_set && sf->pfminfo.panose[3]==9 &&
104 	    sf->glyphcnt>0 ) {
105 	for ( i=sf->glyphcnt-1; i>=0; --i )
106 	    if ( SCWorthOutputting(sf->glyphs[i])) {
107 		dummy->width = sf->glyphs[i]->width;
108 	break;
109 	    }
110     }
111     dummy->parent = sf;
112     dummy->orig_pos = 0xffff;
113 return( dummy );
114 }
115 
_SFMakeChar(SplineFont * sf,EncMap * map,int enc)116 static SplineChar *_SFMakeChar(SplineFont *sf,EncMap *map,int enc) {
117     SplineChar dummy, *sc;
118     SplineFont *ssf;
119     int j, real_uni, gid;
120     extern const int cns14pua[], amspua[];
121 
122     if ( enc>=map->enccount )
123 	gid = -1;
124     else
125 	gid = map->map[enc];
126     if ( sf->subfontcnt!=0 && gid!=-1 ) {
127 	ssf = NULL;
128 	for ( j=0; j<sf->subfontcnt; ++j )
129 	    if ( gid<sf->subfonts[j]->glyphcnt ) {
130 		ssf = sf->subfonts[j];
131 		if ( ssf->glyphs[gid]!=NULL ) {
132 return( ssf->glyphs[gid] );
133 		}
134 	    }
135 	sf = ssf;
136     }
137 
138     if ( gid==-1 || (sc = sf->glyphs[gid])==NULL ) {
139 	if (( map->enc->is_unicodebmp || map->enc->is_unicodefull ) &&
140 		( enc>=0xe000 && enc<=0xf8ff ) &&
141 		( sf->uni_interp==ui_ams || sf->uni_interp==ui_trad_chinese ) &&
142 		( real_uni = (sf->uni_interp==ui_ams ? amspua : cns14pua)[enc-0xe000])!=0 ) {
143 	    if ( real_uni<map->enccount ) {
144 		SplineChar *sc;
145 		/* if necessary, create the real unicode code point */
146 		/*  and then make us be a duplicate of it */
147 		sc = _SFMakeChar(sf,map,real_uni);
148 		map->map[enc] = gid = sc->orig_pos;
149 		SCCharChangedUpdate(sc,ly_all);
150 return( sc );
151 	    }
152 	}
153 
154 	SCBuildDummy(&dummy,sf,map,enc);
155 	/* Let's say a user has a postscript encoding where the glyph ".notdef" */
156 	/*  is assigned to many slots. Once the user creates a .notdef glyph */
157 	/*  all those slots should fill in. If they don't they damn well better*/
158 	/*  when the user clicks on one to edit it */
159 	/* Used to do that with all encodings. It just confused people */
160 	if ( map->enc->psnames!=NULL &&
161 		(sc = SFGetChar(sf,dummy.unicodeenc,dummy.name))!=NULL ) {
162 	    map->map[enc] = sc->orig_pos;
163 return( sc );
164 	}
165 	sc = SFSplineCharCreate(sf);
166 	sc->unicodeenc = dummy.unicodeenc;
167 	sc->name = copy(dummy.name);
168 	sc->width = dummy.width;
169 	sc->orig_pos = 0xffff;
170 	/*SCLigDefault(sc);*/
171 	SFAddGlyphAndEncode(sf,sc,map,enc);
172     }
173 return( sc );
174 }
175 
SFMakeChar(SplineFont * sf,EncMap * map,int enc)176 SplineChar *SFMakeChar(SplineFont *sf,EncMap *map, int enc) {
177     int gid;
178 
179     if ( enc==-1 )
180 return( NULL );
181     if ( enc>=map->enccount )
182 	gid = -1;
183     else
184 	gid = map->map[enc];
185     if ( sf->mm!=NULL && (gid==-1 || sf->glyphs[gid]==NULL) ) {
186 	int j;
187 	_SFMakeChar(sf->mm->normal,map,enc);
188 	for ( j=0; j<sf->mm->instance_count; ++j )
189 	    _SFMakeChar(sf->mm->instances[j],map,enc);
190     }
191 return( _SFMakeChar(sf,map,enc));
192 }
193 
194 struct unicoderange specialnames[] = {
195     { NULL, 0, 0, 0, 0, 0, 0 }
196 };
197 
198 
_SFReadPostscript(FILE * file,char * filename)199 static SplineFont *_SFReadPostscript(FILE *file,char *filename) {
200     FontDict *fd=NULL;
201     SplineFont *sf=NULL;
202 
203     ff_progress_change_stages(2);
204     fd = _ReadPSFont(file);
205     ff_progress_next_stage();
206     ff_progress_change_line2(_("Interpreting Glyphs"));
207     if ( fd!=NULL ) {
208 	sf = SplineFontFromPSFont(fd);
209 	PSFontFree(fd);
210 	if ( sf!=NULL )
211 	    CheckAfmOfPostscript(sf,filename,sf->map);
212     }
213 return( sf );
214 }
215 
SFReadPostscript(char * filename)216 static SplineFont *SFReadPostscript(char *filename) {
217     FontDict *fd=NULL;
218     SplineFont *sf=NULL;
219 
220     ff_progress_change_stages(2);
221     fd = ReadPSFont(filename);
222     ff_progress_next_stage();
223     ff_progress_change_line2(_("Interpreting Glyphs"));
224     if ( fd!=NULL ) {
225 	sf = SplineFontFromPSFont(fd);
226 	PSFontFree(fd);
227 	if ( sf!=NULL )
228 	    CheckAfmOfPostscript(sf,filename,sf->map);
229     }
230 return( sf );
231 }
232 
233 
234 struct compressors compressors[] = {
235     { ".gz", "gunzip", "gzip" },
236     { ".bz2", "bunzip2", "bzip2" },
237     { ".bz", "bunzip2", "bzip2" },
238     { ".Z", "gunzip", "compress" },
239 /* file types which are both archived and compressed (.tgz, .zip) are handled */
240 /*  by the archiver above */
241     { NULL, NULL, NULL }
242 };
243 
Decompress(char * name,int compression)244 char *Decompress(char *name, int compression) {
245     char *dir = getenv("TMPDIR");
246     char buf[1500];
247     char *tmpfile;
248 
249     if ( dir==NULL ) dir = P_tmpdir;
250     tmpfile = galloc(strlen(dir)+strlen(GFileNameTail(name))+2);
251     strcpy(tmpfile,dir);
252     strcat(tmpfile,"/");
253     strcat(tmpfile,GFileNameTail(name));
254     *strrchr(tmpfile,'.') = '\0';
255 #if defined( _NO_SNPRINTF ) || defined( __VMS )
256     sprintf( buf, "%s < %s > %s", compressors[compression].decomp, name, tmpfile );
257 #else
258     snprintf( buf, sizeof(buf), "%s < %s > %s", compressors[compression].decomp, name, tmpfile );
259 #endif
260     if ( system(buf)==0 )
261 return( tmpfile );
262     free(tmpfile);
263 return( NULL );
264 }
265 
ForceFileToHaveName(FILE * file,char * exten)266 static char *ForceFileToHaveName(FILE *file, char *exten) {
267     char tmpfilename[L_tmpnam+100];
268     static int try=0;
269     FILE *newfile;
270 
271     forever {
272 	sprintf( tmpfilename, P_tmpdir "/fontforge%d-%d", getpid(), try++ );
273 	if ( exten!=NULL )
274 	    strcat(tmpfilename,exten);
275 	if ( access( tmpfilename, F_OK )==-1 &&
276 		(newfile = fopen(tmpfilename,"w"))!=NULL ) {
277 	    char buffer[1024];
278 	    int len;
279 	    while ( (len = fread(buffer,1,sizeof(buffer),file))>0 )
280 		fwrite(buffer,1,len,newfile);
281 	    fclose(newfile);
282 	}
283 return(copy(tmpfilename));			/* The filename does not exist */
284     }
285 }
286 
287 /* This does not check currently existing fontviews, and should only be used */
288 /*  by LoadSplineFont (which does) and by RevertFile (which knows what it's doing) */
_ReadSplineFont(FILE * file,char * filename,enum openflags openflags)289 SplineFont *_ReadSplineFont(FILE *file,char *filename,enum openflags openflags) {
290     SplineFont *sf;
291     char ubuf[250], *temp;
292     int fromsfd = false;
293     int i;
294     char *pt, *strippedname, *oldstrippedname, *tmpfile=NULL, *paren=NULL, *fullname=filename, *rparen;
295     int len;
296     int checked;
297     int compression=0;
298     int wasurl = false, nowlocal = true;
299 
300     if ( filename==NULL )
301 return( NULL );
302 
303     strippedname = filename;
304     pt = strrchr(filename,'/');
305     if ( pt==NULL ) pt = filename;
306     /* Someone gave me a font "Nafees Nastaleeq(Updated).ttf" and complained */
307     /*  that ff wouldn't open it */
308     /* Now someone will complain about "Nafees(Updated).ttc(fo(ob)ar)" */
309     if ( (paren = strrchr(pt,'('))!=NULL &&
310 	    (rparen = strrchr(paren,')'))!=NULL &&
311 	    rparen[1]=='\0' ) {
312 	strippedname = copy(filename);
313 	strippedname[paren-filename] = '\0';
314     }
315 
316     pt = strrchr(strippedname,'.');
317 
318     i = -1;
319     if ( pt!=NULL ) for ( i=0; compressors[i].ext!=NULL; ++i )
320 	if ( strcmp(compressors[i].ext,pt)==0 )
321     break;
322     oldstrippedname = strippedname;
323     if ( i==-1 || compressors[i].ext==NULL )
324 	i=-1;
325     else {
326 	if ( file!=NULL ) {
327 	    char *spuriousname = ForceFileToHaveName(file,compressors[i].ext);
328 	    tmpfile = Decompress(spuriousname,i);
329 	    fclose(file); file = NULL;
330 	    unlink(spuriousname); free(spuriousname);
331 	} else
332 	    tmpfile = Decompress(strippedname,i);
333 	if ( tmpfile!=NULL ) {
334 	    strippedname = tmpfile;
335 	} else {
336 	    ff_post_error(_("Decompress Failed!"),_("Decompress Failed!"));
337 return( NULL );
338 	}
339 	compression = i+1;
340 	if ( strippedname!=filename && paren!=NULL ) {
341 	    fullname = galloc(strlen(strippedname)+strlen(paren)+1);
342 	    strcpy(fullname,strippedname);
343 	    strcat(fullname,paren);
344 	} else
345 	    fullname = strippedname;
346     }
347 
348     /* If there are no pfaedit windows, give them something to look at */
349     /*  immediately. Otherwise delay a bit */
350     strcpy(ubuf,_("Loading font from "));
351     len = strlen(ubuf);
352     if ( !wasurl || i==-1 )	/* If it wasn't compressed, or it wasn't an url, then the fullname is reasonable, else use the original name */
353 	strncat(ubuf,temp = copy(GFileNameTail(fullname)),100);
354     else
355 	strncat(ubuf,temp = copy(GFileNameTail(filename)),100);
356     free(temp);
357     ubuf[100+len] = '\0';
358     ff_progress_start_indicator(FontViewFirst()==NULL?0:10,_("Loading..."),ubuf,_("Reading Glyphs"),0,1);
359     ff_progress_enable_stop(0);
360 
361     if ( file==NULL ) {
362 	file = fopen(strippedname,"rb");
363 	nowlocal = true;
364     }
365 
366     sf = NULL;
367     checked = false;
368 /* checked == false => not checked */
369 /* checked == 'u'   => UFO */
370 /* checked == 't'   => TTF/OTF */
371 /* checked == 'p'   => pfb/general postscript */
372 /* checked == 'P'   => pdf */
373 /* checked == 'c'   => cff */
374 /* checked == 'S'   => svg */
375 /* checked == 'f'   => sfd */
376 /* checked == 'F'   => sfdir */
377 /* checked == 'b'   => bdf */
378 /* checked == 'i'   => ikarus */
379     if ( file!=NULL ) {
380 	/* Try to guess the file type from the first few characters... */
381 	int ch1 = getc(file);
382 	int ch2 = getc(file);
383 	int ch3 = getc(file);
384 	int ch4 = getc(file);
385 	int ch9, ch10;
386 	fseek(file, 98, SEEK_SET);
387 	ch9 = getc(file);
388 	ch10 = getc(file);
389 	rewind(file);
390 	if (( ch1==0 && ch2==1 && ch3==0 && ch4==0 ) ||
391 		(ch1=='O' && ch2=='T' && ch3=='T' && ch4=='O') ||
392 		(ch1=='t' && ch2=='r' && ch3=='u' && ch4=='e') ||
393 		(ch1=='t' && ch2=='t' && ch3=='c' && ch4=='f') ) {
394 	    sf = _SFReadTTF(file,0,openflags,fullname,NULL);
395 	    checked = 't';
396 	} else if (( ch1=='%' && ch2=='!' ) ||
397 		    ( ch1==0x80 && ch2=='\01' ) ) {	/* PFB header */
398 	    sf = _SFReadPostscript(file,fullname);
399 	    checked = 'p';
400 	} else if ( ch1==1 && ch2==0 && ch3==4 ) {
401 	    int len;
402 	    fseek(file,0,SEEK_END);
403 	    len = ftell(file);
404 	    fseek(file,0,SEEK_SET);
405 	    sf = _CFFParse(file,len,NULL);
406 	    checked = 'c';
407 	} /* Too hard to figure out a valid mark for a mac resource file */
408 	if ( file!=NULL ) fclose(file);
409     }
410 
411     if ( sf!=NULL )
412 	/* good */;
413     else if (( strmatch(fullname+strlen(fullname)-4, ".ttf")==0 ||
414 		strmatch(fullname+strlen(strippedname)-4, ".ttc")==0 ||
415 		strmatch(fullname+strlen(fullname)-4, ".gai")==0 ||
416 		strmatch(fullname+strlen(fullname)-4, ".otf")==0 ||
417 		strmatch(fullname+strlen(fullname)-4, ".otb")==0 ) && checked!='t') {
418 	sf = SFReadTTF(fullname,0,openflags);
419     } else if ( strmatch(fullname+strlen(strippedname)-4, ".bin")==0 ||
420 		strmatch(fullname+strlen(strippedname)-4, ".hqx")==0 ||
421 		strmatch(fullname+strlen(strippedname)-6, ".dfont")==0 ) {
422 	sf = SFReadMacBinary(fullname,0,openflags);
423     } else if ( (strmatch(fullname+strlen(fullname)-4, ".pfa")==0 ||
424 		strmatch(fullname+strlen(fullname)-4, ".pfb")==0 ||
425 		strmatch(fullname+strlen(fullname)-4, ".pf3")==0 ||
426 		strmatch(fullname+strlen(fullname)-4, ".cid")==0 ||
427 		strmatch(fullname+strlen(fullname)-4, ".gsf")==0 ||
428 		strmatch(fullname+strlen(fullname)-4, ".pt3")==0 ||
429 		strmatch(fullname+strlen(fullname)-3, ".ps")==0 ) && checked!='p' ) {
430 	sf = SFReadPostscript(fullname);
431     } else if ( strmatch(fullname+strlen(fullname)-4, ".cff")==0 && checked!='c' ) {
432 	sf = CFFParse(fullname);
433     } else {
434 	sf = SFReadMacBinary(fullname,0,openflags);
435     }
436     ff_progress_end_indicator();
437 
438     if ( sf!=NULL ) {
439 	SplineFont *norm = sf->mm!=NULL ? sf->mm->normal : sf;
440 	if ( compression!=0 ) {
441 	    free(sf->filename);
442 	    *strrchr(oldstrippedname,'.') = '\0';
443 	    sf->filename = copy( oldstrippedname );
444 	}
445 	if ( fromsfd )
446 	    sf->compression = compression;
447 	free( norm->origname );
448 	if ( sf->chosenname!=NULL && strippedname==filename ) {
449 	    norm->origname = galloc(strlen(filename)+strlen(sf->chosenname)+8);
450 	    strcpy(norm->origname,filename);
451 	    strcat(norm->origname,"(");
452 	    strcat(norm->origname,sf->chosenname);
453 	    strcat(norm->origname,")");
454 	} else
455 	    norm->origname = copy(filename);
456 	free( norm->chosenname ); norm->chosenname = NULL;
457 	if ( sf->mm!=NULL ) {
458 	    int j;
459 	    for ( j=0; j<sf->mm->instance_count; ++j ) {
460 		free(sf->mm->instances[j]->origname);
461 		sf->mm->instances[j]->origname = copy(norm->origname);
462 	    }
463 	}
464     } else if ( !GFileExists(filename) )
465 	ff_post_error(_("Couldn't open font"),_("The requested file, %.100s, does not exist"),GFileNameTail(filename));
466     else if ( !GFileReadable(filename) )
467 	ff_post_error(_("Couldn't open font"),_("You do not have permission to read %.100s"),GFileNameTail(filename));
468     else
469 	ff_post_error(_("Couldn't open font"),_("%.100s is not in a known format (or is so badly corrupted as to be unreadable)"),GFileNameTail(filename));
470 
471     if ( oldstrippedname!=filename )
472 	free(oldstrippedname);
473     if ( fullname!=filename && fullname!=strippedname )
474 	free(fullname);
475     if ( tmpfile!=NULL ) {
476 	unlink(tmpfile);
477 	free(tmpfile);
478     }
479     if ( (openflags&of_fstypepermitted) && sf!=NULL && (sf->pfminfo.fstype&0xff)==0x0002 ) {
480 	/* Ok, they have told us from a script they have access to the font */
481     } else if ( !fromsfd && sf!=NULL && (sf->pfminfo.fstype&0xff)==0x0002 ) {
482 	char *buts[3];
483 	buts[0] = _("_Yes"); buts[1] = _("_No"); buts[2] = NULL;
484 	if ( ff_ask(_("Restricted Font"),(const char **) buts,1,1,_("This font is marked with an FSType of 2 (Restricted\nLicense). That means it is not editable without the\npermission of the legal owner.\n\nDo you have such permission?"))==1 ) {
485 	    SplineFontFree(sf);
486 return( NULL );
487 	}
488     }
489 return( sf );
490 }
491 
ReadSplineFont(char * filename,enum openflags openflags)492 SplineFont *ReadSplineFont(char *filename,enum openflags openflags) {
493 return( _ReadSplineFont(NULL,filename,openflags));
494 }
495 
496 
ReadSplineFontInfo(char * filename,enum openflags openflags)497 SplineFont *ReadSplineFontInfo(char *filename,enum openflags openflags) {
498   SplineFont *sf, *sf_ptr;
499 	char **fontlist;
500     char *pt =NULL, *strippedname=filename, *paren=NULL, *rparen=NULL, *fullname=filename;
501     FILE *foo = NULL;
502     int checked = 0;
503 	char s[512] = {0};
504 
505     if ( filename==NULL )
506 return( NULL );
507 
508     pt = strrchr(filename,'/');
509     if ( pt==NULL ) pt = filename;
510     /* Someone gave me a font "Nafees Nastaleeq(Updated).ttf" and complained */
511     /*  that ff wouldn't open it */
512     /* Now someone will complain about "Nafees(Updated).ttc(fo(ob)ar)" */
513     if ( (paren = strrchr(pt,'('))!=NULL &&
514 	    (rparen = strrchr(paren,')'))!=NULL &&
515 	    rparen[1]=='\0' ) {
516 	strippedname = copy(filename);
517 	strippedname[paren-filename] = '\0';
518     }
519 
520     sf = NULL;
521     foo = fopen(strippedname,"rb");
522     checked = false;
523     if ( foo!=NULL ) {
524 	/* Try to guess the file type from the first few characters... */
525 	int ch1 = getc(foo);
526 	int ch2 = getc(foo);
527 	int ch3 = getc(foo);
528 	int ch4 = getc(foo);
529 	fclose(foo);
530 	if (( ch1==0 && ch2==1 && ch3==0 && ch4==0 ) ||
531 		(ch1=='O' && ch2=='T' && ch3=='T' && ch4=='O') ||
532 		(ch1=='t' && ch2=='r' && ch3=='u' && ch4=='e') ) {
533 	    sf = SFReadTTFInfo(fullname,0,openflags);
534 	    checked = 't';
535 	} else if ((ch1=='t' && ch2=='t' && ch3=='c' && ch4=='f')) {
536 	  /* read all fonts in a collection */
537 	  fontlist = NamesReadTTF(fullname);
538 	  if (fontlist) {
539 		while (*fontlist != NULL) {
540 		  snprintf(s,511, "%s(%s)", fullname,*fontlist);
541 		  sf_ptr = SFReadTTFInfo(s,0,openflags);
542 		  if (sf != NULL)
543 			sf_ptr->next = sf;
544 		  sf = sf_ptr;
545 		  fontlist++;
546 		}
547 	  }
548     } else if ( strmatch(fullname+strlen(strippedname)-4, ".bin")==0 ||
549                 strmatch(fullname+strlen(strippedname)-4, ".hqx")==0 ||
550                 strmatch(fullname+strlen(strippedname)-6, ".dfont")==0 ) {
551 	  fontlist = NamesReadMacBinary(fullname);
552 	  if (fontlist) {
553 		while (*fontlist != NULL) {
554 		  snprintf(s,511, "%s(%s)", fullname,*fontlist);
555 		  sf_ptr = SFReadMacBinaryInfo(s,0,openflags);
556 		  if (sf != NULL)
557 			sf_ptr->next = sf;
558 		  sf = sf_ptr;
559 		  fontlist++;
560 		}
561 	  }
562 	} else {
563       sf = ReadSplineFont (fullname, openflags);
564     }
565     }
566     if ( strippedname!=filename )
567       free(strippedname);
568 return( sf );
569 }
570 
571 
572 /* Use URW 4 letter abbreviations */
573 char *knownweights[] = { "Demi", "Bold", "Regu", "Medi", "Book", "Thin",
574 	"Ligh", "Heav", "Blac", "Ultr", "Nord", "Norm", "Gras", "Stan", "Halb",
575 	"Fett", "Mage", "Mitt", "Buch", NULL };
576 char *realweights[] = { "Demi", "Bold", "Regular", "Medium", "Book", "Thin",
577 	"Light", "Heavy", "Black", "Ultra", "Nord", "Normal", "Gras", "Standard", "Halbfett",
578 	"Fett", "Mager", "Mittel", "Buchschrift", NULL};
579 static char *moreweights[] = { "ExtraLight", "VeryLight", NULL };
580 char **noticeweights[] = { moreweights, realweights, knownweights, NULL };
581 
582 static char *modifierlist[] = { "Ital", "Obli", "Kursive", "Cursive", "Slanted",
583 	"Expa", "Cond", NULL };
584 static char *modifierlistfull[] = { "Italic", "Oblique", "Kursive", "Cursive", "Slanted",
585     "Expanded", "Condensed", NULL };
586 static char **mods[] = { knownweights, modifierlist, NULL };
587 static char **fullmods[] = { realweights, modifierlistfull, NULL };
588 
_GetModifiers(char * fontname,char * familyname,char * weight)589 char *_GetModifiers(char *fontname, char *familyname,char *weight) {
590     char *pt, *fpt;
591     int i, j;
592 
593     /* URW fontnames don't match the familyname */
594     /* "NimbusSanL-Regu" vs "Nimbus Sans L" (note "San" vs "Sans") */
595     /* so look for a '-' if there is one and use that as the break point... */
596 
597     if ( (fpt=strchr(fontname,'-'))!=NULL ) {
598 	++fpt;
599 	if ( *fpt=='\0' )
600 	    fpt = NULL;
601     } else if ( familyname!=NULL ) {
602 	for ( pt = fontname, fpt=familyname; *fpt!='\0' && *pt!='\0'; ) {
603 	    if ( *fpt == *pt ) {
604 		++fpt; ++pt;
605 	    } else if ( *fpt==' ' )
606 		++fpt;
607 	    else if ( *pt==' ' )
608 		++pt;
609 	    else if ( *fpt=='a' || *fpt=='e' || *fpt=='i' || *fpt=='o' || *fpt=='u' )
610 		++fpt;	/* allow vowels to be omitted from family when in fontname */
611 	    else
612 	break;
613 	}
614 	if ( *fpt=='\0' && *pt!='\0' )
615 	    fpt = pt;
616 	else
617 	    fpt = NULL;
618     }
619 
620     if ( fpt == NULL ) {
621 	for ( i=0; mods[i]!=NULL; ++i ) for ( j=0; mods[i][j]!=NULL; ++j ) {
622 	    pt = strstr(fontname,mods[i][j]);
623 	    if ( pt!=NULL && (fpt==NULL || pt<fpt))
624 		fpt = pt;
625 	}
626     }
627     if ( fpt!=NULL ) {
628 	for ( i=0; mods[i]!=NULL; ++i ) for ( j=0; mods[i][j]!=NULL; ++j ) {
629 	    if ( strcmp(fpt,mods[i][j])==0 )
630 return( fullmods[i][j]);
631 	}
632 	if ( strcmp(fpt,"BoldItal")==0 )
633 return( "BoldItalic" );
634 	else if ( strcmp(fpt,"BoldObli")==0 )
635 return( "BoldOblique" );
636 
637 return( fpt );
638     }
639 
640 return( weight==NULL || *weight=='\0' ? "Regular": weight );
641 }
642 
SFGetModifiers(SplineFont * sf)643 char *SFGetModifiers(SplineFont *sf) {
644 return( _GetModifiers(sf->fontname,sf->familyname,sf->weight));
645 }
646 
647