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 #include "fontforgevw.h"
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <math.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <time.h>
35 #include <ustring.h>
36 #include "ttf.h"
37 #include "psfont.h"
38 #ifdef LUA_FF_LIB
39 #  undef __Mac
40 #endif
41 #if __Mac
42 #  include <ctype.h>
43 #  include </Developer/Headers/FlatCarbon/Files.h>
44 #else
45 #  include <utype.h>
46 #  undef __Mac
47 #  define __Mac 0
48 #endif
49 
50 const int mac_dpi = 72;
51 /* I had always assumed that the mac still believed in 72dpi screens, but I */
52 /*  see that in geneva under OS/9, the pointsize does not match the pixel */
53 /*  size of the font. But the dpi is not constant (and the differences */
54 /*  excede those supplied by rounding errors) varying between 96 and 84dpi */
55 
56 /* A Mac Resource fork */
57 /*  http://developer.apple.com/techpubs/mac/MoreToolbox/MoreToolbox-9.html */
58 /*    begins with a 16 byte header containing: */
59 /*	resource start offset */
60 /*	map start offset */
61 /*	resource length */
62 /*	map length */
63 /*    then 256-16 bytes of zeros */
64 /*    the resource section consists of (many) */
65 /*	4 byte length count */
66 /*	resource data	*/
67 /*    the map section contains */
68 /*	A copy of the 16 byte header */
69 /*	a 4 byte mac internal value (I hope) */
70 /*	another 4 bytes of mac internal values (I hope) */
71 /*	a 2 byte offset from the start of the map section to the list of resource types */
72 /*	a 2 byte offset from the start of the map section to the list of resource names */
73 /*	The resource type list consists of */
74 /*	    a 2 byte count of the number of resource types (-1) */
75 /*	    (many copies of) */
76 /*		a 4 byte resource type ('FOND' for example) */
77 /*		a 2 byte count of the number of resources of this type (-1) */
78 /*		a 2 byte offset from the type list start to the resource table */
79 /*	    a resource table looks like */
80 /*		a 2 byte offset from the resource name table to a pascal */
81 /*			string containing this resource's name (or 0xffff for none) */
82 /*		1 byte of resource flags */
83 /*		3 bytes of offset from the resource section to the length & */
84 /*			data of this instance of the resource type */
85 /*		4 bytes of 0 */
86 /*	The resource name section consists of */
87 /*	    a bunch of pascal strings (ie. preceded by a length byte) */
88 
89 /* The POST resource isn't noticeably documented, it's pretty much a */
90 /*  straight copy of the pfb file cut up into 0x800 byte chunks. */
91 /*  (each section of the pfb file has it's own set of chunks, the last may be smaller than 0x800) */
92 /* The NFNT resource http://developer.apple.com/techpubs/mac/Text/Text-250.html */
93 /* The FOND resource http://developer.apple.com/techpubs/mac/Text/Text-269.html */
94 /* The sfnt resource is basically a copy of the ttf file */
95 
96 /* A MacBinary file */
97 /*  http://www.lazerware.com/formats/macbinary.html */
98 /*    begins with a 128 byte header */
99 /*	(which specifies lengths for data/resource forks) */
100 /*	(and contains mac type/creator data) */
101 /*	(and other stuff) */
102 /*	(and finally a crc checksum) */
103 /*    is followed by the data section (padded to a mult of 128 bytes) */
104 /*    is followed by the resource section (padded to a mult of 128 bytes) */
105 
106 /* ******************************** Creation ******************************** */
107 
108 
109 struct resource {
110     uint32 pos;
111     uint8 flags;
112     uint16 id;
113     char *name;
114     uint32 nameloc;
115     uint32 nameptloc;
116 };
117 
118 struct resourcetype {
119     uint32 tag;
120     struct resource *res;
121     uint32 resloc;
122 };
123 
124 struct macbinaryheader {
125     char *macfilename;
126     char *binfilename;          /* if macfilename is null and this is set we will figure out macfilename by removing .bin */
127     uint32 type;
128     uint32 creator;
129 };
130 
131 
132 enum psstyle_flags { psf_bold = 1, psf_italic = 2, psf_outline = 4,
133     psf_shadow = 0x8, psf_condense = 0x10, psf_extend = 0x20
134 };
135 
_MacStyleCode(char * styles,SplineFont * sf,uint16 * psstylecode)136 uint16 _MacStyleCode(char *styles, SplineFont * sf, uint16 * psstylecode)
137 {
138     unsigned short stylecode = 0, psstyle = 0;
139 
140     if (strstrmatch(styles, "Bold") || strstrmatch(styles, "Demi") ||
141         strstrmatch(styles, "Heav") || strstrmatch(styles, "Blac") ||
142 /* A few fonts have German/French styles in their names */
143         strstrmatch(styles, "Fett") || strstrmatch(styles, "Gras")) {
144         stylecode = sf_bold;
145         psstyle = psf_bold;
146     } else if (sf != NULL && sf->weight != NULL &&
147                (strstrmatch(sf->weight, "Bold")
148                 || strstrmatch(sf->weight, "Demi")
149                 || strstrmatch(sf->weight, "Heav")
150                 || strstrmatch(sf->weight, "Blac")
151                 || strstrmatch(sf->weight, "Fett")
152                 || strstrmatch(sf->weight, "Gras"))) {
153         stylecode = sf_bold;
154         psstyle = psf_bold;
155     }
156     /* URW uses four leter abbreviations of Italic and Oblique */
157     /* Somebody else uses two letter abbrevs */
158     if ((sf != NULL && sf->italicangle != 0) ||
159         strstrmatch(styles, "Ital") ||
160         strstrmatch(styles, "Obli") ||
161         strstrmatch(styles, "Slanted") ||
162         strstrmatch(styles, "Kurs") || strstr(styles, "It")) {
163         stylecode |= sf_italic;
164         psstyle |= psf_italic;
165     }
166     if (strstrmatch(styles, "Underline")) {
167         stylecode |= sf_underline;
168     }
169     if (strstrmatch(styles, "Outl")) {
170         stylecode |= sf_outline;
171         psstyle |= psf_outline;
172     }
173     if (strstr(styles, "Shadow") != NULL) {
174         stylecode |= sf_shadow;
175         psstyle |= psf_shadow;
176     }
177     if (strstrmatch(styles, "Cond") || strstr(styles, "Cn") ||
178         strstrmatch(styles, "Narrow")) {
179         stylecode |= sf_condense;
180         psstyle |= psf_condense;
181     }
182     if (strstrmatch(styles, "Exte") || strstr(styles, "Ex")) {
183         stylecode |= sf_extend;
184         psstyle |= psf_extend;
185     }
186     if ((psstyle & psf_extend) && (psstyle & psf_condense)) {
187         if (sf != NULL)
188             LogError(_
189                      ("Warning: %s(%s) is both extended and condensed. That's impossible.\n"),
190                      sf->fontname, sf->origname);
191         else
192             LogError(_
193                      ("Warning: Both extended and condensed. That's impossible.\n"));
194         psstyle &= ~psf_extend;
195         stylecode &= ~sf_extend;
196     }
197     if (psstylecode != NULL)
198         *psstylecode = psstyle;
199     return (stylecode);
200 }
201 
202 
203 
204 /* ******************************** Reading ********************************* */
205 
SearchPostscriptResources(FILE * f,long rlistpos,int subcnt,long rdata_pos,long name_list,int flags)206 static SplineFont *SearchPostscriptResources(FILE * f, long rlistpos,
207                                              int subcnt, long rdata_pos,
208                                              long name_list, int flags)
209 {
210     long here = ftell(f);
211     long *offsets, lenpos;
212     int rname = -1, tmp;
213     int ch1, ch2;
214     int len, type, i, j, rlen;
215     unsigned short id, *rsrcids;
216     /* I don't pretend to understand the rational behind the format of a */
217     /*  postscript font. It appears to be split up into chunks where the */
218     /*  maximum chunk size is 0x800, each section (ascii, binary, ascii, eof) */
219     /*  has its own set of chunks (ie chunks don't cross sections) */
220     char *buffer = NULL;
221     int max = 0;
222     FILE *pfb;
223     FontDict *fd;
224     SplineFont *sf;
225     (void) name_list;
226     fseek(f, rlistpos, SEEK_SET);
227     rsrcids = gcalloc(subcnt, sizeof(short));
228     offsets = gcalloc(subcnt, sizeof(long));
229     for (i = 0; i < subcnt; ++i) {
230         rsrcids[i] = getushort(f);
231         tmp = (short) getushort(f);
232         if (rname == -1)
233             rname = tmp;
234         /* flags = */ getc(f);
235         ch1 = getc(f);
236         ch2 = getc(f);
237         offsets[i] = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
238         /* mbz = */ getlong(f);
239     }
240 
241     pfb = tmpfile();
242     if (pfb == NULL) {
243         LogError(_("Can't open temporary file for postscript output\n"));
244         fseek(f, here, SEEK_SET);
245         free(offsets);
246         return (NULL);
247     }
248 
249     putc(0x80, pfb);
250     putc(1, pfb);
251     lenpos = ftell(pfb);
252     putc(0, pfb);
253     putc(0, pfb);
254     putc(0, pfb);
255     putc(0, pfb);
256     len = 0;
257     type = 1;
258     id = 501;
259     for (i = 0; i < subcnt; ++i) {
260         for (j = 0; j < subcnt; ++j)
261             if (rsrcids[j] == id)
262                 break;
263         if (j == subcnt) {
264             LogError(_("Missing POST resource %u\n"), id);
265             break;
266         }
267         id = id + 1;
268         fseek(f, offsets[j], SEEK_SET);
269         rlen = getlong(f);
270         ch1 = getc(f);
271         ch2 = getc(f);
272         rlen -= 2;              /* those two bytes don't count as real data */
273         if (ch1 == type)
274             len += rlen;
275         else {
276             long hold = ftell(pfb);
277             fseek(pfb, lenpos, SEEK_SET);
278             putc(len >> 24, pfb);
279             putc((len >> 16) & 0xff, pfb);
280             putc((len >> 8) & 0xff, pfb);
281             putc(len & 0xff, pfb);
282             fseek(pfb, hold, SEEK_SET);
283             if (ch1 == 5)       /* end of font mark */
284                 break;
285             putc(0x80, pfb);
286             putc(ch1, pfb);
287             lenpos = ftell(pfb);
288             putc(0, pfb);
289             putc(0, pfb);
290             putc(0, pfb);
291             putc(0, pfb);
292             type = ch1;
293             len = rlen;
294         }
295         if (rlen > max) {
296             free(buffer);
297             max = rlen;
298             if (max < 0x800)
299                 max = 0x800;
300             buffer = galloc(max);
301             if (buffer == NULL) {
302                 LogError(_("Out of memory\n"));
303                 exit(1);
304             }
305         }
306         fread(buffer, 1, rlen, f);
307         fwrite(buffer, 1, rlen, pfb);
308     }
309     free(buffer);
310     free(offsets);
311     free(rsrcids);
312     putc(0x80, pfb);
313     putc(3, pfb);
314     fseek(pfb, lenpos, SEEK_SET);
315     putc(len >> 24, pfb);
316     putc((len >> 16) & 0xff, pfb);
317     putc((len >> 8) & 0xff, pfb);
318     putc(len & 0xff, pfb);
319     fseek(f, here, SEEK_SET);
320     rewind(pfb);
321     if (flags & ttf_onlynames)
322         return ((SplineFont *) _NamesReadPostscript(pfb));      /* This closes the font for us */
323 
324     fd = _ReadPSFont(pfb);
325     sf = NULL;
326     if (fd != NULL) {
327         sf = SplineFontFromPSFont(fd);
328         PSFontFree(fd);
329         /* There is no FOND in a postscript file, so we can't read any kerning */
330     }
331     fclose(pfb);
332     return (sf);
333 }
334 
SearchTtfResources(FILE * f,long rlistpos,int subcnt,long rdata_pos,long name_list,char * filename,int flags,enum openflags openflags)335 static SplineFont *SearchTtfResources(FILE * f, long rlistpos, int subcnt,
336                                       long rdata_pos, long name_list,
337                                       char *filename, int flags,
338                                       enum openflags openflags)
339 {
340     long here, start = ftell(f);
341     long roff;
342     int rname = -1;
343     int ch1, ch2;
344     int len, i, rlen, ilen;
345     /* The sfnt resource is just a copy of the ttf file */
346     char *buffer = NULL;
347     int max = 0;
348     FILE *ttf;
349     SplineFont *sf;
350     int which = 0;
351     char **names;
352     char *pt, *lparen, *rparen;
353     char *chosenname = NULL;
354     (void) name_list;
355     fseek(f, rlistpos, SEEK_SET);
356     if (subcnt > 1 || (flags & ttf_onlynames)) {
357         names = gcalloc(subcnt + 1, sizeof(char *));
358         for (i = 0; i < subcnt; ++i) {
359             /* resource id = */ getushort(f);
360             /* rname = (short) */ getushort(f);
361             /* flags = */ getc(f);
362             ch1 = getc(f);
363             ch2 = getc(f);
364             roff = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
365             /* mbz = */ getlong(f);
366             here = ftell(f);
367             names[i] = TTFGetFontName(f, roff + 4, roff + 4);
368             if (names[i] == NULL) {
369                 char buffer[32];
370                 sprintf(buffer, "Nameless%d", i);
371                 names[i] = copy(buffer);
372             }
373             fseek(f, here, SEEK_SET);
374         }
375         if (flags & ttf_onlynames) {
376             return ((SplineFont *) names);
377         }
378         if ((pt = strrchr(filename, '/')) == NULL)
379             pt = filename;
380         /* Someone gave me a font "Nafees Nastaleeq(Updated).ttf" and complained */
381         /*  that ff wouldn't open it */
382         /* Now someone will complain about "Nafees(Updated).ttc(fo(ob)ar)" */
383         if ((lparen = strrchr(pt, '(')) != NULL &&
384             (rparen = strrchr(lparen, ')')) != NULL && rparen[1] == '\0') {
385             char *find = copy(lparen + 1);
386             pt = strchr(find, ')');
387             if (pt != NULL)
388                 *pt = '\0';
389             for (which = subcnt - 1; which >= 0; --which)
390                 if (strcmp(names[which], find) == 0)
391                     break;
392             if (which == -1) {
393                 char *end;
394                 which = strtol(find, &end, 10);
395                 if (*end != '\0')
396                     which = -1;
397             }
398             if (which == -1) {
399                 char *fn = copy(filename);
400                 fn[lparen - filename] = '\0';
401                 ff_post_error(_("Not in Collection"), _("%s is not in %.100s"),
402                               find, fn);
403                 free(fn);
404             }
405             free(find);
406         } else
407             which = 0;
408         if (lparen == NULL && which != -1)
409             chosenname = copy(names[which]);
410         for (i = 0; i < subcnt; ++i)
411             free(names[i]);
412         free(names);
413         fseek(f, rlistpos, SEEK_SET);
414     }
415 
416     for (i = 0; i < subcnt; ++i) {
417         /* resource id = */ getushort(f);
418         rname = (short) getushort(f);
419         /* flags = */ getc(f);
420         ch1 = getc(f);
421         ch2 = getc(f);
422         roff = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
423         /* mbz = */ getlong(f);
424         if (i != which)
425             continue;
426         here = ftell(f);
427 
428         ttf = tmpfile();
429         if (ttf == NULL) {
430             LogError(_("Can't open temporary file for truetype output.\n"));
431             continue;
432         }
433 
434         fseek(f, roff, SEEK_SET);
435         ilen = rlen = getlong(f);
436         if (rlen > 16 * 1024)
437             ilen = 16 * 1024;
438         if (ilen > max) {
439             free(buffer);
440             max = ilen;
441             if (max < 0x800)
442                 max = 0x800;
443             buffer = malloc(max);
444         }
445         for (len = 0; len < rlen;) {
446             int temp = ilen;
447             if (rlen - len < ilen)
448                 temp = rlen - len;
449             temp = fread(buffer, 1, temp, f);
450             if (temp == EOF)
451                 break;
452             fwrite(buffer, 1, temp, ttf);
453             len += temp;
454         }
455         rewind(ttf);
456         sf = _SFReadTTF(ttf, flags, openflags, NULL, NULL);
457         fclose(ttf);
458         if (sf != NULL) {
459             free(buffer);
460             fseek(f, start, SEEK_SET);
461             if (sf->chosenname == NULL)
462                 sf->chosenname = chosenname;
463             return (sf);
464         }
465         fseek(f, here, SEEK_SET);
466     }
467     free(chosenname);
468     free(buffer);
469     fseek(f, start, SEEK_SET);
470     return (NULL);
471 }
472 
473 typedef struct fond {
474     char *fondname;
475     int first, last;
476     int assoc_cnt;
477     struct assoc {
478         short size, style, id;
479     } *assoc;
480     /* size==0 => scalable */
481     /* style>>8 is the bit depth (0=>1, 1=>2, 2=>4, 3=>8) */
482     /* search order for ID is sfnt, NFNT, FONT */
483     int stylewidthcnt;
484     struct stylewidths {
485         short style;
486         short *widthtab;        /* 4.12 fixed number with the width specified as a fraction of an em */
487     } *stylewidths;
488     int stylekerncnt;
489     struct stylekerns {
490         short style;
491         int kernpairs;
492         struct kerns {
493             unsigned char ch1, ch2;
494             short offset;       /* 4.12 */
495         } *kerns;
496     } *stylekerns;
497     char *psnames[48];
498     struct fond *next;
499 } FOND;
500 
501 struct MacFontRec {
502     short fontType;
503     short firstChar;
504     short lastChar;
505     short widthMax;
506     short kernMax;              /* bb learing */
507     short Descent;              /* maximum negative distance below baseline */
508     short fRectWidth;           /* bounding box width */
509     short fRectHeight;          /* bounding box height */
510     unsigned short *offsetWidths;       /* offset to start of offset/width table */
511     /* 0xffff => undefined, else high byte is offset in locTable, */
512     /*  low byte is width */
513     short ascent;
514     short descent;
515     short leading;
516     short rowWords;             /* shorts per row */
517     unsigned short *fontImage;  /* rowWords*fRectHeight */
518     /* Images for all characters plus one extra for undefined */
519     unsigned short *locs;       /* lastchar-firstchar+3 words */
520     /* Horizontal offset to start of n'th character. Note: applies */
521     /*  to each row. Missing characters have same loc as following */
522 };
523 
FondListFree(FOND * list)524 static void FondListFree(FOND * list)
525 {
526     FOND *next;
527     int i;
528 
529     while (list != NULL) {
530         next = list->next;
531         free(list->assoc);
532         for (i = 0; i < list->stylewidthcnt; ++i)
533             free(list->stylewidths[i].widthtab);
534         free(list->stylewidths);
535         for (i = 0; i < list->stylekerncnt; ++i)
536             free(list->stylekerns[i].kerns);
537         free(list->stylekerns);
538         for (i = 0; i < 48; ++i)
539             free(list->psnames[i]);
540         free(list);
541         list = next;
542     }
543 }
544 
545 /* There's probably only one fond in the file, but there could be more so be */
546 /*  prepared... */
547 /* I want the fond: */
548 /*  to get the fractional widths for the SWIDTH entry on bdf */
549 /*  to get the font name */
550 /*  to get the font association tables */
551 /*  to get the style flags */
552 /* http://developer.apple.com/techpubs/mac/Text/Text-269.html */
BuildFondList(FILE * f,long rlistpos,int subcnt,long rdata_pos,long name_list,int flags)553 static FOND *BuildFondList(FILE * f, long rlistpos, int subcnt, long rdata_pos,
554                            long name_list, int flags)
555 {
556     long here, start = ftell(f);
557     long offset;
558     int rname = -1;
559     char name[300];
560     int ch1, ch2;
561     int i, j, k, cnt, isfixed;
562     FOND *head = NULL, *cur;
563     long widoff, kernoff, styleoff;
564 
565     fseek(f, rlistpos, SEEK_SET);
566     for (i = 0; i < subcnt; ++i) {
567         /* resource id = */ getushort(f);
568         rname = (short) getushort(f);
569         /* flags = */ getc(f);
570         ch1 = getc(f);
571         ch2 = getc(f);
572         offset = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
573         /* mbz = */ getlong(f);
574         here = ftell(f);
575 
576         cur = gcalloc(1, sizeof(FOND));
577         cur->next = head;
578         head = cur;
579 
580         if (rname != -1) {
581             fseek(f, name_list + rname, SEEK_SET);
582             ch1 = getc(f);
583             fread(name, 1, ch1, f);
584             name[ch1] = '\0';
585             cur->fondname = copy(name);
586         }
587 
588         offset += 4;
589         fseek(f, offset, SEEK_SET);
590         isfixed = getushort(f) & 0x8000 ? 1 : 0;
591         /* family id = */ getushort(f);
592         cur->first = getushort(f);
593         cur->last = getushort(f);
594 /* on a 1 point font... */
595         /* ascent = */ getushort(f);
596         /* descent = (short) */ getushort(f);
597         /* leading = */ getushort(f);
598         /* widmax = */ getushort(f);
599         if ((widoff = getlong(f)) != 0)
600             widoff += offset;
601         if ((kernoff = getlong(f)) != 0)
602             kernoff += offset;
603         if ((styleoff = getlong(f)) != 0)
604             styleoff += offset;
605         for (j = 0; j < 9; ++j)
606             getushort(f);
607         /* internal & undefined, for international scripts = */ getlong(f);
608         /* version = */ getushort(f);
609         cur->assoc_cnt = getushort(f) + 1;
610         cur->assoc = gcalloc(cur->assoc_cnt, sizeof(struct assoc));
611         for (j = 0; j < cur->assoc_cnt; ++j) {
612             cur->assoc[j].size = getushort(f);
613             cur->assoc[j].style = getushort(f);
614             cur->assoc[j].id = getushort(f);
615         }
616         if (widoff != 0) {
617             fseek(f, widoff, SEEK_SET);
618             cnt = getushort(f) + 1;
619             cur->stylewidthcnt = cnt;
620             cur->stylewidths = gcalloc(cnt, sizeof(struct stylewidths));
621             for (j = 0; j < cnt; ++j) {
622                 cur->stylewidths[j].style = getushort(f);
623                 cur->stylewidths[j].widthtab =
624                     galloc((cur->last - cur->first + 3) * sizeof(short));
625                 for (k = cur->first; k <= cur->last + 2; ++k)
626                     cur->stylewidths[j].widthtab[k] = getushort(f);
627             }
628         }
629         if (kernoff != 0 && (flags & ttf_onlykerns)) {
630             fseek(f, kernoff, SEEK_SET);
631             cnt = getushort(f) + 1;
632             cur->stylekerncnt = cnt;
633             cur->stylekerns = gcalloc(cnt, sizeof(struct stylekerns));
634             for (j = 0; j < cnt; ++j) {
635                 cur->stylekerns[j].style = getushort(f);
636                 cur->stylekerns[j].kernpairs = getushort(f);
637                 cur->stylekerns[j].kerns =
638                     galloc(cur->stylekerns[j].kernpairs * sizeof(struct kerns));
639                 for (k = 0; k < cur->stylekerns[j].kernpairs; ++k) {
640                     cur->stylekerns[j].kerns[k].ch1 = getc(f);
641                     cur->stylekerns[j].kerns[k].ch2 = getc(f);
642                     cur->stylekerns[j].kerns[k].offset = getushort(f);
643                 }
644             }
645         }
646         if (styleoff != 0) {
647             uint8 stringoffsets[48];
648             int strcnt, stringlen, format;
649             char **strings, *pt;
650             fseek(f, styleoff, SEEK_SET);
651             /* class = */ getushort(f);
652             /* glyph encoding offset = */ getlong(f);
653             /* reserved = */ getlong(f);
654             for (j = 0; j < 48; ++j)
655                 stringoffsets[j] = getc(f);
656             strcnt = getushort(f);
657             strings = galloc(strcnt * sizeof(char *));
658             for (j = 0; j < strcnt; ++j) {
659                 stringlen = getc(f);
660                 strings[j] = galloc(stringlen + 2);
661                 strings[j][0] = stringlen;
662                 strings[j][stringlen + 1] = '\0';
663                 for (k = 0; k < stringlen; ++k)
664                     strings[j][k + 1] = getc(f);
665             }
666             for (j = 0; j < 48; ++j) {
667                 for (k = j - 1; k >= 0; --k)
668                     if (stringoffsets[j] == stringoffsets[k])
669                         break;
670                 if (k != -1)
671                     continue;   /* this style doesn't exist */
672                 format = stringoffsets[j] - 1;
673                 stringlen = strings[0][0];
674                 if (format != 0)
675                     for (k = 0; k < strings[format][0]; ++k)
676                         stringlen += strings[strings[format][k + 1] - 1][0];
677                 pt = cur->psnames[j] = galloc(stringlen + 1);
678                 strcpy(pt, strings[0] + 1);
679                 pt += strings[0][0];
680                 if (format != 0)
681                     for (k = 0; k < strings[format][0]; ++k) {
682                         strcpy(pt, strings[strings[format][k + 1] - 1] + 1);
683                         pt += strings[strings[format][k + 1] - 1][0];
684                     }
685                 *pt = '\0';
686             }
687             for (j = 0; j < strcnt; ++j)
688                 free(strings[j]);
689             free(strings);
690         }
691         fseek(f, here, SEEK_SET);
692     }
693     fseek(f, start, SEEK_SET);
694     return (head);
695 }
696 
BuildName(char * family,int style)697 static char *BuildName(char *family, int style)
698 {
699     char buffer[350] = "";
700 
701     strncpy(buffer, family, 200);
702     if (style != 0)
703         strcat(buffer, "-");
704     if (style & sf_bold)
705         strcat(buffer, "Bold");
706     if (style & sf_italic)
707         strcat(buffer, "Italic");
708     if (style & sf_underline)
709         strcat(buffer, "Underline");
710     if (style & sf_outline)
711         strcat(buffer, "Outline");
712     if (style & sf_shadow)
713         strcat(buffer, "Shadow");
714     if (style & sf_condense)
715         strcat(buffer, "Condensed");
716     if (style & sf_extend)
717         strcat(buffer, "Extended");
718     return (copy(buffer));
719 }
720 
GuessStyle(char * fontname,int * styles,int style_cnt)721 static int GuessStyle(char *fontname, int *styles, int style_cnt)
722 {
723     int which, style;
724     char *stylenames = _GetModifiers(fontname, NULL, NULL);
725 
726     style = _MacStyleCode(stylenames, NULL, NULL);
727     for (which = style_cnt; which >= 0; --which)
728         if (styles[which] == style)
729             return (which);
730 
731     return (-1);
732 }
733 
PickFOND(FOND * fondlist,char * filename,char ** name,int * style)734 static FOND *PickFOND(FOND * fondlist, char *filename, char **name, int *style)
735 {
736     int i, j;
737     FOND *test;
738     uint8 stylesused[96];
739     char **names;
740     FOND **fonds = NULL, *fond = NULL;
741     int *styles = NULL;
742     int cnt, which;
743     char *pt, *lparen;
744     char *find = NULL;
745 
746     if ((pt = strrchr(filename, '/')) != NULL)
747         pt = filename;
748     if ((lparen = strchr(filename, '(')) != NULL && strchr(lparen, ')') != NULL) {
749         find = copy(lparen + 1);
750         pt = strchr(find, ')');
751         if (pt != NULL)
752             *pt = '\0';
753         for (test = fondlist; test != NULL; test = test->next) {
754             for (i = 0; i < 48; ++i)
755                 if (test->psnames[i] != NULL
756                     && strcmp(find, test->psnames[i]) == 0) {
757                     *style = (i & 3) | ((i & ~3) << 1); /* PS styles skip underline bit */
758                     *name = copy(test->psnames[i]);
759                     return (test);
760                 }
761         }
762     }
763 
764     /* The file may contain multiple families, and each family may contain */
765     /*  multiple styles (and each style may contain multiple sizes, but that's */
766     /*  not an issue for us here) */
767     names = NULL;
768     for (i = 0; i < 2; ++i) {
769         cnt = 0;
770         for (test = fondlist; test != NULL; test = test->next)
771             if (test->fondname != NULL) {
772                 memset(stylesused, 0, sizeof(stylesused));
773                 for (j = 0; j < test->assoc_cnt; ++j) {
774                     if (test->assoc[j].size != 0
775                         && !stylesused[test->assoc[j].style]) {
776                         stylesused[test->assoc[j].style] = true;
777                         if (names != NULL) {
778                             names[cnt] =
779                                 BuildName(test->fondname, test->assoc[j].style);
780                             styles[cnt] = test->assoc[j].style;
781                             fonds[cnt] = test;
782                         }
783                         ++cnt;
784                     }
785                 }
786             }
787         if (names == NULL) {
788             names = gcalloc(cnt + 1, sizeof(char *));
789             fonds = galloc(cnt * sizeof(FOND *));
790             styles = galloc(cnt * sizeof(int));
791         }
792     }
793 
794     if (find != NULL) {
795         for (which = cnt - 1; which >= 0; --which)
796             if (strcmp(names[which], find) == 0)
797                 break;
798         if (which == -1 && strstrmatch(find, test->fondname) != NULL)
799             which = GuessStyle(find, styles, cnt);
800         if (which == -1) {
801             char *fn = copy(filename);
802             fn[lparen - filename] = '\0';
803             ff_post_error(_("Not in Collection"), _("%s is not in %.100s"),
804                           find, fn);
805             free(fn);
806         }
807         free(find);
808     } else
809         which = 0;
810 
811     if (which != -1) {
812         fond = fonds[which];
813         *name = copy(names[which]);
814         *style = styles[which];
815     }
816     for (i = 0; i < cnt; ++i)
817         free(names[i]);
818     free(names);
819     free(fonds);
820     free(styles);
821     if (which == -1)
822         return (NULL);
823 
824     return (fond);
825 }
826 
827 
828 /* Look for kerning info and merge it into the currently existing font "into" */
FindFamilyStyleKerns(SplineFont * into,EncMap * map,FOND * fondlist,char * filename)829 static SplineFont *FindFamilyStyleKerns(SplineFont * into, EncMap * map,
830                                         FOND * fondlist, char *filename)
831 {
832     char *name;
833     int style;
834     FOND *fond;
835     int i, j;
836     int ch1, ch2, offset;
837     KernPair *kp;
838     SplineChar *sc1, *sc2;
839 
840     fond = PickFOND(fondlist, filename, &name, &style);
841     if (fond == NULL || into == NULL)
842         return (NULL);
843     for (i = 0; i < fond->stylekerncnt; ++i)
844         if (fond->stylekerns[i].style == style)
845             break;
846     if (i == fond->stylekerncnt) {
847         LogError(_("No kerning table for %s\n"), name);
848         free(name);
849         return (NULL);
850     }
851     for (j = 0; j < fond->stylekerns[i].kernpairs; ++j) {
852         ch1 = fond->stylekerns[i].kerns[j].ch1;
853         ch2 = fond->stylekerns[i].kerns[j].ch2;
854         offset =
855             (fond->stylekerns[i].kerns[j].offset *
856              (into->ascent + into->descent) + (1 << 11)) >> 12;
857         sc1 = SFMakeChar(into, map, ch1);
858         sc2 = SFMakeChar(into, map, ch2);
859         for (kp = sc1->kerns; kp != NULL; kp = kp->next)
860             if (kp->sc == sc2)
861                 break;
862         if (kp == NULL) {
863             uint32 script;
864             kp = chunkalloc(sizeof(KernPair));
865             kp->sc = sc2;
866             kp->next = sc1->kerns;
867             sc1->kerns = kp;
868             script = SCScriptFromUnicode(sc1);
869             if (script == DEFAULT_SCRIPT)
870                 script = SCScriptFromUnicode(sc2);
871             kp->subtable =
872                 SFSubTableFindOrMake(sc1->parent, CHR('k', 'e', 'r', 'n'),
873                                      script, gpos_pair);
874         }
875         kp->off = offset;
876     }
877     return (into);
878 }
879 
880 /* Look for a bare truetype font in a binhex/macbinary wrapper */
MightBeTrueType(FILE * binary,int32 pos,int32 dlen,int flags,enum openflags openflags)881 static SplineFont *MightBeTrueType(FILE * binary, int32 pos, int32 dlen,
882                                    int flags, enum openflags openflags)
883 {
884     FILE *temp ;
885     char *buffer ;
886     int len;
887     SplineFont *sf;
888 
889     if (flags & ttf_onlynames) {
890         char **ret;
891         char *temp = TTFGetFontName(binary, pos, pos);
892         if (temp == NULL)
893             return (NULL);
894         ret = galloc(2 * sizeof(char *));
895         ret[0] = temp;
896         ret[1] = NULL;
897         return ((SplineFont *) ret);
898     }
899     temp = tmpfile();
900     buffer = galloc(8192);
901 
902 
903     fseek(binary, pos, SEEK_SET);
904     while (dlen > 0) {
905         len = dlen > 8192 ? 8192 : dlen;
906         len = fread(buffer, 1, dlen > 8192 ? 8192 : dlen, binary);
907         if (len == 0)
908             break;
909         fwrite(buffer, 1, len, temp);
910         dlen -= len;
911     }
912     rewind(temp);
913     sf = _SFReadTTF(temp, flags, openflags, NULL, NULL);
914     fclose(temp);
915     free(buffer);
916     return (sf);
917 }
918 
IsResourceFork(FILE * f,long offset,char * filename,int flags,enum openflags openflags,SplineFont * into,EncMap * map)919 static SplineFont *IsResourceFork(FILE * f, long offset, char *filename,
920                                   int flags, enum openflags openflags,
921                                   SplineFont * into, EncMap * map)
922 {
923     /* If it is a good resource fork then the first 16 bytes are repeated */
924     /*  at the location specified in bytes 4-7 */
925     /* We include an offset because if we are looking at a mac binary file */
926     /*  the resource fork will actually start somewhere in the middle of the */
927     /*  file, not at the beginning */
928     unsigned char buffer[16], buffer2[16];
929     long rdata_pos, map_pos, type_list, name_list, rpos;
930     int32 rdata_len, map_len;
931     uint32 nfnt_pos, font_pos, fond_pos;
932     unsigned long tag;
933     int i, cnt, subcnt, nfnt_subcnt = 0, font_subcnt = 0, fond_subcnt = 0;
934     SplineFont *sf;
935     FOND *fondlist = NULL;
936     fond_pos = 0;
937     fseek(f, offset, SEEK_SET);
938     if (fread(buffer, 1, 16, f) != 16)
939         return (NULL);
940     rdata_pos =
941         offset +
942         ((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]);
943     map_pos =
944         offset +
945         ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]);
946     rdata_len =
947         ((buffer[8] << 24) | (buffer[9] << 16) | (buffer[10] << 8) |
948          buffer[11]);
949     map_len =
950         ((buffer[12] << 24) | (buffer[13] << 16) | (buffer[14] << 8) |
951          buffer[15]);
952     if (rdata_pos + rdata_len != map_pos || rdata_len == 0)
953         return (NULL);
954     fseek(f, map_pos, SEEK_SET);
955     buffer2[15] = buffer[15] + 1;       /* make it be different */
956     if (fread(buffer2, 1, 16, f) != 16)
957         return (NULL);
958 
959 /* Apple's data fork resources appear to have a bunch of zeroes here instead */
960 /*  of a copy of the first 16 bytes */
961     for (i = 0; i < 16; ++i)
962         if (buffer2[i] != 0)
963             break;
964     if (i != 16) {
965         for (i = 0; i < 16; ++i)
966             if (buffer[i] != buffer2[i])
967                 return (NULL);
968     }
969     getlong(f);                 /* skip the handle to the next resource map */
970     getushort(f);               /* skip the file resource number */
971     getushort(f);               /* skip the attributes */
972     type_list = map_pos + getushort(f);
973     name_list = map_pos + getushort(f);
974 
975     fseek(f, type_list, SEEK_SET);
976     cnt = getushort(f) + 1;
977     for (i = 0; i < cnt; ++i) {
978         tag = getlong(f);
979         /* printf( "%c%c%c%c\n", tag>>24, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff ); */
980         subcnt = getushort(f) + 1;
981         rpos = type_list + getushort(f);
982         sf = NULL;
983         if (tag == CHR('P', 'O', 'S', 'T') && !(flags & (ttf_onlystrikes | ttf_onlykerns)))     /* No FOND */
984             sf = SearchPostscriptResources(f, rpos, subcnt, rdata_pos,
985                                            name_list, flags);
986         else if (tag == CHR('s', 'f', 'n', 't') && !(flags & ttf_onlykerns))
987             sf = SearchTtfResources(f, rpos, subcnt, rdata_pos, name_list,
988                                     filename, flags, openflags);
989         else if (tag == CHR('N', 'F', 'N', 'T')) {
990             nfnt_pos = rpos;
991             nfnt_subcnt = subcnt;
992         } else if (tag == CHR('F', 'O', 'N', 'T')) {
993             font_pos = rpos;
994             font_subcnt = subcnt;
995         } else if (tag == CHR('F', 'O', 'N', 'D')) {
996             fond_pos = rpos;
997             fond_subcnt = subcnt;
998         }
999         if (sf != NULL)
1000             return (sf);
1001     }
1002     if (flags & ttf_onlynames)  /* Not interested in bitmap resources here */
1003         return (NULL);
1004 
1005     if (flags & ttf_onlykerns) {        /* For kerns */
1006         if (fond_subcnt != 0)
1007             fondlist =
1008                 BuildFondList(f, fond_pos, fond_subcnt, rdata_pos, name_list,
1009                               flags);
1010         into = FindFamilyStyleKerns(into, map, fondlist, filename);
1011         FondListFree(fondlist);
1012         return (into);
1013     }
1014     /* Ok. If no outline font, try for a bitmap */
1015     if (nfnt_subcnt == 0) {
1016         nfnt_pos = font_pos;
1017         nfnt_subcnt = font_subcnt;
1018     }
1019     return ((SplineFont *) - 1);        /* It's a valid resource file, but just has no fonts */
1020 }
1021 
1022 
IsResourceInBinary(FILE * f,char * filename,int flags,enum openflags openflags,SplineFont * into,EncMap * map)1023 static SplineFont *IsResourceInBinary(FILE * f, char *filename, int flags,
1024                                       enum openflags openflags,
1025                                       SplineFont * into, EncMap * map)
1026 {
1027     unsigned char header[128];
1028     unsigned long offset, dlen, rlen;
1029 
1030     if (fread(header, 1, 128, f) != 128)
1031         return (NULL);
1032     if (header[0] != 0 || header[74] != 0 || header[82] != 0 || header[1] <= 0
1033         || header[1] > 33 || header[63] != 0 || header[2 + header[1]] != 0)
1034         return (NULL);
1035     dlen =
1036         ((header[0x53] << 24) | (header[0x54] << 16) | (header[0x55] << 8) |
1037          header[0x56]);
1038     rlen =
1039         ((header[0x57] << 24) | (header[0x58] << 16) | (header[0x59] << 8) |
1040          header[0x5a]);
1041     /* 128 bytes for header, then the dlen is padded to a 128 byte boundary */
1042     offset = 128 + ((dlen + 127) & ~127);
1043 /* Look for a bare truetype font in a binhex/macbinary wrapper */
1044     if (dlen != 0 && rlen <= dlen) {
1045         int pos = ftell(f);
1046         fread(header, 1, 4, f);
1047         header[5] = '\0';
1048         if (strcmp((char *) header, "OTTO") == 0
1049             || strcmp((char *) header, "true") == 0
1050             || strcmp((char *) header, "ttcf") == 0 || (header[0] == 0
1051                                                         && header[1] == 1
1052                                                         && header[2] == 0
1053                                                         && header[3] == 0))
1054             return (MightBeTrueType(f, pos, dlen, flags, openflags));
1055     }
1056     return (IsResourceFork(f, offset, filename, flags, openflags, into, map));
1057 }
1058 
1059 static int lastch = 0, repeat = 0;
outchr(FILE * binary,int ch)1060 static void outchr(FILE * binary, int ch)
1061 {
1062     int i;
1063 
1064     if (repeat) {
1065         if (ch == 0) {
1066             /* no repeat, output a literal 0x90 (the repeat flag) */
1067             lastch = 0x90;
1068             putc(lastch, binary);
1069         } else {
1070             for (i = 1; i < ch; ++i)
1071                 putc(lastch, binary);
1072         }
1073         repeat = 0;
1074     } else if (ch == 0x90) {
1075         repeat = 1;
1076     } else {
1077         putc(ch, binary);
1078         lastch = ch;
1079     }
1080 }
1081 
IsResourceInHex(FILE * f,char * filename,int flags,enum openflags openflags,SplineFont * into,EncMap * map)1082 static SplineFont *IsResourceInHex(FILE * f, char *filename, int flags,
1083                                    enum openflags openflags, SplineFont * into,
1084                                    EncMap * map)
1085 {
1086     /* convert file from 6bit to 8bit */
1087     /* interesting data is enclosed between two colons */
1088     FILE *binary = tmpfile();
1089     char *sixbit =
1090         "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
1091     int ch, val, cnt, i, dlen, rlen;
1092     unsigned char header[20];
1093     char *pt;
1094     SplineFont *ret;
1095 
1096     if (binary == NULL) {
1097         LogError(_("can't create temporary file\n"));
1098         return (NULL);
1099     }
1100 
1101     lastch = repeat = 0;
1102     while ((ch = getc(f)) != ':');      /* There may be comments before file start */
1103     cnt = val = 0;
1104     while ((ch = getc(f)) != ':') {
1105         if (isspace(ch))
1106             continue;
1107         for (pt = sixbit; *pt != ch && *pt != '\0'; ++pt);
1108         if (*pt == '\0') {
1109             fclose(binary);
1110             return (NULL);
1111         }
1112         val = (val << 6) | (pt - sixbit);
1113         if (++cnt == 4) {
1114             outchr(binary, (val >> 16) & 0xff);
1115             outchr(binary, (val >> 8) & 0xff);
1116             outchr(binary, val & 0xff);
1117             val = cnt = 0;
1118         }
1119     }
1120     if (cnt != 0) {
1121         if (cnt == 1)
1122             outchr(binary, val << 2);
1123         else if (cnt == 2) {
1124             val <<= 4;
1125             outchr(binary, (val >> 8) & 0xff);
1126             outchr(binary, val & 0xff);
1127         } else if (cnt == 3) {
1128             val <<= 6;
1129             outchr(binary, (val >> 16) & 0xff);
1130             outchr(binary, (val >> 8) & 0xff);
1131             outchr(binary, val & 0xff);
1132         }
1133     }
1134 
1135     rewind(binary);
1136     ch = getc(binary);          /* Name length */
1137     /* skip name */
1138     for (i = 0; i < ch; ++i)
1139         getc(binary);
1140     if (getc(binary) != '\0') {
1141         fclose(binary);
1142         return (NULL);
1143     }
1144     fread(header, 1, 20, binary);
1145     dlen =
1146         (header[10] << 24) | (header[11] << 16) | (header[12] << 8) |
1147         header[13];
1148     rlen =
1149         (header[14] << 24) | (header[15] << 16) | (header[16] << 8) |
1150         header[17];
1151 /* Look for a bare truetype font in a binhex/macbinary wrapper */
1152     if (dlen != 0 && rlen < dlen) {
1153         int pos = ftell(binary);
1154         fread(header, 1, 4, binary);
1155         header[5] = '\0';
1156         if (strcmp((char *) header, "OTTO") == 0
1157             || strcmp((char *) header, "true") == 0
1158             || strcmp((char *) header, "ttcf") == 0 || (header[0] == 0
1159                                                         && header[1] == 1
1160                                                         && header[2] == 0
1161                                                         && header[3] == 0)) {
1162             ret = MightBeTrueType(binary, pos, dlen, flags, openflags);
1163             fclose(binary);
1164             return (ret);
1165         }
1166     }
1167     if (rlen == 0) {
1168         fclose(binary);
1169         return (NULL);
1170     }
1171 
1172     ret =
1173         IsResourceFork(binary, ftell(binary) + dlen + 2, filename, flags,
1174                        openflags, into, map);
1175 
1176     fclose(binary);
1177     return (ret);
1178 }
1179 
IsResourceInFile(char * filename,int flags,enum openflags openflags,SplineFont * into,EncMap * map)1180 static SplineFont *IsResourceInFile(char *filename, int flags,
1181                                     enum openflags openflags, SplineFont * into,
1182                                     EncMap * map)
1183 {
1184     FILE *f;
1185     char *spt, *pt;
1186     SplineFont *sf;
1187     char *temp = filename, *lparen;
1188 
1189     if ((pt = strrchr(filename, '/')) == NULL)
1190         pt = filename;
1191     if ((lparen = strchr(pt, '(')) != NULL && strchr(lparen, ')') != NULL) {
1192         temp = copy(filename);
1193         temp[lparen - filename] = '\0';
1194     }
1195     f = fopen(temp, "rb");
1196     if (temp != filename)
1197         free(temp);
1198     if (f == NULL)
1199         return (NULL);
1200     spt = strrchr(filename, '/');
1201     if (spt == NULL)
1202         spt = filename;
1203     pt = strrchr(spt, '.');
1204     if (pt != NULL && (pt[1] == 'b' || pt[1] == 'B')
1205         && (pt[2] == 'i' || pt[2] == 'I') && (pt[3] == 'n' || pt[3] == 'N')
1206         && (pt[4] == '\0' || pt[4] == '(')) {
1207         if ((sf = IsResourceInBinary(f, filename, flags, openflags, into, map))) {
1208             fclose(f);
1209             return (sf);
1210         }
1211     } else if (pt != NULL && (pt[1] == 'h' || pt[1] == 'H')
1212                && (pt[2] == 'q' || pt[2] == 'Q') && (pt[3] == 'x'
1213                                                      || pt[3] == 'X')
1214                && (pt[4] == '\0' || pt[4] == '(')) {
1215         if ((sf = IsResourceInHex(f, filename, flags, openflags, into, map))) {
1216             fclose(f);
1217             return (sf);
1218         }
1219     }
1220 
1221     sf = IsResourceFork(f, 0, filename, flags, openflags, into, map);
1222     fclose(f);
1223 #if __Mac
1224     if (sf == NULL)
1225         sf = HasResourceFork(filename, flags, openflags, into, map);
1226 #endif
1227     return (sf);
1228 }
1229 
FindResourceFile(char * filename,int flags,enum openflags openflags,SplineFont * into,EncMap * map)1230 static SplineFont *FindResourceFile(char *filename, int flags,
1231                                     enum openflags openflags, SplineFont * into,
1232                                     EncMap * map)
1233 {
1234     char *spt, *pt, *dpt;
1235     char buffer[1400];
1236     SplineFont *sf;
1237 
1238     if ((sf = IsResourceInFile(filename, flags, openflags, into, map)))
1239         return (sf);
1240 
1241     /* Well, look in the resource fork directory (if it exists), the resource */
1242     /*  fork is placed there in a seperate file on (some) non-Mac disks */
1243     strcpy(buffer, filename);
1244     spt = strrchr(buffer, '/');
1245     if (spt == NULL) {
1246         spt = buffer;
1247         pt = filename;
1248     } else {
1249         ++spt;
1250         pt = filename + (spt - buffer);
1251     }
1252     strcpy(spt, "resource.frk/");
1253     strcat(spt, pt);
1254     if ((sf = IsResourceInFile(buffer, flags, openflags, into, map)))
1255         return (sf);
1256 
1257     /* however the resource fork does not appear to do long names properly */
1258     /*  names are always lower case 8.3, do some simple things to check */
1259     spt = strrchr(buffer, '/') + 1;
1260     for (pt = spt; *pt; ++pt)
1261         if (isupper(*pt))
1262             *pt = tolower(*pt);
1263     dpt = strchr(spt, '.');
1264     if (dpt == NULL)
1265         dpt = spt + strlen(spt);
1266     if (dpt - spt > 8 || strlen(dpt) > 4) {
1267         char exten[8];
1268         strncpy(exten, dpt, 7);
1269         exten[4] = '\0';        /* it includes the dot */
1270         if (dpt - spt > 6)
1271             dpt = spt + 6;
1272         *dpt++ = '~';
1273         *dpt++ = '1';
1274         strcpy(dpt, exten);
1275     }
1276     return (IsResourceInFile(buffer, flags, openflags, into, map));
1277 }
1278 
1279 
createtmpfile(char * filename)1280 static char *createtmpfile(char *filename)
1281 {
1282     char *p, *tempname;
1283     p = strrchr(filename,'/');
1284     if (p != NULL) {
1285 	filename = p+1;
1286     }
1287     assert(strlen(filename)>=5);
1288     tempname = malloc(strlen(filename)+2);
1289     if (tempname == NULL) {
1290 	LogError(_("Out of memory\n"));
1291 	exit(1);
1292     }
1293     strcpy(tempname,filename);
1294     strcpy(tempname+strlen(tempname)-5,"XXXXXX"); /* dfont -> XXXXXX */
1295 
1296 #ifdef HAVE_MKSTEMP
1297     {
1298       int i = mkstemp(tempname);
1299       if (i) {
1300         close(i);
1301       }
1302     }
1303 #else
1304     mktemp(tempname);
1305 #endif
1306     return tempname;
1307 }
1308 
SearchTtfResourcesFile(FILE * f,long rlistpos,int subcnt,long rdata_pos,long name_list,char * filename,char * fontname)1309 static char *SearchTtfResourcesFile(FILE * f, long rlistpos, int subcnt,
1310                                     long rdata_pos, long name_list,
1311                                     char *filename, char *fontname)
1312 {
1313     long here;
1314     long roff;
1315     int rname = -1;
1316     int ch1, ch2;
1317     int len, i, rlen, ilen;
1318     /* The sfnt resource is just a copy of the ttf file */
1319     char *buffer = NULL;
1320     int max = 0;
1321     FILE *ttf;
1322     char *sf = NULL;
1323     int which = 0;
1324     char **names;
1325     (void)name_list;
1326     fseek(f, rlistpos, SEEK_SET);
1327     if (subcnt > 1) {
1328         names = gcalloc(subcnt + 1, sizeof(char *));
1329         for (i = 0; i < subcnt; ++i) {
1330             /* resource id = */ getushort(f);
1331             /* rname = (short) */ getushort(f);
1332             /* flags = */ getc(f);
1333             ch1 = getc(f);
1334             ch2 = getc(f);
1335             roff = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
1336             /* mbz = */ getlong(f);
1337             here = ftell(f);
1338             names[i] = TTFGetPSFontName(f, roff + 4, roff + 4);
1339             if (names[i] == NULL) {
1340                 char buffer[32];
1341                 sprintf(buffer, "Nameless%d", i);
1342                 names[i] = copy(buffer);
1343             }
1344             fseek(f, here, SEEK_SET);
1345         }
1346         if (1) {
1347             char *find = fontname;
1348             for (which = subcnt - 1; which >= 0; --which)
1349                 if (strcmp(names[which], find) == 0)
1350                     break;
1351             if (which == -1) {
1352                 char *end;
1353                 which = strtol(find, &end, 10);
1354                 if (*end != '\0')
1355                     which = -1;
1356             }
1357             if (which == -1) {
1358                 ff_post_error(_("Not in Collection"), _("%s is not in %.100s"),
1359                               find, filename);
1360             }
1361         } else {
1362             which = 0;
1363         }
1364         for (i = 0; i < subcnt; ++i)
1365             free(names[i]);
1366         free(names);
1367         fseek(f, rlistpos, SEEK_SET);
1368     }
1369 
1370     for (i = 0; i < subcnt; ++i) {
1371         /* resource id = */ getushort(f);
1372         rname = (short) getushort(f);
1373         /* flags = */ getc(f);
1374         ch1 = getc(f);
1375         ch2 = getc(f);
1376         roff = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
1377         /* mbz = */ getlong(f);
1378         if (i != which)
1379             continue;
1380         here = ftell(f);
1381 
1382         sf = createtmpfile(filename);
1383         ttf = fopen(sf, "wb");
1384         if (ttf == NULL) {
1385             LogError(_("Can't open temporary file for truetype output.\n"));
1386             continue;
1387         }
1388 
1389         fseek(f, roff, SEEK_SET);
1390         ilen = rlen = getlong(f);
1391         if (rlen > 16 * 1024)
1392             ilen = 16 * 1024;
1393         if (ilen > max) {
1394             free(buffer);
1395             max = ilen;
1396             if (max < 0x800)
1397                 max = 0x800;
1398             buffer = malloc(max);
1399         }
1400         for (len = 0; len < rlen;) {
1401             int temp = ilen;
1402             if (rlen - len < ilen)
1403                 temp = rlen - len;
1404             temp = fread(buffer, 1, temp, f);
1405             if (temp == EOF)
1406                 break;
1407             fwrite(buffer, 1, temp, ttf);
1408             len += temp;
1409         }
1410         fclose(ttf);
1411     }
1412     free(buffer);
1413     return sf;
1414 }
1415 
IsResourceForkFile(FILE * f,char * filename,char * fontname)1416 static char *IsResourceForkFile(FILE * f, char *filename, char *fontname)
1417 {
1418     /* If it is a good resource fork then the first 16 bytes are repeated */
1419     /*  at the location specified in bytes 4-7 */
1420     /* We include an offset because if we are looking at a mac binary file */
1421     /*  the resource fork will actually start somewhere in the middle of the */
1422     /*  file, not at the beginning */
1423     unsigned char buffer[16], buffer2[16];
1424     long rdata_pos, map_pos, type_list, name_list, rpos;
1425     int32 rdata_len, map_len;
1426     uint32 fond_pos;
1427     unsigned long tag;
1428     int i, cnt, subcnt;
1429     char *sf = NULL;
1430     fond_pos = 0;
1431     fseek(f, 0, SEEK_SET);
1432     if (fread(buffer, 1, 16, f) != 16)
1433         return (NULL);
1434     rdata_pos =
1435         ((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]);
1436     map_pos =
1437         ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]);
1438     rdata_len =
1439         ((buffer[8] << 24) | (buffer[9] << 16) | (buffer[10] << 8) |
1440          buffer[11]);
1441     map_len =
1442         ((buffer[12] << 24) | (buffer[13] << 16) | (buffer[14] << 8) |
1443          buffer[15]);
1444     if (rdata_pos + rdata_len != map_pos || rdata_len == 0)
1445         return (NULL);
1446     fseek(f, map_pos, SEEK_SET);
1447     buffer2[15] = buffer[15] + 1;       /* make it be different */
1448     if (fread(buffer2, 1, 16, f) != 16)
1449         return (NULL);
1450     for (i = 0; i < 16; ++i)
1451         if (buffer2[i] != 0)
1452             break;
1453     if (i != 16) {
1454         for (i = 0; i < 16; ++i)
1455             if (buffer[i] != buffer2[i])
1456                 return (NULL);
1457     }
1458     getlong(f);                 /* skip the handle to the next resource map */
1459     getushort(f);               /* skip the file resource number */
1460     getushort(f);               /* skip the attributes */
1461     type_list = map_pos + getushort(f);
1462     name_list = map_pos + getushort(f);
1463     fseek(f, type_list, SEEK_SET);
1464     cnt = getushort(f) + 1;
1465     for (i = 0; i < cnt; ++i) {
1466         tag = getlong(f);
1467         subcnt = getushort(f) + 1;
1468         rpos = type_list + getushort(f);
1469         sf = NULL;
1470         if (tag == CHR('s', 'f', 'n', 't')) {
1471             sf = SearchTtfResourcesFile(f, rpos, subcnt, rdata_pos, name_list,
1472                                         filename, fontname);
1473         }
1474         if (sf != NULL)
1475             return (sf);
1476     }
1477     return NULL;
1478 }
1479 
1480 
1481 /* filename "/opt/tex/texmf-fonts/fonts/data/LucidaGrande.dfont",
1482    fontname "Lucida Grande Bold"
1483  */
FindResourceTtfFont(char * filename,char * fontname)1484 char *FindResourceTtfFont(char *filename, char *fontname)
1485 {
1486     char *sf = NULL;
1487     FILE *f = fopen(filename, "rb");
1488     if (f == NULL)
1489         return (NULL);
1490     sf = IsResourceForkFile(f, filename, fontname);
1491     fclose(f);
1492     return sf;
1493 }
1494 
SFReadMacBinary(char * filename,int flags,enum openflags openflags)1495 SplineFont *SFReadMacBinary(char *filename, int flags, enum openflags openflags)
1496 {
1497     SplineFont *sf = FindResourceFile(filename, flags, openflags, NULL, NULL);
1498 
1499     if (sf == NULL)
1500         LogError(_("Couldn't find a font file named %s\n"), filename);
1501     else if (sf == (SplineFont *) (-1)) {
1502         LogError(_
1503                  ("%s is a mac resource file but contains no postscript or truetype fonts\n"),
1504                  filename);
1505         sf = NULL;
1506     }
1507     return (sf);
1508 }
1509 
NamesReadMacBinary(char * filename)1510 char **NamesReadMacBinary(char *filename)
1511 {
1512     return ((char **) FindResourceFile(filename, ttf_onlynames, 0, NULL, NULL));
1513 }
1514 
1515 /* should try to optimize this */
SFReadMacBinaryInfo(char * filename,int flags,enum openflags openflags)1516 SplineFont *SFReadMacBinaryInfo(char *filename, int flags,
1517                                 enum openflags openflags)
1518 {
1519     SplineFont *sf = FindResourceFile(filename, flags, openflags, NULL, NULL);
1520 
1521     if (sf == NULL)
1522         LogError(_("Couldn't find a font file named %s\n"), filename);
1523     else if (sf == (SplineFont *) (-1)) {
1524         LogError(_
1525                  ("%s is a mac resource file but contains no postscript or truetype fonts\n"),
1526                  filename);
1527         sf = NULL;
1528     }
1529     return (sf);
1530 }
1531