ident.c revision ea6ae205
11.1Sthorpej/*
21.1Sthorpej  Copyright (c) 2003 by Juliusz Chroboczek
31.1Sthorpej
4  Permission is hereby granted, free of charge, to any person obtaining a copy
5  of this software and associated documentation files (the "Software"), to deal
6  in the Software without restriction, including without limitation the rights
7  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  copies of the Software, and to permit persons to whom the Software is
9  furnished to do so, subject to the following conditions:
10
11  The above copyright notice and this permission notice shall be included in
12  all copies or substantial portions of the Software.
13
14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  THE SOFTWARE.
21*/
22/* $XFree86: xc/programs/mkfontscale/ident.c,v 1.3tsi Exp $ */
23
24/* The function identifyBitmap returns -1 if filename is definitively not
25   a font file, 1 if it is a single-face bitmap font with a XLFD name,
26   and 0 if it should be processed normally.  identifyBitmap is
27   much faster than parsing the whole font. */
28
29#include <stdlib.h>
30#include <string.h>
31#include "zlib.h"
32#include "ident.h"
33
34#define PCF_VERSION (('p'<<24)|('c'<<16)|('f'<<8)|1)
35#define PCF_PROPERTIES (1 << 0)
36
37typedef struct _Prop {
38    unsigned name;
39    int isString;
40    unsigned value;
41} PropRec, *PropPtr;
42
43static int pcfIdentify(gzFile f, char **name);
44static int bdfIdentify(gzFile f, char **name);
45
46static int
47getLSB32(gzFile f)
48{
49    int rc;
50    unsigned char c[4];
51
52    rc = gzread(f, c, 4);
53    if(rc != 4)
54        return -1;
55    return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
56}
57
58static int
59getInt8(gzFile f, int format)
60{
61    unsigned char c;
62    int rc;
63
64    rc = gzread(f, &c, 1);
65    if(rc != 1)
66        return -1;
67    return c;
68}
69
70static int
71getInt32(gzFile f, int format)
72{
73    int rc;
74    unsigned char c[4];
75
76    rc = gzread(f, c, 4);
77    if(rc != 4)
78        return -1;
79
80    if(format & (1 << 2)) {
81        return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3]);
82    } else {
83        return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
84    }
85}
86
87static int
88pcfskip(gzFile f, int n)
89{
90    char buf[32];
91    int i, rc;
92    while(n > 0) {
93        i = (n > 32 ? 32 : n);
94        rc = gzread(f, buf, i);
95        if(rc != i)
96            return -1;
97        n -= rc;
98    }
99    return 1;
100}
101
102int
103bitmapIdentify(char *filename, char **name)
104{
105    gzFile f;
106    int magic;
107
108    f = gzopen(filename, "rb");
109    if(f == NULL)
110        return -1;
111
112    magic = getLSB32(f);
113    if(magic == PCF_VERSION)
114        return pcfIdentify(f, name);
115    else if(magic == ('S' | ('T' << 8) | ('A' << 16) | ('R') << 24))
116        return bdfIdentify(f, name);
117
118    gzclose(f);
119    return 0;
120}
121
122static int
123pcfIdentify(gzFile f, char **name)
124{
125    int prop_position;
126    PropPtr props = NULL;
127    int format, count, nprops, i, string_size, rc;
128    char *strings = NULL, *s;
129
130    count = getLSB32(f);
131    if(count <= 0)
132        goto fail;
133
134    prop_position = -1;
135    for(i = 0; i < count; i++) {
136        int type, offset;
137        type = getLSB32(f);
138        (void) getLSB32(f);
139        (void) getLSB32(f);
140        offset = getLSB32(f);
141        if(type == PCF_PROPERTIES) {
142            prop_position = offset;
143            break;
144        }
145    }
146    if(prop_position < 0)
147        goto fail;
148
149    rc = gzseek(f, prop_position, SEEK_SET);
150    if(rc < 0)
151        goto fail;
152
153    format = getLSB32(f);
154    if((format & 0xFFFFFF00) != 0)
155        goto fail;
156    nprops = getInt32(f, format);
157    if(nprops <= 0 || nprops > 1000)
158        goto fail;
159    props = malloc(nprops * sizeof(PropRec));
160    if(props == NULL)
161        goto fail;
162
163    for(i = 0; i < nprops; i++) {
164        props[i].name = getInt32(f, format);
165        props[i].isString = getInt8(f, format);
166        props[i].value = getInt32(f, format);
167    }
168    if(nprops & 3) {
169        rc = pcfskip(f, 4 - (nprops & 3));
170        if(rc < 0)
171            goto fail;
172    }
173
174    string_size = getInt32(f, format);
175    if(string_size < 0 || string_size > 100000)
176        goto fail;
177    strings = malloc(string_size);
178    if(!strings)
179        goto fail;
180
181    rc = gzread(f, strings, string_size);
182    if(rc != string_size)
183        goto fail;
184
185    for(i = 0; i < nprops; i++) {
186        if(!props[i].isString ||
187           props[i].name >= string_size - 4 ||
188           props[i].value >= string_size)
189            continue;
190        if(strcmp(strings + props[i].name, "FONT") == 0)
191            break;
192    }
193
194    if(i >= nprops)
195        goto fail;
196
197    s = malloc(strlen(strings + props[i].value) + 1);
198    if(s == NULL)
199        goto fail;
200    strcpy(s, strings + props[i].value);
201    *name = s;
202    free(strings);
203    free(props);
204    gzclose(f);
205    return 1;
206
207 fail:
208    if(strings) free(strings);
209    if(props) free(props);
210    gzclose(f);
211    return 0;
212}
213
214#define NKEY 20
215
216static char*
217getKeyword(gzFile *f, int *eol)
218{
219    static char keyword[NKEY + 1];
220    int c, i;
221    i = 0;
222    while(i < NKEY) {
223        c = gzgetc(f);
224        if(c == ' ' || c == '\n') {
225            if(i <= 0)
226                return NULL;
227            if(eol)
228                *eol = (c == '\n');
229            keyword[i] = '\0';
230            return keyword;
231        }
232        if(c < 'A' || c > 'Z')
233            return NULL;
234        keyword[i++] = c;
235    }
236    return NULL;
237}
238
239static int
240bdfskip(gzFile *f)
241{
242    int c;
243    do {
244        c = gzgetc(f);
245    } while(c >= 0 && c != '\n');
246    if(c < 0)
247        return -1;
248    return 1;
249}
250
251static char *
252bdfend(gzFile *f)
253{
254    int c;
255    char *buf = NULL;
256    int bufsize = 0;
257    int i = 0;
258
259    do {
260        c = gzgetc(f);
261    } while (c == ' ');
262
263    while(i < 1000) {
264        if(c < 0 || (c == '\n' && i == 0)) {
265            goto fail;
266        }
267        if(bufsize < i + 1) {
268            char *newbuf;
269            if(bufsize == 0) {
270                bufsize = 20;
271                newbuf = malloc(bufsize);
272            } else {
273                bufsize = 2 * bufsize;
274                newbuf = realloc(buf, bufsize);
275            }
276            if(newbuf == NULL)
277                goto fail;
278            buf = newbuf;
279        }
280        if(c == '\n') {
281            buf[i] = '\0';
282            return buf;
283        }
284        buf[i++] = c;
285        c = gzgetc(f);
286    }
287
288 fail:
289    if(buf)
290        free(buf);
291    return NULL;
292}
293
294static int
295bdfIdentify(gzFile f, char **name)
296{
297    char *k;
298    int rc;
299    int eol;
300    /* bitmapIdentify already read "STAR", so we need to check for
301       "TFONT" */
302    k = getKeyword(f, &eol);
303    if(k == NULL || eol)
304        goto fail;
305    if(strcmp(k, "TFONT") != 0)
306        goto fail;
307    while(1) {
308        if(!eol) {
309            rc = bdfskip(f);
310            if(rc < 0)
311                goto fail;
312        }
313        k = getKeyword(f, &eol);
314        if(k == NULL)
315            goto fail;
316        else if(strcmp(k, "FONT") == 0) {
317            if(eol)
318                goto fail;
319            k = bdfend(f);
320            if(k == NULL)
321                goto fail;
322            *name = k;
323            gzclose(f);
324            return 1;
325        } else if(strcmp(k, "CHARS") == 0)
326            goto fail;
327    }
328 fail:
329    gzclose(f);
330    return 0;
331}
332