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