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