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