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