ident.c revision a5c37dfe
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 (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 = malloc(strlen(strings + props[i].value) + 1); 321 if(s == NULL) 322 goto fail; 323 strcpy(s, strings + props[i].value); 324 *name = s; 325 free(strings); 326 free(props); 327 fontFileClose(f); 328 return 1; 329 330 fail: 331 if(strings) free(strings); 332 if(props) free(props); 333 fontFileClose(f); 334 return 0; 335} 336 337#define NKEY 20 338 339static char* 340getKeyword(fontFile *f, int *eol) 341{ 342 static char keyword[NKEY + 1]; 343 int c, i; 344 i = 0; 345 while(i < NKEY) { 346 c = fontFileGetc(f); 347 if(c == ' ' || c == '\n') { 348 if(i <= 0) 349 return NULL; 350 if(eol) 351 *eol = (c == '\n'); 352 keyword[i] = '\0'; 353 return keyword; 354 } 355 if(c < 'A' || c > 'Z') 356 return NULL; 357 keyword[i++] = c; 358 } 359 return NULL; 360} 361 362static int 363bdfskip(fontFile *f) 364{ 365 int c; 366 do { 367 c = fontFileGetc(f); 368 } while(c >= 0 && c != '\n'); 369 if(c < 0) 370 return -1; 371 return 1; 372} 373 374static char * 375bdfend(fontFile *f) 376{ 377 int c; 378 char *buf = NULL; 379 int bufsize = 0; 380 int i = 0; 381 382 do { 383 c = fontFileGetc(f); 384 } while (c == ' '); 385 386 while(i < 1000) { 387 if(c < 0 || (c == '\n' && i == 0)) { 388 goto fail; 389 } 390 if(bufsize < i + 1) { 391 char *newbuf; 392 if(bufsize == 0) { 393 bufsize = 20; 394 newbuf = malloc(bufsize); 395 } else { 396 bufsize = 2 * bufsize; 397 newbuf = realloc(buf, bufsize); 398 } 399 if(newbuf == NULL) 400 goto fail; 401 buf = newbuf; 402 } 403 if(c == '\n') { 404 buf[i] = '\0'; 405 return buf; 406 } 407 buf[i++] = c; 408 c = fontFileGetc(f); 409 } 410 411 fail: 412 if(buf) 413 free(buf); 414 return NULL; 415} 416 417static int 418bdfIdentify(fontFile *f, char **name) 419{ 420 char *k; 421 int rc; 422 int eol; 423 /* bitmapIdentify already read "STAR", so we need to check for 424 "TFONT" */ 425 k = getKeyword(f, &eol); 426 if(k == NULL || eol) 427 goto fail; 428 if(strcmp(k, "TFONT") != 0) 429 goto fail; 430 while(1) { 431 if(!eol) { 432 rc = bdfskip(f); 433 if(rc < 0) 434 goto fail; 435 } 436 k = getKeyword(f, &eol); 437 if(k == NULL) 438 goto fail; 439 else if(strcmp(k, "FONT") == 0) { 440 if(eol) 441 goto fail; 442 k = bdfend(f); 443 if(k == NULL) 444 goto fail; 445 *name = k; 446 fontFileClose(f); 447 return 1; 448 } else if(strcmp(k, "CHARS") == 0) 449 goto fail; 450 } 451 fail: 452 fontFileClose(f); 453 return 0; 454} 455