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