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