1 /*
2 Copyright 1996-2014 Han The Thanh, <thanh@pdftex.org>
3 
4 This file is part of pdfTeX.
5 
6 pdfTeX is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 
11 pdfTeX is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License along
17 with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /*
21 #include <kpathsea/c-auto.h>
22 #include <kpathsea/c-fopen.h>
23 #include <kpathsea/c-limits.h>
24 #include <kpathsea/c-memstr.h>
25 #include <kpathsea/c-std.h>
26 #include <kpathsea/c-unistd.h>
27 #include <stdarg.h>
28 #include <kpathsea/getopt.h>
29 */
30 #include <kpathsea/kpathsea.h>
31 #include <time.h>
32 #include <pdftexdir/ptexmac.h>
33 #include <pdftexdir/writettf.h>
34 #include <string.h>
35 
36 /* constants used for print_glyph */
37 #define AS_NAME         0
38 #define AS_INDEX        1
39 #define AS_UNICODE      2
40 
41 #define VERSION         "1.02"
42 
43 /* FIXME */
44 #define NOGLYPH_ASSIGNED_YET USHRT_MAX
45 
46 #define enc_getchar()   xgetc(encfile)
47 #define enc_eof()       feof(encfile)
48 #define pdftex_fail     ttf_fail
49 
50 #define print_str(S)    if (S != NULL) fprintf(outfile, #S " %s\n", escape_eol(S))
51 #define print_dimen(N)  if (N != 0) fprintf(outfile, #N " %i\n", (int)get_ttf_funit(N))
52 
53 #define get_ttf_funit(n) \
54     (n < 0 ? -((-n/upem)*1000 + ((-n%upem)*1000)/upem) :\
55     ((n/upem)*1000 + ((n%upem)*1000)/upem))
56 
57 typedef struct _unicode_entry {
58     TTF_USHORT code;
59     struct _unicode_entry *next;
60 } unicode_entry;
61 
62 typedef struct {
63     TTF_ULONG wx;
64     const char *name;
65     TTF_USHORT index;
66     TTF_LONG bbox[4];
67     TTF_LONG offset;
68     char found;
69     unicode_entry *unicode_list;
70 } mtx_entry;
71 
72 typedef struct _kern_entry {
73     TTF_FWORD value;
74     TTF_USHORT adjacent;
75     struct _kern_entry *next;
76 } kern_entry;
77 
78 
79 char *FontName = NULL;
80 char *FullName = NULL;
81 char *FamilyName = NULL;
82 char *Notice = NULL;
83 char *Version = NULL;
84 char *Weight = NULL;
85 TTF_LONG ItalicAngle = 0;
86 TTF_LONG IsFixedPitch = 0;
87 TTF_LONG FontBBox1 = 0;
88 TTF_LONG FontBBox2 = 0;
89 TTF_LONG FontBBox3 = 0;
90 TTF_LONG FontBBox4 = 0;
91 TTF_LONG UnderlinePosition = 0;
92 TTF_LONG UnderlineThickness = 0;
93 TTF_LONG CapHeight = 0;
94 TTF_LONG XHeight = 0;
95 TTF_LONG Ascender = 0;
96 TTF_LONG Descender = 0;
97 
98 char *cur_file_name = NULL;
99 char *bname = NULL;
100 FILE *fontfile, *encfile, *outfile = NULL;
101 char enc_line[ENC_BUF_SIZE];
102 int print_glyph = AS_NAME;      /* print glyph as names by default */
103 int print_cmap = 0;
104 int use_ext_enc = 0;            /* use external encoding? */
105 int select_unicode = 1;         /* use the first unicode mapping by default */
106 int printing_enc = 0;           /* set to 1 while printing encodings */
107 
108 
109 TTF_USHORT upem;
110 TTF_USHORT ntabs;
111 int nhmtx;
112 int post_format;
113 int loca_format;
114 long nglyphs;
115 int nkernpairs = 0;
116 int names_count = 0;
117 char *ps_glyphs_buf = NULL;
118 dirtab_entry *dir_tab;
119 mtx_entry *mtx_tab;
120 kern_entry *kern_tab;
121 char *enc_names[256];
122 
123 cmap_entry *cmap_tab;
124 TTF_USHORT ncmapsubtabs;
125 long cmap_offset;
126 
127 TTF_USHORT unicode_map[0xFFFF];
128 
129 #include "macnames.c"
130 
131 #if defined __GNUC__ && __GNUC__ >=3
132 __attribute__((__noreturn__))
133 #endif
ttf_fail(const char * fmt,...)134 static void ttf_fail(const char *fmt, ...)
135 {
136     va_list args;
137     va_start(args, fmt);
138     fprintf(stderr, "\nError: ttf2afm");
139     if (cur_file_name)
140         fprintf(stderr, " (file %s)", cur_file_name);
141     fprintf(stderr, ": ");
142     vfprintf(stderr, fmt, args);
143     fprintf(stderr, "\n");
144     va_end(args);
145     exit(-1);
146 }
147 
ttf_warn(const char * fmt,...)148 static void ttf_warn(const char *fmt, ...)
149 {
150     va_list args;
151     va_start(args, fmt);
152     fprintf(stderr, "\nWarning: ttf2afm");
153     if (cur_file_name)
154         fprintf(stderr, " (file %s)", cur_file_name);
155     fprintf(stderr, ": ");
156     vfprintf(stderr, fmt, args);
157     fprintf(stderr, "\n");
158     va_end(args);
159 }
160 
xgetc(FILE * stream)161 static int xgetc(FILE * stream)
162 {
163     int c = getc(stream);
164     if (c < 0 && c != EOF)
165         ttf_fail("getc() failed");
166     return c;
167 }
168 
ttf_getnum(int s)169 static long ttf_getnum(int s)
170 {
171     long i = 0;
172     int c;
173     while (s > 0) {
174         if ((c = xgetc(fontfile)) < 0)
175             ttf_fail("unexpected EOF");
176         i = (i << 8) + c;
177         s--;
178     }
179     return i;
180 }
181 
name_lookup(const char * s)182 static dirtab_entry *name_lookup(const char *s)
183 {
184     dirtab_entry *p;
185     for (p = dir_tab; p - dir_tab < ntabs; p++)
186         if (strncmp(p->tag, s, 4) == 0)
187             break;
188     if (p - dir_tab == ntabs)
189         p = NULL;
190     return p;
191 }
192 
ttf_seek_tab(const char * name,TTF_LONG offset)193 static void ttf_seek_tab(const char *name, TTF_LONG offset)
194 {
195     dirtab_entry *p = name_lookup(name);
196     if (p == NULL)
197         ttf_fail("can't find table `%s'", name);
198     if (fseek(fontfile, p->offset + offset, SEEK_SET) < 0)
199         ttf_fail("fseek() failed while reading `%s' table", name);
200 }
201 
ttf_seek_off(const char * name,TTF_LONG offset)202 static void ttf_seek_off(const char *name, TTF_LONG offset)
203 {
204     if (fseek(fontfile, offset, SEEK_SET) < 0)
205         ttf_fail("fseek() failed while reading `%s' table", name);
206 }
207 
store_kern_value(TTF_USHORT i,TTF_USHORT j,TTF_FWORD v)208 static void store_kern_value(TTF_USHORT i, TTF_USHORT j, TTF_FWORD v)
209 {
210     kern_entry *pk;
211     for (pk = kern_tab + i; pk->next != NULL; pk = pk->next);
212     pk->next = xtalloc(1, kern_entry);
213     pk = pk->next;
214     pk->next = NULL;
215     pk->adjacent = j;
216     pk->value = v;
217 }
218 
219 #if 0 /* unused */
220 static TTF_FWORD get_kern_value(TTF_USHORT i, TTF_USHORT j)
221 {
222     kern_entry *pk;
223     for (pk = kern_tab + i; pk->next != NULL; pk = pk->next)
224         if (pk->adjacent == j)
225             return pk->value;
226     return 0;
227 }
228 #endif
229 
free_tabs(void)230 static void free_tabs(void)
231 {
232     int i;
233     kern_entry *p, *q, *r;
234     unicode_entry *u, *v;
235     mtx_entry *pm;
236     xfree(ps_glyphs_buf);
237     xfree(dir_tab);
238     xfree(cmap_tab);
239     for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
240         if (pm->unicode_list != NULL) {
241             for (u = pm->unicode_list; u != NULL; u = v) {
242                 v = u->next;
243                 xfree(u);
244             }
245         }
246     xfree(mtx_tab);
247     for (i = 0; i < 256; i++)
248         if (enc_names[i] != notdef)
249             free(enc_names[i]);
250     if (kern_tab == NULL)
251         return;
252     for (p = kern_tab; p - kern_tab < nglyphs; p++)
253         if (p->next != NULL) {
254             for (q = p->next; q != NULL; q = r) {
255                 r = q->next;
256                 xfree(q);
257             }
258         }
259     xfree(kern_tab);
260 }
261 
enc_getline(void)262 static void enc_getline(void)
263 {
264     char *p;
265     int c;
266   restart:
267     if (enc_eof())
268         ttf_fail("unexpected end of file");
269     p = enc_line;
270     do {
271         c = enc_getchar();
272         append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE);
273     } while (c != 10);
274     append_eol(p, enc_line, ENC_BUF_SIZE);
275     if (p - enc_line <= 2 || *enc_line == '%')
276         goto restart;
277 }
278 
read_encoding(char * encname)279 static void read_encoding(char *encname)
280 {
281     char buf[ENC_BUF_SIZE], *q, *r;
282     int i;
283     cur_file_name = encname;
284     if ((encfile = kpse_open_file(encname, kpse_enc_format)) == NULL)
285         ttf_fail("can't open encoding file for reading");
286     enc_getline();
287     if (*enc_line != '/' || (r = strchr(enc_line, '[')) == 0)
288         ttf_fail("invalid encoding vector: name or `[' missing:\n%s", enc_line);
289     for (i = 0; i < 256; i++)
290         enc_names[i] = notdef;
291     if (r[1] == 32)
292         r += 2;
293     else
294         r++;
295     for (;;) {
296         while (*r == '/') {
297             for (q = buf, r++; *r != ' ' && *r != 10 && *r != ']' && *r != '/';
298                  *q++ = *r++);
299             *q = 0;
300             if (*r == ' ')
301                 r++;
302             if (strcmp(buf, notdef) != 0)
303                 enc_names[names_count] = xstrdup(buf);
304             if (++names_count > 256)
305                 ttf_fail("encoding vector contains more than 256 names");
306         }
307         if (*r != 10 && *r != '%') {
308             if (str_prefix(r, "] def"))
309                 goto done;
310             else
311                 ttf_fail
312                     ("invalid encoding vector: a name or `] def' expected:\n%s",
313                      enc_line);
314         }
315         enc_getline();
316         r = enc_line;
317     }
318   done:
319     xfclose(encfile, cur_file_name);
320     if (names_count != 256)
321         ttf_warn("encoding vector contains only %i names (expected %i)",
322                  names_count, 256);
323 }
324 
append_unicode(long glyph_index,TTF_USHORT code)325 static void append_unicode(long glyph_index, TTF_USHORT code)
326 {
327     mtx_entry *m;
328     unicode_entry *u, *v;
329     assert(glyph_index >= 0 && glyph_index < nglyphs);
330     u = xtalloc(1, unicode_entry);
331     m = mtx_tab + glyph_index;
332     u->next = NULL;
333     u->code = code;
334     if (m->unicode_list == NULL)
335         m->unicode_list = u;
336     else {
337         for (v = m->unicode_list; v->next != NULL; v = v->next);
338         v->next = u;
339     }
340 }
341 
read_cmap(void)342 static void read_cmap(void)
343 {
344     cmap_entry *e;
345     seg_entry *seg_tab, *s;
346     TTF_USHORT *glyphId, format, segCount;
347     long int n, i, k, length, index;
348     int unicode_map_count = 0;
349     ttf_seek_tab("cmap", TTF_USHORT_SIZE);      /* skip the table version number (=0) */
350     ncmapsubtabs = get_ushort();
351     cmap_offset = xftell(fontfile, cur_file_name) - 2 * TTF_USHORT_SIZE;
352     cmap_tab = xtalloc(ncmapsubtabs, cmap_entry);
353     for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) {
354         e->platform_id = get_ushort();
355         e->encoding_id = get_ushort();
356         e->offset = get_ulong();
357     }
358     for (i = 0; i < 0xFFFF; ++i)
359         unicode_map[i] = NOGLYPH_ASSIGNED_YET;
360     for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) {
361         ttf_seek_off("cmap", cmap_offset + e->offset);
362         format = get_ushort();
363         if (is_unicode_mapping(e) && format == 4) {
364             ++unicode_map_count;
365             if (unicode_map_count == select_unicode)
366                 goto read_unicode_mapping;
367         }
368         continue;
369       read_unicode_mapping:
370         length = get_ushort();  /* length of subtable */
371         (void) get_ushort();    /* skip the version number */
372         segCount = get_ushort() / 2;
373         (void) get_ushort();    /* skip searchRange */
374         (void) get_ushort();    /* skip entrySelector */
375         (void) get_ushort();    /* skip rangeShift */
376         seg_tab = xtalloc(segCount, seg_entry);
377         for (s = seg_tab; s - seg_tab < segCount; s++)
378             s->endCode = get_ushort();
379         (void) get_ushort();    /* skip reversedPad */
380         for (s = seg_tab; s - seg_tab < segCount; s++)
381             s->startCode = get_ushort();
382         for (s = seg_tab; s - seg_tab < segCount; s++)
383             s->idDelta = get_ushort();
384         for (s = seg_tab; s - seg_tab < segCount; s++)
385             s->idRangeOffset = get_ushort();
386         length -= 8 * TTF_USHORT_SIZE + 4 * segCount * TTF_USHORT_SIZE;
387         n = length / TTF_USHORT_SIZE;   /* number of glyphID's */
388         glyphId = xtalloc(n, TTF_USHORT);
389         for (i = 0; i < n; i++)
390             glyphId[i] = get_ushort();
391         for (s = seg_tab; s - seg_tab < segCount; s++) {
392             for (i = s->startCode; i <= s->endCode; i++) {
393                 if (i == 0xFFFF)
394                     break;
395                 if (s->idRangeOffset != 0xFFFF) {
396                     if (s->idRangeOffset == 0)
397                         index = (s->idDelta + i) & 0xFFFF;
398                     else {
399                         k = (i - s->startCode) + s->idRangeOffset / 2 +
400                             (s - seg_tab) - segCount;
401                         assert(k >= 0 && k < n);
402                         index = glyphId[k];
403                         if (index != 0)
404                             index = (index + s->idDelta) & 0xFFFF;
405                     }
406                     if (index < 0 || index >= nglyphs)
407                         ttf_fail("cmap: glyph index out of range [0..%i)",
408                                  nglyphs);
409                     if (unicode_map[i] != NOGLYPH_ASSIGNED_YET)
410                         ttf_fail
411                             ("cmap: unicode %.4X is mapped to multiple glyphs",
412                              i);
413                     if (unicode_map[i] == 0)
414                         ttf_warn("unicode %.4X is mapped to glyph 0", i);
415                     unicode_map[i] = index;
416                     append_unicode(index, i);
417                 }
418             }
419         }
420         xfree(seg_tab);
421         xfree(glyphId);
422         break;
423     }
424     if (e - cmap_tab == ncmapsubtabs)
425         ttf_fail("Invalid argument `-m %i': out of range [1..%i]",
426                  select_unicode, unicode_map_count);
427 }
428 
read_font(void)429 static void read_font(void)
430 {
431     long i, j, k, l, n, m, platform_id, encoding_id;
432     TTF_FWORD kern_value;
433     char buf[1024], *p;
434     dirtab_entry *pd;
435     kern_entry *pk;
436     mtx_entry *pm;
437     ttf_skip(TTF_FIXED_SIZE);
438     ntabs = get_ushort();
439     ttf_skip(3 * TTF_USHORT_SIZE);
440     dir_tab = xtalloc(ntabs, dirtab_entry);
441     for (pd = dir_tab; pd - dir_tab < ntabs; pd++) {
442         pd->tag[0] = get_char();
443         pd->tag[1] = get_char();
444         pd->tag[2] = get_char();
445         pd->tag[3] = get_char();
446         ttf_skip(TTF_ULONG_SIZE);
447         pd->offset = get_ulong();
448         pd->length = get_ulong();
449     }
450     ttf_seek_tab("head",
451                  2 * TTF_FIXED_SIZE + 2 * TTF_ULONG_SIZE + TTF_USHORT_SIZE);
452     upem = get_ushort();
453     ttf_skip(16);
454     FontBBox1 = get_fword();
455     FontBBox2 = get_fword();
456     FontBBox3 = get_fword();
457     FontBBox4 = get_fword();
458     ttf_skip(TTF_USHORT_SIZE);
459     ttf_skip(TTF_USHORT_SIZE + TTF_SHORT_SIZE);
460     loca_format = get_short();
461     ttf_seek_tab("maxp", TTF_FIXED_SIZE);
462     nglyphs = get_ushort();
463     mtx_tab = xtalloc(nglyphs + 1, mtx_entry);
464     for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++) {
465         pm->name = NULL;        /* notdef */
466         pm->found = 0;
467         pm->unicode_list = NULL;
468     }
469     ttf_seek_tab("hhea", TTF_FIXED_SIZE);
470     Ascender = get_fword();
471     Descender = get_fword();
472     ttf_skip(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3 * TTF_FWORD_SIZE +
473              8 * TTF_SHORT_SIZE);
474     nhmtx = get_ushort();
475     ttf_seek_tab("hmtx", 0);
476     for (pm = mtx_tab; pm - mtx_tab < nhmtx; pm++) {
477         pm->wx = get_ufword();
478         ttf_skip(TTF_FWORD_SIZE);
479     }
480     i = pm[-1].wx;
481     for (; pm - mtx_tab < nglyphs; pm++)
482         pm->wx = i;
483     ttf_seek_tab("post", 0);
484     post_format = get_fixed();
485     ItalicAngle = get_fixed();
486     UnderlinePosition = get_fword();
487     UnderlineThickness = get_fword();
488     IsFixedPitch = get_ulong();
489     ttf_skip(4 * TTF_ULONG_SIZE);
490     switch (post_format) {
491     case 0x00010000:
492         for (pm = mtx_tab; pm - mtx_tab < NMACGLYPHS; pm++)
493             pm->name = mac_glyph_names[pm - mtx_tab];
494         break;
495     case 0x00020000:
496         l = get_ushort();       /* some fonts have this value different from nglyphs */
497         for (pm = mtx_tab; pm - mtx_tab < l; pm++)
498             pm->index = get_ushort();
499         if ((pd = name_lookup("post")) == NULL)
500             ttf_fail("can't find table `post'");
501         n = pd->length - (xftell(fontfile, cur_file_name) - pd->offset);
502         ps_glyphs_buf = xtalloc(n + 1, char);
503         for (m = 0, p = ps_glyphs_buf; p - ps_glyphs_buf < n;) {
504             for (i = get_byte(); i > 0; i--)
505                 *p++ = get_char();
506             *p++ = 0;
507             m++;
508         }
509         for (pm = mtx_tab; pm - mtx_tab < l; pm++) {
510             if (pm->index < NMACGLYPHS)
511                 pm->name = mac_glyph_names[pm->index];
512             else {
513                 k = pm->index - NMACGLYPHS;
514                 if (k < m) {
515                     for (p = ps_glyphs_buf; k > 0; k--)
516                         p = (char *) strend(p) + 1;
517                     pm->name = p;
518                 } else {
519                     pm->name = NULL;    /* index out of valid range, fix name to notdef */
520                 }
521             }
522         }
523         break;
524     default:
525         ttf_warn("unsupported format (%.8X) of `post' table, assuming 3.0",
526                  post_format);
527     case 0x00030000:
528         if (print_glyph == AS_NAME) {
529             ttf_warn
530                 ("no names available in `post' table, print glyph names as indices");
531             print_glyph = AS_INDEX;
532         }
533     }
534     ttf_seek_tab("loca", 0);
535     if (loca_format == 1) {
536         for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++)
537             pm->offset = get_ulong();
538     } else {
539         for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++)
540             pm->offset = get_ushort() << 1;
541     }
542     if ((pd = name_lookup("glyf")) == NULL)
543         ttf_fail("can't find table `glyf'");
544     for (n = pd->offset, pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) {
545         ttf_seek_off("glyf", n + pm->offset);
546         ttf_skip(TTF_SHORT_SIZE);
547         pm->bbox[0] = get_fword();
548         pm->bbox[1] = get_fword();
549         pm->bbox[2] = get_fword();
550         pm->bbox[3] = get_fword();
551     }
552 
553     ttf_seek_tab("name", 0);
554     i = ftell(fontfile);
555     (void) get_ushort();        /* skip Format selector (=0) */
556     n = get_ushort();           /* number of name records */
557     j = get_ushort() + i;       /* start of string storage */
558     i += 3 * TTF_USHORT_SIZE;   /* update the current offset */
559     while (n-- > 0) {
560         ttf_seek_off("name", i);
561         platform_id = get_ushort();
562         encoding_id = get_ushort();
563         (void) get_ushort();    /* skip language_id */
564         k = get_ushort();       /* name_id */
565         l = get_ushort();       /* string length */
566         if ((platform_id == 1 && encoding_id == 0) &&
567             (k == 0 || k == 1 || k == 4 || k == 5 || k == 6)) {
568             ttf_seek_off("name", j + get_ushort());
569             for (p = buf; l-- > 0; p++)
570                 *p = get_char();
571             *p++ = 0;
572             p = xstrdup(buf);
573             switch (k) {
574             case 0:
575                 Notice = p;
576                 break;
577             case 1:
578                 FamilyName = p;
579                 break;
580             case 4:
581                 FullName = p;
582                 break;
583             case 5:
584                 Version = p;
585                 break;
586             case 6:
587                 FontName = p;
588                 break;
589             }
590             if (Notice != NULL && FamilyName != NULL &&
591                 FullName != NULL && FontName != NULL && Version != NULL)
592                 break;
593         }
594         i += 6 * TTF_USHORT_SIZE;
595     }
596     if ((pd = name_lookup("PCLT")) != NULL) {
597         ttf_seek_off("PCLT",
598                      pd->offset + TTF_FIXED_SIZE + TTF_ULONG_SIZE +
599                      TTF_USHORT_SIZE);
600         XHeight = get_ushort();
601         if (XHeight > FontBBox4) {
602             ttf_warn("XHeight is too big (%i)\n"
603                      "This is likely a font bug, so I discarded this parameter.",
604                      (int) get_ttf_funit(XHeight));
605             XHeight = 0;
606         }
607         ttf_skip(2 * TTF_USHORT_SIZE);
608         CapHeight = get_ushort();
609         if (CapHeight > FontBBox4) {
610             ttf_warn("CapHeight is too big (%i)\n"
611                      "This is likely a font bug, so I discarded this parameter.",
612                      (int) get_ttf_funit(CapHeight));
613             CapHeight = 0;
614         }
615     }
616     if ((pd = name_lookup("OS/2")) != NULL) {
617         ttf_seek_off("OS/2", pd->offset + TTF_USHORT_SIZE + TTF_SHORT_SIZE);
618         switch (get_ushort()) {
619         case 100:
620             Weight = xstrdup("Thin");
621             break;
622         case 200:
623             Weight = xstrdup("ExtraLight");
624             break;
625         case 300:
626             Weight = xstrdup("Light");
627             break;
628         case 400:
629             Weight = xstrdup("Normal");
630             break;
631         case 500:
632             Weight = xstrdup("Medium");
633             break;
634         case 600:
635             Weight = xstrdup("SemiBold");
636             break;
637         case 700:
638             Weight = xstrdup("Bold");
639             break;
640         case 800:
641             Weight = xstrdup("ExtraBold");
642             break;
643         case 900:
644             Weight = xstrdup("Black");
645             break;
646         }
647     }
648     read_cmap();
649     if ((pd = name_lookup("kern")) == NULL)
650         return;
651     kern_tab = xtalloc(nglyphs, kern_entry);
652     for (pk = kern_tab; pk - kern_tab < nglyphs; pk++) {
653         pk->next = NULL;
654         pk->value = 0;
655     }
656     ttf_seek_off("kern", pd->offset + TTF_USHORT_SIZE);
657     for (n = get_ushort(); n > 0; n--) {
658         ttf_skip(2 * TTF_USHORT_SIZE);
659         k = get_ushort();
660         if (!(k & 1) || (k & 2) || (k & 4))
661             return;
662         if (k >> 8 != 0) {
663             ttf_warn("warning: only format 0 supported of `kern' \
664                  subtables, others are ignored\n");
665             continue;
666         }
667         k = get_ushort();
668         ttf_skip(3 * TTF_USHORT_SIZE);
669         while (k-- > 0) {
670             i = get_ushort();
671             j = get_ushort();
672             kern_value = get_fword();
673             if (kern_value != 0) {
674                 store_kern_value(i, j, kern_value);
675                 nkernpairs++;
676             }
677         }
678     }
679 }
680 
null_glyph(const char * s)681 static int null_glyph(const char *s)
682 {
683     return (s == NULL || s == notdef);
684     /*
685        strcmp(s, ".null") == 0 ||
686        strcmp(s, ".notdef") == 0 ||
687        strcmp(s, "CR") == 0 ||
688        strcmp(s, "nonmarkingreturn") == 0
689      */
690 }
691 
print_glyph_name(FILE * f,long glyph_index,int convention)692 static void print_glyph_name(FILE * f, long glyph_index, int convention)
693 {
694     unicode_entry *u;
695     static char buf[1024];
696     const char *n;
697     assert(glyph_index >= 0 && glyph_index < nglyphs);
698     n = mtx_tab[glyph_index].name;
699     if (printing_enc && (n == notdef || glyph_index == 0)) {
700         fputs(notdef, f);
701         return;
702     }
703     switch (convention) {
704     case AS_NAME:
705         if (!null_glyph(n))
706             fprintf(f, "%s", mtx_tab[glyph_index].name);
707         else if (n == notdef && glyph_index == 0)
708             fputs(notdef, f);
709         else
710             fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index);
711         break;
712     case AS_INDEX:
713         fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index);
714         break;
715     case AS_UNICODE:
716         u = mtx_tab[glyph_index].unicode_list;
717         if (glyph_index == 0 || u == NULL)
718             fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index);
719         else {
720             fprintf(f, "%s%.4X", GLYPH_PREFIX_UNICODE, u->code);
721             if (u->next != NULL) {
722                 *buf = 0;
723                 for (; u != NULL; u = u->next) {
724                     assert(strlen(buf) + strlen(GLYPH_PREFIX_UNICODE) + 4 <
725                            sizeof(buf));
726                     sprintf(strend(buf), "%s%.4X ", GLYPH_PREFIX_UNICODE,
727                             u->code);
728                 }
729                 ttf_warn
730                     ("glyph %li has multiple encodings (the first one being used): %s",
731                      glyph_index, buf);
732             }
733         }
734         break;
735     }
736 }
737 
print_char_metric(FILE * f,int charcode,long glyph_index)738 static void print_char_metric(FILE * f, int charcode, long glyph_index)
739 {
740     assert(glyph_index >= 0 && glyph_index < nglyphs);
741     fprintf(f, "C %i ; WX %i ; N ", (int) charcode,
742             (int) get_ttf_funit(mtx_tab[glyph_index].wx));
743     print_glyph_name(f, glyph_index, print_glyph);
744     fprintf(f, " ; B %i %i %i %i ;\n",
745             (int) get_ttf_funit(mtx_tab[glyph_index].bbox[0]),
746             (int) get_ttf_funit(mtx_tab[glyph_index].bbox[1]),
747             (int) get_ttf_funit(mtx_tab[glyph_index].bbox[2]),
748             (int) get_ttf_funit(mtx_tab[glyph_index].bbox[3]));
749 }
750 
escape_eol(char * s)751 static char * escape_eol(char *s)
752 {
753     char *p, *e;
754     char *dest, *d;
755 
756     if (s == NULL)
757         return NULL;
758 
759     dest = d = xtalloc(2*strlen(s), char);
760     e = strend(s);
761     for (p = s; p < e; p++) {
762         if (*p == 10 || *p == 13) {
763             *d++ = '\\';
764             *d++ = 'n';
765         }
766         else
767             *d++ = *p;
768     }
769     *d = 0;
770     return dest;
771 }
772 
print_afm(char * date,char * fontname)773 static void print_afm(char *date, char *fontname)
774 {
775     int ncharmetrics;
776     mtx_entry *pm;
777     long mtx_index[256], *idx;
778     unsigned int index;
779     char **pe;
780     kern_entry *pk, *qk;
781     char *p;
782     double d;
783     long l;
784     fputs("StartFontMetrics 2.0\n", outfile);
785     fprintf(outfile,
786             "Comment Converted at %s by ttf2afm from font file `%s'\n", date,
787             fontname);
788     print_str(FontName);
789     print_str(FullName);
790     print_str(FamilyName);
791     print_str(Weight);
792     l = ItalicAngle >> 16;
793     if (l > 0x8000)
794         l = l - 0x10000;
795     d = (ItalicAngle & 0xffff)/65536.0;
796     if (d >= 0.1)
797         fprintf(outfile, "ItalicAngle %.1f", d + l);
798     else
799         fprintf(outfile, "ItalicAngle %li", l);
800     fputs("\n", outfile);
801     fprintf(outfile, "IsFixedPitch %s\n", IsFixedPitch ? "true" : "false");
802     fprintf(outfile, "FontBBox %i %i %i %i\n",
803             (int) get_ttf_funit(FontBBox1),
804             (int) get_ttf_funit(FontBBox2),
805             (int) get_ttf_funit(FontBBox3), (int) get_ttf_funit(FontBBox4));
806     print_dimen(UnderlinePosition);
807     print_dimen(UnderlineThickness);
808     print_str(Version);
809     /* remove trailing whitespaces from Notice */
810     if (Notice != NULL) {
811         for (p = strend(Notice); p > Notice && isspace((unsigned char)*p); p--);
812         *p = 0;
813     }
814     print_str(Notice);
815     fputs("EncodingScheme FontSpecific\n", outfile);
816     print_dimen(CapHeight);
817     print_dimen(XHeight);
818     print_dimen(Ascender);
819     print_dimen(Descender);
820     ncharmetrics = nglyphs;
821     if (use_ext_enc == 0) {     /* external encoding vector not given */
822         fprintf(outfile, "StartCharMetrics %u\n", ncharmetrics);
823         for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) {
824             pm->found = 1;
825             print_char_metric(outfile, -1, pm - mtx_tab);
826         }
827     } else {                    /* external encoding vector given */
828         for (idx = mtx_index; idx - mtx_index < 256; *idx++ = 0);
829         for (pe = enc_names; pe - enc_names < names_count; pe++) {
830             if (*pe == notdef)
831                 continue;
832             /* scan form `uniABCD' */
833             if (sscanf(*pe, GLYPH_PREFIX_UNICODE "%4X", &index) == 1) {
834                 if (unicode_map[index] != NOGLYPH_ASSIGNED_YET) {
835                     pm = mtx_tab + unicode_map[index];
836                     mtx_index[pe - enc_names] = pm - mtx_tab;
837                     pm->found = 1;
838                 } else
839                     ttf_warn("`unicode %s%.4X' is not mapped to any glyph",
840                              GLYPH_PREFIX_UNICODE, index);
841                 continue;
842             }
843             /* scan form `index123' */
844             if (sscanf(*pe, GLYPH_PREFIX_INDEX "%u", &index) == 1) {
845                 if (index >= (unsigned int) nglyphs)
846                     ttf_fail("`%s' out of valid range [0..%i)", *pe, nglyphs);
847                 pm = mtx_tab + index;
848                 mtx_index[pe - enc_names] = pm - mtx_tab;
849                 pm->found = 1;
850                 continue;
851             }
852             for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
853                 if (pm->name != NULL && strcmp(*pe, pm->name) == 0)
854                     break;
855             if (pm - mtx_tab < nglyphs) {
856                 mtx_index[pe - enc_names] = pm - mtx_tab;
857                 pm->found = 1;
858                 continue;
859             } else
860                 ttf_warn("glyph `%s' not found", *pe);
861         }
862         fprintf(outfile, "StartCharMetrics %u\n", ncharmetrics);
863         for (idx = mtx_index; idx - mtx_index < 256; idx++) {
864             if (*idx != 0 && mtx_tab[*idx].found == 1)
865                 print_char_metric(outfile, idx - mtx_index, *idx);
866         }
867         for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) {
868             if (pm->found == 0)
869                 print_char_metric(outfile, -1, pm - mtx_tab);
870         }
871     }
872     fputs("EndCharMetrics\n", outfile);
873     if (nkernpairs == 0)
874         goto end_kerns;
875     fprintf(outfile, "StartKernData\nStartKernPairs %i\n", nkernpairs);
876     for (pk = kern_tab; pk - kern_tab < nglyphs; pk++)
877         for (qk = pk; qk != NULL; qk = qk->next)
878             if (qk->value != 0) {
879                 fputs("KPX ", outfile);
880                 print_glyph_name(outfile, pk - kern_tab, print_glyph);
881                 fputs(" ", outfile);
882                 print_glyph_name(outfile, qk->adjacent, print_glyph);
883                 fprintf(outfile, " %i\n", get_ttf_funit(qk->value));
884             }
885     fputs("EndKernPairs\nEndKernData\n", outfile);
886   end_kerns:
887     fputs("EndFontMetrics\n", outfile);
888 }
889 
print_encoding(char * fontname)890 static void print_encoding(char *fontname)
891 {
892     long int i, k, first_code, length;
893     FILE *file;
894     TTF_USHORT format;
895     char *enc_name, *end_enc_name;
896     cmap_entry *e;
897     printing_enc = 1;
898     enc_name = xtalloc(strlen(bname) + 20, char);
899     strcpy(enc_name, bname);
900     end_enc_name = strend(enc_name);
901     for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) {
902         ttf_seek_off("cmap", cmap_offset + e->offset);
903         format = get_ushort();
904         if (format != 0 && format != 4 && format != 6) {
905             ttf_warn("format %i of encoding subtable unsupported",
906                      (int) format);
907             continue;
908         }
909         sprintf(end_enc_name, ".e%i%i",
910                 (int) e->platform_id, (int) e->encoding_id);
911         if ((file = xfopen(enc_name, FOPEN_W_MODE)) == NULL)
912             ttf_fail("cannot open file for writing (%s)\n", enc_name);
913         fprintf(file, "%% Encoding table from font file %s\n", fontname);
914         fprintf(file, "%% Platform ID %i", (int) e->platform_id);
915         switch (e->platform_id) {
916         case 0:
917             fprintf(file, " (Apple Unicode)");
918             break;
919         case 1:
920             fprintf(file, " (Macintosh)");
921             break;
922         case 2:
923             fprintf(file, " (ISO)");
924             break;
925         case 3:
926             fprintf(file, " (Microsoft)");
927             break;
928         }
929         fprintf(file, "\n");
930         fprintf(file, "%% Encoding ID %i", (int) e->encoding_id);
931         if (e->platform_id == 1 && e->encoding_id == 0)
932             fprintf(file, " (Roman)");
933         if (e->platform_id == 3)
934             switch (e->encoding_id) {
935             case 0:
936                 fprintf(file, " (Symbol)");
937                 break;
938             case 1:
939                 fprintf(file, " (Unicode)");
940                 break;
941             }
942         fprintf(file, "\n");
943         fprintf(file, "%% Format %i", (int) (format));
944         switch (format) {
945         case 0:
946             fprintf(file, " (byte encoding table)");
947             break;
948         case 4:
949             fprintf(file, " (segment mapping to delta values)");
950             break;
951         case 6:
952             fprintf(file, " (trimmed table mapping)");
953             break;
954         }
955         fprintf(file, "\n");
956         fprintf(file, "/Encoding%i [\n", (int) (e - cmap_tab + 1));
957         switch (format) {
958         case 0:
959             (void) get_ushort();        /* skip length */
960             (void) get_ushort();        /* skip version number */
961             for (i = 0; i < 256; i++) {
962                 fputs("/", file);
963                 print_glyph_name(file, get_byte(), print_glyph);
964                 fputs("\n", file);
965             }
966             break;
967         case 4:
968             for (i = 0; i < nglyphs; ++i) {
969                 fprintf(file, "%% Glyph %li -> ", i);
970                 print_glyph_name(file, i, AS_UNICODE);
971                 fputs("\n", file);
972             }
973             break;
974         case 6:
975             (void) get_ushort();        /* skip table length */
976             (void) get_ushort();        /* skip version number */
977             first_code = get_ushort();  /* first character code */
978             for (i = 0; i < first_code; ++i)
979                 fprintf(file, "/%s\n", notdef);
980             length = get_ushort();      /* number of character codes */
981             for (i = first_code; i < first_code + length; i++) {
982                 k = get_ushort();
983                 if (i > 255)
984                     fputs("% ", file);
985                 fputs("/", file);
986                 print_glyph_name(file, k, print_glyph);
987                 fputs("\n", file);
988             }
989             for (i = first_code + length; i < 256; i++)
990                 fprintf(file, "/%s\n", notdef);
991             break;
992         default:
993             ttf_warn("format %i of encoding subtable unsupported",
994                      (int) format);
995         }
996         fprintf(file, "] def\n");
997     }
998     xfree(enc_name);
999 }
1000 
usage(void)1001 static void usage(void)
1002 {
1003     cur_file_name = NULL;
1004     fprintf(stderr,
1005             "Usage: ttf2afm [-i|-u|-c|-v] [-e enc] [-o filename] [-m NUM] fontfile\n"
1006             "    -i:          force printing glyph names in form 'index123'\n"
1007             "    -u:          force printing glyph names in form 'uniABCD'\n"
1008             "    -c:          print encoding tables to `basename.e<platformID><encodingID>'\n"
1009             "    -v:          print version\n"
1010             "    -e enc:      encode the AFM output using encoding vector from `enc'\n"
1011             "    -o filename: write output to file `filename' instead of stdout\n"
1012             "    -m NUM:      select unicode mapping (default = 1, ie the first)\n"
1013             "    fontfile:    the TrueType fontfile\n"
1014             "\nPlease send bug reports or feature requests to <pdftex@tug.org>\n");
1015     _exit(-1);
1016 }
1017 
main(int argc,char ** argv)1018 int main(int argc, char **argv)
1019 {
1020     char date[128], *s;
1021     time_t t = time(&t);
1022     int c;
1023     kpse_set_program_name(argv[0], "ttf2afm");
1024     kpse_init_prog("ttf2afm", 0, 0, 0);
1025     while ((c = getopt(argc, argv, "iucve:o:m:")) != -1)
1026         switch (c) {
1027         case 'i':
1028             print_glyph = AS_INDEX;
1029             break;
1030         case 'u':
1031             print_glyph = AS_UNICODE;
1032             break;
1033         case 'c':
1034             print_cmap = 1;
1035             break;
1036         case 'e':
1037             cur_file_name = optarg;
1038             read_encoding(cur_file_name);
1039             use_ext_enc = 1;
1040             break;
1041         case 'o':
1042             cur_file_name = optarg;
1043             outfile = xfopen(cur_file_name, FOPEN_W_MODE);
1044             if (outfile == NULL)
1045                 ttf_fail("cannot open file for writing");
1046             break;
1047         case 'm':
1048             select_unicode = atoi(optarg);
1049             break;
1050         case 'v':
1051             fprintf(stderr,
1052                     "ttf2afm version " VERSION "\n"
1053                     "Copyright (C) 1997-2014 Han The Thanh.\n"
1054                     "There is NO warranty.  Redistribution of this software is\n"
1055                     "covered by the terms of both the pdfTeX copyright and\n"
1056                     "the GNU General Public License.\n"
1057                     "For more information about these matters, see the files\n"
1058                     "named COPYING and the pdfTeX source.\n"
1059                     "Primary author of ttf2afm: Han The Thanh.\n");
1060             _exit(0);
1061         default:
1062             usage();
1063         }
1064     if (argc - optind != 1)
1065         usage();
1066     sprintf(date, "%s\n", ctime(&t));
1067     *(char *) strchr(date, '\n') = 0;
1068     cur_file_name = argv[optind];
1069     if (print_cmap) {
1070         bname = xstrdup(xbasename(cur_file_name));
1071         if ((s = strrchr(bname, '.')) != NULL)
1072             *s = 0;
1073     }
1074     if ((fontfile =
1075          kpse_open_file(cur_file_name, kpse_truetype_format)) == NULL)
1076         ttf_fail("can't open font file for reading");
1077     read_font();
1078     if (outfile == NULL)
1079         outfile = stdout;
1080     print_afm(date, cur_file_name);
1081     if (print_cmap)
1082         print_encoding(cur_file_name);
1083     xfree(FontName);
1084     xfree(FullName);
1085     xfree(FamilyName);
1086     xfree(Notice);
1087     xfree(Version);
1088     xfree(Weight);
1089     free_tabs();
1090     xfclose(fontfile, cur_file_name);
1091     return 0;
1092 }
1093