1 /*
2  * Copyright 1996, 1997, 1998, 1999 Computing Research Labs,
3  * New Mexico State University
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
20  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #ifndef lint
24 #ifdef __GNUC__
25 static char rcsid[] __attribute__ ((unused)) = "$Id: remap.c,v 1.9 1999/06/16 16:13:11 mleisher Exp $";
26 #else
27 static char rcsid[] = "$Id: remap.c,v 1.9 1999/06/16 16:13:11 mleisher Exp $";
28 #endif
29 #endif
30 
31 #include <stdio.h>
32 #include <string.h>
33 
34 #ifdef WIN32
35 #include <windows.h>
36 #else
37 #include <stdlib.h>
38 #include <unistd.h>
39 #endif
40 
41 /*
42  * Structure for managing simple lists in place.
43  */
44 typedef struct {
45     unsigned char *bfield;
46     unsigned long bsize;
47     unsigned long bused;
48     unsigned char **field;
49     unsigned long size;
50     unsigned long used;
51 } list_t;
52 
53 /*
54  * Callback type used with the high speed text file reader function.
55  */
56 typedef int (*scanlines_callback_t)(
57 #ifdef __STDC__
58     unsigned char *line,
59     unsigned long linelen,
60     unsigned long lineno,
61     void *client_data
62 #endif
63 );
64 
65 /*
66  * Various utility routines.
67  */
68 
69 #define setsbit(m, cc) (m[(cc) >> 3] |= (1 << ((cc) & 7)))
70 #define sbitset(m, cc) (m[(cc) >> 3] & (1 << ((cc) & 7)))
71 
72 /*
73  * An empty string for empty fields.
74  */
75 static unsigned char empty[1] = { 0 };
76 
77 /*
78  * Assume the line is NULL terminated and that the `list' parameter was
79  * initialized the first time it was used.
80  */
81 static void
82 #ifdef __STDC__
splitline(unsigned char * separators,unsigned char * line,unsigned long linelen,list_t * list)83 splitline(unsigned char *separators, unsigned char *line,
84           unsigned long linelen, list_t *list)
85 #else
86 splitline(separators, line, linelen, list)
87 unsigned char *separators, *line;
88 unsigned long linelen;
89 list_t *list;
90 #endif
91 {
92     int mult, final_empty;
93     unsigned char *sp, *ep, *end;
94     unsigned char seps[32];
95 
96     /*
97      * Initialize the list.
98      */
99     list->used = list->bused = 0;
100 
101     /*
102      * If the line is empty, then simply return.
103      */
104     if (linelen == 0 || line[0] == 0)
105       return;
106 
107     /*
108      * If the `separators' parameter is NULL or empty, split the list into
109      * individual bytes.
110      */
111     if (separators == 0 || *separators == 0) {
112         if (linelen > list->bsize) {
113             if (list->bsize)
114               list->bfield = (unsigned char *) malloc(linelen);
115             else
116               list->bfield = (unsigned char *) realloc(list->bfield, linelen);
117             list->bsize = linelen;
118         }
119         list->bused = linelen;
120         (void) memcpy(list->bfield, line, linelen);
121         return;
122     }
123 
124     /*
125      * Prepare the separator bitmap.
126      */
127     (void) memset((char *) seps, 0, 32);
128 
129     /*
130      * If the very last character of the separator string is a plus, then set
131      * the `mult' flag to indicate that multiple separators should be
132      * collapsed into one.
133      */
134     for (mult = 0, sp = separators; sp && *sp; sp++) {
135         if (*sp == '+' && *(sp + 1) == 0)
136           mult = 1;
137         else
138           setsbit(seps, *sp);
139     }
140 
141     /*
142      * Break the line up into fields.
143      */
144     for (final_empty = 0, sp = ep = line, end = sp + linelen;
145          sp < end && *sp;) {
146         /*
147          * Collect everything that is not a separator.
148          */
149         for (; ep < end && *ep && !sbitset(seps, *ep); ep++) ;
150 
151         /*
152          * Resize the list if necessary.
153          */
154         if (list->used == list->size) {
155             if (list->size == 0)
156               list->field = (unsigned char **)
157                   malloc(sizeof(unsigned char *) << 3);
158             else
159               list->field = (unsigned char **)
160                   realloc((char *) list->field,
161                           sizeof(unsigned char *) * (list->size + 8));
162 
163             list->size += 8;
164         }
165 
166         /*
167          * Assign the field appropriately.
168          */
169         list->field[list->used++] = (ep > sp) ? sp : empty;
170 
171         sp = ep;
172         if (mult) {
173             /*
174              * If multiple separators should be collapsed, do it now by
175              * setting all the separator characters to 0.
176              */
177             for (; ep < end && *ep && sbitset(seps, *ep); ep++)
178               *ep = 0;
179         } else
180           /*
181            * Don't collapse multiple separators by making them 0, so just
182            * make the one encountered 0.
183            */
184           *ep++ = 0;
185         final_empty = (ep > sp && *ep == 0);
186         sp = ep;
187     }
188 
189     /*
190      * Finally, NULL terminate the list.
191      */
192     if (list->used + final_empty + 1 >= list->size) {
193         if (list->used == list->size) {
194             if (list->size == 0)
195               list->field = (unsigned char **)
196                   malloc(sizeof(unsigned char *) << 3);
197             else
198               list->field = (unsigned char **)
199                   realloc((unsigned char *) list->field,
200                           sizeof(char *) * (list->size + 8));
201             list->size += 8;
202         }
203     }
204     if (final_empty)
205       list->field[list->used++] = empty;
206 
207     if (list->used == list->size) {
208         if (list->size == 0)
209           list->field = (unsigned char **)
210               malloc(sizeof(unsigned char *) << 3);
211         else
212           list->field = (unsigned char **)
213               realloc((char *) list->field,
214                       sizeof(unsigned char *) * (list->size + 8));
215         list->size += 8;
216     }
217     list->field[list->used] = 0;
218 }
219 
220 static int
221 #ifdef __STDC__
scanlines(int fd,scanlines_callback_t callback,void * client_data,unsigned long * lineno)222 scanlines(int fd, scanlines_callback_t callback, void *client_data,
223           unsigned long *lineno)
224 #else
225 scanlines(fd, callback, client_data, lineno)
226 int fd;
227 scanlines_callback_t callback;
228 void *client_data;
229 unsigned long *lineno;
230 #endif
231 {
232     unsigned long lno;
233     int n, res, done, refill, bytes, hold;
234     char *ls, *le, *pp, *pe, *hp;
235     char buf[65536];
236 
237     if (callback == 0)
238       return -1;
239 
240     lno = 1;
241     (void) memset(buf, 0, 65536);
242     res = done = 0;
243     pp = ls = le = buf;
244     bytes = 65536;
245     while (!done && (n = read(fd, pp, bytes)) > 0) {
246         /*
247          * Determine the new end of the buffer pages.
248          */
249         pe = pp + n;
250 
251         for (refill = 0; done == 0 && refill == 0; ) {
252             while (le < pe && *le != '\n' && *le != '\r')
253               le++;
254 
255             if (le == pe) {
256                 /*
257                  * Hit the end of the last page in the buffer.
258                  * Need to find out how many pages to shift
259                  * and how many pages need to be read in.
260                  * Adjust the line start and end pointers down
261                  * to point to the right places in the pages.
262                  */
263                 pp = buf + (((ls - buf) >> 13) << 13);
264                 n = pp - buf;
265                 ls -= n;
266                 le -= n;
267                 n = pe - pp;
268                 (void) memcpy(buf, pp, n);
269                 pp = buf + n;
270                 bytes = 65536 - n;
271                 refill = 1;
272             } else {
273                 /*
274                  * Temporarily NULL terminate the line.
275                  */
276                 hp = le;
277                 hold = *le;
278                 *le = 0;
279 
280                 if (callback && *ls != '#' && *ls != 0x1a && le > ls &&
281                     (res = (*callback)((unsigned char *) ls, le - ls, lno,
282                                        client_data)) != 0)
283                   done = 1;
284                 else {
285                     ls = ++le;
286                     /*
287                      * Handle the case of DOS CRLF sequences.
288                      */
289                     if (le < pe && hold == '\n' && *le =='\r')
290                       ls = ++le;
291                 }
292 
293                 /*
294                  * Increment the line number.
295                  */
296                 lno++;
297 
298                 /*
299                  * Restore the character at the end of the line.
300                  */
301                 *hp = hold;
302             }
303         }
304     }
305 
306     /*
307      * Return with the last line number processed.
308      */
309     *lineno = lno;
310 
311     return res;
312 }
313 
314 static unsigned char a2i[128] = {
315     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
320     0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
321     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323     0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
324     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
326 };
327 
328 static unsigned char odigits[32] = {
329     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
330     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 };
334 
335 static unsigned char ddigits[32] = {
336     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
337     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 };
341 
342 static unsigned char hdigits[32] = {
343     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
344     0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
345     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 };
348 
349 #define isdigok(m, d) (m[(d) >> 3] & (1 << ((d) & 7)))
350 
351 static unsigned short
352 #ifdef __STDC__
my_atous(unsigned char * s,unsigned char ** end,int base)353 my_atous(unsigned char *s, unsigned char **end, int base)
354 #else
355 my_atous(s, end, base)
356 unsigned char *s, **end;
357 int base;
358 #endif
359 {
360     unsigned short v;
361     unsigned char *dmap;
362 
363     if (s == 0 || *s == 0)
364       return 0;
365 
366     /*
367      * Make sure the radix is something recognizable.  Default to 10.
368      */
369     switch (base) {
370       case 8: dmap = odigits; break;
371       case 16: dmap = hdigits; break;
372       default: base = 10; dmap = ddigits; break;
373     }
374 
375     /*
376      * Check for the special hex prefix.
377      */
378     if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
379         base = 16;
380         dmap = hdigits;
381         s += 2;
382     }
383 
384     for (v = 0; isdigok(dmap, *s); s++)
385       v = (v * base) + a2i[(int) *s];
386 
387     if (end != 0)
388       *end = s;
389 
390     return v;
391 }
392 
393 /********************************************************************
394  *
395  * Routines to load, unload, and use mapping tables to remap BDF fonts
396  * generated using ttf2bdf.
397  *
398  ********************************************************************/
399 
400 /*
401  * Strings used to store the registry and encoding values specified
402  * in the mapping table.
403  */
404 static char *registry;
405 static char *encoding;
406 
407 /*
408  * Trie node structure.
409  */
410 typedef struct {
411     unsigned short key;	/* Key value.					*/
412     unsigned short val;	/* Data for the key.				*/
413     unsigned long sibs;	/* Offset of siblings from trie beginning.	*/
414     unsigned long kids; /* Offset of children from trie beginning.	*/
415 } node_t;
416 
417 /*
418  * The trie used for remapping codes.
419  */
420 static node_t *nodes;
421 static unsigned long nodes_size = 0;
422 static unsigned long nodes_used = 0;
423 
424 /*
425  * Gets the next available node in the trie.
426  */
427 static unsigned long
428 #ifdef __STDC__
getnode(unsigned short key)429 getnode(unsigned short key)
430 #else
431 getnode(key)
432 unsigned short key;
433 #endif
434 {
435     unsigned long loc;
436     node_t *np;
437 
438     if (nodes_used == nodes_size) {
439         if (nodes_size == 0)
440           nodes = (node_t *) malloc(sizeof(node_t) << 7);
441         else
442           nodes = (node_t *) realloc((char *) nodes, sizeof(node_t) *
443                                      (nodes_size + 128));
444         np = nodes + nodes_size;
445         nodes_size += 128;
446         (void) memset((char *) np, 0, sizeof(node_t) << 7);
447     }
448 
449     loc = nodes_used++;
450     np = nodes + loc;
451     np->kids = np->sibs = 0;
452     np->key = key;
453     return loc;
454 }
455 
456 /*
457  * Inserts a node in the trie.
458  */
459 static void
460 #ifdef __STDC__
trie_insert(unsigned short key,unsigned short val)461 trie_insert(unsigned short key, unsigned short val)
462 #else
463 trie_insert(key, val)
464 unsigned short key, val;
465 #endif
466 {
467     unsigned long i, n, t, l;
468     unsigned short codes[2];
469 
470     /*
471      * Convert the incoming key into two codes to make the trie lookup more
472      * efficient.
473      */
474     codes[0] = (key >> 8) & 0xff;
475     codes[1] = key & 0xff;
476 
477     for (i = t = 0; i < 2; i++) {
478         if (nodes[t].kids == 0) {
479             n = getnode(codes[i]);
480             nodes[t].kids = t = n;
481         } else if (nodes[nodes[t].kids].key == codes[i])
482           t = nodes[t].kids;
483         else if (nodes[nodes[t].kids].key > codes[i]) {
484             n = getnode(codes[i]);
485             nodes[n].sibs = nodes[t].kids;
486             nodes[t].kids = t = n;
487         } else {
488             t = nodes[t].kids;
489             for (l = t; nodes[t].sibs && nodes[t].key < codes[i]; ) {
490                 l = t;
491                 t = nodes[t].sibs;
492             }
493             if (nodes[t].key < codes[i]) {
494                 n = getnode(codes[i]);
495                 nodes[t].sibs = t = n;
496             } else if (nodes[t].key > codes[i]) {
497                 n = getnode(codes[i]);
498                 nodes[n].sibs = t;
499                 nodes[l].sibs = t = n;
500             }
501         }
502     }
503 
504     /*
505      * Set the value in the leaf node.
506      */
507     nodes[t].val = val;
508 }
509 
510 /*
511  * List used by the routine that parses the map lines.
512  */
513 static list_t list;
514 
515 /*
516  * Routine to parse each line of the mapping file.
517  */
518 static int
519 #ifdef __STDC__
add_mapping(unsigned char * line,unsigned long linelen,unsigned long lineno,void * client_data)520 add_mapping(unsigned char *line, unsigned long linelen, unsigned long lineno,
521             void *client_data)
522 #else
523 add_mapping(line, linelen, lineno, client_data)
524 unsigned char *line;
525 unsigned long linelen, lineno;
526 void *client_data;
527 #endif
528 {
529     unsigned short key, val;
530 
531     /*
532      * Split the line into parts separted by one or more spaces or tabs.
533      */
534     splitline((unsigned char *) " \t+", line, linelen, &list);
535 
536     /*
537      * Check to see if the line starts with one of the keywords.
538      */
539     if (memcmp((char *) list.field[0], "REGISTRY", 8) == 0) {
540         /*
541          * Collect the XLFD CHARSET_REGISTRY value.
542          */
543         if (registry != 0)
544           free((char *) registry);
545         if ((val = strlen((char *) list.field[1])) == 0)
546           registry = 0;
547         else {
548             registry = (char *) malloc(val + 1);
549             (void) memcpy(registry, (char *) list.field[1], val + 1);
550         }
551         return 0;
552     }
553 
554     if (memcmp((char *) list.field[0], "ENCODING", 8) == 0) {
555         /*
556          * Collect the XLFD CHARSET_ENCODING value.
557          */
558         if (encoding != 0)
559           free((char *) encoding);
560         if ((val = strlen((char *) list.field[1])) == 0)
561           encoding = 0;
562         else {
563             encoding = (char *) malloc(val + 1);
564             (void) memcpy(encoding, (char *) list.field[1], val + 1);
565         }
566         return 0;
567     }
568 
569     /*
570      * Get the second field value as the key (the Unicode value).  Always
571      * assume the values are in hex.
572      */
573     key = my_atous(list.field[1], 0, 16);
574     val = my_atous(list.field[0], 0, 16);
575 
576     trie_insert(key, val);
577 
578     return 0;
579 }
580 
581 /********************************************************************
582  *
583  * API for mapping table support.
584  *
585  ********************************************************************/
586 
587 int
588 #ifdef __STDC__
ttf2bdf_load_map(FILE * in)589 ttf2bdf_load_map(FILE *in)
590 #else
591 ttf2bdf_load_map(in)
592 FILE *in;
593 #endif
594 {
595     unsigned long lineno;
596 
597     /*
598      * Allocate some nodes initially.
599      */
600     if (nodes_size == 0) {
601         nodes = (node_t *) malloc(sizeof(node_t) << 7);
602         nodes_size = 128;
603     }
604 
605     /*
606      * Reset the trie in case more than one gets loaded for some reason.
607      */
608     if (nodes_size > 0)
609       (void) memset((char *) nodes, 0, sizeof(node_t) * nodes_size);
610     nodes_used = 1;
611 
612     return scanlines(fileno(in), add_mapping, 0, &lineno);
613 }
614 
615 /*
616  * Routine that deallocates the mapping trie.
617  */
618 void
619 #ifdef __STDC__
ttf2bdf_free_map(void)620 ttf2bdf_free_map(void)
621 #else
622 ttf2bdf_free_map()
623 #endif
624 {
625     if (registry != 0)
626       free((char *) registry);
627     if (encoding != 0)
628       free((char *) encoding);
629     registry = encoding = 0;
630 
631     if (list.size > 0)
632       free((char *) list.field);
633     list.size = list.used = 0;
634 
635     if (nodes_size > 0)
636       free((char *) nodes);
637     nodes_size = nodes_used = 0;
638 }
639 
640 /*
641  * The routine that actually remaps the code by looking it up in the trie.
642  */
643 int
644 #ifdef __STDC__
ttf2bdf_remap(unsigned short * code)645 ttf2bdf_remap(unsigned short *code)
646 #else
647 ttf2bdf_remap(code)
648 unsigned short *code;
649 #endif
650 {
651     unsigned long i, n, t;
652     unsigned short c, codes[2];
653 
654     /*
655      * If no mapping table was loaded, then simply return the code.
656      */
657     if (nodes_used == 0)
658       return 1;
659 
660     c = *code;
661     codes[0] = (c >> 8) & 0xff;
662     codes[1] = c & 0xff;
663 
664     for (i = n = 0; i < 2; i++) {
665         t = nodes[n].kids;
666         if (t == 0)
667           return 0;
668         for (; nodes[t].sibs && nodes[t].key != codes[i]; t = nodes[t].sibs);
669         if (nodes[t].key != codes[i])
670           return 0;
671         n = t;
672     }
673 
674     *code = nodes[n].val;
675     return 1;
676 }
677 
678 void
679 #ifdef __STDC__
ttf2bdf_remap_charset(char ** registry_name,char ** encoding_name)680 ttf2bdf_remap_charset(char **registry_name, char **encoding_name)
681 #else
682 ttf2bdf_remap_charset(registry_name, encoding_name)
683 char **registry_name, **encoding_name;
684 #endif
685 {
686     if (registry_name != 0)
687       *registry_name = registry;
688     if (encoding_name != 0)
689       *encoding_name = encoding;
690 }
691