ident.c revision eaa89f16
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#ifdef HAVE_CONFIG_H 51#include "config.h" 52#endif 53 54#include <stdlib.h> 55#include <string.h> 56#include "zlib.h" 57#include "ident.h" 58 59#ifdef X_BZIP2_FONT_COMPRESSION 60# include <bzlib.h> 61#endif 62 63#define PCF_VERSION (('p'<<24)|('c'<<16)|('f'<<8)|1) 64#define PCF_PROPERTIES (1 << 0) 65 66typedef struct _Prop { 67 unsigned name; 68 int isString; 69 unsigned value; 70} PropRec, *PropPtr; 71 72#ifdef X_BZIP2_FONT_COMPRESSION 73typedef struct { 74 enum { gzFontFile, bz2FontFile } type; 75 union { 76 gzFile gz; 77 BZFILE *bz2; 78 } f; 79 unsigned pos; 80} fontFile; 81 82static inline void * 83fontFileOpen(fontFile *ff, const char *filename) { 84 int n = strlen(filename); 85 86 if (n > 4 && strcmp(filename + n - 4, ".bz2") == 0) { 87 ff->type = bz2FontFile; 88 ff->f.bz2 = BZ2_bzopen(filename, "rb"); 89 ff->pos = 0; 90 return ff->f.bz2; 91 } else { 92 ff->type = gzFontFile; 93 ff->f.gz = gzopen(filename, "rb"); 94 return ff->f.gz; 95 } 96} 97 98static inline int 99fontFileRead(fontFile *ff, void *buf, unsigned len) 100{ 101 if (ff->type == gzFontFile) { 102 return gzread(ff->f.gz, buf, len); 103 } else { 104 int r = BZ2_bzread(ff->f.bz2, buf, len); 105 ff->pos += r; 106 return r; 107 } 108} 109 110static inline int 111fontFileGetc(fontFile *ff) 112{ 113 if (ff->type == gzFontFile) { 114 return gzgetc(ff->f.gz); 115 } else { 116 char buf; 117 if (BZ2_bzread(ff->f.bz2, &buf, 1) != 1) { 118 return -1; 119 } else { 120 ff->pos += 1; 121 return (int) buf; 122 } 123 } 124} 125 126static int 127fontFileSeek(fontFile *ff, z_off_t offset, int whence) 128{ 129 if (ff->type == gzFontFile) { 130 return gzseek(ff->f.gz, offset, whence); 131 } else { 132 /* bzlib has no easy equivalent so we have to fake it, 133 * fortunately, we only have to handle a couple of cases 134 */ 135 int n; 136 char buf[BUFSIZ]; 137 138 switch (whence) { 139 case SEEK_SET: 140 n = offset - ff->pos; 141 break; 142 case SEEK_CUR: 143 n = offset; 144 break; 145 default: 146 return -1; 147 } 148 149 while (n > BUFSIZ) { 150 if (BZ2_bzread(ff->f.bz2, buf, BUFSIZ) != BUFSIZ) 151 return -1; 152 n -= BUFSIZ; 153 } 154 if (BZ2_bzread(ff->f.bz2, buf, n) != n) 155 return -1; 156 ff->pos = offset; 157 return offset; 158 } 159} 160 161 162static inline int 163fontFileClose(fontFile *ff) 164{ 165 if (ff->type == gzFontFile) { 166 return gzclose(ff->f.gz); 167 } else { 168 BZ2_bzclose(ff->f.bz2); 169 return 0; 170 } 171} 172 173#else /* no bzip2, only gzip */ 174typedef gzFile fontFile; 175# define fontFileOpen(ff, filename) (*(ff) = gzopen(filename, "rb")) 176# define fontFileRead(ff, buf, len) gzread(*(ff), buf, len) 177# define fontFileGetc(ff) gzgetc(*(ff)) 178# define fontFileSeek(ff, off, whence) gzseek(*(ff), off, whence) 179# define fontFileClose(ff) gzclose(*(ff)) 180#endif 181 182static int pcfIdentify(fontFile *f, char **name); 183static int bdfIdentify(fontFile *f, char **name); 184 185static int 186getLSB32(fontFile *f) 187{ 188 int rc; 189 unsigned char c[4]; 190 191 rc = fontFileRead(f, c, 4); 192 if(rc != 4) 193 return -1; 194 return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); 195} 196 197static int 198getInt8(fontFile *f, int format) 199{ 200 unsigned char c; 201 int rc; 202 203 rc = fontFileRead(f, &c, 1); 204 if(rc != 1) 205 return -1; 206 return c; 207} 208 209static int 210getInt32(fontFile *f, int format) 211{ 212 int rc; 213 unsigned char c[4]; 214 215 rc = fontFileRead(f, c, 4); 216 if(rc != 4) 217 return -1; 218 219 if(format & (1 << 2)) { 220 return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3]); 221 } else { 222 return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); 223 } 224} 225 226int 227bitmapIdentify(const char *filename, char **name) 228{ 229 fontFile ff; 230 int magic; 231 232 if (fontFileOpen(&ff, filename) == NULL) 233 return -1; 234 235 magic = getLSB32(&ff); 236 if(magic == PCF_VERSION) 237 return pcfIdentify(&ff, name); 238 else if(magic == ('S' | ('T' << 8) | ('A' << 16) | ('R') << 24)) 239 return bdfIdentify(&ff, name); 240 241 fontFileClose(&ff); 242 return 0; 243} 244 245static int 246pcfIdentify(fontFile *f, char **name) 247{ 248 int prop_position; 249 PropPtr props = NULL; 250 int format, count, nprops, i, string_size, rc; 251 char *strings = NULL, *s; 252 253 count = getLSB32(f); 254 if(count <= 0) 255 goto fail; 256 257 prop_position = -1; 258 for(i = 0; i < count; i++) { 259 int type, offset; 260 type = getLSB32(f); 261 (void) getLSB32(f); 262 (void) getLSB32(f); 263 offset = getLSB32(f); 264 if(type == PCF_PROPERTIES) { 265 prop_position = offset; 266 break; 267 } 268 } 269 if(prop_position < 0) 270 goto fail; 271 272 rc = fontFileSeek(f, prop_position, SEEK_SET); 273 if(rc < 0) 274 goto fail; 275 276 format = getLSB32(f); 277 if((format & 0xFFFFFF00) != 0) 278 goto fail; 279 nprops = getInt32(f, format); 280 if(nprops <= 0 || nprops > 1000) 281 goto fail; 282 props = malloc(nprops * sizeof(PropRec)); 283 if(props == NULL) 284 goto fail; 285 286 for(i = 0; i < nprops; i++) { 287 props[i].name = getInt32(f, format); 288 props[i].isString = getInt8(f, format); 289 props[i].value = getInt32(f, format); 290 } 291 if(nprops & 3) { 292 rc = fontFileSeek(f, 4 - (nprops & 3), SEEK_CUR); 293 if(rc < 0) 294 goto fail; 295 } 296 297 string_size = getInt32(f, format); 298 if(string_size < 0 || string_size > 100000) 299 goto fail; 300 strings = malloc(string_size); 301 if(!strings) 302 goto fail; 303 304 rc = fontFileRead(f, strings, string_size); 305 if(rc != string_size) 306 goto fail; 307 308 for(i = 0; i < nprops; i++) { 309 if(!props[i].isString || 310 props[i].name >= string_size - 4 || 311 props[i].value >= string_size) 312 continue; 313 if(strcmp(strings + props[i].name, "FONT") == 0) 314 break; 315 } 316 317 if(i >= nprops) 318 goto fail; 319 320 s = strdup(strings + props[i].value); 321 if(s == NULL) 322 goto fail; 323 *name = s; 324 free(strings); 325 free(props); 326 fontFileClose(f); 327 return 1; 328 329 fail: 330 if(strings) free(strings); 331 if(props) free(props); 332 fontFileClose(f); 333 return 0; 334} 335 336#define NKEY 20 337 338static char* 339getKeyword(fontFile *f, int *eol) 340{ 341 static char keyword[NKEY + 1]; 342 int c, i; 343 i = 0; 344 while(i < NKEY) { 345 c = fontFileGetc(f); 346 if(c == ' ' || c == '\n') { 347 if(i <= 0) 348 return NULL; 349 if(eol) 350 *eol = (c == '\n'); 351 keyword[i] = '\0'; 352 return keyword; 353 } 354 if(c < 'A' || c > 'Z') 355 return NULL; 356 keyword[i++] = c; 357 } 358 return NULL; 359} 360 361static int 362bdfskip(fontFile *f) 363{ 364 int c; 365 do { 366 c = fontFileGetc(f); 367 } while(c >= 0 && c != '\n'); 368 if(c < 0) 369 return -1; 370 return 1; 371} 372 373static char * 374bdfend(fontFile *f) 375{ 376 int c; 377 char *buf = NULL; 378 int bufsize = 0; 379 int i = 0; 380 381 do { 382 c = fontFileGetc(f); 383 } while (c == ' '); 384 385 while(i < 1000) { 386 if(c < 0 || (c == '\n' && i == 0)) { 387 goto fail; 388 } 389 if(bufsize < i + 1) { 390 char *newbuf; 391 if(bufsize == 0) { 392 bufsize = 20; 393 newbuf = malloc(bufsize); 394 } else { 395 bufsize = 2 * bufsize; 396 newbuf = realloc(buf, bufsize); 397 } 398 if(newbuf == NULL) 399 goto fail; 400 buf = newbuf; 401 } 402 if(c == '\n') { 403 buf[i] = '\0'; 404 return buf; 405 } 406 buf[i++] = c; 407 c = fontFileGetc(f); 408 } 409 410 fail: 411 if(buf) 412 free(buf); 413 return NULL; 414} 415 416static int 417bdfIdentify(fontFile *f, char **name) 418{ 419 char *k; 420 int rc; 421 int eol; 422 /* bitmapIdentify already read "STAR", so we need to check for 423 "TFONT" */ 424 k = getKeyword(f, &eol); 425 if(k == NULL || eol) 426 goto fail; 427 if(strcmp(k, "TFONT") != 0) 428 goto fail; 429 while(1) { 430 if(!eol) { 431 rc = bdfskip(f); 432 if(rc < 0) 433 goto fail; 434 } 435 k = getKeyword(f, &eol); 436 if(k == NULL) 437 goto fail; 438 else if(strcmp(k, "FONT") == 0) { 439 if(eol) 440 goto fail; 441 k = bdfend(f); 442 if(k == NULL) 443 goto fail; 444 *name = k; 445 fontFileClose(f); 446 return 1; 447 } else if(strcmp(k, "CHARS") == 0) 448 goto fail; 449 } 450 fail: 451 fontFileClose(f); 452 return 0; 453} 454