encparse.c revision e1c0d025
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
303da084b3Smrg#include <string.h>
313da084b3Smrg#include <strings.h>
3248c85eb7Smrg#include <stdio.h>
333da084b3Smrg
343da084b3Smrg#include <stdlib.h>
353da084b3Smrg
363da084b3Smrg#include "zlib.h"
373da084b3Smrgtypedef gzFile FontFilePtr;
38e1c0d025Smrg
393da084b3Smrg#define FontFileGetc(f) gzgetc(f)
403da084b3Smrg#define FontFileOpen(filename) gzopen(filename, "rb")
413da084b3Smrg#define FontFileClose(f) gzclose(f)
423da084b3Smrg
433da084b3Smrg#define MAXFONTFILENAMELEN 1024
443da084b3Smrg#define MAXFONTNAMELEN 1024
453da084b3Smrg
463da084b3Smrg#include <X11/fonts/fontenc.h>
473da084b3Smrg#include "fontencI.h"
483da084b3Smrg
493da084b3Smrg#define MAXALIASES 20
503da084b3Smrg
513da084b3Smrg#define EOF_TOKEN -1
523da084b3Smrg#define ERROR_TOKEN -2
533da084b3Smrg#define EOL_TOKEN 0
543da084b3Smrg#define NUMBER_TOKEN 1
553da084b3Smrg#define KEYWORD_TOKEN 2
563da084b3Smrg
573da084b3Smrg#define EOF_LINE -1
583da084b3Smrg#define ERROR_LINE -2
593da084b3Smrg#define STARTENCODING_LINE 1
603da084b3Smrg#define STARTMAPPING_LINE 2
613da084b3Smrg#define ENDMAPPING_LINE 3
623da084b3Smrg#define CODE_LINE 4
633da084b3Smrg#define CODE_RANGE_LINE 5
643da084b3Smrg#define CODE_UNDEFINE_LINE 6
653da084b3Smrg#define NAME_LINE 7
663da084b3Smrg#define SIZE_LINE 8
673da084b3Smrg#define ALIAS_LINE 9
683da084b3Smrg#define FIRSTINDEX_LINE 10
693da084b3Smrg
703da084b3Smrg/* Return from lexer */
713da084b3Smrg#define MAXKEYWORDLEN 100
723da084b3Smrg
733da084b3Smrgstatic long number_value;
74e1c0d025Smrgstatic char keyword_value[MAXKEYWORDLEN + 1];
753da084b3Smrg
763da084b3Smrgstatic long value1, value2, value3;
773da084b3Smrg
783da084b3Smrg/* Lexer code */
793da084b3Smrg
803da084b3Smrg/* Skip to the beginning of new line */
813da084b3Smrgstatic void
823da084b3SmrgskipEndOfLine(FontFilePtr f, int c)
833da084b3Smrg{
84e1c0d025Smrg    if (c == 0)
853da084b3Smrg        c = FontFileGetc(f);
8648c85eb7Smrg
87e1c0d025Smrg    for (;;)
88e1c0d025Smrg        if (c <= 0 || c == '\n')
893da084b3Smrg            return;
903da084b3Smrg        else
913da084b3Smrg            c = FontFileGetc(f);
923da084b3Smrg}
933da084b3Smrg
943da084b3Smrg/* Get a number; we're at the first digit. */
953da084b3Smrgstatic unsigned
963da084b3Smrggetnum(FontFilePtr f, int c, int *cp)
973da084b3Smrg{
983da084b3Smrg    unsigned n = 0;
993da084b3Smrg    int base = 10;
1003da084b3Smrg
1013da084b3Smrg    /* look for `0' or `0x' prefix */
102e1c0d025Smrg    if (c == '0') {
1033da084b3Smrg        c = FontFileGetc(f);
1043da084b3Smrg        base = 8;
105e1c0d025Smrg        if (c == 'x' || c == 'X') {
1063da084b3Smrg            base = 16;
1073da084b3Smrg            c = FontFileGetc(f);
1083da084b3Smrg        }
1093da084b3Smrg    }
1103da084b3Smrg
1113da084b3Smrg    /* accumulate digits */
112e1c0d025Smrg    for (;;) {
1133da084b3Smrg        if ('0' <= c && c <= '9') {
114e1c0d025Smrg            n *= base;
115e1c0d025Smrg            n += c - '0';
116e1c0d025Smrg        }
117e1c0d025Smrg        else if ('a' <= c && c <= 'f') {
118e1c0d025Smrg            n *= base;
119e1c0d025Smrg            n += c - 'a' + 10;
120e1c0d025Smrg        }
121e1c0d025Smrg        else if ('A' <= c && c <= 'F') {
122e1c0d025Smrg            n *= base;
123e1c0d025Smrg            n += c - 'A' + 10;
124e1c0d025Smrg        }
125e1c0d025Smrg        else
1263da084b3Smrg            break;
1273da084b3Smrg        c = FontFileGetc(f);
1283da084b3Smrg    }
1293da084b3Smrg
130e1c0d025Smrg    *cp = c;
131e1c0d025Smrg    return n;
1323da084b3Smrg}
13348c85eb7Smrg
1343da084b3Smrg/* Skip to beginning of new line; return 1 if only whitespace was found. */
1353da084b3Smrgstatic int
1363da084b3SmrgendOfLine(FontFilePtr f, int c)
1373da084b3Smrg{
138e1c0d025Smrg    if (c == 0)
1393da084b3Smrg        c = FontFileGetc(f);
1403da084b3Smrg
141e1c0d025Smrg    for (;;) {
142e1c0d025Smrg        if (c <= 0 || c == '\n')
1433da084b3Smrg            return 1;
144e1c0d025Smrg        else if (c == '#') {
145e1c0d025Smrg            skipEndOfLine(f, c);
1463da084b3Smrg            return 1;
1473da084b3Smrg        }
148e1c0d025Smrg        else if (c == ' ' || c == '\t') {
149e1c0d025Smrg            skipEndOfLine(f, c);
1503da084b3Smrg            return 0;
1513da084b3Smrg        }
1523da084b3Smrg        c = FontFileGetc(f);
1533da084b3Smrg    }
1543da084b3Smrg}
1553da084b3Smrg
1563da084b3Smrg/* Get a token; we're at first char */
1573da084b3Smrgstatic int
1583da084b3Smrggettoken(FontFilePtr f, int c, int *cp)
1593da084b3Smrg{
1603da084b3Smrg    char *p;
1613da084b3Smrg
162e1c0d025Smrg    if (c <= 0)
163e1c0d025Smrg        c = FontFileGetc(f);
1643da084b3Smrg
165e1c0d025Smrg    if (c <= 0) {
1663da084b3Smrg        return EOF_TOKEN;
1673da084b3Smrg    }
1683da084b3Smrg
169e1c0d025Smrg    while (c == ' ' || c == '\t')
1703da084b3Smrg        c = FontFileGetc(f);
1713da084b3Smrg
172e1c0d025Smrg    if (c == '\n') {
1733da084b3Smrg        return EOL_TOKEN;
174e1c0d025Smrg    }
175e1c0d025Smrg    else if (c == '#') {
176e1c0d025Smrg        skipEndOfLine(f, c);
1773da084b3Smrg        return EOL_TOKEN;
178e1c0d025Smrg    }
179e1c0d025Smrg    else if (c >= '0' && c <= '9') {
180e1c0d025Smrg        number_value = getnum(f, c, cp);
1813da084b3Smrg        return NUMBER_TOKEN;
182e1c0d025Smrg    }
183e1c0d025Smrg    else if ((c >= 'A' && c <= 'Z') ||
184e1c0d025Smrg             (c >= 'a' && c <= 'z') ||
185e1c0d025Smrg             c == '/' || c == '_' || c == '-' || c == '.') {
1863da084b3Smrg        p = keyword_value;
1873da084b3Smrg        *p++ = c;
188e1c0d025Smrg        while (p - keyword_value < MAXKEYWORDLEN) {
1893da084b3Smrg            c = FontFileGetc(f);
190e1c0d025Smrg            if (c <= ' ' || c > '~' || c == '#')
1913da084b3Smrg                break;
1923da084b3Smrg            *p++ = c;
1933da084b3Smrg        }
1943da084b3Smrg        *cp = c;
1953da084b3Smrg        *p = '\0';
1963da084b3Smrg        return KEYWORD_TOKEN;
197e1c0d025Smrg    }
198e1c0d025Smrg    else {
1993da084b3Smrg        *cp = c;
2003da084b3Smrg        return ERROR_TOKEN;
2013da084b3Smrg    }
2023da084b3Smrg}
2033da084b3Smrg
2043da084b3Smrg/* Parse a line.
2053da084b3Smrg * Always skips to the beginning of a new line, even if an error occurs */
2063da084b3Smrgstatic int
2073da084b3Smrggetnextline(FontFilePtr f)
2083da084b3Smrg{
2093da084b3Smrg    int c, token;
210e1c0d025Smrg
2113da084b3Smrg    c = FontFileGetc(f);
212e1c0d025Smrg    if (c <= 0)
2133da084b3Smrg        return EOF_LINE;
2143da084b3Smrg
215e1c0d025Smrg again:
216e1c0d025Smrg    token = gettoken(f, c, &c);
2173da084b3Smrg
218e1c0d025Smrg    switch (token) {
2193da084b3Smrg    case EOF_TOKEN:
2203da084b3Smrg        return EOF_LINE;
2213da084b3Smrg    case EOL_TOKEN:
2223da084b3Smrg        /* empty line */
2233da084b3Smrg        c = FontFileGetc(f);
2243da084b3Smrg        goto again;
2253da084b3Smrg    case NUMBER_TOKEN:
2263da084b3Smrg        value1 = number_value;
227e1c0d025Smrg        token = gettoken(f, c, &c);
228e1c0d025Smrg        switch (token) {
2293da084b3Smrg        case NUMBER_TOKEN:
2303da084b3Smrg            value2 = number_value;
231e1c0d025Smrg            token = gettoken(f, c, &c);
232e1c0d025Smrg            switch (token) {
2333da084b3Smrg            case NUMBER_TOKEN:
2343da084b3Smrg                value3 = number_value;
2353da084b3Smrg                return CODE_RANGE_LINE;
2363da084b3Smrg            case EOL_TOKEN:
2373da084b3Smrg                return CODE_LINE;
2383da084b3Smrg            default:
239e1c0d025Smrg                skipEndOfLine(f, c);
2403da084b3Smrg                return ERROR_LINE;
2413da084b3Smrg            }
2423da084b3Smrg        case KEYWORD_TOKEN:
243e1c0d025Smrg            if (!endOfLine(f, c))
2443da084b3Smrg                return ERROR_LINE;
2453da084b3Smrg            else
2463da084b3Smrg                return NAME_LINE;
2473da084b3Smrg        default:
248e1c0d025Smrg            skipEndOfLine(f, c);
2493da084b3Smrg            return ERROR_LINE;
2503da084b3Smrg        }
2513da084b3Smrg    case KEYWORD_TOKEN:
252e1c0d025Smrg        if (!strcasecmp(keyword_value, "STARTENCODING")) {
253e1c0d025Smrg            token = gettoken(f, c, &c);
254e1c0d025Smrg            if (token == KEYWORD_TOKEN) {
255e1c0d025Smrg                if (endOfLine(f, c))
2563da084b3Smrg                    return STARTENCODING_LINE;
2573da084b3Smrg                else
2583da084b3Smrg                    return ERROR_LINE;
259e1c0d025Smrg            }
260e1c0d025Smrg            else {
261e1c0d025Smrg                skipEndOfLine(f, c);
2623da084b3Smrg                return ERROR_LINE;
2633da084b3Smrg            }
264e1c0d025Smrg        }
265e1c0d025Smrg        else if (!strcasecmp(keyword_value, "ALIAS")) {
266e1c0d025Smrg            token = gettoken(f, c, &c);
267e1c0d025Smrg            if (token == KEYWORD_TOKEN) {
268e1c0d025Smrg                if (endOfLine(f, c))
2693da084b3Smrg                    return ALIAS_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, "SIZE")) {
279e1c0d025Smrg            token = gettoken(f, c, &c);
280e1c0d025Smrg            if (token == NUMBER_TOKEN) {
2813da084b3Smrg                value1 = number_value;
282e1c0d025Smrg                token = gettoken(f, c, &c);
283e1c0d025Smrg                switch (token) {
2843da084b3Smrg                case NUMBER_TOKEN:
2853da084b3Smrg                    value2 = number_value;
2863da084b3Smrg                    return SIZE_LINE;
2873da084b3Smrg                case EOL_TOKEN:
288e1c0d025Smrg                    value2 = 0;
2893da084b3Smrg                    return SIZE_LINE;
2903da084b3Smrg                default:
291e1c0d025Smrg                    skipEndOfLine(f, c);
2923da084b3Smrg                    return ERROR_LINE;
2933da084b3Smrg                }
294e1c0d025Smrg            }
295e1c0d025Smrg            else {
296e1c0d025Smrg                skipEndOfLine(f, c);
2973da084b3Smrg                return ERROR_LINE;
2983da084b3Smrg            }
299e1c0d025Smrg        }
300e1c0d025Smrg        else if (!strcasecmp(keyword_value, "FIRSTINDEX")) {
301e1c0d025Smrg            token = gettoken(f, c, &c);
302e1c0d025Smrg            if (token == NUMBER_TOKEN) {
3033da084b3Smrg                value1 = number_value;
304e1c0d025Smrg                token = gettoken(f, c, &c);
305e1c0d025Smrg                switch (token) {
3063da084b3Smrg                case NUMBER_TOKEN:
3073da084b3Smrg                    value2 = number_value;
3083da084b3Smrg                    return FIRSTINDEX_LINE;
3093da084b3Smrg                case EOL_TOKEN:
3103da084b3Smrg                    value2 = 0;
3113da084b3Smrg                    return FIRSTINDEX_LINE;
3123da084b3Smrg                default:
313e1c0d025Smrg                    skipEndOfLine(f, c);
3143da084b3Smrg                    return ERROR_LINE;
3153da084b3Smrg                }
316e1c0d025Smrg            }
317e1c0d025Smrg            else {
318e1c0d025Smrg                skipEndOfLine(f, c);
3193da084b3Smrg                return ERROR_LINE;
3203da084b3Smrg            }
321e1c0d025Smrg        }
322e1c0d025Smrg        else if (!strcasecmp(keyword_value, "STARTMAPPING")) {
3233da084b3Smrg            keyword_value[0] = 0;
324e1c0d025Smrg            value1 = 0;
325e1c0d025Smrg            value2 = 0;
3263da084b3Smrg            /* first a keyword */
327e1c0d025Smrg            token = gettoken(f, c, &c);
328e1c0d025Smrg            if (token != KEYWORD_TOKEN) {
3293da084b3Smrg                skipEndOfLine(f, c);
3303da084b3Smrg                return ERROR_LINE;
3313da084b3Smrg            }
3323da084b3Smrg
3333da084b3Smrg            /* optional first integer */
334e1c0d025Smrg            token = gettoken(f, c, &c);
335e1c0d025Smrg            if (token == NUMBER_TOKEN) {
3363da084b3Smrg                value1 = number_value;
337e1c0d025Smrg            }
338e1c0d025Smrg            else if (token == EOL_TOKEN) {
3393da084b3Smrg                return STARTMAPPING_LINE;
340e1c0d025Smrg            }
341e1c0d025Smrg            else {
3423da084b3Smrg                skipEndOfLine(f, c);
3433da084b3Smrg                return ERROR_LINE;
3443da084b3Smrg            }
3453da084b3Smrg
3463da084b3Smrg            /* optional second integer */
347e1c0d025Smrg            token = gettoken(f, c, &c);
348e1c0d025Smrg            if (token == NUMBER_TOKEN) {
3493da084b3Smrg                value2 = 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
359e1c0d025Smrg            if (!endOfLine(f, c))
3603da084b3Smrg                return ERROR_LINE;
3613da084b3Smrg            else {
3623da084b3Smrg                return STARTMAPPING_LINE;
3633da084b3Smrg            }
364e1c0d025Smrg        }
365e1c0d025Smrg        else if (!strcasecmp(keyword_value, "UNDEFINE")) {
3663da084b3Smrg            /* first integer */
367e1c0d025Smrg            token = gettoken(f, c, &c);
368e1c0d025Smrg            if (token != NUMBER_TOKEN) {
369e1c0d025Smrg                skipEndOfLine(f, c);
3703da084b3Smrg                return ERROR_LINE;
3713da084b3Smrg            }
3723da084b3Smrg            value1 = number_value;
3733da084b3Smrg            /* optional second integer */
374e1c0d025Smrg            token = gettoken(f, c, &c);
375e1c0d025Smrg            if (token == EOL_TOKEN) {
3763da084b3Smrg                value2 = value1;
3773da084b3Smrg                return CODE_UNDEFINE_LINE;
378e1c0d025Smrg            }
379e1c0d025Smrg            else if (token == NUMBER_TOKEN) {
3803da084b3Smrg                value2 = number_value;
381e1c0d025Smrg                if (endOfLine(f, c)) {
3823da084b3Smrg                    return CODE_UNDEFINE_LINE;
383e1c0d025Smrg                }
384e1c0d025Smrg                else
3853da084b3Smrg                    return ERROR_LINE;
386e1c0d025Smrg            }
387e1c0d025Smrg            else {
388e1c0d025Smrg                skipEndOfLine(f, c);
3893da084b3Smrg                return ERROR_LINE;
3903da084b3Smrg            }
391e1c0d025Smrg        }
392e1c0d025Smrg        else if (!strcasecmp(keyword_value, "ENDENCODING")) {
393e1c0d025Smrg            if (endOfLine(f, c))
3943da084b3Smrg                return EOF_LINE;
3953da084b3Smrg            else
3963da084b3Smrg                return ERROR_LINE;
397e1c0d025Smrg        }
398e1c0d025Smrg        else if (!strcasecmp(keyword_value, "ENDMAPPING")) {
399e1c0d025Smrg            if (endOfLine(f, c))
4003da084b3Smrg                return ENDMAPPING_LINE;
4013da084b3Smrg            else
4023da084b3Smrg                return ERROR_LINE;
403e1c0d025Smrg        }
404e1c0d025Smrg        else {
405e1c0d025Smrg            skipEndOfLine(f, c);
4063da084b3Smrg            return ERROR_LINE;
4073da084b3Smrg        }
4083da084b3Smrg    default:
4093da084b3Smrg        return ERROR_LINE;
4103da084b3Smrg    }
4113da084b3Smrg}
4123da084b3Smrg
41348c85eb7Smrgstatic void
4143da084b3Smrginstall_mapping(FontEncPtr encoding, FontMapPtr mapping)
4153da084b3Smrg{
4163da084b3Smrg    FontMapPtr m;
4173da084b3Smrg
418e1c0d025Smrg    if (encoding->mappings == NULL)
4193da084b3Smrg        encoding->mappings = mapping;
4203da084b3Smrg    else {
4213da084b3Smrg        m = encoding->mappings;
422e1c0d025Smrg        while (m->next != NULL)
4233da084b3Smrg            m = m->next;
4243da084b3Smrg        m->next = mapping;
4253da084b3Smrg    }
4263da084b3Smrg    mapping->next = NULL;
4273da084b3Smrg    mapping->encoding = encoding;
4283da084b3Smrg}
4293da084b3Smrg
4303da084b3Smrgstatic int
4313da084b3SmrgsetCode(unsigned from, unsigned to, unsigned row_size,
4323da084b3Smrg        unsigned *first, unsigned *last,
4333da084b3Smrg        unsigned *encsize, unsigned short **enc)
4343da084b3Smrg{
4353da084b3Smrg    unsigned index, i;
436e1c0d025Smrg
4373da084b3Smrg    unsigned short *newenc;
4383da084b3Smrg
439e1c0d025Smrg    if (from > 0xFFFF)
4403da084b3Smrg        return 0;               /* success */
4413da084b3Smrg
442e1c0d025Smrg    if (row_size == 0)
443e1c0d025Smrg        index = from;
4443da084b3Smrg    else {
445e1c0d025Smrg        if ((value1 & 0xFF) >= row_size)
4463da084b3Smrg            return 0;           /* ignore out of range mappings */
447e1c0d025Smrg        index = (from >> 8) * row_size + (from & 0xFF);
4483da084b3Smrg    }
4493da084b3Smrg
4503da084b3Smrg    /* Optimize away useless identity mappings.  This is only expected
4513da084b3Smrg       to be useful with linear encodings. */
452e1c0d025Smrg    if (index == to && (index < *first || index > *last))
4533da084b3Smrg        return 0;
454e1c0d025Smrg    if (*encsize == 0) {
4553da084b3Smrg        *encsize = (index < 256) ? 256 : 0x10000;
45655acc8fcSmrg        *enc = malloc((*encsize) * sizeof(unsigned short));
457e1c0d025Smrg        if (*enc == NULL) {
4583da084b3Smrg            *encsize = 0;
4593da084b3Smrg            return 1;
4603da084b3Smrg        }
461e1c0d025Smrg    }
462e1c0d025Smrg    else if (*encsize <= index) {
4633da084b3Smrg        *encsize = 0x10000;
464e1c0d025Smrg        if ((newenc =
465e1c0d025Smrg             realloc(*enc, (*encsize) * sizeof(unsigned short))) == NULL)
4663da084b3Smrg            return 1;
4673da084b3Smrg        *enc = newenc;
4683da084b3Smrg    }
469e1c0d025Smrg    if (*first > *last) {
4703da084b3Smrg        *first = *last = index;
4713da084b3Smrg    }
472e1c0d025Smrg    if (index < *first) {
473e1c0d025Smrg        for (i = index; i < *first; i++)
4743da084b3Smrg            (*enc)[i] = i;
4753da084b3Smrg        *first = index;
4763da084b3Smrg    }
477e1c0d025Smrg    if (index > *last) {
478e1c0d025Smrg        for (i = *last + 1; i <= index; i++)
4793da084b3Smrg            (*enc)[i] = i;
4803da084b3Smrg        *last = index;
4813da084b3Smrg    }
4823da084b3Smrg    (*enc)[index] = to;
4833da084b3Smrg    return 0;
4843da084b3Smrg}
4853da084b3Smrg
4863da084b3Smrg/* Parser.  If headerOnly is true, we're only interested in the
4873da084b3Smrg   data contained in the encoding file's header. */
4883da084b3Smrg
4893da084b3Smrg/* As font encodings are currently never freed, the allocations done
4903da084b3Smrg   by this function are mostly its private business.  Note, however,
4913da084b3Smrg   that FontEncIdentify needs to free the header fields -- so if you
4923da084b3Smrg   change this function, you may need to change FontEncIdentify. */
4933da084b3Smrg
4943da084b3Smrg/* I want a garbage collector. */
4953da084b3Smrg
4963da084b3Smrgstatic FontEncPtr
4973da084b3SmrgparseEncodingFile(FontFilePtr f, int headerOnly)
4983da084b3Smrg{
4993da084b3Smrg    int line;
5003da084b3Smrg
501e1c0d025Smrg    unsigned short *enc = NULL;
5023da084b3Smrg    char **nam = NULL, **newnam;
503e1c0d025Smrg    unsigned i, first = 0xFFFF, last = 0, encsize = 0, namsize = 0;
5043da084b3Smrg    FontEncPtr encoding = NULL;
5053da084b3Smrg    FontMapPtr mapping = NULL;
5063da084b3Smrg    FontEncSimpleMapPtr sm;
5073da084b3Smrg    FontEncSimpleNamePtr sn;
508e1c0d025Smrg    char *aliases[MAXALIASES] = { NULL };
509e1c0d025Smrg    int numaliases = 0;
5103da084b3Smrg
5113da084b3Smrg#if 0
5123da084b3Smrg    /* GCC complains about unused labels.  Please fix GCC rather than
5133da084b3Smrg       obfuscating my code. */
514e1c0d025Smrg no_encoding:
5153da084b3Smrg#endif
5163da084b3Smrg    line = getnextline(f);
517e1c0d025Smrg    switch (line) {
5183da084b3Smrg    case EOF_LINE:
5193da084b3Smrg        goto error;
5203da084b3Smrg    case STARTENCODING_LINE:
52155acc8fcSmrg        encoding = malloc(sizeof(FontEncRec));
522e1c0d025Smrg        if (encoding == NULL)
5233da084b3Smrg            goto error;
52455acc8fcSmrg        encoding->name = strdup(keyword_value);
525e1c0d025Smrg        if (encoding->name == NULL)
5263da084b3Smrg            goto error;
5273da084b3Smrg        encoding->size = 256;
5283da084b3Smrg        encoding->row_size = 0;
5293da084b3Smrg        encoding->mappings = NULL;
5303da084b3Smrg        encoding->next = NULL;
531e1c0d025Smrg        encoding->first = encoding->first_col = 0;
5323da084b3Smrg        goto no_mapping;
5333da084b3Smrg    default:
5343da084b3Smrg        goto error;
5353da084b3Smrg    }
5363da084b3Smrg
537e1c0d025Smrg no_mapping:
5383da084b3Smrg    line = getnextline(f);
539e1c0d025Smrg    switch (line) {
540e1c0d025Smrg    case EOF_LINE:
541e1c0d025Smrg        goto done;
5423da084b3Smrg    case ALIAS_LINE:
543e1c0d025Smrg        if (numaliases < MAXALIASES) {
54455acc8fcSmrg            aliases[numaliases] = strdup(keyword_value);
545e1c0d025Smrg            if (aliases[numaliases] == NULL)
5463da084b3Smrg                goto error;
5473da084b3Smrg            numaliases++;
5483da084b3Smrg        }
5493da084b3Smrg        goto no_mapping;
5503da084b3Smrg    case SIZE_LINE:
5513da084b3Smrg        encoding->size = value1;
5523da084b3Smrg        encoding->row_size = value2;
5533da084b3Smrg        goto no_mapping;
5543da084b3Smrg    case FIRSTINDEX_LINE:
5553da084b3Smrg        encoding->first = value1;
5563da084b3Smrg        encoding->first_col = value2;
5573da084b3Smrg        goto no_mapping;
5583da084b3Smrg    case STARTMAPPING_LINE:
559e1c0d025Smrg        if (headerOnly)
5603da084b3Smrg            goto done;
561e1c0d025Smrg        if (!strcasecmp(keyword_value, "unicode")) {
56255acc8fcSmrg            mapping = malloc(sizeof(FontMapRec));
563e1c0d025Smrg            if (mapping == NULL)
5643da084b3Smrg                goto error;
5653da084b3Smrg            mapping->type = FONT_ENCODING_UNICODE;
5663da084b3Smrg            mapping->pid = 0;
5673da084b3Smrg            mapping->eid = 0;
5683da084b3Smrg            mapping->recode = NULL;
5693da084b3Smrg            mapping->name = NULL;
5703da084b3Smrg            mapping->client_data = NULL;
5713da084b3Smrg            mapping->next = NULL;
5723da084b3Smrg            goto mapping;
573e1c0d025Smrg        }
574e1c0d025Smrg        else if (!strcasecmp(keyword_value, "cmap")) {
57555acc8fcSmrg            mapping = malloc(sizeof(FontMapRec));
576e1c0d025Smrg            if (mapping == NULL)
5773da084b3Smrg                goto error;
5783da084b3Smrg            mapping->type = FONT_ENCODING_TRUETYPE;
5793da084b3Smrg            mapping->pid = value1;
5803da084b3Smrg            mapping->eid = value2;
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, "postscript")) {
58855acc8fcSmrg            mapping = malloc(sizeof(FontMapRec));
589e1c0d025Smrg            if (mapping == NULL)
5903da084b3Smrg                goto error;
5913da084b3Smrg            mapping->type = FONT_ENCODING_POSTSCRIPT;
5923da084b3Smrg            mapping->pid = 0;
5933da084b3Smrg            mapping->eid = 0;
5943da084b3Smrg            mapping->recode = NULL;
5953da084b3Smrg            mapping->name = NULL;
5963da084b3Smrg            mapping->client_data = NULL;
5973da084b3Smrg            mapping->next = NULL;
5983da084b3Smrg            goto string_mapping;
599e1c0d025Smrg        }
600e1c0d025Smrg        else {                  /* unknown mapping type -- ignore */
6013da084b3Smrg            goto skipmapping;
6023da084b3Smrg        }
6033da084b3Smrg        /* NOTREACHED */
6043da084b3Smrg        goto error;
605e1c0d025Smrg    default:
606e1c0d025Smrg        goto no_mapping;        /* ignore unknown lines */
6073da084b3Smrg    }
6083da084b3Smrg
609e1c0d025Smrg skipmapping:
6103da084b3Smrg    line = getnextline(f);
611e1c0d025Smrg    switch (line) {
6123da084b3Smrg    case ENDMAPPING_LINE:
6133da084b3Smrg        goto no_mapping;
6143da084b3Smrg    case EOF_LINE:
6153da084b3Smrg        goto error;
6163da084b3Smrg    default:
6173da084b3Smrg        goto skipmapping;
6183da084b3Smrg    }
6193da084b3Smrg
620e1c0d025Smrg mapping:
6213da084b3Smrg    line = getnextline(f);
622e1c0d025Smrg    switch (line) {
623e1c0d025Smrg    case EOF_LINE:
624e1c0d025Smrg        goto error;
6253da084b3Smrg    case ENDMAPPING_LINE:
6263da084b3Smrg        mapping->recode = FontEncSimpleRecode;
6273da084b3Smrg        mapping->name = FontEncUndefinedName;
62855acc8fcSmrg        mapping->client_data = sm = malloc(sizeof(FontEncSimpleMapRec));
629e1c0d025Smrg        if (sm == NULL)
6303da084b3Smrg            goto error;
6313da084b3Smrg        sm->row_size = encoding->row_size;
632e1c0d025Smrg        if (first <= last) {
6333da084b3Smrg            unsigned short *newmap;
6343da084b3Smrg
6353da084b3Smrg            sm->first = first;
636e1c0d025Smrg            sm->len = last - first + 1;
63755acc8fcSmrg            newmap = malloc(sm->len * sizeof(unsigned short));
638e1c0d025Smrg            if (newmap == NULL) {
63955acc8fcSmrg                free(sm);
6403da084b3Smrg                mapping->client_data = sm = NULL;
6413da084b3Smrg                goto error;
6423da084b3Smrg            }
643e1c0d025Smrg            for (i = 0; i < sm->len; i++)
644e1c0d025Smrg                newmap[i] = enc[first + i];
645e1c0d025Smrg            sm->map = newmap;
646e1c0d025Smrg        }
647e1c0d025Smrg        else {
6483da084b3Smrg            sm->first = 0;
6493da084b3Smrg            sm->len = 0;
6503da084b3Smrg            sm->map = NULL;
6513da084b3Smrg        }
6523da084b3Smrg        install_mapping(encoding, mapping);
6533da084b3Smrg        mapping = NULL;
654e1c0d025Smrg        first = 0xFFFF;
655e1c0d025Smrg        last = 0;
6563da084b3Smrg        goto no_mapping;
6573da084b3Smrg
6583da084b3Smrg    case CODE_LINE:
659e1c0d025Smrg        if (setCode(value1, value2, encoding->row_size,
660e1c0d025Smrg                    &first, &last, &encsize, &enc))
6613da084b3Smrg            goto error;
6623da084b3Smrg        goto mapping;
6633da084b3Smrg
6643da084b3Smrg    case CODE_RANGE_LINE:
665e1c0d025Smrg        if (value1 > 0x10000)
6663da084b3Smrg            value1 = 0x10000;
667e1c0d025Smrg        if (value2 > 0x10000)
6683da084b3Smrg            value2 = 0x10000;
669e1c0d025Smrg        if (value2 < value1)
6703da084b3Smrg            goto mapping;
6713da084b3Smrg        /* Do the last value first to avoid having to realloc() */
672e1c0d025Smrg        if (setCode(value2, value3 + (value2 - value1), encoding->row_size,
673e1c0d025Smrg                    &first, &last, &encsize, &enc))
6743da084b3Smrg            goto error;
675e1c0d025Smrg        for (i = value1; i < value2; i++) {
676e1c0d025Smrg            if (setCode(i, value3 + (i - value1), encoding->row_size,
677e1c0d025Smrg                        &first, &last, &encsize, &enc))
6783da084b3Smrg                goto error;
6793da084b3Smrg        }
6803da084b3Smrg        goto mapping;
68148c85eb7Smrg
6823da084b3Smrg    case CODE_UNDEFINE_LINE:
683e1c0d025Smrg        if (value1 > 0x10000)
6843da084b3Smrg            value1 = 0x10000;
685e1c0d025Smrg        if (value2 > 0x10000)
6863da084b3Smrg            value2 = 0x10000;
687e1c0d025Smrg        if (value2 < value1)
6883da084b3Smrg            goto mapping;
6893da084b3Smrg        /* Do the last value first to avoid having to realloc() */
690e1c0d025Smrg        if (setCode(value2, 0, encoding->row_size,
691e1c0d025Smrg                    &first, &last, &encsize, &enc))
6923da084b3Smrg            goto error;
693e1c0d025Smrg        for (i = value1; i < value2; i++) {
694e1c0d025Smrg            if (setCode(i, 0, encoding->row_size,
695e1c0d025Smrg                        &first, &last, &encsize, &enc))
6963da084b3Smrg                goto error;
6973da084b3Smrg        }
6983da084b3Smrg        goto mapping;
6993da084b3Smrg
700e1c0d025Smrg    default:
701e1c0d025Smrg        goto mapping;           /* ignore unknown lines */
7023da084b3Smrg    }
70348c85eb7Smrg
704e1c0d025Smrg string_mapping:
7053da084b3Smrg    line = getnextline(f);
706e1c0d025Smrg    switch (line) {
707e1c0d025Smrg    case EOF_LINE:
708e1c0d025Smrg        goto error;
7093da084b3Smrg    case ENDMAPPING_LINE:
7103da084b3Smrg        mapping->recode = FontEncUndefinedRecode;
7113da084b3Smrg        mapping->name = FontEncSimpleName;
71255acc8fcSmrg        mapping->client_data = sn = malloc(sizeof(FontEncSimpleNameRec));
713e1c0d025Smrg        if (sn == NULL)
7143da084b3Smrg            goto error;
715e1c0d025Smrg        if (first > last) {
71655acc8fcSmrg            free(sn);
7173da084b3Smrg            mapping->client_data = sn = NULL;
7183da084b3Smrg            goto error;
7193da084b3Smrg        }
7203da084b3Smrg        sn->first = first;
7213da084b3Smrg        sn->len = last - first + 1;
722e1c0d025Smrg        sn->map = malloc(sn->len * sizeof(char *));
723e1c0d025Smrg        if (sn->map == NULL) {
72455acc8fcSmrg            free(sn);
7253da084b3Smrg            mapping->client_data = sn = NULL;
7263da084b3Smrg            goto error;
7273da084b3Smrg        }
728e1c0d025Smrg        for (i = 0; i < sn->len; i++)
729e1c0d025Smrg            sn->map[i] = nam[first + i];
730e1c0d025Smrg        install_mapping(encoding, mapping);
7313da084b3Smrg        mapping = NULL;
732e1c0d025Smrg        first = 0xFFFF;
733e1c0d025Smrg        last = 0;
7343da084b3Smrg        goto no_mapping;
7353da084b3Smrg    case NAME_LINE:
736e1c0d025Smrg        if (value1 >= 0x10000)
737e1c0d025Smrg            goto string_mapping;
738e1c0d025Smrg        if (namsize == 0) {
7393da084b3Smrg            namsize = (value1) < 256 ? 256 : 0x10000;
740e1c0d025Smrg            nam = malloc(namsize * sizeof(char *));
741e1c0d025Smrg            if (nam == NULL) {
742e1c0d025Smrg                namsize = 0;
7433da084b3Smrg                goto error;
7443da084b3Smrg            }
745e1c0d025Smrg        }
746e1c0d025Smrg        else if (namsize <= value1) {
7473da084b3Smrg            namsize = 0x10000;
748e1c0d025Smrg            if ((newnam = (char **) realloc(nam, namsize)) == NULL)
7493da084b3Smrg                goto error;
7503da084b3Smrg            nam = newnam;
7513da084b3Smrg        }
752e1c0d025Smrg        if (first > last) {
7533da084b3Smrg            first = last = value1;
7543da084b3Smrg        }
755e1c0d025Smrg        if (value1 < first) {
756e1c0d025Smrg            for (i = value1; i < first; i++)
7573da084b3Smrg                nam[i] = NULL;
7583da084b3Smrg            first = value1;
7593da084b3Smrg        }
760e1c0d025Smrg        if (value1 > last) {
761e1c0d025Smrg            for (i = last + 1; i <= value1; i++)
762e1c0d025Smrg                nam[i] = NULL;
7633da084b3Smrg            last = value1;
7643da084b3Smrg        }
76555acc8fcSmrg        nam[value1] = strdup(keyword_value);
766e1c0d025Smrg        if (nam[value1] == NULL) {
7673da084b3Smrg            goto error;
7683da084b3Smrg        }
7693da084b3Smrg        goto string_mapping;
7703da084b3Smrg
771e1c0d025Smrg    default:
772e1c0d025Smrg        goto string_mapping;    /* ignore unknown lines */
7733da084b3Smrg    }
7743da084b3Smrg
775e1c0d025Smrg done:
776e1c0d025Smrg    if (encsize) {
777e1c0d025Smrg        free(enc);
778e1c0d025Smrg        encsize = 0;
779e1c0d025Smrg        enc = NULL;
780e1c0d025Smrg    }
781e1c0d025Smrg    if (namsize) {
782e1c0d025Smrg        free(nam);             /* don't free entries! */
783e1c0d025Smrg        namsize = 0;
784e1c0d025Smrg        nam = NULL;
785e1c0d025Smrg    }
7863da084b3Smrg
787e1c0d025Smrg    encoding->aliases = NULL;
788e1c0d025Smrg    if (numaliases) {
789e1c0d025Smrg        encoding->aliases = malloc((numaliases + 1) * sizeof(char *));
790e1c0d025Smrg        if (encoding->aliases == NULL)
7913da084b3Smrg            goto error;
792e1c0d025Smrg        for (i = 0; i < numaliases; i++)
7933da084b3Smrg            encoding->aliases[i] = aliases[i];
794e1c0d025Smrg        encoding->aliases[numaliases] = NULL;
7953da084b3Smrg    }
7963da084b3Smrg
7973da084b3Smrg    return encoding;
7983da084b3Smrg
799e1c0d025Smrg error:
800e1c0d025Smrg    if (encsize) {
801e1c0d025Smrg        free(enc);
802e1c0d025Smrg        encsize = 0;
803e1c0d025Smrg    }
804e1c0d025Smrg    if (namsize) {
805e1c0d025Smrg        for (i = first; i <= last; i++)
80655acc8fcSmrg            free(nam[i]);
80755acc8fcSmrg        free(nam);
8083da084b3Smrg    }
809e1c0d025Smrg    if (mapping) {
81055acc8fcSmrg        free(mapping->client_data);
81155acc8fcSmrg        free(mapping);
8123da084b3Smrg    }
813e1c0d025Smrg    if (encoding) {
814e1c0d025Smrg        FontMapPtr nextmap;
815e1c0d025Smrg
816e1c0d025Smrg        free(encoding->name);
817e1c0d025Smrg        for (mapping = encoding->mappings; mapping; mapping = nextmap) {
818e1c0d025Smrg            free(mapping->client_data);
819e1c0d025Smrg            nextmap = mapping->next;
820e1c0d025Smrg            free(mapping);
821e1c0d025Smrg        }
822e1c0d025Smrg        free(encoding);
823e1c0d025Smrg    }
824e1c0d025Smrg    for (i = 0; i < numaliases; i++)
82555acc8fcSmrg        free(aliases[i]);
826e1c0d025Smrg    /* We don't need to free sn and sm as they handled locally in the body. */
8273da084b3Smrg    return NULL;
8283da084b3Smrg}
8293da084b3Smrg
830e1c0d025Smrgchar *
8313da084b3SmrgFontEncDirectory(void)
8323da084b3Smrg{
833e1c0d025Smrg    static char *dir = NULL;
8343da084b3Smrg
835e1c0d025Smrg    if (dir == NULL) {
8363da084b3Smrg        char *c = getenv("FONT_ENCODINGS_DIRECTORY");
837e1c0d025Smrg
838e1c0d025Smrg        if (c) {
83955acc8fcSmrg            dir = strdup(c);
840e1c0d025Smrg            if (!dir)
8413da084b3Smrg                return NULL;
842e1c0d025Smrg        }
843e1c0d025Smrg        else {
8443da084b3Smrg            dir = FONT_ENCODINGS_DIRECTORY;
8453da084b3Smrg        }
8463da084b3Smrg    }
8473da084b3Smrg    return dir;
8483da084b3Smrg}
8493da084b3Smrg
8503da084b3Smrgstatic void
8513da084b3SmrgparseFontFileName(const char *fontFileName, char *buf, char *dir)
8523da084b3Smrg{
8533da084b3Smrg    const char *p;
8543da084b3Smrg    char *q, *lastslash;
85548c85eb7Smrg
856e1c0d025Smrg    for (p = fontFileName, q = dir, lastslash = NULL; *p; p++, q++) {
8573da084b3Smrg        *q = *p;
858e1c0d025Smrg        if (*p == '/')
859e1c0d025Smrg            lastslash = q + 1;
8603da084b3Smrg    }
86148c85eb7Smrg
862e1c0d025Smrg    if (!lastslash)
8633da084b3Smrg        lastslash = dir;
86448c85eb7Smrg
8653da084b3Smrg    *lastslash = '\0';
8663da084b3Smrg
867e1c0d025Smrg    if (buf && strlen(dir) + 14 < MAXFONTFILENAMELEN) {
868e1c0d025Smrg        snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, "encodings.dir");
8693da084b3Smrg    }
8703da084b3Smrg}
8713da084b3Smrg
8723da084b3Smrgstatic FontEncPtr
87348c85eb7SmrgFontEncReallyReallyLoad(const char *charset,
8743da084b3Smrg                        const char *dirname, const char *dir)
8753da084b3Smrg{
8763da084b3Smrg    FontFilePtr f;
8773da084b3Smrg    FILE *file;
8783da084b3Smrg    FontEncPtr encoding;
8793da084b3Smrg    char file_name[MAXFONTFILENAMELEN], encoding_name[MAXFONTNAMELEN],
8803da084b3Smrg        buf[MAXFONTFILENAMELEN];
8813da084b3Smrg    int count, n;
8823da084b3Smrg    static char format[24] = "";
88348c85eb7Smrg
8843da084b3Smrg    /* As we don't really expect to open encodings that often, we don't
8853da084b3Smrg       take the trouble of caching encodings directories. */
8863da084b3Smrg
887e1c0d025Smrg    if ((file = fopen(dirname, "r")) == NULL) {
8883da084b3Smrg        return NULL;
8893da084b3Smrg    }
89048c85eb7Smrg
8913da084b3Smrg    count = fscanf(file, "%d\n", &n);
892e1c0d025Smrg    if (count == EOF || count != 1) {
8933da084b3Smrg        fclose(file);
8943da084b3Smrg        return NULL;
8953da084b3Smrg    }
8963da084b3Smrg
8973da084b3Smrg    encoding = NULL;
8983da084b3Smrg    if (!format[0]) {
899e1c0d025Smrg        snprintf(format, sizeof(format), "%%%ds %%%d[^\n]\n",
900e1c0d025Smrg                 (int) sizeof(encoding_name) - 1, (int) sizeof(file_name) - 1);
9013da084b3Smrg    }
902e1c0d025Smrg    for (;;) {
9033da084b3Smrg        count = fscanf(file, format, encoding_name, file_name);
904e1c0d025Smrg        if (count == EOF)
9053da084b3Smrg            break;
906e1c0d025Smrg        if (count != 2)
9073da084b3Smrg            break;
9083da084b3Smrg
909e1c0d025Smrg        if (!strcasecmp(encoding_name, charset)) {
9103da084b3Smrg            /* Found it */
911e1c0d025Smrg            if (file_name[0] != '/') {
912e1c0d025Smrg                if (strlen(dir) + strlen(file_name) >= MAXFONTFILENAMELEN) {
913e1c0d025Smrg                    fclose(file);
9143da084b3Smrg                    return NULL;
915e1c0d025Smrg                }
916e1c0d025Smrg                snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, file_name);
917e1c0d025Smrg            }
918e1c0d025Smrg            else {
919e1c0d025Smrg                snprintf(buf, MAXFONTFILENAMELEN, "%s", file_name);
9203da084b3Smrg            }
9213da084b3Smrg
9223da084b3Smrg            f = FontFileOpen(buf);
923e1c0d025Smrg            if (f == NULL) {
924e1c0d025Smrg                fclose(file);
9253da084b3Smrg                return NULL;
9263da084b3Smrg            }
9273da084b3Smrg            encoding = parseEncodingFile(f, 0);
9283da084b3Smrg            FontFileClose(f);
9293da084b3Smrg            break;
9303da084b3Smrg        }
9313da084b3Smrg    }
9323da084b3Smrg
9333da084b3Smrg    fclose(file);
9343da084b3Smrg
9353da084b3Smrg    return encoding;
9363da084b3Smrg}
9373da084b3Smrg
93848c85eb7Smrg/* Parser ntrypoint -- used by FontEncLoad */
9393da084b3SmrgFontEncPtr
9403da084b3SmrgFontEncReallyLoad(const char *charset, const char *fontFileName)
9413da084b3Smrg{
9423da084b3Smrg    FontEncPtr encoding;
9433da084b3Smrg    char dir[MAXFONTFILENAMELEN], dirname[MAXFONTFILENAMELEN];
9443da084b3Smrg    char *d;
9453da084b3Smrg
946e1c0d025Smrg    if (fontFileName) {
9473da084b3Smrg        parseFontFileName(fontFileName, dirname, dir);
9483da084b3Smrg        encoding = FontEncReallyReallyLoad(charset, dirname, dir);
949e1c0d025Smrg        if (encoding)
950e1c0d025Smrg            return (encoding);
9513da084b3Smrg    }
95248c85eb7Smrg
9533da084b3Smrg    d = FontEncDirectory();
954e1c0d025Smrg    if (d) {
9553da084b3Smrg        parseFontFileName(d, NULL, dir);
9563da084b3Smrg        encoding = FontEncReallyReallyLoad(charset, d, dir);
9573da084b3Smrg        return encoding;
9583da084b3Smrg    }
95948c85eb7Smrg
9603da084b3Smrg    return NULL;
9613da084b3Smrg}
9623da084b3Smrg
9633da084b3Smrg/* Return a NULL-terminated array of encoding names.  Note that this
9643da084b3Smrg * function has incestuous knowledge of the allocations done by
9653da084b3Smrg * parseEncodingFile. */
9663da084b3Smrg
9673da084b3Smrgchar **
9683da084b3SmrgFontEncIdentify(const char *fileName)
9693da084b3Smrg{
9703da084b3Smrg    FontFilePtr f;
9713da084b3Smrg    FontEncPtr encoding;
9723da084b3Smrg    char **names, **name, **alias;
9733da084b3Smrg    int numaliases;
97448c85eb7Smrg
975e1c0d025Smrg    if ((f = FontFileOpen(fileName)) == NULL) {
9763da084b3Smrg        return NULL;
9773da084b3Smrg    }
9783da084b3Smrg    encoding = parseEncodingFile(f, 1);
9793da084b3Smrg    FontFileClose(f);
9803da084b3Smrg
981e1c0d025Smrg    if (!encoding)
9823da084b3Smrg        return NULL;
9833da084b3Smrg
9843da084b3Smrg    numaliases = 0;
985e1c0d025Smrg    if (encoding->aliases)
986e1c0d025Smrg        for (alias = encoding->aliases; *alias; alias++)
9873da084b3Smrg            numaliases++;
9883da084b3Smrg
989e1c0d025Smrg    names = malloc((numaliases + 2) * sizeof(char *));
990e1c0d025Smrg    if (names == NULL) {
99155acc8fcSmrg        free(encoding->aliases);
99255acc8fcSmrg        free(encoding);
9933da084b3Smrg        return NULL;
9943da084b3Smrg    }
9953da084b3Smrg
9963da084b3Smrg    name = names;
9973da084b3Smrg    *(name++) = encoding->name;
998e1c0d025Smrg    if (numaliases > 0)
999e1c0d025Smrg        for (alias = encoding->aliases; *alias; alias++, name++)
1000e1c0d025Smrg            *name = *alias;
10013da084b3Smrg
10023da084b3Smrg    *name = NULL;
100355acc8fcSmrg    free(encoding->aliases);
100455acc8fcSmrg    free(encoding);
10053da084b3Smrg
10063da084b3Smrg    return names;
10073da084b3Smrg}
1008