ident.c revision 7c5a9b20
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;
797c5a9b20Smrg    unsigned long pos;
807978d3cdSmrg} fontFile;
817978d3cdSmrg
827978d3cdSmrgstatic inline void *
837978d3cdSmrgfontFileOpen(fontFile *ff, const char *filename) {
847c5a9b20Smrg    size_t 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
1267c5a9b20Smrgstatic long
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	 */
1357c5a9b20Smrg	z_off_t 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	}
1547c5a9b20Smrg	if (BZ2_bzread(ff->f.bz2, buf, (int) 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;
2507c5a9b20Smrg    int format, count, nprops, i, string_size;
2517c5a9b20Smrg    long rc;
252ea6ae205Smrg    char *strings = NULL, *s;
253ea6ae205Smrg
254ea6ae205Smrg    count = getLSB32(f);
255ea6ae205Smrg    if(count <= 0)
256ea6ae205Smrg        goto fail;
257ea6ae205Smrg
258ea6ae205Smrg    prop_position = -1;
259ea6ae205Smrg    for(i = 0; i < count; i++) {
260ea6ae205Smrg        int type, offset;
261ea6ae205Smrg        type = getLSB32(f);
262ea6ae205Smrg        (void) getLSB32(f);
263ea6ae205Smrg        (void) getLSB32(f);
264ea6ae205Smrg        offset = getLSB32(f);
265ea6ae205Smrg        if(type == PCF_PROPERTIES) {
266ea6ae205Smrg            prop_position = offset;
267ea6ae205Smrg            break;
268ea6ae205Smrg        }
269ea6ae205Smrg    }
270ea6ae205Smrg    if(prop_position < 0)
271ea6ae205Smrg        goto fail;
272ea6ae205Smrg
2737978d3cdSmrg    rc = fontFileSeek(f, prop_position, SEEK_SET);
274ea6ae205Smrg    if(rc < 0)
275ea6ae205Smrg        goto fail;
276a5c37dfeSmrg
277ea6ae205Smrg    format = getLSB32(f);
278ea6ae205Smrg    if((format & 0xFFFFFF00) != 0)
279ea6ae205Smrg        goto fail;
280ea6ae205Smrg    nprops = getInt32(f, format);
281ea6ae205Smrg    if(nprops <= 0 || nprops > 1000)
282ea6ae205Smrg        goto fail;
283ea6ae205Smrg    props = malloc(nprops * sizeof(PropRec));
284ea6ae205Smrg    if(props == NULL)
285ea6ae205Smrg        goto fail;
286ea6ae205Smrg
287ea6ae205Smrg    for(i = 0; i < nprops; i++) {
288ea6ae205Smrg        props[i].name = getInt32(f, format);
289ea6ae205Smrg        props[i].isString = getInt8(f, format);
290ea6ae205Smrg        props[i].value = getInt32(f, format);
291ea6ae205Smrg    }
292ea6ae205Smrg    if(nprops & 3) {
2937978d3cdSmrg	rc = fontFileSeek(f, 4 - (nprops & 3), SEEK_CUR);
294ea6ae205Smrg        if(rc < 0)
295ea6ae205Smrg            goto fail;
296ea6ae205Smrg    }
297ea6ae205Smrg
298ea6ae205Smrg    string_size = getInt32(f, format);
299ea6ae205Smrg    if(string_size < 0 || string_size > 100000)
300ea6ae205Smrg        goto fail;
301ea6ae205Smrg    strings = malloc(string_size);
302ea6ae205Smrg    if(!strings)
303ea6ae205Smrg        goto fail;
304ea6ae205Smrg
3057978d3cdSmrg    rc = fontFileRead(f, strings, string_size);
306ea6ae205Smrg    if(rc != string_size)
307ea6ae205Smrg        goto fail;
308ea6ae205Smrg
309ea6ae205Smrg    for(i = 0; i < nprops; i++) {
310ea6ae205Smrg        if(!props[i].isString ||
311ea6ae205Smrg           props[i].name >= string_size - 4 ||
312ea6ae205Smrg           props[i].value >= string_size)
313ea6ae205Smrg            continue;
314ea6ae205Smrg        if(strcmp(strings + props[i].name, "FONT") == 0)
315ea6ae205Smrg            break;
316ea6ae205Smrg    }
317ea6ae205Smrg
318ea6ae205Smrg    if(i >= nprops)
319ea6ae205Smrg        goto fail;
320ea6ae205Smrg
3212d6e8b77Smrg    s = strdup(strings + props[i].value);
322ea6ae205Smrg    if(s == NULL)
323ea6ae205Smrg        goto fail;
324ea6ae205Smrg    *name = s;
325ea6ae205Smrg    free(strings);
326ea6ae205Smrg    free(props);
3277978d3cdSmrg    fontFileClose(f);
328ea6ae205Smrg    return 1;
329ea6ae205Smrg
330ea6ae205Smrg fail:
331ea6ae205Smrg    if(strings) free(strings);
332ea6ae205Smrg    if(props) free(props);
3337978d3cdSmrg    fontFileClose(f);
334ea6ae205Smrg    return 0;
335ea6ae205Smrg}
336ea6ae205Smrg
337ea6ae205Smrg#define NKEY 20
338ea6ae205Smrg
339ea6ae205Smrgstatic char*
3407978d3cdSmrggetKeyword(fontFile *f, int *eol)
341ea6ae205Smrg{
342ea6ae205Smrg    static char keyword[NKEY + 1];
343ea6ae205Smrg    int c, i;
344ea6ae205Smrg    i = 0;
345ea6ae205Smrg    while(i < NKEY) {
3467978d3cdSmrg        c = fontFileGetc(f);
347ea6ae205Smrg        if(c == ' ' || c == '\n') {
348ea6ae205Smrg            if(i <= 0)
349ea6ae205Smrg                return NULL;
350ea6ae205Smrg            if(eol)
351ea6ae205Smrg                *eol = (c == '\n');
352ea6ae205Smrg            keyword[i] = '\0';
353ea6ae205Smrg            return keyword;
354ea6ae205Smrg        }
355ea6ae205Smrg        if(c < 'A' || c > 'Z')
356ea6ae205Smrg            return NULL;
357ea6ae205Smrg        keyword[i++] = c;
358ea6ae205Smrg    }
359ea6ae205Smrg    return NULL;
360ea6ae205Smrg}
361ea6ae205Smrg
362ea6ae205Smrgstatic int
3637978d3cdSmrgbdfskip(fontFile *f)
364ea6ae205Smrg{
365ea6ae205Smrg    int c;
366ea6ae205Smrg    do {
3677978d3cdSmrg        c = fontFileGetc(f);
368ea6ae205Smrg    } while(c >= 0 && c != '\n');
369ea6ae205Smrg    if(c < 0)
370ea6ae205Smrg        return -1;
371ea6ae205Smrg    return 1;
372ea6ae205Smrg}
373ea6ae205Smrg
374ea6ae205Smrgstatic char *
3757978d3cdSmrgbdfend(fontFile *f)
376ea6ae205Smrg{
377ea6ae205Smrg    int c;
378ea6ae205Smrg    char *buf = NULL;
379ea6ae205Smrg    int bufsize = 0;
380ea6ae205Smrg    int i = 0;
381ea6ae205Smrg
382ea6ae205Smrg    do {
3837978d3cdSmrg        c = fontFileGetc(f);
384ea6ae205Smrg    } while (c == ' ');
385ea6ae205Smrg
386ea6ae205Smrg    while(i < 1000) {
387ea6ae205Smrg        if(c < 0 || (c == '\n' && i == 0)) {
388ea6ae205Smrg            goto fail;
389ea6ae205Smrg        }
390ea6ae205Smrg        if(bufsize < i + 1) {
391ea6ae205Smrg            char *newbuf;
392ea6ae205Smrg            if(bufsize == 0) {
393ea6ae205Smrg                bufsize = 20;
394ea6ae205Smrg                newbuf = malloc(bufsize);
395ea6ae205Smrg            } else {
396ea6ae205Smrg                bufsize = 2 * bufsize;
397ea6ae205Smrg                newbuf = realloc(buf, bufsize);
398ea6ae205Smrg            }
399ea6ae205Smrg            if(newbuf == NULL)
400ea6ae205Smrg                goto fail;
401ea6ae205Smrg            buf = newbuf;
402ea6ae205Smrg        }
403ea6ae205Smrg        if(c == '\n') {
404ea6ae205Smrg            buf[i] = '\0';
405ea6ae205Smrg            return buf;
406ea6ae205Smrg        }
407ea6ae205Smrg        buf[i++] = c;
4087978d3cdSmrg        c = fontFileGetc(f);
409ea6ae205Smrg    }
410ea6ae205Smrg
411ea6ae205Smrg fail:
412ea6ae205Smrg    if(buf)
413ea6ae205Smrg        free(buf);
414ea6ae205Smrg    return NULL;
415ea6ae205Smrg}
416ea6ae205Smrg
417ea6ae205Smrgstatic int
4187978d3cdSmrgbdfIdentify(fontFile *f, char **name)
419ea6ae205Smrg{
420ea6ae205Smrg    char *k;
421ea6ae205Smrg    int rc;
422ea6ae205Smrg    int eol;
423ea6ae205Smrg    /* bitmapIdentify already read "STAR", so we need to check for
424ea6ae205Smrg       "TFONT" */
425ea6ae205Smrg    k = getKeyword(f, &eol);
426ea6ae205Smrg    if(k == NULL || eol)
427ea6ae205Smrg        goto fail;
428ea6ae205Smrg    if(strcmp(k, "TFONT") != 0)
429ea6ae205Smrg        goto fail;
430ea6ae205Smrg    while(1) {
431ea6ae205Smrg        if(!eol) {
432ea6ae205Smrg            rc = bdfskip(f);
433a5c37dfeSmrg            if(rc < 0)
434ea6ae205Smrg                goto fail;
435ea6ae205Smrg        }
436ea6ae205Smrg        k = getKeyword(f, &eol);
437ea6ae205Smrg        if(k == NULL)
438ea6ae205Smrg            goto fail;
439ea6ae205Smrg        else if(strcmp(k, "FONT") == 0) {
440ea6ae205Smrg            if(eol)
441ea6ae205Smrg                goto fail;
442ea6ae205Smrg            k = bdfend(f);
443ea6ae205Smrg            if(k == NULL)
444ea6ae205Smrg                goto fail;
445ea6ae205Smrg            *name = k;
4467978d3cdSmrg            fontFileClose(f);
447ea6ae205Smrg            return 1;
448ea6ae205Smrg        } else if(strcmp(k, "CHARS") == 0)
449ea6ae205Smrg            goto fail;
450ea6ae205Smrg    }
451ea6ae205Smrg fail:
4527978d3cdSmrg    fontFileClose(f);
453ea6ae205Smrg    return 0;
454ea6ae205Smrg}
455