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