encparse.c revision e1c0d025
1/* 2Copyright (c) 1998-2001 by Juliusz Chroboczek 3 4Permission is hereby granted, free of charge, to any person obtaining a copy 5of this software and associated documentation files (the "Software"), to deal 6in the Software without restriction, including without limitation the rights 7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8copies of the Software, and to permit persons to whom the Software is 9furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20THE SOFTWARE. 21*/ 22 23/* Parser for encoding files */ 24 25/* This code assumes that we are using ASCII. We don't use the ctype 26 functions, as they depend on the current locale. On the other 27 hand, we do use strcasecmp, but only on strings that we've checked 28 to be pure ASCII. Bloody ``Code Set Independence''. */ 29 30#include <string.h> 31#include <strings.h> 32#include <stdio.h> 33 34#include <stdlib.h> 35 36#include "zlib.h" 37typedef gzFile FontFilePtr; 38 39#define FontFileGetc(f) gzgetc(f) 40#define FontFileOpen(filename) gzopen(filename, "rb") 41#define FontFileClose(f) gzclose(f) 42 43#define MAXFONTFILENAMELEN 1024 44#define MAXFONTNAMELEN 1024 45 46#include <X11/fonts/fontenc.h> 47#include "fontencI.h" 48 49#define MAXALIASES 20 50 51#define EOF_TOKEN -1 52#define ERROR_TOKEN -2 53#define EOL_TOKEN 0 54#define NUMBER_TOKEN 1 55#define KEYWORD_TOKEN 2 56 57#define EOF_LINE -1 58#define ERROR_LINE -2 59#define STARTENCODING_LINE 1 60#define STARTMAPPING_LINE 2 61#define ENDMAPPING_LINE 3 62#define CODE_LINE 4 63#define CODE_RANGE_LINE 5 64#define CODE_UNDEFINE_LINE 6 65#define NAME_LINE 7 66#define SIZE_LINE 8 67#define ALIAS_LINE 9 68#define FIRSTINDEX_LINE 10 69 70/* Return from lexer */ 71#define MAXKEYWORDLEN 100 72 73static long number_value; 74static char keyword_value[MAXKEYWORDLEN + 1]; 75 76static long value1, value2, value3; 77 78/* Lexer code */ 79 80/* Skip to the beginning of new line */ 81static void 82skipEndOfLine(FontFilePtr f, int c) 83{ 84 if (c == 0) 85 c = FontFileGetc(f); 86 87 for (;;) 88 if (c <= 0 || c == '\n') 89 return; 90 else 91 c = FontFileGetc(f); 92} 93 94/* Get a number; we're at the first digit. */ 95static unsigned 96getnum(FontFilePtr f, int c, int *cp) 97{ 98 unsigned n = 0; 99 int base = 10; 100 101 /* look for `0' or `0x' prefix */ 102 if (c == '0') { 103 c = FontFileGetc(f); 104 base = 8; 105 if (c == 'x' || c == 'X') { 106 base = 16; 107 c = FontFileGetc(f); 108 } 109 } 110 111 /* accumulate digits */ 112 for (;;) { 113 if ('0' <= c && c <= '9') { 114 n *= base; 115 n += c - '0'; 116 } 117 else if ('a' <= c && c <= 'f') { 118 n *= base; 119 n += c - 'a' + 10; 120 } 121 else if ('A' <= c && c <= 'F') { 122 n *= base; 123 n += c - 'A' + 10; 124 } 125 else 126 break; 127 c = FontFileGetc(f); 128 } 129 130 *cp = c; 131 return n; 132} 133 134/* Skip to beginning of new line; return 1 if only whitespace was found. */ 135static int 136endOfLine(FontFilePtr f, int c) 137{ 138 if (c == 0) 139 c = FontFileGetc(f); 140 141 for (;;) { 142 if (c <= 0 || c == '\n') 143 return 1; 144 else if (c == '#') { 145 skipEndOfLine(f, c); 146 return 1; 147 } 148 else if (c == ' ' || c == '\t') { 149 skipEndOfLine(f, c); 150 return 0; 151 } 152 c = FontFileGetc(f); 153 } 154} 155 156/* Get a token; we're at first char */ 157static int 158gettoken(FontFilePtr f, int c, int *cp) 159{ 160 char *p; 161 162 if (c <= 0) 163 c = FontFileGetc(f); 164 165 if (c <= 0) { 166 return EOF_TOKEN; 167 } 168 169 while (c == ' ' || c == '\t') 170 c = FontFileGetc(f); 171 172 if (c == '\n') { 173 return EOL_TOKEN; 174 } 175 else if (c == '#') { 176 skipEndOfLine(f, c); 177 return EOL_TOKEN; 178 } 179 else if (c >= '0' && c <= '9') { 180 number_value = getnum(f, c, cp); 181 return NUMBER_TOKEN; 182 } 183 else if ((c >= 'A' && c <= 'Z') || 184 (c >= 'a' && c <= 'z') || 185 c == '/' || c == '_' || c == '-' || c == '.') { 186 p = keyword_value; 187 *p++ = c; 188 while (p - keyword_value < MAXKEYWORDLEN) { 189 c = FontFileGetc(f); 190 if (c <= ' ' || c > '~' || c == '#') 191 break; 192 *p++ = c; 193 } 194 *cp = c; 195 *p = '\0'; 196 return KEYWORD_TOKEN; 197 } 198 else { 199 *cp = c; 200 return ERROR_TOKEN; 201 } 202} 203 204/* Parse a line. 205 * Always skips to the beginning of a new line, even if an error occurs */ 206static int 207getnextline(FontFilePtr f) 208{ 209 int c, token; 210 211 c = FontFileGetc(f); 212 if (c <= 0) 213 return EOF_LINE; 214 215 again: 216 token = gettoken(f, c, &c); 217 218 switch (token) { 219 case EOF_TOKEN: 220 return EOF_LINE; 221 case EOL_TOKEN: 222 /* empty line */ 223 c = FontFileGetc(f); 224 goto again; 225 case NUMBER_TOKEN: 226 value1 = number_value; 227 token = gettoken(f, c, &c); 228 switch (token) { 229 case NUMBER_TOKEN: 230 value2 = number_value; 231 token = gettoken(f, c, &c); 232 switch (token) { 233 case NUMBER_TOKEN: 234 value3 = number_value; 235 return CODE_RANGE_LINE; 236 case EOL_TOKEN: 237 return CODE_LINE; 238 default: 239 skipEndOfLine(f, c); 240 return ERROR_LINE; 241 } 242 case KEYWORD_TOKEN: 243 if (!endOfLine(f, c)) 244 return ERROR_LINE; 245 else 246 return NAME_LINE; 247 default: 248 skipEndOfLine(f, c); 249 return ERROR_LINE; 250 } 251 case KEYWORD_TOKEN: 252 if (!strcasecmp(keyword_value, "STARTENCODING")) { 253 token = gettoken(f, c, &c); 254 if (token == KEYWORD_TOKEN) { 255 if (endOfLine(f, c)) 256 return STARTENCODING_LINE; 257 else 258 return ERROR_LINE; 259 } 260 else { 261 skipEndOfLine(f, c); 262 return ERROR_LINE; 263 } 264 } 265 else if (!strcasecmp(keyword_value, "ALIAS")) { 266 token = gettoken(f, c, &c); 267 if (token == KEYWORD_TOKEN) { 268 if (endOfLine(f, c)) 269 return ALIAS_LINE; 270 else 271 return ERROR_LINE; 272 } 273 else { 274 skipEndOfLine(f, c); 275 return ERROR_LINE; 276 } 277 } 278 else if (!strcasecmp(keyword_value, "SIZE")) { 279 token = gettoken(f, c, &c); 280 if (token == NUMBER_TOKEN) { 281 value1 = number_value; 282 token = gettoken(f, c, &c); 283 switch (token) { 284 case NUMBER_TOKEN: 285 value2 = number_value; 286 return SIZE_LINE; 287 case EOL_TOKEN: 288 value2 = 0; 289 return SIZE_LINE; 290 default: 291 skipEndOfLine(f, c); 292 return ERROR_LINE; 293 } 294 } 295 else { 296 skipEndOfLine(f, c); 297 return ERROR_LINE; 298 } 299 } 300 else if (!strcasecmp(keyword_value, "FIRSTINDEX")) { 301 token = gettoken(f, c, &c); 302 if (token == NUMBER_TOKEN) { 303 value1 = number_value; 304 token = gettoken(f, c, &c); 305 switch (token) { 306 case NUMBER_TOKEN: 307 value2 = number_value; 308 return FIRSTINDEX_LINE; 309 case EOL_TOKEN: 310 value2 = 0; 311 return FIRSTINDEX_LINE; 312 default: 313 skipEndOfLine(f, c); 314 return ERROR_LINE; 315 } 316 } 317 else { 318 skipEndOfLine(f, c); 319 return ERROR_LINE; 320 } 321 } 322 else if (!strcasecmp(keyword_value, "STARTMAPPING")) { 323 keyword_value[0] = 0; 324 value1 = 0; 325 value2 = 0; 326 /* first a keyword */ 327 token = gettoken(f, c, &c); 328 if (token != KEYWORD_TOKEN) { 329 skipEndOfLine(f, c); 330 return ERROR_LINE; 331 } 332 333 /* optional first integer */ 334 token = gettoken(f, c, &c); 335 if (token == NUMBER_TOKEN) { 336 value1 = number_value; 337 } 338 else if (token == EOL_TOKEN) { 339 return STARTMAPPING_LINE; 340 } 341 else { 342 skipEndOfLine(f, c); 343 return ERROR_LINE; 344 } 345 346 /* optional second integer */ 347 token = gettoken(f, c, &c); 348 if (token == NUMBER_TOKEN) { 349 value2 = number_value; 350 } 351 else if (token == EOL_TOKEN) { 352 return STARTMAPPING_LINE; 353 } 354 else { 355 skipEndOfLine(f, c); 356 return ERROR_LINE; 357 } 358 359 if (!endOfLine(f, c)) 360 return ERROR_LINE; 361 else { 362 return STARTMAPPING_LINE; 363 } 364 } 365 else if (!strcasecmp(keyword_value, "UNDEFINE")) { 366 /* first integer */ 367 token = gettoken(f, c, &c); 368 if (token != NUMBER_TOKEN) { 369 skipEndOfLine(f, c); 370 return ERROR_LINE; 371 } 372 value1 = number_value; 373 /* optional second integer */ 374 token = gettoken(f, c, &c); 375 if (token == EOL_TOKEN) { 376 value2 = value1; 377 return CODE_UNDEFINE_LINE; 378 } 379 else if (token == NUMBER_TOKEN) { 380 value2 = number_value; 381 if (endOfLine(f, c)) { 382 return CODE_UNDEFINE_LINE; 383 } 384 else 385 return ERROR_LINE; 386 } 387 else { 388 skipEndOfLine(f, c); 389 return ERROR_LINE; 390 } 391 } 392 else if (!strcasecmp(keyword_value, "ENDENCODING")) { 393 if (endOfLine(f, c)) 394 return EOF_LINE; 395 else 396 return ERROR_LINE; 397 } 398 else if (!strcasecmp(keyword_value, "ENDMAPPING")) { 399 if (endOfLine(f, c)) 400 return ENDMAPPING_LINE; 401 else 402 return ERROR_LINE; 403 } 404 else { 405 skipEndOfLine(f, c); 406 return ERROR_LINE; 407 } 408 default: 409 return ERROR_LINE; 410 } 411} 412 413static void 414install_mapping(FontEncPtr encoding, FontMapPtr mapping) 415{ 416 FontMapPtr m; 417 418 if (encoding->mappings == NULL) 419 encoding->mappings = mapping; 420 else { 421 m = encoding->mappings; 422 while (m->next != NULL) 423 m = m->next; 424 m->next = mapping; 425 } 426 mapping->next = NULL; 427 mapping->encoding = encoding; 428} 429 430static int 431setCode(unsigned from, unsigned to, unsigned row_size, 432 unsigned *first, unsigned *last, 433 unsigned *encsize, unsigned short **enc) 434{ 435 unsigned index, i; 436 437 unsigned short *newenc; 438 439 if (from > 0xFFFF) 440 return 0; /* success */ 441 442 if (row_size == 0) 443 index = from; 444 else { 445 if ((value1 & 0xFF) >= row_size) 446 return 0; /* ignore out of range mappings */ 447 index = (from >> 8) * row_size + (from & 0xFF); 448 } 449 450 /* Optimize away useless identity mappings. This is only expected 451 to be useful with linear encodings. */ 452 if (index == to && (index < *first || index > *last)) 453 return 0; 454 if (*encsize == 0) { 455 *encsize = (index < 256) ? 256 : 0x10000; 456 *enc = malloc((*encsize) * sizeof(unsigned short)); 457 if (*enc == NULL) { 458 *encsize = 0; 459 return 1; 460 } 461 } 462 else if (*encsize <= index) { 463 *encsize = 0x10000; 464 if ((newenc = 465 realloc(*enc, (*encsize) * sizeof(unsigned short))) == NULL) 466 return 1; 467 *enc = newenc; 468 } 469 if (*first > *last) { 470 *first = *last = index; 471 } 472 if (index < *first) { 473 for (i = index; i < *first; i++) 474 (*enc)[i] = i; 475 *first = index; 476 } 477 if (index > *last) { 478 for (i = *last + 1; i <= index; i++) 479 (*enc)[i] = i; 480 *last = index; 481 } 482 (*enc)[index] = to; 483 return 0; 484} 485 486/* Parser. If headerOnly is true, we're only interested in the 487 data contained in the encoding file's header. */ 488 489/* As font encodings are currently never freed, the allocations done 490 by this function are mostly its private business. Note, however, 491 that FontEncIdentify needs to free the header fields -- so if you 492 change this function, you may need to change FontEncIdentify. */ 493 494/* I want a garbage collector. */ 495 496static FontEncPtr 497parseEncodingFile(FontFilePtr f, int headerOnly) 498{ 499 int line; 500 501 unsigned short *enc = NULL; 502 char **nam = NULL, **newnam; 503 unsigned i, first = 0xFFFF, last = 0, encsize = 0, namsize = 0; 504 FontEncPtr encoding = NULL; 505 FontMapPtr mapping = NULL; 506 FontEncSimpleMapPtr sm; 507 FontEncSimpleNamePtr sn; 508 char *aliases[MAXALIASES] = { NULL }; 509 int numaliases = 0; 510 511#if 0 512 /* GCC complains about unused labels. Please fix GCC rather than 513 obfuscating my code. */ 514 no_encoding: 515#endif 516 line = getnextline(f); 517 switch (line) { 518 case EOF_LINE: 519 goto error; 520 case STARTENCODING_LINE: 521 encoding = malloc(sizeof(FontEncRec)); 522 if (encoding == NULL) 523 goto error; 524 encoding->name = strdup(keyword_value); 525 if (encoding->name == NULL) 526 goto error; 527 encoding->size = 256; 528 encoding->row_size = 0; 529 encoding->mappings = NULL; 530 encoding->next = NULL; 531 encoding->first = encoding->first_col = 0; 532 goto no_mapping; 533 default: 534 goto error; 535 } 536 537 no_mapping: 538 line = getnextline(f); 539 switch (line) { 540 case EOF_LINE: 541 goto done; 542 case ALIAS_LINE: 543 if (numaliases < MAXALIASES) { 544 aliases[numaliases] = strdup(keyword_value); 545 if (aliases[numaliases] == NULL) 546 goto error; 547 numaliases++; 548 } 549 goto no_mapping; 550 case SIZE_LINE: 551 encoding->size = value1; 552 encoding->row_size = value2; 553 goto no_mapping; 554 case FIRSTINDEX_LINE: 555 encoding->first = value1; 556 encoding->first_col = value2; 557 goto no_mapping; 558 case STARTMAPPING_LINE: 559 if (headerOnly) 560 goto done; 561 if (!strcasecmp(keyword_value, "unicode")) { 562 mapping = malloc(sizeof(FontMapRec)); 563 if (mapping == NULL) 564 goto error; 565 mapping->type = FONT_ENCODING_UNICODE; 566 mapping->pid = 0; 567 mapping->eid = 0; 568 mapping->recode = NULL; 569 mapping->name = NULL; 570 mapping->client_data = NULL; 571 mapping->next = NULL; 572 goto mapping; 573 } 574 else if (!strcasecmp(keyword_value, "cmap")) { 575 mapping = malloc(sizeof(FontMapRec)); 576 if (mapping == NULL) 577 goto error; 578 mapping->type = FONT_ENCODING_TRUETYPE; 579 mapping->pid = value1; 580 mapping->eid = value2; 581 mapping->recode = NULL; 582 mapping->name = NULL; 583 mapping->client_data = NULL; 584 mapping->next = NULL; 585 goto mapping; 586 } 587 else if (!strcasecmp(keyword_value, "postscript")) { 588 mapping = malloc(sizeof(FontMapRec)); 589 if (mapping == NULL) 590 goto error; 591 mapping->type = FONT_ENCODING_POSTSCRIPT; 592 mapping->pid = 0; 593 mapping->eid = 0; 594 mapping->recode = NULL; 595 mapping->name = NULL; 596 mapping->client_data = NULL; 597 mapping->next = NULL; 598 goto string_mapping; 599 } 600 else { /* unknown mapping type -- ignore */ 601 goto skipmapping; 602 } 603 /* NOTREACHED */ 604 goto error; 605 default: 606 goto no_mapping; /* ignore unknown lines */ 607 } 608 609 skipmapping: 610 line = getnextline(f); 611 switch (line) { 612 case ENDMAPPING_LINE: 613 goto no_mapping; 614 case EOF_LINE: 615 goto error; 616 default: 617 goto skipmapping; 618 } 619 620 mapping: 621 line = getnextline(f); 622 switch (line) { 623 case EOF_LINE: 624 goto error; 625 case ENDMAPPING_LINE: 626 mapping->recode = FontEncSimpleRecode; 627 mapping->name = FontEncUndefinedName; 628 mapping->client_data = sm = malloc(sizeof(FontEncSimpleMapRec)); 629 if (sm == NULL) 630 goto error; 631 sm->row_size = encoding->row_size; 632 if (first <= last) { 633 unsigned short *newmap; 634 635 sm->first = first; 636 sm->len = last - first + 1; 637 newmap = malloc(sm->len * sizeof(unsigned short)); 638 if (newmap == NULL) { 639 free(sm); 640 mapping->client_data = sm = NULL; 641 goto error; 642 } 643 for (i = 0; i < sm->len; i++) 644 newmap[i] = enc[first + i]; 645 sm->map = newmap; 646 } 647 else { 648 sm->first = 0; 649 sm->len = 0; 650 sm->map = NULL; 651 } 652 install_mapping(encoding, mapping); 653 mapping = NULL; 654 first = 0xFFFF; 655 last = 0; 656 goto no_mapping; 657 658 case CODE_LINE: 659 if (setCode(value1, value2, encoding->row_size, 660 &first, &last, &encsize, &enc)) 661 goto error; 662 goto mapping; 663 664 case CODE_RANGE_LINE: 665 if (value1 > 0x10000) 666 value1 = 0x10000; 667 if (value2 > 0x10000) 668 value2 = 0x10000; 669 if (value2 < value1) 670 goto mapping; 671 /* Do the last value first to avoid having to realloc() */ 672 if (setCode(value2, value3 + (value2 - value1), encoding->row_size, 673 &first, &last, &encsize, &enc)) 674 goto error; 675 for (i = value1; i < value2; i++) { 676 if (setCode(i, value3 + (i - value1), encoding->row_size, 677 &first, &last, &encsize, &enc)) 678 goto error; 679 } 680 goto mapping; 681 682 case CODE_UNDEFINE_LINE: 683 if (value1 > 0x10000) 684 value1 = 0x10000; 685 if (value2 > 0x10000) 686 value2 = 0x10000; 687 if (value2 < value1) 688 goto mapping; 689 /* Do the last value first to avoid having to realloc() */ 690 if (setCode(value2, 0, encoding->row_size, 691 &first, &last, &encsize, &enc)) 692 goto error; 693 for (i = value1; i < value2; i++) { 694 if (setCode(i, 0, encoding->row_size, 695 &first, &last, &encsize, &enc)) 696 goto error; 697 } 698 goto mapping; 699 700 default: 701 goto mapping; /* ignore unknown lines */ 702 } 703 704 string_mapping: 705 line = getnextline(f); 706 switch (line) { 707 case EOF_LINE: 708 goto error; 709 case ENDMAPPING_LINE: 710 mapping->recode = FontEncUndefinedRecode; 711 mapping->name = FontEncSimpleName; 712 mapping->client_data = sn = malloc(sizeof(FontEncSimpleNameRec)); 713 if (sn == NULL) 714 goto error; 715 if (first > last) { 716 free(sn); 717 mapping->client_data = sn = NULL; 718 goto error; 719 } 720 sn->first = first; 721 sn->len = last - first + 1; 722 sn->map = malloc(sn->len * sizeof(char *)); 723 if (sn->map == NULL) { 724 free(sn); 725 mapping->client_data = sn = NULL; 726 goto error; 727 } 728 for (i = 0; i < sn->len; i++) 729 sn->map[i] = nam[first + i]; 730 install_mapping(encoding, mapping); 731 mapping = NULL; 732 first = 0xFFFF; 733 last = 0; 734 goto no_mapping; 735 case NAME_LINE: 736 if (value1 >= 0x10000) 737 goto string_mapping; 738 if (namsize == 0) { 739 namsize = (value1) < 256 ? 256 : 0x10000; 740 nam = malloc(namsize * sizeof(char *)); 741 if (nam == NULL) { 742 namsize = 0; 743 goto error; 744 } 745 } 746 else if (namsize <= value1) { 747 namsize = 0x10000; 748 if ((newnam = (char **) realloc(nam, namsize)) == NULL) 749 goto error; 750 nam = newnam; 751 } 752 if (first > last) { 753 first = last = value1; 754 } 755 if (value1 < first) { 756 for (i = value1; i < first; i++) 757 nam[i] = NULL; 758 first = value1; 759 } 760 if (value1 > last) { 761 for (i = last + 1; i <= value1; i++) 762 nam[i] = NULL; 763 last = value1; 764 } 765 nam[value1] = strdup(keyword_value); 766 if (nam[value1] == NULL) { 767 goto error; 768 } 769 goto string_mapping; 770 771 default: 772 goto string_mapping; /* ignore unknown lines */ 773 } 774 775 done: 776 if (encsize) { 777 free(enc); 778 encsize = 0; 779 enc = NULL; 780 } 781 if (namsize) { 782 free(nam); /* don't free entries! */ 783 namsize = 0; 784 nam = NULL; 785 } 786 787 encoding->aliases = NULL; 788 if (numaliases) { 789 encoding->aliases = malloc((numaliases + 1) * sizeof(char *)); 790 if (encoding->aliases == NULL) 791 goto error; 792 for (i = 0; i < numaliases; i++) 793 encoding->aliases[i] = aliases[i]; 794 encoding->aliases[numaliases] = NULL; 795 } 796 797 return encoding; 798 799 error: 800 if (encsize) { 801 free(enc); 802 encsize = 0; 803 } 804 if (namsize) { 805 for (i = first; i <= last; i++) 806 free(nam[i]); 807 free(nam); 808 } 809 if (mapping) { 810 free(mapping->client_data); 811 free(mapping); 812 } 813 if (encoding) { 814 FontMapPtr nextmap; 815 816 free(encoding->name); 817 for (mapping = encoding->mappings; mapping; mapping = nextmap) { 818 free(mapping->client_data); 819 nextmap = mapping->next; 820 free(mapping); 821 } 822 free(encoding); 823 } 824 for (i = 0; i < numaliases; i++) 825 free(aliases[i]); 826 /* We don't need to free sn and sm as they handled locally in the body. */ 827 return NULL; 828} 829 830char * 831FontEncDirectory(void) 832{ 833 static char *dir = NULL; 834 835 if (dir == NULL) { 836 char *c = getenv("FONT_ENCODINGS_DIRECTORY"); 837 838 if (c) { 839 dir = strdup(c); 840 if (!dir) 841 return NULL; 842 } 843 else { 844 dir = FONT_ENCODINGS_DIRECTORY; 845 } 846 } 847 return dir; 848} 849 850static void 851parseFontFileName(const char *fontFileName, char *buf, char *dir) 852{ 853 const char *p; 854 char *q, *lastslash; 855 856 for (p = fontFileName, q = dir, lastslash = NULL; *p; p++, q++) { 857 *q = *p; 858 if (*p == '/') 859 lastslash = q + 1; 860 } 861 862 if (!lastslash) 863 lastslash = dir; 864 865 *lastslash = '\0'; 866 867 if (buf && strlen(dir) + 14 < MAXFONTFILENAMELEN) { 868 snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, "encodings.dir"); 869 } 870} 871 872static FontEncPtr 873FontEncReallyReallyLoad(const char *charset, 874 const char *dirname, const char *dir) 875{ 876 FontFilePtr f; 877 FILE *file; 878 FontEncPtr encoding; 879 char file_name[MAXFONTFILENAMELEN], encoding_name[MAXFONTNAMELEN], 880 buf[MAXFONTFILENAMELEN]; 881 int count, n; 882 static char format[24] = ""; 883 884 /* As we don't really expect to open encodings that often, we don't 885 take the trouble of caching encodings directories. */ 886 887 if ((file = fopen(dirname, "r")) == NULL) { 888 return NULL; 889 } 890 891 count = fscanf(file, "%d\n", &n); 892 if (count == EOF || count != 1) { 893 fclose(file); 894 return NULL; 895 } 896 897 encoding = NULL; 898 if (!format[0]) { 899 snprintf(format, sizeof(format), "%%%ds %%%d[^\n]\n", 900 (int) sizeof(encoding_name) - 1, (int) sizeof(file_name) - 1); 901 } 902 for (;;) { 903 count = fscanf(file, format, encoding_name, file_name); 904 if (count == EOF) 905 break; 906 if (count != 2) 907 break; 908 909 if (!strcasecmp(encoding_name, charset)) { 910 /* Found it */ 911 if (file_name[0] != '/') { 912 if (strlen(dir) + strlen(file_name) >= MAXFONTFILENAMELEN) { 913 fclose(file); 914 return NULL; 915 } 916 snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, file_name); 917 } 918 else { 919 snprintf(buf, MAXFONTFILENAMELEN, "%s", file_name); 920 } 921 922 f = FontFileOpen(buf); 923 if (f == NULL) { 924 fclose(file); 925 return NULL; 926 } 927 encoding = parseEncodingFile(f, 0); 928 FontFileClose(f); 929 break; 930 } 931 } 932 933 fclose(file); 934 935 return encoding; 936} 937 938/* Parser ntrypoint -- used by FontEncLoad */ 939FontEncPtr 940FontEncReallyLoad(const char *charset, const char *fontFileName) 941{ 942 FontEncPtr encoding; 943 char dir[MAXFONTFILENAMELEN], dirname[MAXFONTFILENAMELEN]; 944 char *d; 945 946 if (fontFileName) { 947 parseFontFileName(fontFileName, dirname, dir); 948 encoding = FontEncReallyReallyLoad(charset, dirname, dir); 949 if (encoding) 950 return (encoding); 951 } 952 953 d = FontEncDirectory(); 954 if (d) { 955 parseFontFileName(d, NULL, dir); 956 encoding = FontEncReallyReallyLoad(charset, d, dir); 957 return encoding; 958 } 959 960 return NULL; 961} 962 963/* Return a NULL-terminated array of encoding names. Note that this 964 * function has incestuous knowledge of the allocations done by 965 * parseEncodingFile. */ 966 967char ** 968FontEncIdentify(const char *fileName) 969{ 970 FontFilePtr f; 971 FontEncPtr encoding; 972 char **names, **name, **alias; 973 int numaliases; 974 975 if ((f = FontFileOpen(fileName)) == NULL) { 976 return NULL; 977 } 978 encoding = parseEncodingFile(f, 1); 979 FontFileClose(f); 980 981 if (!encoding) 982 return NULL; 983 984 numaliases = 0; 985 if (encoding->aliases) 986 for (alias = encoding->aliases; *alias; alias++) 987 numaliases++; 988 989 names = malloc((numaliases + 2) * sizeof(char *)); 990 if (names == NULL) { 991 free(encoding->aliases); 992 free(encoding); 993 return NULL; 994 } 995 996 name = names; 997 *(name++) = encoding->name; 998 if (numaliases > 0) 999 for (alias = encoding->aliases; *alias; alias++, name++) 1000 *name = *alias; 1001 1002 *name = NULL; 1003 free(encoding->aliases); 1004 free(encoding); 1005 1006 return names; 1007} 1008