13da084b3Smrg/* 23da084b3SmrgCopyright (c) 1998-2001 by Juliusz Chroboczek 33da084b3Smrg 43da084b3SmrgPermission is hereby granted, free of charge, to any person obtaining a copy 53da084b3Smrgof this software and associated documentation files (the "Software"), to deal 63da084b3Smrgin the Software without restriction, including without limitation the rights 73da084b3Smrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell 83da084b3Smrgcopies of the Software, and to permit persons to whom the Software is 93da084b3Smrgfurnished to do so, subject to the following conditions: 103da084b3Smrg 113da084b3SmrgThe above copyright notice and this permission notice shall be included in 123da084b3Smrgall copies or substantial portions of the Software. 133da084b3Smrg 143da084b3SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 153da084b3SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 163da084b3SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 173da084b3SmrgAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 183da084b3SmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 193da084b3SmrgOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 203da084b3SmrgTHE SOFTWARE. 213da084b3Smrg*/ 223da084b3Smrg 233da084b3Smrg/* Parser for encoding files */ 243da084b3Smrg 253da084b3Smrg/* This code assumes that we are using ASCII. We don't use the ctype 263da084b3Smrg functions, as they depend on the current locale. On the other 273da084b3Smrg hand, we do use strcasecmp, but only on strings that we've checked 283da084b3Smrg to be pure ASCII. Bloody ``Code Set Independence''. */ 293da084b3Smrg 302a53b785Smrg#ifdef HAVE_CONFIG_H 312a53b785Smrg#include <config.h> 322a53b785Smrg#endif 332a53b785Smrg 343da084b3Smrg#include <string.h> 353da084b3Smrg#include <strings.h> 3648c85eb7Smrg#include <stdio.h> 373da084b3Smrg 383da084b3Smrg#include <stdlib.h> 393da084b3Smrg 40da2777aaSmrg#include <fcntl.h> 41da2777aaSmrg#ifdef O_CLOEXEC 42da2777aaSmrg#define FOPEN_CLOEXEC "e" 43da2777aaSmrg#else 44da2777aaSmrg#define FOPEN_CLOEXEC "" 45da2777aaSmrg#endif 46da2777aaSmrg 47da2777aaSmrg 483da084b3Smrg#include "zlib.h" 493da084b3Smrgtypedef gzFile FontFilePtr; 50e1c0d025Smrg 513da084b3Smrg#define FontFileGetc(f) gzgetc(f) 523da084b3Smrg#define FontFileOpen(filename) gzopen(filename, "rb") 533da084b3Smrg#define FontFileClose(f) gzclose(f) 543da084b3Smrg 553da084b3Smrg#define MAXFONTFILENAMELEN 1024 563da084b3Smrg#define MAXFONTNAMELEN 1024 573da084b3Smrg 583da084b3Smrg#include <X11/fonts/fontenc.h> 593da084b3Smrg#include "fontencI.h" 602a53b785Smrg#include "reallocarray.h" 613da084b3Smrg 623da084b3Smrg#define MAXALIASES 20 633da084b3Smrg 643da084b3Smrg#define EOF_TOKEN -1 653da084b3Smrg#define ERROR_TOKEN -2 663da084b3Smrg#define EOL_TOKEN 0 673da084b3Smrg#define NUMBER_TOKEN 1 683da084b3Smrg#define KEYWORD_TOKEN 2 693da084b3Smrg 703da084b3Smrg#define EOF_LINE -1 713da084b3Smrg#define ERROR_LINE -2 723da084b3Smrg#define STARTENCODING_LINE 1 733da084b3Smrg#define STARTMAPPING_LINE 2 743da084b3Smrg#define ENDMAPPING_LINE 3 753da084b3Smrg#define CODE_LINE 4 763da084b3Smrg#define CODE_RANGE_LINE 5 773da084b3Smrg#define CODE_UNDEFINE_LINE 6 783da084b3Smrg#define NAME_LINE 7 793da084b3Smrg#define SIZE_LINE 8 803da084b3Smrg#define ALIAS_LINE 9 813da084b3Smrg#define FIRSTINDEX_LINE 10 823da084b3Smrg 833da084b3Smrg/* Return from lexer */ 843da084b3Smrg#define MAXKEYWORDLEN 100 853da084b3Smrg 863da084b3Smrgstatic long number_value; 87e1c0d025Smrgstatic char keyword_value[MAXKEYWORDLEN + 1]; 883da084b3Smrg 893da084b3Smrgstatic long value1, value2, value3; 903da084b3Smrg 913da084b3Smrg/* Lexer code */ 923da084b3Smrg 933da084b3Smrg/* Skip to the beginning of new line */ 943da084b3Smrgstatic void 953da084b3SmrgskipEndOfLine(FontFilePtr f, int c) 963da084b3Smrg{ 97e1c0d025Smrg if (c == 0) 983da084b3Smrg c = FontFileGetc(f); 9948c85eb7Smrg 100e1c0d025Smrg for (;;) 101e1c0d025Smrg if (c <= 0 || c == '\n') 1023da084b3Smrg return; 1033da084b3Smrg else 1043da084b3Smrg c = FontFileGetc(f); 1053da084b3Smrg} 1063da084b3Smrg 1073da084b3Smrg/* Get a number; we're at the first digit. */ 1083da084b3Smrgstatic unsigned 1093da084b3Smrggetnum(FontFilePtr f, int c, int *cp) 1103da084b3Smrg{ 1113da084b3Smrg unsigned n = 0; 1123da084b3Smrg int base = 10; 1133da084b3Smrg 1143da084b3Smrg /* look for `0' or `0x' prefix */ 115e1c0d025Smrg if (c == '0') { 1163da084b3Smrg c = FontFileGetc(f); 1173da084b3Smrg base = 8; 118e1c0d025Smrg if (c == 'x' || c == 'X') { 1193da084b3Smrg base = 16; 1203da084b3Smrg c = FontFileGetc(f); 1213da084b3Smrg } 1223da084b3Smrg } 1233da084b3Smrg 1243da084b3Smrg /* accumulate digits */ 125e1c0d025Smrg for (;;) { 1263da084b3Smrg if ('0' <= c && c <= '9') { 127e1c0d025Smrg n *= base; 128e1c0d025Smrg n += c - '0'; 129e1c0d025Smrg } 130e1c0d025Smrg else if ('a' <= c && c <= 'f') { 131e1c0d025Smrg n *= base; 132e1c0d025Smrg n += c - 'a' + 10; 133e1c0d025Smrg } 134e1c0d025Smrg else if ('A' <= c && c <= 'F') { 135e1c0d025Smrg n *= base; 136e1c0d025Smrg n += c - 'A' + 10; 137e1c0d025Smrg } 138e1c0d025Smrg else 1393da084b3Smrg break; 1403da084b3Smrg c = FontFileGetc(f); 1413da084b3Smrg } 1423da084b3Smrg 143e1c0d025Smrg *cp = c; 144e1c0d025Smrg return n; 1453da084b3Smrg} 14648c85eb7Smrg 1473da084b3Smrg/* Skip to beginning of new line; return 1 if only whitespace was found. */ 1483da084b3Smrgstatic int 1493da084b3SmrgendOfLine(FontFilePtr f, int c) 1503da084b3Smrg{ 151e1c0d025Smrg if (c == 0) 1523da084b3Smrg c = FontFileGetc(f); 1533da084b3Smrg 154e1c0d025Smrg for (;;) { 155e1c0d025Smrg if (c <= 0 || c == '\n') 1563da084b3Smrg return 1; 157e1c0d025Smrg else if (c == '#') { 158e1c0d025Smrg skipEndOfLine(f, c); 1593da084b3Smrg return 1; 1603da084b3Smrg } 161e1c0d025Smrg else if (c == ' ' || c == '\t') { 162e1c0d025Smrg skipEndOfLine(f, c); 1633da084b3Smrg return 0; 1643da084b3Smrg } 1653da084b3Smrg c = FontFileGetc(f); 1663da084b3Smrg } 1673da084b3Smrg} 1683da084b3Smrg 1693da084b3Smrg/* Get a token; we're at first char */ 1703da084b3Smrgstatic int 1713da084b3Smrggettoken(FontFilePtr f, int c, int *cp) 1723da084b3Smrg{ 1733da084b3Smrg char *p; 1743da084b3Smrg 175e1c0d025Smrg if (c <= 0) 176e1c0d025Smrg c = FontFileGetc(f); 1773da084b3Smrg 178e1c0d025Smrg if (c <= 0) { 1793da084b3Smrg return EOF_TOKEN; 1803da084b3Smrg } 1813da084b3Smrg 182e1c0d025Smrg while (c == ' ' || c == '\t') 1833da084b3Smrg c = FontFileGetc(f); 1843da084b3Smrg 185e1c0d025Smrg if (c == '\n') { 1863da084b3Smrg return EOL_TOKEN; 187e1c0d025Smrg } 188e1c0d025Smrg else if (c == '#') { 189e1c0d025Smrg skipEndOfLine(f, c); 1903da084b3Smrg return EOL_TOKEN; 191e1c0d025Smrg } 192e1c0d025Smrg else if (c >= '0' && c <= '9') { 193e1c0d025Smrg number_value = getnum(f, c, cp); 1943da084b3Smrg return NUMBER_TOKEN; 195e1c0d025Smrg } 196e1c0d025Smrg else if ((c >= 'A' && c <= 'Z') || 197e1c0d025Smrg (c >= 'a' && c <= 'z') || 198e1c0d025Smrg c == '/' || c == '_' || c == '-' || c == '.') { 1993da084b3Smrg p = keyword_value; 2003da084b3Smrg *p++ = c; 201e1c0d025Smrg while (p - keyword_value < MAXKEYWORDLEN) { 2023da084b3Smrg c = FontFileGetc(f); 203e1c0d025Smrg if (c <= ' ' || c > '~' || c == '#') 2043da084b3Smrg break; 2053da084b3Smrg *p++ = c; 2063da084b3Smrg } 2073da084b3Smrg *cp = c; 2083da084b3Smrg *p = '\0'; 2093da084b3Smrg return KEYWORD_TOKEN; 210e1c0d025Smrg } 211e1c0d025Smrg else { 2123da084b3Smrg *cp = c; 2133da084b3Smrg return ERROR_TOKEN; 2143da084b3Smrg } 2153da084b3Smrg} 2163da084b3Smrg 2173da084b3Smrg/* Parse a line. 2183da084b3Smrg * Always skips to the beginning of a new line, even if an error occurs */ 2193da084b3Smrgstatic int 2203da084b3Smrggetnextline(FontFilePtr f) 2213da084b3Smrg{ 2223da084b3Smrg int c, token; 223e1c0d025Smrg 2243da084b3Smrg c = FontFileGetc(f); 225e1c0d025Smrg if (c <= 0) 2263da084b3Smrg return EOF_LINE; 2273da084b3Smrg 228e1c0d025Smrg again: 229e1c0d025Smrg token = gettoken(f, c, &c); 2303da084b3Smrg 231e1c0d025Smrg switch (token) { 2323da084b3Smrg case EOF_TOKEN: 2333da084b3Smrg return EOF_LINE; 2343da084b3Smrg case EOL_TOKEN: 2353da084b3Smrg /* empty line */ 2363da084b3Smrg c = FontFileGetc(f); 2373da084b3Smrg goto again; 2383da084b3Smrg case NUMBER_TOKEN: 2393da084b3Smrg value1 = number_value; 240e1c0d025Smrg token = gettoken(f, c, &c); 241e1c0d025Smrg switch (token) { 2423da084b3Smrg case NUMBER_TOKEN: 2433da084b3Smrg value2 = number_value; 244e1c0d025Smrg token = gettoken(f, c, &c); 245e1c0d025Smrg switch (token) { 2463da084b3Smrg case NUMBER_TOKEN: 2473da084b3Smrg value3 = number_value; 2483da084b3Smrg return CODE_RANGE_LINE; 2493da084b3Smrg case EOL_TOKEN: 2503da084b3Smrg return CODE_LINE; 2513da084b3Smrg default: 252e1c0d025Smrg skipEndOfLine(f, c); 2533da084b3Smrg return ERROR_LINE; 2543da084b3Smrg } 2553da084b3Smrg case KEYWORD_TOKEN: 256e1c0d025Smrg if (!endOfLine(f, c)) 2573da084b3Smrg return ERROR_LINE; 2583da084b3Smrg else 2593da084b3Smrg return NAME_LINE; 2603da084b3Smrg default: 261e1c0d025Smrg skipEndOfLine(f, c); 2623da084b3Smrg return ERROR_LINE; 2633da084b3Smrg } 2643da084b3Smrg case KEYWORD_TOKEN: 265e1c0d025Smrg if (!strcasecmp(keyword_value, "STARTENCODING")) { 266e1c0d025Smrg token = gettoken(f, c, &c); 267e1c0d025Smrg if (token == KEYWORD_TOKEN) { 268e1c0d025Smrg if (endOfLine(f, c)) 2693da084b3Smrg return STARTENCODING_LINE; 2703da084b3Smrg else 2713da084b3Smrg return ERROR_LINE; 272e1c0d025Smrg } 273e1c0d025Smrg else { 274e1c0d025Smrg skipEndOfLine(f, c); 2753da084b3Smrg return ERROR_LINE; 2763da084b3Smrg } 277e1c0d025Smrg } 278e1c0d025Smrg else if (!strcasecmp(keyword_value, "ALIAS")) { 279e1c0d025Smrg token = gettoken(f, c, &c); 280e1c0d025Smrg if (token == KEYWORD_TOKEN) { 281e1c0d025Smrg if (endOfLine(f, c)) 2823da084b3Smrg return ALIAS_LINE; 2833da084b3Smrg else 2843da084b3Smrg return ERROR_LINE; 285e1c0d025Smrg } 286e1c0d025Smrg else { 287e1c0d025Smrg skipEndOfLine(f, c); 2883da084b3Smrg return ERROR_LINE; 2893da084b3Smrg } 290e1c0d025Smrg } 291e1c0d025Smrg else if (!strcasecmp(keyword_value, "SIZE")) { 292e1c0d025Smrg token = gettoken(f, c, &c); 293e1c0d025Smrg if (token == NUMBER_TOKEN) { 2943da084b3Smrg value1 = number_value; 295e1c0d025Smrg token = gettoken(f, c, &c); 296e1c0d025Smrg switch (token) { 2973da084b3Smrg case NUMBER_TOKEN: 2983da084b3Smrg value2 = number_value; 2993da084b3Smrg return SIZE_LINE; 3003da084b3Smrg case EOL_TOKEN: 301e1c0d025Smrg value2 = 0; 3023da084b3Smrg return SIZE_LINE; 3033da084b3Smrg default: 304e1c0d025Smrg skipEndOfLine(f, c); 3053da084b3Smrg return ERROR_LINE; 3063da084b3Smrg } 307e1c0d025Smrg } 308e1c0d025Smrg else { 309e1c0d025Smrg skipEndOfLine(f, c); 3103da084b3Smrg return ERROR_LINE; 3113da084b3Smrg } 312e1c0d025Smrg } 313e1c0d025Smrg else if (!strcasecmp(keyword_value, "FIRSTINDEX")) { 314e1c0d025Smrg token = gettoken(f, c, &c); 315e1c0d025Smrg if (token == NUMBER_TOKEN) { 3163da084b3Smrg value1 = number_value; 317e1c0d025Smrg token = gettoken(f, c, &c); 318e1c0d025Smrg switch (token) { 3193da084b3Smrg case NUMBER_TOKEN: 3203da084b3Smrg value2 = number_value; 3213da084b3Smrg return FIRSTINDEX_LINE; 3223da084b3Smrg case EOL_TOKEN: 3233da084b3Smrg value2 = 0; 3243da084b3Smrg return FIRSTINDEX_LINE; 3253da084b3Smrg default: 326e1c0d025Smrg skipEndOfLine(f, c); 3273da084b3Smrg return ERROR_LINE; 3283da084b3Smrg } 329e1c0d025Smrg } 330e1c0d025Smrg else { 331e1c0d025Smrg skipEndOfLine(f, c); 3323da084b3Smrg return ERROR_LINE; 3333da084b3Smrg } 334e1c0d025Smrg } 335e1c0d025Smrg else if (!strcasecmp(keyword_value, "STARTMAPPING")) { 3363da084b3Smrg keyword_value[0] = 0; 337e1c0d025Smrg value1 = 0; 338e1c0d025Smrg value2 = 0; 3393da084b3Smrg /* first a keyword */ 340e1c0d025Smrg token = gettoken(f, c, &c); 341e1c0d025Smrg if (token != KEYWORD_TOKEN) { 3423da084b3Smrg skipEndOfLine(f, c); 3433da084b3Smrg return ERROR_LINE; 3443da084b3Smrg } 3453da084b3Smrg 3463da084b3Smrg /* optional first integer */ 347e1c0d025Smrg token = gettoken(f, c, &c); 348e1c0d025Smrg if (token == NUMBER_TOKEN) { 3493da084b3Smrg value1 = number_value; 350e1c0d025Smrg } 351e1c0d025Smrg else if (token == EOL_TOKEN) { 3523da084b3Smrg return STARTMAPPING_LINE; 353e1c0d025Smrg } 354e1c0d025Smrg else { 3553da084b3Smrg skipEndOfLine(f, c); 3563da084b3Smrg return ERROR_LINE; 3573da084b3Smrg } 3583da084b3Smrg 3593da084b3Smrg /* optional second integer */ 360e1c0d025Smrg token = gettoken(f, c, &c); 361e1c0d025Smrg if (token == NUMBER_TOKEN) { 3623da084b3Smrg value2 = number_value; 363e1c0d025Smrg } 364e1c0d025Smrg else if (token == EOL_TOKEN) { 3653da084b3Smrg return STARTMAPPING_LINE; 366e1c0d025Smrg } 367e1c0d025Smrg else { 3683da084b3Smrg skipEndOfLine(f, c); 3693da084b3Smrg return ERROR_LINE; 3703da084b3Smrg } 3713da084b3Smrg 372e1c0d025Smrg if (!endOfLine(f, c)) 3733da084b3Smrg return ERROR_LINE; 3743da084b3Smrg else { 3753da084b3Smrg return STARTMAPPING_LINE; 3763da084b3Smrg } 377e1c0d025Smrg } 378e1c0d025Smrg else if (!strcasecmp(keyword_value, "UNDEFINE")) { 3793da084b3Smrg /* first integer */ 380e1c0d025Smrg token = gettoken(f, c, &c); 381e1c0d025Smrg if (token != NUMBER_TOKEN) { 382e1c0d025Smrg skipEndOfLine(f, c); 3833da084b3Smrg return ERROR_LINE; 3843da084b3Smrg } 3853da084b3Smrg value1 = number_value; 3863da084b3Smrg /* optional second integer */ 387e1c0d025Smrg token = gettoken(f, c, &c); 388e1c0d025Smrg if (token == EOL_TOKEN) { 3893da084b3Smrg value2 = value1; 3903da084b3Smrg return CODE_UNDEFINE_LINE; 391e1c0d025Smrg } 392e1c0d025Smrg else if (token == NUMBER_TOKEN) { 3933da084b3Smrg value2 = number_value; 394e1c0d025Smrg if (endOfLine(f, c)) { 3953da084b3Smrg return CODE_UNDEFINE_LINE; 396e1c0d025Smrg } 397e1c0d025Smrg else 3983da084b3Smrg return ERROR_LINE; 399e1c0d025Smrg } 400e1c0d025Smrg else { 401e1c0d025Smrg skipEndOfLine(f, c); 4023da084b3Smrg return ERROR_LINE; 4033da084b3Smrg } 404e1c0d025Smrg } 405e1c0d025Smrg else if (!strcasecmp(keyword_value, "ENDENCODING")) { 406e1c0d025Smrg if (endOfLine(f, c)) 4073da084b3Smrg return EOF_LINE; 4083da084b3Smrg else 4093da084b3Smrg return ERROR_LINE; 410e1c0d025Smrg } 411e1c0d025Smrg else if (!strcasecmp(keyword_value, "ENDMAPPING")) { 412e1c0d025Smrg if (endOfLine(f, c)) 4133da084b3Smrg return ENDMAPPING_LINE; 4143da084b3Smrg else 4153da084b3Smrg return ERROR_LINE; 416e1c0d025Smrg } 417e1c0d025Smrg else { 418e1c0d025Smrg skipEndOfLine(f, c); 4193da084b3Smrg return ERROR_LINE; 4203da084b3Smrg } 4213da084b3Smrg default: 4223da084b3Smrg return ERROR_LINE; 4233da084b3Smrg } 4243da084b3Smrg} 4253da084b3Smrg 42648c85eb7Smrgstatic void 4273da084b3Smrginstall_mapping(FontEncPtr encoding, FontMapPtr mapping) 4283da084b3Smrg{ 4293da084b3Smrg FontMapPtr m; 4303da084b3Smrg 431e1c0d025Smrg if (encoding->mappings == NULL) 4323da084b3Smrg encoding->mappings = mapping; 4333da084b3Smrg else { 4343da084b3Smrg m = encoding->mappings; 435e1c0d025Smrg while (m->next != NULL) 4363da084b3Smrg m = m->next; 4373da084b3Smrg m->next = mapping; 4383da084b3Smrg } 4393da084b3Smrg mapping->next = NULL; 4403da084b3Smrg mapping->encoding = encoding; 4413da084b3Smrg} 4423da084b3Smrg 4433da084b3Smrgstatic int 4443da084b3SmrgsetCode(unsigned from, unsigned to, unsigned row_size, 4453da084b3Smrg unsigned *first, unsigned *last, 4463da084b3Smrg unsigned *encsize, unsigned short **enc) 4473da084b3Smrg{ 4483da084b3Smrg unsigned index, i; 449e1c0d025Smrg 4503da084b3Smrg unsigned short *newenc; 4513da084b3Smrg 452e1c0d025Smrg if (from > 0xFFFF) 4533da084b3Smrg return 0; /* success */ 4543da084b3Smrg 455e1c0d025Smrg if (row_size == 0) 456e1c0d025Smrg index = from; 4573da084b3Smrg else { 458e1c0d025Smrg if ((value1 & 0xFF) >= row_size) 4593da084b3Smrg return 0; /* ignore out of range mappings */ 460e1c0d025Smrg index = (from >> 8) * row_size + (from & 0xFF); 4613da084b3Smrg } 4623da084b3Smrg 4633da084b3Smrg /* Optimize away useless identity mappings. This is only expected 4643da084b3Smrg to be useful with linear encodings. */ 465e1c0d025Smrg if (index == to && (index < *first || index > *last)) 4663da084b3Smrg return 0; 467e1c0d025Smrg if (*encsize == 0) { 4683da084b3Smrg *encsize = (index < 256) ? 256 : 0x10000; 4692a53b785Smrg *enc = Xmallocarray(*encsize, sizeof(unsigned short)); 470e1c0d025Smrg if (*enc == NULL) { 4713da084b3Smrg *encsize = 0; 4723da084b3Smrg return 1; 4733da084b3Smrg } 474e1c0d025Smrg } 475e1c0d025Smrg else if (*encsize <= index) { 4763da084b3Smrg *encsize = 0x10000; 4772a53b785Smrg newenc = Xreallocarray(*enc, *encsize, sizeof(unsigned short)); 4782a53b785Smrg if (newenc == NULL) 4793da084b3Smrg return 1; 4803da084b3Smrg *enc = newenc; 4813da084b3Smrg } 482e1c0d025Smrg if (*first > *last) { 4833da084b3Smrg *first = *last = index; 4843da084b3Smrg } 485e1c0d025Smrg if (index < *first) { 486e1c0d025Smrg for (i = index; i < *first; i++) 4873da084b3Smrg (*enc)[i] = i; 4883da084b3Smrg *first = index; 4893da084b3Smrg } 490e1c0d025Smrg if (index > *last) { 491e1c0d025Smrg for (i = *last + 1; i <= index; i++) 4923da084b3Smrg (*enc)[i] = i; 4933da084b3Smrg *last = index; 4943da084b3Smrg } 4953da084b3Smrg (*enc)[index] = to; 4963da084b3Smrg return 0; 4973da084b3Smrg} 4983da084b3Smrg 4993da084b3Smrg/* Parser. If headerOnly is true, we're only interested in the 5003da084b3Smrg data contained in the encoding file's header. */ 5013da084b3Smrg 5023da084b3Smrg/* As font encodings are currently never freed, the allocations done 5033da084b3Smrg by this function are mostly its private business. Note, however, 5043da084b3Smrg that FontEncIdentify needs to free the header fields -- so if you 5053da084b3Smrg change this function, you may need to change FontEncIdentify. */ 5063da084b3Smrg 5073da084b3Smrg/* I want a garbage collector. */ 5083da084b3Smrg 5093da084b3Smrgstatic FontEncPtr 5103da084b3SmrgparseEncodingFile(FontFilePtr f, int headerOnly) 5113da084b3Smrg{ 5123da084b3Smrg int line; 5133da084b3Smrg 514e1c0d025Smrg unsigned short *enc = NULL; 5153da084b3Smrg char **nam = NULL, **newnam; 516e1c0d025Smrg unsigned i, first = 0xFFFF, last = 0, encsize = 0, namsize = 0; 5173da084b3Smrg FontEncPtr encoding = NULL; 5183da084b3Smrg FontMapPtr mapping = NULL; 5193da084b3Smrg FontEncSimpleMapPtr sm; 5203da084b3Smrg FontEncSimpleNamePtr sn; 521e1c0d025Smrg char *aliases[MAXALIASES] = { NULL }; 522e1c0d025Smrg int numaliases = 0; 5233da084b3Smrg 5243da084b3Smrg#if 0 5253da084b3Smrg /* GCC complains about unused labels. Please fix GCC rather than 5263da084b3Smrg obfuscating my code. */ 527e1c0d025Smrg no_encoding: 5283da084b3Smrg#endif 5293da084b3Smrg line = getnextline(f); 530e1c0d025Smrg switch (line) { 5313da084b3Smrg case EOF_LINE: 5323da084b3Smrg goto error; 5333da084b3Smrg case STARTENCODING_LINE: 53455acc8fcSmrg encoding = malloc(sizeof(FontEncRec)); 535e1c0d025Smrg if (encoding == NULL) 5363da084b3Smrg goto error; 53755acc8fcSmrg encoding->name = strdup(keyword_value); 538e1c0d025Smrg if (encoding->name == NULL) 5393da084b3Smrg goto error; 5403da084b3Smrg encoding->size = 256; 5413da084b3Smrg encoding->row_size = 0; 5423da084b3Smrg encoding->mappings = NULL; 5433da084b3Smrg encoding->next = NULL; 544e1c0d025Smrg encoding->first = encoding->first_col = 0; 5453da084b3Smrg goto no_mapping; 5463da084b3Smrg default: 5473da084b3Smrg goto error; 5483da084b3Smrg } 5493da084b3Smrg 550e1c0d025Smrg no_mapping: 5513da084b3Smrg line = getnextline(f); 552e1c0d025Smrg switch (line) { 553e1c0d025Smrg case EOF_LINE: 554e1c0d025Smrg goto done; 5553da084b3Smrg case ALIAS_LINE: 556e1c0d025Smrg if (numaliases < MAXALIASES) { 55755acc8fcSmrg aliases[numaliases] = strdup(keyword_value); 558e1c0d025Smrg if (aliases[numaliases] == NULL) 5593da084b3Smrg goto error; 5603da084b3Smrg numaliases++; 5613da084b3Smrg } 5623da084b3Smrg goto no_mapping; 5633da084b3Smrg case SIZE_LINE: 5643da084b3Smrg encoding->size = value1; 5653da084b3Smrg encoding->row_size = value2; 5663da084b3Smrg goto no_mapping; 5673da084b3Smrg case FIRSTINDEX_LINE: 5683da084b3Smrg encoding->first = value1; 5693da084b3Smrg encoding->first_col = value2; 5703da084b3Smrg goto no_mapping; 5713da084b3Smrg case STARTMAPPING_LINE: 572e1c0d025Smrg if (headerOnly) 5733da084b3Smrg goto done; 574e1c0d025Smrg if (!strcasecmp(keyword_value, "unicode")) { 57555acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 576e1c0d025Smrg if (mapping == NULL) 5773da084b3Smrg goto error; 5783da084b3Smrg mapping->type = FONT_ENCODING_UNICODE; 5793da084b3Smrg mapping->pid = 0; 5803da084b3Smrg mapping->eid = 0; 5813da084b3Smrg mapping->recode = NULL; 5823da084b3Smrg mapping->name = NULL; 5833da084b3Smrg mapping->client_data = NULL; 5843da084b3Smrg mapping->next = NULL; 5853da084b3Smrg goto mapping; 586e1c0d025Smrg } 587e1c0d025Smrg else if (!strcasecmp(keyword_value, "cmap")) { 58855acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 589e1c0d025Smrg if (mapping == NULL) 5903da084b3Smrg goto error; 5913da084b3Smrg mapping->type = FONT_ENCODING_TRUETYPE; 5923da084b3Smrg mapping->pid = value1; 5933da084b3Smrg mapping->eid = value2; 5943da084b3Smrg mapping->recode = NULL; 5953da084b3Smrg mapping->name = NULL; 5963da084b3Smrg mapping->client_data = NULL; 5973da084b3Smrg mapping->next = NULL; 5983da084b3Smrg goto mapping; 599e1c0d025Smrg } 600e1c0d025Smrg else if (!strcasecmp(keyword_value, "postscript")) { 60155acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 602e1c0d025Smrg if (mapping == NULL) 6033da084b3Smrg goto error; 6043da084b3Smrg mapping->type = FONT_ENCODING_POSTSCRIPT; 6053da084b3Smrg mapping->pid = 0; 6063da084b3Smrg mapping->eid = 0; 6073da084b3Smrg mapping->recode = NULL; 6083da084b3Smrg mapping->name = NULL; 6093da084b3Smrg mapping->client_data = NULL; 6103da084b3Smrg mapping->next = NULL; 6113da084b3Smrg goto string_mapping; 612e1c0d025Smrg } 613e1c0d025Smrg else { /* unknown mapping type -- ignore */ 6143da084b3Smrg goto skipmapping; 6153da084b3Smrg } 6163da084b3Smrg /* NOTREACHED */ 6173da084b3Smrg goto error; 618e1c0d025Smrg default: 619e1c0d025Smrg goto no_mapping; /* ignore unknown lines */ 6203da084b3Smrg } 6213da084b3Smrg 622e1c0d025Smrg skipmapping: 6233da084b3Smrg line = getnextline(f); 624e1c0d025Smrg switch (line) { 6253da084b3Smrg case ENDMAPPING_LINE: 6263da084b3Smrg goto no_mapping; 6273da084b3Smrg case EOF_LINE: 6283da084b3Smrg goto error; 6293da084b3Smrg default: 6303da084b3Smrg goto skipmapping; 6313da084b3Smrg } 6323da084b3Smrg 633e1c0d025Smrg mapping: 6343da084b3Smrg line = getnextline(f); 635e1c0d025Smrg switch (line) { 636e1c0d025Smrg case EOF_LINE: 637e1c0d025Smrg goto error; 6383da084b3Smrg case ENDMAPPING_LINE: 6393da084b3Smrg mapping->recode = FontEncSimpleRecode; 6403da084b3Smrg mapping->name = FontEncUndefinedName; 64155acc8fcSmrg mapping->client_data = sm = malloc(sizeof(FontEncSimpleMapRec)); 642e1c0d025Smrg if (sm == NULL) 6433da084b3Smrg goto error; 6443da084b3Smrg sm->row_size = encoding->row_size; 645e1c0d025Smrg if (first <= last) { 6463da084b3Smrg unsigned short *newmap; 6473da084b3Smrg 6483da084b3Smrg sm->first = first; 649e1c0d025Smrg sm->len = last - first + 1; 6502a53b785Smrg newmap = Xmallocarray(sm->len, sizeof(unsigned short)); 651e1c0d025Smrg if (newmap == NULL) { 65255acc8fcSmrg free(sm); 6533da084b3Smrg mapping->client_data = sm = NULL; 6543da084b3Smrg goto error; 6553da084b3Smrg } 656e1c0d025Smrg for (i = 0; i < sm->len; i++) 657e1c0d025Smrg newmap[i] = enc[first + i]; 658e1c0d025Smrg sm->map = newmap; 659e1c0d025Smrg } 660e1c0d025Smrg else { 6613da084b3Smrg sm->first = 0; 6623da084b3Smrg sm->len = 0; 6633da084b3Smrg sm->map = NULL; 6643da084b3Smrg } 6653da084b3Smrg install_mapping(encoding, mapping); 6663da084b3Smrg mapping = NULL; 667e1c0d025Smrg first = 0xFFFF; 668e1c0d025Smrg last = 0; 6693da084b3Smrg goto no_mapping; 6703da084b3Smrg 6713da084b3Smrg case CODE_LINE: 672e1c0d025Smrg if (setCode(value1, value2, encoding->row_size, 673e1c0d025Smrg &first, &last, &encsize, &enc)) 6743da084b3Smrg goto error; 6753da084b3Smrg goto mapping; 6763da084b3Smrg 6773da084b3Smrg case CODE_RANGE_LINE: 678e1c0d025Smrg if (value1 > 0x10000) 6793da084b3Smrg value1 = 0x10000; 680e1c0d025Smrg if (value2 > 0x10000) 6813da084b3Smrg value2 = 0x10000; 682e1c0d025Smrg if (value2 < value1) 6833da084b3Smrg goto mapping; 6843da084b3Smrg /* Do the last value first to avoid having to realloc() */ 685e1c0d025Smrg if (setCode(value2, value3 + (value2 - value1), encoding->row_size, 686e1c0d025Smrg &first, &last, &encsize, &enc)) 6873da084b3Smrg goto error; 688e1c0d025Smrg for (i = value1; i < value2; i++) { 689e1c0d025Smrg if (setCode(i, value3 + (i - value1), encoding->row_size, 690e1c0d025Smrg &first, &last, &encsize, &enc)) 6913da084b3Smrg goto error; 6923da084b3Smrg } 6933da084b3Smrg goto mapping; 69448c85eb7Smrg 6953da084b3Smrg case CODE_UNDEFINE_LINE: 696e1c0d025Smrg if (value1 > 0x10000) 6973da084b3Smrg value1 = 0x10000; 698e1c0d025Smrg if (value2 > 0x10000) 6993da084b3Smrg value2 = 0x10000; 700e1c0d025Smrg if (value2 < value1) 7013da084b3Smrg goto mapping; 7023da084b3Smrg /* Do the last value first to avoid having to realloc() */ 703e1c0d025Smrg if (setCode(value2, 0, encoding->row_size, 704e1c0d025Smrg &first, &last, &encsize, &enc)) 7053da084b3Smrg goto error; 706e1c0d025Smrg for (i = value1; i < value2; i++) { 707e1c0d025Smrg if (setCode(i, 0, encoding->row_size, 708e1c0d025Smrg &first, &last, &encsize, &enc)) 7093da084b3Smrg goto error; 7103da084b3Smrg } 7113da084b3Smrg goto mapping; 7123da084b3Smrg 713e1c0d025Smrg default: 714e1c0d025Smrg goto mapping; /* ignore unknown lines */ 7153da084b3Smrg } 71648c85eb7Smrg 717e1c0d025Smrg string_mapping: 7183da084b3Smrg line = getnextline(f); 719e1c0d025Smrg switch (line) { 720e1c0d025Smrg case EOF_LINE: 721e1c0d025Smrg goto error; 7223da084b3Smrg case ENDMAPPING_LINE: 7233da084b3Smrg mapping->recode = FontEncUndefinedRecode; 7243da084b3Smrg mapping->name = FontEncSimpleName; 72555acc8fcSmrg mapping->client_data = sn = malloc(sizeof(FontEncSimpleNameRec)); 726e1c0d025Smrg if (sn == NULL) 7273da084b3Smrg goto error; 728e1c0d025Smrg if (first > last) { 72955acc8fcSmrg free(sn); 7303da084b3Smrg mapping->client_data = sn = NULL; 7313da084b3Smrg goto error; 7323da084b3Smrg } 7333da084b3Smrg sn->first = first; 7343da084b3Smrg sn->len = last - first + 1; 7352a53b785Smrg sn->map = Xmallocarray(sn->len, sizeof(char *)); 736e1c0d025Smrg if (sn->map == NULL) { 73755acc8fcSmrg free(sn); 7383da084b3Smrg mapping->client_data = sn = NULL; 7393da084b3Smrg goto error; 7403da084b3Smrg } 741e1c0d025Smrg for (i = 0; i < sn->len; i++) 742e1c0d025Smrg sn->map[i] = nam[first + i]; 743e1c0d025Smrg install_mapping(encoding, mapping); 7443da084b3Smrg mapping = NULL; 745e1c0d025Smrg first = 0xFFFF; 746e1c0d025Smrg last = 0; 7473da084b3Smrg goto no_mapping; 7483da084b3Smrg case NAME_LINE: 749e1c0d025Smrg if (value1 >= 0x10000) 750e1c0d025Smrg goto string_mapping; 751e1c0d025Smrg if (namsize == 0) { 7523da084b3Smrg namsize = (value1) < 256 ? 256 : 0x10000; 7532a53b785Smrg nam = Xmallocarray(namsize, sizeof(char *)); 754e1c0d025Smrg if (nam == NULL) { 755e1c0d025Smrg namsize = 0; 7563da084b3Smrg goto error; 7573da084b3Smrg } 758e1c0d025Smrg } 759e1c0d025Smrg else if (namsize <= value1) { 7603da084b3Smrg namsize = 0x10000; 761e1c0d025Smrg if ((newnam = (char **) realloc(nam, namsize)) == NULL) 7623da084b3Smrg goto error; 7633da084b3Smrg nam = newnam; 7643da084b3Smrg } 765e1c0d025Smrg if (first > last) { 7663da084b3Smrg first = last = value1; 7673da084b3Smrg } 768e1c0d025Smrg if (value1 < first) { 769e1c0d025Smrg for (i = value1; i < first; i++) 7703da084b3Smrg nam[i] = NULL; 7713da084b3Smrg first = value1; 7723da084b3Smrg } 773e1c0d025Smrg if (value1 > last) { 774e1c0d025Smrg for (i = last + 1; i <= value1; i++) 775e1c0d025Smrg nam[i] = NULL; 7763da084b3Smrg last = value1; 7773da084b3Smrg } 77855acc8fcSmrg nam[value1] = strdup(keyword_value); 779e1c0d025Smrg if (nam[value1] == NULL) { 7803da084b3Smrg goto error; 7813da084b3Smrg } 7823da084b3Smrg goto string_mapping; 7833da084b3Smrg 784e1c0d025Smrg default: 785e1c0d025Smrg goto string_mapping; /* ignore unknown lines */ 7863da084b3Smrg } 7873da084b3Smrg 788e1c0d025Smrg done: 789e1c0d025Smrg if (encsize) { 790e1c0d025Smrg free(enc); 791e1c0d025Smrg encsize = 0; 792e1c0d025Smrg enc = NULL; 793e1c0d025Smrg } 794e1c0d025Smrg if (namsize) { 795e1c0d025Smrg free(nam); /* don't free entries! */ 796e1c0d025Smrg namsize = 0; 797e1c0d025Smrg nam = NULL; 798e1c0d025Smrg } 7993da084b3Smrg 800e1c0d025Smrg encoding->aliases = NULL; 801e1c0d025Smrg if (numaliases) { 8022a53b785Smrg encoding->aliases = Xmallocarray(numaliases + 1, sizeof(char *)); 803e1c0d025Smrg if (encoding->aliases == NULL) 8043da084b3Smrg goto error; 805e1c0d025Smrg for (i = 0; i < numaliases; i++) 8063da084b3Smrg encoding->aliases[i] = aliases[i]; 807e1c0d025Smrg encoding->aliases[numaliases] = NULL; 8083da084b3Smrg } 8093da084b3Smrg 8103da084b3Smrg return encoding; 8113da084b3Smrg 812e1c0d025Smrg error: 813e1c0d025Smrg if (encsize) { 814e1c0d025Smrg free(enc); 815e1c0d025Smrg encsize = 0; 816e1c0d025Smrg } 817e1c0d025Smrg if (namsize) { 818e1c0d025Smrg for (i = first; i <= last; i++) 81955acc8fcSmrg free(nam[i]); 82055acc8fcSmrg free(nam); 8213da084b3Smrg } 822e1c0d025Smrg if (mapping) { 82355acc8fcSmrg free(mapping->client_data); 82455acc8fcSmrg free(mapping); 8253da084b3Smrg } 826e1c0d025Smrg if (encoding) { 827e1c0d025Smrg FontMapPtr nextmap; 828e1c0d025Smrg 829e1c0d025Smrg free(encoding->name); 830e1c0d025Smrg for (mapping = encoding->mappings; mapping; mapping = nextmap) { 831e1c0d025Smrg free(mapping->client_data); 832e1c0d025Smrg nextmap = mapping->next; 833e1c0d025Smrg free(mapping); 834e1c0d025Smrg } 835e1c0d025Smrg free(encoding); 836e1c0d025Smrg } 837e1c0d025Smrg for (i = 0; i < numaliases; i++) 83855acc8fcSmrg free(aliases[i]); 839e1c0d025Smrg /* We don't need to free sn and sm as they handled locally in the body. */ 8403da084b3Smrg return NULL; 8413da084b3Smrg} 8423da084b3Smrg 84352fd71cdSmrgconst char * 8443da084b3SmrgFontEncDirectory(void) 8453da084b3Smrg{ 84652fd71cdSmrg static const char *dir = NULL; 8473da084b3Smrg 848e1c0d025Smrg if (dir == NULL) { 84952fd71cdSmrg const char *c = getenv("FONT_ENCODINGS_DIRECTORY"); 850e1c0d025Smrg 851e1c0d025Smrg if (c) { 85255acc8fcSmrg dir = strdup(c); 853e1c0d025Smrg if (!dir) 8543da084b3Smrg return NULL; 855e1c0d025Smrg } 856e1c0d025Smrg else { 8573da084b3Smrg dir = FONT_ENCODINGS_DIRECTORY; 8583da084b3Smrg } 8593da084b3Smrg } 8603da084b3Smrg return dir; 8613da084b3Smrg} 8623da084b3Smrg 8633da084b3Smrgstatic void 8643da084b3SmrgparseFontFileName(const char *fontFileName, char *buf, char *dir) 8653da084b3Smrg{ 8663da084b3Smrg const char *p; 8673da084b3Smrg char *q, *lastslash; 86848c85eb7Smrg 869e1c0d025Smrg for (p = fontFileName, q = dir, lastslash = NULL; *p; p++, q++) { 8703da084b3Smrg *q = *p; 871e1c0d025Smrg if (*p == '/') 872e1c0d025Smrg lastslash = q + 1; 8733da084b3Smrg } 87448c85eb7Smrg 875e1c0d025Smrg if (!lastslash) 8763da084b3Smrg lastslash = dir; 87748c85eb7Smrg 8783da084b3Smrg *lastslash = '\0'; 8793da084b3Smrg 880e1c0d025Smrg if (buf && strlen(dir) + 14 < MAXFONTFILENAMELEN) { 881e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, "encodings.dir"); 8823da084b3Smrg } 8833da084b3Smrg} 8843da084b3Smrg 8853da084b3Smrgstatic FontEncPtr 88648c85eb7SmrgFontEncReallyReallyLoad(const char *charset, 8873da084b3Smrg const char *dirname, const char *dir) 8883da084b3Smrg{ 8893da084b3Smrg FontFilePtr f; 8903da084b3Smrg FILE *file; 8913da084b3Smrg FontEncPtr encoding; 8923da084b3Smrg char file_name[MAXFONTFILENAMELEN], encoding_name[MAXFONTNAMELEN], 8933da084b3Smrg buf[MAXFONTFILENAMELEN]; 8943da084b3Smrg int count, n; 8953da084b3Smrg static char format[24] = ""; 89648c85eb7Smrg 8973da084b3Smrg /* As we don't really expect to open encodings that often, we don't 8983da084b3Smrg take the trouble of caching encodings directories. */ 8993da084b3Smrg 900da2777aaSmrg if ((file = fopen(dirname, "r" FOPEN_CLOEXEC)) == NULL) { 9013da084b3Smrg return NULL; 9023da084b3Smrg } 90348c85eb7Smrg 9043da084b3Smrg count = fscanf(file, "%d\n", &n); 905e1c0d025Smrg if (count == EOF || count != 1) { 9063da084b3Smrg fclose(file); 9073da084b3Smrg return NULL; 9083da084b3Smrg } 9093da084b3Smrg 9103da084b3Smrg encoding = NULL; 9113da084b3Smrg if (!format[0]) { 912e1c0d025Smrg snprintf(format, sizeof(format), "%%%ds %%%d[^\n]\n", 913e1c0d025Smrg (int) sizeof(encoding_name) - 1, (int) sizeof(file_name) - 1); 9143da084b3Smrg } 915e1c0d025Smrg for (;;) { 9163da084b3Smrg count = fscanf(file, format, encoding_name, file_name); 917e1c0d025Smrg if (count == EOF) 9183da084b3Smrg break; 919e1c0d025Smrg if (count != 2) 9203da084b3Smrg break; 9213da084b3Smrg 922e1c0d025Smrg if (!strcasecmp(encoding_name, charset)) { 9233da084b3Smrg /* Found it */ 924e1c0d025Smrg if (file_name[0] != '/') { 925e1c0d025Smrg if (strlen(dir) + strlen(file_name) >= MAXFONTFILENAMELEN) { 926e1c0d025Smrg fclose(file); 9273da084b3Smrg return NULL; 928e1c0d025Smrg } 929e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, file_name); 930e1c0d025Smrg } 931e1c0d025Smrg else { 932e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s", file_name); 9333da084b3Smrg } 9343da084b3Smrg 9353da084b3Smrg f = FontFileOpen(buf); 936e1c0d025Smrg if (f == NULL) { 937e1c0d025Smrg fclose(file); 9383da084b3Smrg return NULL; 9393da084b3Smrg } 9403da084b3Smrg encoding = parseEncodingFile(f, 0); 9413da084b3Smrg FontFileClose(f); 9423da084b3Smrg break; 9433da084b3Smrg } 9443da084b3Smrg } 9453da084b3Smrg 9463da084b3Smrg fclose(file); 9473da084b3Smrg 9483da084b3Smrg return encoding; 9493da084b3Smrg} 9503da084b3Smrg 95148c85eb7Smrg/* Parser ntrypoint -- used by FontEncLoad */ 9523da084b3SmrgFontEncPtr 9533da084b3SmrgFontEncReallyLoad(const char *charset, const char *fontFileName) 9543da084b3Smrg{ 9553da084b3Smrg FontEncPtr encoding; 9563da084b3Smrg char dir[MAXFONTFILENAMELEN], dirname[MAXFONTFILENAMELEN]; 95752fd71cdSmrg const char *d; 9583da084b3Smrg 959e1c0d025Smrg if (fontFileName) { 9603da084b3Smrg parseFontFileName(fontFileName, dirname, dir); 9613da084b3Smrg encoding = FontEncReallyReallyLoad(charset, dirname, dir); 962e1c0d025Smrg if (encoding) 963e1c0d025Smrg return (encoding); 9643da084b3Smrg } 96548c85eb7Smrg 9663da084b3Smrg d = FontEncDirectory(); 967e1c0d025Smrg if (d) { 9683da084b3Smrg parseFontFileName(d, NULL, dir); 9693da084b3Smrg encoding = FontEncReallyReallyLoad(charset, d, dir); 9703da084b3Smrg return encoding; 9713da084b3Smrg } 97248c85eb7Smrg 9733da084b3Smrg return NULL; 9743da084b3Smrg} 9753da084b3Smrg 9763da084b3Smrg/* Return a NULL-terminated array of encoding names. Note that this 9773da084b3Smrg * function has incestuous knowledge of the allocations done by 9783da084b3Smrg * parseEncodingFile. */ 9793da084b3Smrg 9803da084b3Smrgchar ** 9813da084b3SmrgFontEncIdentify(const char *fileName) 9823da084b3Smrg{ 9833da084b3Smrg FontFilePtr f; 9843da084b3Smrg FontEncPtr encoding; 9853da084b3Smrg char **names, **name, **alias; 9863da084b3Smrg int numaliases; 98748c85eb7Smrg 988e1c0d025Smrg if ((f = FontFileOpen(fileName)) == NULL) { 9893da084b3Smrg return NULL; 9903da084b3Smrg } 9913da084b3Smrg encoding = parseEncodingFile(f, 1); 9923da084b3Smrg FontFileClose(f); 9933da084b3Smrg 994e1c0d025Smrg if (!encoding) 9953da084b3Smrg return NULL; 9963da084b3Smrg 9973da084b3Smrg numaliases = 0; 998e1c0d025Smrg if (encoding->aliases) 999e1c0d025Smrg for (alias = encoding->aliases; *alias; alias++) 10003da084b3Smrg numaliases++; 10013da084b3Smrg 10022a53b785Smrg names = Xmallocarray(numaliases + 2, sizeof(char *)); 1003e1c0d025Smrg if (names == NULL) { 100455acc8fcSmrg free(encoding->aliases); 100555acc8fcSmrg free(encoding); 10063da084b3Smrg return NULL; 10073da084b3Smrg } 10083da084b3Smrg 10093da084b3Smrg name = names; 10103da084b3Smrg *(name++) = encoding->name; 1011e1c0d025Smrg if (numaliases > 0) 1012e1c0d025Smrg for (alias = encoding->aliases; *alias; alias++, name++) 1013e1c0d025Smrg *name = *alias; 10143da084b3Smrg 10153da084b3Smrg *name = NULL; 101655acc8fcSmrg free(encoding->aliases); 101755acc8fcSmrg free(encoding); 10183da084b3Smrg 10193da084b3Smrg return names; 10203da084b3Smrg} 1021