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