1 /*
2 * Here's the code to load a PK file into memory.
3 * Individual bitmaps won't be unpacked until they prove to be needed.
4 */
5 #include "dvips.h" /* The copyright notice in that file is included too! */
6 #ifdef OS2
7 #include <stdlib.h>
8 #endif
9 #ifdef KPATHSEA
10 #include <kpathsea/c-pathmx.h>
11 #include <kpathsea/concatn.h>
12 #include <kpathsea/tex-glyph.h>
13 #include <kpathsea/tex-make.h>
14 #include <kpathsea/lib.h>
15 #ifndef MAXPATHLEN
16 #define MAXPATHLEN (256)
17 #endif
18 #else
19 #if defined(SYSV) || defined(VMS) || (defined(MSDOS) && !defined(__DJGPP__)) || defined(OS2) || defined(ATARIST)
20 #define MAXPATHLEN (256)
21 #else
22 #include <sys/param.h> /* for MAXPATHLEN */
23 #endif
24 #endif
25 /*
26 * The external declarations:
27 */
28 #include "protos_add.h"
29
30 char errbuf[1000];
31 int lastresortsizes[40];
32 /*
33 * Now we have some routines to get stuff from the PK file.
34 * Subroutine pkbyte returns the next byte.
35 */
36 FILE *pkfile;
37 char name[MAXPATHLEN];
38 void
badpk(const char * s)39 badpk(const char *s)
40 {
41 char *msg = concatn ("! Bad PK file ", name, ": ", s, NULL);
42 error(msg);
43 }
44
45 shalfword
pkbyte(void)46 pkbyte(void)
47 {
48 register shalfword i;
49
50 if ((i=getc(pkfile))==EOF)
51 badpk("unexpected eof");
52 return(i);
53 }
54
55 integer
pkquad(void)56 pkquad(void)
57 {
58 register integer i;
59
60 i = pkbyte();
61 if (i > 127)
62 i -= 256;
63 i = i * 256 + pkbyte();
64 i = i * 256 + pkbyte();
65 i = i * 256 + pkbyte();
66 return(i);
67 }
68
69 integer
pktrio(void)70 pktrio(void)
71 {
72 register integer i;
73
74 i = pkbyte();
75 i = i * 256 + pkbyte();
76 i = i * 256 + pkbyte();
77 return(i);
78 }
79
80
81 /*
82 * pkopen opens the pk file. This is system dependent. We work really
83 * hard to open some sort of PK file.
84 */
85 #ifdef VMCMS /* IBM: VM/CMS - we let DVIPS EXEC handle this after
86 the DVIPS MODULE has finished to avoid
87 complications with system calls. */
88 int dontmakefont = 0;
89 #else
90 #ifdef MVSXA /* IBM: MVS/XA - we let system administrator handle this on
91 MVS/XA since some printers can't get to user
92 fonts anyway */
93 int dontmakefont = 1;
94 #else
95 int dontmakefont = 0; /* if makefont fails once we won't try again */
96 #endif /* IBM: VM/CMS */
97 #endif
98
99 static void
lectureuser(void)100 lectureuser(void) {
101 static int userwarned = 0;
102
103 if (! userwarned) {
104 error("Such scaling will generate extremely poor output.");
105 userwarned = 1;
106 }
107 }
108 static Boolean
pkopen(register fontdesctype * fd)109 pkopen(register fontdesctype *fd)
110 {
111 register char *d, *n;
112 const char *name_ret;
113 #ifdef KPATHSEA
114 int dpi_ret;
115 #else
116 int vdpi;
117 #endif
118 d = fd->area;
119 n = fd->name;
120 #ifndef KPATHSEA
121 if (*d==0)
122 d = pkpath;
123 #endif
124 #ifdef FONTLIB
125 if (*(fd->area) == 0) {
126 int del;
127 for (del=0; del<=RES_TOLERANCE(fd->dpi); del=del>0?-del:-del+1) {
128 if ((pkfile=flisearch(n, fd->dpi + del)) != (FILE *)NULL )
129 return(1);
130 }
131 }
132 #endif
133 {
134 #ifdef KPATHSEA
135 char *this_name = concat (d, n);
136
137 pkfile = pksearch(this_name, READBIN, fd->dpi, &name_ret, &dpi_ret);
138
139 if (!pkfile || !FILESTRCASEEQ (this_name, name_ret)) {
140 char *msg = concatn ("Font ", fd->area, n, " not found; ", NULL);
141 /* wasting some memory */
142 if (!pkfile)
143 msg = concat (msg, "characters will be left blank.");
144 else
145 msg = concat3 (msg, "using ", name_ret);
146 dontmakefont = 1;
147 error (msg);
148
149 } else if (!kpse_bitmap_tolerance ((double) dpi_ret, (double) fd->dpi))
150 {
151 fd->loadeddpi = dpi_ret;
152 fd->alreadyscaled = 0;
153 sprintf(errbuf,
154 "Font %s at %d not found; scaling %d instead.",
155 n, fd->dpi, dpi_ret);
156 error(errbuf);
157 lectureuser();
158 }
159
160 if (this_name != name_ret)
161 free (this_name);
162
163 return pkfile != NULL;
164 }
165 #else
166 int del;
167 for (del=0; del<=RES_TOLERANCE(fd->dpi); del=del>0?-del:-del+1) {
168 if (actualdpi == vactualdpi) {
169 vdpi = 0;
170 } else {
171 vdpi = (2 * ((long)vactualdpi) * (fd->dpi + del) + actualdpi)
172 / (2 * actualdpi);
173 }
174 #ifdef MVSXA
175 sprintf(name, "pk%d(%s)", fd->dpi + del, n);
176 #else
177 sprintf(name, "%s.%dpk", n, fd->dpi + del);
178 #endif
179 if (0 != (pkfile=pksearch(d, name, READBIN, n, fd->dpi + del, vdpi)))
180 return(1);
181 }
182 }
183 if (d == pkpath) {
184 if (actualdpi == vactualdpi) {
185 vdpi = 0;
186 } else {
187 vdpi = (2 * ((long)vactualdpi) * fd->dpi + actualdpi)
188 / (2 * actualdpi);
189 }
190 #ifdef MVSXA
191 sprintf(name, "pk%d(%s)", fd->dpi, n);
192 #else
193 sprintf(name, "%s.%dpk", n, fd->dpi);
194 #endif
195 makefont(n, (int)fd->dpi, DPI);
196 if (dontmakefont == 0 &&
197 (pkfile = pksearch(d, name, READBIN, n, fd->dpi, vdpi)))
198 return(1);
199 #ifndef MSDOS
200 #ifdef OS2
201 if (_osmode == OS2_MODE)
202 dontmakefont = 1; /* failed so don't try again under OS/2,
203 but do try for MSDOS */
204 #else
205 #ifndef ATARIST
206 dontmakefont = 1;
207 #endif
208 #endif
209 #endif
210 }
211 /*
212 * If nothing above worked, then we get desparate. We attempt to
213 * open the stupid font at one of a small set of predefined sizes,
214 * and then use PostScript scaling to generate the correct size.
215 *
216 * We much prefer scaling up to scaling down, since scaling down
217 * can omit character features, so we try the larger sizes first,
218 * and then work down.
219 */
220 {
221 int i, j;
222
223 if (lastresortsizes[0] && fd->dpi < 30000) {
224 for (i=0; lastresortsizes[i] < fd->dpi; i++);
225 for (j = i-1; j >= 0; j--) {
226 if (actualdpi == vactualdpi) {
227 vdpi = 0;
228 } else {
229 vdpi = (2 * ((long)vactualdpi) * lastresortsizes[j] + actualdpi)
230 / (2 * actualdpi);
231 }
232 #ifdef MVSXA
233 sprintf(name, "pk%d(%s)", lastresortsizes[j], n);
234 #else
235 sprintf(name, "%s.%dpk", n, lastresortsizes[j]);
236 #endif
237 #ifdef FONTLIB
238 if (0 != (pkfile=flisearch(n,(halfword)lastresortsizes[j]))
239 || 0 != (pkfile=pksearch(d, name, READBIN, n,
240 (halfword)lastresortsizes[j], vdpi))) {
241 #else
242 if (0 != (pkfile=pksearch(d, name, READBIN, n,
243 (halfword)lastresortsizes[j], vdpi))) {
244 #endif
245 fd->loadeddpi = lastresortsizes[j];
246 fd->alreadyscaled = 0;
247 sprintf(errbuf,
248 "Font %s at %d dpi not found; scaling %d instead.",
249 n, fd->dpi, lastresortsizes[j]);
250 error(errbuf);
251 lectureuser();
252 return 1;
253 }
254 }
255 for (j = i; lastresortsizes[j] < 30000; j++) {
256 if (actualdpi == vactualdpi) {
257 vdpi = 0;
258 } else {
259 vdpi = (2 * ((long)vactualdpi) * lastresortsizes[j] + actualdpi)
260 / (2 * actualdpi);
261 }
262 sprintf(name, "%s.%dpk", n, lastresortsizes[j]);
263 #ifdef FONTLIB
264 if (0 != (pkfile=flisearch(n, (halfword)lastresortsizes[j]))
265 || 0 != (pkfile=pksearch(d, name, READBIN, n,
266 (halfword)lastresortsizes[j], vdpi))) {
267 #else
268 if (0 != (pkfile=pksearch(d, name, READBIN, n,
269 (halfword)lastresortsizes[j], vdpi))) {
270 #endif
271 fd->loadeddpi = lastresortsizes[j];
272 fd->alreadyscaled = 0;
273 sprintf(errbuf,
274 "Font %s at %d dpi not found; scaling %d instead.",
275 name, fd->dpi, lastresortsizes[j]);
276 error(errbuf);
277 lectureuser();
278 return 1;
279 }
280 }
281 }
282 }
283 #ifdef MVSXA
284 sprintf(name, "%s.pk%d", n, fd->dpi);
285 #else
286 sprintf(name, "%s.%dpk", n, fd->dpi);
287 #endif
288 sprintf(errbuf,
289 "Font %s%s not found, characters will be left blank.",
290 fd->area, name);
291 error(errbuf);
292 return(0);
293 #endif /* KPATHSEA */
294 }
295
296 /*
297 * Now our loadfont routine. We return an integer indicating the
298 * highest character code in the font, so we know how much space
299 * to reserve for the character. (It's returned in the font
300 * structure, along with everything else.)
301 */
302 void
loadfont(register fontdesctype * curfnt)303 loadfont(register fontdesctype *curfnt)
304 {
305 register integer i;
306 register shalfword cmd;
307 register integer k;
308 register integer length = 0;
309 register shalfword cc = 0;
310 register integer scaledsize = curfnt->scaledsize;
311 register quarterword *tempr;
312 register chardesctype *cd = 0;
313 int maxcc = 0;
314 int munged = 0;
315 /*
316 * We clear out some pointers:
317 */
318 if (curfnt->loaded == 3) {
319 for (i=0; i<256; i++) {
320 curfnt->chardesc[i].TFMwidth = 0;
321 curfnt->chardesc[i].packptr = NULL;
322 curfnt->chardesc[i].pixelwidth = 0;
323 curfnt->chardesc[i].flags &= EXISTS;
324 curfnt->chardesc[i].flags2 = 0;
325 }
326 } else {
327 for (i=0; i<256; i++) {
328 curfnt->chardesc[i].TFMwidth = 0;
329 curfnt->chardesc[i].packptr = NULL;
330 curfnt->chardesc[i].pixelwidth = 0;
331 curfnt->chardesc[i].flags = 0;
332 curfnt->chardesc[i].flags2 = 0;
333 }
334 }
335 curfnt->maxchars = 256; /* just in case we return before the end */
336 if (!pkopen(curfnt)) {
337 tfmload(curfnt);
338 return;
339 }
340 curfnt->dir = 0;
341 if (!quiet) {
342 if (strlen(realnameoffile) + prettycolumn > STDOUTSIZE) {
343 fprintf(stderr, "\n");
344 prettycolumn = 0;
345 }
346 fprintf(stderr, "<%s>", realnameoffile);
347 prettycolumn += strlen(realnameoffile) + 2;
348 }
349 #ifdef DEBUG
350 if (dd(D_FONTS))
351 fprintf(stderr,"Loading pk font %s at %.1fpt\n",
352 curfnt->name, (real)scaledsize/(alpha*0x100000));
353 #endif /* DEBUG */
354 if (pkbyte()!=247)
355 badpk("expected pre");
356 if (pkbyte()!=89)
357 badpk("wrong id byte");
358 for(i=pkbyte(); i>0; i--)
359 pkbyte();
360 k = (integer)(alpha * (real)pkquad());
361 if (k > curfnt->designsize + fsizetol
362 || k < curfnt->designsize - fsizetol) {
363 char *msg = concat ("Design size mismatch in font ", curfnt->name);
364 error (msg);
365 free (msg);
366 }
367 k = pkquad();
368 if (k && curfnt->checksum)
369 if (k!=curfnt->checksum) {
370 char *msg = concat ("Checksum mismatch in font ", curfnt->name);
371 error (msg);
372 free (msg);
373 }
374 k = pkquad(); /* assume that hppp is correct in the PK file */
375 k = pkquad(); /* assume that vppp is correct in the PK file */
376 /*
377 * Now we get down to the serious business of reading character definitions.
378 */
379 while ((cmd=pkbyte())!=245) {
380 if (cmd < 240) {
381 switch (cmd & 7) {
382 case 0: case 1: case 2: case 3:
383 length = (cmd & 7) * 256 + pkbyte() - 3;
384 cc = pkbyte();
385 cd = curfnt->chardesc+cc;
386 if (nosmallchars || curfnt->dpi != curfnt->loadeddpi)
387 cd->flags |= BIGCHAR;
388 cd->TFMwidth = scalewidth(pktrio(), scaledsize);
389 cd->pixelwidth = pkbyte();
390 break;
391 case 4: case 5: case 6:
392 length = (cmd & 3) * 65536L + pkbyte() * 256L;
393 length = length + pkbyte() - 4L;
394 cc = pkbyte();
395 cd = curfnt->chardesc+cc;
396 cd->TFMwidth = scalewidth(pktrio(), scaledsize);
397 cd->flags |= BIGCHAR;
398 i = pkbyte();
399 cd->pixelwidth = i * 256 + pkbyte();
400 break;
401 case 7:
402 length = pkquad() - 11;
403 cc = pkquad();
404 if (cc<0 || cc>255) badpk("character code out of range");
405 cd = curfnt->chardesc + cc;
406 cd->flags |= BIGCHAR;
407 cd->TFMwidth = scalewidth(pkquad(), scaledsize);
408 cd->pixelwidth = (pkquad() + 32768) >> 16;
409 k = pkquad();
410 }
411 if (cd->pixelwidth == 0 && cd->TFMwidth != 0) {
412 if (cd->TFMwidth > 0)
413 k = (integer)(cd->TFMwidth * conv + 0.5);
414 else
415 k = -(integer)(-cd->TFMwidth * conv + 0.5);
416 if (k != 0) {
417 cd->pixelwidth = k;
418 munged++;
419 }
420 }
421 if (length <= 0)
422 badpk("packet length too small");
423 if (dopprescan && ((cd->flags & EXISTS) == 0)) {
424 for (length--; length>0; length--)
425 pkbyte();
426 } else {
427 if (cc > maxcc)
428 maxcc = cc;
429 if (bytesleft < length || (length > MINCHUNK && compressed)) {
430 #ifdef DEBUG
431 if (dd(D_MEM))
432 fprintf(stderr,
433 #ifdef SHORTINT
434 "Allocating new raster memory (%ld req, %ld left)\n",
435 length, bytesleft);
436 #else
437 "Allocating new raster memory (%d req, %d left)\n",
438 (int)length, (int)bytesleft);
439 #endif
440 #endif /* DEBUG */
441 if (length > MINCHUNK) {
442 tempr = (quarterword *)mymalloc((integer)length);
443 } else {
444 raster = (quarterword *)mymalloc((integer)RASTERCHUNK);
445 tempr = raster;
446 bytesleft = RASTERCHUNK - length;
447 raster += length;
448 }
449 } else {
450 tempr = raster;
451 bytesleft -= length;
452 raster += length;
453 }
454 cd->packptr = tempr;
455 *tempr++ = cmd;
456 for (length--; length>0; length--)
457 *tempr++ = pkbyte();
458 }
459 cd->flags2 |= EXISTS;
460 } else {
461 k = 0;
462 switch (cmd) {
463 case 243:
464 k = pkbyte();
465 if (k > 127)
466 k -= 256;
467 case 242:
468 k = k * 256 + pkbyte();
469 case 241:
470 k = k * 256 + pkbyte();
471 case 240:
472 k = k * 256 + pkbyte();
473 while (k-- > 0)
474 i = pkbyte();
475 break;
476 case 244:
477 k = pkquad();
478 break;
479 case 246:
480 break;
481 default:
482 badpk("! unexpected command");
483 }
484 }
485 }
486 #ifdef FONTLIB
487 if (flib)
488 flib = 0;
489 else
490 #endif
491 fclose(pkfile);
492 curfnt->loaded = 1;
493 curfnt->maxchars = maxcc + 1;
494 if (munged > 0) {
495 static int seen = 0;
496 sprintf(errbuf,
497 "Font %s at %d dpi has most likely been made improperly;",
498 curfnt->name, curfnt->dpi);
499 error(errbuf);
500 if (seen)
501 return;
502 seen = 1;
503 sprintf(errbuf,
504 "%d characters have 0 escapements but non-trivial TFM widths.", munged);
505 error(errbuf);
506 error(
507 "I'm stumbling along as best I can, but I recommend regenerating");
508 error(
509 "these fonts; the problem is probably that they are non-CM fonts");
510 error(
511 "(such as circle10 or line10) created with a MF with the CM base");
512 error("preloaded .");
513 }
514 }
515