encparse.c revision 3da084b3
13da084b3Smrg/* $XdotOrg: lib/fontenc/src/encparse.c,v 1.6 2006/04/10 16:15:12 alanc Exp $ */
23da084b3Smrg/*
33da084b3SmrgCopyright (c) 1998-2001 by Juliusz Chroboczek
43da084b3Smrg
53da084b3SmrgPermission is hereby granted, free of charge, to any person obtaining a copy
63da084b3Smrgof this software and associated documentation files (the "Software"), to deal
73da084b3Smrgin the Software without restriction, including without limitation the rights
83da084b3Smrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
93da084b3Smrgcopies of the Software, and to permit persons to whom the Software is
103da084b3Smrgfurnished to do so, subject to the following conditions:
113da084b3Smrg
123da084b3SmrgThe above copyright notice and this permission notice shall be included in
133da084b3Smrgall copies or substantial portions of the Software.
143da084b3Smrg
153da084b3SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
163da084b3SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
173da084b3SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
183da084b3SmrgAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
193da084b3SmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
203da084b3SmrgOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
213da084b3SmrgTHE SOFTWARE.
223da084b3Smrg*/
233da084b3Smrg
243da084b3Smrg/* $XFree86: xc/lib/font/fontfile/encparse.c,v 1.20tsi Exp $ */
253da084b3Smrg
263da084b3Smrg/* Parser for encoding files */
273da084b3Smrg
283da084b3Smrg/* This code assumes that we are using ASCII.  We don't use the ctype
293da084b3Smrg   functions, as they depend on the current locale.  On the other
303da084b3Smrg   hand, we do use strcasecmp, but only on strings that we've checked
313da084b3Smrg   to be pure ASCII.  Bloody ``Code Set Independence''. */
323da084b3Smrg
333da084b3Smrg#include <string.h>
343da084b3Smrg#include <stdio.h>
353da084b3Smrg
363da084b3Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
373da084b3Smrg#include <strings.h>
383da084b3Smrg#endif
393da084b3Smrg
403da084b3Smrg#ifndef FONTENC_NO_LIBFONT
413da084b3Smrg
423da084b3Smrg#include <X11/fonts/fntfilio.h>
433da084b3Smrg#include <X11/fonts/fntfilst.h>
443da084b3Smrg
453da084b3Smrg#else
463da084b3Smrg
473da084b3Smrg#include <stdlib.h>
483da084b3Smrg#define xalloc(n) malloc(n)
493da084b3Smrg#define xrealloc(p, n) realloc(p, n)
503da084b3Smrg#define xfree(p) free(p)
513da084b3Smrg
523da084b3Smrg#include "zlib.h"
533da084b3Smrgtypedef gzFile FontFilePtr;
543da084b3Smrg#define FontFileGetc(f) gzgetc(f)
553da084b3Smrg#define FontFileOpen(filename) gzopen(filename, "rb")
563da084b3Smrg#define FontFileClose(f) gzclose(f)
573da084b3Smrg
583da084b3Smrg#define MAXFONTFILENAMELEN 1024
593da084b3Smrg#define MAXFONTNAMELEN 1024
603da084b3Smrg
613da084b3Smrg#endif
623da084b3Smrg
633da084b3Smrg#include <X11/fonts/fontenc.h>
643da084b3Smrg#include "fontencI.h"
653da084b3Smrg
663da084b3Smrg#define MAXALIASES 20
673da084b3Smrg
683da084b3Smrg#define EOF_TOKEN -1
693da084b3Smrg#define ERROR_TOKEN -2
703da084b3Smrg#define EOL_TOKEN 0
713da084b3Smrg#define NUMBER_TOKEN 1
723da084b3Smrg#define KEYWORD_TOKEN 2
733da084b3Smrg
743da084b3Smrg#define EOF_LINE -1
753da084b3Smrg#define ERROR_LINE -2
763da084b3Smrg#define STARTENCODING_LINE 1
773da084b3Smrg#define STARTMAPPING_LINE 2
783da084b3Smrg#define ENDMAPPING_LINE 3
793da084b3Smrg#define CODE_LINE 4
803da084b3Smrg#define CODE_RANGE_LINE 5
813da084b3Smrg#define CODE_UNDEFINE_LINE 6
823da084b3Smrg#define NAME_LINE 7
833da084b3Smrg#define SIZE_LINE 8
843da084b3Smrg#define ALIAS_LINE 9
853da084b3Smrg#define FIRSTINDEX_LINE 10
863da084b3Smrg
873da084b3Smrg/* Return from lexer */
883da084b3Smrg#define MAXKEYWORDLEN 100
893da084b3Smrg
903da084b3Smrgstatic long number_value;
913da084b3Smrgstatic char keyword_value[MAXKEYWORDLEN+1];
923da084b3Smrg
933da084b3Smrgstatic long value1, value2, value3;
943da084b3Smrg
953da084b3Smrg/* Lexer code */
963da084b3Smrg
973da084b3Smrg/* Skip to the beginning of new line */
983da084b3Smrgstatic void
993da084b3SmrgskipEndOfLine(FontFilePtr f, int c)
1003da084b3Smrg{
1013da084b3Smrg    if(c == 0)
1023da084b3Smrg        c = FontFileGetc(f);
1033da084b3Smrg
1043da084b3Smrg    for(;;)
1053da084b3Smrg        if(c <= 0 || c == '\n')
1063da084b3Smrg            return;
1073da084b3Smrg        else
1083da084b3Smrg            c = FontFileGetc(f);
1093da084b3Smrg}
1103da084b3Smrg
1113da084b3Smrg/* Get a number; we're at the first digit. */
1123da084b3Smrgstatic unsigned
1133da084b3Smrggetnum(FontFilePtr f, int c, int *cp)
1143da084b3Smrg{
1153da084b3Smrg    unsigned n = 0;
1163da084b3Smrg    int base = 10;
1173da084b3Smrg
1183da084b3Smrg    /* look for `0' or `0x' prefix */
1193da084b3Smrg    if(c == '0') {
1203da084b3Smrg        c = FontFileGetc(f);
1213da084b3Smrg        base = 8;
1223da084b3Smrg        if(c == 'x' || c == 'X') {
1233da084b3Smrg            base = 16;
1243da084b3Smrg            c = FontFileGetc(f);
1253da084b3Smrg        }
1263da084b3Smrg    }
1273da084b3Smrg
1283da084b3Smrg    /* accumulate digits */
1293da084b3Smrg    for(;;) {
1303da084b3Smrg        if ('0' <= c && c <= '9') {
1313da084b3Smrg            n *= base; n += c - '0';
1323da084b3Smrg        } else if('a' <= c && c <= 'f') {
1333da084b3Smrg            n *= base; n += c - 'a' + 10;
1343da084b3Smrg        } else if('A' <=c && c <= 'F') {
1353da084b3Smrg            n *= base; n += c - 'A' + 10;
1363da084b3Smrg        } else
1373da084b3Smrg            break;
1383da084b3Smrg        c = FontFileGetc(f);
1393da084b3Smrg    }
1403da084b3Smrg
1413da084b3Smrg    *cp = c; return n;
1423da084b3Smrg}
1433da084b3Smrg
1443da084b3Smrg/* Skip to beginning of new line; return 1 if only whitespace was found. */
1453da084b3Smrgstatic int
1463da084b3SmrgendOfLine(FontFilePtr f, int c)
1473da084b3Smrg{
1483da084b3Smrg    if(c == 0)
1493da084b3Smrg        c = FontFileGetc(f);
1503da084b3Smrg
1513da084b3Smrg    for(;;) {
1523da084b3Smrg        if(c <= 0 || c == '\n')
1533da084b3Smrg            return 1;
1543da084b3Smrg        else if(c == '#') {
1553da084b3Smrg            skipEndOfLine(f,c);
1563da084b3Smrg            return 1;
1573da084b3Smrg        }
1583da084b3Smrg        else if(c == ' ' || c == '\t') {
1593da084b3Smrg            skipEndOfLine(f,c);
1603da084b3Smrg            return 0;
1613da084b3Smrg        }
1623da084b3Smrg        c = FontFileGetc(f);
1633da084b3Smrg    }
1643da084b3Smrg}
1653da084b3Smrg
1663da084b3Smrg/* Get a token; we're at first char */
1673da084b3Smrgstatic int
1683da084b3Smrggettoken(FontFilePtr f, int c, int *cp)
1693da084b3Smrg{
1703da084b3Smrg    char *p;
1713da084b3Smrg
1723da084b3Smrg    if(c <= 0)
1733da084b3Smrg    c = FontFileGetc(f);
1743da084b3Smrg
1753da084b3Smrg    if(c <= 0) {
1763da084b3Smrg        return EOF_TOKEN;
1773da084b3Smrg    }
1783da084b3Smrg
1793da084b3Smrg    while(c == ' ' || c == '\t')
1803da084b3Smrg        c = FontFileGetc(f);
1813da084b3Smrg
1823da084b3Smrg    if(c=='\n') {
1833da084b3Smrg        return EOL_TOKEN;
1843da084b3Smrg    } else if(c == '#') {
1853da084b3Smrg        skipEndOfLine(f,c);
1863da084b3Smrg        return EOL_TOKEN;
1873da084b3Smrg    } else if(c >= '0' && c <= '9') {
1883da084b3Smrg        number_value = getnum(f,c,cp);
1893da084b3Smrg        return NUMBER_TOKEN;
1903da084b3Smrg    } else if((c >= 'A' && c <= 'Z') ||
1913da084b3Smrg              (c >= 'a' && c <= 'z') ||
1923da084b3Smrg              c == '/' || c == '_' || c == '-' || c == '.') {
1933da084b3Smrg        p = keyword_value;
1943da084b3Smrg        *p++ = c;
1953da084b3Smrg        while(p-keyword_value < MAXKEYWORDLEN) {
1963da084b3Smrg            c = FontFileGetc(f);
1973da084b3Smrg            if(c <= ' ' || c > '~' || c == '#')
1983da084b3Smrg                break;
1993da084b3Smrg            *p++ = c;
2003da084b3Smrg        }
2013da084b3Smrg        *cp = c;
2023da084b3Smrg        *p = '\0';
2033da084b3Smrg        return KEYWORD_TOKEN;
2043da084b3Smrg    } else {
2053da084b3Smrg        *cp = c;
2063da084b3Smrg        return ERROR_TOKEN;
2073da084b3Smrg    }
2083da084b3Smrg}
2093da084b3Smrg
2103da084b3Smrg/* Parse a line.
2113da084b3Smrg * Always skips to the beginning of a new line, even if an error occurs */
2123da084b3Smrgstatic int
2133da084b3Smrggetnextline(FontFilePtr f)
2143da084b3Smrg{
2153da084b3Smrg    int c, token;
2163da084b3Smrg    c = FontFileGetc(f);
2173da084b3Smrg    if(c <= 0)
2183da084b3Smrg        return EOF_LINE;
2193da084b3Smrg
2203da084b3Smrg  again:
2213da084b3Smrg    token=gettoken(f,c,&c);
2223da084b3Smrg
2233da084b3Smrg    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;
2323da084b3Smrg        token = gettoken(f,c,&c);
2333da084b3Smrg        switch(token) {
2343da084b3Smrg        case NUMBER_TOKEN:
2353da084b3Smrg            value2 = number_value;
2363da084b3Smrg            token = gettoken(f,c,&c);
2373da084b3Smrg            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:
2443da084b3Smrg                skipEndOfLine(f,c);
2453da084b3Smrg                return ERROR_LINE;
2463da084b3Smrg            }
2473da084b3Smrg        case KEYWORD_TOKEN:
2483da084b3Smrg            if(!endOfLine(f,c))
2493da084b3Smrg                return ERROR_LINE;
2503da084b3Smrg            else
2513da084b3Smrg                return NAME_LINE;
2523da084b3Smrg        default:
2533da084b3Smrg            skipEndOfLine(f,c);
2543da084b3Smrg            return ERROR_LINE;
2553da084b3Smrg        }
2563da084b3Smrg    case KEYWORD_TOKEN:
2573da084b3Smrg        if(!strcasecmp(keyword_value, "STARTENCODING")) {
2583da084b3Smrg            token = gettoken(f,c,&c);
2593da084b3Smrg            if(token == KEYWORD_TOKEN) {
2603da084b3Smrg                if(endOfLine(f,c))
2613da084b3Smrg                    return STARTENCODING_LINE;
2623da084b3Smrg                else
2633da084b3Smrg                    return ERROR_LINE;
2643da084b3Smrg            } else {
2653da084b3Smrg                skipEndOfLine(f,c);
2663da084b3Smrg                return ERROR_LINE;
2673da084b3Smrg            }
2683da084b3Smrg        } else if(!strcasecmp(keyword_value, "ALIAS")) {
2693da084b3Smrg            token = gettoken(f,c,&c);
2703da084b3Smrg            if(token == KEYWORD_TOKEN) {
2713da084b3Smrg                if(endOfLine(f,c))
2723da084b3Smrg                    return ALIAS_LINE;
2733da084b3Smrg                else
2743da084b3Smrg                    return ERROR_LINE;
2753da084b3Smrg            } else {
2763da084b3Smrg                skipEndOfLine(f,c);
2773da084b3Smrg                return ERROR_LINE;
2783da084b3Smrg            }
2793da084b3Smrg        } else if(!strcasecmp(keyword_value, "SIZE")) {
2803da084b3Smrg            token = gettoken(f,c,&c);
2813da084b3Smrg            if(token == NUMBER_TOKEN) {
2823da084b3Smrg                value1 = number_value;
2833da084b3Smrg                token = gettoken(f,c,&c);
2843da084b3Smrg                switch(token) {
2853da084b3Smrg                case NUMBER_TOKEN:
2863da084b3Smrg                    value2 = number_value;
2873da084b3Smrg                    return SIZE_LINE;
2883da084b3Smrg                case EOL_TOKEN:
2893da084b3Smrg                    value2=0;
2903da084b3Smrg                    return SIZE_LINE;
2913da084b3Smrg                default:
2923da084b3Smrg                    skipEndOfLine(f,c);
2933da084b3Smrg                    return ERROR_LINE;
2943da084b3Smrg                }
2953da084b3Smrg            } else {
2963da084b3Smrg                skipEndOfLine(f,c);
2973da084b3Smrg                return ERROR_LINE;
2983da084b3Smrg            }
2993da084b3Smrg        } else if(!strcasecmp(keyword_value, "FIRSTINDEX")) {
3003da084b3Smrg            token = gettoken(f,c,&c);
3013da084b3Smrg            if(token == NUMBER_TOKEN) {
3023da084b3Smrg                value1 = number_value;
3033da084b3Smrg                token = gettoken(f,c,&c);
3043da084b3Smrg                switch(token) {
3053da084b3Smrg                case NUMBER_TOKEN:
3063da084b3Smrg                    value2 = number_value;
3073da084b3Smrg                    return FIRSTINDEX_LINE;
3083da084b3Smrg                case EOL_TOKEN:
3093da084b3Smrg                    value2 = 0;
3103da084b3Smrg                    return FIRSTINDEX_LINE;
3113da084b3Smrg                default:
3123da084b3Smrg                    skipEndOfLine(f,c);
3133da084b3Smrg                    return ERROR_LINE;
3143da084b3Smrg                }
3153da084b3Smrg            } else {
3163da084b3Smrg                skipEndOfLine(f,c);
3173da084b3Smrg                return ERROR_LINE;
3183da084b3Smrg            }
3193da084b3Smrg        } else if(!strcasecmp(keyword_value, "STARTMAPPING")) {
3203da084b3Smrg            keyword_value[0] = 0;
3213da084b3Smrg            value1 = 0; value1 = 0;
3223da084b3Smrg            /* first a keyword */
3233da084b3Smrg            token = gettoken(f,c,&c);
3243da084b3Smrg            if(token != KEYWORD_TOKEN) {
3253da084b3Smrg                skipEndOfLine(f, c);
3263da084b3Smrg                return ERROR_LINE;
3273da084b3Smrg            }
3283da084b3Smrg
3293da084b3Smrg            /* optional first integer */
3303da084b3Smrg            token = gettoken(f,c,&c);
3313da084b3Smrg            if(token == NUMBER_TOKEN) {
3323da084b3Smrg                value1 = number_value;
3333da084b3Smrg            } else if(token == EOL_TOKEN) {
3343da084b3Smrg                return STARTMAPPING_LINE;
3353da084b3Smrg            } else {
3363da084b3Smrg                skipEndOfLine(f, c);
3373da084b3Smrg                return ERROR_LINE;
3383da084b3Smrg            }
3393da084b3Smrg
3403da084b3Smrg            /* optional second integer */
3413da084b3Smrg            token = gettoken(f,c,&c);
3423da084b3Smrg            if(token == NUMBER_TOKEN) {
3433da084b3Smrg                value2 = number_value;
3443da084b3Smrg            } else if(token == EOL_TOKEN) {
3453da084b3Smrg                return STARTMAPPING_LINE;
3463da084b3Smrg            } else {
3473da084b3Smrg                skipEndOfLine(f, c);
3483da084b3Smrg                return ERROR_LINE;
3493da084b3Smrg            }
3503da084b3Smrg
3513da084b3Smrg            if(!endOfLine(f,c))
3523da084b3Smrg                return ERROR_LINE;
3533da084b3Smrg            else {
3543da084b3Smrg                return STARTMAPPING_LINE;
3553da084b3Smrg            }
3563da084b3Smrg        } else if(!strcasecmp(keyword_value, "UNDEFINE")) {
3573da084b3Smrg            /* first integer */
3583da084b3Smrg            token = gettoken(f,c,&c);
3593da084b3Smrg            if(token != NUMBER_TOKEN) {
3603da084b3Smrg                skipEndOfLine(f,c);
3613da084b3Smrg                return ERROR_LINE;
3623da084b3Smrg            }
3633da084b3Smrg            value1 = number_value;
3643da084b3Smrg            /* optional second integer */
3653da084b3Smrg            token = gettoken(f,c,&c);
3663da084b3Smrg            if(token == EOL_TOKEN) {
3673da084b3Smrg                value2 = value1;
3683da084b3Smrg                return CODE_UNDEFINE_LINE;
3693da084b3Smrg            } else if(token == NUMBER_TOKEN) {
3703da084b3Smrg                value2 = number_value;
3713da084b3Smrg                if(endOfLine(f,c)) {
3723da084b3Smrg                    return CODE_UNDEFINE_LINE;
3733da084b3Smrg                } else
3743da084b3Smrg                    return ERROR_LINE;
3753da084b3Smrg            } else {
3763da084b3Smrg                skipEndOfLine(f,c);
3773da084b3Smrg                return ERROR_LINE;
3783da084b3Smrg            }
3793da084b3Smrg        } else if(!strcasecmp(keyword_value, "ENDENCODING")) {
3803da084b3Smrg            if(endOfLine(f,c))
3813da084b3Smrg                return EOF_LINE;
3823da084b3Smrg            else
3833da084b3Smrg                return ERROR_LINE;
3843da084b3Smrg        } else if(!strcasecmp(keyword_value, "ENDMAPPING")) {
3853da084b3Smrg            if(endOfLine(f,c))
3863da084b3Smrg                return ENDMAPPING_LINE;
3873da084b3Smrg            else
3883da084b3Smrg                return ERROR_LINE;
3893da084b3Smrg        } else {
3903da084b3Smrg            skipEndOfLine(f,c);
3913da084b3Smrg            return ERROR_LINE;
3923da084b3Smrg        }
3933da084b3Smrg    default:
3943da084b3Smrg        return ERROR_LINE;
3953da084b3Smrg    }
3963da084b3Smrg}
3973da084b3Smrg
3983da084b3Smrgstatic void
3993da084b3Smrginstall_mapping(FontEncPtr encoding, FontMapPtr mapping)
4003da084b3Smrg{
4013da084b3Smrg    FontMapPtr m;
4023da084b3Smrg
4033da084b3Smrg    if(encoding->mappings == NULL)
4043da084b3Smrg        encoding->mappings = mapping;
4053da084b3Smrg    else {
4063da084b3Smrg        m = encoding->mappings;
4073da084b3Smrg        while(m->next != NULL)
4083da084b3Smrg            m = m->next;
4093da084b3Smrg        m->next = mapping;
4103da084b3Smrg    }
4113da084b3Smrg    mapping->next = NULL;
4123da084b3Smrg    mapping->encoding = encoding;
4133da084b3Smrg}
4143da084b3Smrg
4153da084b3Smrgstatic int
4163da084b3SmrgsetCode(unsigned from, unsigned to, unsigned row_size,
4173da084b3Smrg        unsigned *first, unsigned *last,
4183da084b3Smrg        unsigned *encsize, unsigned short **enc)
4193da084b3Smrg{
4203da084b3Smrg    unsigned index, i;
4213da084b3Smrg    unsigned short *newenc;
4223da084b3Smrg
4233da084b3Smrg    if(from>0xFFFF)
4243da084b3Smrg        return 0;               /* success */
4253da084b3Smrg
4263da084b3Smrg    if(row_size==0)
4273da084b3Smrg        index=from;
4283da084b3Smrg    else {
4293da084b3Smrg        if((value1 & 0xFF) >= row_size)
4303da084b3Smrg            return 0;           /* ignore out of range mappings */
4313da084b3Smrg        index = (from>>8) * row_size + (from&0xFF);
4323da084b3Smrg    }
4333da084b3Smrg
4343da084b3Smrg    /* Optimize away useless identity mappings.  This is only expected
4353da084b3Smrg       to be useful with linear encodings. */
4363da084b3Smrg    if(index == to && (index < *first || index > *last))
4373da084b3Smrg        return 0;
4383da084b3Smrg    if(*encsize == 0) {
4393da084b3Smrg        *encsize = (index < 256) ? 256 : 0x10000;
4403da084b3Smrg        *enc = (unsigned short*)xalloc((*encsize) * sizeof(unsigned short));
4413da084b3Smrg        if(*enc == NULL) {
4423da084b3Smrg            *encsize = 0;
4433da084b3Smrg            return 1;
4443da084b3Smrg        }
4453da084b3Smrg    } else if(*encsize <= index) {
4463da084b3Smrg        *encsize = 0x10000;
4473da084b3Smrg        if((newenc = (unsigned short*)xrealloc(enc, *encsize))==NULL)
4483da084b3Smrg            return 1;
4493da084b3Smrg        *enc = newenc;
4503da084b3Smrg    }
4513da084b3Smrg    if(*first > *last) {
4523da084b3Smrg        *first = *last = index;
4533da084b3Smrg    }
4543da084b3Smrg    if(index < *first) {
4553da084b3Smrg        for(i = index; i < *first; i++)
4563da084b3Smrg            (*enc)[i] = i;
4573da084b3Smrg        *first = index;
4583da084b3Smrg    }
4593da084b3Smrg    if(index > *last) {
4603da084b3Smrg        for(i = *last + 1; i <= index; i++)
4613da084b3Smrg            (*enc)[i] = i;
4623da084b3Smrg        *last = index;
4633da084b3Smrg    }
4643da084b3Smrg    (*enc)[index] = to;
4653da084b3Smrg    return 0;
4663da084b3Smrg}
4673da084b3Smrg
4683da084b3Smrg/* Parser.  If headerOnly is true, we're only interested in the
4693da084b3Smrg   data contained in the encoding file's header. */
4703da084b3Smrg
4713da084b3Smrg/* As font encodings are currently never freed, the allocations done
4723da084b3Smrg   by this function are mostly its private business.  Note, however,
4733da084b3Smrg   that FontEncIdentify needs to free the header fields -- so if you
4743da084b3Smrg   change this function, you may need to change FontEncIdentify. */
4753da084b3Smrg
4763da084b3Smrg/* I want a garbage collector. */
4773da084b3Smrg
4783da084b3Smrgstatic FontEncPtr
4793da084b3SmrgparseEncodingFile(FontFilePtr f, int headerOnly)
4803da084b3Smrg{
4813da084b3Smrg    int line;
4823da084b3Smrg
4833da084b3Smrg    unsigned short *enc=NULL;
4843da084b3Smrg    char **nam = NULL, **newnam;
4853da084b3Smrg    unsigned i, first = 0xFFFF, last=0, encsize=0, namsize=0;
4863da084b3Smrg    FontEncPtr encoding = NULL;
4873da084b3Smrg    FontMapPtr mapping = NULL;
4883da084b3Smrg    FontEncSimpleMapPtr sm;
4893da084b3Smrg    FontEncSimpleNamePtr sn;
4903da084b3Smrg    char *aliases[MAXALIASES];
4913da084b3Smrg    int numaliases=0;
4923da084b3Smrg
4933da084b3Smrg#if 0
4943da084b3Smrg    /* GCC complains about unused labels.  Please fix GCC rather than
4953da084b3Smrg       obfuscating my code. */
4963da084b3Smrg  no_encoding:
4973da084b3Smrg#endif
4983da084b3Smrg    line = getnextline(f);
4993da084b3Smrg    switch(line) {
5003da084b3Smrg    case EOF_LINE:
5013da084b3Smrg        goto error;
5023da084b3Smrg    case STARTENCODING_LINE:
5033da084b3Smrg        encoding = (FontEncPtr)xalloc(sizeof(FontEncRec));
5043da084b3Smrg        if(encoding == NULL)
5053da084b3Smrg            goto error;
5063da084b3Smrg        encoding->name = (char*)xalloc(strlen(keyword_value)+1);
5073da084b3Smrg        if(encoding->name == NULL)
5083da084b3Smrg            goto error;
5093da084b3Smrg        strcpy(encoding->name, keyword_value);
5103da084b3Smrg        encoding->size = 256;
5113da084b3Smrg        encoding->row_size = 0;
5123da084b3Smrg        encoding->mappings = NULL;
5133da084b3Smrg        encoding->next = NULL;
5143da084b3Smrg        encoding->first = encoding->first_col=0;
5153da084b3Smrg        goto no_mapping;
5163da084b3Smrg    default:
5173da084b3Smrg        goto error;
5183da084b3Smrg    }
5193da084b3Smrg
5203da084b3Smrg  no_mapping:
5213da084b3Smrg    line = getnextline(f);
5223da084b3Smrg    switch(line) {
5233da084b3Smrg    case EOF_LINE: goto done;
5243da084b3Smrg    case ALIAS_LINE:
5253da084b3Smrg        if(numaliases < MAXALIASES) {
5263da084b3Smrg            aliases[numaliases] = (char*)xalloc(strlen(keyword_value)+1);
5273da084b3Smrg            if(aliases[numaliases] == NULL)
5283da084b3Smrg                goto error;
5293da084b3Smrg            strcpy(aliases[numaliases], keyword_value);
5303da084b3Smrg            numaliases++;
5313da084b3Smrg        }
5323da084b3Smrg        goto no_mapping;
5333da084b3Smrg    case SIZE_LINE:
5343da084b3Smrg        encoding->size = value1;
5353da084b3Smrg        encoding->row_size = value2;
5363da084b3Smrg        goto no_mapping;
5373da084b3Smrg    case FIRSTINDEX_LINE:
5383da084b3Smrg        encoding->first = value1;
5393da084b3Smrg        encoding->first_col = value2;
5403da084b3Smrg        goto no_mapping;
5413da084b3Smrg    case STARTMAPPING_LINE:
5423da084b3Smrg        if(headerOnly)
5433da084b3Smrg            goto done;
5443da084b3Smrg        if(!strcasecmp(keyword_value, "unicode")) {
5453da084b3Smrg            mapping = (FontMapPtr)xalloc(sizeof(FontMapRec));
5463da084b3Smrg            if(mapping == NULL)
5473da084b3Smrg                goto error;
5483da084b3Smrg            mapping->type = FONT_ENCODING_UNICODE;
5493da084b3Smrg            mapping->pid = 0;
5503da084b3Smrg            mapping->eid = 0;
5513da084b3Smrg            mapping->recode = NULL;
5523da084b3Smrg            mapping->name = NULL;
5533da084b3Smrg            mapping->client_data = NULL;
5543da084b3Smrg            mapping->next = NULL;
5553da084b3Smrg            goto mapping;
5563da084b3Smrg        } else if(!strcasecmp(keyword_value, "cmap")) {
5573da084b3Smrg            mapping = (FontMapPtr)xalloc(sizeof(FontMapRec));
5583da084b3Smrg            if(mapping == NULL)
5593da084b3Smrg                goto error;
5603da084b3Smrg            mapping->type = FONT_ENCODING_TRUETYPE;
5613da084b3Smrg            mapping->pid = value1;
5623da084b3Smrg            mapping->eid = value2;
5633da084b3Smrg            mapping->recode = NULL;
5643da084b3Smrg            mapping->name = NULL;
5653da084b3Smrg            mapping->client_data = NULL;
5663da084b3Smrg            mapping->next = NULL;
5673da084b3Smrg            goto mapping;
5683da084b3Smrg        } else if(!strcasecmp(keyword_value, "postscript")) {
5693da084b3Smrg            mapping = (FontMapPtr)xalloc(sizeof(FontMapRec));
5703da084b3Smrg            if(mapping == NULL)
5713da084b3Smrg                goto error;
5723da084b3Smrg            mapping->type = FONT_ENCODING_POSTSCRIPT;
5733da084b3Smrg            mapping->pid = 0;
5743da084b3Smrg            mapping->eid = 0;
5753da084b3Smrg            mapping->recode = NULL;
5763da084b3Smrg            mapping->name = NULL;
5773da084b3Smrg            mapping->client_data = NULL;
5783da084b3Smrg            mapping->next = NULL;
5793da084b3Smrg            goto string_mapping;
5803da084b3Smrg        } else {                /* unknown mapping type -- ignore */
5813da084b3Smrg            goto skipmapping;
5823da084b3Smrg        }
5833da084b3Smrg        /* NOTREACHED */
5843da084b3Smrg        goto error;
5853da084b3Smrg    default: goto no_mapping;   /* ignore unknown lines */
5863da084b3Smrg    }
5873da084b3Smrg
5883da084b3Smrg  skipmapping:
5893da084b3Smrg    line = getnextline(f);
5903da084b3Smrg    switch(line) {
5913da084b3Smrg    case ENDMAPPING_LINE:
5923da084b3Smrg        goto no_mapping;
5933da084b3Smrg    case EOF_LINE:
5943da084b3Smrg        goto error;
5953da084b3Smrg    default:
5963da084b3Smrg        goto skipmapping;
5973da084b3Smrg    }
5983da084b3Smrg
5993da084b3Smrg  mapping:
6003da084b3Smrg    line = getnextline(f);
6013da084b3Smrg    switch(line) {
6023da084b3Smrg    case EOF_LINE: goto error;
6033da084b3Smrg    case ENDMAPPING_LINE:
6043da084b3Smrg        mapping->recode = FontEncSimpleRecode;
6053da084b3Smrg        mapping->name = FontEncUndefinedName;
6063da084b3Smrg        mapping->client_data = sm =
6073da084b3Smrg            (FontEncSimpleMapPtr)xalloc(sizeof(FontEncSimpleMapRec));
6083da084b3Smrg        if(sm == NULL)
6093da084b3Smrg            goto error;
6103da084b3Smrg        sm->row_size = encoding->row_size;
6113da084b3Smrg        if(first <= last) {
6123da084b3Smrg            unsigned short *newmap;
6133da084b3Smrg
6143da084b3Smrg            sm->first = first;
6153da084b3Smrg            sm->len=last-first+1;
6163da084b3Smrg            newmap =
6173da084b3Smrg                (unsigned short*)xalloc(sm->len * sizeof(unsigned short));
6183da084b3Smrg            if(newmap == NULL) {
6193da084b3Smrg                xfree(sm);
6203da084b3Smrg                mapping->client_data = sm = NULL;
6213da084b3Smrg                goto error;
6223da084b3Smrg            }
6233da084b3Smrg	    for(i=0; i < sm->len; i++)
6243da084b3Smrg		newmap[i] = enc[first+i];
6253da084b3Smrg	    sm->map = newmap;
6263da084b3Smrg        } else {
6273da084b3Smrg            sm->first = 0;
6283da084b3Smrg            sm->len = 0;
6293da084b3Smrg            sm->map = NULL;
6303da084b3Smrg        }
6313da084b3Smrg        install_mapping(encoding, mapping);
6323da084b3Smrg        mapping = NULL;
6333da084b3Smrg        first = 0xFFFF; last=0;
6343da084b3Smrg        goto no_mapping;
6353da084b3Smrg
6363da084b3Smrg    case CODE_LINE:
6373da084b3Smrg        if(setCode(value1, value2, encoding->row_size,
6383da084b3Smrg                   &first, &last, &encsize, &enc))
6393da084b3Smrg            goto error;
6403da084b3Smrg        goto mapping;
6413da084b3Smrg
6423da084b3Smrg    case CODE_RANGE_LINE:
6433da084b3Smrg        if(value1 > 0x10000)
6443da084b3Smrg            value1 = 0x10000;
6453da084b3Smrg        if(value2 > 0x10000)
6463da084b3Smrg            value2 = 0x10000;
6473da084b3Smrg        if(value2 < value1)
6483da084b3Smrg            goto mapping;
6493da084b3Smrg        /* Do the last value first to avoid having to realloc() */
6503da084b3Smrg        if(setCode(value2, value3+(value2-value1), encoding->row_size,
6513da084b3Smrg                   &first, &last, &encsize, &enc))
6523da084b3Smrg            goto error;
6533da084b3Smrg        for(i=value1; i<value2; i++) {
6543da084b3Smrg            if(setCode(i, value3+(i-value1), encoding->row_size,
6553da084b3Smrg                       &first, &last, &encsize, &enc))
6563da084b3Smrg                goto error;
6573da084b3Smrg        }
6583da084b3Smrg        goto mapping;
6593da084b3Smrg
6603da084b3Smrg    case CODE_UNDEFINE_LINE:
6613da084b3Smrg        if(value1 > 0x10000)
6623da084b3Smrg            value1 = 0x10000;
6633da084b3Smrg        if(value2 > 0x10000)
6643da084b3Smrg            value2 = 0x10000;
6653da084b3Smrg        if(value2 < value1)
6663da084b3Smrg            goto mapping;
6673da084b3Smrg        /* Do the last value first to avoid having to realloc() */
6683da084b3Smrg        if(setCode(value2, 0, encoding->row_size,
6693da084b3Smrg                   &first, &last, &encsize, &enc))
6703da084b3Smrg            goto error;
6713da084b3Smrg        for(i = value1; i < value2; i++) {
6723da084b3Smrg            if(setCode(i, 0, encoding->row_size,
6733da084b3Smrg                       &first, &last, &encsize, &enc))
6743da084b3Smrg                goto error;
6753da084b3Smrg        }
6763da084b3Smrg        goto mapping;
6773da084b3Smrg
6783da084b3Smrg    default: goto mapping;      /* ignore unknown lines */
6793da084b3Smrg    }
6803da084b3Smrg
6813da084b3Smrg  string_mapping:
6823da084b3Smrg    line = getnextline(f);
6833da084b3Smrg    switch(line) {
6843da084b3Smrg    case EOF_LINE: goto error;
6853da084b3Smrg    case ENDMAPPING_LINE:
6863da084b3Smrg        mapping->recode = FontEncUndefinedRecode;
6873da084b3Smrg        mapping->name = FontEncSimpleName;
6883da084b3Smrg        mapping->client_data = sn =
6893da084b3Smrg            (FontEncSimpleNamePtr)xalloc(sizeof(FontEncSimpleNameRec));
6903da084b3Smrg        if(sn == NULL)
6913da084b3Smrg            goto error;
6923da084b3Smrg        if(first > last) {
6933da084b3Smrg            xfree(sn);
6943da084b3Smrg            mapping->client_data = sn = NULL;
6953da084b3Smrg            goto error;
6963da084b3Smrg        }
6973da084b3Smrg        sn->first = first;
6983da084b3Smrg        sn->len = last - first + 1;
6993da084b3Smrg        sn->map = (char**)xalloc(sn->len*sizeof(char*));
7003da084b3Smrg        if(sn->map == NULL) {
7013da084b3Smrg            xfree(sn);
7023da084b3Smrg            mapping->client_data = sn = NULL;
7033da084b3Smrg            goto error;
7043da084b3Smrg        }
7053da084b3Smrg        for(i = 0; i < sn->len; i++)
7063da084b3Smrg            sn->map[i] = nam[first+i];
7073da084b3Smrg        install_mapping(encoding,mapping);
7083da084b3Smrg        mapping = NULL;
7093da084b3Smrg        first = 0xFFFF; last=0;
7103da084b3Smrg        goto no_mapping;
7113da084b3Smrg    case NAME_LINE:
7123da084b3Smrg        if(value1 >= 0x10000) goto string_mapping;
7133da084b3Smrg        if(namsize == 0) {
7143da084b3Smrg            namsize = (value1) < 256 ? 256 : 0x10000;
7153da084b3Smrg            nam = (char**)xalloc(namsize * sizeof(char*));
7163da084b3Smrg            if(nam == NULL) {
7173da084b3Smrg                namsize=0;
7183da084b3Smrg                goto error;
7193da084b3Smrg            }
7203da084b3Smrg        } else if(namsize <= value1) {
7213da084b3Smrg            namsize = 0x10000;
7223da084b3Smrg            if((newnam = (char**)xrealloc(nam, namsize)) == NULL)
7233da084b3Smrg                goto error;
7243da084b3Smrg            nam = newnam;
7253da084b3Smrg        }
7263da084b3Smrg        if(first > last) {
7273da084b3Smrg            first = last = value1;
7283da084b3Smrg        }
7293da084b3Smrg        if(value1 < first) {
7303da084b3Smrg            for(i = value1; i < first; i++)
7313da084b3Smrg                nam[i] = NULL;
7323da084b3Smrg            first = value1;
7333da084b3Smrg        }
7343da084b3Smrg        if(value1 > last) {
7353da084b3Smrg            for(i=last+1; i <= value1; i++)
7363da084b3Smrg                nam[i]=NULL;
7373da084b3Smrg            last = value1;
7383da084b3Smrg        }
7393da084b3Smrg        nam[value1] = (char*)xalloc(strlen(keyword_value)+1);
7403da084b3Smrg        if(nam[value1] == NULL) {
7413da084b3Smrg            goto error;
7423da084b3Smrg        }
7433da084b3Smrg        strcpy(nam[value1], keyword_value);
7443da084b3Smrg        goto string_mapping;
7453da084b3Smrg
7463da084b3Smrg    default: goto string_mapping; /* ignore unknown lines */
7473da084b3Smrg    }
7483da084b3Smrg
7493da084b3Smrg  done:
7503da084b3Smrg    if(encsize) xfree(enc); encsize=0; enc = NULL;
7513da084b3Smrg    if(namsize) xfree(nam); namsize=0; nam = NULL; /* don't free entries! */
7523da084b3Smrg
7533da084b3Smrg    encoding->aliases=NULL;
7543da084b3Smrg    if(numaliases) {
7553da084b3Smrg        encoding->aliases = (char**)xalloc((numaliases+1)*sizeof(char*));
7563da084b3Smrg        if(encoding->aliases == NULL)
7573da084b3Smrg            goto error;
7583da084b3Smrg        for(i=0; i<numaliases; i++)
7593da084b3Smrg            encoding->aliases[i] = aliases[i];
7603da084b3Smrg        encoding->aliases[numaliases]=NULL;
7613da084b3Smrg    }
7623da084b3Smrg
7633da084b3Smrg    return encoding;
7643da084b3Smrg
7653da084b3Smrgerror:
7663da084b3Smrg    if(encsize) xfree(enc); encsize=0;
7673da084b3Smrg    if(namsize) {
7683da084b3Smrg        for(i = first; i <= last; i++)
7693da084b3Smrg            if(nam[i])
7703da084b3Smrg                xfree(nam[i]);
7713da084b3Smrg        xfree(nam);
7723da084b3Smrg        namsize = 0;
7733da084b3Smrg    }
7743da084b3Smrg    if(mapping) {
7753da084b3Smrg        if(mapping->client_data) xfree(mapping->client_data);
7763da084b3Smrg        xfree(mapping);
7773da084b3Smrg    }
7783da084b3Smrg    if(encoding) {
7793da084b3Smrg	FontMapPtr nextmap;
7803da084b3Smrg	if (encoding->name) xfree(encoding->name);
7813da084b3Smrg	for (mapping = encoding->mappings; mapping; mapping = nextmap) {
7823da084b3Smrg	    if (mapping->client_data) xfree(mapping->client_data);
7833da084b3Smrg	    nextmap = mapping->next;
7843da084b3Smrg	    xfree(mapping);
7853da084b3Smrg	}
7863da084b3Smrg	xfree(encoding);
7873da084b3Smrg    }
7883da084b3Smrg    for(i = 0; i < numaliases; i++)
7893da084b3Smrg        xfree(aliases[i]);
7903da084b3Smrg    /* We don't need to free sn and sm as they handled locally in the body.*/
7913da084b3Smrg    return NULL;
7923da084b3Smrg}
7933da084b3Smrg
7943da084b3Smrgchar*
7953da084b3SmrgFontEncDirectory(void)
7963da084b3Smrg{
7973da084b3Smrg    static char* dir = NULL;
7983da084b3Smrg
7993da084b3Smrg    if(dir == NULL) {
8003da084b3Smrg        char *c = getenv("FONT_ENCODINGS_DIRECTORY");
8013da084b3Smrg        if(c) {
8023da084b3Smrg            dir = malloc(strlen(c) + 1);
8033da084b3Smrg            if(!dir)
8043da084b3Smrg                return NULL;
8053da084b3Smrg            strcpy(dir, c);
8063da084b3Smrg        } else {
8073da084b3Smrg            dir = FONT_ENCODINGS_DIRECTORY;
8083da084b3Smrg        }
8093da084b3Smrg    }
8103da084b3Smrg    return dir;
8113da084b3Smrg}
8123da084b3Smrg
8133da084b3Smrgstatic void
8143da084b3SmrgparseFontFileName(const char *fontFileName, char *buf, char *dir)
8153da084b3Smrg{
8163da084b3Smrg    const char *p;
8173da084b3Smrg    char *q, *lastslash;
8183da084b3Smrg
8193da084b3Smrg    for(p = fontFileName, q = dir, lastslash = NULL; *p; p++, q++) {
8203da084b3Smrg        *q = *p;
8213da084b3Smrg        if(*p == '/')
8223da084b3Smrg            lastslash = q+1;
8233da084b3Smrg    }
8243da084b3Smrg
8253da084b3Smrg    if(!lastslash)
8263da084b3Smrg        lastslash = dir;
8273da084b3Smrg
8283da084b3Smrg    *lastslash = '\0';
8293da084b3Smrg
8303da084b3Smrg    if(buf && strlen(dir) + 14 < MAXFONTFILENAMELEN) {
8313da084b3Smrg        strcpy(buf, dir);
8323da084b3Smrg        strcat(buf, "encodings.dir");
8333da084b3Smrg    }
8343da084b3Smrg}
8353da084b3Smrg
8363da084b3Smrgstatic FontEncPtr
8373da084b3SmrgFontEncReallyReallyLoad(const char *charset,
8383da084b3Smrg                        const char *dirname, const char *dir)
8393da084b3Smrg{
8403da084b3Smrg    FontFilePtr f;
8413da084b3Smrg    FILE *file;
8423da084b3Smrg    FontEncPtr encoding;
8433da084b3Smrg    char file_name[MAXFONTFILENAMELEN], encoding_name[MAXFONTNAMELEN],
8443da084b3Smrg        buf[MAXFONTFILENAMELEN];
8453da084b3Smrg    int count, n;
8463da084b3Smrg    static char format[24] = "";
8473da084b3Smrg
8483da084b3Smrg    /* As we don't really expect to open encodings that often, we don't
8493da084b3Smrg       take the trouble of caching encodings directories. */
8503da084b3Smrg
8513da084b3Smrg    if((file = fopen(dirname, "r")) == NULL) {
8523da084b3Smrg        return NULL;
8533da084b3Smrg    }
8543da084b3Smrg
8553da084b3Smrg    count = fscanf(file, "%d\n", &n);
8563da084b3Smrg    if(count == EOF || count != 1) {
8573da084b3Smrg        fclose(file);
8583da084b3Smrg        return NULL;
8593da084b3Smrg    }
8603da084b3Smrg
8613da084b3Smrg    encoding = NULL;
8623da084b3Smrg    if (!format[0]) {
8633da084b3Smrg	sprintf(format, "%%%ds %%%d[^\n]\n", (int)sizeof(encoding_name) - 1,
8643da084b3Smrg		(int)sizeof(file_name) - 1);
8653da084b3Smrg    }
8663da084b3Smrg    for(;;) {
8673da084b3Smrg        count = fscanf(file, format, encoding_name, file_name);
8683da084b3Smrg        if(count == EOF)
8693da084b3Smrg            break;
8703da084b3Smrg        if(count != 2)
8713da084b3Smrg            break;
8723da084b3Smrg
8733da084b3Smrg        if(!strcasecmp(encoding_name, charset)) {
8743da084b3Smrg            /* Found it */
8753da084b3Smrg            if(file_name[0] != '/') {
8763da084b3Smrg                if(strlen(dir) + strlen(file_name) >= MAXFONTFILENAMELEN) {
8773da084b3Smrg		    fclose(file);
8783da084b3Smrg                    return NULL;
8793da084b3Smrg		}
8803da084b3Smrg                strcpy(buf, dir);
8813da084b3Smrg                strcat(buf, file_name);
8823da084b3Smrg            } else {
8833da084b3Smrg                strcpy(buf , file_name);
8843da084b3Smrg            }
8853da084b3Smrg
8863da084b3Smrg            f = FontFileOpen(buf);
8873da084b3Smrg            if(f == NULL) {
8883da084b3Smrg		fclose(file);
8893da084b3Smrg                return NULL;
8903da084b3Smrg            }
8913da084b3Smrg            encoding = parseEncodingFile(f, 0);
8923da084b3Smrg            FontFileClose(f);
8933da084b3Smrg            break;
8943da084b3Smrg        }
8953da084b3Smrg    }
8963da084b3Smrg
8973da084b3Smrg    fclose(file);
8983da084b3Smrg
8993da084b3Smrg    return encoding;
9003da084b3Smrg}
9013da084b3Smrg
9023da084b3Smrg/* Parser ntrypoint -- used by FontEncLoad */
9033da084b3SmrgFontEncPtr
9043da084b3SmrgFontEncReallyLoad(const char *charset, const char *fontFileName)
9053da084b3Smrg{
9063da084b3Smrg    FontEncPtr encoding;
9073da084b3Smrg    char dir[MAXFONTFILENAMELEN], dirname[MAXFONTFILENAMELEN];
9083da084b3Smrg    char *d;
9093da084b3Smrg
9103da084b3Smrg    if(fontFileName) {
9113da084b3Smrg        parseFontFileName(fontFileName, dirname, dir);
9123da084b3Smrg        encoding = FontEncReallyReallyLoad(charset, dirname, dir);
9133da084b3Smrg        if(encoding)
9143da084b3Smrg            return(encoding);
9153da084b3Smrg    }
9163da084b3Smrg
9173da084b3Smrg    d = FontEncDirectory();
9183da084b3Smrg    if(d) {
9193da084b3Smrg        parseFontFileName(d, NULL, dir);
9203da084b3Smrg        encoding = FontEncReallyReallyLoad(charset, d, dir);
9213da084b3Smrg        return encoding;
9223da084b3Smrg    }
9233da084b3Smrg
9243da084b3Smrg    return NULL;
9253da084b3Smrg}
9263da084b3Smrg
9273da084b3Smrg/* Return a NULL-terminated array of encoding names.  Note that this
9283da084b3Smrg * function has incestuous knowledge of the allocations done by
9293da084b3Smrg * parseEncodingFile. */
9303da084b3Smrg
9313da084b3Smrgchar **
9323da084b3SmrgFontEncIdentify(const char *fileName)
9333da084b3Smrg{
9343da084b3Smrg    FontFilePtr f;
9353da084b3Smrg    FontEncPtr encoding;
9363da084b3Smrg    char **names, **name, **alias;
9373da084b3Smrg    int numaliases;
9383da084b3Smrg
9393da084b3Smrg    if((f = FontFileOpen(fileName))==NULL) {
9403da084b3Smrg        return NULL;
9413da084b3Smrg    }
9423da084b3Smrg    encoding = parseEncodingFile(f, 1);
9433da084b3Smrg    FontFileClose(f);
9443da084b3Smrg
9453da084b3Smrg    if(!encoding)
9463da084b3Smrg        return NULL;
9473da084b3Smrg
9483da084b3Smrg    numaliases = 0;
9493da084b3Smrg    if(encoding->aliases)
9503da084b3Smrg        for(alias = encoding->aliases; *alias; alias++)
9513da084b3Smrg            numaliases++;
9523da084b3Smrg
9533da084b3Smrg    names = (char**)xalloc((numaliases+2)*sizeof(char*));
9543da084b3Smrg    if(names == NULL) {
9553da084b3Smrg        if(encoding->aliases)
9563da084b3Smrg            xfree(encoding->aliases);
9573da084b3Smrg        xfree(encoding);
9583da084b3Smrg        return NULL;
9593da084b3Smrg    }
9603da084b3Smrg
9613da084b3Smrg    name = names;
9623da084b3Smrg    *(name++) = encoding->name;
9633da084b3Smrg    if(numaliases > 0)
9643da084b3Smrg    for(alias = encoding->aliases; *alias; alias++, name++)
9653da084b3Smrg        *name = *alias;
9663da084b3Smrg
9673da084b3Smrg    *name = NULL;
9683da084b3Smrg    xfree(encoding->aliases);
9693da084b3Smrg    xfree(encoding);
9703da084b3Smrg
9713da084b3Smrg    return names;
9723da084b3Smrg}
973