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