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