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