ident.c revision eaa89f16
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/*
23ca74b209Smrg * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
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
607978d3cdSmrg# 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 {
767978d3cdSmrg	gzFile gz;
777978d3cdSmrg	BZFILE *bz2;
787978d3cdSmrg    } f;
797978d3cdSmrg    unsigned pos;
807978d3cdSmrg} fontFile;
817978d3cdSmrg
827978d3cdSmrgstatic inline void *
837978d3cdSmrgfontFileOpen(fontFile *ff, const char *filename) {
847978d3cdSmrg    int n = strlen(filename);
857978d3cdSmrg
86eaa89f16Smrg    if (n > 4 && strcmp(filename + n - 4, ".bz2") == 0) {
877978d3cdSmrg	ff->type = bz2FontFile;
887978d3cdSmrg	ff->f.bz2 = BZ2_bzopen(filename, "rb");
897978d3cdSmrg	ff->pos = 0;
907978d3cdSmrg	return ff->f.bz2;
917978d3cdSmrg    } else {
927978d3cdSmrg	ff->type = gzFontFile;
937978d3cdSmrg	ff->f.gz = gzopen(filename, "rb");
947978d3cdSmrg	return ff->f.gz;
957978d3cdSmrg    }
967978d3cdSmrg}
977978d3cdSmrg
987978d3cdSmrgstatic inline int
997978d3cdSmrgfontFileRead(fontFile *ff, void *buf, unsigned len)
1007978d3cdSmrg{
1017978d3cdSmrg    if (ff->type == gzFontFile) {
1027978d3cdSmrg	return gzread(ff->f.gz, buf, len);
1037978d3cdSmrg    } else {
1047978d3cdSmrg	int r = BZ2_bzread(ff->f.bz2, buf, len);
1057978d3cdSmrg	ff->pos += r;
1067978d3cdSmrg	return r;
1077978d3cdSmrg    }
1087978d3cdSmrg}
1097978d3cdSmrg
1107978d3cdSmrgstatic inline int
1117978d3cdSmrgfontFileGetc(fontFile *ff)
1127978d3cdSmrg{
1137978d3cdSmrg    if (ff->type == gzFontFile) {
1147978d3cdSmrg	return gzgetc(ff->f.gz);
1157978d3cdSmrg    } else {
1167978d3cdSmrg	char buf;
1177978d3cdSmrg	if (BZ2_bzread(ff->f.bz2, &buf, 1) != 1) {
1187978d3cdSmrg	    return -1;
1197978d3cdSmrg	} else {
1207978d3cdSmrg	    ff->pos += 1;
1217978d3cdSmrg	    return (int) buf;
1227978d3cdSmrg	}
1237978d3cdSmrg    }
1247978d3cdSmrg}
1257978d3cdSmrg
1267978d3cdSmrgstatic int
1277978d3cdSmrgfontFileSeek(fontFile *ff, z_off_t offset, int whence)
1287978d3cdSmrg{
1297978d3cdSmrg    if (ff->type == gzFontFile) {
1307978d3cdSmrg	return gzseek(ff->f.gz, offset, whence);
1317978d3cdSmrg    } else {
1327978d3cdSmrg	/* bzlib has no easy equivalent so we have to fake it,
1337978d3cdSmrg	 * fortunately, we only have to handle a couple of cases
1347978d3cdSmrg	 */
1357978d3cdSmrg	int n;
1367978d3cdSmrg	char buf[BUFSIZ];
1377978d3cdSmrg
1387978d3cdSmrg	switch (whence) {
1397978d3cdSmrg	  case SEEK_SET:
1407978d3cdSmrg	    n = offset - ff->pos;
1417978d3cdSmrg	    break;
1427978d3cdSmrg	  case SEEK_CUR:
1437978d3cdSmrg	    n = offset;
1447978d3cdSmrg	    break;
1457978d3cdSmrg	  default:
1467978d3cdSmrg	    return -1;
147a5c37dfeSmrg	}
148a5c37dfeSmrg
1497978d3cdSmrg	while (n > BUFSIZ) {
1507978d3cdSmrg	    if (BZ2_bzread(ff->f.bz2, buf, BUFSIZ) != BUFSIZ)
1517978d3cdSmrg		return -1;
1527978d3cdSmrg	    n -= BUFSIZ;
1537978d3cdSmrg	}
1547978d3cdSmrg	if (BZ2_bzread(ff->f.bz2, buf, n) != n)
1557978d3cdSmrg	    return -1;
1567978d3cdSmrg	ff->pos = offset;
1577978d3cdSmrg	return offset;
1587978d3cdSmrg    }
1597978d3cdSmrg}
1607978d3cdSmrg
1617978d3cdSmrg
1627978d3cdSmrgstatic inline int
1637978d3cdSmrgfontFileClose(fontFile *ff)
1647978d3cdSmrg{
1657978d3cdSmrg    if (ff->type == gzFontFile) {
1667978d3cdSmrg	return gzclose(ff->f.gz);
1677978d3cdSmrg    } else {
1687978d3cdSmrg	BZ2_bzclose(ff->f.bz2);
1697978d3cdSmrg	return 0;
1707978d3cdSmrg    }
1717978d3cdSmrg}
1727978d3cdSmrg
1737978d3cdSmrg#else /* no bzip2, only gzip */
1747978d3cdSmrgtypedef gzFile fontFile;
1757978d3cdSmrg# define fontFileOpen(ff, filename)	(*(ff) = gzopen(filename, "rb"))
1767978d3cdSmrg# define fontFileRead(ff, buf, len)	gzread(*(ff), buf, len)
1777978d3cdSmrg# define fontFileGetc(ff)		gzgetc(*(ff))
1787978d3cdSmrg# define fontFileSeek(ff, off, whence)	gzseek(*(ff), off, whence)
1797978d3cdSmrg# define fontFileClose(ff)		gzclose(*(ff))
1807978d3cdSmrg#endif
1817978d3cdSmrg
1827978d3cdSmrgstatic int pcfIdentify(fontFile *f, char **name);
1837978d3cdSmrgstatic int bdfIdentify(fontFile *f, char **name);
184ea6ae205Smrg
185ea6ae205Smrgstatic int
1867978d3cdSmrggetLSB32(fontFile *f)
187ea6ae205Smrg{
188ea6ae205Smrg    int rc;
189ea6ae205Smrg    unsigned char c[4];
190ea6ae205Smrg
1917978d3cdSmrg    rc = fontFileRead(f, c, 4);
192ea6ae205Smrg    if(rc != 4)
193ea6ae205Smrg        return -1;
194ea6ae205Smrg    return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
195ea6ae205Smrg}
196ea6ae205Smrg
197ea6ae205Smrgstatic int
1987978d3cdSmrggetInt8(fontFile *f, int format)
199ea6ae205Smrg{
200ea6ae205Smrg    unsigned char c;
201ea6ae205Smrg    int rc;
202ea6ae205Smrg
2037978d3cdSmrg    rc = fontFileRead(f, &c, 1);
204ea6ae205Smrg    if(rc != 1)
205ea6ae205Smrg        return -1;
206ea6ae205Smrg    return c;
207ea6ae205Smrg}
208ea6ae205Smrg
209ea6ae205Smrgstatic int
2107978d3cdSmrggetInt32(fontFile *f, int format)
211ea6ae205Smrg{
212ea6ae205Smrg    int rc;
213ea6ae205Smrg    unsigned char c[4];
214ea6ae205Smrg
2157978d3cdSmrg    rc = fontFileRead(f, c, 4);
216ea6ae205Smrg    if(rc != 4)
217ea6ae205Smrg        return -1;
218ea6ae205Smrg
219ea6ae205Smrg    if(format & (1 << 2)) {
220ea6ae205Smrg        return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3]);
221ea6ae205Smrg    } else {
222ea6ae205Smrg        return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
223ea6ae205Smrg    }
224ea6ae205Smrg}
225ea6ae205Smrg
226a5c37dfeSmrgint
2277978d3cdSmrgbitmapIdentify(const char *filename, char **name)
228ea6ae205Smrg{
2297978d3cdSmrg    fontFile ff;
230ea6ae205Smrg    int magic;
231ea6ae205Smrg
2327978d3cdSmrg    if (fontFileOpen(&ff, filename) == NULL)
2337978d3cdSmrg	return -1;
234ea6ae205Smrg
2357978d3cdSmrg    magic = getLSB32(&ff);
236ea6ae205Smrg    if(magic == PCF_VERSION)
2377978d3cdSmrg        return pcfIdentify(&ff, name);
238ea6ae205Smrg    else if(magic == ('S' | ('T' << 8) | ('A' << 16) | ('R') << 24))
2397978d3cdSmrg        return bdfIdentify(&ff, name);
240ea6ae205Smrg
2417978d3cdSmrg    fontFileClose(&ff);
242ea6ae205Smrg    return 0;
243ea6ae205Smrg}
244ea6ae205Smrg
245ea6ae205Smrgstatic int
2467978d3cdSmrgpcfIdentify(fontFile *f, char **name)
247ea6ae205Smrg{
248ea6ae205Smrg    int prop_position;
249ea6ae205Smrg    PropPtr props = NULL;
250ea6ae205Smrg    int format, count, nprops, i, string_size, rc;
251ea6ae205Smrg    char *strings = NULL, *s;
252ea6ae205Smrg
253ea6ae205Smrg    count = getLSB32(f);
254ea6ae205Smrg    if(count <= 0)
255ea6ae205Smrg        goto fail;
256ea6ae205Smrg
257ea6ae205Smrg    prop_position = -1;
258ea6ae205Smrg    for(i = 0; i < count; i++) {
259ea6ae205Smrg        int type, offset;
260ea6ae205Smrg        type = getLSB32(f);
261ea6ae205Smrg        (void) getLSB32(f);
262ea6ae205Smrg        (void) getLSB32(f);
263ea6ae205Smrg        offset = getLSB32(f);
264ea6ae205Smrg        if(type == PCF_PROPERTIES) {
265ea6ae205Smrg            prop_position = offset;
266ea6ae205Smrg            break;
267ea6ae205Smrg        }
268ea6ae205Smrg    }
269ea6ae205Smrg    if(prop_position < 0)
270ea6ae205Smrg        goto fail;
271ea6ae205Smrg
2727978d3cdSmrg    rc = fontFileSeek(f, prop_position, SEEK_SET);
273ea6ae205Smrg    if(rc < 0)
274ea6ae205Smrg        goto fail;
275a5c37dfeSmrg
276ea6ae205Smrg    format = getLSB32(f);
277ea6ae205Smrg    if((format & 0xFFFFFF00) != 0)
278ea6ae205Smrg        goto fail;
279ea6ae205Smrg    nprops = getInt32(f, format);
280ea6ae205Smrg    if(nprops <= 0 || nprops > 1000)
281ea6ae205Smrg        goto fail;
282ea6ae205Smrg    props = malloc(nprops * sizeof(PropRec));
283ea6ae205Smrg    if(props == NULL)
284ea6ae205Smrg        goto fail;
285ea6ae205Smrg
286ea6ae205Smrg    for(i = 0; i < nprops; i++) {
287ea6ae205Smrg        props[i].name = getInt32(f, format);
288ea6ae205Smrg        props[i].isString = getInt8(f, format);
289ea6ae205Smrg        props[i].value = getInt32(f, format);
290ea6ae205Smrg    }
291ea6ae205Smrg    if(nprops & 3) {
2927978d3cdSmrg	rc = fontFileSeek(f, 4 - (nprops & 3), SEEK_CUR);
293ea6ae205Smrg        if(rc < 0)
294ea6ae205Smrg            goto fail;
295ea6ae205Smrg    }
296ea6ae205Smrg
297ea6ae205Smrg    string_size = getInt32(f, format);
298ea6ae205Smrg    if(string_size < 0 || string_size > 100000)
299ea6ae205Smrg        goto fail;
300ea6ae205Smrg    strings = malloc(string_size);
301ea6ae205Smrg    if(!strings)
302ea6ae205Smrg        goto fail;
303ea6ae205Smrg
3047978d3cdSmrg    rc = fontFileRead(f, strings, string_size);
305ea6ae205Smrg    if(rc != string_size)
306ea6ae205Smrg        goto fail;
307ea6ae205Smrg
308ea6ae205Smrg    for(i = 0; i < nprops; i++) {
309ea6ae205Smrg        if(!props[i].isString ||
310ea6ae205Smrg           props[i].name >= string_size - 4 ||
311ea6ae205Smrg           props[i].value >= string_size)
312ea6ae205Smrg            continue;
313ea6ae205Smrg        if(strcmp(strings + props[i].name, "FONT") == 0)
314ea6ae205Smrg            break;
315ea6ae205Smrg    }
316ea6ae205Smrg
317ea6ae205Smrg    if(i >= nprops)
318ea6ae205Smrg        goto fail;
319ea6ae205Smrg
3202d6e8b77Smrg    s = strdup(strings + props[i].value);
321ea6ae205Smrg    if(s == NULL)
322ea6ae205Smrg        goto fail;
323ea6ae205Smrg    *name = s;
324ea6ae205Smrg    free(strings);
325ea6ae205Smrg    free(props);
3267978d3cdSmrg    fontFileClose(f);
327ea6ae205Smrg    return 1;
328ea6ae205Smrg
329ea6ae205Smrg fail:
330ea6ae205Smrg    if(strings) free(strings);
331ea6ae205Smrg    if(props) free(props);
3327978d3cdSmrg    fontFileClose(f);
333ea6ae205Smrg    return 0;
334ea6ae205Smrg}
335ea6ae205Smrg
336ea6ae205Smrg#define NKEY 20
337ea6ae205Smrg
338ea6ae205Smrgstatic char*
3397978d3cdSmrggetKeyword(fontFile *f, int *eol)
340ea6ae205Smrg{
341ea6ae205Smrg    static char keyword[NKEY + 1];
342ea6ae205Smrg    int c, i;
343ea6ae205Smrg    i = 0;
344ea6ae205Smrg    while(i < NKEY) {
3457978d3cdSmrg        c = fontFileGetc(f);
346ea6ae205Smrg        if(c == ' ' || c == '\n') {
347ea6ae205Smrg            if(i <= 0)
348ea6ae205Smrg                return NULL;
349ea6ae205Smrg            if(eol)
350ea6ae205Smrg                *eol = (c == '\n');
351ea6ae205Smrg            keyword[i] = '\0';
352ea6ae205Smrg            return keyword;
353ea6ae205Smrg        }
354ea6ae205Smrg        if(c < 'A' || c > 'Z')
355ea6ae205Smrg            return NULL;
356ea6ae205Smrg        keyword[i++] = c;
357ea6ae205Smrg    }
358ea6ae205Smrg    return NULL;
359ea6ae205Smrg}
360ea6ae205Smrg
361ea6ae205Smrgstatic int
3627978d3cdSmrgbdfskip(fontFile *f)
363ea6ae205Smrg{
364ea6ae205Smrg    int c;
365ea6ae205Smrg    do {
3667978d3cdSmrg        c = fontFileGetc(f);
367ea6ae205Smrg    } while(c >= 0 && c != '\n');
368ea6ae205Smrg    if(c < 0)
369ea6ae205Smrg        return -1;
370ea6ae205Smrg    return 1;
371ea6ae205Smrg}
372ea6ae205Smrg
373ea6ae205Smrgstatic char *
3747978d3cdSmrgbdfend(fontFile *f)
375ea6ae205Smrg{
376ea6ae205Smrg    int c;
377ea6ae205Smrg    char *buf = NULL;
378ea6ae205Smrg    int bufsize = 0;
379ea6ae205Smrg    int i = 0;
380ea6ae205Smrg
381ea6ae205Smrg    do {
3827978d3cdSmrg        c = fontFileGetc(f);
383ea6ae205Smrg    } while (c == ' ');
384ea6ae205Smrg
385ea6ae205Smrg    while(i < 1000) {
386ea6ae205Smrg        if(c < 0 || (c == '\n' && i == 0)) {
387ea6ae205Smrg            goto fail;
388ea6ae205Smrg        }
389ea6ae205Smrg        if(bufsize < i + 1) {
390ea6ae205Smrg            char *newbuf;
391ea6ae205Smrg            if(bufsize == 0) {
392ea6ae205Smrg                bufsize = 20;
393ea6ae205Smrg                newbuf = malloc(bufsize);
394ea6ae205Smrg            } else {
395ea6ae205Smrg                bufsize = 2 * bufsize;
396ea6ae205Smrg                newbuf = realloc(buf, bufsize);
397ea6ae205Smrg            }
398ea6ae205Smrg            if(newbuf == NULL)
399ea6ae205Smrg                goto fail;
400ea6ae205Smrg            buf = newbuf;
401ea6ae205Smrg        }
402ea6ae205Smrg        if(c == '\n') {
403ea6ae205Smrg            buf[i] = '\0';
404ea6ae205Smrg            return buf;
405ea6ae205Smrg        }
406ea6ae205Smrg        buf[i++] = c;
4077978d3cdSmrg        c = fontFileGetc(f);
408ea6ae205Smrg    }
409ea6ae205Smrg
410ea6ae205Smrg fail:
411ea6ae205Smrg    if(buf)
412ea6ae205Smrg        free(buf);
413ea6ae205Smrg    return NULL;
414ea6ae205Smrg}
415ea6ae205Smrg
416ea6ae205Smrgstatic int
4177978d3cdSmrgbdfIdentify(fontFile *f, char **name)
418ea6ae205Smrg{
419ea6ae205Smrg    char *k;
420ea6ae205Smrg    int rc;
421ea6ae205Smrg    int eol;
422ea6ae205Smrg    /* bitmapIdentify already read "STAR", so we need to check for
423ea6ae205Smrg       "TFONT" */
424ea6ae205Smrg    k = getKeyword(f, &eol);
425ea6ae205Smrg    if(k == NULL || eol)
426ea6ae205Smrg        goto fail;
427ea6ae205Smrg    if(strcmp(k, "TFONT") != 0)
428ea6ae205Smrg        goto fail;
429ea6ae205Smrg    while(1) {
430ea6ae205Smrg        if(!eol) {
431ea6ae205Smrg            rc = bdfskip(f);
432a5c37dfeSmrg            if(rc < 0)
433ea6ae205Smrg                goto fail;
434ea6ae205Smrg        }
435ea6ae205Smrg        k = getKeyword(f, &eol);
436ea6ae205Smrg        if(k == NULL)
437ea6ae205Smrg            goto fail;
438ea6ae205Smrg        else if(strcmp(k, "FONT") == 0) {
439ea6ae205Smrg            if(eol)
440ea6ae205Smrg                goto fail;
441ea6ae205Smrg            k = bdfend(f);
442ea6ae205Smrg            if(k == NULL)
443ea6ae205Smrg                goto fail;
444ea6ae205Smrg            *name = k;
4457978d3cdSmrg            fontFileClose(f);
446ea6ae205Smrg            return 1;
447ea6ae205Smrg        } else if(strcmp(k, "CHARS") == 0)
448ea6ae205Smrg            goto fail;
449ea6ae205Smrg    }
450ea6ae205Smrg fail:
4517978d3cdSmrg    fontFileClose(f);
452ea6ae205Smrg    return 0;
453ea6ae205Smrg}
454