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