1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2
3 Copyright (C) 2002-2014 by Jin-Hwan Cho and Shunsaku Hirata,
4 the dvipdfmx project team.
5
6 Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28
29 #include "system.h"
30 #include "mem.h"
31 #include "mfileio.h"
32 #include "error.h"
33
34 #include "numbers.h"
35 #include "dpxutil.h"
36
37 #include "tfm.h"
38
39 #define TFM_FORMAT 1
40 #define OFM_FORMAT 2
41
42 #define FWBASE ((double) (1<<20))
43
44 static int verbose = 0;
45
46
47 #ifndef WITHOUT_ASCII_PTEX
48 /*
49 * ID is 9 for vertical JFM file.
50 */
51 #define JFM_ID 11
52 #define JFMV_ID 9
53 #define IS_JFM(i) ((i) == JFM_ID || (i) == JFMV_ID)
54
55 #define CHARACTER_INDEX(i) ((i > 0xFFFFUL ? 0x10000UL : i))
56 #else
57 #define CHARACTER_INDEX(i) ((i))
58 #endif
59
60 /*
61 * TFM Record structure:
62 * Multiple TFM's may be read in at once.
63 */
64
65 struct tfm_font
66 {
67 #ifndef WITHOUT_ASCII_PTEX
68 int id;
69 int nt;
70 #endif /* !WITHOUT_ASCII_PTEX */
71 #ifndef WITHOUT_OMEGA
72 int32_t level;
73 #endif /* !WITHOUT_OMEGA */
74 uint32_t wlenfile;
75 uint32_t wlenheader;
76 uint32_t bc, ec;
77 uint32_t nwidths, nheights, ndepths;
78 uint32_t nitcor, nlig, nkern, nextens;
79 uint32_t nfonparm;
80 #ifndef WITHOUT_OMEGA
81 uint32_t fontdir;
82 uint32_t nco, ncw, npc;
83 #endif /* !WITHOUT_OMEGA */
84 fixword *header;
85 #ifndef WITHOUT_ASCII_PTEX
86 unsigned short *chartypes;
87 #endif /* !WITHOUT_ASCII_PTEX */
88 uint32_t *char_info;
89 unsigned short *width_index;
90 unsigned char *height_index;
91 unsigned char *depth_index;
92 fixword *width;
93 fixword *height;
94 fixword *depth;
95 };
96
97 static void
tfm_font_init(struct tfm_font * tfm)98 tfm_font_init (struct tfm_font *tfm)
99 {
100 tfm->header = NULL;
101 #ifndef WITHOUT_ASCII_PTEX
102 tfm->id = 0;
103 tfm->nt = 0;
104 tfm->chartypes = NULL;
105 #endif /* !WITHOUT_ASCII_PTEX */
106 #ifndef WITHOUT_OMEGA
107 tfm->level = 0;
108 tfm->fontdir = 0;
109 tfm->nco = tfm->ncw = tfm->npc = 0;
110 #endif
111 tfm->char_info = NULL;
112 tfm->width_index = NULL;
113 tfm->height_index = NULL;
114 tfm->depth_index = NULL;
115 tfm->width = tfm->height = tfm->depth = NULL;
116 }
117
118 static void
tfm_font_clear(struct tfm_font * tfm)119 tfm_font_clear (struct tfm_font *tfm)
120 {
121 if (tfm) {
122 if (tfm->header) {
123 RELEASE(tfm->header);
124 tfm->header = NULL;
125 }
126 if (tfm->char_info) {
127 RELEASE(tfm->char_info);
128 tfm->char_info = NULL;
129 }
130 if (tfm->width) {
131 RELEASE(tfm->width);
132 tfm->width = NULL;
133 }
134 if (tfm->height) {
135 RELEASE(tfm->height);
136 tfm->height = NULL;
137 }
138 if (tfm->depth) {
139 RELEASE(tfm->depth);
140 tfm->depth = NULL;
141 }
142 #ifndef WITHOUT_ASCII_PTEX
143 if (tfm->chartypes) {
144 RELEASE(tfm->chartypes);
145 tfm->chartypes = NULL;
146 }
147 #endif /* !WITHOUT_ASCII_PTEX */
148 if (tfm->width_index) {
149 RELEASE(tfm->width_index);
150 tfm->width_index = NULL;
151 }
152 if (tfm->height_index) {
153 RELEASE(tfm->height_index);
154 tfm->height_index = NULL;
155 }
156 if (tfm->depth_index) {
157 RELEASE(tfm->depth_index);
158 tfm->depth_index = NULL;
159 }
160 }
161 }
162
163
164 struct coverage
165 {
166 int first_char;
167 int num_chars;
168 };
169
170 /*
171 * All characters in the same range have same metrics.
172 */
173
174 struct range_map {
175 unsigned short num_coverages;
176 struct coverage *coverages;
177 unsigned short *indices;
178 };
179
180 /* Special case of num_coverages = 1 */
181 struct char_map
182 {
183 struct coverage coverage;
184 unsigned short *indices;
185 };
186
187 static void
release_char_map(struct char_map * map)188 release_char_map (struct char_map *map)
189 {
190 if (map->indices)
191 RELEASE(map->indices);
192 map->indices = NULL;
193 RELEASE(map);
194 }
195
196 static void
release_range_map(struct range_map * map)197 release_range_map (struct range_map *map)
198 {
199 if (map->coverages)
200 RELEASE(map->coverages);
201 if (map->indices)
202 RELEASE(map->indices);
203 map->coverages = NULL;
204 map->indices = NULL;
205 RELEASE(map);
206 }
207
208 static int
lookup_char(const struct char_map * map,int charcode)209 lookup_char (const struct char_map *map, int charcode)
210 {
211 if (charcode >= map->coverage.first_char &&
212 charcode <= map->coverage.first_char + map->coverage.num_chars)
213 return map->indices[CHARACTER_INDEX(charcode - map->coverage.first_char)];
214 else
215 return -1;
216 }
217
218 static int
lookup_range(const struct range_map * map,int charcode)219 lookup_range (const struct range_map *map, int charcode)
220 {
221 int idx;
222
223 for (idx = map->num_coverages - 1; idx >= 0 &&
224 charcode >= map->coverages[idx].first_char; idx--) {
225 if (charcode <=
226 map->coverages[idx].first_char + map->coverages[idx].num_chars)
227 return map->indices[CHARACTER_INDEX(idx)];
228 }
229
230 return -1;
231 }
232
233 #define SOURCE_TYPE_TFM 0
234 #define SOURCE_TYPE_JFM 1
235 #define SOURCE_TYPE_OFM 2
236
237 #define MAPTYPE_NONE 0
238 #define MAPTYPE_CHAR 1
239 #define MAPTYPE_RANGE 2
240
241 #define FONT_DIR_HORIZ 0
242 #define FONT_DIR_VERT 1
243
244 struct font_metric
245 {
246 char *tex_name;
247 fixword designsize;
248 char *codingscheme;
249
250 int fontdir;
251 int firstchar, lastchar;
252
253 fixword *widths;
254 fixword *heights;
255 fixword *depths;
256
257 struct {
258 int type;
259 void *data;
260 } charmap;
261
262 int source;
263 };
264
265 static void
fm_init(struct font_metric * fm)266 fm_init (struct font_metric *fm)
267 {
268 fm->tex_name = NULL;
269 fm->firstchar = 0;
270 fm->lastchar = 0;
271 fm->fontdir = FONT_DIR_HORIZ;
272 fm->codingscheme = NULL;
273 fm->designsize = 0;
274
275 fm->widths = NULL;
276 fm->heights = NULL;
277 fm->depths = NULL;
278
279 fm->charmap.type = MAPTYPE_NONE;
280 fm->charmap.data = NULL;
281
282 fm->source = SOURCE_TYPE_TFM;
283 }
284
285 static void
fm_clear(struct font_metric * fm)286 fm_clear (struct font_metric *fm)
287 {
288 if (fm) {
289 if (fm->tex_name)
290 RELEASE(fm->tex_name);
291 if (fm->widths)
292 RELEASE(fm->widths);
293 if (fm->heights)
294 RELEASE(fm->heights);
295 if (fm->depths)
296 RELEASE(fm->depths);
297 if (fm->codingscheme)
298 RELEASE(fm->codingscheme);
299
300 switch (fm->charmap.type) {
301 case MAPTYPE_CHAR:
302 release_char_map(fm->charmap.data);
303 break;
304 case MAPTYPE_RANGE:
305 release_range_map(fm->charmap.data);
306 break;
307 }
308 }
309 }
310
311 #ifndef MAX_FONTS
312 #define MAX_FONTS 16
313 #endif
314
315 struct font_metric *fms = NULL;
316 static unsigned numfms = 0, max_fms = 0;
317
318 static void
fms_need(unsigned n)319 fms_need (unsigned n)
320 {
321 if (n > max_fms) {
322 max_fms = MAX(max_fms + MAX_FONTS, n);
323 fms = RENEW(fms, max_fms, struct font_metric);
324 }
325 }
326
327 void
tfm_set_verbose(void)328 tfm_set_verbose (void)
329 {
330 verbose++;
331 }
332
333
334 static int
fread_fwords(fixword * words,int32_t nmemb,FILE * fp)335 fread_fwords (fixword *words, int32_t nmemb, FILE *fp)
336 {
337 int i;
338
339 for (i = 0; i < nmemb; i++)
340 words[i] = get_signed_quad(fp);
341
342 return nmemb*4;
343 }
344
345 static int
fread_uquads(uint32_t * quads,int32_t nmemb,FILE * fp)346 fread_uquads (uint32_t *quads, int32_t nmemb, FILE *fp)
347 {
348 int i;
349
350 for (i = 0; i < nmemb; i++) {
351 quads[i] = get_unsigned_quad(fp);
352 }
353
354 return nmemb*4;
355 }
356
357 /*
358 * TFM and JFM
359 */
360 static void
tfm_check_size(struct tfm_font * tfm,off_t tfm_file_size)361 tfm_check_size (struct tfm_font *tfm, off_t tfm_file_size)
362 {
363 uint32_t expected_size = 6;
364
365 /* Removed the warning message caused by EC TFM metric files.
366 *
367 if (tfm->wlenfile != tfm_file_size / 4) {
368 WARN("TFM file size is %ld bytes but it says it is %ld bytes!",
369 tfm_file_size, tfm->wlenfile * 4);
370 if (tfm_file_size > tfm->wlenfile * 4) {
371 WARN("Proceeding nervously...");
372 } else {
373 ERROR("Can't proceed...");
374 }
375 }
376 */
377 if ((int64_t)tfm_file_size < (int64_t)tfm->wlenfile * 4) {
378 ERROR("Can't proceed...");
379 }
380
381 expected_size += (tfm->ec - tfm->bc + 1);
382 expected_size += tfm->wlenheader;
383 expected_size += tfm->nwidths;
384 expected_size += tfm->nheights;
385 expected_size += tfm->ndepths;
386 expected_size += tfm->nitcor;
387 expected_size += tfm->nlig;
388 expected_size += tfm->nkern;
389 expected_size += tfm->nextens;
390 expected_size += tfm->nfonparm;
391 #ifndef WITHOUT_ASCII_PTEX
392 if (IS_JFM(tfm->id)) {
393 expected_size += tfm->nt + 1;
394 }
395 #endif /* !WITHOUT_ASCII_PTEX */
396 if (expected_size != tfm->wlenfile) {
397 WARN("TFM file size is expected to be %" PRId64 " bytes but it says it is %" PRId64 "bytes!",
398 (int64_t)expected_size * 4, (int64_t)tfm->wlenfile * 4);
399 if ((int64_t)tfm_file_size > (int64_t)expected_size *4) {
400 WARN("Proceeding nervously...");
401 } else {
402 ERROR("Can't proceed...");
403 }
404 }
405 }
406
407 static void
tfm_get_sizes(FILE * tfm_file,off_t tfm_file_size,struct tfm_font * tfm)408 tfm_get_sizes (FILE *tfm_file, off_t tfm_file_size, struct tfm_font *tfm)
409 {
410 #ifndef WITHOUT_ASCII_PTEX
411 {
412 unsigned short first_hword;
413
414 /*
415 * The first half word of TFM/JFM is TFM ID for JFM or size of
416 * TFM file in word for TFM. TFM with 9*4 or 11*4 bytes is not
417 * expected to be a valid TFM. So, we always assume that TFMs
418 * starting with 00 09 or 00 0B is JFM.
419 */
420 first_hword = get_unsigned_pair(tfm_file);
421 if (IS_JFM(first_hword)) {
422 tfm->id = first_hword;
423 tfm->nt = get_unsigned_pair(tfm_file);
424 tfm->wlenfile = get_unsigned_pair(tfm_file);
425 } else {
426 tfm->wlenfile = first_hword;
427 }
428 }
429 #else /* WITHOUT_ASCII_PTEX */
430 tfm->wlenfile = get_unsigned_pair(tfm_file);
431 #endif /* !WITHOUT_ASCII_PTEX */
432
433 tfm->wlenheader = get_unsigned_pair(tfm_file);
434 tfm->bc = get_unsigned_pair(tfm_file);
435 tfm->ec = get_unsigned_pair(tfm_file);
436 if (tfm->ec < tfm->bc) {
437 ERROR("TFM file error: ec(%u) < bc(%u) ???", tfm->ec, tfm->bc);
438 }
439 tfm->nwidths = get_unsigned_pair(tfm_file);
440 tfm->nheights = get_unsigned_pair(tfm_file);
441 tfm->ndepths = get_unsigned_pair(tfm_file);
442 tfm->nitcor = get_unsigned_pair(tfm_file);
443 tfm->nlig = get_unsigned_pair(tfm_file);
444 tfm->nkern = get_unsigned_pair(tfm_file);
445 tfm->nextens = get_unsigned_pair(tfm_file);
446 tfm->nfonparm = get_unsigned_pair(tfm_file);
447
448 tfm_check_size(tfm, tfm_file_size);
449
450 return;
451 }
452
453 #ifndef WITHOUT_ASCII_PTEX
454 static void
jfm_do_char_type_array(FILE * tfm_file,struct tfm_font * tfm)455 jfm_do_char_type_array (FILE *tfm_file, struct tfm_font *tfm)
456 {
457 unsigned short charcode;
458 unsigned short chartype;
459 int i;
460
461 tfm->chartypes = NEW(65536, unsigned short);
462 for (i = 0; i < 65536; i++) {
463 tfm->chartypes[i] = 0;
464 }
465 for (i = 0; i < tfm->nt; i++) {
466 charcode = get_unsigned_pair(tfm_file);
467 chartype = get_unsigned_pair(tfm_file);
468 tfm->chartypes[charcode] = chartype;
469 }
470 }
471
472 static void
jfm_make_charmap(struct font_metric * fm,struct tfm_font * tfm)473 jfm_make_charmap (struct font_metric *fm, struct tfm_font *tfm)
474 {
475 if (tfm->nt > 1) {
476 struct char_map *map;
477 int code;
478
479 fm->charmap.type = MAPTYPE_CHAR;
480 fm->charmap.data = map = NEW(1, struct char_map);
481 map->coverage.first_char = 0;
482 #ifndef WITHOUT_ASCII_PTEX
483 map->coverage.num_chars = 0x10FFFFL;
484 map->indices = NEW(0x10001L, unsigned short);
485 map->indices[0x10000L] = tfm->chartypes[0];
486 #else
487 map->coverage.num_chars = 0xFFFFL;
488 map->indices = NEW(0x10000L, unsigned short);
489 #endif
490
491 for (code = 0; code <= 0xFFFFU; code++) {
492 map->indices[code] = tfm->chartypes[code];
493 }
494 } else {
495 struct range_map *map;
496
497 fm->charmap.type = MAPTYPE_RANGE;
498 fm->charmap.data = map = NEW(1, struct range_map);
499 map->num_coverages = 1;
500 map->coverages = NEW(map->num_coverages, struct coverage);
501 map->coverages[0].first_char = 0;
502 #ifndef WITHOUT_ASCII_PTEX
503 map->coverages[0].num_chars = 0x10FFFFL;
504 #else
505 map->coverages[0].num_chars = 0xFFFFL;
506 #endif
507 map->indices = NEW(1, unsigned short);
508 map->indices[0] = 0; /* Only default type used. */
509 }
510 }
511 #endif /* !WITHOUT_ASCII_PTEX */
512
513 static void
tfm_unpack_arrays(struct font_metric * fm,struct tfm_font * tfm)514 tfm_unpack_arrays (struct font_metric *fm, struct tfm_font *tfm)
515 {
516 uint32_t charinfo;
517 unsigned short width_index;
518 unsigned char height_index, depth_index;
519 int i;
520
521 fm->widths = NEW(256, fixword);
522 fm->heights = NEW(256, fixword);
523 fm->depths = NEW(256, fixword);
524 for (i = 0; i < 256; i++) {
525 fm->widths [i] = 0;
526 fm->heights[i] = 0;
527 fm->depths [i] = 0;
528 }
529
530 for (i = tfm->bc; i <= tfm->ec; i++ ) {
531 charinfo = tfm->char_info[i - tfm->bc];
532 width_index = (charinfo >> 24);
533 height_index = (charinfo >> 20) & 0xf;
534 depth_index = (charinfo >> 16) & 0xf;
535 fm->widths [i] = tfm->width [width_index];
536 fm->heights[i] = tfm->height[height_index];
537 fm->depths [i] = tfm->depth [depth_index];
538 }
539
540 return;
541 }
542
543 static int
sput_bigendian(char * s,int32_t v,int n)544 sput_bigendian (char *s, int32_t v, int n)
545 {
546 int i;
547
548 for (i = n-1; i >= 0; i--) {
549 s[i] = (char) (v & 0xff);
550 v >>= 8;
551 }
552
553 return n;
554 }
555
556 static void
tfm_unpack_header(struct font_metric * fm,struct tfm_font * tfm)557 tfm_unpack_header (struct font_metric *fm, struct tfm_font *tfm)
558 {
559 if (tfm->wlenheader < 12) {
560 fm->codingscheme = NULL;
561 } else {
562 int i, len;
563 char *p;
564
565 len = (tfm->header[2] >> 24);
566 if (len < 0 || len > 39)
567 ERROR("Invalid TFM header.");
568 if (len > 0) {
569 fm->codingscheme = NEW(40, char);
570 p = fm->codingscheme;
571 p += sput_bigendian(p, tfm->header[2], 3);
572 for (i = 1; i <= len / 4; i++) {
573 p += sput_bigendian(p, tfm->header[2+i], 4);
574 }
575 fm->codingscheme[len] = '\0';
576 } else {
577 fm->codingscheme = NULL;
578 }
579 }
580
581 fm->designsize = tfm->header[1];
582 }
583
584 #ifndef WITHOUT_OMEGA
585
586 static void
ofm_check_size_one(struct tfm_font * tfm,off_t ofm_file_size)587 ofm_check_size_one (struct tfm_font *tfm, off_t ofm_file_size)
588 {
589 uint32_t ofm_size = 14;
590
591 ofm_size += 2*(tfm->ec - tfm->bc + 1);
592 ofm_size += tfm->wlenheader;
593 ofm_size += tfm->nwidths;
594 ofm_size += tfm->nheights;
595 ofm_size += tfm->ndepths;
596 ofm_size += tfm->nitcor;
597 ofm_size += 2*(tfm->nlig);
598 ofm_size += tfm->nkern;
599 ofm_size += 2*(tfm->nextens);
600 ofm_size += tfm->nfonparm;
601 if (tfm->wlenfile != ofm_file_size / 4 ||
602 tfm->wlenfile != ofm_size) {
603 ERROR("OFM file problem. Table sizes don't agree.");
604 }
605 }
606
607 static void
ofm_get_sizes(FILE * ofm_file,off_t ofm_file_size,struct tfm_font * tfm)608 ofm_get_sizes (FILE *ofm_file, off_t ofm_file_size, struct tfm_font *tfm)
609 {
610 tfm->level = get_signed_quad(ofm_file);
611
612 tfm->wlenfile = get_positive_quad(ofm_file, "OFM", "wlenfile");
613 tfm->wlenheader = get_positive_quad(ofm_file, "OFM", "wlenheader");
614 tfm->bc = get_positive_quad(ofm_file, "OFM", "bc");
615 tfm->ec = get_positive_quad(ofm_file, "OFM", "ec");
616 if (tfm->ec < tfm->bc) {
617 ERROR("OFM file error: ec(%u) < bc(%u) ???", tfm->ec, tfm->bc);
618 }
619 tfm->nwidths = get_positive_quad(ofm_file, "OFM", "nwidths");
620 tfm->nheights = get_positive_quad(ofm_file, "OFM", "nheights");
621 tfm->ndepths = get_positive_quad(ofm_file, "OFM", "ndepths");
622 tfm->nitcor = get_positive_quad(ofm_file, "OFM", "nitcor");
623 tfm->nlig = get_positive_quad(ofm_file, "OFM", "nlig");
624 tfm->nkern = get_positive_quad(ofm_file, "OFM", "nkern");
625 tfm->nextens = get_positive_quad(ofm_file, "OFM", "nextens");
626 tfm->nfonparm = get_positive_quad(ofm_file, "OFM", "nfonparm");
627 tfm->fontdir = get_positive_quad(ofm_file, "OFM", "fontdir");
628 if (tfm->fontdir) {
629 WARN("I may be interpreting a font direction incorrectly.");
630 }
631 if (tfm->level == 0) {
632 ofm_check_size_one(tfm, ofm_file_size);
633 } else if (tfm->level == 1) {
634 tfm->nco = get_positive_quad(ofm_file, "OFM", "nco");
635 tfm->ncw = get_positive_quad(ofm_file, "OFM", "nco");
636 tfm->npc = get_positive_quad(ofm_file, "OFM", "npc");
637 xseek_absolute(ofm_file, 4*(off_t)(tfm->nco - tfm->wlenheader), "OFM");
638 } else {
639 ERROR("Can't handle OFM files with level > 1");
640 }
641
642 return;
643 }
644
645 static void
ofm_do_char_info_zero(FILE * tfm_file,struct tfm_font * tfm)646 ofm_do_char_info_zero (FILE *tfm_file, struct tfm_font *tfm)
647 {
648 uint32_t num_chars;
649
650 num_chars = tfm->ec - tfm->bc + 1;
651 if (num_chars != 0) {
652 uint32_t i;
653
654 tfm->width_index = NEW(num_chars, unsigned short);
655 tfm->height_index = NEW(num_chars, unsigned char);
656 tfm->depth_index = NEW(num_chars, unsigned char);
657 for (i = 0; i < num_chars; i++) {
658 tfm->width_index [i] = get_unsigned_pair(tfm_file);
659 tfm->height_index[i] = get_unsigned_byte(tfm_file);
660 tfm->depth_index [i] = get_unsigned_byte(tfm_file);
661 /* Ignore remaining quad */
662 skip_bytes(4, tfm_file);
663 }
664 }
665 }
666
667 static void
ofm_do_char_info_one(FILE * tfm_file,struct tfm_font * tfm)668 ofm_do_char_info_one (FILE *tfm_file, struct tfm_font *tfm)
669 {
670 uint32_t num_char_infos;
671 uint32_t num_chars;
672
673 num_char_infos = tfm->ncw / (3 + (tfm->npc / 2));
674 num_chars = tfm->ec - tfm ->bc + 1;
675
676 if (num_chars != 0) {
677 uint32_t i;
678 uint32_t char_infos_read;
679
680 tfm->width_index = NEW(num_chars, unsigned short);
681 tfm->height_index = NEW(num_chars, unsigned char);
682 tfm->depth_index = NEW(num_chars, unsigned char);
683 char_infos_read = 0;
684 for (i = 0; i < num_chars &&
685 char_infos_read < num_char_infos; i++) {
686 int repeats, j;
687
688 tfm->width_index [i] = get_unsigned_pair(tfm_file);
689 tfm->height_index[i] = get_unsigned_byte(tfm_file);
690 tfm->depth_index [i] = get_unsigned_byte(tfm_file);
691 /* Ignore next quad */
692 skip_bytes(4, tfm_file);
693 repeats = get_unsigned_pair(tfm_file);
694 /* Skip params */
695 for (j = 0; j < tfm->npc; j++) {
696 get_unsigned_pair(tfm_file);
697 }
698 /* Remove word padding if necessary */
699 if (ISEVEN(tfm->npc)){
700 get_unsigned_pair(tfm_file);
701 }
702 char_infos_read++;
703 if (i + repeats > num_chars) {
704 ERROR("Repeats causes number of characters to be exceeded.");
705 }
706 for (j = 0; j < repeats; j++) {
707 tfm->width_index [i+j+1] = tfm->width_index [i];
708 tfm->height_index[i+j+1] = tfm->height_index[i];
709 tfm->depth_index [i+j+1] = tfm->depth_index [i];
710 }
711 /* Skip ahead because we have already handled repeats */
712 i += repeats;
713 }
714 }
715 }
716
717 static void
ofm_unpack_arrays(struct font_metric * fm,struct tfm_font * tfm,uint32_t num_chars)718 ofm_unpack_arrays (struct font_metric *fm,
719 struct tfm_font *tfm, uint32_t num_chars)
720 {
721 int i;
722
723 fm->widths = NEW(tfm->bc + num_chars, fixword);
724 fm->heights = NEW(tfm->bc + num_chars, fixword);
725 fm->depths = NEW(tfm->bc + num_chars, fixword);
726 for (i = 0; i < num_chars; i++) {
727 fm->widths [tfm->bc + i] = tfm->width [ tfm->width_index [i] ];
728 fm->heights[tfm->bc + i] = tfm->height[ tfm->height_index[i] ];
729 fm->depths [tfm->bc + i] = tfm->depth [ tfm->depth_index [i] ];
730 }
731 }
732
733 static void
read_ofm(struct font_metric * fm,FILE * ofm_file,off_t ofm_file_size)734 read_ofm (struct font_metric *fm, FILE *ofm_file, off_t ofm_file_size)
735 {
736 struct tfm_font tfm;
737
738 tfm_font_init(&tfm);
739
740 ofm_get_sizes(ofm_file, ofm_file_size, &tfm);
741
742 if (tfm.level < 0 || tfm.level > 1)
743 ERROR ("OFM level %d not supported.", tfm.level);
744
745 if (tfm.wlenheader > 0) {
746 tfm.header = NEW(tfm.wlenheader, fixword);
747 fread_fwords(tfm.header, tfm.wlenheader, ofm_file);
748 }
749 if (tfm.level == 0) {
750 ofm_do_char_info_zero(ofm_file, &tfm);
751 } else if (tfm.level == 1) {
752 ofm_do_char_info_one(ofm_file, &tfm);
753 }
754 if (tfm.nwidths > 0) {
755 tfm.width = NEW(tfm.nwidths, fixword);
756 fread_fwords(tfm.width, tfm.nwidths, ofm_file);
757 }
758 if (tfm.nheights > 0) {
759 tfm.height = NEW(tfm.nheights, fixword);
760 fread_fwords(tfm.height, tfm.nheights, ofm_file);
761 }
762 if (tfm.ndepths > 0) {
763 tfm.depth = NEW(tfm.ndepths, fixword);
764 fread_fwords(tfm.depth, tfm.ndepths, ofm_file);
765 }
766
767 ofm_unpack_arrays(fm, &tfm, tfm.ec - tfm.bc + 1);
768 tfm_unpack_header(fm, &tfm);
769 fm->firstchar = tfm.bc;
770 fm->lastchar = tfm.ec;
771 fm->source = SOURCE_TYPE_OFM;
772
773 tfm_font_clear(&tfm);
774
775 return;
776 }
777 #endif /* !WITHOUT_OMEGA */
778
779 static void
read_tfm(struct font_metric * fm,FILE * tfm_file,off_t tfm_file_size)780 read_tfm (struct font_metric *fm, FILE *tfm_file, off_t tfm_file_size)
781 {
782 struct tfm_font tfm;
783
784 tfm_font_init(&tfm);
785
786 tfm_get_sizes(tfm_file, tfm_file_size, &tfm);
787 fm->firstchar = tfm.bc;
788 fm->lastchar = tfm.ec;
789 if (tfm.wlenheader > 0) {
790 tfm.header = NEW(tfm.wlenheader, fixword);
791 fread_fwords(tfm.header, tfm.wlenheader, tfm_file);
792 }
793 #ifndef WITHOUT_ASCII_PTEX
794 if (IS_JFM(tfm.id)) {
795 jfm_do_char_type_array(tfm_file, &tfm);
796 jfm_make_charmap(fm, &tfm);
797 fm->firstchar = 0;
798 fm->lastchar = 0x10FFFFL;
799 fm->fontdir = (tfm.id == JFMV_ID) ? FONT_DIR_VERT : FONT_DIR_HORIZ;
800 fm->source = SOURCE_TYPE_JFM;
801 }
802 #endif /* !WITHOUT_ASCII_PTEX */
803 if (tfm.ec - tfm.bc + 1 > 0) {
804 tfm.char_info = NEW(tfm.ec - tfm.bc + 1, uint32_t);
805 fread_uquads(tfm.char_info, tfm.ec - tfm.bc + 1, tfm_file);
806 }
807 if (tfm.nwidths > 0) {
808 tfm.width = NEW(tfm.nwidths, fixword);
809 fread_fwords(tfm.width, tfm.nwidths, tfm_file);
810 }
811 if (tfm.nheights > 0) {
812 tfm.height = NEW(tfm.nheights, fixword);
813 fread_fwords(tfm.height, tfm.nheights, tfm_file);
814 }
815 if (tfm.ndepths > 0) {
816 tfm.depth = NEW(tfm.ndepths, fixword);
817 fread_fwords(tfm.depth, tfm.ndepths, tfm_file);
818 }
819 tfm_unpack_arrays(fm, &tfm);
820 tfm_unpack_header(fm, &tfm);
821
822 tfm_font_clear(&tfm);
823
824 return;
825 }
826
827 int
tfm_open(const char * tfm_name,int must_exist)828 tfm_open (const char *tfm_name, int must_exist)
829 {
830 FILE *tfm_file;
831 int i, format = TFM_FORMAT;
832 off_t tfm_file_size;
833 char *file_name = NULL;
834
835 for (i = 0; i < numfms; i++) {
836 if (!strcmp(tfm_name, fms[i].tex_name))
837 return i;
838 }
839
840 /*
841 * The procedure to search tfm or ofm files:
842 * 1. Search tfm file with the given name with the must_exist flag unset.
843 * 2. Search ofm file with the given name with the must_exist flag unset.
844 * 3. If not found and must_exist flag is set, try again to search
845 * tfm file with the must_exist flag set.
846 * 4. If not found and must_exist flag is not set, return -1.
847 */
848
849
850 /*
851 * We first look for OFM and then TFM.
852 * The reason for this change is incompatibility introduced when dvipdfmx
853 * started to write correct glyph metrics to output PDF for CID fonts.
854 * I'll not explain this in detail... This change is mostly specific to
855 * Japanese support.
856 */
857 #if 0
858 if ((file_name = kpse_find_file(tfm_name, kpse_tfm_format, 0))) {
859 format = TFM_FORMAT;
860 } else if ((file_name = kpse_find_file(tfm_name, kpse_ofm_format, 0))) {
861 format = OFM_FORMAT;
862 }
863 #endif
864 {
865 char *ofm_name, *suffix;
866
867 suffix = strrchr(tfm_name, '.');
868 if (!suffix || (strcmp(suffix, ".tfm") != 0 &&
869 strcmp(suffix, ".ofm") != 0)) {
870 ofm_name = NEW(strlen(tfm_name) + strlen(".ofm") + 1, char);
871 strcpy(ofm_name, tfm_name);
872 strcat(ofm_name, ".ofm");
873 } else {
874 ofm_name = NULL;
875 }
876 if (ofm_name &&
877 (file_name = kpse_find_file(ofm_name, kpse_ofm_format, 0)) != NULL) {
878 format = OFM_FORMAT;
879 } else if ((file_name =
880 kpse_find_file(tfm_name, kpse_tfm_format, 0)) != NULL) {
881 format = TFM_FORMAT;
882 } else if ((file_name =
883 kpse_find_file(tfm_name, kpse_ofm_format, 0)) != NULL) {
884 format = OFM_FORMAT;
885 }
886 if (ofm_name)
887 RELEASE(ofm_name);
888 }
889
890 /*
891 * In case that must_exist is set, MiKTeX returns always non-NULL value
892 * even if the tfm file is not found.
893 */
894 if (file_name == NULL) {
895 if (must_exist) {
896 if ((file_name = kpse_find_file(tfm_name, kpse_tfm_format, 1)) != NULL)
897 format = TFM_FORMAT;
898 else {
899 ERROR("Unable to find TFM file \"%s\".", tfm_name);
900 }
901 } else {
902 return -1;
903 }
904 }
905
906 tfm_file = MFOPEN(file_name, FOPEN_RBIN_MODE);
907 if (!tfm_file) {
908 ERROR("Could not open specified TFM/OFM file \"%s\".", tfm_name);
909 }
910
911 if (verbose) {
912 if (format == TFM_FORMAT)
913 MESG("(TFM:%s", tfm_name);
914 else if (format == OFM_FORMAT)
915 MESG("(OFM:%s", tfm_name);
916 if (verbose > 1)
917 MESG("[%s]", file_name);
918 }
919
920 RELEASE(file_name);
921
922 tfm_file_size = xfile_size (tfm_file, "TFM/OFM");
923 if (tfm_file_size > 0x1ffffffff)
924 ERROR("TFM/OFM file size exceeds 33-bit");
925 if (tfm_file_size < 24) {
926 ERROR("TFM/OFM file too small to be a valid file.");
927 }
928
929 fms_need(numfms + 1);
930 fm_init(fms + numfms);
931
932 #ifndef WITHOUT_OMEGA
933 if (format == OFM_FORMAT)
934 read_ofm(&fms[numfms], tfm_file, tfm_file_size);
935 else
936 #endif /* !WITHOUT_OMEGA */
937 {
938 read_tfm(&fms[numfms], tfm_file, tfm_file_size);
939 }
940
941 MFCLOSE(tfm_file);
942
943 fms[numfms].tex_name = NEW(strlen(tfm_name)+1, char);
944 strcpy(fms[numfms].tex_name, tfm_name);
945
946 if (verbose)
947 MESG(")");
948
949 return numfms++;
950 }
951
952 void
tfm_close_all(void)953 tfm_close_all (void)
954 {
955 int i;
956
957 if (fms) {
958 for (i = 0; i < numfms; i++) {
959 fm_clear(&(fms[i]));
960 }
961 RELEASE(fms);
962 }
963 }
964
965 #define CHECK_ID(n) do {\
966 if ((n) < 0 || (n) >= numfms)\
967 ERROR("TFM: Invalid TFM ID: %d", (n));\
968 } while (0)
969
970 fixword
tfm_get_fw_width(int font_id,int32_t ch)971 tfm_get_fw_width (int font_id, int32_t ch)
972 {
973 struct font_metric *fm;
974 int idx = 0;
975
976 CHECK_ID(font_id);
977
978 fm = &(fms[font_id]);
979 if (ch >= fm->firstchar && ch <= fm->lastchar) {
980 switch (fm->charmap.type) {
981 case MAPTYPE_CHAR:
982 idx = lookup_char(fm->charmap.data, ch);
983 if (idx < 0)
984 ERROR("Invalid char: %ld\n", ch);
985 break;
986 case MAPTYPE_RANGE:
987 idx = lookup_range(fm->charmap.data, ch);
988 if (idx < 0)
989 ERROR("Invalid char: %ld\n", ch);
990 break;
991 default:
992 idx = ch;
993 }
994 } else {
995 ERROR("Invalid char: %ld\n", ch);
996 }
997
998 return fm->widths[idx];
999 }
1000
1001 fixword
tfm_get_fw_height(int font_id,int32_t ch)1002 tfm_get_fw_height (int font_id, int32_t ch)
1003 {
1004 struct font_metric *fm;
1005 int idx = 0;
1006
1007 CHECK_ID(font_id);
1008
1009 fm = &(fms[font_id]);
1010 if (ch >= fm->firstchar && ch <= fm->lastchar) {
1011 switch (fm->charmap.type) {
1012 case MAPTYPE_CHAR:
1013 idx = lookup_char(fm->charmap.data, ch);
1014 if (idx < 0)
1015 ERROR("Invalid char: %ld\n", ch);
1016 break;
1017 case MAPTYPE_RANGE:
1018 idx = lookup_range(fm->charmap.data, ch);
1019 if (idx < 0)
1020 ERROR("Invalid char: %ld\n", ch);
1021 break;
1022 default:
1023 idx = ch;
1024 }
1025 } else {
1026 ERROR("Invalid char: %ld\n", ch);
1027 }
1028
1029 return fm->heights[idx];
1030 }
1031
1032 fixword
tfm_get_fw_depth(int font_id,int32_t ch)1033 tfm_get_fw_depth (int font_id, int32_t ch)
1034 {
1035 struct font_metric *fm;
1036 int idx = 0;
1037
1038 CHECK_ID(font_id);
1039
1040 fm = &(fms[font_id]);
1041 if (ch >= fm->firstchar && ch <= fm->lastchar) {
1042 switch (fm->charmap.type) {
1043 case MAPTYPE_CHAR:
1044 idx = lookup_char(fm->charmap.data, ch);
1045 if (idx < 0)
1046 ERROR("Invalid char: %ld\n", ch);
1047 break;
1048 case MAPTYPE_RANGE:
1049 idx = lookup_range(fm->charmap.data, ch);
1050 if (idx < 0)
1051 ERROR("Invalid char: %ld\n", ch);
1052 break;
1053 default:
1054 idx = ch;
1055 }
1056 } else {
1057 ERROR("Invalid char: %ld\n", ch);
1058 }
1059
1060 return fm->depths[idx];
1061 }
1062
1063
1064 /*
1065 * tfm_get_width returns the width of the font
1066 * as a (double) fraction of the design size.
1067 */
1068 double
tfm_get_width(int font_id,int32_t ch)1069 tfm_get_width (int font_id, int32_t ch)
1070 {
1071 return ((double) tfm_get_fw_width(font_id, ch)/FWBASE);
1072 }
1073
1074 #if 0
1075 double
1076 tfm_get_height (int font_id, int32_t ch)
1077 {
1078 return ((double) tfm_get_fw_height(font_id, ch)/FWBASE);
1079 }
1080
1081 double
1082 tfm_get_depth (int font_id, Sint32_t ch)
1083 {
1084 return ((double) tfm_get_fw_depth(font_id, ch)/FWBASE);
1085 }
1086 #endif
1087
1088 /* tfm_string_xxx() do not work for OFM... */
1089 fixword
tfm_string_width(int font_id,const unsigned char * s,unsigned len)1090 tfm_string_width (int font_id, const unsigned char *s, unsigned len)
1091 {
1092 fixword result = 0;
1093 struct font_metric *fm;
1094 unsigned i;
1095
1096 CHECK_ID(font_id);
1097
1098 fm = &(fms[font_id]);
1099 #ifndef WITHOUT_ASCII_PTEX
1100 if (fm->source == SOURCE_TYPE_JFM) {
1101 for (i = 0; i < len/2; i++) {
1102 int32_t ch;
1103
1104 ch = (s[2*i] << 8)|s[2*i+1];
1105 result += tfm_get_fw_width(font_id, ch);
1106 }
1107 } else
1108 #endif
1109 for (i = 0; i < len; i++) {
1110 result += tfm_get_fw_width(font_id, s[i]);
1111 }
1112
1113 return result;
1114 }
1115
1116 fixword
tfm_string_depth(int font_id,const unsigned char * s,unsigned len)1117 tfm_string_depth (int font_id, const unsigned char *s, unsigned len)
1118 {
1119 fixword result = 0;
1120 struct font_metric *fm;
1121 unsigned i;
1122
1123 CHECK_ID(font_id);
1124
1125 fm = &(fms[font_id]);
1126 #ifndef WITHOUT_ASCII_PTEX
1127 if (fm->source == SOURCE_TYPE_JFM) {
1128 for (i = 0; i < len/2; i++) {
1129 int32_t ch;
1130
1131 ch = (s[2*i] << 8)|s[2*i+1];
1132 result += tfm_get_fw_depth(font_id, ch);
1133 }
1134 } else
1135 #endif
1136 for (i = 0; i < len; i++) {
1137 result = MAX(result, tfm_get_fw_depth(font_id, s[i]));
1138 }
1139
1140 return result;
1141 }
1142
1143 fixword
tfm_string_height(int font_id,const unsigned char * s,unsigned len)1144 tfm_string_height (int font_id, const unsigned char *s, unsigned len)
1145 {
1146 fixword result = 0;
1147 struct font_metric *fm;
1148 unsigned i;
1149
1150 CHECK_ID(font_id);
1151
1152 fm = &(fms[font_id]);
1153 #ifndef WITHOUT_ASCII_PTEX
1154 if (fm->source == SOURCE_TYPE_JFM) {
1155 for (i = 0; i < len/2; i++) {
1156 int32_t ch;
1157
1158 ch = (s[2*i] << 8)|s[2*i+1];
1159 result += tfm_get_fw_height(font_id, ch);
1160 }
1161 } else
1162 #endif
1163 for (i = 0; i < len; i++) {
1164 result = MAX(result, tfm_get_fw_height(font_id, s[i]));
1165 }
1166
1167 return result;
1168 }
1169
1170 double
tfm_get_design_size(int font_id)1171 tfm_get_design_size (int font_id)
1172 {
1173 CHECK_ID(font_id);
1174
1175 return (double) (fms[font_id].designsize)/FWBASE*(72.0/72.27);
1176 }
1177
1178 #if 0
1179 char *
1180 tfm_get_codingscheme (int font_id)
1181 {
1182 CHECK_ID(font_id);
1183
1184 return fms[font_id].codingscheme;
1185 }
1186
1187 #ifndef WITHOUT_ASCII_PTEX
1188 /* Vertical version of JFM */
1189 int
1190 tfm_is_vert (int font_id)
1191 {
1192 CHECK_ID(font_id);
1193
1194 return (fms[font_id].fontdir == FONT_DIR_VERT) ? 1 : 0;
1195 }
1196 #else /* WITHOUT_ASCII_PTEX */
1197 int
1198 tfm_is_vert (int font_id)
1199 {
1200 return 0;
1201 }
1202 #endif /* !WITHOUT_ASCII_PTEX */
1203 #endif
1204
1205 int
tfm_exists(const char * tfm_name)1206 tfm_exists (const char *tfm_name)
1207 {
1208 char *fullname;
1209
1210 fullname = kpse_find_file(tfm_name, kpse_ofm_format, 0);
1211 if (fullname) {
1212 RELEASE(fullname);
1213 return 1;
1214 }
1215 fullname = kpse_find_file(tfm_name, kpse_tfm_format, 0);
1216 if (fullname) {
1217 RELEASE(fullname);
1218 return 1;
1219 }
1220
1221 return 0;
1222 }
1223