beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luafontloader / fontforge / fontforge / macbinary.c
blobca8ceed899f65b8bd85cec1f1f9b30c812222241
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:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
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.
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.
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.
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
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 */
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) */
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 */
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) */
106 /* ******************************** Creation ******************************** */
109 struct resource {
110 uint32 pos;
111 uint8 flags;
112 uint16 id;
113 char *name;
114 uint32 nameloc;
115 uint32 nameptloc;
118 struct resourcetype {
119 uint32 tag;
120 struct resource *res;
121 uint32 resloc;
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;
132 enum psstyle_flags { psf_bold = 1, psf_italic = 2, psf_outline = 4,
133 psf_shadow = 0x8, psf_condense = 0x10, psf_extend = 0x20
136 uint16 _MacStyleCode(char *styles, SplineFont * sf, uint16 * psstylecode)
138 unsigned short stylecode = 0, psstyle = 0;
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;
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;
166 if (strstrmatch(styles, "Underline")) {
167 stylecode |= sf_underline;
169 if (strstrmatch(styles, "Outl")) {
170 stylecode |= sf_outline;
171 psstyle |= psf_outline;
173 if (strstr(styles, "Shadow") != NULL) {
174 stylecode |= sf_shadow;
175 psstyle |= psf_shadow;
177 if (strstrmatch(styles, "Cond") || strstr(styles, "Cn") ||
178 strstrmatch(styles, "Narrow")) {
179 stylecode |= sf_condense;
180 psstyle |= psf_condense;
182 if (strstrmatch(styles, "Exte") || strstr(styles, "Ex")) {
183 stylecode |= sf_extend;
184 psstyle |= psf_extend;
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;
197 if (psstylecode != NULL)
198 *psstylecode = psstyle;
199 return (stylecode);
204 /* ******************************** Reading ********************************* */
206 static SplineFont *SearchPostscriptResources(FILE * f, long rlistpos,
207 int subcnt, long rdata_pos,
208 long name_list, int flags)
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);
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);
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;
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;
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);
306 if(fread(buffer, 1, rlen, f) != ((size_t)rlen) ) {
307 LogError(_("Unable to read %u bytes for buffer\n"),rlen);
308 exit(1);
310 fwrite(buffer, 1, rlen, pfb);
312 free(buffer);
313 free(offsets);
314 free(rsrcids);
315 putc(0x80, pfb);
316 putc(3, pfb);
317 fseek(pfb, lenpos, SEEK_SET);
318 putc(len >> 24, pfb);
319 putc((len >> 16) & 0xff, pfb);
320 putc((len >> 8) & 0xff, pfb);
321 putc(len & 0xff, pfb);
322 fseek(f, here, SEEK_SET);
323 rewind(pfb);
324 if (flags & ttf_onlynames)
325 return ((SplineFont *) _NamesReadPostscript(pfb)); /* This closes the font for us */
327 fd = _ReadPSFont(pfb);
328 sf = NULL;
329 if (fd != NULL) {
330 sf = SplineFontFromPSFont(fd);
331 PSFontFree(fd);
332 /* There is no FOND in a postscript file, so we can't read any kerning */
334 fclose(pfb);
335 return (sf);
338 static SplineFont *SearchTtfResources(FILE * f, long rlistpos, int subcnt,
339 long rdata_pos, long name_list,
340 char *filename, int flags,
341 enum openflags openflags)
343 long here, start = ftell(f);
344 long roff;
345 int rname = -1;
346 int ch1, ch2;
347 int len, i, rlen, ilen;
348 /* The sfnt resource is just a copy of the ttf file */
349 char *buffer = NULL;
350 int max = 0;
351 FILE *ttf;
352 SplineFont *sf;
353 int which = 0;
354 char **names;
355 char *pt, *lparen, *rparen;
356 char *chosenname = NULL;
357 (void) name_list;
358 fseek(f, rlistpos, SEEK_SET);
359 if (subcnt > 1 || (flags & ttf_onlynames)) {
360 names = gcalloc(subcnt + 1, sizeof(char *));
361 for (i = 0; i < subcnt; ++i) {
362 /* resource id = */ getushort(f);
363 /* rname = (short) */ getushort(f);
364 /* flags = */ getc(f);
365 ch1 = getc(f);
366 ch2 = getc(f);
367 roff = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
368 /* mbz = */ getlong(f);
369 here = ftell(f);
370 names[i] = TTFGetFontName(f, roff + 4, roff + 4);
371 if (names[i] == NULL) {
372 char buffer[32];
373 sprintf(buffer, "Nameless%d", i);
374 names[i] = copy(buffer);
376 fseek(f, here, SEEK_SET);
378 if (flags & ttf_onlynames) {
379 return ((SplineFont *) names);
381 if ((pt = strrchr(filename, '/')) == NULL)
382 pt = filename;
383 /* Someone gave me a font "Nafees Nastaleeq(Updated).ttf" and complained */
384 /* that ff wouldn't open it */
385 /* Now someone will complain about "Nafees(Updated).ttc(fo(ob)ar)" */
386 if ((lparen = strrchr(pt, '(')) != NULL &&
387 (rparen = strrchr(lparen, ')')) != NULL && rparen[1] == '\0') {
388 char *find = copy(lparen + 1);
389 pt = strchr(find, ')');
390 if (pt != NULL)
391 *pt = '\0';
392 for (which = subcnt - 1; which >= 0; --which)
393 if (strcmp(names[which], find) == 0)
394 break;
395 if (which == -1) {
396 char *end;
397 which = strtol(find, &end, 10);
398 if (*end != '\0')
399 which = -1;
401 if (which == -1) {
402 char *fn = copy(filename);
403 fn[lparen - filename] = '\0';
404 ff_post_error(_("Not in Collection"), _("%s is not in %.100s"),
405 find, fn);
406 free(fn);
408 free(find);
409 } else
410 which = 0;
411 if (lparen == NULL && which != -1)
412 chosenname = copy(names[which]);
413 for (i = 0; i < subcnt; ++i)
414 free(names[i]);
415 free(names);
416 fseek(f, rlistpos, SEEK_SET);
419 for (i = 0; i < subcnt; ++i) {
420 /* resource id = */ getushort(f);
421 rname = (short) getushort(f);
422 /* flags = */ getc(f);
423 ch1 = getc(f);
424 ch2 = getc(f);
425 roff = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
426 /* mbz = */ getlong(f);
427 if (i != which)
428 continue;
429 here = ftell(f);
431 ttf = tmpfile();
432 if (ttf == NULL) {
433 LogError(_("Can't open temporary file for truetype output.\n"));
434 continue;
437 fseek(f, roff, SEEK_SET);
438 ilen = rlen = getlong(f);
439 if (rlen > 16 * 1024)
440 ilen = 16 * 1024;
441 if (ilen > max) {
442 free(buffer);
443 max = ilen;
444 if (max < 0x800)
445 max = 0x800;
446 buffer = malloc(max);
448 for (len = 0; len < rlen;) {
449 int temp = ilen;
450 if (rlen - len < ilen)
451 temp = rlen - len;
452 temp = fread(buffer, 1, temp, f);
453 if (temp == EOF)
454 break;
455 fwrite(buffer, 1, temp, ttf);
456 len += temp;
458 rewind(ttf);
459 sf = _SFReadTTF(ttf, flags, openflags, NULL, NULL);
460 fclose(ttf);
461 if (sf != NULL) {
462 free(buffer);
463 fseek(f, start, SEEK_SET);
464 if (sf->chosenname == NULL)
465 sf->chosenname = chosenname;
466 return (sf);
468 fseek(f, here, SEEK_SET);
470 free(chosenname);
471 free(buffer);
472 fseek(f, start, SEEK_SET);
473 return (NULL);
476 typedef struct fond {
477 char *fondname;
478 int first, last;
479 int assoc_cnt;
480 struct assoc {
481 short size, style, id;
482 } *assoc;
483 /* size==0 => scalable */
484 /* style>>8 is the bit depth (0=>1, 1=>2, 2=>4, 3=>8) */
485 /* search order for ID is sfnt, NFNT, FONT */
486 int stylewidthcnt;
487 struct stylewidths {
488 short style;
489 short *widthtab; /* 4.12 fixed number with the width specified as a fraction of an em */
490 } *stylewidths;
491 int stylekerncnt;
492 struct stylekerns {
493 short style;
494 int kernpairs;
495 struct kerns {
496 unsigned char ch1, ch2;
497 short offset; /* 4.12 */
498 } *kerns;
499 } *stylekerns;
500 char *psnames[48];
501 struct fond *next;
502 } FOND;
504 struct MacFontRec {
505 short fontType;
506 short firstChar;
507 short lastChar;
508 short widthMax;
509 short kernMax; /* bb learing */
510 short Descent; /* maximum negative distance below baseline */
511 short fRectWidth; /* bounding box width */
512 short fRectHeight; /* bounding box height */
513 unsigned short *offsetWidths; /* offset to start of offset/width table */
514 /* 0xffff => undefined, else high byte is offset in locTable, */
515 /* low byte is width */
516 short ascent;
517 short descent;
518 short leading;
519 short rowWords; /* shorts per row */
520 unsigned short *fontImage; /* rowWords*fRectHeight */
521 /* Images for all characters plus one extra for undefined */
522 unsigned short *locs; /* lastchar-firstchar+3 words */
523 /* Horizontal offset to start of n'th character. Note: applies */
524 /* to each row. Missing characters have same loc as following */
527 static void FondListFree(FOND * list)
529 FOND *next;
530 int i;
532 while (list != NULL) {
533 next = list->next;
534 free(list->assoc);
535 for (i = 0; i < list->stylewidthcnt; ++i)
536 free(list->stylewidths[i].widthtab);
537 free(list->stylewidths);
538 for (i = 0; i < list->stylekerncnt; ++i)
539 free(list->stylekerns[i].kerns);
540 free(list->stylekerns);
541 for (i = 0; i < 48; ++i)
542 free(list->psnames[i]);
543 free(list);
544 list = next;
548 /* There's probably only one fond in the file, but there could be more so be */
549 /* prepared... */
550 /* I want the fond: */
551 /* to get the fractional widths for the SWIDTH entry on bdf */
552 /* to get the font name */
553 /* to get the font association tables */
554 /* to get the style flags */
555 /* http://developer.apple.com/techpubs/mac/Text/Text-269.html */
556 static FOND *BuildFondList(FILE * f, long rlistpos, int subcnt, long rdata_pos,
557 long name_list, int flags)
559 long here, start = ftell(f);
560 long offset;
561 int rname = -1;
562 char name[300];
563 int ch1, ch2;
564 int i, j, k, cnt, isfixed;
565 FOND *head = NULL, *cur;
566 long widoff, kernoff, styleoff;
568 fseek(f, rlistpos, SEEK_SET);
569 for (i = 0; i < subcnt; ++i) {
570 /* resource id = */ getushort(f);
571 rname = (short) getushort(f);
572 /* flags = */ getc(f);
573 ch1 = getc(f);
574 ch2 = getc(f);
575 offset = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
576 /* mbz = */ getlong(f);
577 here = ftell(f);
579 cur = gcalloc(1, sizeof(FOND));
580 cur->next = head;
581 head = cur;
583 if (rname != -1) {
584 fseek(f, name_list + rname, SEEK_SET);
585 ch1 = getc(f);
586 if( fread(name, 1, ch1, f) != ((size_t)ch1)) {
587 LogError(_("Unable to read %u bytes for name, but going on.\n"),ch1);
589 name[ch1] = '\0';
590 cur->fondname = copy(name);
593 offset += 4;
594 fseek(f, offset, SEEK_SET);
595 isfixed = getushort(f) & 0x8000 ? 1 : 0;
596 /* family id = */ getushort(f);
597 cur->first = getushort(f);
598 cur->last = getushort(f);
599 /* on a 1 point font... */
600 /* ascent = */ getushort(f);
601 /* descent = (short) */ getushort(f);
602 /* leading = */ getushort(f);
603 /* widmax = */ getushort(f);
604 if ((widoff = getlong(f)) != 0)
605 widoff += offset;
606 if ((kernoff = getlong(f)) != 0)
607 kernoff += offset;
608 if ((styleoff = getlong(f)) != 0)
609 styleoff += offset;
610 for (j = 0; j < 9; ++j)
611 getushort(f);
612 /* internal & undefined, for international scripts = */ getlong(f);
613 /* version = */ getushort(f);
614 cur->assoc_cnt = getushort(f) + 1;
615 cur->assoc = gcalloc(cur->assoc_cnt, sizeof(struct assoc));
616 for (j = 0; j < cur->assoc_cnt; ++j) {
617 cur->assoc[j].size = getushort(f);
618 cur->assoc[j].style = getushort(f);
619 cur->assoc[j].id = getushort(f);
621 if (widoff != 0) {
622 fseek(f, widoff, SEEK_SET);
623 cnt = getushort(f) + 1;
624 cur->stylewidthcnt = cnt;
625 cur->stylewidths = gcalloc(cnt, sizeof(struct stylewidths));
626 for (j = 0; j < cnt; ++j) {
627 cur->stylewidths[j].style = getushort(f);
628 cur->stylewidths[j].widthtab =
629 galloc((cur->last - cur->first + 3) * sizeof(short));
630 for (k = cur->first; k <= cur->last + 2; ++k)
631 cur->stylewidths[j].widthtab[k] = getushort(f);
634 if (kernoff != 0 && (flags & ttf_onlykerns)) {
635 fseek(f, kernoff, SEEK_SET);
636 cnt = getushort(f) + 1;
637 cur->stylekerncnt = cnt;
638 cur->stylekerns = gcalloc(cnt, sizeof(struct stylekerns));
639 for (j = 0; j < cnt; ++j) {
640 cur->stylekerns[j].style = getushort(f);
641 cur->stylekerns[j].kernpairs = getushort(f);
642 cur->stylekerns[j].kerns =
643 galloc(cur->stylekerns[j].kernpairs * sizeof(struct kerns));
644 for (k = 0; k < cur->stylekerns[j].kernpairs; ++k) {
645 cur->stylekerns[j].kerns[k].ch1 = getc(f);
646 cur->stylekerns[j].kerns[k].ch2 = getc(f);
647 cur->stylekerns[j].kerns[k].offset = getushort(f);
651 if (styleoff != 0) {
652 uint8 stringoffsets[48];
653 int strcnt, stringlen, format;
654 char **strings, *pt;
655 fseek(f, styleoff, SEEK_SET);
656 /* class = */ getushort(f);
657 /* glyph encoding offset = */ getlong(f);
658 /* reserved = */ getlong(f);
659 for (j = 0; j < 48; ++j)
660 stringoffsets[j] = getc(f);
661 strcnt = getushort(f);
662 strings = galloc(strcnt * sizeof(char *));
663 for (j = 0; j < strcnt; ++j) {
664 stringlen = getc(f);
665 strings[j] = galloc(stringlen + 2);
666 strings[j][0] = stringlen;
667 strings[j][stringlen + 1] = '\0';
668 for (k = 0; k < stringlen; ++k)
669 strings[j][k + 1] = getc(f);
671 for (j = 0; j < 48; ++j) {
672 for (k = j - 1; k >= 0; --k)
673 if (stringoffsets[j] == stringoffsets[k])
674 break;
675 if (k != -1)
676 continue; /* this style doesn't exist */
677 format = stringoffsets[j] - 1;
678 stringlen = strings[0][0];
679 if (format != 0)
680 for (k = 0; k < strings[format][0]; ++k)
681 stringlen += strings[strings[format][k + 1] - 1][0];
682 pt = cur->psnames[j] = galloc(stringlen + 1);
683 strcpy(pt, strings[0] + 1);
684 pt += strings[0][0];
685 if (format != 0)
686 for (k = 0; k < strings[format][0]; ++k) {
687 strcpy(pt, strings[strings[format][k + 1] - 1] + 1);
688 pt += strings[strings[format][k + 1] - 1][0];
690 *pt = '\0';
692 for (j = 0; j < strcnt; ++j)
693 free(strings[j]);
694 free(strings);
696 fseek(f, here, SEEK_SET);
698 fseek(f, start, SEEK_SET);
699 return (head);
702 static char *BuildName(char *family, int style)
704 char buffer[350] = "";
706 strncpy(buffer, family, 200);
707 if (style != 0)
708 strcat(buffer, "-");
709 if (style & sf_bold)
710 strcat(buffer, "Bold");
711 if (style & sf_italic)
712 strcat(buffer, "Italic");
713 if (style & sf_underline)
714 strcat(buffer, "Underline");
715 if (style & sf_outline)
716 strcat(buffer, "Outline");
717 if (style & sf_shadow)
718 strcat(buffer, "Shadow");
719 if (style & sf_condense)
720 strcat(buffer, "Condensed");
721 if (style & sf_extend)
722 strcat(buffer, "Extended");
723 return (copy(buffer));
726 static int GuessStyle(char *fontname, int *styles, int style_cnt)
728 int which, style;
729 char *stylenames = _GetModifiers(fontname, NULL, NULL);
731 style = _MacStyleCode(stylenames, NULL, NULL);
732 for (which = style_cnt; which >= 0; --which)
733 if (styles[which] == style)
734 return (which);
736 return (-1);
739 static FOND *PickFOND(FOND * fondlist, char *filename, char **name, int *style)
741 int i, j;
742 FOND *test;
743 uint8 stylesused[96];
744 char **names;
745 FOND **fonds = NULL, *fond = NULL;
746 int *styles = NULL;
747 int cnt, which;
748 char *pt, *lparen;
749 char *find = NULL;
751 if ((pt = strrchr(filename, '/')) != NULL)
752 pt = filename;
753 if ((lparen = strchr(filename, '(')) != NULL && strchr(lparen, ')') != NULL) {
754 find = copy(lparen + 1);
755 pt = strchr(find, ')');
756 if (pt != NULL)
757 *pt = '\0';
758 for (test = fondlist; test != NULL; test = test->next) {
759 for (i = 0; i < 48; ++i)
760 if (test->psnames[i] != NULL
761 && strcmp(find, test->psnames[i]) == 0) {
762 *style = (i & 3) | ((i & ~3) << 1); /* PS styles skip underline bit */
763 *name = copy(test->psnames[i]);
764 return (test);
769 /* The file may contain multiple families, and each family may contain */
770 /* multiple styles (and each style may contain multiple sizes, but that's */
771 /* not an issue for us here) */
772 names = NULL;
773 for (i = 0; i < 2; ++i) {
774 cnt = 0;
775 for (test = fondlist; test != NULL; test = test->next)
776 if (test->fondname != NULL) {
777 memset(stylesused, 0, sizeof(stylesused));
778 for (j = 0; j < test->assoc_cnt; ++j) {
779 if (test->assoc[j].size != 0
780 && !stylesused[test->assoc[j].style]) {
781 stylesused[test->assoc[j].style] = true;
782 if (names != NULL) {
783 names[cnt] =
784 BuildName(test->fondname, test->assoc[j].style);
785 styles[cnt] = test->assoc[j].style;
786 fonds[cnt] = test;
788 ++cnt;
792 if (names == NULL) {
793 names = gcalloc(cnt + 1, sizeof(char *));
794 fonds = galloc(cnt * sizeof(FOND *));
795 styles = galloc(cnt * sizeof(int));
799 if (find != NULL) {
800 for (which = cnt - 1; which >= 0; --which)
801 if (strcmp(names[which], find) == 0)
802 break;
803 if (which == -1 && strstrmatch(find, test->fondname) != NULL)
804 which = GuessStyle(find, styles, cnt);
805 if (which == -1) {
806 char *fn = copy(filename);
807 fn[lparen - filename] = '\0';
808 ff_post_error(_("Not in Collection"), _("%s is not in %.100s"),
809 find, fn);
810 free(fn);
812 free(find);
813 } else
814 which = 0;
816 if (which != -1) {
817 fond = fonds[which];
818 *name = copy(names[which]);
819 *style = styles[which];
821 for (i = 0; i < cnt; ++i)
822 free(names[i]);
823 free(names);
824 free(fonds);
825 free(styles);
826 if (which == -1)
827 return (NULL);
829 return (fond);
833 /* Look for kerning info and merge it into the currently existing font "into" */
834 static SplineFont *FindFamilyStyleKerns(SplineFont * into, EncMap * map,
835 FOND * fondlist, char *filename)
837 char *name;
838 int style;
839 FOND *fond;
840 int i, j;
841 int ch1, ch2, offset;
842 KernPair *kp;
843 SplineChar *sc1, *sc2;
845 fond = PickFOND(fondlist, filename, &name, &style);
846 if (fond == NULL || into == NULL)
847 return (NULL);
848 for (i = 0; i < fond->stylekerncnt; ++i)
849 if (fond->stylekerns[i].style == style)
850 break;
851 if (i == fond->stylekerncnt) {
852 LogError(_("No kerning table for %s\n"), name);
853 free(name);
854 return (NULL);
856 for (j = 0; j < fond->stylekerns[i].kernpairs; ++j) {
857 ch1 = fond->stylekerns[i].kerns[j].ch1;
858 ch2 = fond->stylekerns[i].kerns[j].ch2;
859 offset =
860 (fond->stylekerns[i].kerns[j].offset *
861 (into->ascent + into->descent) + (1 << 11)) >> 12;
862 sc1 = SFMakeChar(into, map, ch1);
863 sc2 = SFMakeChar(into, map, ch2);
864 for (kp = sc1->kerns; kp != NULL; kp = kp->next)
865 if (kp->sc == sc2)
866 break;
867 if (kp == NULL) {
868 uint32 script;
869 kp = chunkalloc(sizeof(KernPair));
870 kp->sc = sc2;
871 kp->next = sc1->kerns;
872 sc1->kerns = kp;
873 script = SCScriptFromUnicode(sc1);
874 if (script == DEFAULT_SCRIPT)
875 script = SCScriptFromUnicode(sc2);
876 kp->subtable =
877 SFSubTableFindOrMake(sc1->parent, CHR('k', 'e', 'r', 'n'),
878 script, gpos_pair);
880 kp->off = offset;
882 return (into);
885 /* Look for a bare truetype font in a binhex/macbinary wrapper */
886 static SplineFont *MightBeTrueType(FILE * binary, int32 pos, int32 dlen,
887 int flags, enum openflags openflags)
889 FILE *temp ;
890 char *buffer ;
891 int len;
892 SplineFont *sf;
894 if (flags & ttf_onlynames) {
895 char **ret;
896 char *temp = TTFGetFontName(binary, pos, pos);
897 if (temp == NULL)
898 return (NULL);
899 ret = galloc(2 * sizeof(char *));
900 ret[0] = temp;
901 ret[1] = NULL;
902 return ((SplineFont *) ret);
904 temp = tmpfile();
905 buffer = galloc(8192);
908 fseek(binary, pos, SEEK_SET);
909 while (dlen > 0) {
910 len = dlen > 8192 ? 8192 : dlen;
911 len = fread(buffer, 1, dlen > 8192 ? 8192 : dlen, binary);
912 if (len == 0)
913 break;
914 fwrite(buffer, 1, len, temp);
915 dlen -= len;
917 rewind(temp);
918 sf = _SFReadTTF(temp, flags, openflags, NULL, NULL);
919 fclose(temp);
920 free(buffer);
921 return (sf);
924 static SplineFont *IsResourceFork(FILE * f, long offset, char *filename,
925 int flags, enum openflags openflags,
926 SplineFont * into, EncMap * map)
928 /* If it is a good resource fork then the first 16 bytes are repeated */
929 /* at the location specified in bytes 4-7 */
930 /* We include an offset because if we are looking at a mac binary file */
931 /* the resource fork will actually start somewhere in the middle of the */
932 /* file, not at the beginning */
933 unsigned char buffer[16], buffer2[16];
934 long rdata_pos, map_pos, type_list, name_list, rpos;
935 int32 rdata_len, map_len;
936 uint32 nfnt_pos, font_pos, fond_pos;
937 unsigned long tag;
938 int i, cnt, subcnt, nfnt_subcnt = 0, font_subcnt = 0, fond_subcnt = 0;
939 SplineFont *sf;
940 FOND *fondlist = NULL;
941 fond_pos = 0;
942 fseek(f, offset, SEEK_SET);
943 if (fread(buffer, 1, 16, f) != 16)
944 return (NULL);
945 rdata_pos =
946 offset +
947 ((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]);
948 map_pos =
949 offset +
950 ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]);
951 rdata_len =
952 ((buffer[8] << 24) | (buffer[9] << 16) | (buffer[10] << 8) |
953 buffer[11]);
954 map_len =
955 ((buffer[12] << 24) | (buffer[13] << 16) | (buffer[14] << 8) |
956 buffer[15]);
957 if (rdata_pos + rdata_len != map_pos || rdata_len == 0)
958 return (NULL);
959 fseek(f, map_pos, SEEK_SET);
960 buffer2[15] = buffer[15] + 1; /* make it be different */
961 if (fread(buffer2, 1, 16, f) != 16)
962 return (NULL);
964 /* Apple's data fork resources appear to have a bunch of zeroes here instead */
965 /* of a copy of the first 16 bytes */
966 for (i = 0; i < 16; ++i)
967 if (buffer2[i] != 0)
968 break;
969 if (i != 16) {
970 for (i = 0; i < 16; ++i)
971 if (buffer[i] != buffer2[i])
972 return (NULL);
974 getlong(f); /* skip the handle to the next resource map */
975 getushort(f); /* skip the file resource number */
976 getushort(f); /* skip the attributes */
977 type_list = map_pos + getushort(f);
978 name_list = map_pos + getushort(f);
980 fseek(f, type_list, SEEK_SET);
981 cnt = getushort(f) + 1;
982 for (i = 0; i < cnt; ++i) {
983 tag = getlong(f);
984 /* printf( "%c%c%c%c\n", tag>>24, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff ); */
985 subcnt = getushort(f) + 1;
986 rpos = type_list + getushort(f);
987 sf = NULL;
988 if (tag == CHR('P', 'O', 'S', 'T') && !(flags & (ttf_onlystrikes | ttf_onlykerns))) /* No FOND */
989 sf = SearchPostscriptResources(f, rpos, subcnt, rdata_pos,
990 name_list, flags);
991 else if (tag == CHR('s', 'f', 'n', 't') && !(flags & ttf_onlykerns))
992 sf = SearchTtfResources(f, rpos, subcnt, rdata_pos, name_list,
993 filename, flags, openflags);
994 else if (tag == CHR('N', 'F', 'N', 'T')) {
995 nfnt_pos = rpos;
996 nfnt_subcnt = subcnt;
997 } else if (tag == CHR('F', 'O', 'N', 'T')) {
998 font_pos = rpos;
999 font_subcnt = subcnt;
1000 } else if (tag == CHR('F', 'O', 'N', 'D')) {
1001 fond_pos = rpos;
1002 fond_subcnt = subcnt;
1004 if (sf != NULL)
1005 return (sf);
1007 if (flags & ttf_onlynames) /* Not interested in bitmap resources here */
1008 return (NULL);
1010 if (flags & ttf_onlykerns) { /* For kerns */
1011 if (fond_subcnt != 0)
1012 fondlist =
1013 BuildFondList(f, fond_pos, fond_subcnt, rdata_pos, name_list,
1014 flags);
1015 into = FindFamilyStyleKerns(into, map, fondlist, filename);
1016 FondListFree(fondlist);
1017 return (into);
1019 /* Ok. If no outline font, try for a bitmap */
1020 if (nfnt_subcnt == 0) {
1021 nfnt_pos = font_pos;
1022 nfnt_subcnt = font_subcnt;
1024 return ((SplineFont *) - 1); /* It's a valid resource file, but just has no fonts */
1028 static SplineFont *IsResourceInBinary(FILE * f, char *filename, int flags,
1029 enum openflags openflags,
1030 SplineFont * into, EncMap * map)
1032 unsigned char header[128];
1033 unsigned long offset, dlen, rlen;
1035 if (fread(header, 1, 128, f) != 128)
1036 return (NULL);
1037 if (header[0] != 0 || header[74] != 0 || header[82] != 0 || header[1] <= 0
1038 || header[1] > 33 || header[63] != 0 || header[2 + header[1]] != 0)
1039 return (NULL);
1040 dlen =
1041 ((header[0x53] << 24) | (header[0x54] << 16) | (header[0x55] << 8) |
1042 header[0x56]);
1043 rlen =
1044 ((header[0x57] << 24) | (header[0x58] << 16) | (header[0x59] << 8) |
1045 header[0x5a]);
1046 /* 128 bytes for header, then the dlen is padded to a 128 byte boundary */
1047 offset = 128 + ((dlen + 127) & ~127);
1048 /* Look for a bare truetype font in a binhex/macbinary wrapper */
1049 if (dlen != 0 && rlen <= dlen) {
1050 int pos = ftell(f);
1051 if (fread(header, 1, 4, f) != ((size_t)4)) {
1052 LogError(_("Unable to read 4 bytes for header, but going on.\n"));
1054 header[5] = '\0';
1055 if (strcmp((char *) header, "OTTO") == 0
1056 || strcmp((char *) header, "true") == 0
1057 || strcmp((char *) header, "ttcf") == 0 || (header[0] == 0
1058 && header[1] == 1
1059 && header[2] == 0
1060 && header[3] == 0))
1061 return (MightBeTrueType(f, pos, dlen, flags, openflags));
1063 return (IsResourceFork(f, offset, filename, flags, openflags, into, map));
1066 static int lastch = 0, repeat = 0;
1067 static void outchr(FILE * binary, int ch)
1069 int i;
1071 if (repeat) {
1072 if (ch == 0) {
1073 /* no repeat, output a literal 0x90 (the repeat flag) */
1074 lastch = 0x90;
1075 putc(lastch, binary);
1076 } else {
1077 for (i = 1; i < ch; ++i)
1078 putc(lastch, binary);
1080 repeat = 0;
1081 } else if (ch == 0x90) {
1082 repeat = 1;
1083 } else {
1084 putc(ch, binary);
1085 lastch = ch;
1089 static SplineFont *IsResourceInHex(FILE * f, char *filename, int flags,
1090 enum openflags openflags, SplineFont * into,
1091 EncMap * map)
1093 /* convert file from 6bit to 8bit */
1094 /* interesting data is enclosed between two colons */
1095 FILE *binary = tmpfile();
1096 char *sixbit =
1097 "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
1098 int ch, val, cnt, i, dlen, rlen;
1099 unsigned char header[20];
1100 char *pt;
1101 SplineFont *ret;
1103 if (binary == NULL) {
1104 LogError(_("can't create temporary file\n"));
1105 return (NULL);
1108 lastch = repeat = 0;
1109 while ((ch = getc(f)) != ':'); /* There may be comments before file start */
1110 cnt = val = 0;
1111 while ((ch = getc(f)) != ':') {
1112 if (isspace(ch))
1113 continue;
1114 for (pt = sixbit; *pt != ch && *pt != '\0'; ++pt);
1115 if (*pt == '\0') {
1116 fclose(binary);
1117 return (NULL);
1119 val = (val << 6) | (pt - sixbit);
1120 if (++cnt == 4) {
1121 outchr(binary, (val >> 16) & 0xff);
1122 outchr(binary, (val >> 8) & 0xff);
1123 outchr(binary, val & 0xff);
1124 val = cnt = 0;
1127 if (cnt != 0) {
1128 if (cnt == 1)
1129 outchr(binary, val << 2);
1130 else if (cnt == 2) {
1131 val <<= 4;
1132 outchr(binary, (val >> 8) & 0xff);
1133 outchr(binary, val & 0xff);
1134 } else if (cnt == 3) {
1135 val <<= 6;
1136 outchr(binary, (val >> 16) & 0xff);
1137 outchr(binary, (val >> 8) & 0xff);
1138 outchr(binary, val & 0xff);
1142 rewind(binary);
1143 ch = getc(binary); /* Name length */
1144 /* skip name */
1145 for (i = 0; i < ch; ++i)
1146 getc(binary);
1147 if (getc(binary) != '\0') {
1148 fclose(binary);
1149 return (NULL);
1151 if ( fread(header, 1, 20, binary) != 20 ) {
1152 LogError(_("Can't read 20 bytes for header\n"));
1153 return (NULL);
1155 dlen =
1156 (header[10] << 24) | (header[11] << 16) | (header[12] << 8) |
1157 header[13];
1158 rlen =
1159 (header[14] << 24) | (header[15] << 16) | (header[16] << 8) |
1160 header[17];
1161 /* Look for a bare truetype font in a binhex/macbinary wrapper */
1162 if (dlen != 0 && rlen < dlen) {
1163 int pos = ftell(binary);
1164 if (fread(header, 1, 4, binary) != 4) {
1165 LogError(_("Can't read 4 bytes for header\n"));
1166 return (NULL);
1168 header[5] = '\0';
1169 if (strcmp((char *) header, "OTTO") == 0
1170 || strcmp((char *) header, "true") == 0
1171 || strcmp((char *) header, "ttcf") == 0 || (header[0] == 0
1172 && header[1] == 1
1173 && header[2] == 0
1174 && header[3] == 0)) {
1175 ret = MightBeTrueType(binary, pos, dlen, flags, openflags);
1176 fclose(binary);
1177 return (ret);
1180 if (rlen == 0) {
1181 fclose(binary);
1182 return (NULL);
1185 ret =
1186 IsResourceFork(binary, ftell(binary) + dlen + 2, filename, flags,
1187 openflags, into, map);
1189 fclose(binary);
1190 return (ret);
1193 static SplineFont *IsResourceInFile(char *filename, int flags,
1194 enum openflags openflags, SplineFont * into,
1195 EncMap * map)
1197 FILE *f;
1198 char *spt, *pt;
1199 SplineFont *sf;
1200 char *temp = filename, *lparen;
1202 if ((pt = strrchr(filename, '/')) == NULL)
1203 pt = filename;
1204 if ((lparen = strchr(pt, '(')) != NULL && strchr(lparen, ')') != NULL) {
1205 temp = copy(filename);
1206 temp[lparen - filename] = '\0';
1208 f = fopen(temp, "rb");
1209 if (temp != filename)
1210 free(temp);
1211 if (f == NULL)
1212 return (NULL);
1213 spt = strrchr(filename, '/');
1214 if (spt == NULL)
1215 spt = filename;
1216 pt = strrchr(spt, '.');
1217 if (pt != NULL && (pt[1] == 'b' || pt[1] == 'B')
1218 && (pt[2] == 'i' || pt[2] == 'I') && (pt[3] == 'n' || pt[3] == 'N')
1219 && (pt[4] == '\0' || pt[4] == '(')) {
1220 if ((sf = IsResourceInBinary(f, filename, flags, openflags, into, map))) {
1221 fclose(f);
1222 return (sf);
1224 } else if (pt != NULL && (pt[1] == 'h' || pt[1] == 'H')
1225 && (pt[2] == 'q' || pt[2] == 'Q') && (pt[3] == 'x'
1226 || pt[3] == 'X')
1227 && (pt[4] == '\0' || pt[4] == '(')) {
1228 if ((sf = IsResourceInHex(f, filename, flags, openflags, into, map))) {
1229 fclose(f);
1230 return (sf);
1234 sf = IsResourceFork(f, 0, filename, flags, openflags, into, map);
1235 fclose(f);
1236 #if __Mac
1237 if (sf == NULL)
1238 sf = HasResourceFork(filename, flags, openflags, into, map);
1239 #endif
1240 return (sf);
1243 static SplineFont *FindResourceFile(char *filename, int flags,
1244 enum openflags openflags, SplineFont * into,
1245 EncMap * map)
1247 char *spt, *pt, *dpt;
1248 char buffer[1400];
1249 SplineFont *sf;
1251 if ((sf = IsResourceInFile(filename, flags, openflags, into, map)))
1252 return (sf);
1254 /* Well, look in the resource fork directory (if it exists), the resource */
1255 /* fork is placed there in a seperate file on (some) non-Mac disks */
1256 strcpy(buffer, filename);
1257 spt = strrchr(buffer, '/');
1258 if (spt == NULL) {
1259 spt = buffer;
1260 pt = filename;
1261 } else {
1262 ++spt;
1263 pt = filename + (spt - buffer);
1265 strcpy(spt, "resource.frk/");
1266 strcat(spt, pt);
1267 if ((sf = IsResourceInFile(buffer, flags, openflags, into, map)))
1268 return (sf);
1270 /* however the resource fork does not appear to do long names properly */
1271 /* names are always lower case 8.3, do some simple things to check */
1272 spt = strrchr(buffer, '/') + 1;
1273 for (pt = spt; *pt; ++pt)
1274 if (isupper(*pt))
1275 *pt = tolower(*pt);
1276 dpt = strchr(spt, '.');
1277 if (dpt == NULL)
1278 dpt = spt + strlen(spt);
1279 if (dpt - spt > 8 || strlen(dpt) > 4) {
1280 char exten[8];
1281 strncpy(exten, dpt, 7);
1282 exten[4] = '\0'; /* it includes the dot */
1283 if (dpt - spt > 6)
1284 dpt = spt + 6;
1285 *dpt++ = '~';
1286 *dpt++ = '1';
1287 strcpy(dpt, exten);
1289 return (IsResourceInFile(buffer, flags, openflags, into, map));
1293 static char *createtmpfile(char *filename)
1295 char *p, *tempname;
1296 p = strrchr(filename,'/');
1297 if (p != NULL) {
1298 filename = p+1;
1300 assert(strlen(filename)>=5);
1301 tempname = malloc(strlen(filename)+2);
1302 if (tempname == NULL) {
1303 LogError(_("Out of memory\n"));
1304 exit(1);
1306 strcpy(tempname,filename);
1307 strcpy(tempname+strlen(tempname)-5,"XXXXXX"); /* dfont -> XXXXXX */
1309 #ifdef HAVE_MKSTEMP
1311 int i = mkstemp(tempname);
1312 if (i) {
1313 close(i);
1316 #else
1317 mktemp(tempname);
1318 #endif
1319 return tempname;
1322 static char *SearchTtfResourcesFile(FILE * f, long rlistpos, int subcnt,
1323 long rdata_pos, long name_list,
1324 char *filename, char *fontname)
1326 long here;
1327 long roff;
1328 int rname = -1;
1329 int ch1, ch2;
1330 int len, i, rlen, ilen;
1331 /* The sfnt resource is just a copy of the ttf file */
1332 char *buffer = NULL;
1333 int max = 0;
1334 FILE *ttf;
1335 char *sf = NULL;
1336 int which = 0;
1337 char **names;
1338 (void)name_list;
1339 fseek(f, rlistpos, SEEK_SET);
1340 if (subcnt > 1) {
1341 names = gcalloc(subcnt + 1, sizeof(char *));
1342 for (i = 0; i < subcnt; ++i) {
1343 /* resource id = */ getushort(f);
1344 /* rname = (short) */ getushort(f);
1345 /* flags = */ getc(f);
1346 ch1 = getc(f);
1347 ch2 = getc(f);
1348 roff = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
1349 /* mbz = */ getlong(f);
1350 here = ftell(f);
1351 names[i] = TTFGetPSFontName(f, roff + 4, roff + 4);
1352 if (names[i] == NULL) {
1353 char buffer[32];
1354 sprintf(buffer, "Nameless%d", i);
1355 names[i] = copy(buffer);
1357 fseek(f, here, SEEK_SET);
1359 if (1) {
1360 char *find = fontname;
1361 for (which = subcnt - 1; which >= 0; --which)
1362 if (strcmp(names[which], find) == 0)
1363 break;
1364 if (which == -1) {
1365 char *end;
1366 which = strtol(find, &end, 10);
1367 if (*end != '\0')
1368 which = -1;
1370 if (which == -1) {
1371 ff_post_error(_("Not in Collection"), _("%s is not in %.100s"),
1372 find, filename);
1374 } else {
1375 which = 0;
1377 for (i = 0; i < subcnt; ++i)
1378 free(names[i]);
1379 free(names);
1380 fseek(f, rlistpos, SEEK_SET);
1383 for (i = 0; i < subcnt; ++i) {
1384 /* resource id = */ getushort(f);
1385 rname = (short) getushort(f);
1386 /* flags = */ getc(f);
1387 ch1 = getc(f);
1388 ch2 = getc(f);
1389 roff = rdata_pos + ((ch1 << 16) | (ch2 << 8) | getc(f));
1390 /* mbz = */ getlong(f);
1391 if (i != which)
1392 continue;
1393 here = ftell(f);
1395 sf = createtmpfile(filename);
1396 ttf = fopen(sf, "wb");
1397 if (ttf == NULL) {
1398 LogError(_("Can't open temporary file for truetype output.\n"));
1399 continue;
1402 fseek(f, roff, SEEK_SET);
1403 ilen = rlen = getlong(f);
1404 if (rlen > 16 * 1024)
1405 ilen = 16 * 1024;
1406 if (ilen > max) {
1407 free(buffer);
1408 max = ilen;
1409 if (max < 0x800)
1410 max = 0x800;
1411 buffer = malloc(max);
1413 for (len = 0; len < rlen;) {
1414 int temp = ilen;
1415 if (rlen - len < ilen)
1416 temp = rlen - len;
1417 temp = fread(buffer, 1, temp, f);
1418 if (temp == EOF)
1419 break;
1420 fwrite(buffer, 1, temp, ttf);
1421 len += temp;
1423 fclose(ttf);
1425 free(buffer);
1426 return sf;
1429 static char *IsResourceForkFile(FILE * f, char *filename, char *fontname)
1431 /* If it is a good resource fork then the first 16 bytes are repeated */
1432 /* at the location specified in bytes 4-7 */
1433 /* We include an offset because if we are looking at a mac binary file */
1434 /* the resource fork will actually start somewhere in the middle of the */
1435 /* file, not at the beginning */
1436 unsigned char buffer[16], buffer2[16];
1437 long rdata_pos, map_pos, type_list, name_list, rpos;
1438 int32 rdata_len, map_len;
1439 uint32 fond_pos;
1440 unsigned long tag;
1441 int i, cnt, subcnt;
1442 char *sf = NULL;
1443 fond_pos = 0;
1444 fseek(f, 0, SEEK_SET);
1445 if (fread(buffer, 1, 16, f) != 16)
1446 return (NULL);
1447 rdata_pos =
1448 ((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]);
1449 map_pos =
1450 ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]);
1451 rdata_len =
1452 ((buffer[8] << 24) | (buffer[9] << 16) | (buffer[10] << 8) |
1453 buffer[11]);
1454 map_len =
1455 ((buffer[12] << 24) | (buffer[13] << 16) | (buffer[14] << 8) |
1456 buffer[15]);
1457 if (rdata_pos + rdata_len != map_pos || rdata_len == 0)
1458 return (NULL);
1459 fseek(f, map_pos, SEEK_SET);
1460 buffer2[15] = buffer[15] + 1; /* make it be different */
1461 if (fread(buffer2, 1, 16, f) != 16)
1462 return (NULL);
1463 for (i = 0; i < 16; ++i)
1464 if (buffer2[i] != 0)
1465 break;
1466 if (i != 16) {
1467 for (i = 0; i < 16; ++i)
1468 if (buffer[i] != buffer2[i])
1469 return (NULL);
1471 getlong(f); /* skip the handle to the next resource map */
1472 getushort(f); /* skip the file resource number */
1473 getushort(f); /* skip the attributes */
1474 type_list = map_pos + getushort(f);
1475 name_list = map_pos + getushort(f);
1476 fseek(f, type_list, SEEK_SET);
1477 cnt = getushort(f) + 1;
1478 for (i = 0; i < cnt; ++i) {
1479 tag = getlong(f);
1480 subcnt = getushort(f) + 1;
1481 rpos = type_list + getushort(f);
1482 sf = NULL;
1483 if (tag == CHR('s', 'f', 'n', 't')) {
1484 sf = SearchTtfResourcesFile(f, rpos, subcnt, rdata_pos, name_list,
1485 filename, fontname);
1487 if (sf != NULL)
1488 return (sf);
1490 return NULL;
1494 /* filename "/opt/tex/texmf-fonts/fonts/data/LucidaGrande.dfont",
1495 fontname "Lucida Grande Bold"
1497 char *FindResourceTtfFont(char *filename, char *fontname)
1499 char *sf = NULL;
1500 FILE *f = fopen(filename, "rb");
1501 if (f == NULL)
1502 return (NULL);
1503 sf = IsResourceForkFile(f, filename, fontname);
1504 fclose(f);
1505 return sf;
1508 SplineFont *SFReadMacBinary(char *filename, int flags, enum openflags openflags)
1510 SplineFont *sf = FindResourceFile(filename, flags, openflags, NULL, NULL);
1512 if (sf == NULL)
1513 LogError(_("Couldn't find a font file named %s\n"), filename);
1514 else if (sf == (SplineFont *) (-1)) {
1515 LogError(_
1516 ("%s is a mac resource file but contains no postscript or truetype fonts\n"),
1517 filename);
1518 sf = NULL;
1520 return (sf);
1523 char **NamesReadMacBinary(char *filename)
1525 return ((char **) FindResourceFile(filename, ttf_onlynames, 0, NULL, NULL));
1528 /* should try to optimize this */
1529 SplineFont *SFReadMacBinaryInfo(char *filename, int flags,
1530 enum openflags openflags)
1532 SplineFont *sf = FindResourceFile(filename, flags, openflags, NULL, NULL);
1534 if (sf == NULL)
1535 LogError(_("Couldn't find a font file named %s\n"), filename);
1536 else if (sf == (SplineFont *) (-1)) {
1537 LogError(_
1538 ("%s is a mac resource file but contains no postscript or truetype fonts\n"),
1539 filename);
1540 sf = NULL;
1542 return (sf);