encparse.c revision 55acc8fc
11.80Sjmcneill/* 21.1StvCopyright (c) 1998-2001 by Juliusz Chroboczek 31.1Stv 41.1StvPermission is hereby granted, free of charge, to any person obtaining a copy 51.62Sapbof this software and associated documentation files (the "Software"), to deal 61.62Sapbin the Software without restriction, including without limitation the rights 71.62Sapbto use, copy, modify, merge, publish, distribute, sublicense, and/or sell 81.62Sapbcopies of the Software, and to permit persons to whom the Software is 91.62Sapbfurnished to do so, subject to the following conditions: 101.62Sapb 111.62SapbThe above copyright notice and this permission notice shall be included in 121.62Sapball copies or substantial portions of the Software. 131.62Sapb 141.62SapbTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 151.62SapbIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 161.62SapbFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 171.64SapbAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 181.64SapbLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 191.64SapbOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 201.62SapbTHE SOFTWARE. 211.1Stv*/ 221.40Ssalo 231.56Swiz/* Parser for encoding files */ 241.1Stv 251.20Sbjh21/* This code assumes that we are using ASCII. We don't use the ctype 261.56Swiz functions, as they depend on the current locale. On the other 271.72Sapb hand, we do use strcasecmp, but only on strings that we've checked 281.56Swiz to be pure ASCII. Bloody ``Code Set Independence''. */ 291.56Swiz 301.56Swiz#include <string.h> 311.56Swiz#include <stdio.h> 321.56Swiz 331.56Swiz#if defined(__SCO__) || defined(__UNIXWARE__) 341.56Swiz#include <strings.h> 351.44Sjmc#endif 361.44Sjmc 371.44Sjmc#include <stdlib.h> 381.44Sjmc 391.44Sjmc#include "zlib.h" 401.44Sjmctypedef gzFile FontFilePtr; 411.44Sjmc#define FontFileGetc(f) gzgetc(f) 421.44Sjmc#define FontFileOpen(filename) gzopen(filename, "rb") 431.44Sjmc#define FontFileClose(f) gzclose(f) 441.44Sjmc 451.53Swiz#define MAXFONTFILENAMELEN 1024 461.53Swiz#define MAXFONTNAMELEN 1024 471.53Swiz 481.44Sjmc#include <X11/fonts/fontenc.h> 491.44Sjmc#include "fontencI.h" 501.44Sjmc 511.44Sjmc#define MAXALIASES 20 521.20Sbjh21 531.20Sbjh21#define EOF_TOKEN -1 541.20Sbjh21#define ERROR_TOKEN -2 551.20Sbjh21#define EOL_TOKEN 0 561.53Swiz#define NUMBER_TOKEN 1 571.1Stv#define KEYWORD_TOKEN 2 581.4Stv 591.6Stv#define EOF_LINE -1 601.6Stv#define ERROR_LINE -2 611.6Stv#define STARTENCODING_LINE 1 621.6Stv#define STARTMAPPING_LINE 2 631.6Stv#define ENDMAPPING_LINE 3 641.6Stv#define CODE_LINE 4 651.6Stv#define CODE_RANGE_LINE 5 661.6Stv#define CODE_UNDEFINE_LINE 6 671.6Stv#define NAME_LINE 7 681.4Stv#define SIZE_LINE 8 691.4Stv#define ALIAS_LINE 9 701.4Stv#define FIRSTINDEX_LINE 10 711.4Stv 721.69Sdbj/* Return from lexer */ 731.34Sthorpej#define MAXKEYWORDLEN 100 741.34Sthorpej 751.28Sbriggsstatic long number_value; 761.22Sthorpejstatic char keyword_value[MAXKEYWORDLEN+1]; 771.4Stv 781.4Stvstatic long value1, value2, value3; 791.4Stv 801.6Stv/* Lexer code */ 811.69Sdbj 821.75Schristos/* Skip to the beginning of new line */ 831.72Sapbstatic void 841.72SapbskipEndOfLine(FontFilePtr f, int c) 851.72Sapb{ 861.11Stv if(c == 0) 871.44Sjmc c = FontFileGetc(f); 881.41Slukem 891.72Sapb for(;;) 901.72Sapb if(c <= 0 || c == '\n') 911.11Stv return; 921.11Stv else 931.11Stv c = FontFileGetc(f); 941.11Stv} 951.11Stv 961.4Stv/* Get a number; we're at the first digit. */ 971.4Stvstatic unsigned 981.1Stvgetnum(FontFilePtr f, int c, int *cp) 991.44Sjmc{ 1001.53Swiz unsigned n = 0; 1011.53Swiz int base = 10; 1021.35Sthorpej 1031.77Spooka /* look for `0' or `0x' prefix */ 1041.75Schristos if(c == '0') { 1051.77Spooka c = FontFileGetc(f); 1061.35Sthorpej base = 8; 1071.6Stv if(c == 'x' || c == 'X') { 1081.9Stv base = 16; 1091.9Stv c = FontFileGetc(f); 1101.9Stv } 1111.6Stv } 1121.9Stv 1131.9Stv /* accumulate digits */ 1141.53Swiz for(;;) { 1151.53Swiz if ('0' <= c && c <= '9') { 1161.9Stv n *= base; n += c - '0'; 1171.9Stv } else if('a' <= c && c <= 'f') { 1181.6Stv n *= base; n += c - 'a' + 10; 1191.6Stv } else if('A' <=c && c <= 'F') { 1201.53Swiz n *= base; n += c - 'A' + 10; 1211.53Swiz } else 1221.6Stv break; 1231.6Stv c = FontFileGetc(f); 1241.6Stv } 1251.6Stv 1261.6Stv *cp = c; return n; 1271.6Stv} 1281.6Stv 1291.6Stv/* Skip to beginning of new line; return 1 if only whitespace was found. */ 1301.4Stvstatic int 1311.4StvendOfLine(FontFilePtr f, int c) 1321.58Sthorpej{ 1331.32Sthorpej if(c == 0) 1341.32Sthorpej c = FontFileGetc(f); 1351.7Stv 1361.49Sjmc for(;;) { 1371.49Sjmc if(c <= 0 || c == '\n') 1381.49Sjmc return 1; 1391.46Sdbj else if(c == '#') { 1401.80Sjmcneill skipEndOfLine(f,c); 1411.4Stv return 1; 1421.4Stv } 1431.7Stv else if(c == ' ' || c == '\t') { 1441.7Stv skipEndOfLine(f,c); 1451.7Stv return 0; 1461.7Stv } 1471.77Spooka c = FontFileGetc(f); 1481.77Spooka } 1491.77Spooka} 1501.7Stv 1511.4Stv/* Get a token; we're at first char */ 1521.4Stvstatic int 1531.4Stvgettoken(FontFilePtr f, int c, int *cp) 1541.19Sbjh21{ 1551.39Satatat char *p; 1561.76Schristos 1571.74Sjoerg if(c <= 0) 1581.48Sjmc c = FontFileGetc(f); 1591.72Sapb 1601.72Sapb if(c <= 0) { 1611.78Sapb return EOF_TOKEN; 1621.78Sapb } 1631.61Snakayama 1641.66Schristos while(c == ' ' || c == '\t') 1651.8Stv c = FontFileGetc(f); 1661.66Schristos 1671.66Schristos if(c=='\n') { 1681.66Schristos return EOL_TOKEN; 1691.66Schristos } else if(c == '#') { 1701.66Schristos skipEndOfLine(f,c); 1711.66Schristos return EOL_TOKEN; 1721.66Schristos } else if(c >= '0' && c <= '9') { 1731.54Swiz number_value = getnum(f,c,cp); 1741.66Schristos return NUMBER_TOKEN; 1751.66Schristos } else if((c >= 'A' && c <= 'Z') || 1761.66Schristos (c >= 'a' && c <= 'z') || 1771.66Schristos c == '/' || c == '_' || c == '-' || c == '.') { 1781.54Swiz p = keyword_value; 1791.72Sapb *p++ = c; 1801.72Sapb while(p-keyword_value < MAXKEYWORDLEN) { 1811.72Sapb c = FontFileGetc(f); 1821.44Sjmc if(c <= ' ' || c > '~' || c == '#') 1831.54Swiz break; 1841.44Sjmc *p++ = c; 1851.72Sapb } 1861.72Sapb *cp = c; 1871.72Sapb *p = '\0'; 1881.63Sapb return KEYWORD_TOKEN; 1891.54Swiz } else { 1901.47Sjmc *cp = c; 1911.8Stv return ERROR_TOKEN; 1921.33Sthorpej } 1931.8Stv} 1941.8Stv 1951.8Stv/* Parse a line. 1961.1Stv * Always skips to the beginning of a new line, even if an error occurs */ 1971.4Stvstatic int 1981.4Stvgetnextline(FontFilePtr f) 1991.1Stv{ 2001.4Stv int c, token; 2011.4Stv c = FontFileGetc(f); 2021.4Stv if(c <= 0) 2031.4Stv return EOF_LINE; 2041.1Stv 2051.79Sjmcneill again: 2061.79Sjmcneill token=gettoken(f,c,&c); 2071.68Stnozaki 2081.68Stnozaki switch(token) { 2091.68Stnozaki case EOF_TOKEN: 2101.68Stnozaki return EOF_LINE; 2111.68Stnozaki case EOL_TOKEN: 2121.68Stnozaki /* empty line */ 2131.68Stnozaki c = FontFileGetc(f); 2141.68Stnozaki goto again; 2151.68Stnozaki case NUMBER_TOKEN: 2161.68Stnozaki value1 = number_value; 2171.68Stnozaki token = gettoken(f,c,&c); 2181.68Stnozaki switch(token) { 2191.68Stnozaki case NUMBER_TOKEN: 2201.68Stnozaki value2 = number_value; 2211.68Stnozaki token = gettoken(f,c,&c); 2221.68Stnozaki switch(token) { 2231.68Stnozaki case NUMBER_TOKEN: 2241.68Stnozaki value3 = number_value; 2251.68Stnozaki return CODE_RANGE_LINE; 2261.68Stnozaki case EOL_TOKEN: 2271.68Stnozaki return CODE_LINE; 2281.68Stnozaki default: 2291.68Stnozaki skipEndOfLine(f,c); 2301.68Stnozaki return ERROR_LINE; 2311.68Stnozaki } 2321.68Stnozaki case KEYWORD_TOKEN: 2331.68Stnozaki if(!endOfLine(f,c)) 2341.68Stnozaki return ERROR_LINE; 2351.68Stnozaki else 2361.68Stnozaki return NAME_LINE; 2371.68Stnozaki default: 2381.68Stnozaki skipEndOfLine(f,c); 2391.68Stnozaki return ERROR_LINE; 2401.68Stnozaki } 2411.68Stnozaki case KEYWORD_TOKEN: 2421.68Stnozaki if(!strcasecmp(keyword_value, "STARTENCODING")) { 2431.73Sapb token = gettoken(f,c,&c); 2441.73Sapb if(token == KEYWORD_TOKEN) { 2451.73Sapb if(endOfLine(f,c)) 2461.1Stv return STARTENCODING_LINE; 247 else 248 return ERROR_LINE; 249 } else { 250 skipEndOfLine(f,c); 251 return ERROR_LINE; 252 } 253 } else if(!strcasecmp(keyword_value, "ALIAS")) { 254 token = gettoken(f,c,&c); 255 if(token == KEYWORD_TOKEN) { 256 if(endOfLine(f,c)) 257 return ALIAS_LINE; 258 else 259 return ERROR_LINE; 260 } else { 261 skipEndOfLine(f,c); 262 return ERROR_LINE; 263 } 264 } else if(!strcasecmp(keyword_value, "SIZE")) { 265 token = gettoken(f,c,&c); 266 if(token == NUMBER_TOKEN) { 267 value1 = number_value; 268 token = gettoken(f,c,&c); 269 switch(token) { 270 case NUMBER_TOKEN: 271 value2 = number_value; 272 return SIZE_LINE; 273 case EOL_TOKEN: 274 value2=0; 275 return SIZE_LINE; 276 default: 277 skipEndOfLine(f,c); 278 return ERROR_LINE; 279 } 280 } else { 281 skipEndOfLine(f,c); 282 return ERROR_LINE; 283 } 284 } else if(!strcasecmp(keyword_value, "FIRSTINDEX")) { 285 token = gettoken(f,c,&c); 286 if(token == NUMBER_TOKEN) { 287 value1 = number_value; 288 token = gettoken(f,c,&c); 289 switch(token) { 290 case NUMBER_TOKEN: 291 value2 = number_value; 292 return FIRSTINDEX_LINE; 293 case EOL_TOKEN: 294 value2 = 0; 295 return FIRSTINDEX_LINE; 296 default: 297 skipEndOfLine(f,c); 298 return ERROR_LINE; 299 } 300 } else { 301 skipEndOfLine(f,c); 302 return ERROR_LINE; 303 } 304 } else if(!strcasecmp(keyword_value, "STARTMAPPING")) { 305 keyword_value[0] = 0; 306 value1 = 0; value1 = 0; 307 /* first a keyword */ 308 token = gettoken(f,c,&c); 309 if(token != KEYWORD_TOKEN) { 310 skipEndOfLine(f, c); 311 return ERROR_LINE; 312 } 313 314 /* optional first integer */ 315 token = gettoken(f,c,&c); 316 if(token == NUMBER_TOKEN) { 317 value1 = number_value; 318 } else if(token == EOL_TOKEN) { 319 return STARTMAPPING_LINE; 320 } else { 321 skipEndOfLine(f, c); 322 return ERROR_LINE; 323 } 324 325 /* optional second integer */ 326 token = gettoken(f,c,&c); 327 if(token == NUMBER_TOKEN) { 328 value2 = number_value; 329 } else if(token == EOL_TOKEN) { 330 return STARTMAPPING_LINE; 331 } else { 332 skipEndOfLine(f, c); 333 return ERROR_LINE; 334 } 335 336 if(!endOfLine(f,c)) 337 return ERROR_LINE; 338 else { 339 return STARTMAPPING_LINE; 340 } 341 } else if(!strcasecmp(keyword_value, "UNDEFINE")) { 342 /* first integer */ 343 token = gettoken(f,c,&c); 344 if(token != NUMBER_TOKEN) { 345 skipEndOfLine(f,c); 346 return ERROR_LINE; 347 } 348 value1 = number_value; 349 /* optional second integer */ 350 token = gettoken(f,c,&c); 351 if(token == EOL_TOKEN) { 352 value2 = value1; 353 return CODE_UNDEFINE_LINE; 354 } else if(token == NUMBER_TOKEN) { 355 value2 = number_value; 356 if(endOfLine(f,c)) { 357 return CODE_UNDEFINE_LINE; 358 } else 359 return ERROR_LINE; 360 } else { 361 skipEndOfLine(f,c); 362 return ERROR_LINE; 363 } 364 } else if(!strcasecmp(keyword_value, "ENDENCODING")) { 365 if(endOfLine(f,c)) 366 return EOF_LINE; 367 else 368 return ERROR_LINE; 369 } else if(!strcasecmp(keyword_value, "ENDMAPPING")) { 370 if(endOfLine(f,c)) 371 return ENDMAPPING_LINE; 372 else 373 return ERROR_LINE; 374 } else { 375 skipEndOfLine(f,c); 376 return ERROR_LINE; 377 } 378 default: 379 return ERROR_LINE; 380 } 381} 382 383static void 384install_mapping(FontEncPtr encoding, FontMapPtr mapping) 385{ 386 FontMapPtr m; 387 388 if(encoding->mappings == NULL) 389 encoding->mappings = mapping; 390 else { 391 m = encoding->mappings; 392 while(m->next != NULL) 393 m = m->next; 394 m->next = mapping; 395 } 396 mapping->next = NULL; 397 mapping->encoding = encoding; 398} 399 400static int 401setCode(unsigned from, unsigned to, unsigned row_size, 402 unsigned *first, unsigned *last, 403 unsigned *encsize, unsigned short **enc) 404{ 405 unsigned index, i; 406 unsigned short *newenc; 407 408 if(from>0xFFFF) 409 return 0; /* success */ 410 411 if(row_size==0) 412 index=from; 413 else { 414 if((value1 & 0xFF) >= row_size) 415 return 0; /* ignore out of range mappings */ 416 index = (from>>8) * row_size + (from&0xFF); 417 } 418 419 /* Optimize away useless identity mappings. This is only expected 420 to be useful with linear encodings. */ 421 if(index == to && (index < *first || index > *last)) 422 return 0; 423 if(*encsize == 0) { 424 *encsize = (index < 256) ? 256 : 0x10000; 425 *enc = malloc((*encsize) * sizeof(unsigned short)); 426 if(*enc == NULL) { 427 *encsize = 0; 428 return 1; 429 } 430 } else if(*encsize <= index) { 431 *encsize = 0x10000; 432 if((newenc = realloc(enc, *encsize))==NULL) 433 return 1; 434 *enc = newenc; 435 } 436 if(*first > *last) { 437 *first = *last = index; 438 } 439 if(index < *first) { 440 for(i = index; i < *first; i++) 441 (*enc)[i] = i; 442 *first = index; 443 } 444 if(index > *last) { 445 for(i = *last + 1; i <= index; i++) 446 (*enc)[i] = i; 447 *last = index; 448 } 449 (*enc)[index] = to; 450 return 0; 451} 452 453/* Parser. If headerOnly is true, we're only interested in the 454 data contained in the encoding file's header. */ 455 456/* As font encodings are currently never freed, the allocations done 457 by this function are mostly its private business. Note, however, 458 that FontEncIdentify needs to free the header fields -- so if you 459 change this function, you may need to change FontEncIdentify. */ 460 461/* I want a garbage collector. */ 462 463static FontEncPtr 464parseEncodingFile(FontFilePtr f, int headerOnly) 465{ 466 int line; 467 468 unsigned short *enc=NULL; 469 char **nam = NULL, **newnam; 470 unsigned i, first = 0xFFFF, last=0, encsize=0, namsize=0; 471 FontEncPtr encoding = NULL; 472 FontMapPtr mapping = NULL; 473 FontEncSimpleMapPtr sm; 474 FontEncSimpleNamePtr sn; 475 char *aliases[MAXALIASES]; 476 int numaliases=0; 477 478#if 0 479 /* GCC complains about unused labels. Please fix GCC rather than 480 obfuscating my code. */ 481 no_encoding: 482#endif 483 line = getnextline(f); 484 switch(line) { 485 case EOF_LINE: 486 goto error; 487 case STARTENCODING_LINE: 488 encoding = malloc(sizeof(FontEncRec)); 489 if(encoding == NULL) 490 goto error; 491 encoding->name = strdup(keyword_value); 492 if(encoding->name == NULL) 493 goto error; 494 encoding->size = 256; 495 encoding->row_size = 0; 496 encoding->mappings = NULL; 497 encoding->next = NULL; 498 encoding->first = encoding->first_col=0; 499 goto no_mapping; 500 default: 501 goto error; 502 } 503 504 no_mapping: 505 line = getnextline(f); 506 switch(line) { 507 case EOF_LINE: goto done; 508 case ALIAS_LINE: 509 if(numaliases < MAXALIASES) { 510 aliases[numaliases] = strdup(keyword_value); 511 if(aliases[numaliases] == NULL) 512 goto error; 513 numaliases++; 514 } 515 goto no_mapping; 516 case SIZE_LINE: 517 encoding->size = value1; 518 encoding->row_size = value2; 519 goto no_mapping; 520 case FIRSTINDEX_LINE: 521 encoding->first = value1; 522 encoding->first_col = value2; 523 goto no_mapping; 524 case STARTMAPPING_LINE: 525 if(headerOnly) 526 goto done; 527 if(!strcasecmp(keyword_value, "unicode")) { 528 mapping = malloc(sizeof(FontMapRec)); 529 if(mapping == NULL) 530 goto error; 531 mapping->type = FONT_ENCODING_UNICODE; 532 mapping->pid = 0; 533 mapping->eid = 0; 534 mapping->recode = NULL; 535 mapping->name = NULL; 536 mapping->client_data = NULL; 537 mapping->next = NULL; 538 goto mapping; 539 } else if(!strcasecmp(keyword_value, "cmap")) { 540 mapping = malloc(sizeof(FontMapRec)); 541 if(mapping == NULL) 542 goto error; 543 mapping->type = FONT_ENCODING_TRUETYPE; 544 mapping->pid = value1; 545 mapping->eid = value2; 546 mapping->recode = NULL; 547 mapping->name = NULL; 548 mapping->client_data = NULL; 549 mapping->next = NULL; 550 goto mapping; 551 } else if(!strcasecmp(keyword_value, "postscript")) { 552 mapping = malloc(sizeof(FontMapRec)); 553 if(mapping == NULL) 554 goto error; 555 mapping->type = FONT_ENCODING_POSTSCRIPT; 556 mapping->pid = 0; 557 mapping->eid = 0; 558 mapping->recode = NULL; 559 mapping->name = NULL; 560 mapping->client_data = NULL; 561 mapping->next = NULL; 562 goto string_mapping; 563 } else { /* unknown mapping type -- ignore */ 564 goto skipmapping; 565 } 566 /* NOTREACHED */ 567 goto error; 568 default: goto no_mapping; /* ignore unknown lines */ 569 } 570 571 skipmapping: 572 line = getnextline(f); 573 switch(line) { 574 case ENDMAPPING_LINE: 575 goto no_mapping; 576 case EOF_LINE: 577 goto error; 578 default: 579 goto skipmapping; 580 } 581 582 mapping: 583 line = getnextline(f); 584 switch(line) { 585 case EOF_LINE: goto error; 586 case ENDMAPPING_LINE: 587 mapping->recode = FontEncSimpleRecode; 588 mapping->name = FontEncUndefinedName; 589 mapping->client_data = sm = malloc(sizeof(FontEncSimpleMapRec)); 590 if(sm == NULL) 591 goto error; 592 sm->row_size = encoding->row_size; 593 if(first <= last) { 594 unsigned short *newmap; 595 596 sm->first = first; 597 sm->len=last-first+1; 598 newmap = malloc(sm->len * sizeof(unsigned short)); 599 if(newmap == NULL) { 600 free(sm); 601 mapping->client_data = sm = NULL; 602 goto error; 603 } 604 for(i=0; i < sm->len; i++) 605 newmap[i] = enc[first+i]; 606 sm->map = newmap; 607 } else { 608 sm->first = 0; 609 sm->len = 0; 610 sm->map = NULL; 611 } 612 install_mapping(encoding, mapping); 613 mapping = NULL; 614 first = 0xFFFF; last=0; 615 goto no_mapping; 616 617 case CODE_LINE: 618 if(setCode(value1, value2, encoding->row_size, 619 &first, &last, &encsize, &enc)) 620 goto error; 621 goto mapping; 622 623 case CODE_RANGE_LINE: 624 if(value1 > 0x10000) 625 value1 = 0x10000; 626 if(value2 > 0x10000) 627 value2 = 0x10000; 628 if(value2 < value1) 629 goto mapping; 630 /* Do the last value first to avoid having to realloc() */ 631 if(setCode(value2, value3+(value2-value1), encoding->row_size, 632 &first, &last, &encsize, &enc)) 633 goto error; 634 for(i=value1; i<value2; i++) { 635 if(setCode(i, value3+(i-value1), encoding->row_size, 636 &first, &last, &encsize, &enc)) 637 goto error; 638 } 639 goto mapping; 640 641 case CODE_UNDEFINE_LINE: 642 if(value1 > 0x10000) 643 value1 = 0x10000; 644 if(value2 > 0x10000) 645 value2 = 0x10000; 646 if(value2 < value1) 647 goto mapping; 648 /* Do the last value first to avoid having to realloc() */ 649 if(setCode(value2, 0, encoding->row_size, 650 &first, &last, &encsize, &enc)) 651 goto error; 652 for(i = value1; i < value2; i++) { 653 if(setCode(i, 0, encoding->row_size, 654 &first, &last, &encsize, &enc)) 655 goto error; 656 } 657 goto mapping; 658 659 default: goto mapping; /* ignore unknown lines */ 660 } 661 662 string_mapping: 663 line = getnextline(f); 664 switch(line) { 665 case EOF_LINE: goto error; 666 case ENDMAPPING_LINE: 667 mapping->recode = FontEncUndefinedRecode; 668 mapping->name = FontEncSimpleName; 669 mapping->client_data = sn = malloc(sizeof(FontEncSimpleNameRec)); 670 if(sn == NULL) 671 goto error; 672 if(first > last) { 673 free(sn); 674 mapping->client_data = sn = NULL; 675 goto error; 676 } 677 sn->first = first; 678 sn->len = last - first + 1; 679 sn->map = malloc(sn->len*sizeof(char*)); 680 if(sn->map == NULL) { 681 free(sn); 682 mapping->client_data = sn = NULL; 683 goto error; 684 } 685 for(i = 0; i < sn->len; i++) 686 sn->map[i] = nam[first+i]; 687 install_mapping(encoding,mapping); 688 mapping = NULL; 689 first = 0xFFFF; last=0; 690 goto no_mapping; 691 case NAME_LINE: 692 if(value1 >= 0x10000) goto string_mapping; 693 if(namsize == 0) { 694 namsize = (value1) < 256 ? 256 : 0x10000; 695 nam = malloc(namsize * sizeof(char*)); 696 if(nam == NULL) { 697 namsize=0; 698 goto error; 699 } 700 } else if(namsize <= value1) { 701 namsize = 0x10000; 702 if((newnam = (char**)realloc(nam, namsize)) == NULL) 703 goto error; 704 nam = newnam; 705 } 706 if(first > last) { 707 first = last = value1; 708 } 709 if(value1 < first) { 710 for(i = value1; i < first; i++) 711 nam[i] = NULL; 712 first = value1; 713 } 714 if(value1 > last) { 715 for(i=last+1; i <= value1; i++) 716 nam[i]=NULL; 717 last = value1; 718 } 719 nam[value1] = strdup(keyword_value); 720 if(nam[value1] == NULL) { 721 goto error; 722 } 723 goto string_mapping; 724 725 default: goto string_mapping; /* ignore unknown lines */ 726 } 727 728 done: 729 if(encsize) free(enc); encsize=0; enc = NULL; 730 if(namsize) free(nam); namsize=0; nam = NULL; /* don't free entries! */ 731 732 encoding->aliases=NULL; 733 if(numaliases) { 734 encoding->aliases = malloc((numaliases+1)*sizeof(char*)); 735 if(encoding->aliases == NULL) 736 goto error; 737 for(i=0; i<numaliases; i++) 738 encoding->aliases[i] = aliases[i]; 739 encoding->aliases[numaliases]=NULL; 740 } 741 742 return encoding; 743 744error: 745 if(encsize) free(enc); encsize=0; 746 if(namsize) { 747 for(i = first; i <= last; i++) 748 free(nam[i]); 749 free(nam); 750 namsize = 0; 751 } 752 if(mapping) { 753 free(mapping->client_data); 754 free(mapping); 755 } 756 if(encoding) { 757 FontMapPtr nextmap; 758 free(encoding->name); 759 for (mapping = encoding->mappings; mapping; mapping = nextmap) { 760 free(mapping->client_data); 761 nextmap = mapping->next; 762 free(mapping); 763 } 764 free(encoding); 765 } 766 for(i = 0; i < numaliases; i++) 767 free(aliases[i]); 768 /* We don't need to free sn and sm as they handled locally in the body.*/ 769 return NULL; 770} 771 772char* 773FontEncDirectory(void) 774{ 775 static char* dir = NULL; 776 777 if(dir == NULL) { 778 char *c = getenv("FONT_ENCODINGS_DIRECTORY"); 779 if(c) { 780 dir = strdup(c); 781 if(!dir) 782 return NULL; 783 } else { 784 dir = FONT_ENCODINGS_DIRECTORY; 785 } 786 } 787 return dir; 788} 789 790static void 791parseFontFileName(const char *fontFileName, char *buf, char *dir) 792{ 793 const char *p; 794 char *q, *lastslash; 795 796 for(p = fontFileName, q = dir, lastslash = NULL; *p; p++, q++) { 797 *q = *p; 798 if(*p == '/') 799 lastslash = q+1; 800 } 801 802 if(!lastslash) 803 lastslash = dir; 804 805 *lastslash = '\0'; 806 807 if(buf && strlen(dir) + 14 < MAXFONTFILENAMELEN) { 808 strcpy(buf, dir); 809 strcat(buf, "encodings.dir"); 810 } 811} 812 813static FontEncPtr 814FontEncReallyReallyLoad(const char *charset, 815 const char *dirname, const char *dir) 816{ 817 FontFilePtr f; 818 FILE *file; 819 FontEncPtr encoding; 820 char file_name[MAXFONTFILENAMELEN], encoding_name[MAXFONTNAMELEN], 821 buf[MAXFONTFILENAMELEN]; 822 int count, n; 823 static char format[24] = ""; 824 825 /* As we don't really expect to open encodings that often, we don't 826 take the trouble of caching encodings directories. */ 827 828 if((file = fopen(dirname, "r")) == NULL) { 829 return NULL; 830 } 831 832 count = fscanf(file, "%d\n", &n); 833 if(count == EOF || count != 1) { 834 fclose(file); 835 return NULL; 836 } 837 838 encoding = NULL; 839 if (!format[0]) { 840 sprintf(format, "%%%ds %%%d[^\n]\n", (int)sizeof(encoding_name) - 1, 841 (int)sizeof(file_name) - 1); 842 } 843 for(;;) { 844 count = fscanf(file, format, encoding_name, file_name); 845 if(count == EOF) 846 break; 847 if(count != 2) 848 break; 849 850 if(!strcasecmp(encoding_name, charset)) { 851 /* Found it */ 852 if(file_name[0] != '/') { 853 if(strlen(dir) + strlen(file_name) >= MAXFONTFILENAMELEN) { 854 fclose(file); 855 return NULL; 856 } 857 strcpy(buf, dir); 858 strcat(buf, file_name); 859 } else { 860 strcpy(buf , file_name); 861 } 862 863 f = FontFileOpen(buf); 864 if(f == NULL) { 865 fclose(file); 866 return NULL; 867 } 868 encoding = parseEncodingFile(f, 0); 869 FontFileClose(f); 870 break; 871 } 872 } 873 874 fclose(file); 875 876 return encoding; 877} 878 879/* Parser ntrypoint -- used by FontEncLoad */ 880FontEncPtr 881FontEncReallyLoad(const char *charset, const char *fontFileName) 882{ 883 FontEncPtr encoding; 884 char dir[MAXFONTFILENAMELEN], dirname[MAXFONTFILENAMELEN]; 885 char *d; 886 887 if(fontFileName) { 888 parseFontFileName(fontFileName, dirname, dir); 889 encoding = FontEncReallyReallyLoad(charset, dirname, dir); 890 if(encoding) 891 return(encoding); 892 } 893 894 d = FontEncDirectory(); 895 if(d) { 896 parseFontFileName(d, NULL, dir); 897 encoding = FontEncReallyReallyLoad(charset, d, dir); 898 return encoding; 899 } 900 901 return NULL; 902} 903 904/* Return a NULL-terminated array of encoding names. Note that this 905 * function has incestuous knowledge of the allocations done by 906 * parseEncodingFile. */ 907 908char ** 909FontEncIdentify(const char *fileName) 910{ 911 FontFilePtr f; 912 FontEncPtr encoding; 913 char **names, **name, **alias; 914 int numaliases; 915 916 if((f = FontFileOpen(fileName))==NULL) { 917 return NULL; 918 } 919 encoding = parseEncodingFile(f, 1); 920 FontFileClose(f); 921 922 if(!encoding) 923 return NULL; 924 925 numaliases = 0; 926 if(encoding->aliases) 927 for(alias = encoding->aliases; *alias; alias++) 928 numaliases++; 929 930 names = malloc((numaliases+2)*sizeof(char*)); 931 if(names == NULL) { 932 free(encoding->aliases); 933 free(encoding); 934 return NULL; 935 } 936 937 name = names; 938 *(name++) = encoding->name; 939 if(numaliases > 0) 940 for(alias = encoding->aliases; *alias; alias++, name++) 941 *name = *alias; 942 943 *name = NULL; 944 free(encoding->aliases); 945 free(encoding); 946 947 return names; 948} 949