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