encparse.c revision 2a53b785
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
403da084b3Smrg#include "zlib.h"
413da084b3Smrgtypedef gzFile FontFilePtr;
42e1c0d025Smrg
433da084b3Smrg#define FontFileGetc(f) gzgetc(f)
443da084b3Smrg#define FontFileOpen(filename) gzopen(filename, "rb")
453da084b3Smrg#define FontFileClose(f) gzclose(f)
463da084b3Smrg
473da084b3Smrg#define MAXFONTFILENAMELEN 1024
483da084b3Smrg#define MAXFONTNAMELEN 1024
493da084b3Smrg
503da084b3Smrg#include <X11/fonts/fontenc.h>
513da084b3Smrg#include "fontencI.h"
522a53b785Smrg#include "reallocarray.h"
533da084b3Smrg
543da084b3Smrg#define MAXALIASES 20
553da084b3Smrg
563da084b3Smrg#define EOF_TOKEN -1
573da084b3Smrg#define ERROR_TOKEN -2
583da084b3Smrg#define EOL_TOKEN 0
593da084b3Smrg#define NUMBER_TOKEN 1
603da084b3Smrg#define KEYWORD_TOKEN 2
613da084b3Smrg
623da084b3Smrg#define EOF_LINE -1
633da084b3Smrg#define ERROR_LINE -2
643da084b3Smrg#define STARTENCODING_LINE 1
653da084b3Smrg#define STARTMAPPING_LINE 2
663da084b3Smrg#define ENDMAPPING_LINE 3
673da084b3Smrg#define CODE_LINE 4
683da084b3Smrg#define CODE_RANGE_LINE 5
693da084b3Smrg#define CODE_UNDEFINE_LINE 6
703da084b3Smrg#define NAME_LINE 7
713da084b3Smrg#define SIZE_LINE 8
723da084b3Smrg#define ALIAS_LINE 9
733da084b3Smrg#define FIRSTINDEX_LINE 10
743da084b3Smrg
753da084b3Smrg/* Return from lexer */
763da084b3Smrg#define MAXKEYWORDLEN 100
773da084b3Smrg
783da084b3Smrgstatic long number_value;
79e1c0d025Smrgstatic char keyword_value[MAXKEYWORDLEN + 1];
803da084b3Smrg
813da084b3Smrgstatic long value1, value2, value3;
823da084b3Smrg
833da084b3Smrg/* Lexer code */
843da084b3Smrg
853da084b3Smrg/* Skip to the beginning of new line */
863da084b3Smrgstatic void
873da084b3SmrgskipEndOfLine(FontFilePtr f, int c)
883da084b3Smrg{
89e1c0d025Smrg    if (c == 0)
903da084b3Smrg        c = FontFileGetc(f);
9148c85eb7Smrg
92e1c0d025Smrg    for (;;)
93e1c0d025Smrg        if (c <= 0 || c == '\n')
943da084b3Smrg            return;
953da084b3Smrg        else
963da084b3Smrg            c = FontFileGetc(f);
973da084b3Smrg}
983da084b3Smrg
993da084b3Smrg/* Get a number; we're at the first digit. */
1003da084b3Smrgstatic unsigned
1013da084b3Smrggetnum(FontFilePtr f, int c, int *cp)
1023da084b3Smrg{
1033da084b3Smrg    unsigned n = 0;
1043da084b3Smrg    int base = 10;
1053da084b3Smrg
1063da084b3Smrg    /* look for `0' or `0x' prefix */
107e1c0d025Smrg    if (c == '0') {
1083da084b3Smrg        c = FontFileGetc(f);
1093da084b3Smrg        base = 8;
110e1c0d025Smrg        if (c == 'x' || c == 'X') {
1113da084b3Smrg            base = 16;
1123da084b3Smrg            c = FontFileGetc(f);
1133da084b3Smrg        }
1143da084b3Smrg    }
1153da084b3Smrg
1163da084b3Smrg    /* accumulate digits */
117e1c0d025Smrg    for (;;) {
1183da084b3Smrg        if ('0' <= c && c <= '9') {
119e1c0d025Smrg            n *= base;
120e1c0d025Smrg            n += c - '0';
121e1c0d025Smrg        }
122e1c0d025Smrg        else if ('a' <= c && c <= 'f') {
123e1c0d025Smrg            n *= base;
124e1c0d025Smrg            n += c - 'a' + 10;
125e1c0d025Smrg        }
126e1c0d025Smrg        else if ('A' <= c && c <= 'F') {
127e1c0d025Smrg            n *= base;
128e1c0d025Smrg            n += c - 'A' + 10;
129e1c0d025Smrg        }
130e1c0d025Smrg        else
1313da084b3Smrg            break;
1323da084b3Smrg        c = FontFileGetc(f);
1333da084b3Smrg    }
1343da084b3Smrg
135e1c0d025Smrg    *cp = c;
136e1c0d025Smrg    return n;
1373da084b3Smrg}
13848c85eb7Smrg
1393da084b3Smrg/* Skip to beginning of new line; return 1 if only whitespace was found. */
1403da084b3Smrgstatic int
1413da084b3SmrgendOfLine(FontFilePtr f, int c)
1423da084b3Smrg{
143e1c0d025Smrg    if (c == 0)
1443da084b3Smrg        c = FontFileGetc(f);
1453da084b3Smrg
146e1c0d025Smrg    for (;;) {
147e1c0d025Smrg        if (c <= 0 || c == '\n')
1483da084b3Smrg            return 1;
149e1c0d025Smrg        else if (c == '#') {
150e1c0d025Smrg            skipEndOfLine(f, c);
1513da084b3Smrg            return 1;
1523da084b3Smrg        }
153e1c0d025Smrg        else if (c == ' ' || c == '\t') {
154e1c0d025Smrg            skipEndOfLine(f, c);
1553da084b3Smrg            return 0;
1563da084b3Smrg        }
1573da084b3Smrg        c = FontFileGetc(f);
1583da084b3Smrg    }
1593da084b3Smrg}
1603da084b3Smrg
1613da084b3Smrg/* Get a token; we're at first char */
1623da084b3Smrgstatic int
1633da084b3Smrggettoken(FontFilePtr f, int c, int *cp)
1643da084b3Smrg{
1653da084b3Smrg    char *p;
1663da084b3Smrg
167e1c0d025Smrg    if (c <= 0)
168e1c0d025Smrg        c = FontFileGetc(f);
1693da084b3Smrg
170e1c0d025Smrg    if (c <= 0) {
1713da084b3Smrg        return EOF_TOKEN;
1723da084b3Smrg    }
1733da084b3Smrg
174e1c0d025Smrg    while (c == ' ' || c == '\t')
1753da084b3Smrg        c = FontFileGetc(f);
1763da084b3Smrg
177e1c0d025Smrg    if (c == '\n') {
1783da084b3Smrg        return EOL_TOKEN;
179e1c0d025Smrg    }
180e1c0d025Smrg    else if (c == '#') {
181e1c0d025Smrg        skipEndOfLine(f, c);
1823da084b3Smrg        return EOL_TOKEN;
183e1c0d025Smrg    }
184e1c0d025Smrg    else if (c >= '0' && c <= '9') {
185e1c0d025Smrg        number_value = getnum(f, c, cp);
1863da084b3Smrg        return NUMBER_TOKEN;
187e1c0d025Smrg    }
188e1c0d025Smrg    else if ((c >= 'A' && c <= 'Z') ||
189e1c0d025Smrg             (c >= 'a' && c <= 'z') ||
190e1c0d025Smrg             c == '/' || c == '_' || c == '-' || c == '.') {
1913da084b3Smrg        p = keyword_value;
1923da084b3Smrg        *p++ = c;
193e1c0d025Smrg        while (p - keyword_value < MAXKEYWORDLEN) {
1943da084b3Smrg            c = FontFileGetc(f);
195e1c0d025Smrg            if (c <= ' ' || c > '~' || c == '#')
1963da084b3Smrg                break;
1973da084b3Smrg            *p++ = c;
1983da084b3Smrg        }
1993da084b3Smrg        *cp = c;
2003da084b3Smrg        *p = '\0';
2013da084b3Smrg        return KEYWORD_TOKEN;
202e1c0d025Smrg    }
203e1c0d025Smrg    else {
2043da084b3Smrg        *cp = c;
2053da084b3Smrg        return ERROR_TOKEN;
2063da084b3Smrg    }
2073da084b3Smrg}
2083da084b3Smrg
2093da084b3Smrg/* Parse a line.
2103da084b3Smrg * Always skips to the beginning of a new line, even if an error occurs */
2113da084b3Smrgstatic int
2123da084b3Smrggetnextline(FontFilePtr f)
2133da084b3Smrg{
2143da084b3Smrg    int c, token;
215e1c0d025Smrg
2163da084b3Smrg    c = FontFileGetc(f);
217e1c0d025Smrg    if (c <= 0)
2183da084b3Smrg        return EOF_LINE;
2193da084b3Smrg
220e1c0d025Smrg again:
221e1c0d025Smrg    token = gettoken(f, c, &c);
2223da084b3Smrg
223e1c0d025Smrg    switch (token) {
2243da084b3Smrg    case EOF_TOKEN:
2253da084b3Smrg        return EOF_LINE;
2263da084b3Smrg    case EOL_TOKEN:
2273da084b3Smrg        /* empty line */
2283da084b3Smrg        c = FontFileGetc(f);
2293da084b3Smrg        goto again;
2303da084b3Smrg    case NUMBER_TOKEN:
2313da084b3Smrg        value1 = number_value;
232e1c0d025Smrg        token = gettoken(f, c, &c);
233e1c0d025Smrg        switch (token) {
2343da084b3Smrg        case NUMBER_TOKEN:
2353da084b3Smrg            value2 = number_value;
236e1c0d025Smrg            token = gettoken(f, c, &c);
237e1c0d025Smrg            switch (token) {
2383da084b3Smrg            case NUMBER_TOKEN:
2393da084b3Smrg                value3 = number_value;
2403da084b3Smrg                return CODE_RANGE_LINE;
2413da084b3Smrg            case EOL_TOKEN:
2423da084b3Smrg                return CODE_LINE;
2433da084b3Smrg            default:
244e1c0d025Smrg                skipEndOfLine(f, c);
2453da084b3Smrg                return ERROR_LINE;
2463da084b3Smrg            }
2473da084b3Smrg        case KEYWORD_TOKEN:
248e1c0d025Smrg            if (!endOfLine(f, c))
2493da084b3Smrg                return ERROR_LINE;
2503da084b3Smrg            else
2513da084b3Smrg                return NAME_LINE;
2523da084b3Smrg        default:
253e1c0d025Smrg            skipEndOfLine(f, c);
2543da084b3Smrg            return ERROR_LINE;
2553da084b3Smrg        }
2563da084b3Smrg    case KEYWORD_TOKEN:
257e1c0d025Smrg        if (!strcasecmp(keyword_value, "STARTENCODING")) {
258e1c0d025Smrg            token = gettoken(f, c, &c);
259e1c0d025Smrg            if (token == KEYWORD_TOKEN) {
260e1c0d025Smrg                if (endOfLine(f, c))
2613da084b3Smrg                    return STARTENCODING_LINE;
2623da084b3Smrg                else
2633da084b3Smrg                    return ERROR_LINE;
264e1c0d025Smrg            }
265e1c0d025Smrg            else {
266e1c0d025Smrg                skipEndOfLine(f, c);
2673da084b3Smrg                return ERROR_LINE;
2683da084b3Smrg            }
269e1c0d025Smrg        }
270e1c0d025Smrg        else if (!strcasecmp(keyword_value, "ALIAS")) {
271e1c0d025Smrg            token = gettoken(f, c, &c);
272e1c0d025Smrg            if (token == KEYWORD_TOKEN) {
273e1c0d025Smrg                if (endOfLine(f, c))
2743da084b3Smrg                    return ALIAS_LINE;
2753da084b3Smrg                else
2763da084b3Smrg                    return ERROR_LINE;
277e1c0d025Smrg            }
278e1c0d025Smrg            else {
279e1c0d025Smrg                skipEndOfLine(f, c);
2803da084b3Smrg                return ERROR_LINE;
2813da084b3Smrg            }
282e1c0d025Smrg        }
283e1c0d025Smrg        else if (!strcasecmp(keyword_value, "SIZE")) {
284e1c0d025Smrg            token = gettoken(f, c, &c);
285e1c0d025Smrg            if (token == NUMBER_TOKEN) {
2863da084b3Smrg                value1 = number_value;
287e1c0d025Smrg                token = gettoken(f, c, &c);
288e1c0d025Smrg                switch (token) {
2893da084b3Smrg                case NUMBER_TOKEN:
2903da084b3Smrg                    value2 = number_value;
2913da084b3Smrg                    return SIZE_LINE;
2923da084b3Smrg                case EOL_TOKEN:
293e1c0d025Smrg                    value2 = 0;
2943da084b3Smrg                    return SIZE_LINE;
2953da084b3Smrg                default:
296e1c0d025Smrg                    skipEndOfLine(f, c);
2973da084b3Smrg                    return ERROR_LINE;
2983da084b3Smrg                }
299e1c0d025Smrg            }
300e1c0d025Smrg            else {
301e1c0d025Smrg                skipEndOfLine(f, c);
3023da084b3Smrg                return ERROR_LINE;
3033da084b3Smrg            }
304e1c0d025Smrg        }
305e1c0d025Smrg        else if (!strcasecmp(keyword_value, "FIRSTINDEX")) {
306e1c0d025Smrg            token = gettoken(f, c, &c);
307e1c0d025Smrg            if (token == NUMBER_TOKEN) {
3083da084b3Smrg                value1 = number_value;
309e1c0d025Smrg                token = gettoken(f, c, &c);
310e1c0d025Smrg                switch (token) {
3113da084b3Smrg                case NUMBER_TOKEN:
3123da084b3Smrg                    value2 = number_value;
3133da084b3Smrg                    return FIRSTINDEX_LINE;
3143da084b3Smrg                case EOL_TOKEN:
3153da084b3Smrg                    value2 = 0;
3163da084b3Smrg                    return FIRSTINDEX_LINE;
3173da084b3Smrg                default:
318e1c0d025Smrg                    skipEndOfLine(f, c);
3193da084b3Smrg                    return ERROR_LINE;
3203da084b3Smrg                }
321e1c0d025Smrg            }
322e1c0d025Smrg            else {
323e1c0d025Smrg                skipEndOfLine(f, c);
3243da084b3Smrg                return ERROR_LINE;
3253da084b3Smrg            }
326e1c0d025Smrg        }
327e1c0d025Smrg        else if (!strcasecmp(keyword_value, "STARTMAPPING")) {
3283da084b3Smrg            keyword_value[0] = 0;
329e1c0d025Smrg            value1 = 0;
330e1c0d025Smrg            value2 = 0;
3313da084b3Smrg            /* first a keyword */
332e1c0d025Smrg            token = gettoken(f, c, &c);
333e1c0d025Smrg            if (token != KEYWORD_TOKEN) {
3343da084b3Smrg                skipEndOfLine(f, c);
3353da084b3Smrg                return ERROR_LINE;
3363da084b3Smrg            }
3373da084b3Smrg
3383da084b3Smrg            /* optional first integer */
339e1c0d025Smrg            token = gettoken(f, c, &c);
340e1c0d025Smrg            if (token == NUMBER_TOKEN) {
3413da084b3Smrg                value1 = number_value;
342e1c0d025Smrg            }
343e1c0d025Smrg            else if (token == EOL_TOKEN) {
3443da084b3Smrg                return STARTMAPPING_LINE;
345e1c0d025Smrg            }
346e1c0d025Smrg            else {
3473da084b3Smrg                skipEndOfLine(f, c);
3483da084b3Smrg                return ERROR_LINE;
3493da084b3Smrg            }
3503da084b3Smrg
3513da084b3Smrg            /* optional second integer */
352e1c0d025Smrg            token = gettoken(f, c, &c);
353e1c0d025Smrg            if (token == NUMBER_TOKEN) {
3543da084b3Smrg                value2 = number_value;
355e1c0d025Smrg            }
356e1c0d025Smrg            else if (token == EOL_TOKEN) {
3573da084b3Smrg                return STARTMAPPING_LINE;
358e1c0d025Smrg            }
359e1c0d025Smrg            else {
3603da084b3Smrg                skipEndOfLine(f, c);
3613da084b3Smrg                return ERROR_LINE;
3623da084b3Smrg            }
3633da084b3Smrg
364e1c0d025Smrg            if (!endOfLine(f, c))
3653da084b3Smrg                return ERROR_LINE;
3663da084b3Smrg            else {
3673da084b3Smrg                return STARTMAPPING_LINE;
3683da084b3Smrg            }
369e1c0d025Smrg        }
370e1c0d025Smrg        else if (!strcasecmp(keyword_value, "UNDEFINE")) {
3713da084b3Smrg            /* first integer */
372e1c0d025Smrg            token = gettoken(f, c, &c);
373e1c0d025Smrg            if (token != NUMBER_TOKEN) {
374e1c0d025Smrg                skipEndOfLine(f, c);
3753da084b3Smrg                return ERROR_LINE;
3763da084b3Smrg            }
3773da084b3Smrg            value1 = number_value;
3783da084b3Smrg            /* optional second integer */
379e1c0d025Smrg            token = gettoken(f, c, &c);
380e1c0d025Smrg            if (token == EOL_TOKEN) {
3813da084b3Smrg                value2 = value1;
3823da084b3Smrg                return CODE_UNDEFINE_LINE;
383e1c0d025Smrg            }
384e1c0d025Smrg            else if (token == NUMBER_TOKEN) {
3853da084b3Smrg                value2 = number_value;
386e1c0d025Smrg                if (endOfLine(f, c)) {
3873da084b3Smrg                    return CODE_UNDEFINE_LINE;
388e1c0d025Smrg                }
389e1c0d025Smrg                else
3903da084b3Smrg                    return ERROR_LINE;
391e1c0d025Smrg            }
392e1c0d025Smrg            else {
393e1c0d025Smrg                skipEndOfLine(f, c);
3943da084b3Smrg                return ERROR_LINE;
3953da084b3Smrg            }
396e1c0d025Smrg        }
397e1c0d025Smrg        else if (!strcasecmp(keyword_value, "ENDENCODING")) {
398e1c0d025Smrg            if (endOfLine(f, c))
3993da084b3Smrg                return EOF_LINE;
4003da084b3Smrg            else
4013da084b3Smrg                return ERROR_LINE;
402e1c0d025Smrg        }
403e1c0d025Smrg        else if (!strcasecmp(keyword_value, "ENDMAPPING")) {
404e1c0d025Smrg            if (endOfLine(f, c))
4053da084b3Smrg                return ENDMAPPING_LINE;
4063da084b3Smrg            else
4073da084b3Smrg                return ERROR_LINE;
408e1c0d025Smrg        }
409e1c0d025Smrg        else {
410e1c0d025Smrg            skipEndOfLine(f, c);
4113da084b3Smrg            return ERROR_LINE;
4123da084b3Smrg        }
4133da084b3Smrg    default:
4143da084b3Smrg        return ERROR_LINE;
4153da084b3Smrg    }
4163da084b3Smrg}
4173da084b3Smrg
41848c85eb7Smrgstatic void
4193da084b3Smrginstall_mapping(FontEncPtr encoding, FontMapPtr mapping)
4203da084b3Smrg{
4213da084b3Smrg    FontMapPtr m;
4223da084b3Smrg
423e1c0d025Smrg    if (encoding->mappings == NULL)
4243da084b3Smrg        encoding->mappings = mapping;
4253da084b3Smrg    else {
4263da084b3Smrg        m = encoding->mappings;
427e1c0d025Smrg        while (m->next != NULL)
4283da084b3Smrg            m = m->next;
4293da084b3Smrg        m->next = mapping;
4303da084b3Smrg    }
4313da084b3Smrg    mapping->next = NULL;
4323da084b3Smrg    mapping->encoding = encoding;
4333da084b3Smrg}
4343da084b3Smrg
4353da084b3Smrgstatic int
4363da084b3SmrgsetCode(unsigned from, unsigned to, unsigned row_size,
4373da084b3Smrg        unsigned *first, unsigned *last,
4383da084b3Smrg        unsigned *encsize, unsigned short **enc)
4393da084b3Smrg{
4403da084b3Smrg    unsigned index, i;
441e1c0d025Smrg
4423da084b3Smrg    unsigned short *newenc;
4433da084b3Smrg
444e1c0d025Smrg    if (from > 0xFFFF)
4453da084b3Smrg        return 0;               /* success */
4463da084b3Smrg
447e1c0d025Smrg    if (row_size == 0)
448e1c0d025Smrg        index = from;
4493da084b3Smrg    else {
450e1c0d025Smrg        if ((value1 & 0xFF) >= row_size)
4513da084b3Smrg            return 0;           /* ignore out of range mappings */
452e1c0d025Smrg        index = (from >> 8) * row_size + (from & 0xFF);
4533da084b3Smrg    }
4543da084b3Smrg
4553da084b3Smrg    /* Optimize away useless identity mappings.  This is only expected
4563da084b3Smrg       to be useful with linear encodings. */
457e1c0d025Smrg    if (index == to && (index < *first || index > *last))
4583da084b3Smrg        return 0;
459e1c0d025Smrg    if (*encsize == 0) {
4603da084b3Smrg        *encsize = (index < 256) ? 256 : 0x10000;
4612a53b785Smrg        *enc = Xmallocarray(*encsize, sizeof(unsigned short));
462e1c0d025Smrg        if (*enc == NULL) {
4633da084b3Smrg            *encsize = 0;
4643da084b3Smrg            return 1;
4653da084b3Smrg        }
466e1c0d025Smrg    }
467e1c0d025Smrg    else if (*encsize <= index) {
4683da084b3Smrg        *encsize = 0x10000;
4692a53b785Smrg        newenc = Xreallocarray(*enc, *encsize, sizeof(unsigned short));
4702a53b785Smrg        if (newenc == NULL)
4713da084b3Smrg            return 1;
4723da084b3Smrg        *enc = newenc;
4733da084b3Smrg    }
474e1c0d025Smrg    if (*first > *last) {
4753da084b3Smrg        *first = *last = index;
4763da084b3Smrg    }
477e1c0d025Smrg    if (index < *first) {
478e1c0d025Smrg        for (i = index; i < *first; i++)
4793da084b3Smrg            (*enc)[i] = i;
4803da084b3Smrg        *first = index;
4813da084b3Smrg    }
482e1c0d025Smrg    if (index > *last) {
483e1c0d025Smrg        for (i = *last + 1; i <= index; i++)
4843da084b3Smrg            (*enc)[i] = i;
4853da084b3Smrg        *last = index;
4863da084b3Smrg    }
4873da084b3Smrg    (*enc)[index] = to;
4883da084b3Smrg    return 0;
4893da084b3Smrg}
4903da084b3Smrg
4913da084b3Smrg/* Parser.  If headerOnly is true, we're only interested in the
4923da084b3Smrg   data contained in the encoding file's header. */
4933da084b3Smrg
4943da084b3Smrg/* As font encodings are currently never freed, the allocations done
4953da084b3Smrg   by this function are mostly its private business.  Note, however,
4963da084b3Smrg   that FontEncIdentify needs to free the header fields -- so if you
4973da084b3Smrg   change this function, you may need to change FontEncIdentify. */
4983da084b3Smrg
4993da084b3Smrg/* I want a garbage collector. */
5003da084b3Smrg
5013da084b3Smrgstatic FontEncPtr
5023da084b3SmrgparseEncodingFile(FontFilePtr f, int headerOnly)
5033da084b3Smrg{
5043da084b3Smrg    int line;
5053da084b3Smrg
506e1c0d025Smrg    unsigned short *enc = NULL;
5073da084b3Smrg    char **nam = NULL, **newnam;
508e1c0d025Smrg    unsigned i, first = 0xFFFF, last = 0, encsize = 0, namsize = 0;
5093da084b3Smrg    FontEncPtr encoding = NULL;
5103da084b3Smrg    FontMapPtr mapping = NULL;
5113da084b3Smrg    FontEncSimpleMapPtr sm;
5123da084b3Smrg    FontEncSimpleNamePtr sn;
513e1c0d025Smrg    char *aliases[MAXALIASES] = { NULL };
514e1c0d025Smrg    int numaliases = 0;
5153da084b3Smrg
5163da084b3Smrg#if 0
5173da084b3Smrg    /* GCC complains about unused labels.  Please fix GCC rather than
5183da084b3Smrg       obfuscating my code. */
519e1c0d025Smrg no_encoding:
5203da084b3Smrg#endif
5213da084b3Smrg    line = getnextline(f);
522e1c0d025Smrg    switch (line) {
5233da084b3Smrg    case EOF_LINE:
5243da084b3Smrg        goto error;
5253da084b3Smrg    case STARTENCODING_LINE:
52655acc8fcSmrg        encoding = malloc(sizeof(FontEncRec));
527e1c0d025Smrg        if (encoding == NULL)
5283da084b3Smrg            goto error;
52955acc8fcSmrg        encoding->name = strdup(keyword_value);
530e1c0d025Smrg        if (encoding->name == NULL)
5313da084b3Smrg            goto error;
5323da084b3Smrg        encoding->size = 256;
5333da084b3Smrg        encoding->row_size = 0;
5343da084b3Smrg        encoding->mappings = NULL;
5353da084b3Smrg        encoding->next = NULL;
536e1c0d025Smrg        encoding->first = encoding->first_col = 0;
5373da084b3Smrg        goto no_mapping;
5383da084b3Smrg    default:
5393da084b3Smrg        goto error;
5403da084b3Smrg    }
5413da084b3Smrg
542e1c0d025Smrg no_mapping:
5433da084b3Smrg    line = getnextline(f);
544e1c0d025Smrg    switch (line) {
545e1c0d025Smrg    case EOF_LINE:
546e1c0d025Smrg        goto done;
5473da084b3Smrg    case ALIAS_LINE:
548e1c0d025Smrg        if (numaliases < MAXALIASES) {
54955acc8fcSmrg            aliases[numaliases] = strdup(keyword_value);
550e1c0d025Smrg            if (aliases[numaliases] == NULL)
5513da084b3Smrg                goto error;
5523da084b3Smrg            numaliases++;
5533da084b3Smrg        }
5543da084b3Smrg        goto no_mapping;
5553da084b3Smrg    case SIZE_LINE:
5563da084b3Smrg        encoding->size = value1;
5573da084b3Smrg        encoding->row_size = value2;
5583da084b3Smrg        goto no_mapping;
5593da084b3Smrg    case FIRSTINDEX_LINE:
5603da084b3Smrg        encoding->first = value1;
5613da084b3Smrg        encoding->first_col = value2;
5623da084b3Smrg        goto no_mapping;
5633da084b3Smrg    case STARTMAPPING_LINE:
564e1c0d025Smrg        if (headerOnly)
5653da084b3Smrg            goto done;
566e1c0d025Smrg        if (!strcasecmp(keyword_value, "unicode")) {
56755acc8fcSmrg            mapping = malloc(sizeof(FontMapRec));
568e1c0d025Smrg            if (mapping == NULL)
5693da084b3Smrg                goto error;
5703da084b3Smrg            mapping->type = FONT_ENCODING_UNICODE;
5713da084b3Smrg            mapping->pid = 0;
5723da084b3Smrg            mapping->eid = 0;
5733da084b3Smrg            mapping->recode = NULL;
5743da084b3Smrg            mapping->name = NULL;
5753da084b3Smrg            mapping->client_data = NULL;
5763da084b3Smrg            mapping->next = NULL;
5773da084b3Smrg            goto mapping;
578e1c0d025Smrg        }
579e1c0d025Smrg        else if (!strcasecmp(keyword_value, "cmap")) {
58055acc8fcSmrg            mapping = malloc(sizeof(FontMapRec));
581e1c0d025Smrg            if (mapping == NULL)
5823da084b3Smrg                goto error;
5833da084b3Smrg            mapping->type = FONT_ENCODING_TRUETYPE;
5843da084b3Smrg            mapping->pid = value1;
5853da084b3Smrg            mapping->eid = value2;
5863da084b3Smrg            mapping->recode = NULL;
5873da084b3Smrg            mapping->name = NULL;
5883da084b3Smrg            mapping->client_data = NULL;
5893da084b3Smrg            mapping->next = NULL;
5903da084b3Smrg            goto mapping;
591e1c0d025Smrg        }
592e1c0d025Smrg        else if (!strcasecmp(keyword_value, "postscript")) {
59355acc8fcSmrg            mapping = malloc(sizeof(FontMapRec));
594e1c0d025Smrg            if (mapping == NULL)
5953da084b3Smrg                goto error;
5963da084b3Smrg            mapping->type = FONT_ENCODING_POSTSCRIPT;
5973da084b3Smrg            mapping->pid = 0;
5983da084b3Smrg            mapping->eid = 0;
5993da084b3Smrg            mapping->recode = NULL;
6003da084b3Smrg            mapping->name = NULL;
6013da084b3Smrg            mapping->client_data = NULL;
6023da084b3Smrg            mapping->next = NULL;
6033da084b3Smrg            goto string_mapping;
604e1c0d025Smrg        }
605e1c0d025Smrg        else {                  /* unknown mapping type -- ignore */
6063da084b3Smrg            goto skipmapping;
6073da084b3Smrg        }
6083da084b3Smrg        /* NOTREACHED */
6093da084b3Smrg        goto error;
610e1c0d025Smrg    default:
611e1c0d025Smrg        goto no_mapping;        /* ignore unknown lines */
6123da084b3Smrg    }
6133da084b3Smrg
614e1c0d025Smrg skipmapping:
6153da084b3Smrg    line = getnextline(f);
616e1c0d025Smrg    switch (line) {
6173da084b3Smrg    case ENDMAPPING_LINE:
6183da084b3Smrg        goto no_mapping;
6193da084b3Smrg    case EOF_LINE:
6203da084b3Smrg        goto error;
6213da084b3Smrg    default:
6223da084b3Smrg        goto skipmapping;
6233da084b3Smrg    }
6243da084b3Smrg
625e1c0d025Smrg mapping:
6263da084b3Smrg    line = getnextline(f);
627e1c0d025Smrg    switch (line) {
628e1c0d025Smrg    case EOF_LINE:
629e1c0d025Smrg        goto error;
6303da084b3Smrg    case ENDMAPPING_LINE:
6313da084b3Smrg        mapping->recode = FontEncSimpleRecode;
6323da084b3Smrg        mapping->name = FontEncUndefinedName;
63355acc8fcSmrg        mapping->client_data = sm = malloc(sizeof(FontEncSimpleMapRec));
634e1c0d025Smrg        if (sm == NULL)
6353da084b3Smrg            goto error;
6363da084b3Smrg        sm->row_size = encoding->row_size;
637e1c0d025Smrg        if (first <= last) {
6383da084b3Smrg            unsigned short *newmap;
6393da084b3Smrg
6403da084b3Smrg            sm->first = first;
641e1c0d025Smrg            sm->len = last - first + 1;
6422a53b785Smrg            newmap = Xmallocarray(sm->len, sizeof(unsigned short));
643e1c0d025Smrg            if (newmap == NULL) {
64455acc8fcSmrg                free(sm);
6453da084b3Smrg                mapping->client_data = sm = NULL;
6463da084b3Smrg                goto error;
6473da084b3Smrg            }
648e1c0d025Smrg            for (i = 0; i < sm->len; i++)
649e1c0d025Smrg                newmap[i] = enc[first + i];
650e1c0d025Smrg            sm->map = newmap;
651e1c0d025Smrg        }
652e1c0d025Smrg        else {
6533da084b3Smrg            sm->first = 0;
6543da084b3Smrg            sm->len = 0;
6553da084b3Smrg            sm->map = NULL;
6563da084b3Smrg        }
6573da084b3Smrg        install_mapping(encoding, mapping);
6583da084b3Smrg        mapping = NULL;
659e1c0d025Smrg        first = 0xFFFF;
660e1c0d025Smrg        last = 0;
6613da084b3Smrg        goto no_mapping;
6623da084b3Smrg
6633da084b3Smrg    case CODE_LINE:
664e1c0d025Smrg        if (setCode(value1, value2, encoding->row_size,
665e1c0d025Smrg                    &first, &last, &encsize, &enc))
6663da084b3Smrg            goto error;
6673da084b3Smrg        goto mapping;
6683da084b3Smrg
6693da084b3Smrg    case CODE_RANGE_LINE:
670e1c0d025Smrg        if (value1 > 0x10000)
6713da084b3Smrg            value1 = 0x10000;
672e1c0d025Smrg        if (value2 > 0x10000)
6733da084b3Smrg            value2 = 0x10000;
674e1c0d025Smrg        if (value2 < value1)
6753da084b3Smrg            goto mapping;
6763da084b3Smrg        /* Do the last value first to avoid having to realloc() */
677e1c0d025Smrg        if (setCode(value2, value3 + (value2 - value1), encoding->row_size,
678e1c0d025Smrg                    &first, &last, &encsize, &enc))
6793da084b3Smrg            goto error;
680e1c0d025Smrg        for (i = value1; i < value2; i++) {
681e1c0d025Smrg            if (setCode(i, value3 + (i - value1), encoding->row_size,
682e1c0d025Smrg                        &first, &last, &encsize, &enc))
6833da084b3Smrg                goto error;
6843da084b3Smrg        }
6853da084b3Smrg        goto mapping;
68648c85eb7Smrg
6873da084b3Smrg    case CODE_UNDEFINE_LINE:
688e1c0d025Smrg        if (value1 > 0x10000)
6893da084b3Smrg            value1 = 0x10000;
690e1c0d025Smrg        if (value2 > 0x10000)
6913da084b3Smrg            value2 = 0x10000;
692e1c0d025Smrg        if (value2 < value1)
6933da084b3Smrg            goto mapping;
6943da084b3Smrg        /* Do the last value first to avoid having to realloc() */
695e1c0d025Smrg        if (setCode(value2, 0, encoding->row_size,
696e1c0d025Smrg                    &first, &last, &encsize, &enc))
6973da084b3Smrg            goto error;
698e1c0d025Smrg        for (i = value1; i < value2; i++) {
699e1c0d025Smrg            if (setCode(i, 0, encoding->row_size,
700e1c0d025Smrg                        &first, &last, &encsize, &enc))
7013da084b3Smrg                goto error;
7023da084b3Smrg        }
7033da084b3Smrg        goto mapping;
7043da084b3Smrg
705e1c0d025Smrg    default:
706e1c0d025Smrg        goto mapping;           /* ignore unknown lines */
7073da084b3Smrg    }
70848c85eb7Smrg
709e1c0d025Smrg string_mapping:
7103da084b3Smrg    line = getnextline(f);
711e1c0d025Smrg    switch (line) {
712e1c0d025Smrg    case EOF_LINE:
713e1c0d025Smrg        goto error;
7143da084b3Smrg    case ENDMAPPING_LINE:
7153da084b3Smrg        mapping->recode = FontEncUndefinedRecode;
7163da084b3Smrg        mapping->name = FontEncSimpleName;
71755acc8fcSmrg        mapping->client_data = sn = malloc(sizeof(FontEncSimpleNameRec));
718e1c0d025Smrg        if (sn == NULL)
7193da084b3Smrg            goto error;
720e1c0d025Smrg        if (first > last) {
72155acc8fcSmrg            free(sn);
7223da084b3Smrg            mapping->client_data = sn = NULL;
7233da084b3Smrg            goto error;
7243da084b3Smrg        }
7253da084b3Smrg        sn->first = first;
7263da084b3Smrg        sn->len = last - first + 1;
7272a53b785Smrg        sn->map = Xmallocarray(sn->len, sizeof(char *));
728e1c0d025Smrg        if (sn->map == NULL) {
72955acc8fcSmrg            free(sn);
7303da084b3Smrg            mapping->client_data = sn = NULL;
7313da084b3Smrg            goto error;
7323da084b3Smrg        }
733e1c0d025Smrg        for (i = 0; i < sn->len; i++)
734e1c0d025Smrg            sn->map[i] = nam[first + i];
735e1c0d025Smrg        install_mapping(encoding, mapping);
7363da084b3Smrg        mapping = NULL;
737e1c0d025Smrg        first = 0xFFFF;
738e1c0d025Smrg        last = 0;
7393da084b3Smrg        goto no_mapping;
7403da084b3Smrg    case NAME_LINE:
741e1c0d025Smrg        if (value1 >= 0x10000)
742e1c0d025Smrg            goto string_mapping;
743e1c0d025Smrg        if (namsize == 0) {
7443da084b3Smrg            namsize = (value1) < 256 ? 256 : 0x10000;
7452a53b785Smrg            nam = Xmallocarray(namsize, sizeof(char *));
746e1c0d025Smrg            if (nam == NULL) {
747e1c0d025Smrg                namsize = 0;
7483da084b3Smrg                goto error;
7493da084b3Smrg            }
750e1c0d025Smrg        }
751e1c0d025Smrg        else if (namsize <= value1) {
7523da084b3Smrg            namsize = 0x10000;
753e1c0d025Smrg            if ((newnam = (char **) realloc(nam, namsize)) == NULL)
7543da084b3Smrg                goto error;
7553da084b3Smrg            nam = newnam;
7563da084b3Smrg        }
757e1c0d025Smrg        if (first > last) {
7583da084b3Smrg            first = last = value1;
7593da084b3Smrg        }
760e1c0d025Smrg        if (value1 < first) {
761e1c0d025Smrg            for (i = value1; i < first; i++)
7623da084b3Smrg                nam[i] = NULL;
7633da084b3Smrg            first = value1;
7643da084b3Smrg        }
765e1c0d025Smrg        if (value1 > last) {
766e1c0d025Smrg            for (i = last + 1; i <= value1; i++)
767e1c0d025Smrg                nam[i] = NULL;
7683da084b3Smrg            last = value1;
7693da084b3Smrg        }
77055acc8fcSmrg        nam[value1] = strdup(keyword_value);
771e1c0d025Smrg        if (nam[value1] == NULL) {
7723da084b3Smrg            goto error;
7733da084b3Smrg        }
7743da084b3Smrg        goto string_mapping;
7753da084b3Smrg
776e1c0d025Smrg    default:
777e1c0d025Smrg        goto string_mapping;    /* ignore unknown lines */
7783da084b3Smrg    }
7793da084b3Smrg
780e1c0d025Smrg done:
781e1c0d025Smrg    if (encsize) {
782e1c0d025Smrg        free(enc);
783e1c0d025Smrg        encsize = 0;
784e1c0d025Smrg        enc = NULL;
785e1c0d025Smrg    }
786e1c0d025Smrg    if (namsize) {
787e1c0d025Smrg        free(nam);             /* don't free entries! */
788e1c0d025Smrg        namsize = 0;
789e1c0d025Smrg        nam = NULL;
790e1c0d025Smrg    }
7913da084b3Smrg
792e1c0d025Smrg    encoding->aliases = NULL;
793e1c0d025Smrg    if (numaliases) {
7942a53b785Smrg        encoding->aliases = Xmallocarray(numaliases + 1, sizeof(char *));
795e1c0d025Smrg        if (encoding->aliases == NULL)
7963da084b3Smrg            goto error;
797e1c0d025Smrg        for (i = 0; i < numaliases; i++)
7983da084b3Smrg            encoding->aliases[i] = aliases[i];
799e1c0d025Smrg        encoding->aliases[numaliases] = NULL;
8003da084b3Smrg    }
8013da084b3Smrg
8023da084b3Smrg    return encoding;
8033da084b3Smrg
804e1c0d025Smrg error:
805e1c0d025Smrg    if (encsize) {
806e1c0d025Smrg        free(enc);
807e1c0d025Smrg        encsize = 0;
808e1c0d025Smrg    }
809e1c0d025Smrg    if (namsize) {
810e1c0d025Smrg        for (i = first; i <= last; i++)
81155acc8fcSmrg            free(nam[i]);
81255acc8fcSmrg        free(nam);
8133da084b3Smrg    }
814e1c0d025Smrg    if (mapping) {
81555acc8fcSmrg        free(mapping->client_data);
81655acc8fcSmrg        free(mapping);
8173da084b3Smrg    }
818e1c0d025Smrg    if (encoding) {
819e1c0d025Smrg        FontMapPtr nextmap;
820e1c0d025Smrg
821e1c0d025Smrg        free(encoding->name);
822e1c0d025Smrg        for (mapping = encoding->mappings; mapping; mapping = nextmap) {
823e1c0d025Smrg            free(mapping->client_data);
824e1c0d025Smrg            nextmap = mapping->next;
825e1c0d025Smrg            free(mapping);
826e1c0d025Smrg        }
827e1c0d025Smrg        free(encoding);
828e1c0d025Smrg    }
829e1c0d025Smrg    for (i = 0; i < numaliases; i++)
83055acc8fcSmrg        free(aliases[i]);
831e1c0d025Smrg    /* We don't need to free sn and sm as they handled locally in the body. */
8323da084b3Smrg    return NULL;
8333da084b3Smrg}
8343da084b3Smrg
83552fd71cdSmrgconst char *
8363da084b3SmrgFontEncDirectory(void)
8373da084b3Smrg{
83852fd71cdSmrg    static const char *dir = NULL;
8393da084b3Smrg
840e1c0d025Smrg    if (dir == NULL) {
84152fd71cdSmrg        const char *c = getenv("FONT_ENCODINGS_DIRECTORY");
842e1c0d025Smrg
843e1c0d025Smrg        if (c) {
84455acc8fcSmrg            dir = strdup(c);
845e1c0d025Smrg            if (!dir)
8463da084b3Smrg                return NULL;
847e1c0d025Smrg        }
848e1c0d025Smrg        else {
8493da084b3Smrg            dir = FONT_ENCODINGS_DIRECTORY;
8503da084b3Smrg        }
8513da084b3Smrg    }
8523da084b3Smrg    return dir;
8533da084b3Smrg}
8543da084b3Smrg
8553da084b3Smrgstatic void
8563da084b3SmrgparseFontFileName(const char *fontFileName, char *buf, char *dir)
8573da084b3Smrg{
8583da084b3Smrg    const char *p;
8593da084b3Smrg    char *q, *lastslash;
86048c85eb7Smrg
861e1c0d025Smrg    for (p = fontFileName, q = dir, lastslash = NULL; *p; p++, q++) {
8623da084b3Smrg        *q = *p;
863e1c0d025Smrg        if (*p == '/')
864e1c0d025Smrg            lastslash = q + 1;
8653da084b3Smrg    }
86648c85eb7Smrg
867e1c0d025Smrg    if (!lastslash)
8683da084b3Smrg        lastslash = dir;
86948c85eb7Smrg
8703da084b3Smrg    *lastslash = '\0';
8713da084b3Smrg
872e1c0d025Smrg    if (buf && strlen(dir) + 14 < MAXFONTFILENAMELEN) {
873e1c0d025Smrg        snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, "encodings.dir");
8743da084b3Smrg    }
8753da084b3Smrg}
8763da084b3Smrg
8773da084b3Smrgstatic FontEncPtr
87848c85eb7SmrgFontEncReallyReallyLoad(const char *charset,
8793da084b3Smrg                        const char *dirname, const char *dir)
8803da084b3Smrg{
8813da084b3Smrg    FontFilePtr f;
8823da084b3Smrg    FILE *file;
8833da084b3Smrg    FontEncPtr encoding;
8843da084b3Smrg    char file_name[MAXFONTFILENAMELEN], encoding_name[MAXFONTNAMELEN],
8853da084b3Smrg        buf[MAXFONTFILENAMELEN];
8863da084b3Smrg    int count, n;
8873da084b3Smrg    static char format[24] = "";
88848c85eb7Smrg
8893da084b3Smrg    /* As we don't really expect to open encodings that often, we don't
8903da084b3Smrg       take the trouble of caching encodings directories. */
8913da084b3Smrg
892e1c0d025Smrg    if ((file = fopen(dirname, "r")) == NULL) {
8933da084b3Smrg        return NULL;
8943da084b3Smrg    }
89548c85eb7Smrg
8963da084b3Smrg    count = fscanf(file, "%d\n", &n);
897e1c0d025Smrg    if (count == EOF || count != 1) {
8983da084b3Smrg        fclose(file);
8993da084b3Smrg        return NULL;
9003da084b3Smrg    }
9013da084b3Smrg
9023da084b3Smrg    encoding = NULL;
9033da084b3Smrg    if (!format[0]) {
904e1c0d025Smrg        snprintf(format, sizeof(format), "%%%ds %%%d[^\n]\n",
905e1c0d025Smrg                 (int) sizeof(encoding_name) - 1, (int) sizeof(file_name) - 1);
9063da084b3Smrg    }
907e1c0d025Smrg    for (;;) {
9083da084b3Smrg        count = fscanf(file, format, encoding_name, file_name);
909e1c0d025Smrg        if (count == EOF)
9103da084b3Smrg            break;
911e1c0d025Smrg        if (count != 2)
9123da084b3Smrg            break;
9133da084b3Smrg
914e1c0d025Smrg        if (!strcasecmp(encoding_name, charset)) {
9153da084b3Smrg            /* Found it */
916e1c0d025Smrg            if (file_name[0] != '/') {
917e1c0d025Smrg                if (strlen(dir) + strlen(file_name) >= MAXFONTFILENAMELEN) {
918e1c0d025Smrg                    fclose(file);
9193da084b3Smrg                    return NULL;
920e1c0d025Smrg                }
921e1c0d025Smrg                snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, file_name);
922e1c0d025Smrg            }
923e1c0d025Smrg            else {
924e1c0d025Smrg                snprintf(buf, MAXFONTFILENAMELEN, "%s", file_name);
9253da084b3Smrg            }
9263da084b3Smrg
9273da084b3Smrg            f = FontFileOpen(buf);
928e1c0d025Smrg            if (f == NULL) {
929e1c0d025Smrg                fclose(file);
9303da084b3Smrg                return NULL;
9313da084b3Smrg            }
9323da084b3Smrg            encoding = parseEncodingFile(f, 0);
9333da084b3Smrg            FontFileClose(f);
9343da084b3Smrg            break;
9353da084b3Smrg        }
9363da084b3Smrg    }
9373da084b3Smrg
9383da084b3Smrg    fclose(file);
9393da084b3Smrg
9403da084b3Smrg    return encoding;
9413da084b3Smrg}
9423da084b3Smrg
94348c85eb7Smrg/* Parser ntrypoint -- used by FontEncLoad */
9443da084b3SmrgFontEncPtr
9453da084b3SmrgFontEncReallyLoad(const char *charset, const char *fontFileName)
9463da084b3Smrg{
9473da084b3Smrg    FontEncPtr encoding;
9483da084b3Smrg    char dir[MAXFONTFILENAMELEN], dirname[MAXFONTFILENAMELEN];
94952fd71cdSmrg    const char *d;
9503da084b3Smrg
951e1c0d025Smrg    if (fontFileName) {
9523da084b3Smrg        parseFontFileName(fontFileName, dirname, dir);
9533da084b3Smrg        encoding = FontEncReallyReallyLoad(charset, dirname, dir);
954e1c0d025Smrg        if (encoding)
955e1c0d025Smrg            return (encoding);
9563da084b3Smrg    }
95748c85eb7Smrg
9583da084b3Smrg    d = FontEncDirectory();
959e1c0d025Smrg    if (d) {
9603da084b3Smrg        parseFontFileName(d, NULL, dir);
9613da084b3Smrg        encoding = FontEncReallyReallyLoad(charset, d, dir);
9623da084b3Smrg        return encoding;
9633da084b3Smrg    }
96448c85eb7Smrg
9653da084b3Smrg    return NULL;
9663da084b3Smrg}
9673da084b3Smrg
9683da084b3Smrg/* Return a NULL-terminated array of encoding names.  Note that this
9693da084b3Smrg * function has incestuous knowledge of the allocations done by
9703da084b3Smrg * parseEncodingFile. */
9713da084b3Smrg
9723da084b3Smrgchar **
9733da084b3SmrgFontEncIdentify(const char *fileName)
9743da084b3Smrg{
9753da084b3Smrg    FontFilePtr f;
9763da084b3Smrg    FontEncPtr encoding;
9773da084b3Smrg    char **names, **name, **alias;
9783da084b3Smrg    int numaliases;
97948c85eb7Smrg
980e1c0d025Smrg    if ((f = FontFileOpen(fileName)) == NULL) {
9813da084b3Smrg        return NULL;
9823da084b3Smrg    }
9833da084b3Smrg    encoding = parseEncodingFile(f, 1);
9843da084b3Smrg    FontFileClose(f);
9853da084b3Smrg
986e1c0d025Smrg    if (!encoding)
9873da084b3Smrg        return NULL;
9883da084b3Smrg
9893da084b3Smrg    numaliases = 0;
990e1c0d025Smrg    if (encoding->aliases)
991e1c0d025Smrg        for (alias = encoding->aliases; *alias; alias++)
9923da084b3Smrg            numaliases++;
9933da084b3Smrg
9942a53b785Smrg    names = Xmallocarray(numaliases + 2, sizeof(char *));
995e1c0d025Smrg    if (names == NULL) {
99655acc8fcSmrg        free(encoding->aliases);
99755acc8fcSmrg        free(encoding);
9983da084b3Smrg        return NULL;
9993da084b3Smrg    }
10003da084b3Smrg
10013da084b3Smrg    name = names;
10023da084b3Smrg    *(name++) = encoding->name;
1003e1c0d025Smrg    if (numaliases > 0)
1004e1c0d025Smrg        for (alias = encoding->aliases; *alias; alias++, name++)
1005e1c0d025Smrg            *name = *alias;
10063da084b3Smrg
10073da084b3Smrg    *name = NULL;
100855acc8fcSmrg    free(encoding->aliases);
100955acc8fcSmrg    free(encoding);
10103da084b3Smrg
10113da084b3Smrg    return names;
10123da084b3Smrg}
1013