1 /* 2 * Copyright 2000 Computing Research Labs, New Mexico State University 3 * Copyright 2001-2014 4 * Francesco Zappa Nardelli 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY 20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 /*************************************************************************/ 26 /* */ 27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */ 28 /* */ 29 /* taken from Mark Leisher's xmbdfed package */ 30 /* */ 31 /*************************************************************************/ 32 33 34 #include <ft2build.h> 35 36 #include FT_FREETYPE_H 37 #include FT_INTERNAL_DEBUG_H 38 #include FT_INTERNAL_STREAM_H 39 #include FT_INTERNAL_OBJECTS_H 40 41 #include "bdf.h" 42 #include "bdferror.h" 43 44 45 /*************************************************************************/ 46 /* */ 47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 49 /* messages during execution. */ 50 /* */ 51 #undef FT_COMPONENT 52 #define FT_COMPONENT trace_bdflib 53 54 55 /*************************************************************************/ 56 /* */ 57 /* Default BDF font options. */ 58 /* */ 59 /*************************************************************************/ 60 61 62 static const bdf_options_t _bdf_opts = 63 { 64 1, /* Correct metrics. */ 65 1, /* Preserve unencoded glyphs. */ 66 0, /* Preserve comments. */ 67 BDF_PROPORTIONAL /* Default spacing. */ 68 }; 69 70 71 /*************************************************************************/ 72 /* */ 73 /* Builtin BDF font properties. */ 74 /* */ 75 /*************************************************************************/ 76 77 /* List of most properties that might appear in a font. Doesn't include */ 78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */ 79 80 static const bdf_property_t _bdf_properties[] = 81 { 82 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, 83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, 84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, 85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, 86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, 87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, 88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, 89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, 90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } }, 91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } }, 92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, 93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } }, 94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } }, 95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } }, 96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } }, 97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } }, 98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, 99 { (char *)"FONT", BDF_ATOM, 1, { 0 } }, 100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } }, 101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } }, 102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } }, 103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } }, 104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } }, 105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } }, 106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } }, 107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } }, 108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } }, 109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } }, 110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, 111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } }, 112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, 113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } }, 114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, 115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, 116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, 117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, 118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } }, 119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } }, 120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, 121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } }, 122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } }, 123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } }, 124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, 125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } }, 126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } }, 127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } }, 128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, 129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, 130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, 131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, 132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, 139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, 140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } }, 141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } }, 142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } }, 143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } }, 144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } }, 145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } }, 146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } }, 147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } }, 148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, 149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } }, 150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, 151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, 152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, 159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, 160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } }, 161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } }, 162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } }, 163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } }, 164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } }, 165 }; 166 167 static const unsigned long 168 _num_bdf_properties = sizeof ( _bdf_properties ) / 169 sizeof ( _bdf_properties[0] ); 170 171 172 /* Auto correction messages. */ 173 #define ACMSG1 "FONT_ASCENT property missing. " \ 174 "Added `FONT_ASCENT %hd'.\n" 175 #define ACMSG2 "FONT_DESCENT property missing. " \ 176 "Added `FONT_DESCENT %hd'.\n" 177 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n" 178 #define ACMSG4 "Font left bearing != actual left bearing. " \ 179 "Old: %hd New: %hd.\n" 180 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n" 181 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n" 182 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n" 183 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n" 184 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n" 185 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n" 186 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" 187 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n" 188 #define ACMSG13 "Glyph %ld extra rows removed.\n" 189 #define ACMSG14 "Glyph %ld extra columns removed.\n" 190 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n" 191 #define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n" 192 193 /* Error messages. */ 194 #define ERRMSG1 "[line %ld] Missing `%s' line.\n" 195 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n" 196 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n" 197 #define ERRMSG4 "[line %ld] BBX too big.\n" 198 #define ERRMSG5 "[line %ld] `%s' value too big.\n" 199 #define ERRMSG6 "[line %ld] Input line too long.\n" 200 #define ERRMSG7 "[line %ld] Font name too long.\n" 201 #define ERRMSG8 "[line %ld] Invalid `%s' value.\n" 202 #define ERRMSG9 "[line %ld] Invalid keyword.\n" 203 204 /* Debug messages. */ 205 #define DBGMSG1 " [%6ld] %s" /* no \n */ 206 #define DBGMSG2 " (0x%lX)\n" 207 208 209 /*************************************************************************/ 210 /* */ 211 /* Hash table utilities for the properties. */ 212 /* */ 213 /*************************************************************************/ 214 215 /* XXX: Replace this with FreeType's hash functions */ 216 217 218 #define INITIAL_HT_SIZE 241 219 220 typedef void 221 (*hash_free_func)( hashnode node ); 222 223 static hashnode* hash_bucket(const char * key,hashtable * ht)224 hash_bucket( const char* key, 225 hashtable* ht ) 226 { 227 const char* kp = key; 228 unsigned long res = 0; 229 hashnode* bp = ht->table, *ndp; 230 231 232 /* Mocklisp hash function. */ 233 while ( *kp ) 234 res = ( res << 5 ) - res + *kp++; 235 236 ndp = bp + ( res % ht->size ); 237 while ( *ndp ) 238 { 239 kp = (*ndp)->key; 240 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 ) 241 break; 242 ndp--; 243 if ( ndp < bp ) 244 ndp = bp + ( ht->size - 1 ); 245 } 246 247 return ndp; 248 } 249 250 251 static FT_Error hash_rehash(hashtable * ht,FT_Memory memory)252 hash_rehash( hashtable* ht, 253 FT_Memory memory ) 254 { 255 hashnode* obp = ht->table, *bp, *nbp; 256 int i, sz = ht->size; 257 FT_Error error = FT_Err_Ok; 258 259 260 ht->size <<= 1; 261 ht->limit = ht->size / 3; 262 263 if ( FT_NEW_ARRAY( ht->table, ht->size ) ) 264 goto Exit; 265 266 for ( i = 0, bp = obp; i < sz; i++, bp++ ) 267 { 268 if ( *bp ) 269 { 270 nbp = hash_bucket( (*bp)->key, ht ); 271 *nbp = *bp; 272 } 273 } 274 FT_FREE( obp ); 275 276 Exit: 277 return error; 278 } 279 280 281 static FT_Error hash_init(hashtable * ht,FT_Memory memory)282 hash_init( hashtable* ht, 283 FT_Memory memory ) 284 { 285 int sz = INITIAL_HT_SIZE; 286 FT_Error error = FT_Err_Ok; 287 288 289 ht->size = sz; 290 ht->limit = sz / 3; 291 ht->used = 0; 292 293 if ( FT_NEW_ARRAY( ht->table, sz ) ) 294 goto Exit; 295 296 Exit: 297 return error; 298 } 299 300 301 static void hash_free(hashtable * ht,FT_Memory memory)302 hash_free( hashtable* ht, 303 FT_Memory memory ) 304 { 305 if ( ht != 0 ) 306 { 307 int i, sz = ht->size; 308 hashnode* bp = ht->table; 309 310 311 for ( i = 0; i < sz; i++, bp++ ) 312 FT_FREE( *bp ); 313 314 FT_FREE( ht->table ); 315 } 316 } 317 318 319 static FT_Error hash_insert(char * key,size_t data,hashtable * ht,FT_Memory memory)320 hash_insert( char* key, 321 size_t data, 322 hashtable* ht, 323 FT_Memory memory ) 324 { 325 hashnode nn; 326 hashnode* bp = hash_bucket( key, ht ); 327 FT_Error error = FT_Err_Ok; 328 329 330 nn = *bp; 331 if ( !nn ) 332 { 333 if ( FT_NEW( nn ) ) 334 goto Exit; 335 *bp = nn; 336 337 nn->key = key; 338 nn->data = data; 339 340 if ( ht->used >= ht->limit ) 341 { 342 error = hash_rehash( ht, memory ); 343 if ( error ) 344 goto Exit; 345 } 346 ht->used++; 347 } 348 else 349 nn->data = data; 350 351 Exit: 352 return error; 353 } 354 355 356 static hashnode hash_lookup(const char * key,hashtable * ht)357 hash_lookup( const char* key, 358 hashtable* ht ) 359 { 360 hashnode *np = hash_bucket( key, ht ); 361 362 363 return *np; 364 } 365 366 367 /*************************************************************************/ 368 /* */ 369 /* Utility types and functions. */ 370 /* */ 371 /*************************************************************************/ 372 373 374 /* Function type for parsing lines of a BDF font. */ 375 376 typedef FT_Error 377 (*_bdf_line_func_t)( char* line, 378 unsigned long linelen, 379 unsigned long lineno, 380 void* call_data, 381 void* client_data ); 382 383 384 /* List structure for splitting lines into fields. */ 385 386 typedef struct _bdf_list_t_ 387 { 388 char** field; 389 unsigned long size; 390 unsigned long used; 391 FT_Memory memory; 392 393 } _bdf_list_t; 394 395 396 /* Structure used while loading BDF fonts. */ 397 398 typedef struct _bdf_parse_t_ 399 { 400 unsigned long flags; 401 unsigned long cnt; 402 unsigned long row; 403 404 short minlb; 405 short maxlb; 406 short maxrb; 407 short maxas; 408 short maxds; 409 410 short rbearing; 411 412 char* glyph_name; 413 long glyph_enc; 414 415 bdf_font_t* font; 416 bdf_options_t* opts; 417 418 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */ 419 /* arrays from `bdf_font_t' structure */ 420 _bdf_list_t list; 421 422 FT_Memory memory; 423 424 } _bdf_parse_t; 425 426 427 #define setsbit( m, cc ) \ 428 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) ) 429 #define sbitset( m, cc ) \ 430 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) 431 432 433 static void _bdf_list_init(_bdf_list_t * list,FT_Memory memory)434 _bdf_list_init( _bdf_list_t* list, 435 FT_Memory memory ) 436 { 437 FT_ZERO( list ); 438 list->memory = memory; 439 } 440 441 442 static void _bdf_list_done(_bdf_list_t * list)443 _bdf_list_done( _bdf_list_t* list ) 444 { 445 FT_Memory memory = list->memory; 446 447 448 if ( memory ) 449 { 450 FT_FREE( list->field ); 451 FT_ZERO( list ); 452 } 453 } 454 455 456 static FT_Error _bdf_list_ensure(_bdf_list_t * list,unsigned long num_items)457 _bdf_list_ensure( _bdf_list_t* list, 458 unsigned long num_items ) /* same as _bdf_list_t.used */ 459 { 460 FT_Error error = FT_Err_Ok; 461 462 463 if ( num_items > list->size ) 464 { 465 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */ 466 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5; 467 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) ); 468 FT_Memory memory = list->memory; 469 470 471 if ( oldsize == bigsize ) 472 { 473 error = FT_THROW( Out_Of_Memory ); 474 goto Exit; 475 } 476 else if ( newsize < oldsize || newsize > bigsize ) 477 newsize = bigsize; 478 479 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) ) 480 goto Exit; 481 482 list->size = newsize; 483 } 484 485 Exit: 486 return error; 487 } 488 489 490 static void _bdf_list_shift(_bdf_list_t * list,unsigned long n)491 _bdf_list_shift( _bdf_list_t* list, 492 unsigned long n ) 493 { 494 unsigned long i, u; 495 496 497 if ( list == 0 || list->used == 0 || n == 0 ) 498 return; 499 500 if ( n >= list->used ) 501 { 502 list->used = 0; 503 return; 504 } 505 506 for ( u = n, i = 0; u < list->used; i++, u++ ) 507 list->field[i] = list->field[u]; 508 list->used -= n; 509 } 510 511 512 /* An empty string for empty fields. */ 513 514 static const char empty[1] = { 0 }; /* XXX eliminate this */ 515 516 517 static char * _bdf_list_join(_bdf_list_t * list,int c,unsigned long * alen)518 _bdf_list_join( _bdf_list_t* list, 519 int c, 520 unsigned long *alen ) 521 { 522 unsigned long i, j; 523 char* dp; 524 525 526 *alen = 0; 527 528 if ( list == 0 || list->used == 0 ) 529 return 0; 530 531 dp = list->field[0]; 532 for ( i = j = 0; i < list->used; i++ ) 533 { 534 char* fp = list->field[i]; 535 536 537 while ( *fp ) 538 dp[j++] = *fp++; 539 540 if ( i + 1 < list->used ) 541 dp[j++] = (char)c; 542 } 543 if ( dp != empty ) 544 dp[j] = 0; 545 546 *alen = j; 547 return dp; 548 } 549 550 551 /* The code below ensures that we have at least 4 + 1 `field' */ 552 /* elements in `list' (which are possibly NULL) so that we */ 553 /* don't have to check the number of fields in most cases. */ 554 555 static FT_Error _bdf_list_split(_bdf_list_t * list,char * separators,char * line,unsigned long linelen)556 _bdf_list_split( _bdf_list_t* list, 557 char* separators, 558 char* line, 559 unsigned long linelen ) 560 { 561 int mult, final_empty; 562 char *sp, *ep, *end; 563 char seps[32]; 564 FT_Error error = FT_Err_Ok; 565 566 567 /* Initialize the list. */ 568 list->used = 0; 569 if ( list->size ) 570 { 571 list->field[0] = (char*)empty; 572 list->field[1] = (char*)empty; 573 list->field[2] = (char*)empty; 574 list->field[3] = (char*)empty; 575 list->field[4] = (char*)empty; 576 } 577 578 /* If the line is empty, then simply return. */ 579 if ( linelen == 0 || line[0] == 0 ) 580 goto Exit; 581 582 /* In the original code, if the `separators' parameter is NULL or */ 583 /* empty, the list is split into individual bytes. We don't need */ 584 /* this, so an error is signaled. */ 585 if ( separators == 0 || *separators == 0 ) 586 { 587 error = FT_THROW( Invalid_Argument ); 588 goto Exit; 589 } 590 591 /* Prepare the separator bitmap. */ 592 FT_MEM_ZERO( seps, 32 ); 593 594 /* If the very last character of the separator string is a plus, then */ 595 /* set the `mult' flag to indicate that multiple separators should be */ 596 /* collapsed into one. */ 597 for ( mult = 0, sp = separators; sp && *sp; sp++ ) 598 { 599 if ( *sp == '+' && *( sp + 1 ) == 0 ) 600 mult = 1; 601 else 602 setsbit( seps, *sp ); 603 } 604 605 /* Break the line up into fields. */ 606 for ( final_empty = 0, sp = ep = line, end = sp + linelen; 607 sp < end && *sp; ) 608 { 609 /* Collect everything that is not a separator. */ 610 for ( ; *ep && !sbitset( seps, *ep ); ep++ ) 611 ; 612 613 /* Resize the list if necessary. */ 614 if ( list->used == list->size ) 615 { 616 error = _bdf_list_ensure( list, list->used + 1 ); 617 if ( error ) 618 goto Exit; 619 } 620 621 /* Assign the field appropriately. */ 622 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty; 623 624 sp = ep; 625 626 if ( mult ) 627 { 628 /* If multiple separators should be collapsed, do it now by */ 629 /* setting all the separator characters to 0. */ 630 for ( ; *ep && sbitset( seps, *ep ); ep++ ) 631 *ep = 0; 632 } 633 else if ( *ep != 0 ) 634 /* Don't collapse multiple separators by making them 0, so just */ 635 /* make the one encountered 0. */ 636 *ep++ = 0; 637 638 final_empty = ( ep > sp && *ep == 0 ); 639 sp = ep; 640 } 641 642 /* Finally, NULL-terminate the list. */ 643 if ( list->used + final_empty >= list->size ) 644 { 645 error = _bdf_list_ensure( list, list->used + final_empty + 1 ); 646 if ( error ) 647 goto Exit; 648 } 649 650 if ( final_empty ) 651 list->field[list->used++] = (char*)empty; 652 653 list->field[list->used] = 0; 654 655 Exit: 656 return error; 657 } 658 659 660 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */ 661 662 663 static FT_Error _bdf_readstream(FT_Stream stream,_bdf_line_func_t callback,void * client_data,unsigned long * lno)664 _bdf_readstream( FT_Stream stream, 665 _bdf_line_func_t callback, 666 void* client_data, 667 unsigned long *lno ) 668 { 669 _bdf_line_func_t cb; 670 unsigned long lineno, buf_size; 671 int refill, hold, to_skip; 672 ptrdiff_t bytes, start, end, cursor, avail; 673 char* buf = 0; 674 FT_Memory memory = stream->memory; 675 FT_Error error = FT_Err_Ok; 676 677 678 if ( callback == 0 ) 679 { 680 error = FT_THROW( Invalid_Argument ); 681 goto Exit; 682 } 683 684 /* initial size and allocation of the input buffer */ 685 buf_size = 1024; 686 687 if ( FT_NEW_ARRAY( buf, buf_size ) ) 688 goto Exit; 689 690 cb = callback; 691 lineno = 1; 692 buf[0] = 0; 693 start = 0; 694 avail = 0; 695 cursor = 0; 696 refill = 1; 697 to_skip = NO_SKIP; 698 bytes = 0; /* make compiler happy */ 699 700 for (;;) 701 { 702 if ( refill ) 703 { 704 bytes = (ptrdiff_t)FT_Stream_TryRead( 705 stream, (FT_Byte*)buf + cursor, 706 (FT_ULong)( buf_size - cursor ) ); 707 avail = cursor + bytes; 708 cursor = 0; 709 refill = 0; 710 } 711 712 end = start; 713 714 /* should we skip an optional character like \n or \r? */ 715 if ( start < avail && buf[start] == to_skip ) 716 { 717 start += 1; 718 to_skip = NO_SKIP; 719 continue; 720 } 721 722 /* try to find the end of the line */ 723 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' ) 724 end++; 725 726 /* if we hit the end of the buffer, try shifting its content */ 727 /* or even resizing it */ 728 if ( end >= avail ) 729 { 730 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */ 731 break; /* ignore it then exit */ 732 733 if ( start == 0 ) 734 { 735 /* this line is definitely too long; try resizing the input */ 736 /* buffer a bit to handle it. */ 737 FT_ULong new_size; 738 739 740 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */ 741 { 742 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno )); 743 error = FT_THROW( Invalid_Argument ); 744 goto Exit; 745 } 746 747 new_size = buf_size * 2; 748 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) ) 749 goto Exit; 750 751 cursor = buf_size; 752 buf_size = new_size; 753 } 754 else 755 { 756 bytes = avail - start; 757 758 FT_MEM_MOVE( buf, buf + start, bytes ); 759 760 cursor = bytes; 761 avail -= bytes; 762 start = 0; 763 } 764 refill = 1; 765 continue; 766 } 767 768 /* Temporarily NUL-terminate the line. */ 769 hold = buf[end]; 770 buf[end] = 0; 771 772 /* XXX: Use encoding independent value for 0x1a */ 773 if ( buf[start] != '#' && buf[start] != 0x1a && end > start ) 774 { 775 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, 776 (void*)&cb, client_data ); 777 /* Redo if we have encountered CHARS without properties. */ 778 if ( error == -1 ) 779 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, 780 (void*)&cb, client_data ); 781 if ( error ) 782 break; 783 } 784 785 lineno += 1; 786 buf[end] = (char)hold; 787 start = end + 1; 788 789 if ( hold == '\n' ) 790 to_skip = '\r'; 791 else if ( hold == '\r' ) 792 to_skip = '\n'; 793 else 794 to_skip = NO_SKIP; 795 } 796 797 *lno = lineno; 798 799 Exit: 800 FT_FREE( buf ); 801 return error; 802 } 803 804 805 /* XXX: make this work with EBCDIC also */ 806 807 static const unsigned char a2i[128] = 808 { 809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 813 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, 814 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 817 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 820 }; 821 822 static const unsigned char odigits[32] = 823 { 824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 828 }; 829 830 static const unsigned char ddigits[32] = 831 { 832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 836 }; 837 838 static const unsigned char hdigits[32] = 839 { 840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 841 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 844 }; 845 846 847 /* Routine to convert an ASCII string into an unsigned long integer. */ 848 static unsigned long _bdf_atoul(char * s,char ** end,int base)849 _bdf_atoul( char* s, 850 char** end, 851 int base ) 852 { 853 unsigned long v; 854 const unsigned char* dmap; 855 856 857 if ( s == 0 || *s == 0 ) 858 return 0; 859 860 /* Make sure the radix is something recognizable. Default to 10. */ 861 switch ( base ) 862 { 863 case 8: 864 dmap = odigits; 865 break; 866 case 16: 867 dmap = hdigits; 868 break; 869 default: 870 base = 10; 871 dmap = ddigits; 872 break; 873 } 874 875 /* Check for the special hex prefix. */ 876 if ( *s == '0' && 877 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) 878 { 879 base = 16; 880 dmap = hdigits; 881 s += 2; 882 } 883 884 for ( v = 0; sbitset( dmap, *s ); s++ ) 885 v = v * base + a2i[(int)*s]; 886 887 if ( end != 0 ) 888 *end = s; 889 890 return v; 891 } 892 893 894 /* Routine to convert an ASCII string into an signed long integer. */ 895 static long _bdf_atol(char * s,char ** end,int base)896 _bdf_atol( char* s, 897 char** end, 898 int base ) 899 { 900 long v, neg; 901 const unsigned char* dmap; 902 903 904 if ( s == 0 || *s == 0 ) 905 return 0; 906 907 /* Make sure the radix is something recognizable. Default to 10. */ 908 switch ( base ) 909 { 910 case 8: 911 dmap = odigits; 912 break; 913 case 16: 914 dmap = hdigits; 915 break; 916 default: 917 base = 10; 918 dmap = ddigits; 919 break; 920 } 921 922 /* Check for a minus sign. */ 923 neg = 0; 924 if ( *s == '-' ) 925 { 926 s++; 927 neg = 1; 928 } 929 930 /* Check for the special hex prefix. */ 931 if ( *s == '0' && 932 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) 933 { 934 base = 16; 935 dmap = hdigits; 936 s += 2; 937 } 938 939 for ( v = 0; sbitset( dmap, *s ); s++ ) 940 v = v * base + a2i[(int)*s]; 941 942 if ( end != 0 ) 943 *end = s; 944 945 return ( !neg ) ? v : -v; 946 } 947 948 949 /* Routine to convert an ASCII string into an signed short integer. */ 950 static short _bdf_atos(char * s,char ** end,int base)951 _bdf_atos( char* s, 952 char** end, 953 int base ) 954 { 955 short v, neg; 956 const unsigned char* dmap; 957 958 959 if ( s == 0 || *s == 0 ) 960 return 0; 961 962 /* Make sure the radix is something recognizable. Default to 10. */ 963 switch ( base ) 964 { 965 case 8: 966 dmap = odigits; 967 break; 968 case 16: 969 dmap = hdigits; 970 break; 971 default: 972 base = 10; 973 dmap = ddigits; 974 break; 975 } 976 977 /* Check for a minus. */ 978 neg = 0; 979 if ( *s == '-' ) 980 { 981 s++; 982 neg = 1; 983 } 984 985 /* Check for the special hex prefix. */ 986 if ( *s == '0' && 987 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) 988 { 989 base = 16; 990 dmap = hdigits; 991 s += 2; 992 } 993 994 for ( v = 0; sbitset( dmap, *s ); s++ ) 995 v = (short)( v * base + a2i[(int)*s] ); 996 997 if ( end != 0 ) 998 *end = s; 999 1000 return (short)( ( !neg ) ? v : -v ); 1001 } 1002 1003 1004 /* Routine to compare two glyphs by encoding so they can be sorted. */ 1005 static int by_encoding(const void * a,const void * b)1006 by_encoding( const void* a, 1007 const void* b ) 1008 { 1009 bdf_glyph_t *c1, *c2; 1010 1011 1012 c1 = (bdf_glyph_t *)a; 1013 c2 = (bdf_glyph_t *)b; 1014 1015 if ( c1->encoding < c2->encoding ) 1016 return -1; 1017 1018 if ( c1->encoding > c2->encoding ) 1019 return 1; 1020 1021 return 0; 1022 } 1023 1024 1025 static FT_Error bdf_create_property(char * name,int format,bdf_font_t * font)1026 bdf_create_property( char* name, 1027 int format, 1028 bdf_font_t* font ) 1029 { 1030 size_t n; 1031 bdf_property_t* p; 1032 FT_Memory memory = font->memory; 1033 FT_Error error = FT_Err_Ok; 1034 1035 1036 /* First check whether the property has */ 1037 /* already been added or not. If it has, then */ 1038 /* simply ignore it. */ 1039 if ( hash_lookup( name, &(font->proptbl) ) ) 1040 goto Exit; 1041 1042 if ( FT_RENEW_ARRAY( font->user_props, 1043 font->nuser_props, 1044 font->nuser_props + 1 ) ) 1045 goto Exit; 1046 1047 p = font->user_props + font->nuser_props; 1048 FT_ZERO( p ); 1049 1050 n = ft_strlen( name ) + 1; 1051 if ( n > FT_ULONG_MAX ) 1052 return FT_THROW( Invalid_Argument ); 1053 1054 if ( FT_NEW_ARRAY( p->name, n ) ) 1055 goto Exit; 1056 1057 FT_MEM_COPY( (char *)p->name, name, n ); 1058 1059 p->format = format; 1060 p->builtin = 0; 1061 1062 n = _num_bdf_properties + font->nuser_props; 1063 1064 error = hash_insert( p->name, n, &(font->proptbl), memory ); 1065 if ( error ) 1066 goto Exit; 1067 1068 font->nuser_props++; 1069 1070 Exit: 1071 return error; 1072 } 1073 1074 1075 FT_LOCAL_DEF( bdf_property_t * ) bdf_get_property(char * name,bdf_font_t * font)1076 bdf_get_property( char* name, 1077 bdf_font_t* font ) 1078 { 1079 hashnode hn; 1080 size_t propid; 1081 1082 1083 if ( name == 0 || *name == 0 ) 1084 return 0; 1085 1086 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 ) 1087 return 0; 1088 1089 propid = hn->data; 1090 if ( propid >= _num_bdf_properties ) 1091 return font->user_props + ( propid - _num_bdf_properties ); 1092 1093 return (bdf_property_t*)_bdf_properties + propid; 1094 } 1095 1096 1097 /*************************************************************************/ 1098 /* */ 1099 /* BDF font file parsing flags and functions. */ 1100 /* */ 1101 /*************************************************************************/ 1102 1103 1104 /* Parse flags. */ 1105 1106 #define _BDF_START 0x0001 1107 #define _BDF_FONT_NAME 0x0002 1108 #define _BDF_SIZE 0x0004 1109 #define _BDF_FONT_BBX 0x0008 1110 #define _BDF_PROPS 0x0010 1111 #define _BDF_GLYPHS 0x0020 1112 #define _BDF_GLYPH 0x0040 1113 #define _BDF_ENCODING 0x0080 1114 #define _BDF_SWIDTH 0x0100 1115 #define _BDF_DWIDTH 0x0200 1116 #define _BDF_BBX 0x0400 1117 #define _BDF_BITMAP 0x0800 1118 1119 #define _BDF_SWIDTH_ADJ 0x1000 1120 1121 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \ 1122 _BDF_ENCODING | \ 1123 _BDF_SWIDTH | \ 1124 _BDF_DWIDTH | \ 1125 _BDF_BBX | \ 1126 _BDF_BITMAP ) 1127 1128 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL 1129 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL 1130 1131 1132 static FT_Error _bdf_add_comment(bdf_font_t * font,char * comment,unsigned long len)1133 _bdf_add_comment( bdf_font_t* font, 1134 char* comment, 1135 unsigned long len ) 1136 { 1137 char* cp; 1138 FT_Memory memory = font->memory; 1139 FT_Error error = FT_Err_Ok; 1140 1141 1142 if ( FT_RENEW_ARRAY( font->comments, 1143 font->comments_len, 1144 font->comments_len + len + 1 ) ) 1145 goto Exit; 1146 1147 cp = font->comments + font->comments_len; 1148 1149 FT_MEM_COPY( cp, comment, len ); 1150 cp[len] = '\n'; 1151 1152 font->comments_len += len + 1; 1153 1154 Exit: 1155 return error; 1156 } 1157 1158 1159 /* Set the spacing from the font name if it exists, or set it to the */ 1160 /* default specified in the options. */ 1161 static FT_Error _bdf_set_default_spacing(bdf_font_t * font,bdf_options_t * opts,unsigned long lineno)1162 _bdf_set_default_spacing( bdf_font_t* font, 1163 bdf_options_t* opts, 1164 unsigned long lineno ) 1165 { 1166 size_t len; 1167 char name[256]; 1168 _bdf_list_t list; 1169 FT_Memory memory; 1170 FT_Error error = FT_Err_Ok; 1171 1172 FT_UNUSED( lineno ); /* only used in debug mode */ 1173 1174 1175 if ( font == 0 || font->name == 0 || font->name[0] == 0 ) 1176 { 1177 error = FT_THROW( Invalid_Argument ); 1178 goto Exit; 1179 } 1180 1181 memory = font->memory; 1182 1183 _bdf_list_init( &list, memory ); 1184 1185 font->spacing = opts->font_spacing; 1186 1187 len = ft_strlen( font->name ) + 1; 1188 /* Limit ourselves to 256 characters in the font name. */ 1189 if ( len >= 256 ) 1190 { 1191 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno )); 1192 error = FT_THROW( Invalid_Argument ); 1193 goto Exit; 1194 } 1195 1196 FT_MEM_COPY( name, font->name, len ); 1197 1198 error = _bdf_list_split( &list, (char *)"-", name, (unsigned long)len ); 1199 if ( error ) 1200 goto Fail; 1201 1202 if ( list.used == 15 ) 1203 { 1204 switch ( list.field[11][0] ) 1205 { 1206 case 'C': 1207 case 'c': 1208 font->spacing = BDF_CHARCELL; 1209 break; 1210 case 'M': 1211 case 'm': 1212 font->spacing = BDF_MONOWIDTH; 1213 break; 1214 case 'P': 1215 case 'p': 1216 font->spacing = BDF_PROPORTIONAL; 1217 break; 1218 } 1219 } 1220 1221 Fail: 1222 _bdf_list_done( &list ); 1223 1224 Exit: 1225 return error; 1226 } 1227 1228 1229 /* Determine whether the property is an atom or not. If it is, then */ 1230 /* clean it up so the double quotes are removed if they exist. */ 1231 static int _bdf_is_atom(char * line,unsigned long linelen,char ** name,char ** value,bdf_font_t * font)1232 _bdf_is_atom( char* line, 1233 unsigned long linelen, 1234 char** name, 1235 char** value, 1236 bdf_font_t* font ) 1237 { 1238 int hold; 1239 char *sp, *ep; 1240 bdf_property_t* p; 1241 1242 1243 *name = sp = ep = line; 1244 1245 while ( *ep && *ep != ' ' && *ep != '\t' ) 1246 ep++; 1247 1248 hold = -1; 1249 if ( *ep ) 1250 { 1251 hold = *ep; 1252 *ep = 0; 1253 } 1254 1255 p = bdf_get_property( sp, font ); 1256 1257 /* Restore the character that was saved before any return can happen. */ 1258 if ( hold != -1 ) 1259 *ep = (char)hold; 1260 1261 /* If the property exists and is not an atom, just return here. */ 1262 if ( p && p->format != BDF_ATOM ) 1263 return 0; 1264 1265 /* The property is an atom. Trim all leading and trailing whitespace */ 1266 /* and double quotes for the atom value. */ 1267 sp = ep; 1268 ep = line + linelen; 1269 1270 /* Trim the leading whitespace if it exists. */ 1271 if ( *sp ) 1272 *sp++ = 0; 1273 while ( *sp && 1274 ( *sp == ' ' || *sp == '\t' ) ) 1275 sp++; 1276 1277 /* Trim the leading double quote if it exists. */ 1278 if ( *sp == '"' ) 1279 sp++; 1280 *value = sp; 1281 1282 /* Trim the trailing whitespace if it exists. */ 1283 while ( ep > sp && 1284 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) ) 1285 *--ep = 0; 1286 1287 /* Trim the trailing double quote if it exists. */ 1288 if ( ep > sp && *( ep - 1 ) == '"' ) 1289 *--ep = 0; 1290 1291 return 1; 1292 } 1293 1294 1295 static FT_Error _bdf_add_property(bdf_font_t * font,char * name,char * value,unsigned long lineno)1296 _bdf_add_property( bdf_font_t* font, 1297 char* name, 1298 char* value, 1299 unsigned long lineno ) 1300 { 1301 size_t propid; 1302 hashnode hn; 1303 bdf_property_t *prop, *fp; 1304 FT_Memory memory = font->memory; 1305 FT_Error error = FT_Err_Ok; 1306 1307 FT_UNUSED( lineno ); /* only used in debug mode */ 1308 1309 1310 /* First, check whether the property already exists in the font. */ 1311 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 ) 1312 { 1313 /* The property already exists in the font, so simply replace */ 1314 /* the value of the property with the current value. */ 1315 fp = font->props + hn->data; 1316 1317 switch ( fp->format ) 1318 { 1319 case BDF_ATOM: 1320 /* Delete the current atom if it exists. */ 1321 FT_FREE( fp->value.atom ); 1322 1323 if ( value && value[0] != 0 ) 1324 { 1325 if ( FT_STRDUP( fp->value.atom, value ) ) 1326 goto Exit; 1327 } 1328 break; 1329 1330 case BDF_INTEGER: 1331 fp->value.l = _bdf_atol( value, 0, 10 ); 1332 break; 1333 1334 case BDF_CARDINAL: 1335 fp->value.ul = _bdf_atoul( value, 0, 10 ); 1336 break; 1337 1338 default: 1339 ; 1340 } 1341 1342 goto Exit; 1343 } 1344 1345 /* See whether this property type exists yet or not. */ 1346 /* If not, create it. */ 1347 hn = hash_lookup( name, &(font->proptbl) ); 1348 if ( hn == 0 ) 1349 { 1350 error = bdf_create_property( name, BDF_ATOM, font ); 1351 if ( error ) 1352 goto Exit; 1353 hn = hash_lookup( name, &(font->proptbl) ); 1354 } 1355 1356 /* Allocate another property if this is overflow. */ 1357 if ( font->props_used == font->props_size ) 1358 { 1359 if ( font->props_size == 0 ) 1360 { 1361 if ( FT_NEW_ARRAY( font->props, 1 ) ) 1362 goto Exit; 1363 } 1364 else 1365 { 1366 if ( FT_RENEW_ARRAY( font->props, 1367 font->props_size, 1368 font->props_size + 1 ) ) 1369 goto Exit; 1370 } 1371 1372 fp = font->props + font->props_size; 1373 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) ); 1374 font->props_size++; 1375 } 1376 1377 propid = hn->data; 1378 if ( propid >= _num_bdf_properties ) 1379 prop = font->user_props + ( propid - _num_bdf_properties ); 1380 else 1381 prop = (bdf_property_t*)_bdf_properties + propid; 1382 1383 fp = font->props + font->props_used; 1384 1385 fp->name = prop->name; 1386 fp->format = prop->format; 1387 fp->builtin = prop->builtin; 1388 1389 switch ( prop->format ) 1390 { 1391 case BDF_ATOM: 1392 fp->value.atom = 0; 1393 if ( value != 0 && value[0] ) 1394 { 1395 if ( FT_STRDUP( fp->value.atom, value ) ) 1396 goto Exit; 1397 } 1398 break; 1399 1400 case BDF_INTEGER: 1401 fp->value.l = _bdf_atol( value, 0, 10 ); 1402 break; 1403 1404 case BDF_CARDINAL: 1405 fp->value.ul = _bdf_atoul( value, 0, 10 ); 1406 break; 1407 } 1408 1409 /* If the property happens to be a comment, then it doesn't need */ 1410 /* to be added to the internal hash table. */ 1411 if ( ft_strncmp( name, "COMMENT", 7 ) != 0 ) 1412 { 1413 /* Add the property to the font property table. */ 1414 error = hash_insert( fp->name, 1415 font->props_used, 1416 (hashtable *)font->internal, 1417 memory ); 1418 if ( error ) 1419 goto Exit; 1420 } 1421 1422 font->props_used++; 1423 1424 /* Some special cases need to be handled here. The DEFAULT_CHAR */ 1425 /* property needs to be located if it exists in the property list, the */ 1426 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */ 1427 /* present, and the SPACING property should override the default */ 1428 /* spacing. */ 1429 if ( ft_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 ) 1430 font->default_char = fp->value.l; 1431 else if ( ft_strncmp( name, "FONT_ASCENT", 11 ) == 0 ) 1432 font->font_ascent = fp->value.l; 1433 else if ( ft_strncmp( name, "FONT_DESCENT", 12 ) == 0 ) 1434 font->font_descent = fp->value.l; 1435 else if ( ft_strncmp( name, "SPACING", 7 ) == 0 ) 1436 { 1437 if ( !fp->value.atom ) 1438 { 1439 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" )); 1440 error = FT_THROW( Invalid_File_Format ); 1441 goto Exit; 1442 } 1443 1444 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' ) 1445 font->spacing = BDF_PROPORTIONAL; 1446 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' ) 1447 font->spacing = BDF_MONOWIDTH; 1448 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' ) 1449 font->spacing = BDF_CHARCELL; 1450 } 1451 1452 Exit: 1453 return error; 1454 } 1455 1456 1457 static const unsigned char nibble_mask[8] = 1458 { 1459 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE 1460 }; 1461 1462 1463 /* Actually parse the glyph info and bitmaps. */ 1464 static FT_Error _bdf_parse_glyphs(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1465 _bdf_parse_glyphs( char* line, 1466 unsigned long linelen, 1467 unsigned long lineno, 1468 void* call_data, 1469 void* client_data ) 1470 { 1471 int c, mask_index; 1472 char* s; 1473 unsigned char* bp; 1474 unsigned long i, slen, nibbles; 1475 1476 _bdf_parse_t* p; 1477 bdf_glyph_t* glyph; 1478 bdf_font_t* font; 1479 1480 FT_Memory memory; 1481 FT_Error error = FT_Err_Ok; 1482 1483 FT_UNUSED( call_data ); 1484 FT_UNUSED( lineno ); /* only used in debug mode */ 1485 1486 1487 p = (_bdf_parse_t *)client_data; 1488 1489 font = p->font; 1490 memory = font->memory; 1491 1492 /* Check for a comment. */ 1493 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) 1494 { 1495 linelen -= 7; 1496 1497 s = line + 7; 1498 if ( *s != 0 ) 1499 { 1500 s++; 1501 linelen--; 1502 } 1503 error = _bdf_add_comment( p->font, s, linelen ); 1504 goto Exit; 1505 } 1506 1507 /* The very first thing expected is the number of glyphs. */ 1508 if ( !( p->flags & _BDF_GLYPHS ) ) 1509 { 1510 if ( ft_strncmp( line, "CHARS", 5 ) != 0 ) 1511 { 1512 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" )); 1513 error = FT_THROW( Missing_Chars_Field ); 1514 goto Exit; 1515 } 1516 1517 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 1518 if ( error ) 1519 goto Exit; 1520 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 ); 1521 1522 /* Make sure the number of glyphs is non-zero. */ 1523 if ( p->cnt == 0 ) 1524 font->glyphs_size = 64; 1525 1526 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ 1527 /* number of code points available in Unicode). */ 1528 if ( p->cnt >= 0x110000UL ) 1529 { 1530 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" )); 1531 error = FT_THROW( Invalid_Argument ); 1532 goto Exit; 1533 } 1534 1535 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) 1536 goto Exit; 1537 1538 p->flags |= _BDF_GLYPHS; 1539 1540 goto Exit; 1541 } 1542 1543 /* Check for the ENDFONT field. */ 1544 if ( ft_strncmp( line, "ENDFONT", 7 ) == 0 ) 1545 { 1546 /* Sort the glyphs by encoding. */ 1547 ft_qsort( (char *)font->glyphs, 1548 font->glyphs_used, 1549 sizeof ( bdf_glyph_t ), 1550 by_encoding ); 1551 1552 p->flags &= ~_BDF_START; 1553 1554 goto Exit; 1555 } 1556 1557 /* Check for the ENDCHAR field. */ 1558 if ( ft_strncmp( line, "ENDCHAR", 7 ) == 0 ) 1559 { 1560 p->glyph_enc = 0; 1561 p->flags &= ~_BDF_GLYPH_BITS; 1562 1563 goto Exit; 1564 } 1565 1566 /* Check whether a glyph is being scanned but should be */ 1567 /* ignored because it is an unencoded glyph. */ 1568 if ( ( p->flags & _BDF_GLYPH ) && 1569 p->glyph_enc == -1 && 1570 p->opts->keep_unencoded == 0 ) 1571 goto Exit; 1572 1573 /* Check for the STARTCHAR field. */ 1574 if ( ft_strncmp( line, "STARTCHAR", 9 ) == 0 ) 1575 { 1576 /* Set the character name in the parse info first until the */ 1577 /* encoding can be checked for an unencoded character. */ 1578 FT_FREE( p->glyph_name ); 1579 1580 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 1581 if ( error ) 1582 goto Exit; 1583 1584 _bdf_list_shift( &p->list, 1 ); 1585 1586 s = _bdf_list_join( &p->list, ' ', &slen ); 1587 1588 if ( !s ) 1589 { 1590 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" )); 1591 error = FT_THROW( Invalid_File_Format ); 1592 goto Exit; 1593 } 1594 1595 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) ) 1596 goto Exit; 1597 1598 FT_MEM_COPY( p->glyph_name, s, slen + 1 ); 1599 1600 p->flags |= _BDF_GLYPH; 1601 1602 FT_TRACE4(( DBGMSG1, lineno, s )); 1603 1604 goto Exit; 1605 } 1606 1607 /* Check for the ENCODING field. */ 1608 if ( ft_strncmp( line, "ENCODING", 8 ) == 0 ) 1609 { 1610 if ( !( p->flags & _BDF_GLYPH ) ) 1611 { 1612 /* Missing STARTCHAR field. */ 1613 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" )); 1614 error = FT_THROW( Missing_Startchar_Field ); 1615 goto Exit; 1616 } 1617 1618 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 1619 if ( error ) 1620 goto Exit; 1621 1622 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 ); 1623 1624 /* Normalize negative encoding values. The specification only */ 1625 /* allows -1, but we can be more generous here. */ 1626 if ( p->glyph_enc < -1 ) 1627 p->glyph_enc = -1; 1628 1629 /* Check for alternative encoding format. */ 1630 if ( p->glyph_enc == -1 && p->list.used > 2 ) 1631 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 ); 1632 1633 if ( p->glyph_enc < -1 ) 1634 p->glyph_enc = -1; 1635 1636 FT_TRACE4(( DBGMSG2, p->glyph_enc )); 1637 1638 /* Check that the encoding is in the Unicode range because */ 1639 /* otherwise p->have (a bitmap with static size) overflows. */ 1640 if ( p->glyph_enc > 0 && 1641 (size_t)p->glyph_enc >= sizeof ( p->have ) / 1642 sizeof ( unsigned long ) * 32 ) 1643 { 1644 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" )); 1645 error = FT_THROW( Invalid_File_Format ); 1646 goto Exit; 1647 } 1648 1649 /* Check whether this encoding has already been encountered. */ 1650 /* If it has then change it to unencoded so it gets added if */ 1651 /* indicated. */ 1652 if ( p->glyph_enc >= 0 ) 1653 { 1654 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) ) 1655 { 1656 /* Emit a message saying a glyph has been moved to the */ 1657 /* unencoded area. */ 1658 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12, 1659 p->glyph_enc, p->glyph_name )); 1660 p->glyph_enc = -1; 1661 font->modified = 1; 1662 } 1663 else 1664 _bdf_set_glyph_modified( p->have, p->glyph_enc ); 1665 } 1666 1667 if ( p->glyph_enc >= 0 ) 1668 { 1669 /* Make sure there are enough glyphs allocated in case the */ 1670 /* number of characters happen to be wrong. */ 1671 if ( font->glyphs_used == font->glyphs_size ) 1672 { 1673 if ( FT_RENEW_ARRAY( font->glyphs, 1674 font->glyphs_size, 1675 font->glyphs_size + 64 ) ) 1676 goto Exit; 1677 1678 font->glyphs_size += 64; 1679 } 1680 1681 glyph = font->glyphs + font->glyphs_used++; 1682 glyph->name = p->glyph_name; 1683 glyph->encoding = p->glyph_enc; 1684 1685 /* Reset the initial glyph info. */ 1686 p->glyph_name = 0; 1687 } 1688 else 1689 { 1690 /* Unencoded glyph. Check whether it should */ 1691 /* be added or not. */ 1692 if ( p->opts->keep_unencoded != 0 ) 1693 { 1694 /* Allocate the next unencoded glyph. */ 1695 if ( font->unencoded_used == font->unencoded_size ) 1696 { 1697 if ( FT_RENEW_ARRAY( font->unencoded , 1698 font->unencoded_size, 1699 font->unencoded_size + 4 ) ) 1700 goto Exit; 1701 1702 font->unencoded_size += 4; 1703 } 1704 1705 glyph = font->unencoded + font->unencoded_used; 1706 glyph->name = p->glyph_name; 1707 glyph->encoding = font->unencoded_used++; 1708 } 1709 else 1710 /* Free up the glyph name if the unencoded shouldn't be */ 1711 /* kept. */ 1712 FT_FREE( p->glyph_name ); 1713 1714 p->glyph_name = 0; 1715 } 1716 1717 /* Clear the flags that might be added when width and height are */ 1718 /* checked for consistency. */ 1719 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK ); 1720 1721 p->flags |= _BDF_ENCODING; 1722 1723 goto Exit; 1724 } 1725 1726 /* Point at the glyph being constructed. */ 1727 if ( p->glyph_enc == -1 ) 1728 glyph = font->unencoded + ( font->unencoded_used - 1 ); 1729 else 1730 glyph = font->glyphs + ( font->glyphs_used - 1 ); 1731 1732 /* Check whether a bitmap is being constructed. */ 1733 if ( p->flags & _BDF_BITMAP ) 1734 { 1735 /* If there are more rows than are specified in the glyph metrics, */ 1736 /* ignore the remaining lines. */ 1737 if ( p->row >= (unsigned long)glyph->bbx.height ) 1738 { 1739 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) ) 1740 { 1741 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding )); 1742 p->flags |= _BDF_GLYPH_HEIGHT_CHECK; 1743 font->modified = 1; 1744 } 1745 1746 goto Exit; 1747 } 1748 1749 /* Only collect the number of nibbles indicated by the glyph */ 1750 /* metrics. If there are more columns, they are simply ignored. */ 1751 nibbles = glyph->bpr << 1; 1752 bp = glyph->bitmap + p->row * glyph->bpr; 1753 1754 for ( i = 0; i < nibbles; i++ ) 1755 { 1756 c = line[i]; 1757 if ( !sbitset( hdigits, c ) ) 1758 break; 1759 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); 1760 if ( i + 1 < nibbles && ( i & 1 ) ) 1761 *++bp = 0; 1762 } 1763 1764 /* If any line has not enough columns, */ 1765 /* indicate they have been padded with zero bits. */ 1766 if ( i < nibbles && 1767 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) ) 1768 { 1769 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding )); 1770 p->flags |= _BDF_GLYPH_WIDTH_CHECK; 1771 font->modified = 1; 1772 } 1773 1774 /* Remove possible garbage at the right. */ 1775 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7; 1776 if ( glyph->bbx.width ) 1777 *bp &= nibble_mask[mask_index]; 1778 1779 /* If any line has extra columns, indicate they have been removed. */ 1780 if ( i == nibbles && 1781 sbitset( hdigits, line[nibbles] ) && 1782 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) ) 1783 { 1784 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding )); 1785 p->flags |= _BDF_GLYPH_WIDTH_CHECK; 1786 font->modified = 1; 1787 } 1788 1789 p->row++; 1790 goto Exit; 1791 } 1792 1793 /* Expect the SWIDTH (scalable width) field next. */ 1794 if ( ft_strncmp( line, "SWIDTH", 6 ) == 0 ) 1795 { 1796 if ( !( p->flags & _BDF_ENCODING ) ) 1797 goto Missing_Encoding; 1798 1799 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 1800 if ( error ) 1801 goto Exit; 1802 1803 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); 1804 p->flags |= _BDF_SWIDTH; 1805 1806 goto Exit; 1807 } 1808 1809 /* Expect the DWIDTH (scalable width) field next. */ 1810 if ( ft_strncmp( line, "DWIDTH", 6 ) == 0 ) 1811 { 1812 if ( !( p->flags & _BDF_ENCODING ) ) 1813 goto Missing_Encoding; 1814 1815 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 1816 if ( error ) 1817 goto Exit; 1818 1819 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); 1820 1821 if ( !( p->flags & _BDF_SWIDTH ) ) 1822 { 1823 /* Missing SWIDTH field. Emit an auto correction message and set */ 1824 /* the scalable width from the device width. */ 1825 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno )); 1826 1827 glyph->swidth = (unsigned short)FT_MulDiv( 1828 glyph->dwidth, 72000L, 1829 (FT_Long)( font->point_size * 1830 font->resolution_x ) ); 1831 } 1832 1833 p->flags |= _BDF_DWIDTH; 1834 goto Exit; 1835 } 1836 1837 /* Expect the BBX field next. */ 1838 if ( ft_strncmp( line, "BBX", 3 ) == 0 ) 1839 { 1840 if ( !( p->flags & _BDF_ENCODING ) ) 1841 goto Missing_Encoding; 1842 1843 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 1844 if ( error ) 1845 goto Exit; 1846 1847 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); 1848 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); 1849 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); 1850 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); 1851 1852 /* Generate the ascent and descent of the character. */ 1853 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); 1854 glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); 1855 1856 /* Determine the overall font bounding box as the characters are */ 1857 /* loaded so corrections can be done later if indicated. */ 1858 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); 1859 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); 1860 1861 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); 1862 1863 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); 1864 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); 1865 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); 1866 1867 if ( !( p->flags & _BDF_DWIDTH ) ) 1868 { 1869 /* Missing DWIDTH field. Emit an auto correction message and set */ 1870 /* the device width to the glyph width. */ 1871 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno )); 1872 glyph->dwidth = glyph->bbx.width; 1873 } 1874 1875 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ 1876 /* value if necessary. */ 1877 if ( p->opts->correct_metrics != 0 ) 1878 { 1879 /* Determine the point size of the glyph. */ 1880 unsigned short sw = (unsigned short)FT_MulDiv( 1881 glyph->dwidth, 72000L, 1882 (FT_Long)( font->point_size * 1883 font->resolution_x ) ); 1884 1885 1886 if ( sw != glyph->swidth ) 1887 { 1888 glyph->swidth = sw; 1889 1890 if ( p->glyph_enc == -1 ) 1891 _bdf_set_glyph_modified( font->umod, 1892 font->unencoded_used - 1 ); 1893 else 1894 _bdf_set_glyph_modified( font->nmod, glyph->encoding ); 1895 1896 p->flags |= _BDF_SWIDTH_ADJ; 1897 font->modified = 1; 1898 } 1899 } 1900 1901 p->flags |= _BDF_BBX; 1902 goto Exit; 1903 } 1904 1905 /* And finally, gather up the bitmap. */ 1906 if ( ft_strncmp( line, "BITMAP", 6 ) == 0 ) 1907 { 1908 unsigned long bitmap_size; 1909 1910 1911 if ( !( p->flags & _BDF_BBX ) ) 1912 { 1913 /* Missing BBX field. */ 1914 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" )); 1915 error = FT_THROW( Missing_Bbx_Field ); 1916 goto Exit; 1917 } 1918 1919 /* Allocate enough space for the bitmap. */ 1920 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; 1921 1922 bitmap_size = glyph->bpr * glyph->bbx.height; 1923 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU ) 1924 { 1925 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno )); 1926 error = FT_THROW( Bbx_Too_Big ); 1927 goto Exit; 1928 } 1929 else 1930 glyph->bytes = (unsigned short)bitmap_size; 1931 1932 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) ) 1933 goto Exit; 1934 1935 p->row = 0; 1936 p->flags |= _BDF_BITMAP; 1937 1938 goto Exit; 1939 } 1940 1941 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno )); 1942 error = FT_THROW( Invalid_File_Format ); 1943 goto Exit; 1944 1945 Missing_Encoding: 1946 /* Missing ENCODING field. */ 1947 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" )); 1948 error = FT_THROW( Missing_Encoding_Field ); 1949 1950 Exit: 1951 if ( error && ( p->flags & _BDF_GLYPH ) ) 1952 FT_FREE( p->glyph_name ); 1953 1954 return error; 1955 } 1956 1957 1958 /* Load the font properties. */ 1959 static FT_Error _bdf_parse_properties(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1960 _bdf_parse_properties( char* line, 1961 unsigned long linelen, 1962 unsigned long lineno, 1963 void* call_data, 1964 void* client_data ) 1965 { 1966 unsigned long vlen; 1967 _bdf_line_func_t* next; 1968 _bdf_parse_t* p; 1969 char* name; 1970 char* value; 1971 char nbuf[128]; 1972 FT_Error error = FT_Err_Ok; 1973 1974 FT_UNUSED( lineno ); 1975 1976 1977 next = (_bdf_line_func_t *)call_data; 1978 p = (_bdf_parse_t *) client_data; 1979 1980 /* Check for the end of the properties. */ 1981 if ( ft_strncmp( line, "ENDPROPERTIES", 13 ) == 0 ) 1982 { 1983 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */ 1984 /* encountered yet, then make sure they are added as properties and */ 1985 /* make sure they are set from the font bounding box info. */ 1986 /* */ 1987 /* This is *always* done regardless of the options, because X11 */ 1988 /* requires these two fields to compile fonts. */ 1989 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 ) 1990 { 1991 p->font->font_ascent = p->font->bbx.ascent; 1992 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); 1993 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", 1994 nbuf, lineno ); 1995 if ( error ) 1996 goto Exit; 1997 1998 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); 1999 p->font->modified = 1; 2000 } 2001 2002 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 ) 2003 { 2004 p->font->font_descent = p->font->bbx.descent; 2005 ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); 2006 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", 2007 nbuf, lineno ); 2008 if ( error ) 2009 goto Exit; 2010 2011 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); 2012 p->font->modified = 1; 2013 } 2014 2015 p->flags &= ~_BDF_PROPS; 2016 *next = _bdf_parse_glyphs; 2017 2018 goto Exit; 2019 } 2020 2021 /* Ignore the _XFREE86_GLYPH_RANGES properties. */ 2022 if ( ft_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) 2023 goto Exit; 2024 2025 /* Handle COMMENT fields and properties in a special way to preserve */ 2026 /* the spacing. */ 2027 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) 2028 { 2029 name = value = line; 2030 value += 7; 2031 if ( *value ) 2032 *value++ = 0; 2033 error = _bdf_add_property( p->font, name, value, lineno ); 2034 if ( error ) 2035 goto Exit; 2036 } 2037 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) ) 2038 { 2039 error = _bdf_add_property( p->font, name, value, lineno ); 2040 if ( error ) 2041 goto Exit; 2042 } 2043 else 2044 { 2045 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 2046 if ( error ) 2047 goto Exit; 2048 name = p->list.field[0]; 2049 2050 _bdf_list_shift( &p->list, 1 ); 2051 value = _bdf_list_join( &p->list, ' ', &vlen ); 2052 2053 error = _bdf_add_property( p->font, name, value, lineno ); 2054 if ( error ) 2055 goto Exit; 2056 } 2057 2058 Exit: 2059 return error; 2060 } 2061 2062 2063 /* Load the font header. */ 2064 static FT_Error _bdf_parse_start(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)2065 _bdf_parse_start( char* line, 2066 unsigned long linelen, 2067 unsigned long lineno, 2068 void* call_data, 2069 void* client_data ) 2070 { 2071 unsigned long slen; 2072 _bdf_line_func_t* next; 2073 _bdf_parse_t* p; 2074 bdf_font_t* font; 2075 char *s; 2076 2077 FT_Memory memory = NULL; 2078 FT_Error error = FT_Err_Ok; 2079 2080 FT_UNUSED( lineno ); /* only used in debug mode */ 2081 2082 2083 next = (_bdf_line_func_t *)call_data; 2084 p = (_bdf_parse_t *) client_data; 2085 2086 if ( p->font ) 2087 memory = p->font->memory; 2088 2089 /* Check for a comment. This is done to handle those fonts that have */ 2090 /* comments before the STARTFONT line for some reason. */ 2091 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) 2092 { 2093 if ( p->opts->keep_comments != 0 && p->font != 0 ) 2094 { 2095 linelen -= 7; 2096 2097 s = line + 7; 2098 if ( *s != 0 ) 2099 { 2100 s++; 2101 linelen--; 2102 } 2103 2104 error = _bdf_add_comment( p->font, s, linelen ); 2105 if ( error ) 2106 goto Exit; 2107 /* here font is not defined! */ 2108 } 2109 2110 goto Exit; 2111 } 2112 2113 if ( !( p->flags & _BDF_START ) ) 2114 { 2115 memory = p->memory; 2116 2117 if ( ft_strncmp( line, "STARTFONT", 9 ) != 0 ) 2118 { 2119 /* we don't emit an error message since this code gets */ 2120 /* explicitly caught one level higher */ 2121 error = FT_THROW( Missing_Startfont_Field ); 2122 goto Exit; 2123 } 2124 2125 p->flags = _BDF_START; 2126 font = p->font = 0; 2127 2128 if ( FT_NEW( font ) ) 2129 goto Exit; 2130 p->font = font; 2131 2132 font->memory = p->memory; 2133 p->memory = 0; 2134 2135 { /* setup */ 2136 size_t i; 2137 bdf_property_t* prop; 2138 2139 2140 error = hash_init( &(font->proptbl), memory ); 2141 if ( error ) 2142 goto Exit; 2143 for ( i = 0, prop = (bdf_property_t*)_bdf_properties; 2144 i < _num_bdf_properties; i++, prop++ ) 2145 { 2146 error = hash_insert( prop->name, i, 2147 &(font->proptbl), memory ); 2148 if ( error ) 2149 goto Exit; 2150 } 2151 } 2152 2153 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) ) 2154 goto Exit; 2155 error = hash_init( (hashtable *)p->font->internal,memory ); 2156 if ( error ) 2157 goto Exit; 2158 p->font->spacing = p->opts->font_spacing; 2159 p->font->default_char = -1; 2160 2161 goto Exit; 2162 } 2163 2164 /* Check for the start of the properties. */ 2165 if ( ft_strncmp( line, "STARTPROPERTIES", 15 ) == 0 ) 2166 { 2167 if ( !( p->flags & _BDF_FONT_BBX ) ) 2168 { 2169 /* Missing the FONTBOUNDINGBOX field. */ 2170 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); 2171 error = FT_THROW( Missing_Fontboundingbox_Field ); 2172 goto Exit; 2173 } 2174 2175 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 2176 if ( error ) 2177 goto Exit; 2178 /* at this point, `p->font' can't be NULL */ 2179 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 ); 2180 2181 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) 2182 { 2183 p->font->props_size = 0; 2184 goto Exit; 2185 } 2186 2187 p->flags |= _BDF_PROPS; 2188 *next = _bdf_parse_properties; 2189 2190 goto Exit; 2191 } 2192 2193 /* Check for the FONTBOUNDINGBOX field. */ 2194 if ( ft_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) 2195 { 2196 if ( !( p->flags & _BDF_SIZE ) ) 2197 { 2198 /* Missing the SIZE field. */ 2199 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" )); 2200 error = FT_THROW( Missing_Size_Field ); 2201 goto Exit; 2202 } 2203 2204 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 2205 if ( error ) 2206 goto Exit; 2207 2208 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); 2209 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); 2210 2211 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); 2212 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); 2213 2214 p->font->bbx.ascent = (short)( p->font->bbx.height + 2215 p->font->bbx.y_offset ); 2216 2217 p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); 2218 2219 p->flags |= _BDF_FONT_BBX; 2220 2221 goto Exit; 2222 } 2223 2224 /* The next thing to check for is the FONT field. */ 2225 if ( ft_strncmp( line, "FONT", 4 ) == 0 ) 2226 { 2227 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 2228 if ( error ) 2229 goto Exit; 2230 _bdf_list_shift( &p->list, 1 ); 2231 2232 s = _bdf_list_join( &p->list, ' ', &slen ); 2233 2234 if ( !s ) 2235 { 2236 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" )); 2237 error = FT_THROW( Invalid_File_Format ); 2238 goto Exit; 2239 } 2240 2241 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ 2242 FT_FREE( p->font->name ); 2243 2244 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) ) 2245 goto Exit; 2246 FT_MEM_COPY( p->font->name, s, slen + 1 ); 2247 2248 /* If the font name is an XLFD name, set the spacing to the one in */ 2249 /* the font name. If there is no spacing fall back on the default. */ 2250 error = _bdf_set_default_spacing( p->font, p->opts, lineno ); 2251 if ( error ) 2252 goto Exit; 2253 2254 p->flags |= _BDF_FONT_NAME; 2255 2256 goto Exit; 2257 } 2258 2259 /* Check for the SIZE field. */ 2260 if ( ft_strncmp( line, "SIZE", 4 ) == 0 ) 2261 { 2262 if ( !( p->flags & _BDF_FONT_NAME ) ) 2263 { 2264 /* Missing the FONT field. */ 2265 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" )); 2266 error = FT_THROW( Missing_Font_Field ); 2267 goto Exit; 2268 } 2269 2270 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 2271 if ( error ) 2272 goto Exit; 2273 2274 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 ); 2275 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 ); 2276 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 ); 2277 2278 /* Check for the bits per pixel field. */ 2279 if ( p->list.used == 5 ) 2280 { 2281 unsigned short bitcount, i, shift; 2282 2283 2284 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 ); 2285 2286 /* Only values 1, 2, 4, 8 are allowed. */ 2287 shift = p->font->bpp; 2288 bitcount = 0; 2289 for ( i = 0; shift > 0; i++ ) 2290 { 2291 if ( shift & 1 ) 2292 bitcount = i; 2293 shift >>= 1; 2294 } 2295 2296 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) ); 2297 2298 if ( p->font->bpp > shift || p->font->bpp != shift ) 2299 { 2300 /* select next higher value */ 2301 p->font->bpp = (unsigned short)( shift << 1 ); 2302 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp )); 2303 } 2304 } 2305 else 2306 p->font->bpp = 1; 2307 2308 p->flags |= _BDF_SIZE; 2309 2310 goto Exit; 2311 } 2312 2313 /* Check for the CHARS field -- font properties are optional */ 2314 if ( ft_strncmp( line, "CHARS", 5 ) == 0 ) 2315 { 2316 char nbuf[128]; 2317 2318 2319 if ( !( p->flags & _BDF_FONT_BBX ) ) 2320 { 2321 /* Missing the FONTBOUNDINGBOX field. */ 2322 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); 2323 error = FT_THROW( Missing_Fontboundingbox_Field ); 2324 goto Exit; 2325 } 2326 2327 /* Add the two standard X11 properties which are required */ 2328 /* for compiling fonts. */ 2329 p->font->font_ascent = p->font->bbx.ascent; 2330 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); 2331 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", 2332 nbuf, lineno ); 2333 if ( error ) 2334 goto Exit; 2335 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); 2336 2337 p->font->font_descent = p->font->bbx.descent; 2338 ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); 2339 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", 2340 nbuf, lineno ); 2341 if ( error ) 2342 goto Exit; 2343 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); 2344 2345 p->font->modified = 1; 2346 2347 *next = _bdf_parse_glyphs; 2348 2349 /* A special return value. */ 2350 error = -1; 2351 goto Exit; 2352 } 2353 2354 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno )); 2355 error = FT_THROW( Invalid_File_Format ); 2356 2357 Exit: 2358 return error; 2359 } 2360 2361 2362 /*************************************************************************/ 2363 /* */ 2364 /* API. */ 2365 /* */ 2366 /*************************************************************************/ 2367 2368 2369 FT_LOCAL_DEF( FT_Error ) bdf_load_font(FT_Stream stream,FT_Memory extmemory,bdf_options_t * opts,bdf_font_t ** font)2370 bdf_load_font( FT_Stream stream, 2371 FT_Memory extmemory, 2372 bdf_options_t* opts, 2373 bdf_font_t* *font ) 2374 { 2375 unsigned long lineno = 0; /* make compiler happy */ 2376 _bdf_parse_t *p = NULL; 2377 2378 FT_Memory memory = extmemory; /* needed for FT_NEW */ 2379 FT_Error error = FT_Err_Ok; 2380 2381 2382 if ( FT_NEW( p ) ) 2383 goto Exit; 2384 2385 memory = NULL; 2386 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts ); 2387 p->minlb = 32767; 2388 p->memory = extmemory; /* only during font creation */ 2389 2390 _bdf_list_init( &p->list, extmemory ); 2391 2392 error = _bdf_readstream( stream, _bdf_parse_start, 2393 (void *)p, &lineno ); 2394 if ( error ) 2395 goto Fail; 2396 2397 if ( p->font != 0 ) 2398 { 2399 /* If the font is not proportional, set the font's monowidth */ 2400 /* field to the width of the font bounding box. */ 2401 2402 if ( p->font->spacing != BDF_PROPORTIONAL ) 2403 p->font->monowidth = p->font->bbx.width; 2404 2405 /* If the number of glyphs loaded is not that of the original count, */ 2406 /* indicate the difference. */ 2407 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) 2408 { 2409 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, 2410 p->font->glyphs_used + p->font->unencoded_used )); 2411 p->font->modified = 1; 2412 } 2413 2414 /* Once the font has been loaded, adjust the overall font metrics if */ 2415 /* necessary. */ 2416 if ( p->opts->correct_metrics != 0 && 2417 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) 2418 { 2419 if ( p->maxrb - p->minlb != p->font->bbx.width ) 2420 { 2421 FT_TRACE2(( "bdf_load_font: " ACMSG3, 2422 p->font->bbx.width, p->maxrb - p->minlb )); 2423 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); 2424 p->font->modified = 1; 2425 } 2426 2427 if ( p->font->bbx.x_offset != p->minlb ) 2428 { 2429 FT_TRACE2(( "bdf_load_font: " ACMSG4, 2430 p->font->bbx.x_offset, p->minlb )); 2431 p->font->bbx.x_offset = p->minlb; 2432 p->font->modified = 1; 2433 } 2434 2435 if ( p->font->bbx.ascent != p->maxas ) 2436 { 2437 FT_TRACE2(( "bdf_load_font: " ACMSG5, 2438 p->font->bbx.ascent, p->maxas )); 2439 p->font->bbx.ascent = p->maxas; 2440 p->font->modified = 1; 2441 } 2442 2443 if ( p->font->bbx.descent != p->maxds ) 2444 { 2445 FT_TRACE2(( "bdf_load_font: " ACMSG6, 2446 p->font->bbx.descent, p->maxds )); 2447 p->font->bbx.descent = p->maxds; 2448 p->font->bbx.y_offset = (short)( -p->maxds ); 2449 p->font->modified = 1; 2450 } 2451 2452 if ( p->maxas + p->maxds != p->font->bbx.height ) 2453 { 2454 FT_TRACE2(( "bdf_load_font: " ACMSG7, 2455 p->font->bbx.height, p->maxas + p->maxds )); 2456 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); 2457 } 2458 2459 if ( p->flags & _BDF_SWIDTH_ADJ ) 2460 FT_TRACE2(( "bdf_load_font: " ACMSG8 )); 2461 } 2462 } 2463 2464 if ( p->flags & _BDF_START ) 2465 { 2466 /* The ENDFONT field was never reached or did not exist. */ 2467 if ( !( p->flags & _BDF_GLYPHS ) ) 2468 { 2469 /* Error happened while parsing header. */ 2470 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); 2471 error = FT_THROW( Corrupted_Font_Header ); 2472 goto Exit; 2473 } 2474 else 2475 { 2476 /* Error happened when parsing glyphs. */ 2477 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); 2478 error = FT_THROW( Corrupted_Font_Glyphs ); 2479 goto Exit; 2480 } 2481 } 2482 2483 if ( p->font != 0 ) 2484 { 2485 /* Make sure the comments are NULL terminated if they exist. */ 2486 memory = p->font->memory; 2487 2488 if ( p->font->comments_len > 0 ) 2489 { 2490 if ( FT_RENEW_ARRAY( p->font->comments, 2491 p->font->comments_len, 2492 p->font->comments_len + 1 ) ) 2493 goto Fail; 2494 2495 p->font->comments[p->font->comments_len] = 0; 2496 } 2497 } 2498 else if ( error == FT_Err_Ok ) 2499 error = FT_THROW( Invalid_File_Format ); 2500 2501 *font = p->font; 2502 2503 Exit: 2504 if ( p ) 2505 { 2506 _bdf_list_done( &p->list ); 2507 2508 memory = extmemory; 2509 2510 FT_FREE( p ); 2511 } 2512 2513 return error; 2514 2515 Fail: 2516 bdf_free_font( p->font ); 2517 2518 memory = extmemory; 2519 2520 FT_FREE( p->font ); 2521 2522 goto Exit; 2523 } 2524 2525 2526 FT_LOCAL_DEF( void ) bdf_free_font(bdf_font_t * font)2527 bdf_free_font( bdf_font_t* font ) 2528 { 2529 bdf_property_t* prop; 2530 unsigned long i; 2531 bdf_glyph_t* glyphs; 2532 FT_Memory memory; 2533 2534 2535 if ( font == 0 ) 2536 return; 2537 2538 memory = font->memory; 2539 2540 FT_FREE( font->name ); 2541 2542 /* Free up the internal hash table of property names. */ 2543 if ( font->internal ) 2544 { 2545 hash_free( (hashtable *)font->internal, memory ); 2546 FT_FREE( font->internal ); 2547 } 2548 2549 /* Free up the comment info. */ 2550 FT_FREE( font->comments ); 2551 2552 /* Free up the properties. */ 2553 for ( i = 0; i < font->props_size; i++ ) 2554 { 2555 if ( font->props[i].format == BDF_ATOM ) 2556 FT_FREE( font->props[i].value.atom ); 2557 } 2558 2559 FT_FREE( font->props ); 2560 2561 /* Free up the character info. */ 2562 for ( i = 0, glyphs = font->glyphs; 2563 i < font->glyphs_used; i++, glyphs++ ) 2564 { 2565 FT_FREE( glyphs->name ); 2566 FT_FREE( glyphs->bitmap ); 2567 } 2568 2569 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; 2570 i++, glyphs++ ) 2571 { 2572 FT_FREE( glyphs->name ); 2573 FT_FREE( glyphs->bitmap ); 2574 } 2575 2576 FT_FREE( font->glyphs ); 2577 FT_FREE( font->unencoded ); 2578 2579 /* Free up the overflow storage if it was used. */ 2580 for ( i = 0, glyphs = font->overflow.glyphs; 2581 i < font->overflow.glyphs_used; i++, glyphs++ ) 2582 { 2583 FT_FREE( glyphs->name ); 2584 FT_FREE( glyphs->bitmap ); 2585 } 2586 2587 FT_FREE( font->overflow.glyphs ); 2588 2589 /* bdf_cleanup */ 2590 hash_free( &(font->proptbl), memory ); 2591 2592 /* Free up the user defined properties. */ 2593 for ( prop = font->user_props, i = 0; 2594 i < font->nuser_props; i++, prop++ ) 2595 { 2596 FT_FREE( prop->name ); 2597 if ( prop->format == BDF_ATOM ) 2598 FT_FREE( prop->value.atom ); 2599 } 2600 2601 FT_FREE( font->user_props ); 2602 2603 /* FREE( font ); */ /* XXX Fixme */ 2604 } 2605 2606 2607 FT_LOCAL_DEF( bdf_property_t * ) bdf_get_font_property(bdf_font_t * font,const char * name)2608 bdf_get_font_property( bdf_font_t* font, 2609 const char* name ) 2610 { 2611 hashnode hn; 2612 2613 2614 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 ) 2615 return 0; 2616 2617 hn = hash_lookup( name, (hashtable *)font->internal ); 2618 2619 return hn ? ( font->props + hn->data ) : 0; 2620 } 2621 2622 2623 /* END */ 2624