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/* 236ae2c069Smrg * Copyright (c) 2008, Oracle and/or its affiliates. 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 606ae2c069Smrg#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 { 766ae2c069Smrg gzFile gz; 776ae2c069Smrg BZFILE *bz2; 787978d3cdSmrg } f; 797c5a9b20Smrg unsigned long pos; 807978d3cdSmrg} fontFile; 817978d3cdSmrg 827978d3cdSmrgstatic inline void * 836ae2c069SmrgfontFileOpen(fontFile *ff, const char *filename) 846ae2c069Smrg{ 857c5a9b20Smrg size_t n = strlen(filename); 867978d3cdSmrg 87eaa89f16Smrg if (n > 4 && strcmp(filename + n - 4, ".bz2") == 0) { 886ae2c069Smrg ff->type = bz2FontFile; 896ae2c069Smrg ff->f.bz2 = BZ2_bzopen(filename, "rb"); 906ae2c069Smrg ff->pos = 0; 916ae2c069Smrg return ff->f.bz2; 926ae2c069Smrg } 936ae2c069Smrg else { 946ae2c069Smrg ff->type = gzFontFile; 956ae2c069Smrg ff->f.gz = gzopen(filename, "rb"); 966ae2c069Smrg return ff->f.gz; 977978d3cdSmrg } 987978d3cdSmrg} 997978d3cdSmrg 1007978d3cdSmrgstatic inline int 1017978d3cdSmrgfontFileRead(fontFile *ff, void *buf, unsigned len) 1027978d3cdSmrg{ 1037978d3cdSmrg if (ff->type == gzFontFile) { 1046ae2c069Smrg return gzread(ff->f.gz, buf, len); 1056ae2c069Smrg } 1066ae2c069Smrg else { 1076ae2c069Smrg int r = BZ2_bzread(ff->f.bz2, buf, len); 1086ae2c069Smrg 1096ae2c069Smrg ff->pos += r; 1106ae2c069Smrg return r; 1117978d3cdSmrg } 1127978d3cdSmrg} 1137978d3cdSmrg 1147978d3cdSmrgstatic inline int 1157978d3cdSmrgfontFileGetc(fontFile *ff) 1167978d3cdSmrg{ 1177978d3cdSmrg if (ff->type == gzFontFile) { 1186ae2c069Smrg return gzgetc(ff->f.gz); 1196ae2c069Smrg } 1206ae2c069Smrg else { 1216ae2c069Smrg char buf; 1226ae2c069Smrg 1236ae2c069Smrg if (BZ2_bzread(ff->f.bz2, &buf, 1) != 1) { 1246ae2c069Smrg return -1; 1256ae2c069Smrg } 1266ae2c069Smrg else { 1276ae2c069Smrg ff->pos += 1; 1286ae2c069Smrg return (int) buf; 1296ae2c069Smrg } 1307978d3cdSmrg } 1317978d3cdSmrg} 1327978d3cdSmrg 1337c5a9b20Smrgstatic long 1347978d3cdSmrgfontFileSeek(fontFile *ff, z_off_t offset, int whence) 1357978d3cdSmrg{ 1367978d3cdSmrg if (ff->type == gzFontFile) { 1376ae2c069Smrg return gzseek(ff->f.gz, offset, whence); 1387978d3cdSmrg } 1396ae2c069Smrg else { 1406ae2c069Smrg /* bzlib has no easy equivalent so we have to fake it, 1416ae2c069Smrg * fortunately, we only have to handle a couple of cases 1426ae2c069Smrg */ 1436ae2c069Smrg z_off_t n; 1446ae2c069Smrg char buf[BUFSIZ]; 1456ae2c069Smrg 1466ae2c069Smrg switch (whence) { 1476ae2c069Smrg case SEEK_SET: 1486ae2c069Smrg n = offset - ff->pos; 1496ae2c069Smrg break; 1506ae2c069Smrg case SEEK_CUR: 1516ae2c069Smrg n = offset; 1526ae2c069Smrg break; 1536ae2c069Smrg default: 1546ae2c069Smrg return -1; 1556ae2c069Smrg } 1567978d3cdSmrg 1576ae2c069Smrg while (n > BUFSIZ) { 1586ae2c069Smrg if (BZ2_bzread(ff->f.bz2, buf, BUFSIZ) != BUFSIZ) 1596ae2c069Smrg return -1; 1606ae2c069Smrg n -= BUFSIZ; 1616ae2c069Smrg } 1626ae2c069Smrg if (BZ2_bzread(ff->f.bz2, buf, (int) n) != n) 1636ae2c069Smrg return -1; 1646ae2c069Smrg ff->pos = offset; 1656ae2c069Smrg return offset; 1666ae2c069Smrg } 1676ae2c069Smrg} 1687978d3cdSmrg 1697978d3cdSmrgstatic inline int 1707978d3cdSmrgfontFileClose(fontFile *ff) 1717978d3cdSmrg{ 1727978d3cdSmrg if (ff->type == gzFontFile) { 1736ae2c069Smrg return gzclose(ff->f.gz); 1746ae2c069Smrg } 1756ae2c069Smrg else { 1766ae2c069Smrg BZ2_bzclose(ff->f.bz2); 1776ae2c069Smrg return 0; 1787978d3cdSmrg } 1797978d3cdSmrg} 1807978d3cdSmrg 1816ae2c069Smrg#else /* no bzip2, only gzip */ 1827978d3cdSmrgtypedef gzFile fontFile; 1836ae2c069Smrg 1846ae2c069Smrg#define fontFileOpen(ff, filename) (*(ff) = gzopen(filename, "rb")) 1856ae2c069Smrg#define fontFileRead(ff, buf, len) gzread(*(ff), buf, len) 1866ae2c069Smrg#define fontFileGetc(ff) gzgetc(*(ff)) 1876ae2c069Smrg#define fontFileSeek(ff, off, whence) gzseek(*(ff), off, whence) 1886ae2c069Smrg#define fontFileClose(ff) gzclose(*(ff)) 1897978d3cdSmrg#endif 1907978d3cdSmrg 1917978d3cdSmrgstatic int pcfIdentify(fontFile *f, char **name); 1927978d3cdSmrgstatic int bdfIdentify(fontFile *f, char **name); 193ea6ae205Smrg 194ea6ae205Smrgstatic int 1957978d3cdSmrggetLSB32(fontFile *f) 196ea6ae205Smrg{ 197ea6ae205Smrg int rc; 198ea6ae205Smrg unsigned char c[4]; 199ea6ae205Smrg 2007978d3cdSmrg rc = fontFileRead(f, c, 4); 2016ae2c069Smrg if (rc != 4) 202ea6ae205Smrg return -1; 203ea6ae205Smrg return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); 204ea6ae205Smrg} 205ea6ae205Smrg 206ea6ae205Smrgstatic int 2077978d3cdSmrggetInt8(fontFile *f, int format) 208ea6ae205Smrg{ 209ea6ae205Smrg unsigned char c; 210ea6ae205Smrg int rc; 211ea6ae205Smrg 2127978d3cdSmrg rc = fontFileRead(f, &c, 1); 2136ae2c069Smrg if (rc != 1) 214ea6ae205Smrg return -1; 215ea6ae205Smrg return c; 216ea6ae205Smrg} 217ea6ae205Smrg 218ea6ae205Smrgstatic int 2197978d3cdSmrggetInt32(fontFile *f, int format) 220ea6ae205Smrg{ 221ea6ae205Smrg int rc; 222ea6ae205Smrg unsigned char c[4]; 223ea6ae205Smrg 2247978d3cdSmrg rc = fontFileRead(f, c, 4); 2256ae2c069Smrg if (rc != 4) 226ea6ae205Smrg return -1; 2276ae2c069Smrg else { 2286ae2c069Smrg unsigned int u[4] = { c[0], c[1], c[2], c[3] }; 229ea6ae205Smrg 2306ae2c069Smrg if (format & (1 << 2)) { 2316ae2c069Smrg return (int) ((u[0] << 24) | (u[1] << 16) | (u[2] << 8) | (u[3])); 2326ae2c069Smrg } 2336ae2c069Smrg else { 2346ae2c069Smrg return (int) ((u[0]) | (u[1] << 8) | (u[2] << 16) | (u[3] << 24)); 2356ae2c069Smrg } 236ea6ae205Smrg } 237ea6ae205Smrg} 238ea6ae205Smrg 239a5c37dfeSmrgint 2407978d3cdSmrgbitmapIdentify(const char *filename, char **name) 241ea6ae205Smrg{ 2427978d3cdSmrg fontFile ff; 243ea6ae205Smrg int magic; 244ea6ae205Smrg 2457978d3cdSmrg if (fontFileOpen(&ff, filename) == NULL) 2466ae2c069Smrg return -1; 247ea6ae205Smrg 2487978d3cdSmrg magic = getLSB32(&ff); 2496ae2c069Smrg if (magic == PCF_VERSION) 2507978d3cdSmrg return pcfIdentify(&ff, name); 2516ae2c069Smrg else if (magic == ('S' | ('T' << 8) | ('A' << 16) | ('R') << 24)) 2527978d3cdSmrg return bdfIdentify(&ff, name); 253ea6ae205Smrg 2547978d3cdSmrg fontFileClose(&ff); 255ea6ae205Smrg return 0; 256ea6ae205Smrg} 257ea6ae205Smrg 258ea6ae205Smrgstatic int 2597978d3cdSmrgpcfIdentify(fontFile *f, char **name) 260ea6ae205Smrg{ 261ea6ae205Smrg int prop_position; 262ea6ae205Smrg PropPtr props = NULL; 2637c5a9b20Smrg int format, count, nprops, i, string_size; 2647c5a9b20Smrg long rc; 265ea6ae205Smrg char *strings = NULL, *s; 266ea6ae205Smrg 267ea6ae205Smrg count = getLSB32(f); 2686ae2c069Smrg if (count <= 0) 269ea6ae205Smrg goto fail; 270ea6ae205Smrg 271ea6ae205Smrg prop_position = -1; 2726ae2c069Smrg for (i = 0; i < count; i++) { 273ea6ae205Smrg int type, offset; 2746ae2c069Smrg 275ea6ae205Smrg type = getLSB32(f); 276ea6ae205Smrg (void) getLSB32(f); 277ea6ae205Smrg (void) getLSB32(f); 278ea6ae205Smrg offset = getLSB32(f); 2796ae2c069Smrg if (type == PCF_PROPERTIES) { 280ea6ae205Smrg prop_position = offset; 281ea6ae205Smrg break; 282ea6ae205Smrg } 283ea6ae205Smrg } 2846ae2c069Smrg if (prop_position < 0) 285ea6ae205Smrg goto fail; 286ea6ae205Smrg 2877978d3cdSmrg rc = fontFileSeek(f, prop_position, SEEK_SET); 2886ae2c069Smrg if (rc < 0) 289ea6ae205Smrg goto fail; 290a5c37dfeSmrg 291ea6ae205Smrg format = getLSB32(f); 2926ae2c069Smrg if ((format & 0xFFFFFF00) != 0) 293ea6ae205Smrg goto fail; 294ea6ae205Smrg nprops = getInt32(f, format); 2956ae2c069Smrg if (nprops <= 0 || nprops > 1000) 296ea6ae205Smrg goto fail; 297ea6ae205Smrg props = malloc(nprops * sizeof(PropRec)); 2986ae2c069Smrg if (props == NULL) 299ea6ae205Smrg goto fail; 300ea6ae205Smrg 3016ae2c069Smrg for (i = 0; i < nprops; i++) { 302ea6ae205Smrg props[i].name = getInt32(f, format); 303ea6ae205Smrg props[i].isString = getInt8(f, format); 304ea6ae205Smrg props[i].value = getInt32(f, format); 305ea6ae205Smrg } 3066ae2c069Smrg if (nprops & 3) { 3076ae2c069Smrg rc = fontFileSeek(f, 4 - (nprops & 3), SEEK_CUR); 3086ae2c069Smrg if (rc < 0) 309ea6ae205Smrg goto fail; 310ea6ae205Smrg } 311ea6ae205Smrg 312ea6ae205Smrg string_size = getInt32(f, format); 3136ae2c069Smrg if (string_size < 0 || string_size > 100000) 314ea6ae205Smrg goto fail; 315ea6ae205Smrg strings = malloc(string_size); 3166ae2c069Smrg if (!strings) 317ea6ae205Smrg goto fail; 318ea6ae205Smrg 3197978d3cdSmrg rc = fontFileRead(f, strings, string_size); 3206ae2c069Smrg if (rc != string_size) 321ea6ae205Smrg goto fail; 322ea6ae205Smrg 3236ae2c069Smrg for (i = 0; i < nprops; i++) { 3246ae2c069Smrg if (!props[i].isString || 3256ae2c069Smrg props[i].name >= string_size - 4 || props[i].value >= string_size) 326ea6ae205Smrg continue; 3276ae2c069Smrg if (strcmp(strings + props[i].name, "FONT") == 0) 328ea6ae205Smrg break; 329ea6ae205Smrg } 330ea6ae205Smrg 3316ae2c069Smrg if (i >= nprops) 332ea6ae205Smrg goto fail; 333ea6ae205Smrg 3342d6e8b77Smrg s = strdup(strings + props[i].value); 3356ae2c069Smrg if (s == NULL) 336ea6ae205Smrg goto fail; 337ea6ae205Smrg *name = s; 338ea6ae205Smrg free(strings); 339ea6ae205Smrg free(props); 3407978d3cdSmrg fontFileClose(f); 341ea6ae205Smrg return 1; 342ea6ae205Smrg 343ea6ae205Smrg fail: 3446ae2c069Smrg if (strings) 3456ae2c069Smrg free(strings); 3466ae2c069Smrg if (props) 3476ae2c069Smrg free(props); 3487978d3cdSmrg fontFileClose(f); 349ea6ae205Smrg return 0; 350ea6ae205Smrg} 351ea6ae205Smrg 352ea6ae205Smrg#define NKEY 20 353ea6ae205Smrg 3546ae2c069Smrgstatic char * 3557978d3cdSmrggetKeyword(fontFile *f, int *eol) 356ea6ae205Smrg{ 357ea6ae205Smrg static char keyword[NKEY + 1]; 3586ae2c069Smrg int i = 0; 3596ae2c069Smrg 3606ae2c069Smrg while (i < NKEY) { 3616ae2c069Smrg int c = fontFileGetc(f); 3626ae2c069Smrg if (c == ' ' || c == '\n') { 3636ae2c069Smrg if (i <= 0) 364ea6ae205Smrg return NULL; 3656ae2c069Smrg if (eol) 366ea6ae205Smrg *eol = (c == '\n'); 367ea6ae205Smrg keyword[i] = '\0'; 368ea6ae205Smrg return keyword; 369ea6ae205Smrg } 3706ae2c069Smrg if (c < 'A' || c > 'Z') 371ea6ae205Smrg return NULL; 372ea6ae205Smrg keyword[i++] = c; 373ea6ae205Smrg } 374ea6ae205Smrg return NULL; 375ea6ae205Smrg} 376ea6ae205Smrg 377ea6ae205Smrgstatic int 3787978d3cdSmrgbdfskip(fontFile *f) 379ea6ae205Smrg{ 380ea6ae205Smrg int c; 3816ae2c069Smrg 382ea6ae205Smrg do { 3837978d3cdSmrg c = fontFileGetc(f); 3846ae2c069Smrg } while (c >= 0 && c != '\n'); 3856ae2c069Smrg if (c < 0) 386ea6ae205Smrg return -1; 387ea6ae205Smrg return 1; 388ea6ae205Smrg} 389ea6ae205Smrg 390ea6ae205Smrgstatic char * 3917978d3cdSmrgbdfend(fontFile *f) 392ea6ae205Smrg{ 393ea6ae205Smrg int c; 394ea6ae205Smrg char *buf = NULL; 3956ae2c069Smrg size_t bufsize = 0; 3966ae2c069Smrg unsigned int i = 0; 397ea6ae205Smrg 398ea6ae205Smrg do { 3997978d3cdSmrg c = fontFileGetc(f); 400ea6ae205Smrg } while (c == ' '); 401ea6ae205Smrg 4026ae2c069Smrg while (i < 1000) { 4036ae2c069Smrg if (c < 0 || (c == '\n' && i == 0)) { 404ea6ae205Smrg goto fail; 405ea6ae205Smrg } 4066ae2c069Smrg if (bufsize < i + 1) { 407ea6ae205Smrg char *newbuf; 4086ae2c069Smrg 4096ae2c069Smrg if (bufsize == 0) { 410ea6ae205Smrg bufsize = 20; 411ea6ae205Smrg newbuf = malloc(bufsize); 4126ae2c069Smrg } 4136ae2c069Smrg else { 414ea6ae205Smrg bufsize = 2 * bufsize; 415ea6ae205Smrg newbuf = realloc(buf, bufsize); 416ea6ae205Smrg } 4176ae2c069Smrg if (newbuf == NULL) 418ea6ae205Smrg goto fail; 419ea6ae205Smrg buf = newbuf; 420ea6ae205Smrg } 4216ae2c069Smrg if (c == '\n') { 422ea6ae205Smrg buf[i] = '\0'; 423ea6ae205Smrg return buf; 424ea6ae205Smrg } 425ea6ae205Smrg buf[i++] = c; 4267978d3cdSmrg c = fontFileGetc(f); 427ea6ae205Smrg } 428ea6ae205Smrg 429ea6ae205Smrg fail: 4306ae2c069Smrg if (buf) 431ea6ae205Smrg free(buf); 432ea6ae205Smrg return NULL; 433ea6ae205Smrg} 434ea6ae205Smrg 435ea6ae205Smrgstatic int 4367978d3cdSmrgbdfIdentify(fontFile *f, char **name) 437ea6ae205Smrg{ 438ea6ae205Smrg char *k; 439ea6ae205Smrg int eol; 4406ae2c069Smrg 441ea6ae205Smrg /* bitmapIdentify already read "STAR", so we need to check for 442ea6ae205Smrg "TFONT" */ 443ea6ae205Smrg k = getKeyword(f, &eol); 4446ae2c069Smrg if (k == NULL || eol) 445ea6ae205Smrg goto fail; 4466ae2c069Smrg if (strcmp(k, "TFONT") != 0) 447ea6ae205Smrg goto fail; 4486ae2c069Smrg while (1) { 4496ae2c069Smrg if (!eol) { 4506ae2c069Smrg int rc = bdfskip(f); 4516ae2c069Smrg if (rc < 0) 452ea6ae205Smrg goto fail; 453ea6ae205Smrg } 454ea6ae205Smrg k = getKeyword(f, &eol); 4556ae2c069Smrg if (k == NULL) 456ea6ae205Smrg goto fail; 4576ae2c069Smrg else if (strcmp(k, "FONT") == 0) { 4586ae2c069Smrg if (eol) 459ea6ae205Smrg goto fail; 460ea6ae205Smrg k = bdfend(f); 4616ae2c069Smrg if (k == NULL) 462ea6ae205Smrg goto fail; 463ea6ae205Smrg *name = k; 4647978d3cdSmrg fontFileClose(f); 465ea6ae205Smrg return 1; 4666ae2c069Smrg } 4676ae2c069Smrg else if (strcmp(k, "CHARS") == 0) 468ea6ae205Smrg goto fail; 469ea6ae205Smrg } 470ea6ae205Smrg fail: 4717978d3cdSmrg fontFileClose(f); 472ea6ae205Smrg return 0; 473ea6ae205Smrg} 474