resetting manifest requested domain to floor
[platform/upstream/mkfontscale.git] / ident.c
1 /*
2   Copyright (c) 2003 by Juliusz Chroboczek
3
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 /*
23  * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
24  *
25  * Permission is hereby granted, free of charge, to any person obtaining a
26  * copy of this software and associated documentation files (the "Software"),
27  * to deal in the Software without restriction, including without limitation
28  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29  * and/or sell copies of the Software, and to permit persons to whom the
30  * Software is furnished to do so, subject to the following conditions:
31  *
32  * The above copyright notice and this permission notice (including the next
33  * paragraph) shall be included in all copies or substantial portions of the
34  * Software.
35  *
36  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
39  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
41  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
42  * DEALINGS IN THE SOFTWARE.
43  */
44
45 /* The function identifyBitmap returns -1 if filename is definitively not
46    a font file, 1 if it is a single-face bitmap font with a XLFD name,
47    and 0 if it should be processed normally.  identifyBitmap is
48    much faster than parsing the whole font. */
49
50 #include "config.h"
51
52 #include <stdlib.h>
53 #include <string.h>
54 #include "zlib.h"
55 #include "ident.h"
56
57 #ifdef X_BZIP2_FONT_COMPRESSION
58 # include <bzlib.h>
59 #endif
60
61 #define PCF_VERSION (('p'<<24)|('c'<<16)|('f'<<8)|1)
62 #define PCF_PROPERTIES (1 << 0)
63
64 typedef struct _Prop {
65     unsigned name;
66     int isString;
67     unsigned value;
68 } PropRec, *PropPtr;
69
70 #ifdef X_BZIP2_FONT_COMPRESSION
71 typedef struct {
72     enum { gzFontFile, bz2FontFile } type;
73     union {
74         gzFile gz;
75         BZFILE *bz2;
76     } f;
77     unsigned pos;
78 } fontFile;
79
80 static inline void *
81 fontFileOpen(fontFile *ff, const char *filename) {
82     int n = strlen(filename);
83
84     if (strcmp(filename + n - 4, ".bz2") == 0) {
85         ff->type = bz2FontFile;
86         ff->f.bz2 = BZ2_bzopen(filename, "rb");
87         ff->pos = 0;
88         return ff->f.bz2;
89     } else {
90         ff->type = gzFontFile;
91         ff->f.gz = gzopen(filename, "rb");
92         return ff->f.gz;
93     }
94 }
95
96 static inline int
97 fontFileRead(fontFile *ff, void *buf, unsigned len)
98 {
99     if (ff->type == gzFontFile) {
100         return gzread(ff->f.gz, buf, len);
101     } else {
102         int r = BZ2_bzread(ff->f.bz2, buf, len);
103         ff->pos += r;
104         return r;
105     }
106 }
107
108 static inline int
109 fontFileGetc(fontFile *ff)
110 {
111     if (ff->type == gzFontFile) {
112         return gzgetc(ff->f.gz);
113     } else {
114         char buf;
115         if (BZ2_bzread(ff->f.bz2, &buf, 1) != 1) {
116             return -1;
117         } else {
118             ff->pos += 1;
119             return (int) buf;
120         }
121     }
122 }
123
124 static int
125 fontFileSeek(fontFile *ff, z_off_t offset, int whence)
126 {
127     if (ff->type == gzFontFile) {
128         return gzseek(ff->f.gz, offset, whence);
129     } else {
130         /* bzlib has no easy equivalent so we have to fake it,
131          * fortunately, we only have to handle a couple of cases
132          */
133         int n;
134         char buf[BUFSIZ];
135
136         switch (whence) {
137           case SEEK_SET:
138             n = offset - ff->pos;
139             break;
140           case SEEK_CUR:
141             n = offset;
142             break;
143           default:
144             return -1;
145         }
146
147         while (n > BUFSIZ) {
148             if (BZ2_bzread(ff->f.bz2, buf, BUFSIZ) != BUFSIZ)
149                 return -1;
150             n -= BUFSIZ;
151         }
152         if (BZ2_bzread(ff->f.bz2, buf, n) != n)
153             return -1;
154         ff->pos = offset;
155         return offset;
156     }
157 }
158
159
160 static inline int
161 fontFileClose(fontFile *ff)
162 {
163     if (ff->type == gzFontFile) {
164         return gzclose(ff->f.gz);
165     } else {
166         BZ2_bzclose(ff->f.bz2);
167         return 0;
168     }
169 }
170
171 #else /* no bzip2, only gzip */
172 typedef gzFile fontFile;
173 # define fontFileOpen(ff, filename)     (*(ff) = gzopen(filename, "rb"))
174 # define fontFileRead(ff, buf, len)     gzread(*(ff), buf, len)
175 # define fontFileGetc(ff)               gzgetc(*(ff))
176 # define fontFileSeek(ff, off, whence)  gzseek(*(ff), off, whence)
177 # define fontFileClose(ff)              gzclose(*(ff))
178 #endif
179
180 static int pcfIdentify(fontFile *f, char **name);
181 static int bdfIdentify(fontFile *f, char **name);
182
183 static int
184 getLSB32(fontFile *f)
185 {
186     int rc;
187     unsigned char c[4];
188
189     rc = fontFileRead(f, c, 4);
190     if(rc != 4)
191         return -1;
192     return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
193 }
194
195 static int
196 getInt8(fontFile *f, int format)
197 {
198     unsigned char c;
199     int rc;
200
201     rc = fontFileRead(f, &c, 1);
202     if(rc != 1)
203         return -1;
204     return c;
205 }
206
207 static int
208 getInt32(fontFile *f, int format)
209 {
210     int rc;
211     unsigned char c[4];
212
213     rc = fontFileRead(f, c, 4);
214     if(rc != 4)
215         return -1;
216
217     if(format & (1 << 2)) {
218         return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3]);
219     } else {
220         return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
221     }
222 }
223
224 int
225 bitmapIdentify(const char *filename, char **name)
226 {
227     fontFile ff;
228     int magic;
229
230     if (fontFileOpen(&ff, filename) == NULL)
231         return -1;
232
233     magic = getLSB32(&ff);
234     if(magic == PCF_VERSION)
235         return pcfIdentify(&ff, name);
236     else if(magic == ('S' | ('T' << 8) | ('A' << 16) | ('R') << 24))
237         return bdfIdentify(&ff, name);
238
239     fontFileClose(&ff);
240     return 0;
241 }
242
243 static int
244 pcfIdentify(fontFile *f, char **name)
245 {
246     int prop_position;
247     PropPtr props = NULL;
248     int format, count, nprops, i, string_size, rc;
249     char *strings = NULL, *s;
250
251     count = getLSB32(f);
252     if(count <= 0)
253         goto fail;
254
255     prop_position = -1;
256     for(i = 0; i < count; i++) {
257         int type, offset;
258         type = getLSB32(f);
259         (void) getLSB32(f);
260         (void) getLSB32(f);
261         offset = getLSB32(f);
262         if(type == PCF_PROPERTIES) {
263             prop_position = offset;
264             break;
265         }
266     }
267     if(prop_position < 0)
268         goto fail;
269
270     rc = fontFileSeek(f, prop_position, SEEK_SET);
271     if(rc < 0)
272         goto fail;
273
274     format = getLSB32(f);
275     if((format & 0xFFFFFF00) != 0)
276         goto fail;
277     nprops = getInt32(f, format);
278     if(nprops <= 0 || nprops > 1000)
279         goto fail;
280     props = malloc(nprops * sizeof(PropRec));
281     if(props == NULL)
282         goto fail;
283
284     for(i = 0; i < nprops; i++) {
285         props[i].name = getInt32(f, format);
286         props[i].isString = getInt8(f, format);
287         props[i].value = getInt32(f, format);
288     }
289     if(nprops & 3) {
290         rc = fontFileSeek(f, 4 - (nprops & 3), SEEK_CUR);
291         if(rc < 0)
292             goto fail;
293     }
294
295     string_size = getInt32(f, format);
296     if(string_size < 0 || string_size > 100000)
297         goto fail;
298     strings = malloc(string_size);
299     if(!strings)
300         goto fail;
301
302     rc = fontFileRead(f, strings, string_size);
303     if(rc != string_size)
304         goto fail;
305
306     for(i = 0; i < nprops; i++) {
307         if(!props[i].isString ||
308            props[i].name >= string_size - 4 ||
309            props[i].value >= string_size)
310             continue;
311         if(strcmp(strings + props[i].name, "FONT") == 0)
312             break;
313     }
314
315     if(i >= nprops)
316         goto fail;
317
318     s = malloc(strlen(strings + props[i].value) + 1);
319     if(s == NULL)
320         goto fail;
321     strcpy(s, strings + props[i].value);
322     *name = s;
323     free(strings);
324     free(props);
325     fontFileClose(f);
326     return 1;
327
328  fail:
329     if(strings) free(strings);
330     if(props) free(props);
331     fontFileClose(f);
332     return 0;
333 }
334
335 #define NKEY 20
336
337 static char*
338 getKeyword(fontFile *f, int *eol)
339 {
340     static char keyword[NKEY + 1];
341     int c, i;
342     i = 0;
343     while(i < NKEY) {
344         c = fontFileGetc(f);
345         if(c == ' ' || c == '\n') {
346             if(i <= 0)
347                 return NULL;
348             if(eol)
349                 *eol = (c == '\n');
350             keyword[i] = '\0';
351             return keyword;
352         }
353         if(c < 'A' || c > 'Z')
354             return NULL;
355         keyword[i++] = c;
356     }
357     return NULL;
358 }
359
360 static int
361 bdfskip(fontFile *f)
362 {
363     int c;
364     do {
365         c = fontFileGetc(f);
366     } while(c >= 0 && c != '\n');
367     if(c < 0)
368         return -1;
369     return 1;
370 }
371
372 static char *
373 bdfend(fontFile *f)
374 {
375     int c;
376     char *buf = NULL;
377     int bufsize = 0;
378     int i = 0;
379
380     do {
381         c = fontFileGetc(f);
382     } while (c == ' ');
383
384     while(i < 1000) {
385         if(c < 0 || (c == '\n' && i == 0)) {
386             goto fail;
387         }
388         if(bufsize < i + 1) {
389             char *newbuf;
390             if(bufsize == 0) {
391                 bufsize = 20;
392                 newbuf = malloc(bufsize);
393             } else {
394                 bufsize = 2 * bufsize;
395                 newbuf = realloc(buf, bufsize);
396             }
397             if(newbuf == NULL)
398                 goto fail;
399             buf = newbuf;
400         }
401         if(c == '\n') {
402             buf[i] = '\0';
403             return buf;
404         }
405         buf[i++] = c;
406         c = fontFileGetc(f);
407     }
408
409  fail:
410     if(buf)
411         free(buf);
412     return NULL;
413 }
414
415 static int
416 bdfIdentify(fontFile *f, char **name)
417 {
418     char *k;
419     int rc;
420     int eol;
421     /* bitmapIdentify already read "STAR", so we need to check for
422        "TFONT" */
423     k = getKeyword(f, &eol);
424     if(k == NULL || eol)
425         goto fail;
426     if(strcmp(k, "TFONT") != 0)
427         goto fail;
428     while(1) {
429         if(!eol) {
430             rc = bdfskip(f);
431             if(rc < 0)
432                 goto fail;
433         }
434         k = getKeyword(f, &eol);
435         if(k == NULL)
436             goto fail;
437         else if(strcmp(k, "FONT") == 0) {
438             if(eol)
439                 goto fail;
440             k = bdfend(f);
441             if(k == NULL)
442                 goto fail;
443             *name = k;
444             fontFileClose(f);
445             return 1;
446         } else if(strcmp(k, "CHARS") == 0)
447             goto fail;
448     }
449  fail:
450     fontFileClose(f);
451     return 0;
452 }