Bug Summary

File:backend/dvi/mdvi-lib/tfmfile.c
Warning:line 336, column 3
Value stored to 'i' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tfmfile.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/backend/dvi/mdvi-lib -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../../.. -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/backend/dvi/mdvi-lib -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-18-115154-54189-1 -x c tfmfile.c
1/* tfmfile.c -- readers for TFM, AFM, OTFM-0 and OTFM-1 files */
2/*
3 * Copyright (C) 2000, Matias Atria
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include <config.h>
21#include <stdio.h> /* tex-file.h needs this */
22#include <stdlib.h>
23#include <stdarg.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <unistd.h>
27
28#include "mdvi.h"
29#include "private.h"
30
31#ifdef WITH_AFM_FILES
32#undef TRUE1
33#undef FALSE0
34#include "afmparse.h"
35#endif
36
37typedef struct tfmpool {
38 struct tfmpool *next;
39 struct tfmpool *prev;
40 char *short_name;
41 int links;
42 TFMInfo tfminfo;
43} TFMPool;
44
45static ListHead tfmpool = {NULL((void*)0), NULL((void*)0), 0};
46static DviHashTable tfmhash;
47
48#define TFM_HASH_SIZE31 31
49
50#ifdef WORD_LITTLE_ENDIAN1
51static inline void swap_array(Uint32 *ptr, int n)
52{
53 Uint32 i;
54
55 while(n-- > 0) {
56 i = *ptr;
57 *ptr++ = ((i & 0xff000000) >> 24)
58 | ((i & 0x00ff0000) >> 8)
59 | ((i & 0x0000ff00) << 8)
60 | ((i & 0x000000ff) << 24);
61 }
62}
63#endif
64
65#ifdef WITH_AFM_FILES
66
67static int __PROTO(ofm_load_file(const char *filename, TFMInfo *info))ofm_load_file(const char *filename, TFMInfo *info);
68
69/* reading of AFM files */
70/* macro to convert between AFM and TFM units */
71#define AFM2TFM(x) FROUND((double)(x) * 0x100000 / 1000)(int)(((double)(x) * 0x100000 / 1000) + 0.5)
72int afm_load_file(const char *filename, TFMInfo *info)
73{
74 /* the information we want is:
75 * - tfmwidth
76 * - width and heights
77 * - character origins
78 */
79 FontInfo *fi = NULL((void*)0);
80 int status;
81 CharMetricInfo *cm;
82 FILE *in;
83
84 in = fopenkpse_fopen_trace(filename, "rb");
85 if(in == NULL((void*)0))
86 return -1;
87 status = afm_parse_file(in, &fi, P_GM);
88 fclosekpse_fclose_trace(in);
89
90 if(status != ok) {
91 mdvi_error(_("%s: Error reading AFM data\n")gettext("%s: Error reading AFM data\n"), filename);
92 return -1;
93 }
94
95 /* aim high */
96 info->chars = xnalloc(TFMChar, 256)(TFMChar *)mdvi_calloc((256), sizeof(TFMChar));
97 info->loc = 256;
98 info->hic = 0;
99 info->design = 0xa00000; /* fake -- 10pt */
100 info->checksum = 0; /* no checksum */
101 info->type = DviFontAFM;
102 mdvi_strncpy(info->coding, fi->gfi->encodingScheme, 63);
103 mdvi_strncpy(info->family, fi->gfi->familyName, 63);
104
105 /* now get the data */
106 for(cm = fi->cmi; cm < fi->cmi + fi->numOfChars; cm++) {
107 int code;
108 TFMChar *ch;
109
110 code = cm->code;
111 if(code < 0 || code > 255)
112 continue; /* ignore it */
113 ch = &info->chars[code];
114 ch->present = 1;
115 if(code < info->loc)
116 info->loc = code;
117 if(code > info->hic)
118 info->hic = code;
119 ch->advance = AFM2TFM(cm->wx);
120 /* this is the `leftSideBearing' */
121 ch->left = AFM2TFM(cm->charBBox.llx);
122 /* this is the height (ascent - descent) -- the sign is to follow
123 * TeX conventions, as opposed to Adobe's ones */
124 ch->depth = -AFM2TFM(cm->charBBox.lly);
125 /* this is the width (rightSideBearing - leftSideBearing) */
126 ch->right = AFM2TFM(cm->charBBox.urx);
127 /* this is the `ascent' */
128 ch->height = AFM2TFM(cm->charBBox.ury);
129 }
130
131 /* we don't need this anymore */
132 afm_free_fontinfo(fi);
133
134 /* optimize storage */
135 if(info->loc > 0 || info->hic < 256) {
136 memmove(&info->chars[0],
137 &info->chars[info->loc],
138 (info->hic - info->loc + 1) * sizeof(TFMChar));
139 info->chars = mdvi_realloc(info->chars,
140 (info->hic - info->loc + 1) * sizeof(TFMChar));
141 }
142
143 /* we're done */
144 return 0;
145}
146
147#endif /* WITH_AFM_FILES */
148
149int tfm_load_file(const char *filename, TFMInfo *info)
150{
151 int lf, lh, bc, ec, nw, nh, nd, ne;
152 int i, n;
153 Uchar *tfm;
154 Uchar *ptr;
155 struct stat st;
156 int size;
157 FILE *in;
158 Int32 *cb;
159 Int32 *charinfo;
160 Int32 *widths;
161 Int32 *heights;
162 Int32 *depths;
163 Uint32 checksum;
164
165 in = fopenkpse_fopen_trace(filename, "rb");
166 if(in == NULL((void*)0))
167 return -1;
168 tfm = NULL((void*)0);
169
170 DEBUG((DBG_FONTS, "(mt) reading TFM file `%s'\n",__debug ((1 << 1), "(mt) reading TFM file `%s'\n", filename
)
171 filename))__debug ((1 << 1), "(mt) reading TFM file `%s'\n", filename
)
;
172 /* We read the entire TFM file into core */
173 if(fstat(fileno(in), &st) < 0)
174 return -1;
175 /* according to the spec, TFM files are smaller than 16K */
176 if(st.st_size == 0 || st.st_size >= 16384)
177 goto bad_tfm;
178
179 /* allocate a word-aligned buffer to hold the file */
180 size = 4 * ROUND(st.st_size, 4)(((st.st_size) + (4) - 1) / (4));
181 if(size != st.st_size)
182 mdvi_warning(_("Warning: TFM file `%s' has suspicious size\n")gettext("Warning: TFM file `%s' has suspicious size\n"),
183 filename);
184 tfm = (Uchar *)mdvi_malloc(size);
185 if(fread(tfm, st.st_size, 1, in) != 1)
186 goto error;
187 /* we don't need this anymore */
188 fclosekpse_fclose_trace(in);
189 in = NULL((void*)0);
190
191 /* not a checksum, but serves a similar purpose */
192 checksum = 0;
193
194 ptr = tfm;
195 /* get the counters */
196 lf = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2)));
197 lh = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); checksum += 6 + lh;
198 bc = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2)));
199 ec = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); checksum += ec - bc + 1;
200 nw = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); checksum += nw;
201 nh = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); checksum += nh;
202 nd = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); checksum += nd;
203 checksum += muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); /* skip italics correction count */
204 checksum += muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); /* skip lig/kern table size */
205 checksum += muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); /* skip kern table size */
206 ne = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); checksum += ne;
207 checksum += muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2))); /* skip # of font parameters */
208
209 size = ec - bc + 1;
210 cb = (Int32 *)tfm; cb += 6 + lh;
211 charinfo = cb; cb += size;
212 widths = cb; cb += nw;
213 heights = cb; cb += nh;
214 depths = cb;
215
216 if(widths[0] || heights[0] || depths[0] ||
217 checksum != lf || bc - 1 > ec || ec > 255 || ne > 256)
218 goto bad_tfm;
219
220 /* from this point on, no error checking is done */
221
222 /* now we're at the header */
223 /* get the checksum */
224 info->checksum = muget4(ptr)(((ptr)) += (4), mugetn(((ptr))-(4), (4)));
225 /* get the design size */
226 info->design = muget4(ptr)(((ptr)) += (4), mugetn(((ptr))-(4), (4)));
227 /* get the coding scheme */
228 if(lh > 2) {
229 /* get the coding scheme */
230 i = n = msget1(ptr)(((ptr)) += (1), msgetn(((ptr))-(1), (1)));
231 if(n < 0 || n > 39) {
232 mdvi_warning(_("%s: font coding scheme truncated to 40 bytes\n")gettext("%s: font coding scheme truncated to 40 bytes\n"),
233 filename);
234 n = 39;
235 }
236 memcpy(info->coding, ptr, n)bcopy ((ptr), (info->coding), (n));
237 info->coding[n] = 0;
238 ptr += i;
239 } else
240 strcpy(info->coding, "FontSpecific");
241 /* get the font family */
242 if(lh > 12) {
243 n = msget1(ptr)(((ptr)) += (1), msgetn(((ptr))-(1), (1)));
244 if(n > 0) {
245 i = Max(n, 63)(((n) > (63)) ? (n) : (63));
246 memcpy(info->family, ptr, i)bcopy ((ptr), (info->family), (i));
247 info->family[i] = 0;
248 } else
249 strcpy(info->family, "unspecified");
250 ptr += n;
251 }
252 /* now we don't read from `ptr' anymore */
253
254 info->loc = bc;
255 info->hic = ec;
256 info->type = DviFontTFM;
257
258 /* allocate characters */
259 info->chars = xnalloc(TFMChar, size)(TFMChar *)mdvi_calloc((size), sizeof(TFMChar));
260
261
262#ifdef WORD_LITTLE_ENDIAN1
263 /* byte-swap the three arrays at once (they are consecutive in memory) */
264 swap_array((Uint32 *)widths, nw + nh + nd);
265#endif
266
267 /* get the relevant data */
268 ptr = (Uchar *)charinfo;
269 for(i = bc; i <= ec; ptr += 3, i++) {
270 int ndx;
271
272 ndx = (int)*ptr; ptr++;
273 info->chars[i-bc].advance = widths[ndx];
274 /* TFM files lack this information */
275 info->chars[i-bc].left = 0;
276 info->chars[i-bc].right = widths[ndx];
277 info->chars[i-bc].present = (ndx != 0);
278 if(ndx) {
279 ndx = ((*ptr >> 4) & 0xf);
280 info->chars[i-bc].height = heights[ndx];
281 ndx = (*ptr & 0xf);
282 info->chars[i-bc].depth = depths[ndx];
283 }
284 }
285
286 /* free everything */
287 mdvi_free(tfm);
288
289 return 0;
290
291bad_tfm:
292 mdvi_error(_("%s: File corrupted, or not a TFM file\n")gettext("%s: File corrupted, or not a TFM file\n"), filename);
293error:
294 if(tfm) mdvi_free(tfm);
295 if(in) fclosekpse_fclose_trace(in);
296 return -1;
297}
298
299static int ofm1_load_file(FILE *in, TFMInfo *info)
300{
301 int lh, bc, ec, nw, nh, nd;
302 int nco, ncw, npc;
303 int i;
304 int n;
305 int size;
306 Int32 *tfm;
307 Int32 *widths;
308 Int32 *heights;
309 Int32 *depths;
310 TFMChar *tch;
311 TFMChar *end;
312
313 lh = fuget4(in)fugetn((in), 4);
314 bc = fuget4(in)fugetn((in), 4);
315 ec = fuget4(in)fugetn((in), 4);
316 nw = fuget4(in)fugetn((in), 4);
317 nh = fuget4(in)fugetn((in), 4);
318 nd = fuget4(in)fugetn((in), 4);
319 fuget4(in)fugetn((in), 4); /* italics */
320 fuget4(in)fugetn((in), 4); /* lig-kern */
321 fuget4(in)fugetn((in), 4); /* kern */
322 fuget4(in)fugetn((in), 4); /* extensible recipe */
323 fuget4(in)fugetn((in), 4); /* parameters */
324 fuget4(in)fugetn((in), 4); /* direction */
325 nco = fuget4(in)fugetn((in), 4);
326 ncw = fuget4(in)fugetn((in), 4);
327 npc = fuget4(in)fugetn((in), 4);
328
329 /* get the checksum */
330 info->checksum = fuget4(in)fugetn((in), 4);
331 /* the design size */
332 info->design = fuget4(in)fugetn((in), 4);
333 /* get the coding scheme */
334 if(lh > 2) {
335 /* get the coding scheme */
336 i = n = fsget1(in)fsgetn((in), 1);
Value stored to 'i' is never read
337 if(n < 0 || n > 39)
338 n = 39;
339 fread(info->coding, 39, 1, in);
340 info->coding[n] = 0;
341 } else
342 strcpy(info->coding, "FontSpecific");
343 /* get the font family */
344 if(lh > 12) {
345 n = fsget1(in)fsgetn((in), 1);
346 if(n > 0) {
347 i = Max(n, 63)(((n) > (63)) ? (n) : (63));
348 fread(info->family, i, 1, in);
349 info->family[i] = 0;
350 } else
351 strcpy(info->family, "unspecified");
352 }
353 tfm = NULL((void*)0);
354
355 /* jump to the beginning of the char-info table */
356 fseek(in, 4L*nco, SEEK_SET0);
357
358 size = ec - bc + 1;
359 info->loc = bc;
360 info->hic = ec;
361 info->chars = xnalloc(TFMChar, size)(TFMChar *)mdvi_calloc((size), sizeof(TFMChar));
362 end = info->chars + size;
363
364 for(tch = info->chars, i = 0; i < ncw; i++) {
365 TFMChar ch;
366 int nr;
367
368 /* in the characters we store the actual indices */
369 ch.advance = fuget2(in)fugetn((in), 2);
370 ch.height = fuget1(in)((unsigned)getc(in));
371 ch.depth = fuget1(in)((unsigned)getc(in));
372 /* skip 2nd word */
373 fuget4(in)fugetn((in), 4);
374 /* get # of repeats */
375 nr = fuget2(in)fugetn((in), 2);
376 /* skip parameters */
377 fseek(in, (long)npc * 2, SEEK_CUR1);
378 /* if npc is odd, skip padding */
379 if(npc & 1) fuget2(in)fugetn((in), 2);
380
381 /* now repeat the character */
382 while(nr-- >= 0 && tch < end)
383 memcpy(tch++, &ch, sizeof(TFMChar))bcopy ((&ch), (tch++), (sizeof(TFMChar)));
384 if(tch == end)
385 goto bad_tfm;
386 }
387
388 /* I wish we were done, but we aren't */
389
390 /* get the widths, heights and depths */
391 size = nw + nh + nd;
392 tfm = xnalloc(Int32, size)(Int32 *)mdvi_calloc((size), sizeof(Int32));
393 /* read them in one sweep */
394 if(fread(tfm, 4, size, in) != size) {
395 mdvi_free(tfm);
396 goto bad_tfm;
397 }
398
399 /* byte-swap things if necessary */
400#ifdef WORD_LITTLE_ENDIAN1
401 swap_array((Uint32 *)tfm, size);
402#endif
403 widths = tfm;
404 heights = widths + nw;
405 depths = heights + nh;
406
407 if(widths[0] || heights[0] || depths[0])
408 goto bad_tfm;
409
410 /* now fix the characters */
411 size = ec - bc + 1;
412 for(tch = info->chars; tch < end; tch++) {
413 tch->present = (tch->advance != 0);
414 tch->advance = widths[tch->advance];
415 tch->height = heights[tch->height];
416 tch->depth = depths[tch->depth];
417 tch->left = 0;
418 tch->right = tch->advance;
419 }
420
421 /* NOW we're done */
422 mdvi_free(tfm);
423 return 0;
424
425bad_tfm:
426 if(tfm) mdvi_free(tfm);
427 return -1;
428}
429
430/* we don't read OFM files into memory, because they can potentially be large */
431static int ofm_load_file(const char *filename, TFMInfo *info)
432{
433 int lf, lh, bc, ec, nw, nh, nd;
434 int i, n;
435 Int32 *tfm;
436 Uchar *ptr;
437 int size;
438 FILE *in;
439 Int32 *cb;
440 Int32 *charinfo;
441 Int32 *widths;
442 Int32 *heights;
443 Int32 *depths;
444 Uint32 checksum;
445 int olevel;
446 int nwords;
447
448 in = fopenkpse_fopen_trace(filename, "rb");
449 if(in == NULL((void*)0))
450 return -1;
451
452 /* not a checksum, but serves a similar purpose */
453 checksum = 0;
454
455 /* get the counters */
456 /* get file level */
457 olevel = fsget2(in)fsgetn((in), 2);
458 if(olevel != 0)
459 goto bad_tfm;
460 olevel = fsget2(in)fsgetn((in), 2);
461 if(olevel != 0) {
462 DEBUG((DBG_FONTS, "(mt) reading Level-1 OFM file `%s'\n",__debug ((1 << 1), "(mt) reading Level-1 OFM file `%s'\n"
, filename)
463 filename))__debug ((1 << 1), "(mt) reading Level-1 OFM file `%s'\n"
, filename)
;
464 /* we handle level-1 files separately */
465 if(ofm1_load_file(in, info) < 0)
466 goto bad_tfm;
467 return 0;
468 }
469
470 DEBUG((DBG_FONTS, "(mt) reading Level-0 OFM file `%s'\n", filename))__debug ((1 << 1), "(mt) reading Level-0 OFM file `%s'\n"
, filename)
;
471 nwords = 14;
472 lf = fuget4(in)fugetn((in), 4); checksum = nwords;
473 lh = fuget4(in)fugetn((in), 4); checksum += lh;
474 bc = fuget4(in)fugetn((in), 4);
475 ec = fuget4(in)fugetn((in), 4); checksum += 2 * (ec - bc + 1);
476 nw = fuget4(in)fugetn((in), 4); checksum += nw;
477 nh = fuget4(in)fugetn((in), 4); checksum += nh;
478 nd = fuget4(in)fugetn((in), 4); checksum += nd;
479 checksum += fuget4(in)fugetn((in), 4); /* skip italics correction count */
480 checksum += 2*fuget4(in)fugetn((in), 4); /* skip lig/kern table size */
481 checksum += fuget4(in)fugetn((in), 4); /* skip kern table size */
482 checksum += 2*fuget4(in)fugetn((in), 4); /* skip extensible recipe count */
483 checksum += fuget4(in)fugetn((in), 4); /* skip # of font parameters */
484
485 /* I have found several .ofm files that seem to have the
486 * font-direction word missing, so we try to detect that here */
487 if(checksum == lf + 1) {
488 DEBUG((DBG_FONTS, "(mt) font direction missing in `%s'\n",__debug ((1 << 1), "(mt) font direction missing in `%s'\n"
, filename)
489 filename))__debug ((1 << 1), "(mt) font direction missing in `%s'\n"
, filename)
;
490 checksum--;
491 nwords--;
492 } else {
493 /* skip font direction */
494 fuget4(in)fugetn((in), 4);
495 }
496
497 if(checksum != lf || bc > ec + 1 || ec > 65535)
498 goto bad_tfm;
499
500 /* now we're at the header */
501
502 /* get the checksum */
503 info->checksum = fuget4(in)fugetn((in), 4);
504 /* get the design size */
505 info->design = fuget4(in)fugetn((in), 4);
506
507 /* get the coding scheme */
508 if(lh > 2) {
509 /* get the coding scheme */
510 i = n = fsget1(in)fsgetn((in), 1);
511 if(n < 0 || n > 39) {
512 mdvi_warning(_("%s: font coding scheme truncated to 40 bytes\n")gettext("%s: font coding scheme truncated to 40 bytes\n"),
513 filename);
514 n = 39;
515 }
516 fread(info->coding, 39, 1, in);
517 info->coding[n] = 0;
518 } else
519 strcpy(info->coding, "FontSpecific");
520 /* get the font family */
521 if(lh > 12) {
522 n = fsget1(in)fsgetn((in), 1);
523 if(n > 0) {
524 i = Max(n, 63)(((n) > (63)) ? (n) : (63));
525 fread(info->family, i, 1, in);
526 info->family[i] = 0;
527 } else
528 strcpy(info->family, "unspecified");
529 }
530
531 /* now skip anything else in the header */
532 fseek(in, 4L*(nwords + lh), SEEK_SET0);
533 /* and read everything at once */
534 size = 2*(ec - bc + 1) + nw + nh + nd;
535 tfm = xnalloc(Int32, size * sizeof(Int32))(Int32 *)mdvi_calloc((size * sizeof(Int32)), sizeof(Int32));
536 if(fread(tfm, 4, size, in) != size) {
537 mdvi_free(tfm);
538 goto bad_tfm;
539 }
540 /* byte-swap all the tables at once */
541#ifdef WORD_LITTLE_ENDIAN1
542 swap_array((Uint32 *)tfm, size);
543#endif
544 cb = tfm;
545 charinfo = cb; cb += 2*(ec - bc + 1);
546 widths = cb; cb += nw;
547 heights = cb; cb += nh;
548 depths = cb;
549
550 if(widths[0] || heights[0] || depths[0]) {
551 mdvi_free(tfm);
552 goto bad_tfm;
553 }
554
555 /* from this point on, no error checking is done */
556
557 /* we don't need this anymore */
558 fclosekpse_fclose_trace(in);
559
560 /* now we don't read from `ptr' anymore */
561
562 info->loc = bc;
563 info->hic = ec;
564 info->type = DviFontTFM;
565
566 /* allocate characters */
567 info->chars = xnalloc(TFMChar, size)(TFMChar *)mdvi_calloc((size), sizeof(TFMChar));
568
569 /* get the relevant data */
570 ptr = (Uchar *)charinfo;
571 for(i = bc; i <= ec; ptr += 4, i++) {
572 int ndx;
573
574 ndx = muget2(ptr)(((ptr)) += (2), mugetn(((ptr))-(2), (2)));
575 info->chars[i-bc].advance = widths[ndx];
576 /* TFM files lack this information */
577 info->chars[i-bc].left = 0;
578 info->chars[i-bc].right = widths[ndx];
579 info->chars[i-bc].present = (ndx != 0);
580 ndx = muget1(ptr)(((ptr)) += (1), mugetn(((ptr))-(1), (1)));
581 info->chars[i-bc].height = heights[ndx];
582 ndx = muget1(ptr)(((ptr)) += (1), mugetn(((ptr))-(1), (1)));
583 info->chars[i-bc].depth = depths[ndx];
584 }
585
586 mdvi_free(tfm);
587 return 0;
588
589bad_tfm:
590 mdvi_error(_("%s: File corrupted, or not a TFM file\n")gettext("%s: File corrupted, or not a TFM file\n"), filename);
591 fclosekpse_fclose_trace(in);
592 return -1;
593}
594
595char *lookup_font_metrics(const char *name, int *type)
596{
597 char *file;
598
599 switch(*type) {
600#ifndef WITH_AFM_FILES
601 case DviFontAny:
602#endif
603 case DviFontTFM:
604 file = kpse_find_tfm(name)kpse_find_file (name, kpse_tfm_format, 1);
605 *type = DviFontTFM;
606 break;
607 case DviFontOFM: {
608 file = kpse_find_ofm(name)kpse_find_file (name, kpse_ofm_format, 1);
609 /* we may have gotten a TFM back */
610 if(file != NULL((void*)0)) {
611 const char *ext = file_extension(file);
612 if(ext && STREQ(ext, "tfm")(((ext) != ((void*)0)) && (("tfm") != ((void*)0)) &&
(strcmp (ext, "tfm") == 0))
)
613 *type = DviFontTFM;
614 }
615 break;
616 }
617#ifdef WITH_AFM_FILES
618 case DviFontAFM:
619 file = kpse_find_file(name, kpse_afm_format, 0);
620 break;
621 case DviFontAny:
622 file = kpse_find_file(name, kpse_afm_format, 0);
623 *type = DviFontAFM;
624 if(file == NULL((void*)0)) {
625 file = kpse_find_tfm(name)kpse_find_file (name, kpse_tfm_format, 1);
626 *type = DviFontTFM;
627 }
628 break;
629#endif
630 default:
631 return NULL((void*)0);
632 }
633
634 return file;
635}
636
637/*
638 * The next two functions are just wrappers for the font metric loaders,
639 * and use the pool of TFM data
640 */
641
642/* this is how we interpret arguments:
643 * - if filename is NULL, we look for files of the given type,
644 * unless type is DviFontAny, in which case we try all the
645 * types we know of.
646 * - if filename is not NULL, we look at `type' to decide
647 * how to read the file. If type is DviFontAny, we just
648 * return an error.
649 */
650TFMInfo *get_font_metrics(const char *short_name, int type, const char *filename)
651{
652 TFMPool *tfm = NULL((void*)0);
653 int status;
654 char *file;
655
656 if(tfmpool.count) {
657 tfm = (TFMPool *)mdvi_hash_lookup(&tfmhash,
658 MDVI_KEY(short_name)((DviHashKey)(short_name)));
659 if(tfm != NULL((void*)0)) {
660 DEBUG((DBG_FONTS, "(mt) reusing metric file `%s' (%d links)\n",__debug ((1 << 1), "(mt) reusing metric file `%s' (%d links)\n"
, short_name, tfm->links)
661 short_name, tfm->links))__debug ((1 << 1), "(mt) reusing metric file `%s' (%d links)\n"
, short_name, tfm->links)
;
662 tfm->links++;
663 return &tfm->tfminfo;
664 }
665 }
666
667 file = filename ? (char *)filename : lookup_font_metrics(short_name, &type);
668 if(file == NULL((void*)0))
669 return NULL((void*)0);
670
671 tfm = xalloc(TFMPool)(TFMPool *)mdvi_malloc(sizeof(TFMPool));
672 DEBUG((DBG_FONTS, "(mt) loading font metric data from `%s'\n", file, file))__debug ((1 << 1), "(mt) loading font metric data from `%s'\n"
, file, file)
;
673 switch(type) {
674 case DviFontTFM:
675 status = tfm_load_file(file, &tfm->tfminfo);
676 break;
677 case DviFontOFM:
678 status = ofm_load_file(file, &tfm->tfminfo);
679 break;
680#ifdef WITH_AFM_FILES
681 case DviFontAFM:
682 status = afm_load_file(file, &tfm->tfminfo);
683 break;
684#endif
685 default:
686 status = -1;
687 break;
688 }
689 if(file != filename)
690 mdvi_free(file);
691 if(status < 0) {
692 mdvi_free(tfm);
693 return NULL((void*)0);
694 }
695 tfm->short_name = mdvi_strdup(short_name);
696
697 /* add it to the pool */
698 if(tfmpool.count == 0)
699 mdvi_hash_create(&tfmhash, TFM_HASH_SIZE31);
700 mdvi_hash_add(&tfmhash, MDVI_KEY(tfm->short_name)((DviHashKey)(tfm->short_name)),
701 tfm, MDVI_HASH_UNCHECKED2);
702 listh_prepend(&tfmpool, LIST(tfm)((List *)(tfm)));
703 tfm->links = 1;
704
705 return &tfm->tfminfo;
706}
707
708void free_font_metrics(TFMInfo *info)
709{
710 TFMPool *tfm;
711
712 if(tfmpool.count == 0)
713 return;
714 /* get the entry -- can't use the hash table for this, because
715 * we don't have the short name */
716 for(tfm = (TFMPool *)tfmpool.head; tfm; tfm = tfm->next)
717 if(info == &tfm->tfminfo)
718 break;
719 if(tfm == NULL((void*)0))
720 return;
721 if(--tfm->links > 0) {
722 DEBUG((DBG_FONTS, "(mt) %s not removed, still in use\n",__debug ((1 << 1), "(mt) %s not removed, still in use\n"
, tfm->short_name)
723 tfm->short_name))__debug ((1 << 1), "(mt) %s not removed, still in use\n"
, tfm->short_name)
;
724 return;
725 }
726 mdvi_hash_remove_ptr(&tfmhash, MDVI_KEY(tfm->short_name)((DviHashKey)(tfm->short_name)));
727
728 DEBUG((DBG_FONTS, "(mt) removing unused TFM data for `%s'\n", tfm->short_name))__debug ((1 << 1), "(mt) removing unused TFM data for `%s'\n"
, tfm->short_name)
;
729 listh_remove(&tfmpool, LIST(tfm)((List *)(tfm)));
730 mdvi_free(tfm->short_name);
731 mdvi_free(tfm->tfminfo.chars);
732 mdvi_free(tfm);
733}
734
735void flush_font_metrics(void)
736{
737 TFMPool *ptr;
738
739 for(; (ptr = (TFMPool *)tfmpool.head); ) {
740 tfmpool.head = LIST(ptr->next)((List *)(ptr->next));
741
742 mdvi_free(ptr->short_name);
743 mdvi_free(ptr->tfminfo.chars);
744 mdvi_free(ptr);
745 }
746 mdvi_hash_reset(&tfmhash, 0);
747}