1ea6ae205Smrg/*
2ea6ae205Smrg  Copyright (c) 2003 by Juliusz Chroboczek
3ea6ae205Smrg
4ea6ae205Smrg  Permission is hereby granted, free of charge, to any person obtaining a copy
5ea6ae205Smrg  of this software and associated documentation files (the "Software"), to deal
6ea6ae205Smrg  in the Software without restriction, including without limitation the rights
7ea6ae205Smrg  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8ea6ae205Smrg  copies of the Software, and to permit persons to whom the Software is
9ea6ae205Smrg  furnished to do so, subject to the following conditions:
10ea6ae205Smrg
11ea6ae205Smrg  The above copyright notice and this permission notice shall be included in
12ea6ae205Smrg  all copies or substantial portions of the Software.
13ea6ae205Smrg
14ea6ae205Smrg  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15ea6ae205Smrg  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16ea6ae205Smrg  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17ea6ae205Smrg  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18ea6ae205Smrg  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19ea6ae205Smrg  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20ea6ae205Smrg  THE SOFTWARE.
21ea6ae205Smrg*/
22ca74b209Smrg/*
236ae2c069Smrg * Copyright (c) 2008, Oracle and/or its affiliates.
247978d3cdSmrg *
257978d3cdSmrg * Permission is hereby granted, free of charge, to any person obtaining a
26ca74b209Smrg * copy of this software and associated documentation files (the "Software"),
27ca74b209Smrg * to deal in the Software without restriction, including without limitation
28ca74b209Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29ca74b209Smrg * and/or sell copies of the Software, and to permit persons to whom the
30ca74b209Smrg * Software is furnished to do so, subject to the following conditions:
317978d3cdSmrg *
32ca74b209Smrg * The above copyright notice and this permission notice (including the next
33ca74b209Smrg * paragraph) shall be included in all copies or substantial portions of the
34ca74b209Smrg * Software.
357978d3cdSmrg *
36ca74b209Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37ca74b209Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38ca74b209Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
39ca74b209Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40ca74b209Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
41ca74b209Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
42ca74b209Smrg * DEALINGS IN THE SOFTWARE.
43ca74b209Smrg */
44ea6ae205Smrg
45ea6ae205Smrg/* The function identifyBitmap returns -1 if filename is definitively not
46ea6ae205Smrg   a font file, 1 if it is a single-face bitmap font with a XLFD name,
47ea6ae205Smrg   and 0 if it should be processed normally.  identifyBitmap is
48ea6ae205Smrg   much faster than parsing the whole font. */
49ea6ae205Smrg
5045a6f659Smrg#ifdef HAVE_CONFIG_H
517978d3cdSmrg#include "config.h"
5245a6f659Smrg#endif
537978d3cdSmrg
54ea6ae205Smrg#include <stdlib.h>
55ea6ae205Smrg#include <string.h>
56ea6ae205Smrg#include "zlib.h"
57ea6ae205Smrg#include "ident.h"
58ea6ae205Smrg
597978d3cdSmrg#ifdef X_BZIP2_FONT_COMPRESSION
606ae2c069Smrg#include <bzlib.h>
617978d3cdSmrg#endif
627978d3cdSmrg
63ea6ae205Smrg#define PCF_VERSION (('p'<<24)|('c'<<16)|('f'<<8)|1)
64ea6ae205Smrg#define PCF_PROPERTIES (1 << 0)
65ea6ae205Smrg
66ea6ae205Smrgtypedef struct _Prop {
67ea6ae205Smrg    unsigned name;
68ea6ae205Smrg    int isString;
69ea6ae205Smrg    unsigned value;
70ea6ae205Smrg} PropRec, *PropPtr;
71ea6ae205Smrg
727978d3cdSmrg#ifdef X_BZIP2_FONT_COMPRESSION
737978d3cdSmrgtypedef struct {
747978d3cdSmrg    enum { gzFontFile, bz2FontFile } type;
757978d3cdSmrg    union {
766ae2c069Smrg        gzFile gz;
776ae2c069Smrg        BZFILE *bz2;
787978d3cdSmrg    } f;
797c5a9b20Smrg    unsigned long pos;
807978d3cdSmrg} fontFile;
817978d3cdSmrg
827978d3cdSmrgstatic inline void *
836ae2c069SmrgfontFileOpen(fontFile *ff, const char *filename)
846ae2c069Smrg{
857c5a9b20Smrg    size_t n = strlen(filename);
867978d3cdSmrg
87eaa89f16Smrg    if (n > 4 && strcmp(filename + n - 4, ".bz2") == 0) {
886ae2c069Smrg        ff->type = bz2FontFile;
896ae2c069Smrg        ff->f.bz2 = BZ2_bzopen(filename, "rb");
906ae2c069Smrg        ff->pos = 0;
916ae2c069Smrg        return ff->f.bz2;
926ae2c069Smrg    }
936ae2c069Smrg    else {
946ae2c069Smrg        ff->type = gzFontFile;
956ae2c069Smrg        ff->f.gz = gzopen(filename, "rb");
966ae2c069Smrg        return ff->f.gz;
977978d3cdSmrg    }
987978d3cdSmrg}
997978d3cdSmrg
1007978d3cdSmrgstatic inline int
1017978d3cdSmrgfontFileRead(fontFile *ff, void *buf, unsigned len)
1027978d3cdSmrg{
1037978d3cdSmrg    if (ff->type == gzFontFile) {
1046ae2c069Smrg        return gzread(ff->f.gz, buf, len);
1056ae2c069Smrg    }
1066ae2c069Smrg    else {
1076ae2c069Smrg        int r = BZ2_bzread(ff->f.bz2, buf, len);
1086ae2c069Smrg
1096ae2c069Smrg        ff->pos += r;
1106ae2c069Smrg        return r;
1117978d3cdSmrg    }
1127978d3cdSmrg}
1137978d3cdSmrg
1147978d3cdSmrgstatic inline int
1157978d3cdSmrgfontFileGetc(fontFile *ff)
1167978d3cdSmrg{
1177978d3cdSmrg    if (ff->type == gzFontFile) {
1186ae2c069Smrg        return gzgetc(ff->f.gz);
1196ae2c069Smrg    }
1206ae2c069Smrg    else {
1216ae2c069Smrg        char buf;
1226ae2c069Smrg
1236ae2c069Smrg        if (BZ2_bzread(ff->f.bz2, &buf, 1) != 1) {
1246ae2c069Smrg            return -1;
1256ae2c069Smrg        }
1266ae2c069Smrg        else {
1276ae2c069Smrg            ff->pos += 1;
1286ae2c069Smrg            return (int) buf;
1296ae2c069Smrg        }
1307978d3cdSmrg    }
1317978d3cdSmrg}
1327978d3cdSmrg
1337c5a9b20Smrgstatic long
1347978d3cdSmrgfontFileSeek(fontFile *ff, z_off_t offset, int whence)
1357978d3cdSmrg{
1367978d3cdSmrg    if (ff->type == gzFontFile) {
1376ae2c069Smrg        return gzseek(ff->f.gz, offset, whence);
1387978d3cdSmrg    }
1396ae2c069Smrg    else {
1406ae2c069Smrg        /* bzlib has no easy equivalent so we have to fake it,
1416ae2c069Smrg         * fortunately, we only have to handle a couple of cases
1426ae2c069Smrg         */
1436ae2c069Smrg        z_off_t n;
1446ae2c069Smrg        char buf[BUFSIZ];
1456ae2c069Smrg
1466ae2c069Smrg        switch (whence) {
1476ae2c069Smrg        case SEEK_SET:
1486ae2c069Smrg            n = offset - ff->pos;
1496ae2c069Smrg            break;
1506ae2c069Smrg        case SEEK_CUR:
1516ae2c069Smrg            n = offset;
1526ae2c069Smrg            break;
1536ae2c069Smrg        default:
1546ae2c069Smrg            return -1;
1556ae2c069Smrg        }
1567978d3cdSmrg
1576ae2c069Smrg        while (n > BUFSIZ) {
1586ae2c069Smrg            if (BZ2_bzread(ff->f.bz2, buf, BUFSIZ) != BUFSIZ)
1596ae2c069Smrg                return -1;
1606ae2c069Smrg            n -= BUFSIZ;
1616ae2c069Smrg        }
1626ae2c069Smrg        if (BZ2_bzread(ff->f.bz2, buf, (int) n) != n)
1636ae2c069Smrg            return -1;
1646ae2c069Smrg        ff->pos = offset;
1656ae2c069Smrg        return offset;
1666ae2c069Smrg    }
1676ae2c069Smrg}
1687978d3cdSmrg
1697978d3cdSmrgstatic inline int
1707978d3cdSmrgfontFileClose(fontFile *ff)
1717978d3cdSmrg{
1727978d3cdSmrg    if (ff->type == gzFontFile) {
1736ae2c069Smrg        return gzclose(ff->f.gz);
1746ae2c069Smrg    }
1756ae2c069Smrg    else {
1766ae2c069Smrg        BZ2_bzclose(ff->f.bz2);
1776ae2c069Smrg        return 0;
1787978d3cdSmrg    }
1797978d3cdSmrg}
1807978d3cdSmrg
1816ae2c069Smrg#else                           /* no bzip2, only gzip */
1827978d3cdSmrgtypedef gzFile fontFile;
1836ae2c069Smrg
1846ae2c069Smrg#define fontFileOpen(ff, filename)	(*(ff) = gzopen(filename, "rb"))
1856ae2c069Smrg#define fontFileRead(ff, buf, len)	gzread(*(ff), buf, len)
1866ae2c069Smrg#define fontFileGetc(ff)		gzgetc(*(ff))
1876ae2c069Smrg#define fontFileSeek(ff, off, whence)	gzseek(*(ff), off, whence)
1886ae2c069Smrg#define fontFileClose(ff)		gzclose(*(ff))
1897978d3cdSmrg#endif
1907978d3cdSmrg
1917978d3cdSmrgstatic int pcfIdentify(fontFile *f, char **name);
1927978d3cdSmrgstatic int bdfIdentify(fontFile *f, char **name);
193ea6ae205Smrg
194ea6ae205Smrgstatic int
1957978d3cdSmrggetLSB32(fontFile *f)
196ea6ae205Smrg{
197ea6ae205Smrg    int rc;
198ea6ae205Smrg    unsigned char c[4];
199ea6ae205Smrg
2007978d3cdSmrg    rc = fontFileRead(f, c, 4);
2016ae2c069Smrg    if (rc != 4)
202ea6ae205Smrg        return -1;
203ea6ae205Smrg    return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
204ea6ae205Smrg}
205ea6ae205Smrg
206ea6ae205Smrgstatic int
2077978d3cdSmrggetInt8(fontFile *f, int format)
208ea6ae205Smrg{
209ea6ae205Smrg    unsigned char c;
210ea6ae205Smrg    int rc;
211ea6ae205Smrg
2127978d3cdSmrg    rc = fontFileRead(f, &c, 1);
2136ae2c069Smrg    if (rc != 1)
214ea6ae205Smrg        return -1;
215ea6ae205Smrg    return c;
216ea6ae205Smrg}
217ea6ae205Smrg
218ea6ae205Smrgstatic int
2197978d3cdSmrggetInt32(fontFile *f, int format)
220ea6ae205Smrg{
221ea6ae205Smrg    int rc;
222ea6ae205Smrg    unsigned char c[4];
223ea6ae205Smrg
2247978d3cdSmrg    rc = fontFileRead(f, c, 4);
2256ae2c069Smrg    if (rc != 4)
226ea6ae205Smrg        return -1;
2276ae2c069Smrg    else {
2286ae2c069Smrg        unsigned int u[4] = { c[0], c[1], c[2], c[3] };
229ea6ae205Smrg
2306ae2c069Smrg        if (format & (1 << 2)) {
2316ae2c069Smrg            return (int) ((u[0] << 24) | (u[1] << 16) | (u[2] << 8) | (u[3]));
2326ae2c069Smrg        }
2336ae2c069Smrg        else {
2346ae2c069Smrg            return (int) ((u[0]) | (u[1] << 8) | (u[2] << 16) | (u[3] << 24));
2356ae2c069Smrg        }
236ea6ae205Smrg    }
237ea6ae205Smrg}
238ea6ae205Smrg
239a5c37dfeSmrgint
2407978d3cdSmrgbitmapIdentify(const char *filename, char **name)
241ea6ae205Smrg{
2427978d3cdSmrg    fontFile ff;
243ea6ae205Smrg    int magic;
244ea6ae205Smrg
2457978d3cdSmrg    if (fontFileOpen(&ff, filename) == NULL)
2466ae2c069Smrg        return -1;
247ea6ae205Smrg
2487978d3cdSmrg    magic = getLSB32(&ff);
2496ae2c069Smrg    if (magic == PCF_VERSION)
2507978d3cdSmrg        return pcfIdentify(&ff, name);
2516ae2c069Smrg    else if (magic == ('S' | ('T' << 8) | ('A' << 16) | ('R') << 24))
2527978d3cdSmrg        return bdfIdentify(&ff, name);
253ea6ae205Smrg
2547978d3cdSmrg    fontFileClose(&ff);
255ea6ae205Smrg    return 0;
256ea6ae205Smrg}
257ea6ae205Smrg
258ea6ae205Smrgstatic int
2597978d3cdSmrgpcfIdentify(fontFile *f, char **name)
260ea6ae205Smrg{
261ea6ae205Smrg    int prop_position;
262ea6ae205Smrg    PropPtr props = NULL;
2637c5a9b20Smrg    int format, count, nprops, i, string_size;
2647c5a9b20Smrg    long rc;
265ea6ae205Smrg    char *strings = NULL, *s;
266ea6ae205Smrg
267ea6ae205Smrg    count = getLSB32(f);
2686ae2c069Smrg    if (count <= 0)
269ea6ae205Smrg        goto fail;
270ea6ae205Smrg
271ea6ae205Smrg    prop_position = -1;
2726ae2c069Smrg    for (i = 0; i < count; i++) {
273ea6ae205Smrg        int type, offset;
2746ae2c069Smrg
275ea6ae205Smrg        type = getLSB32(f);
276ea6ae205Smrg        (void) getLSB32(f);
277ea6ae205Smrg        (void) getLSB32(f);
278ea6ae205Smrg        offset = getLSB32(f);
2796ae2c069Smrg        if (type == PCF_PROPERTIES) {
280ea6ae205Smrg            prop_position = offset;
281ea6ae205Smrg            break;
282ea6ae205Smrg        }
283ea6ae205Smrg    }
2846ae2c069Smrg    if (prop_position < 0)
285ea6ae205Smrg        goto fail;
286ea6ae205Smrg
2877978d3cdSmrg    rc = fontFileSeek(f, prop_position, SEEK_SET);
2886ae2c069Smrg    if (rc < 0)
289ea6ae205Smrg        goto fail;
290a5c37dfeSmrg
291ea6ae205Smrg    format = getLSB32(f);
2926ae2c069Smrg    if ((format & 0xFFFFFF00) != 0)
293ea6ae205Smrg        goto fail;
294ea6ae205Smrg    nprops = getInt32(f, format);
2956ae2c069Smrg    if (nprops <= 0 || nprops > 1000)
296ea6ae205Smrg        goto fail;
297ea6ae205Smrg    props = malloc(nprops * sizeof(PropRec));
2986ae2c069Smrg    if (props == NULL)
299ea6ae205Smrg        goto fail;
300ea6ae205Smrg
3016ae2c069Smrg    for (i = 0; i < nprops; i++) {
302ea6ae205Smrg        props[i].name = getInt32(f, format);
303ea6ae205Smrg        props[i].isString = getInt8(f, format);
304ea6ae205Smrg        props[i].value = getInt32(f, format);
305ea6ae205Smrg    }
3066ae2c069Smrg    if (nprops & 3) {
3076ae2c069Smrg        rc = fontFileSeek(f, 4 - (nprops & 3), SEEK_CUR);
3086ae2c069Smrg        if (rc < 0)
309ea6ae205Smrg            goto fail;
310ea6ae205Smrg    }
311ea6ae205Smrg
312ea6ae205Smrg    string_size = getInt32(f, format);
3136ae2c069Smrg    if (string_size < 0 || string_size > 100000)
314ea6ae205Smrg        goto fail;
315ea6ae205Smrg    strings = malloc(string_size);
3166ae2c069Smrg    if (!strings)
317ea6ae205Smrg        goto fail;
318ea6ae205Smrg
3197978d3cdSmrg    rc = fontFileRead(f, strings, string_size);
3206ae2c069Smrg    if (rc != string_size)
321ea6ae205Smrg        goto fail;
322ea6ae205Smrg
3236ae2c069Smrg    for (i = 0; i < nprops; i++) {
3246ae2c069Smrg        if (!props[i].isString ||
3256ae2c069Smrg            props[i].name >= string_size - 4 || props[i].value >= string_size)
326ea6ae205Smrg            continue;
3276ae2c069Smrg        if (strcmp(strings + props[i].name, "FONT") == 0)
328ea6ae205Smrg            break;
329ea6ae205Smrg    }
330ea6ae205Smrg
3316ae2c069Smrg    if (i >= nprops)
332ea6ae205Smrg        goto fail;
333ea6ae205Smrg
3342d6e8b77Smrg    s = strdup(strings + props[i].value);
3356ae2c069Smrg    if (s == NULL)
336ea6ae205Smrg        goto fail;
337ea6ae205Smrg    *name = s;
338ea6ae205Smrg    free(strings);
339ea6ae205Smrg    free(props);
3407978d3cdSmrg    fontFileClose(f);
341ea6ae205Smrg    return 1;
342ea6ae205Smrg
343ea6ae205Smrg fail:
3446ae2c069Smrg    if (strings)
3456ae2c069Smrg        free(strings);
3466ae2c069Smrg    if (props)
3476ae2c069Smrg        free(props);
3487978d3cdSmrg    fontFileClose(f);
349ea6ae205Smrg    return 0;
350ea6ae205Smrg}
351ea6ae205Smrg
352ea6ae205Smrg#define NKEY 20
353ea6ae205Smrg
3546ae2c069Smrgstatic char *
3557978d3cdSmrggetKeyword(fontFile *f, int *eol)
356ea6ae205Smrg{
357ea6ae205Smrg    static char keyword[NKEY + 1];
3586ae2c069Smrg    int i = 0;
3596ae2c069Smrg
3606ae2c069Smrg    while (i < NKEY) {
3616ae2c069Smrg        int c = fontFileGetc(f);
3626ae2c069Smrg        if (c == ' ' || c == '\n') {
3636ae2c069Smrg            if (i <= 0)
364ea6ae205Smrg                return NULL;
3656ae2c069Smrg            if (eol)
366ea6ae205Smrg                *eol = (c == '\n');
367ea6ae205Smrg            keyword[i] = '\0';
368ea6ae205Smrg            return keyword;
369ea6ae205Smrg        }
3706ae2c069Smrg        if (c < 'A' || c > 'Z')
371ea6ae205Smrg            return NULL;
372ea6ae205Smrg        keyword[i++] = c;
373ea6ae205Smrg    }
374ea6ae205Smrg    return NULL;
375ea6ae205Smrg}
376ea6ae205Smrg
377ea6ae205Smrgstatic int
3787978d3cdSmrgbdfskip(fontFile *f)
379ea6ae205Smrg{
380ea6ae205Smrg    int c;
3816ae2c069Smrg
382ea6ae205Smrg    do {
3837978d3cdSmrg        c = fontFileGetc(f);
3846ae2c069Smrg    } while (c >= 0 && c != '\n');
3856ae2c069Smrg    if (c < 0)
386ea6ae205Smrg        return -1;
387ea6ae205Smrg    return 1;
388ea6ae205Smrg}
389ea6ae205Smrg
390ea6ae205Smrgstatic char *
3917978d3cdSmrgbdfend(fontFile *f)
392ea6ae205Smrg{
393ea6ae205Smrg    int c;
394ea6ae205Smrg    char *buf = NULL;
3956ae2c069Smrg    size_t bufsize = 0;
3966ae2c069Smrg    unsigned int i = 0;
397ea6ae205Smrg
398ea6ae205Smrg    do {
3997978d3cdSmrg        c = fontFileGetc(f);
400ea6ae205Smrg    } while (c == ' ');
401ea6ae205Smrg
4026ae2c069Smrg    while (i < 1000) {
4036ae2c069Smrg        if (c < 0 || (c == '\n' && i == 0)) {
404ea6ae205Smrg            goto fail;
405ea6ae205Smrg        }
4066ae2c069Smrg        if (bufsize < i + 1) {
407ea6ae205Smrg            char *newbuf;
4086ae2c069Smrg
4096ae2c069Smrg            if (bufsize == 0) {
410ea6ae205Smrg                bufsize = 20;
411ea6ae205Smrg                newbuf = malloc(bufsize);
4126ae2c069Smrg            }
4136ae2c069Smrg            else {
414ea6ae205Smrg                bufsize = 2 * bufsize;
415ea6ae205Smrg                newbuf = realloc(buf, bufsize);
416ea6ae205Smrg            }
4176ae2c069Smrg            if (newbuf == NULL)
418ea6ae205Smrg                goto fail;
419ea6ae205Smrg            buf = newbuf;
420ea6ae205Smrg        }
4216ae2c069Smrg        if (c == '\n') {
422ea6ae205Smrg            buf[i] = '\0';
423ea6ae205Smrg            return buf;
424ea6ae205Smrg        }
425ea6ae205Smrg        buf[i++] = c;
4267978d3cdSmrg        c = fontFileGetc(f);
427ea6ae205Smrg    }
428ea6ae205Smrg
429ea6ae205Smrg fail:
4306ae2c069Smrg    if (buf)
431ea6ae205Smrg        free(buf);
432ea6ae205Smrg    return NULL;
433ea6ae205Smrg}
434ea6ae205Smrg
435ea6ae205Smrgstatic int
4367978d3cdSmrgbdfIdentify(fontFile *f, char **name)
437ea6ae205Smrg{
438ea6ae205Smrg    char *k;
439ea6ae205Smrg    int eol;
4406ae2c069Smrg
441ea6ae205Smrg    /* bitmapIdentify already read "STAR", so we need to check for
442ea6ae205Smrg       "TFONT" */
443ea6ae205Smrg    k = getKeyword(f, &eol);
4446ae2c069Smrg    if (k == NULL || eol)
445ea6ae205Smrg        goto fail;
4466ae2c069Smrg    if (strcmp(k, "TFONT") != 0)
447ea6ae205Smrg        goto fail;
4486ae2c069Smrg    while (1) {
4496ae2c069Smrg        if (!eol) {
4506ae2c069Smrg            int rc = bdfskip(f);
4516ae2c069Smrg            if (rc < 0)
452ea6ae205Smrg                goto fail;
453ea6ae205Smrg        }
454ea6ae205Smrg        k = getKeyword(f, &eol);
4556ae2c069Smrg        if (k == NULL)
456ea6ae205Smrg            goto fail;
4576ae2c069Smrg        else if (strcmp(k, "FONT") == 0) {
4586ae2c069Smrg            if (eol)
459ea6ae205Smrg                goto fail;
460ea6ae205Smrg            k = bdfend(f);
4616ae2c069Smrg            if (k == NULL)
462ea6ae205Smrg                goto fail;
463ea6ae205Smrg            *name = k;
4647978d3cdSmrg            fontFileClose(f);
465ea6ae205Smrg            return 1;
4666ae2c069Smrg        }
4676ae2c069Smrg        else if (strcmp(k, "CHARS") == 0)
468ea6ae205Smrg            goto fail;
469ea6ae205Smrg    }
470ea6ae205Smrg fail:
4717978d3cdSmrg    fontFileClose(f);
472ea6ae205Smrg    return 0;
473ea6ae205Smrg}
474