ident.c revision eaa89f16
1ea6ae205Smrg/* 2ea6ae205Smrg Copyright (c) 2003 by Juliusz Chroboczek 3ea6ae205Smrg 4ea6ae205Smrg Permission is hereby granted, free of charge, to any person obtaining a copy 5ea6ae205Smrg of this software and associated documentation files (the "Software"), to deal 6ea6ae205Smrg in the Software without restriction, including without limitation the rights 7ea6ae205Smrg to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8ea6ae205Smrg copies of the Software, and to permit persons to whom the Software is 9ea6ae205Smrg furnished to do so, subject to the following conditions: 10ea6ae205Smrg 11ea6ae205Smrg The above copyright notice and this permission notice shall be included in 12ea6ae205Smrg all copies or substantial portions of the Software. 13ea6ae205Smrg 14ea6ae205Smrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15ea6ae205Smrg IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16ea6ae205Smrg FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17ea6ae205Smrg AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18ea6ae205Smrg LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19ea6ae205Smrg OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20ea6ae205Smrg THE SOFTWARE. 21ea6ae205Smrg*/ 22ca74b209Smrg/* 23ca74b209Smrg * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. 247978d3cdSmrg * 257978d3cdSmrg * Permission is hereby granted, free of charge, to any person obtaining a 26ca74b209Smrg * copy of this software and associated documentation files (the "Software"), 27ca74b209Smrg * to deal in the Software without restriction, including without limitation 28ca74b209Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 29ca74b209Smrg * and/or sell copies of the Software, and to permit persons to whom the 30ca74b209Smrg * Software is furnished to do so, subject to the following conditions: 317978d3cdSmrg * 32ca74b209Smrg * The above copyright notice and this permission notice (including the next 33ca74b209Smrg * paragraph) shall be included in all copies or substantial portions of the 34ca74b209Smrg * Software. 357978d3cdSmrg * 36ca74b209Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37ca74b209Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38ca74b209Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 39ca74b209Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 40ca74b209Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 41ca74b209Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 42ca74b209Smrg * DEALINGS IN THE SOFTWARE. 43ca74b209Smrg */ 44ea6ae205Smrg 45ea6ae205Smrg/* The function identifyBitmap returns -1 if filename is definitively not 46ea6ae205Smrg a font file, 1 if it is a single-face bitmap font with a XLFD name, 47ea6ae205Smrg and 0 if it should be processed normally. identifyBitmap is 48ea6ae205Smrg much faster than parsing the whole font. */ 49ea6ae205Smrg 5045a6f659Smrg#ifdef HAVE_CONFIG_H 517978d3cdSmrg#include "config.h" 5245a6f659Smrg#endif 537978d3cdSmrg 54ea6ae205Smrg#include <stdlib.h> 55ea6ae205Smrg#include <string.h> 56ea6ae205Smrg#include "zlib.h" 57ea6ae205Smrg#include "ident.h" 58ea6ae205Smrg 597978d3cdSmrg#ifdef X_BZIP2_FONT_COMPRESSION 607978d3cdSmrg# include <bzlib.h> 617978d3cdSmrg#endif 627978d3cdSmrg 63ea6ae205Smrg#define PCF_VERSION (('p'<<24)|('c'<<16)|('f'<<8)|1) 64ea6ae205Smrg#define PCF_PROPERTIES (1 << 0) 65ea6ae205Smrg 66ea6ae205Smrgtypedef struct _Prop { 67ea6ae205Smrg unsigned name; 68ea6ae205Smrg int isString; 69ea6ae205Smrg unsigned value; 70ea6ae205Smrg} PropRec, *PropPtr; 71ea6ae205Smrg 727978d3cdSmrg#ifdef X_BZIP2_FONT_COMPRESSION 737978d3cdSmrgtypedef struct { 747978d3cdSmrg enum { gzFontFile, bz2FontFile } type; 757978d3cdSmrg union { 767978d3cdSmrg gzFile gz; 777978d3cdSmrg BZFILE *bz2; 787978d3cdSmrg } f; 797978d3cdSmrg unsigned pos; 807978d3cdSmrg} fontFile; 817978d3cdSmrg 827978d3cdSmrgstatic inline void * 837978d3cdSmrgfontFileOpen(fontFile *ff, const char *filename) { 847978d3cdSmrg int n = strlen(filename); 857978d3cdSmrg 86eaa89f16Smrg if (n > 4 && strcmp(filename + n - 4, ".bz2") == 0) { 877978d3cdSmrg ff->type = bz2FontFile; 887978d3cdSmrg ff->f.bz2 = BZ2_bzopen(filename, "rb"); 897978d3cdSmrg ff->pos = 0; 907978d3cdSmrg return ff->f.bz2; 917978d3cdSmrg } else { 927978d3cdSmrg ff->type = gzFontFile; 937978d3cdSmrg ff->f.gz = gzopen(filename, "rb"); 947978d3cdSmrg return ff->f.gz; 957978d3cdSmrg } 967978d3cdSmrg} 977978d3cdSmrg 987978d3cdSmrgstatic inline int 997978d3cdSmrgfontFileRead(fontFile *ff, void *buf, unsigned len) 1007978d3cdSmrg{ 1017978d3cdSmrg if (ff->type == gzFontFile) { 1027978d3cdSmrg return gzread(ff->f.gz, buf, len); 1037978d3cdSmrg } else { 1047978d3cdSmrg int r = BZ2_bzread(ff->f.bz2, buf, len); 1057978d3cdSmrg ff->pos += r; 1067978d3cdSmrg return r; 1077978d3cdSmrg } 1087978d3cdSmrg} 1097978d3cdSmrg 1107978d3cdSmrgstatic inline int 1117978d3cdSmrgfontFileGetc(fontFile *ff) 1127978d3cdSmrg{ 1137978d3cdSmrg if (ff->type == gzFontFile) { 1147978d3cdSmrg return gzgetc(ff->f.gz); 1157978d3cdSmrg } else { 1167978d3cdSmrg char buf; 1177978d3cdSmrg if (BZ2_bzread(ff->f.bz2, &buf, 1) != 1) { 1187978d3cdSmrg return -1; 1197978d3cdSmrg } else { 1207978d3cdSmrg ff->pos += 1; 1217978d3cdSmrg return (int) buf; 1227978d3cdSmrg } 1237978d3cdSmrg } 1247978d3cdSmrg} 1257978d3cdSmrg 1267978d3cdSmrgstatic int 1277978d3cdSmrgfontFileSeek(fontFile *ff, z_off_t offset, int whence) 1287978d3cdSmrg{ 1297978d3cdSmrg if (ff->type == gzFontFile) { 1307978d3cdSmrg return gzseek(ff->f.gz, offset, whence); 1317978d3cdSmrg } else { 1327978d3cdSmrg /* bzlib has no easy equivalent so we have to fake it, 1337978d3cdSmrg * fortunately, we only have to handle a couple of cases 1347978d3cdSmrg */ 1357978d3cdSmrg int n; 1367978d3cdSmrg char buf[BUFSIZ]; 1377978d3cdSmrg 1387978d3cdSmrg switch (whence) { 1397978d3cdSmrg case SEEK_SET: 1407978d3cdSmrg n = offset - ff->pos; 1417978d3cdSmrg break; 1427978d3cdSmrg case SEEK_CUR: 1437978d3cdSmrg n = offset; 1447978d3cdSmrg break; 1457978d3cdSmrg default: 1467978d3cdSmrg return -1; 147a5c37dfeSmrg } 148a5c37dfeSmrg 1497978d3cdSmrg while (n > BUFSIZ) { 1507978d3cdSmrg if (BZ2_bzread(ff->f.bz2, buf, BUFSIZ) != BUFSIZ) 1517978d3cdSmrg return -1; 1527978d3cdSmrg n -= BUFSIZ; 1537978d3cdSmrg } 1547978d3cdSmrg if (BZ2_bzread(ff->f.bz2, buf, n) != n) 1557978d3cdSmrg return -1; 1567978d3cdSmrg ff->pos = offset; 1577978d3cdSmrg return offset; 1587978d3cdSmrg } 1597978d3cdSmrg} 1607978d3cdSmrg 1617978d3cdSmrg 1627978d3cdSmrgstatic inline int 1637978d3cdSmrgfontFileClose(fontFile *ff) 1647978d3cdSmrg{ 1657978d3cdSmrg if (ff->type == gzFontFile) { 1667978d3cdSmrg return gzclose(ff->f.gz); 1677978d3cdSmrg } else { 1687978d3cdSmrg BZ2_bzclose(ff->f.bz2); 1697978d3cdSmrg return 0; 1707978d3cdSmrg } 1717978d3cdSmrg} 1727978d3cdSmrg 1737978d3cdSmrg#else /* no bzip2, only gzip */ 1747978d3cdSmrgtypedef gzFile fontFile; 1757978d3cdSmrg# define fontFileOpen(ff, filename) (*(ff) = gzopen(filename, "rb")) 1767978d3cdSmrg# define fontFileRead(ff, buf, len) gzread(*(ff), buf, len) 1777978d3cdSmrg# define fontFileGetc(ff) gzgetc(*(ff)) 1787978d3cdSmrg# define fontFileSeek(ff, off, whence) gzseek(*(ff), off, whence) 1797978d3cdSmrg# define fontFileClose(ff) gzclose(*(ff)) 1807978d3cdSmrg#endif 1817978d3cdSmrg 1827978d3cdSmrgstatic int pcfIdentify(fontFile *f, char **name); 1837978d3cdSmrgstatic int bdfIdentify(fontFile *f, char **name); 184ea6ae205Smrg 185ea6ae205Smrgstatic int 1867978d3cdSmrggetLSB32(fontFile *f) 187ea6ae205Smrg{ 188ea6ae205Smrg int rc; 189ea6ae205Smrg unsigned char c[4]; 190ea6ae205Smrg 1917978d3cdSmrg rc = fontFileRead(f, c, 4); 192ea6ae205Smrg if(rc != 4) 193ea6ae205Smrg return -1; 194ea6ae205Smrg return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); 195ea6ae205Smrg} 196ea6ae205Smrg 197ea6ae205Smrgstatic int 1987978d3cdSmrggetInt8(fontFile *f, int format) 199ea6ae205Smrg{ 200ea6ae205Smrg unsigned char c; 201ea6ae205Smrg int rc; 202ea6ae205Smrg 2037978d3cdSmrg rc = fontFileRead(f, &c, 1); 204ea6ae205Smrg if(rc != 1) 205ea6ae205Smrg return -1; 206ea6ae205Smrg return c; 207ea6ae205Smrg} 208ea6ae205Smrg 209ea6ae205Smrgstatic int 2107978d3cdSmrggetInt32(fontFile *f, int format) 211ea6ae205Smrg{ 212ea6ae205Smrg int rc; 213ea6ae205Smrg unsigned char c[4]; 214ea6ae205Smrg 2157978d3cdSmrg rc = fontFileRead(f, c, 4); 216ea6ae205Smrg if(rc != 4) 217ea6ae205Smrg return -1; 218ea6ae205Smrg 219ea6ae205Smrg if(format & (1 << 2)) { 220ea6ae205Smrg return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3]); 221ea6ae205Smrg } else { 222ea6ae205Smrg return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); 223ea6ae205Smrg } 224ea6ae205Smrg} 225ea6ae205Smrg 226a5c37dfeSmrgint 2277978d3cdSmrgbitmapIdentify(const char *filename, char **name) 228ea6ae205Smrg{ 2297978d3cdSmrg fontFile ff; 230ea6ae205Smrg int magic; 231ea6ae205Smrg 2327978d3cdSmrg if (fontFileOpen(&ff, filename) == NULL) 2337978d3cdSmrg return -1; 234ea6ae205Smrg 2357978d3cdSmrg magic = getLSB32(&ff); 236ea6ae205Smrg if(magic == PCF_VERSION) 2377978d3cdSmrg return pcfIdentify(&ff, name); 238ea6ae205Smrg else if(magic == ('S' | ('T' << 8) | ('A' << 16) | ('R') << 24)) 2397978d3cdSmrg return bdfIdentify(&ff, name); 240ea6ae205Smrg 2417978d3cdSmrg fontFileClose(&ff); 242ea6ae205Smrg return 0; 243ea6ae205Smrg} 244ea6ae205Smrg 245ea6ae205Smrgstatic int 2467978d3cdSmrgpcfIdentify(fontFile *f, char **name) 247ea6ae205Smrg{ 248ea6ae205Smrg int prop_position; 249ea6ae205Smrg PropPtr props = NULL; 250ea6ae205Smrg int format, count, nprops, i, string_size, rc; 251ea6ae205Smrg char *strings = NULL, *s; 252ea6ae205Smrg 253ea6ae205Smrg count = getLSB32(f); 254ea6ae205Smrg if(count <= 0) 255ea6ae205Smrg goto fail; 256ea6ae205Smrg 257ea6ae205Smrg prop_position = -1; 258ea6ae205Smrg for(i = 0; i < count; i++) { 259ea6ae205Smrg int type, offset; 260ea6ae205Smrg type = getLSB32(f); 261ea6ae205Smrg (void) getLSB32(f); 262ea6ae205Smrg (void) getLSB32(f); 263ea6ae205Smrg offset = getLSB32(f); 264ea6ae205Smrg if(type == PCF_PROPERTIES) { 265ea6ae205Smrg prop_position = offset; 266ea6ae205Smrg break; 267ea6ae205Smrg } 268ea6ae205Smrg } 269ea6ae205Smrg if(prop_position < 0) 270ea6ae205Smrg goto fail; 271ea6ae205Smrg 2727978d3cdSmrg rc = fontFileSeek(f, prop_position, SEEK_SET); 273ea6ae205Smrg if(rc < 0) 274ea6ae205Smrg goto fail; 275a5c37dfeSmrg 276ea6ae205Smrg format = getLSB32(f); 277ea6ae205Smrg if((format & 0xFFFFFF00) != 0) 278ea6ae205Smrg goto fail; 279ea6ae205Smrg nprops = getInt32(f, format); 280ea6ae205Smrg if(nprops <= 0 || nprops > 1000) 281ea6ae205Smrg goto fail; 282ea6ae205Smrg props = malloc(nprops * sizeof(PropRec)); 283ea6ae205Smrg if(props == NULL) 284ea6ae205Smrg goto fail; 285ea6ae205Smrg 286ea6ae205Smrg for(i = 0; i < nprops; i++) { 287ea6ae205Smrg props[i].name = getInt32(f, format); 288ea6ae205Smrg props[i].isString = getInt8(f, format); 289ea6ae205Smrg props[i].value = getInt32(f, format); 290ea6ae205Smrg } 291ea6ae205Smrg if(nprops & 3) { 2927978d3cdSmrg rc = fontFileSeek(f, 4 - (nprops & 3), SEEK_CUR); 293ea6ae205Smrg if(rc < 0) 294ea6ae205Smrg goto fail; 295ea6ae205Smrg } 296ea6ae205Smrg 297ea6ae205Smrg string_size = getInt32(f, format); 298ea6ae205Smrg if(string_size < 0 || string_size > 100000) 299ea6ae205Smrg goto fail; 300ea6ae205Smrg strings = malloc(string_size); 301ea6ae205Smrg if(!strings) 302ea6ae205Smrg goto fail; 303ea6ae205Smrg 3047978d3cdSmrg rc = fontFileRead(f, strings, string_size); 305ea6ae205Smrg if(rc != string_size) 306ea6ae205Smrg goto fail; 307ea6ae205Smrg 308ea6ae205Smrg for(i = 0; i < nprops; i++) { 309ea6ae205Smrg if(!props[i].isString || 310ea6ae205Smrg props[i].name >= string_size - 4 || 311ea6ae205Smrg props[i].value >= string_size) 312ea6ae205Smrg continue; 313ea6ae205Smrg if(strcmp(strings + props[i].name, "FONT") == 0) 314ea6ae205Smrg break; 315ea6ae205Smrg } 316ea6ae205Smrg 317ea6ae205Smrg if(i >= nprops) 318ea6ae205Smrg goto fail; 319ea6ae205Smrg 3202d6e8b77Smrg s = strdup(strings + props[i].value); 321ea6ae205Smrg if(s == NULL) 322ea6ae205Smrg goto fail; 323ea6ae205Smrg *name = s; 324ea6ae205Smrg free(strings); 325ea6ae205Smrg free(props); 3267978d3cdSmrg fontFileClose(f); 327ea6ae205Smrg return 1; 328ea6ae205Smrg 329ea6ae205Smrg fail: 330ea6ae205Smrg if(strings) free(strings); 331ea6ae205Smrg if(props) free(props); 3327978d3cdSmrg fontFileClose(f); 333ea6ae205Smrg return 0; 334ea6ae205Smrg} 335ea6ae205Smrg 336ea6ae205Smrg#define NKEY 20 337ea6ae205Smrg 338ea6ae205Smrgstatic char* 3397978d3cdSmrggetKeyword(fontFile *f, int *eol) 340ea6ae205Smrg{ 341ea6ae205Smrg static char keyword[NKEY + 1]; 342ea6ae205Smrg int c, i; 343ea6ae205Smrg i = 0; 344ea6ae205Smrg while(i < NKEY) { 3457978d3cdSmrg c = fontFileGetc(f); 346ea6ae205Smrg if(c == ' ' || c == '\n') { 347ea6ae205Smrg if(i <= 0) 348ea6ae205Smrg return NULL; 349ea6ae205Smrg if(eol) 350ea6ae205Smrg *eol = (c == '\n'); 351ea6ae205Smrg keyword[i] = '\0'; 352ea6ae205Smrg return keyword; 353ea6ae205Smrg } 354ea6ae205Smrg if(c < 'A' || c > 'Z') 355ea6ae205Smrg return NULL; 356ea6ae205Smrg keyword[i++] = c; 357ea6ae205Smrg } 358ea6ae205Smrg return NULL; 359ea6ae205Smrg} 360ea6ae205Smrg 361ea6ae205Smrgstatic int 3627978d3cdSmrgbdfskip(fontFile *f) 363ea6ae205Smrg{ 364ea6ae205Smrg int c; 365ea6ae205Smrg do { 3667978d3cdSmrg c = fontFileGetc(f); 367ea6ae205Smrg } while(c >= 0 && c != '\n'); 368ea6ae205Smrg if(c < 0) 369ea6ae205Smrg return -1; 370ea6ae205Smrg return 1; 371ea6ae205Smrg} 372ea6ae205Smrg 373ea6ae205Smrgstatic char * 3747978d3cdSmrgbdfend(fontFile *f) 375ea6ae205Smrg{ 376ea6ae205Smrg int c; 377ea6ae205Smrg char *buf = NULL; 378ea6ae205Smrg int bufsize = 0; 379ea6ae205Smrg int i = 0; 380ea6ae205Smrg 381ea6ae205Smrg do { 3827978d3cdSmrg c = fontFileGetc(f); 383ea6ae205Smrg } while (c == ' '); 384ea6ae205Smrg 385ea6ae205Smrg while(i < 1000) { 386ea6ae205Smrg if(c < 0 || (c == '\n' && i == 0)) { 387ea6ae205Smrg goto fail; 388ea6ae205Smrg } 389ea6ae205Smrg if(bufsize < i + 1) { 390ea6ae205Smrg char *newbuf; 391ea6ae205Smrg if(bufsize == 0) { 392ea6ae205Smrg bufsize = 20; 393ea6ae205Smrg newbuf = malloc(bufsize); 394ea6ae205Smrg } else { 395ea6ae205Smrg bufsize = 2 * bufsize; 396ea6ae205Smrg newbuf = realloc(buf, bufsize); 397ea6ae205Smrg } 398ea6ae205Smrg if(newbuf == NULL) 399ea6ae205Smrg goto fail; 400ea6ae205Smrg buf = newbuf; 401ea6ae205Smrg } 402ea6ae205Smrg if(c == '\n') { 403ea6ae205Smrg buf[i] = '\0'; 404ea6ae205Smrg return buf; 405ea6ae205Smrg } 406ea6ae205Smrg buf[i++] = c; 4077978d3cdSmrg c = fontFileGetc(f); 408ea6ae205Smrg } 409ea6ae205Smrg 410ea6ae205Smrg fail: 411ea6ae205Smrg if(buf) 412ea6ae205Smrg free(buf); 413ea6ae205Smrg return NULL; 414ea6ae205Smrg} 415ea6ae205Smrg 416ea6ae205Smrgstatic int 4177978d3cdSmrgbdfIdentify(fontFile *f, char **name) 418ea6ae205Smrg{ 419ea6ae205Smrg char *k; 420ea6ae205Smrg int rc; 421ea6ae205Smrg int eol; 422ea6ae205Smrg /* bitmapIdentify already read "STAR", so we need to check for 423ea6ae205Smrg "TFONT" */ 424ea6ae205Smrg k = getKeyword(f, &eol); 425ea6ae205Smrg if(k == NULL || eol) 426ea6ae205Smrg goto fail; 427ea6ae205Smrg if(strcmp(k, "TFONT") != 0) 428ea6ae205Smrg goto fail; 429ea6ae205Smrg while(1) { 430ea6ae205Smrg if(!eol) { 431ea6ae205Smrg rc = bdfskip(f); 432a5c37dfeSmrg if(rc < 0) 433ea6ae205Smrg goto fail; 434ea6ae205Smrg } 435ea6ae205Smrg k = getKeyword(f, &eol); 436ea6ae205Smrg if(k == NULL) 437ea6ae205Smrg goto fail; 438ea6ae205Smrg else if(strcmp(k, "FONT") == 0) { 439ea6ae205Smrg if(eol) 440ea6ae205Smrg goto fail; 441ea6ae205Smrg k = bdfend(f); 442ea6ae205Smrg if(k == NULL) 443ea6ae205Smrg goto fail; 444ea6ae205Smrg *name = k; 4457978d3cdSmrg fontFileClose(f); 446ea6ae205Smrg return 1; 447ea6ae205Smrg } else if(strcmp(k, "CHARS") == 0) 448ea6ae205Smrg goto fail; 449ea6ae205Smrg } 450ea6ae205Smrg fail: 4517978d3cdSmrg fontFileClose(f); 452ea6ae205Smrg return 0; 453ea6ae205Smrg} 454