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