1 /*
2  *   pklib.c
3  *
4  *   This file is part of the ttf2pk package.
5  *
6  *   Copyright 1997-1999, 2000 by
7  *     Frederic Loyer <loyer@ensta.fr>
8  *     Werner Lemberg <wl@gnu.org>
9  */
10 
11 /*
12  *   This code has been derived from the program gsftopk.
13  *   Here the original copyright.
14  */
15 
16 /*
17  * Copyright (c) 1994 Paul Vojta.  All rights reserved.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  */
40 
41 
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <stddef.h>         /* for size_t */
49 #include <string.h>
50 #include <errno.h>
51 #include <ctype.h>
52 
53 #include "newobj.h"
54 #include "pklib.h"
55 #include "errormsg.h"
56 #include "filesrch.h"
57 
58 #ifndef MAXPATHLEN
59 #define MAXPATHLEN 256
60 #endif
61 
62 #define PK_PRE  (char)247
63 #define PK_ID   89
64 #define PK_POST (char)245
65 #define PK_NOP  (char)246
66 
67 extern int dpi;
68 
69 FILE *pk_file;
70 
71 
72 /*
73  *   Information from the .tfm file.
74  */
75 
76 int tfm_lengths[12];
77 
78 #define lh tfm_lengths[1]
79 #define bc tfm_lengths[2]
80 #define ec tfm_lengths[3]
81 #define nw tfm_lengths[4]
82 
83 long checksum;
84 long design;
85 byte width_index[256];
86 long tfm_widths[256];
87 
88 /*
89  *   Information on the bitmap currently being worked on.
90  */
91 
92 byte   *bitmap;
93 int    width;
94 int    skip;
95 int    height;
96 int    hoff;
97 int    voff;
98 int    bytes_wide;
99 size_t bm_size;
100 byte   *bitmap_end;
101 int    pk_len;
102 
103 /*
104  *   Here's the path searching stuff.  First the typedefs and variables.
105  */
106 
107 static char searchpath[MAXPATHLEN + 1];
108 
109 #define HUNKSIZE (MAXPATHLEN + 2)
110 
111 struct spacenode                /* used for storage of directory names */
112 {
113   struct spacenode *next;
114   char             *sp_end;     /* end of data for this chunk */
115   char             sp[HUNKSIZE];
116 } firstnode;
117 
118 
119 
120 static FILE *
search_tfm(char ** name)121 search_tfm(char **name)
122 {
123   char *p;
124   FILE *f;
125 
126 
127   p = TeX_search_tfm(name);
128   if (p == NULL)
129     return NULL;
130   strcpy(searchpath, p);
131   f = fopen(searchpath, "rb");
132   return f;
133 }
134 
135 
136 static long
getlong(FILE * f)137 getlong(FILE *f)
138 {
139   unsigned long value;
140 
141 
142   value  = (unsigned long)getc(f) << 24;
143   value |= (unsigned long)getc(f) << 16;
144   value |= (unsigned long)getc(f) << 8;
145   value |= (unsigned long)getc(f);
146   return value;
147 }
148 
149 
150 char line[82];
151 
152 
153 static byte masks[] = {0, 1, 3, 7, 017, 037, 077, 0177, 0377};
154 
155 byte flag;
156 int pk_dyn_f;
157 int pk_dyn_g;
158 int base;          /* cost of this character if pk_dyn_f = 0 */
159 int deltas[13];    /* cost of increasing pk_dyn_f from i to i+1 */
160 
161 
162 /*
163  *   Add up statistics for putting out the given shift count.
164  */
165 
166 static void
tallyup(int n)167 tallyup(int n)
168 {
169   int m;
170 
171 
172   if (n > 208)
173   {
174     ++base;
175     n -= 192;
176     for (m = 0x100; m != 0 && m < n; m <<= 4)
177       base += 2;
178     if (m != 0 && (m = (m - n) / 15) < 13)
179       deltas[m] += 2;
180   }
181   else if (n > 13)
182     ++deltas[(208 - n) / 15];
183   else
184     --deltas[n - 1];
185 }
186 
187 
188 /*
189  *   Routines for storing the shift counts.
190  */
191 
192 static Boolean odd = False;
193 static byte part;
194 
195 
196 static void
pk_put_nyb(int n)197 pk_put_nyb(int n)
198 {
199   if (odd)
200   {
201     *bitmap_end++ = (part << 4) | n;
202     odd = False;
203   }
204   else
205   {
206     part = n;
207     odd = True;
208   }
209 }
210 
211 
212 static void
pk_put_long(int n)213 pk_put_long(int n)
214 {
215   if (n >= 16)
216   {
217     pk_put_nyb(0);
218     pk_put_long(n / 16);
219   }
220   pk_put_nyb(n % 16);
221 }
222 
223 
224 static void
pk_put_count(int n)225 pk_put_count(int n)
226 {
227   if (n > pk_dyn_f)
228   {
229     if (n > pk_dyn_g)
230       pk_put_long(n - pk_dyn_g + 15);
231     else
232     {
233       pk_put_nyb(pk_dyn_f + (n - pk_dyn_f + 15) / 16);
234       pk_put_nyb((n - pk_dyn_f - 1) % 16);
235     }
236   }
237   else
238     pk_put_nyb(n);
239 }
240 
241 
242 static void
trim_bitmap(void)243 trim_bitmap(void)
244 {
245   byte *p;
246   byte mask;
247 
248 
249   /* clear out garbage bits in bitmap */
250 
251   if (width % 8 != 0)
252   {
253     mask = ~masks[8 - width % 8];
254     for (p = bitmap + bytes_wide - 1; p < bitmap_end; p += bytes_wide)
255       *p &= mask;
256   }
257 
258   /* Find the bounding box of the bitmap. */
259 
260   /* trim top */
261 
262   skip = 0;
263   mask = 0;
264 
265   for (;;)
266   {
267     if (bitmap >= bitmap_end)   /* if bitmap is empty */
268     {
269       width = height = hoff = voff = 0;
270       return;
271     }
272 
273     p = bitmap + bytes_wide;
274     while (p > bitmap)
275       mask |= *--p;
276     if (mask)
277       break;
278     ++skip;
279     bitmap += bytes_wide;
280   }
281 
282   height -= skip;
283   voff -= skip;
284 
285 #ifdef  DEBUG
286   if (skip < 2 || skip > 3)
287     printf("Character has %d empty rows at top\n", skip);
288 #endif
289 
290   /* trim bottom */
291 
292   skip = 0;
293   mask = 0;
294 
295   for (;;)
296   {
297     p = bitmap_end - bytes_wide;
298     while (p < bitmap_end)
299       mask |= *p++;
300     if (mask)
301       break;
302     ++skip;
303     bitmap_end -= bytes_wide;
304   }
305 
306   height -= skip;
307 
308 #ifdef  DEBUG
309   if (skip < 2 || skip > 3)
310     printf("Character has %d empty rows at bottom\n", skip);
311 #endif
312 
313   /* trim right */
314 
315   skip = 0;
316   --width;
317 
318   for (;;)
319   {
320     mask = 0;
321     for (p = bitmap + width / 8; p < bitmap_end; p += bytes_wide)
322       mask |= *p;
323     if (mask & (0x80 >> (width % 8)))
324       break;
325 
326     --width;
327     ++skip;
328   }
329 
330   ++width;
331 
332 #ifdef  DEBUG
333   if (skip < 2 || skip > 3)
334     printf("Character has %d empty columns at right\n", skip);
335 #endif
336 
337   /* trim left */
338 
339   skip = 0;
340 
341   for (;;)
342   {
343     mask = 0;
344     for (p = bitmap + skip / 8; p < bitmap_end; p += bytes_wide)
345       mask |= *p;
346     if (mask & (0x80 >> (skip % 8)))
347       break;
348 
349     ++skip;
350   }
351 
352   width -= skip;
353   hoff -= skip;
354 
355 #ifdef  DEBUG
356   if (skip < 2 || skip > 3)
357     printf("Character has %d empty columns at left\n", skip);
358 #endif
359 
360   bitmap += skip / 8;
361   skip = skip % 8;
362 }
363 
364 
365 /*
366  *   Pack the bitmap using the rll method.  (Return false if it's better
367  *   to just pack the bits.)
368  */
369 
370 static Boolean
pk_rll_cvt(void)371 pk_rll_cvt(void)
372 {
373   static int   *counts   = NULL; /* area for saving bit counts */
374   static int   maxcounts = 0;    /* size of this area */
375   unsigned int ncounts;          /* max to allow this time */
376   int          *nextcount;       /* next count value */
377 
378   int  *counts_end;              /* pointer to end */
379   byte *rowptr;
380   byte *p;
381   byte mask;
382   byte *rowdup;                  /* last row checked for dup */
383   byte paint_switch;             /* 0 or 0xff */
384   int  bits_left;                /* bits left in row */
385   int  cost;
386   int  i;
387 
388 
389   /* Allocate space for bit counts. */
390 
391   ncounts = (width * height + 3) / 4;
392   if (ncounts > maxcounts)
393   {
394     if (counts != NULL)
395       free(counts);
396     counts = (int *)mymalloc((ncounts + 2) * sizeof (int));
397     maxcounts = ncounts;
398   }
399   counts_end = counts + ncounts;
400 
401   /* Form bit counts and collect statistics */
402 
403   base = 0;
404   memset(deltas, 0, sizeof (deltas));
405   rowdup = NULL;                    /* last row checked for duplicates */
406   p = rowptr = bitmap;
407   mask = 0x80 >> skip;
408   flag = 0;
409   paint_switch = 0;
410 
411   if (*p & mask)
412   {
413     flag = 8;
414     paint_switch = 0xff;
415   }
416 
417   bits_left = width;
418   nextcount = counts;
419 
420   while (rowptr < bitmap_end)       /* loop over shift counts */
421   {
422     int shift_count = bits_left;
423 
424 
425     for (;;)
426     {
427       if (bits_left == 0)
428       {
429         if ((p = rowptr += bytes_wide) >= bitmap_end)
430           break;
431         mask = 0x80 >> skip;
432         bits_left = width;
433         shift_count += width;
434       }
435       if (((*p ^ paint_switch) & mask) != 0)
436         break;
437       --bits_left;
438       mask >>= 1;
439       if (mask == 0)
440       {
441         ++p;
442         while (*p == paint_switch && bits_left >= 8)
443         {
444           ++p;
445           bits_left -= 8;
446         }
447         mask = 0x80;
448       }
449     }
450 
451     if (nextcount >= counts_end)
452       return False;
453     shift_count -= bits_left;
454     *nextcount++ = shift_count;
455     tallyup(shift_count);
456 
457     /* check for duplicate rows */
458     if (rowptr != rowdup && bits_left != width)
459     {
460       byte *p1 = rowptr;
461       byte *q  = rowptr + bytes_wide;
462       int repeat_count;
463 
464 
465       while (q < bitmap_end && *p1 == *q)
466       {
467         ++p1;
468         ++q;
469       }
470       repeat_count = (p1 - rowptr) / bytes_wide;
471       if (repeat_count > 0)
472       {
473         *nextcount++ = -repeat_count;
474         if (repeat_count == 1)
475           --base;
476         else
477         {
478           ++base;
479           tallyup(repeat_count);
480         }
481         rowptr += repeat_count * bytes_wide;
482       }
483       rowdup = rowptr;
484     }
485     paint_switch = ~paint_switch;
486   }
487 
488 #ifdef  DEBUG
489   /*
490    *      Dump the bitmap
491    */
492 
493   for (p = bitmap; p < bitmap_end; p += bytes_wide)
494   {
495     byte *p1 = p;
496     int j;
497 
498 
499     mask = 0x80 >> skip;
500     for (j = 0; j < width; ++j)
501     {
502       putchar(*p1 & mask ? '@' : '.');
503       if ((mask >>= 1) == 0)
504       {
505         mask = 0x80;
506         ++p1;
507       }
508     }
509     putchar('\n');
510   }
511   putchar('\n');
512 #endif
513 
514   /* Determine the best pk_dyn_f */
515 
516   pk_dyn_f = 0;
517   cost = base += 2 * (nextcount - counts);
518 
519   for (i = 1; i < 14; ++i)
520   {
521     base += deltas[i - 1];
522     if (base < cost)
523     {
524       pk_dyn_f = i;
525       cost = base;
526     }
527   }
528 
529   /* last chance to bail out */
530 
531   if (cost * 4 > width * height)
532     return False;
533 
534   /* Pack the bit counts */
535 
536   pk_dyn_g = 208 - 15 * pk_dyn_f;
537   flag |= pk_dyn_f << 4;
538   bitmap_end = bitmap;
539   *nextcount = 0;
540   nextcount = counts;
541 
542   while (*nextcount != 0)
543   {
544     if (*nextcount > 0)
545       pk_put_count(*nextcount);
546     else
547       if (*nextcount == -1)
548         pk_put_nyb(15);
549       else
550       {
551         pk_put_nyb(14);
552         pk_put_count(-*nextcount);
553       }
554       ++nextcount;
555   }
556 
557   if (odd)
558   {
559     pk_put_nyb(0);
560     ++cost;
561   }
562 
563   if (cost != 2 * (bitmap_end - bitmap))
564     printf("Cost miscalculation:  expected %d, got %ld\n",
565              cost, (long)(2 * (bitmap_end - bitmap)));
566   pk_len = bitmap_end - bitmap;
567   return True;
568 }
569 
570 
571 static void
pk_bm_cvt(void)572 pk_bm_cvt(void)
573 {
574   byte *rowptr;
575   byte *p;
576   int  blib1;          /* bits left in byte */
577   int  bits_left;      /* bits left in row */
578   byte *q;
579   int  blib2;
580   byte nextbyte;
581 
582 
583   flag = 14 << 4;
584   q = bitmap;
585   blib2 = 8;
586   nextbyte = 0;
587 
588   for (rowptr = bitmap; rowptr < bitmap_end; rowptr += bytes_wide)
589   {
590     p = rowptr;
591     blib1 = 8 - skip;
592     bits_left = width;
593 
594     if (blib2 != 8)
595     {
596       int n;
597 
598 
599       if (blib1 < blib2)
600       {
601         nextbyte |= *p << (blib2 - blib1);
602         n = blib1;
603       }
604       else
605       {
606         nextbyte |= *p >> (blib1 - blib2);
607         n = blib2;
608       }
609       blib2 -= n;
610       if ((bits_left -= n) < 0)
611       {
612         blib2 -= bits_left;
613         continue;
614       }
615       if ((blib1 -= n) == 0)
616       {
617         blib1 = 8;
618         ++p;
619         if (blib2 > 0)
620         {
621           nextbyte |= *p >> (8 - blib2);
622           blib1 -= blib2;
623           bits_left -= blib2;
624           if (bits_left < 0)
625           {
626             blib2 = -bits_left;
627             continue;
628           }
629         }
630       }
631       *q++ = nextbyte;
632     }
633 
634     /* fill up whole (destination) bytes */
635 
636     while (bits_left >= 8)
637     {
638       nextbyte = *p++ << (8 - blib1);
639       *q++ = nextbyte | (*p >> blib1);
640       bits_left -= 8;
641     }
642 
643     /* now do the remainder */
644 
645     nextbyte = *p << (8 - blib1);
646     if (bits_left > blib1)
647       nextbyte |= p[1] >> blib1;
648     blib2 = 8 - bits_left;
649   }
650 
651   if (blib2 != 8)
652     *q++ = nextbyte;
653 
654   pk_len = q - bitmap;
655 }
656 
657 
658 static void
putshort(int w)659 putshort(int w)
660 {
661   putc(w >> 8, pk_file);
662   putc(w, pk_file);
663 }
664 
665 
666 static void
putmed(long w)667 putmed(long w)
668 {
669   putc(w >> 16, pk_file);
670   putc(w >> 8, pk_file);
671   putc(w, pk_file);
672 }
673 
674 
675 static void
putlong(long w)676 putlong(long w)
677 {
678   putc(w >> 24, pk_file);
679   putc(w >> 16, pk_file);
680   putc(w >> 8, pk_file);
681   putc(w, pk_file);
682 }
683 
684 
685 static char
xgetc(FILE * f)686 xgetc(FILE *f)
687 {
688   int c;
689 
690 
691   c = getc(f);
692   if (c == EOF)
693     oops("Premature end of file.");
694   return (byte)c;
695 }
696 
697 
698 /*
699  *   Open and read the tfm file.
700  */
701 
702 void
TFMopen(char ** filename)703 TFMopen(char **filename)
704 {
705   FILE *tfm_file;
706   int  i;
707   int  cc;
708 
709 
710   tfm_file = search_tfm(filename);
711   if (tfm_file == NULL)
712     oops("Cannot find tfm file.");
713 
714   for (i = 0; i < 12; i++)
715   {
716     int j;
717 
718 
719     j = (int)((byte)getc(tfm_file)) << 8;
720     tfm_lengths[i] = j | (int)((byte)xgetc(tfm_file));
721   }
722 
723   checksum = getlong(tfm_file);
724   design = getlong(tfm_file);
725   fseek(tfm_file, 4 * (lh + 6), 0);
726 
727   for (cc = bc; cc <= ec; ++cc)
728   {
729     width_index[cc] = (byte)xgetc(tfm_file);
730 
731     (void)xgetc(tfm_file);
732     (void)xgetc(tfm_file);
733     (void)xgetc(tfm_file);
734   }
735 
736   for (i = 0; i < nw; ++i)
737     tfm_widths[i] = getlong(tfm_file);
738 
739   fclose(tfm_file);
740 }
741 
742 
743 /*
744  *   Create pk file and write preamble.
745  */
746 
747 void
PKopen(char * filename,char * ident,int resolution)748 PKopen(char *filename,
749        char *ident,
750        int resolution)
751 {
752   int ppp;
753   int i;
754 
755 
756   dpi = resolution;
757 
758   if ((pk_file = fopen(filename, "wb")) == NULL)
759   {
760     perror(filename);
761     exit(1);
762   }
763 
764   putc(PK_PRE, pk_file);
765   putc(PK_ID, pk_file);
766 
767   i = strlen(ident);
768 
769   putc(i, pk_file);
770   fwrite(ident, 1, i, pk_file);
771   putlong(design);
772   putlong(checksum);
773   ppp = dpi / 72.27 * 65536.0 + 0.5;
774   putlong(ppp);                         /* hppp */
775   putlong(ppp);                         /* vppp */
776 }
777 
778 
779 void
PKputglyph(int cc,int llx,int lly,int urx,int ury,int w,int h,byte * b)780 PKputglyph(int cc,
781            int llx, int lly, int urx, int ury,
782            int w, int h,
783            byte *b)
784 {
785   float char_width;
786 
787   long dm;
788   long tfm_wid;
789 
790 
791   bitmap = b;
792   width = w;
793   height = h;
794 
795   hoff = -llx;
796   voff = ury - 2; /* Don't ask me why `-2' */
797                   /*   Fred                */
798 
799   if (width != urx - llx || height != ury - lly)
800     oops("Dimensions do not match:  (%d - %d) (%d - %d) <=> %d %d",
801            llx, lly, urx, ury, width, height);
802 
803   bytes_wide = (width + 7) / 8;
804   bm_size = bytes_wide * height;
805   bitmap_end = bitmap + bm_size;
806 
807   trim_bitmap();
808 
809   if (height == 0 || !pk_rll_cvt())
810     pk_bm_cvt();
811 
812   if (!width_index[cc])
813     return;
814 
815   tfm_wid = tfm_widths[width_index[cc]];
816   char_width = tfm_wid / 1048576.0 * design / 1048576.0 * dpi / 72.27;
817   dm = (long)(char_width + 0.5) - (char_width < -0.5);
818 
819   if (pk_len + 8 < 4 * 256 && tfm_wid < (1<<24) &&
820       dm >= 0 && dm < 256 && width < 256 && height < 256 &&
821       hoff >= -128 && hoff < 128 && voff >= -128 && voff < 128)
822   {
823     putc(flag | ((pk_len + 8) >> 8), pk_file);
824     putc(pk_len + 8, pk_file);
825     putc(cc, pk_file);
826     putmed(tfm_wid);
827     putc(dm, pk_file);
828     putc(width, pk_file);
829     putc(height, pk_file);
830     putc(hoff, pk_file);
831     putc(voff, pk_file);
832   }
833   else if (pk_len + 13 < 3 * 65536L && tfm_wid < (1<<24) &&
834            dm >= 0 && dm < 65536L && width < 65536L && height < 65536L &&
835            hoff >= -65536L && hoff < 65536L &&
836            voff >= -65536L && voff < 65536L)
837   {
838     putc(flag | 4 | ((pk_len + 13) >> 16), pk_file);
839     putshort(pk_len + 13);
840     putc(cc, pk_file);
841     putmed(tfm_wid);
842     putshort(dm);
843     putshort(width);
844     putshort(height);
845     putshort(hoff);
846     putshort(voff);
847   }
848   else
849   {
850     putc(flag | 7, pk_file);
851     putlong(pk_len + 28);
852     putlong(cc);
853     putlong(tfm_wid);
854     putlong((long)(char_width * 65536.0 + 0.5) - (char_width < -0.5));
855     putlong(0);
856     putlong(width);
857     putlong(height);
858     putlong(hoff);
859     putlong(voff);
860   }
861   fwrite(bitmap, 1, pk_len, pk_file);
862 }
863 
864 
865 void
PKclose(void)866 PKclose(void)
867 {
868   putc(PK_POST, pk_file);
869   while (ftell(pk_file) % 4 != 0)
870     putc(PK_NOP, pk_file);
871 
872   fclose(pk_file);
873 }
874 
875 
876 /* end */
877