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