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