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