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 = (ptrdiff_t)buf_size; 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 avail -= bytes; 627 start = 0; 628 } 629 refill = 1; 630 continue; 631 } 632 633 /* Temporarily NUL-terminate the line. */ 634 hold = buf[end]; 635 buf[end] = 0; 636 637 /* XXX: Use encoding independent value for 0x1A */ 638 if ( buf[start] != '#' && buf[start] != 0x1A && end > start ) 639 { 640 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, 641 (void*)&cb, client_data ); 642 /* Redo if we have encountered CHARS without properties. */ 643 if ( error == -1 ) 644 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, 645 (void*)&cb, client_data ); 646 if ( error ) 647 break; 648 } 649 650 lineno += 1; 651 buf[end] = (char)hold; 652 start = end + 1; 653 654 if ( hold == '\n' ) 655 to_skip = '\r'; 656 else if ( hold == '\r' ) 657 to_skip = '\n'; 658 else 659 to_skip = NO_SKIP; 660 } 661 662 *lno = lineno; 663 664 Exit: 665 FT_FREE( buf ); 666 return error; 667 } 668 669 670 /* XXX: make this work with EBCDIC also */ 671 672 static const unsigned char a2i[128] = 673 { 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 678 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, 679 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 682 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 685 }; 686 687 static const unsigned char ddigits[32] = 688 { 689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 690 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 693 }; 694 695 static const unsigned char hdigits[32] = 696 { 697 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 698 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 700 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 701 }; 702 703 704 /* Routine to convert a decimal ASCII string to an unsigned long integer. */ 705 static unsigned long _bdf_atoul(const char * s)706 _bdf_atoul( const char* s ) 707 { 708 unsigned long v; 709 710 711 if ( s == NULL || *s == 0 ) 712 return 0; 713 714 for ( v = 0; sbitset( ddigits, *s ); s++ ) 715 { 716 if ( v < ( FT_ULONG_MAX - 9 ) / 10 ) 717 v = v * 10 + a2i[(int)*s]; 718 else 719 { 720 v = FT_ULONG_MAX; 721 break; 722 } 723 } 724 725 return v; 726 } 727 728 729 /* Routine to convert a decimal ASCII string to a signed long integer. */ 730 static long _bdf_atol(const char * s)731 _bdf_atol( const char* s ) 732 { 733 long v, neg; 734 735 736 if ( s == NULL || *s == 0 ) 737 return 0; 738 739 /* Check for a minus sign. */ 740 neg = 0; 741 if ( *s == '-' ) 742 { 743 s++; 744 neg = 1; 745 } 746 747 for ( v = 0; sbitset( ddigits, *s ); s++ ) 748 { 749 if ( v < ( FT_LONG_MAX - 9 ) / 10 ) 750 v = v * 10 + a2i[(int)*s]; 751 else 752 { 753 v = FT_LONG_MAX; 754 break; 755 } 756 } 757 758 return ( !neg ) ? v : -v; 759 } 760 761 762 /* Routine to convert a decimal ASCII string to an unsigned short integer. */ 763 static unsigned short _bdf_atous(const char * s)764 _bdf_atous( const char* s ) 765 { 766 unsigned short v; 767 768 769 if ( s == NULL || *s == 0 ) 770 return 0; 771 772 for ( v = 0; sbitset( ddigits, *s ); s++ ) 773 { 774 if ( v < ( FT_USHORT_MAX - 9 ) / 10 ) 775 v = (unsigned short)( v * 10 + a2i[(int)*s] ); 776 else 777 { 778 v = FT_USHORT_MAX; 779 break; 780 } 781 } 782 783 return v; 784 } 785 786 787 /* Routine to convert a decimal ASCII string to a signed short integer. */ 788 static short _bdf_atos(const char * s)789 _bdf_atos( const char* s ) 790 { 791 short v, neg; 792 793 794 if ( s == NULL || *s == 0 ) 795 return 0; 796 797 /* Check for a minus. */ 798 neg = 0; 799 if ( *s == '-' ) 800 { 801 s++; 802 neg = 1; 803 } 804 805 for ( v = 0; sbitset( ddigits, *s ); s++ ) 806 { 807 if ( v < ( SHRT_MAX - 9 ) / 10 ) 808 v = (short)( v * 10 + a2i[(int)*s] ); 809 else 810 { 811 v = SHRT_MAX; 812 break; 813 } 814 } 815 816 return (short)( ( !neg ) ? v : -v ); 817 } 818 819 820 /* Routine to compare two glyphs by encoding so they can be sorted. */ 821 FT_COMPARE_DEF( int ) by_encoding(const void * a,const void * b)822 by_encoding( const void* a, 823 const void* b ) 824 { 825 bdf_glyph_t *c1, *c2; 826 827 828 c1 = (bdf_glyph_t *)a; 829 c2 = (bdf_glyph_t *)b; 830 831 if ( c1->encoding < c2->encoding ) 832 return -1; 833 834 if ( c1->encoding > c2->encoding ) 835 return 1; 836 837 return 0; 838 } 839 840 841 static FT_Error bdf_create_property(const char * name,int format,bdf_font_t * font)842 bdf_create_property( const char* name, 843 int format, 844 bdf_font_t* font ) 845 { 846 size_t n; 847 bdf_property_t* p; 848 FT_Memory memory = font->memory; 849 FT_Error error = FT_Err_Ok; 850 851 852 /* First check whether the property has */ 853 /* already been added or not. If it has, then */ 854 /* simply ignore it. */ 855 if ( ft_hash_str_lookup( name, &(font->proptbl) ) ) 856 goto Exit; 857 858 if ( FT_QRENEW_ARRAY( font->user_props, 859 font->nuser_props, 860 font->nuser_props + 1 ) ) 861 goto Exit; 862 863 p = font->user_props + font->nuser_props; 864 865 n = ft_strlen( name ) + 1; 866 if ( n > FT_LONG_MAX ) 867 return FT_THROW( Invalid_Argument ); 868 869 if ( FT_QALLOC( p->name, n ) ) 870 goto Exit; 871 872 FT_MEM_COPY( (char *)p->name, name, n ); 873 874 p->format = format; 875 p->builtin = 0; 876 p->value.atom = NULL; /* nothing is ever stored here */ 877 878 n = _num_bdf_properties + font->nuser_props; 879 880 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory ); 881 if ( error ) 882 goto Exit; 883 884 font->nuser_props++; 885 886 Exit: 887 return error; 888 } 889 890 891 FT_LOCAL_DEF( bdf_property_t* ) bdf_get_property(char * name,bdf_font_t * font)892 bdf_get_property( char* name, 893 bdf_font_t* font ) 894 { 895 size_t* propid; 896 897 898 if ( name == NULL || *name == 0 ) 899 return 0; 900 901 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL ) 902 return 0; 903 904 if ( *propid >= _num_bdf_properties ) 905 return font->user_props + ( *propid - _num_bdf_properties ); 906 907 return (bdf_property_t*)_bdf_properties + *propid; 908 } 909 910 911 /************************************************************************** 912 * 913 * BDF font file parsing flags and functions. 914 * 915 */ 916 917 918 /* Parse flags. */ 919 920 #define BDF_START_ 0x0001U 921 #define BDF_FONT_NAME_ 0x0002U 922 #define BDF_SIZE_ 0x0004U 923 #define BDF_FONT_BBX_ 0x0008U 924 #define BDF_PROPS_ 0x0010U 925 #define BDF_GLYPHS_ 0x0020U 926 #define BDF_GLYPH_ 0x0040U 927 #define BDF_ENCODING_ 0x0080U 928 #define BDF_SWIDTH_ 0x0100U 929 #define BDF_DWIDTH_ 0x0200U 930 #define BDF_BBX_ 0x0400U 931 #define BDF_BITMAP_ 0x0800U 932 933 #define BDF_SWIDTH_ADJ_ 0x1000U 934 935 #define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \ 936 BDF_ENCODING_ | \ 937 BDF_SWIDTH_ | \ 938 BDF_DWIDTH_ | \ 939 BDF_BBX_ | \ 940 BDF_BITMAP_ ) 941 942 #define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL 943 #define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL 944 945 946 static FT_Error _bdf_add_comment(bdf_font_t * font,char * comment,unsigned long len)947 _bdf_add_comment( bdf_font_t* font, 948 char* comment, 949 unsigned long len ) 950 { 951 char* cp; 952 FT_Memory memory = font->memory; 953 FT_Error error = FT_Err_Ok; 954 955 956 if ( FT_QRENEW_ARRAY( font->comments, 957 font->comments_len, 958 font->comments_len + len + 1 ) ) 959 goto Exit; 960 961 cp = font->comments + font->comments_len; 962 963 FT_MEM_COPY( cp, comment, len ); 964 cp[len] = '\0'; 965 966 font->comments_len += len + 1; 967 968 Exit: 969 return error; 970 } 971 972 973 /* Set the spacing from the font name if it exists, or set it to the */ 974 /* default specified in the options. */ 975 static FT_Error _bdf_set_default_spacing(bdf_font_t * font,bdf_options_t * opts,unsigned long lineno)976 _bdf_set_default_spacing( bdf_font_t* font, 977 bdf_options_t* opts, 978 unsigned long lineno ) 979 { 980 size_t len; 981 char name[256]; 982 _bdf_list_t list; 983 FT_Memory memory; 984 FT_Error error = FT_Err_Ok; 985 986 FT_UNUSED( lineno ); /* only used in debug mode */ 987 988 989 if ( font == NULL || font->name == NULL || font->name[0] == 0 ) 990 { 991 error = FT_THROW( Invalid_Argument ); 992 goto Exit; 993 } 994 995 memory = font->memory; 996 997 _bdf_list_init( &list, memory ); 998 999 font->spacing = opts->font_spacing; 1000 1001 len = ft_strlen( font->name ) + 1; 1002 /* Limit ourselves to 256 characters in the font name. */ 1003 if ( len >= 256 ) 1004 { 1005 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno )); 1006 error = FT_THROW( Invalid_Argument ); 1007 goto Exit; 1008 } 1009 1010 FT_MEM_COPY( name, font->name, len ); 1011 1012 error = _bdf_list_split( &list, "-", name, (unsigned long)len ); 1013 if ( error ) 1014 goto Fail; 1015 1016 if ( list.used == 15 ) 1017 { 1018 switch ( list.field[11][0] ) 1019 { 1020 case 'C': 1021 case 'c': 1022 font->spacing = BDF_CHARCELL; 1023 break; 1024 case 'M': 1025 case 'm': 1026 font->spacing = BDF_MONOWIDTH; 1027 break; 1028 case 'P': 1029 case 'p': 1030 font->spacing = BDF_PROPORTIONAL; 1031 break; 1032 } 1033 } 1034 1035 Fail: 1036 _bdf_list_done( &list ); 1037 1038 Exit: 1039 return error; 1040 } 1041 1042 1043 /* Determine whether the property is an atom or not. If it is, then */ 1044 /* clean it up so the double quotes are removed if they exist. */ 1045 static int _bdf_is_atom(char * line,unsigned long linelen,char ** name,char ** value,bdf_font_t * font)1046 _bdf_is_atom( char* line, 1047 unsigned long linelen, 1048 char** name, 1049 char** value, 1050 bdf_font_t* font ) 1051 { 1052 int hold; 1053 char *sp, *ep; 1054 bdf_property_t* p; 1055 1056 1057 *name = sp = ep = line; 1058 1059 while ( *ep && *ep != ' ' && *ep != '\t' ) 1060 ep++; 1061 1062 hold = -1; 1063 if ( *ep ) 1064 { 1065 hold = *ep; 1066 *ep = 0; 1067 } 1068 1069 p = bdf_get_property( sp, font ); 1070 1071 /* Restore the character that was saved before any return can happen. */ 1072 if ( hold != -1 ) 1073 *ep = (char)hold; 1074 1075 /* If the property exists and is not an atom, just return here. */ 1076 if ( p && p->format != BDF_ATOM ) 1077 return 0; 1078 1079 /* The property is an atom. Trim all leading and trailing whitespace */ 1080 /* and double quotes for the atom value. */ 1081 sp = ep; 1082 ep = line + linelen; 1083 1084 /* Trim the leading whitespace if it exists. */ 1085 if ( *sp ) 1086 *sp++ = 0; 1087 while ( *sp && 1088 ( *sp == ' ' || *sp == '\t' ) ) 1089 sp++; 1090 1091 /* Trim the leading double quote if it exists. */ 1092 if ( *sp == '"' ) 1093 sp++; 1094 *value = sp; 1095 1096 /* Trim the trailing whitespace if it exists. */ 1097 while ( ep > sp && 1098 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) ) 1099 *--ep = 0; 1100 1101 /* Trim the trailing double quote if it exists. */ 1102 if ( ep > sp && *( ep - 1 ) == '"' ) 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 fp = font->props + font->props_size; 1179 font->props_size++; 1180 } 1181 1182 if ( *propid >= _num_bdf_properties ) 1183 prop = font->user_props + ( *propid - _num_bdf_properties ); 1184 else 1185 prop = (bdf_property_t*)_bdf_properties + *propid; 1186 1187 fp = font->props + font->props_used; 1188 1189 fp->name = prop->name; 1190 fp->format = prop->format; 1191 fp->builtin = prop->builtin; 1192 1193 switch ( prop->format ) 1194 { 1195 case BDF_ATOM: 1196 fp->value.atom = NULL; 1197 if ( value && value[0] ) 1198 { 1199 if ( FT_STRDUP( fp->value.atom, value ) ) 1200 goto Exit; 1201 } 1202 break; 1203 1204 case BDF_INTEGER: 1205 fp->value.l = _bdf_atol( value ); 1206 break; 1207 1208 case BDF_CARDINAL: 1209 fp->value.ul = _bdf_atoul( value ); 1210 break; 1211 } 1212 1213 /* If the property happens to be a comment, then it doesn't need */ 1214 /* to be added to the internal hash table. */ 1215 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 ) 1216 { 1217 /* Add the property to the font property table. */ 1218 error = ft_hash_str_insert( fp->name, 1219 font->props_used, 1220 (FT_Hash)font->internal, 1221 memory ); 1222 if ( error ) 1223 goto Exit; 1224 } 1225 1226 font->props_used++; 1227 1228 /* Some special cases need to be handled here. The DEFAULT_CHAR */ 1229 /* property needs to be located if it exists in the property list, the */ 1230 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */ 1231 /* present, and the SPACING property should override the default */ 1232 /* spacing. */ 1233 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 ) 1234 font->default_char = fp->value.ul; 1235 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 ) 1236 font->font_ascent = fp->value.l; 1237 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 ) 1238 font->font_descent = fp->value.l; 1239 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 ) 1240 { 1241 if ( !fp->value.atom ) 1242 { 1243 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" )); 1244 error = FT_THROW( Invalid_File_Format ); 1245 goto Exit; 1246 } 1247 1248 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' ) 1249 font->spacing = BDF_PROPORTIONAL; 1250 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' ) 1251 font->spacing = BDF_MONOWIDTH; 1252 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' ) 1253 font->spacing = BDF_CHARCELL; 1254 } 1255 1256 Exit: 1257 return error; 1258 } 1259 1260 1261 static const unsigned char nibble_mask[8] = 1262 { 1263 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE 1264 }; 1265 1266 1267 static FT_Error _bdf_parse_end(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1268 _bdf_parse_end( char* line, 1269 unsigned long linelen, 1270 unsigned long lineno, 1271 void* call_data, 1272 void* client_data ) 1273 { 1274 /* a no-op; we ignore everything after `ENDFONT' */ 1275 1276 FT_UNUSED( line ); 1277 FT_UNUSED( linelen ); 1278 FT_UNUSED( lineno ); 1279 FT_UNUSED( call_data ); 1280 FT_UNUSED( client_data ); 1281 1282 return FT_Err_Ok; 1283 } 1284 1285 1286 /* Actually parse the glyph info and bitmaps. */ 1287 static FT_Error _bdf_parse_glyphs(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1288 _bdf_parse_glyphs( char* line, 1289 unsigned long linelen, 1290 unsigned long lineno, 1291 void* call_data, 1292 void* client_data ) 1293 { 1294 int c, mask_index; 1295 char* s; 1296 unsigned char* bp; 1297 unsigned long i, slen, nibbles; 1298 1299 _bdf_line_func_t* next; 1300 _bdf_parse_t* p; 1301 bdf_glyph_t* glyph; 1302 bdf_font_t* font; 1303 1304 FT_Memory memory; 1305 FT_Error error = FT_Err_Ok; 1306 1307 FT_UNUSED( lineno ); /* only used in debug mode */ 1308 1309 1310 next = (_bdf_line_func_t *)call_data; 1311 p = (_bdf_parse_t *) client_data; 1312 1313 font = p->font; 1314 memory = font->memory; 1315 1316 /* Check for a comment. */ 1317 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) 1318 { 1319 if ( p->opts->keep_comments ) 1320 { 1321 linelen -= 7; 1322 1323 s = line + 7; 1324 if ( *s != 0 ) 1325 { 1326 s++; 1327 linelen--; 1328 } 1329 error = _bdf_add_comment( p->font, s, linelen ); 1330 } 1331 goto Exit; 1332 } 1333 1334 /* The very first thing expected is the number of glyphs. */ 1335 if ( !( p->flags & BDF_GLYPHS_ ) ) 1336 { 1337 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 ) 1338 { 1339 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" )); 1340 error = FT_THROW( Missing_Chars_Field ); 1341 goto Exit; 1342 } 1343 1344 error = _bdf_list_split( &p->list, " +", line, linelen ); 1345 if ( error ) 1346 goto Exit; 1347 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] ); 1348 1349 /* We need at least 20 bytes per glyph. */ 1350 if ( p->cnt > p->size / 20 ) 1351 { 1352 p->cnt = font->glyphs_size = p->size / 20; 1353 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt )); 1354 } 1355 1356 /* Make sure the number of glyphs is non-zero. */ 1357 if ( p->cnt == 0 ) 1358 font->glyphs_size = 64; 1359 1360 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ 1361 /* number of code points available in Unicode). */ 1362 if ( p->cnt >= 0x110000UL ) 1363 { 1364 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" )); 1365 error = FT_THROW( Invalid_Argument ); 1366 goto Exit; 1367 } 1368 1369 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) 1370 goto Exit; 1371 1372 p->flags |= BDF_GLYPHS_; 1373 1374 goto Exit; 1375 } 1376 1377 /* Check for the ENDFONT field. */ 1378 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 ) 1379 { 1380 if ( p->flags & BDF_GLYPH_BITS_ ) 1381 { 1382 /* Missing ENDCHAR field. */ 1383 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" )); 1384 error = FT_THROW( Corrupted_Font_Glyphs ); 1385 goto Exit; 1386 } 1387 1388 /* Sort the glyphs by encoding. */ 1389 ft_qsort( (char *)font->glyphs, 1390 font->glyphs_used, 1391 sizeof ( bdf_glyph_t ), 1392 by_encoding ); 1393 1394 p->flags &= ~BDF_START_; 1395 *next = _bdf_parse_end; 1396 1397 goto Exit; 1398 } 1399 1400 /* Check for the ENDCHAR field. */ 1401 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 ) 1402 { 1403 p->glyph_enc = 0; 1404 p->flags &= ~BDF_GLYPH_BITS_; 1405 1406 goto Exit; 1407 } 1408 1409 /* Check whether a glyph is being scanned but should be */ 1410 /* ignored because it is an unencoded glyph. */ 1411 if ( ( p->flags & BDF_GLYPH_ ) && 1412 p->glyph_enc == -1 && 1413 p->opts->keep_unencoded == 0 ) 1414 goto Exit; 1415 1416 /* Check for the STARTCHAR field. */ 1417 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 ) 1418 { 1419 if ( p->flags & BDF_GLYPH_BITS_ ) 1420 { 1421 /* Missing ENDCHAR field. */ 1422 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" )); 1423 error = FT_THROW( Missing_Startchar_Field ); 1424 goto Exit; 1425 } 1426 1427 /* Set the character name in the parse info first until the */ 1428 /* encoding can be checked for an unencoded character. */ 1429 FT_FREE( p->glyph_name ); 1430 1431 error = _bdf_list_split( &p->list, " +", line, linelen ); 1432 if ( error ) 1433 goto Exit; 1434 1435 _bdf_list_shift( &p->list, 1 ); 1436 1437 s = _bdf_list_join( &p->list, ' ', &slen ); 1438 1439 if ( !s ) 1440 { 1441 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" )); 1442 error = FT_THROW( Invalid_File_Format ); 1443 goto Exit; 1444 } 1445 1446 if ( FT_QALLOC( p->glyph_name, slen + 1 ) ) 1447 goto Exit; 1448 1449 FT_MEM_COPY( p->glyph_name, s, slen + 1 ); 1450 1451 p->flags |= BDF_GLYPH_; 1452 1453 FT_TRACE4(( DBGMSG1, lineno, s )); 1454 1455 goto Exit; 1456 } 1457 1458 /* Check for the ENCODING field. */ 1459 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 ) 1460 { 1461 if ( !( p->flags & BDF_GLYPH_ ) ) 1462 { 1463 /* Missing STARTCHAR field. */ 1464 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" )); 1465 error = FT_THROW( Missing_Startchar_Field ); 1466 goto Exit; 1467 } 1468 1469 error = _bdf_list_split( &p->list, " +", line, linelen ); 1470 if ( error ) 1471 goto Exit; 1472 1473 p->glyph_enc = _bdf_atol( p->list.field[1] ); 1474 1475 /* Normalize negative encoding values. The specification only */ 1476 /* allows -1, but we can be more generous here. */ 1477 if ( p->glyph_enc < -1 ) 1478 p->glyph_enc = -1; 1479 1480 /* Check for alternative encoding format. */ 1481 if ( p->glyph_enc == -1 && p->list.used > 2 ) 1482 p->glyph_enc = _bdf_atol( p->list.field[2] ); 1483 1484 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L ) 1485 p->glyph_enc = -1; 1486 1487 FT_TRACE4(( DBGMSG2, p->glyph_enc )); 1488 1489 if ( p->glyph_enc >= 0 ) 1490 { 1491 /* Make sure there are enough glyphs allocated in case the */ 1492 /* number of characters happen to be wrong. */ 1493 if ( font->glyphs_used == font->glyphs_size ) 1494 { 1495 if ( FT_RENEW_ARRAY( font->glyphs, 1496 font->glyphs_size, 1497 font->glyphs_size + 64 ) ) 1498 goto Exit; 1499 1500 font->glyphs_size += 64; 1501 } 1502 1503 glyph = font->glyphs + font->glyphs_used++; 1504 glyph->name = p->glyph_name; 1505 glyph->encoding = (unsigned long)p->glyph_enc; 1506 1507 /* Reset the initial glyph info. */ 1508 p->glyph_name = NULL; 1509 } 1510 else 1511 { 1512 /* Unencoded glyph. Check whether it should */ 1513 /* be added or not. */ 1514 if ( p->opts->keep_unencoded ) 1515 { 1516 /* Allocate the next unencoded glyph. */ 1517 if ( font->unencoded_used == font->unencoded_size ) 1518 { 1519 if ( FT_RENEW_ARRAY( font->unencoded , 1520 font->unencoded_size, 1521 font->unencoded_size + 4 ) ) 1522 goto Exit; 1523 1524 font->unencoded_size += 4; 1525 } 1526 1527 glyph = font->unencoded + font->unencoded_used; 1528 glyph->name = p->glyph_name; 1529 glyph->encoding = font->unencoded_used++; 1530 1531 /* Reset the initial glyph info. */ 1532 p->glyph_name = NULL; 1533 } 1534 else 1535 { 1536 /* Free up the glyph name if the unencoded shouldn't be */ 1537 /* kept. */ 1538 FT_FREE( p->glyph_name ); 1539 } 1540 1541 p->glyph_name = NULL; 1542 } 1543 1544 /* Clear the flags that might be added when width and height are */ 1545 /* checked for consistency. */ 1546 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ ); 1547 1548 p->flags |= BDF_ENCODING_; 1549 1550 goto Exit; 1551 } 1552 1553 if ( !( p->flags & BDF_ENCODING_ ) ) 1554 goto Missing_Encoding; 1555 1556 /* Point at the glyph being constructed. */ 1557 if ( p->glyph_enc == -1 ) 1558 glyph = font->unencoded + ( font->unencoded_used - 1 ); 1559 else 1560 glyph = font->glyphs + ( font->glyphs_used - 1 ); 1561 1562 /* Check whether a bitmap is being constructed. */ 1563 if ( p->flags & BDF_BITMAP_ ) 1564 { 1565 /* If there are more rows than are specified in the glyph metrics, */ 1566 /* ignore the remaining lines. */ 1567 if ( p->row >= (unsigned long)glyph->bbx.height ) 1568 { 1569 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) ) 1570 { 1571 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding )); 1572 p->flags |= BDF_GLYPH_HEIGHT_CHECK_; 1573 } 1574 1575 goto Exit; 1576 } 1577 1578 /* Only collect the number of nibbles indicated by the glyph */ 1579 /* metrics. If there are more columns, they are simply ignored. */ 1580 nibbles = glyph->bpr << 1; 1581 bp = glyph->bitmap + p->row * glyph->bpr; 1582 1583 for ( i = 0; i < nibbles; i++ ) 1584 { 1585 c = line[i]; 1586 if ( !sbitset( hdigits, c ) ) 1587 break; 1588 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); 1589 if ( i + 1 < nibbles && ( i & 1 ) ) 1590 *++bp = 0; 1591 } 1592 1593 /* If any line has not enough columns, */ 1594 /* indicate they have been padded with zero bits. */ 1595 if ( i < nibbles && 1596 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) ) 1597 { 1598 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding )); 1599 p->flags |= BDF_GLYPH_WIDTH_CHECK_; 1600 } 1601 1602 /* Remove possible garbage at the right. */ 1603 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7; 1604 if ( glyph->bbx.width ) 1605 *bp &= nibble_mask[mask_index]; 1606 1607 /* If any line has extra columns, indicate they have been removed. */ 1608 if ( i == nibbles && 1609 sbitset( hdigits, line[nibbles] ) && 1610 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) ) 1611 { 1612 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding )); 1613 p->flags |= BDF_GLYPH_WIDTH_CHECK_; 1614 } 1615 1616 p->row++; 1617 goto Exit; 1618 } 1619 1620 /* Expect the SWIDTH (scalable width) field next. */ 1621 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 ) 1622 { 1623 error = _bdf_list_split( &p->list, " +", line, linelen ); 1624 if ( error ) 1625 goto Exit; 1626 1627 glyph->swidth = _bdf_atous( p->list.field[1] ); 1628 p->flags |= BDF_SWIDTH_; 1629 1630 goto Exit; 1631 } 1632 1633 /* Expect the DWIDTH (device width) field next. */ 1634 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 ) 1635 { 1636 error = _bdf_list_split( &p->list, " +", line, linelen ); 1637 if ( error ) 1638 goto Exit; 1639 1640 glyph->dwidth = _bdf_atous( p->list.field[1] ); 1641 1642 if ( !( p->flags & BDF_SWIDTH_ ) ) 1643 { 1644 /* Missing SWIDTH field. Emit an auto correction message and set */ 1645 /* the scalable width from the device width. */ 1646 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno )); 1647 1648 glyph->swidth = (unsigned short)FT_MulDiv( 1649 glyph->dwidth, 72000L, 1650 (FT_Long)( font->point_size * 1651 font->resolution_x ) ); 1652 } 1653 1654 p->flags |= BDF_DWIDTH_; 1655 goto Exit; 1656 } 1657 1658 /* Expect the BBX field next. */ 1659 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 ) 1660 { 1661 error = _bdf_list_split( &p->list, " +", line, linelen ); 1662 if ( error ) 1663 goto Exit; 1664 1665 glyph->bbx.width = _bdf_atous( p->list.field[1] ); 1666 glyph->bbx.height = _bdf_atous( p->list.field[2] ); 1667 glyph->bbx.x_offset = _bdf_atos( p->list.field[3] ); 1668 glyph->bbx.y_offset = _bdf_atos( p->list.field[4] ); 1669 1670 /* Generate the ascent and descent of the character. */ 1671 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); 1672 glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); 1673 1674 /* Determine the overall font bounding box as the characters are */ 1675 /* loaded so corrections can be done later if indicated. */ 1676 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); 1677 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); 1678 1679 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); 1680 1681 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); 1682 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); 1683 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); 1684 1685 if ( !( p->flags & BDF_DWIDTH_ ) ) 1686 { 1687 /* Missing DWIDTH field. Emit an auto correction message and set */ 1688 /* the device width to the glyph width. */ 1689 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno )); 1690 glyph->dwidth = glyph->bbx.width; 1691 } 1692 1693 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ 1694 /* value if necessary. */ 1695 if ( p->opts->correct_metrics ) 1696 { 1697 /* Determine the point size of the glyph. */ 1698 unsigned short sw = (unsigned short)FT_MulDiv( 1699 glyph->dwidth, 72000L, 1700 (FT_Long)( font->point_size * 1701 font->resolution_x ) ); 1702 1703 1704 if ( sw != glyph->swidth ) 1705 { 1706 glyph->swidth = sw; 1707 1708 p->flags |= BDF_SWIDTH_ADJ_; 1709 } 1710 } 1711 1712 p->flags |= BDF_BBX_; 1713 goto Exit; 1714 } 1715 1716 /* And finally, gather up the bitmap. */ 1717 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 ) 1718 { 1719 unsigned long bitmap_size; 1720 1721 1722 if ( !( p->flags & BDF_BBX_ ) ) 1723 { 1724 /* Missing BBX field. */ 1725 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" )); 1726 error = FT_THROW( Missing_Bbx_Field ); 1727 goto Exit; 1728 } 1729 1730 /* Allocate enough space for the bitmap. */ 1731 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; 1732 1733 bitmap_size = glyph->bpr * glyph->bbx.height; 1734 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU ) 1735 { 1736 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno )); 1737 error = FT_THROW( Bbx_Too_Big ); 1738 goto Exit; 1739 } 1740 else 1741 glyph->bytes = (unsigned short)bitmap_size; 1742 1743 if ( FT_ALLOC( glyph->bitmap, glyph->bytes ) ) 1744 goto Exit; 1745 1746 p->row = 0; 1747 p->flags |= BDF_BITMAP_; 1748 1749 goto Exit; 1750 } 1751 1752 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno )); 1753 error = FT_THROW( Invalid_File_Format ); 1754 goto Exit; 1755 1756 Missing_Encoding: 1757 /* Missing ENCODING field. */ 1758 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" )); 1759 error = FT_THROW( Missing_Encoding_Field ); 1760 1761 Exit: 1762 if ( error && ( p->flags & BDF_GLYPH_ ) ) 1763 FT_FREE( p->glyph_name ); 1764 1765 return error; 1766 } 1767 1768 1769 /* Load the font properties. */ 1770 static FT_Error _bdf_parse_properties(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1771 _bdf_parse_properties( char* line, 1772 unsigned long linelen, 1773 unsigned long lineno, 1774 void* call_data, 1775 void* client_data ) 1776 { 1777 unsigned long vlen; 1778 _bdf_line_func_t* next; 1779 _bdf_parse_t* p; 1780 char* name; 1781 char* value; 1782 char nbuf[128]; 1783 FT_Error error = FT_Err_Ok; 1784 1785 FT_UNUSED( lineno ); 1786 1787 1788 next = (_bdf_line_func_t *)call_data; 1789 p = (_bdf_parse_t *) client_data; 1790 1791 /* Check for the end of the properties. */ 1792 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 ) 1793 { 1794 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */ 1795 /* encountered yet, then make sure they are added as properties and */ 1796 /* make sure they are set from the font bounding box info. */ 1797 /* */ 1798 /* This is *always* done regardless of the options, because X11 */ 1799 /* requires these two fields to compile fonts. */ 1800 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 ) 1801 { 1802 p->font->font_ascent = p->font->bbx.ascent; 1803 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); 1804 error = _bdf_add_property( p->font, "FONT_ASCENT", 1805 nbuf, lineno ); 1806 if ( error ) 1807 goto Exit; 1808 1809 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); 1810 } 1811 1812 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 ) 1813 { 1814 p->font->font_descent = p->font->bbx.descent; 1815 ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); 1816 error = _bdf_add_property( p->font, "FONT_DESCENT", 1817 nbuf, lineno ); 1818 if ( error ) 1819 goto Exit; 1820 1821 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); 1822 } 1823 1824 p->flags &= ~BDF_PROPS_; 1825 *next = _bdf_parse_glyphs; 1826 1827 goto Exit; 1828 } 1829 1830 /* Ignore the _XFREE86_GLYPH_RANGES properties. */ 1831 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) 1832 goto Exit; 1833 1834 /* Handle COMMENT fields and properties in a special way to preserve */ 1835 /* the spacing. */ 1836 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) 1837 { 1838 name = value = line; 1839 value += 7; 1840 if ( *value ) 1841 *value++ = 0; 1842 error = _bdf_add_property( p->font, name, value, lineno ); 1843 if ( error ) 1844 goto Exit; 1845 } 1846 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) ) 1847 { 1848 error = _bdf_add_property( p->font, name, value, lineno ); 1849 if ( error ) 1850 goto Exit; 1851 } 1852 else 1853 { 1854 error = _bdf_list_split( &p->list, " +", line, linelen ); 1855 if ( error ) 1856 goto Exit; 1857 name = p->list.field[0]; 1858 1859 _bdf_list_shift( &p->list, 1 ); 1860 value = _bdf_list_join( &p->list, ' ', &vlen ); 1861 1862 error = _bdf_add_property( p->font, name, value, lineno ); 1863 if ( error ) 1864 goto Exit; 1865 } 1866 1867 Exit: 1868 return error; 1869 } 1870 1871 1872 /* Load the font header. */ 1873 static FT_Error _bdf_parse_start(char * line,unsigned long linelen,unsigned long lineno,void * call_data,void * client_data)1874 _bdf_parse_start( char* line, 1875 unsigned long linelen, 1876 unsigned long lineno, 1877 void* call_data, 1878 void* client_data ) 1879 { 1880 unsigned long slen; 1881 _bdf_line_func_t* next; 1882 _bdf_parse_t* p; 1883 bdf_font_t* font; 1884 char *s; 1885 1886 FT_Memory memory = NULL; 1887 FT_Error error = FT_Err_Ok; 1888 1889 FT_UNUSED( lineno ); /* only used in debug mode */ 1890 1891 1892 next = (_bdf_line_func_t *)call_data; 1893 p = (_bdf_parse_t *) client_data; 1894 1895 if ( p->font ) 1896 memory = p->font->memory; 1897 1898 /* Check for a comment. This is done to handle those fonts that have */ 1899 /* comments before the STARTFONT line for some reason. */ 1900 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) 1901 { 1902 if ( p->opts->keep_comments && p->font ) 1903 { 1904 linelen -= 7; 1905 1906 s = line + 7; 1907 if ( *s != 0 ) 1908 { 1909 s++; 1910 linelen--; 1911 } 1912 error = _bdf_add_comment( p->font, s, linelen ); 1913 } 1914 goto Exit; 1915 } 1916 1917 if ( !( p->flags & BDF_START_ ) ) 1918 { 1919 memory = p->memory; 1920 1921 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 ) 1922 { 1923 /* we don't emit an error message since this code gets */ 1924 /* explicitly caught one level higher */ 1925 error = FT_THROW( Missing_Startfont_Field ); 1926 goto Exit; 1927 } 1928 1929 p->flags = BDF_START_; 1930 font = p->font = NULL; 1931 1932 if ( FT_NEW( font ) ) 1933 goto Exit; 1934 p->font = font; 1935 1936 font->memory = p->memory; 1937 1938 { /* setup */ 1939 size_t i; 1940 bdf_property_t* prop; 1941 1942 1943 error = ft_hash_str_init( &(font->proptbl), memory ); 1944 if ( error ) 1945 goto Exit; 1946 for ( i = 0, prop = (bdf_property_t*)_bdf_properties; 1947 i < _num_bdf_properties; i++, prop++ ) 1948 { 1949 error = ft_hash_str_insert( prop->name, i, 1950 &(font->proptbl), memory ); 1951 if ( error ) 1952 goto Exit; 1953 } 1954 } 1955 1956 if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) ) 1957 goto Exit; 1958 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory ); 1959 if ( error ) 1960 goto Exit; 1961 p->font->spacing = p->opts->font_spacing; 1962 p->font->default_char = ~0UL; 1963 1964 goto Exit; 1965 } 1966 1967 /* Check for the start of the properties. */ 1968 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 ) 1969 { 1970 if ( !( p->flags & BDF_FONT_BBX_ ) ) 1971 { 1972 /* Missing the FONTBOUNDINGBOX field. */ 1973 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); 1974 error = FT_THROW( Missing_Fontboundingbox_Field ); 1975 goto Exit; 1976 } 1977 1978 error = _bdf_list_split( &p->list, " +", line, linelen ); 1979 if ( error ) 1980 goto Exit; 1981 1982 /* at this point, `p->font' can't be NULL */ 1983 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] ); 1984 /* We need at least 4 bytes per property. */ 1985 if ( p->cnt > p->size / 4 ) 1986 { 1987 p->font->props_size = 0; 1988 1989 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" )); 1990 error = FT_THROW( Invalid_Argument ); 1991 goto Exit; 1992 } 1993 1994 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) 1995 { 1996 p->font->props_size = 0; 1997 goto Exit; 1998 } 1999 2000 p->flags |= BDF_PROPS_; 2001 *next = _bdf_parse_properties; 2002 2003 goto Exit; 2004 } 2005 2006 /* Check for the FONTBOUNDINGBOX field. */ 2007 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) 2008 { 2009 if ( !( p->flags & BDF_SIZE_ ) ) 2010 { 2011 /* Missing the SIZE field. */ 2012 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" )); 2013 error = FT_THROW( Missing_Size_Field ); 2014 goto Exit; 2015 } 2016 2017 error = _bdf_list_split( &p->list, " +", line, linelen ); 2018 if ( error ) 2019 goto Exit; 2020 2021 p->font->bbx.width = _bdf_atous( p->list.field[1] ); 2022 p->font->bbx.height = _bdf_atous( p->list.field[2] ); 2023 2024 p->font->bbx.x_offset = _bdf_atos( p->list.field[3] ); 2025 p->font->bbx.y_offset = _bdf_atos( p->list.field[4] ); 2026 2027 p->font->bbx.ascent = (short)( p->font->bbx.height + 2028 p->font->bbx.y_offset ); 2029 2030 p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); 2031 2032 p->flags |= BDF_FONT_BBX_; 2033 2034 goto Exit; 2035 } 2036 2037 /* The next thing to check for is the FONT field. */ 2038 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 ) 2039 { 2040 error = _bdf_list_split( &p->list, " +", line, linelen ); 2041 if ( error ) 2042 goto Exit; 2043 _bdf_list_shift( &p->list, 1 ); 2044 2045 s = _bdf_list_join( &p->list, ' ', &slen ); 2046 2047 if ( !s ) 2048 { 2049 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" )); 2050 error = FT_THROW( Invalid_File_Format ); 2051 goto Exit; 2052 } 2053 2054 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ 2055 FT_FREE( p->font->name ); 2056 2057 if ( FT_QALLOC( p->font->name, slen + 1 ) ) 2058 goto Exit; 2059 FT_MEM_COPY( p->font->name, s, slen + 1 ); 2060 2061 /* If the font name is an XLFD name, set the spacing to the one in */ 2062 /* the font name. If there is no spacing fall back on the default. */ 2063 error = _bdf_set_default_spacing( p->font, p->opts, lineno ); 2064 if ( error ) 2065 goto Exit; 2066 2067 p->flags |= BDF_FONT_NAME_; 2068 2069 goto Exit; 2070 } 2071 2072 /* Check for the SIZE field. */ 2073 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 ) 2074 { 2075 if ( !( p->flags & BDF_FONT_NAME_ ) ) 2076 { 2077 /* Missing the FONT field. */ 2078 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" )); 2079 error = FT_THROW( Missing_Font_Field ); 2080 goto Exit; 2081 } 2082 2083 error = _bdf_list_split( &p->list, " +", line, linelen ); 2084 if ( error ) 2085 goto Exit; 2086 2087 p->font->point_size = _bdf_atoul( p->list.field[1] ); 2088 p->font->resolution_x = _bdf_atoul( p->list.field[2] ); 2089 p->font->resolution_y = _bdf_atoul( p->list.field[3] ); 2090 2091 /* Check for the bits per pixel field. */ 2092 if ( p->list.used == 5 ) 2093 { 2094 unsigned short bpp; 2095 2096 2097 bpp = _bdf_atous( p->list.field[4] ); 2098 2099 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */ 2100 if ( bpp > 4 ) 2101 p->font->bpp = 8; 2102 else if ( bpp > 2 ) 2103 p->font->bpp = 4; 2104 else if ( bpp > 1 ) 2105 p->font->bpp = 2; 2106 else 2107 p->font->bpp = 1; 2108 2109 if ( p->font->bpp != bpp ) 2110 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp )); 2111 } 2112 else 2113 p->font->bpp = 1; 2114 2115 p->flags |= BDF_SIZE_; 2116 2117 goto Exit; 2118 } 2119 2120 /* Check for the CHARS field -- font properties are optional */ 2121 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 ) 2122 { 2123 char nbuf[128]; 2124 2125 2126 if ( !( p->flags & BDF_FONT_BBX_ ) ) 2127 { 2128 /* Missing the FONTBOUNDINGBOX field. */ 2129 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); 2130 error = FT_THROW( Missing_Fontboundingbox_Field ); 2131 goto Exit; 2132 } 2133 2134 /* Add the two standard X11 properties which are required */ 2135 /* for compiling fonts. */ 2136 p->font->font_ascent = p->font->bbx.ascent; 2137 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); 2138 error = _bdf_add_property( p->font, "FONT_ASCENT", 2139 nbuf, lineno ); 2140 if ( error ) 2141 goto Exit; 2142 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); 2143 2144 p->font->font_descent = p->font->bbx.descent; 2145 ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); 2146 error = _bdf_add_property( p->font, "FONT_DESCENT", 2147 nbuf, lineno ); 2148 if ( error ) 2149 goto Exit; 2150 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); 2151 2152 *next = _bdf_parse_glyphs; 2153 2154 /* A special return value. */ 2155 error = -1; 2156 goto Exit; 2157 } 2158 2159 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno )); 2160 error = FT_THROW( Invalid_File_Format ); 2161 2162 Exit: 2163 return error; 2164 } 2165 2166 2167 /************************************************************************** 2168 * 2169 * API. 2170 * 2171 */ 2172 2173 2174 FT_LOCAL_DEF( FT_Error ) bdf_load_font(FT_Stream stream,FT_Memory memory,bdf_options_t * opts,bdf_font_t ** font)2175 bdf_load_font( FT_Stream stream, 2176 FT_Memory memory, 2177 bdf_options_t* opts, 2178 bdf_font_t* *font ) 2179 { 2180 unsigned long lineno = 0; /* make compiler happy */ 2181 _bdf_parse_t *p = NULL; 2182 2183 FT_Error error = FT_Err_Ok; 2184 2185 2186 if ( FT_NEW( p ) ) 2187 goto Exit; 2188 2189 p->opts = (bdf_options_t*)( opts ? opts : &_bdf_opts ); 2190 p->minlb = 32767; 2191 p->size = stream->size; 2192 p->memory = memory; /* only during font creation */ 2193 2194 _bdf_list_init( &p->list, memory ); 2195 2196 error = _bdf_readstream( stream, _bdf_parse_start, 2197 (void *)p, &lineno ); 2198 if ( error ) 2199 goto Fail; 2200 2201 if ( p->font ) 2202 { 2203 /* If the font is not proportional, set the font's monowidth */ 2204 /* field to the width of the font bounding box. */ 2205 2206 if ( p->font->spacing != BDF_PROPORTIONAL ) 2207 p->font->monowidth = p->font->bbx.width; 2208 2209 /* If the number of glyphs loaded is not that of the original count, */ 2210 /* indicate the difference. */ 2211 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) 2212 { 2213 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, 2214 p->font->glyphs_used + p->font->unencoded_used )); 2215 } 2216 2217 /* Once the font has been loaded, adjust the overall font metrics if */ 2218 /* necessary. */ 2219 if ( p->opts->correct_metrics != 0 && 2220 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) 2221 { 2222 if ( p->maxrb - p->minlb != p->font->bbx.width ) 2223 { 2224 FT_TRACE2(( "bdf_load_font: " ACMSG3, 2225 p->font->bbx.width, p->maxrb - p->minlb )); 2226 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); 2227 } 2228 2229 if ( p->font->bbx.x_offset != p->minlb ) 2230 { 2231 FT_TRACE2(( "bdf_load_font: " ACMSG4, 2232 p->font->bbx.x_offset, p->minlb )); 2233 p->font->bbx.x_offset = p->minlb; 2234 } 2235 2236 if ( p->font->bbx.ascent != p->maxas ) 2237 { 2238 FT_TRACE2(( "bdf_load_font: " ACMSG5, 2239 p->font->bbx.ascent, p->maxas )); 2240 p->font->bbx.ascent = p->maxas; 2241 } 2242 2243 if ( p->font->bbx.descent != p->maxds ) 2244 { 2245 FT_TRACE2(( "bdf_load_font: " ACMSG6, 2246 p->font->bbx.descent, p->maxds )); 2247 p->font->bbx.descent = p->maxds; 2248 p->font->bbx.y_offset = (short)( -p->maxds ); 2249 } 2250 2251 if ( p->maxas + p->maxds != p->font->bbx.height ) 2252 { 2253 FT_TRACE2(( "bdf_load_font: " ACMSG7, 2254 p->font->bbx.height, p->maxas + p->maxds )); 2255 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); 2256 } 2257 2258 if ( p->flags & BDF_SWIDTH_ADJ_ ) 2259 FT_TRACE2(( "bdf_load_font: " ACMSG8 )); 2260 } 2261 } 2262 2263 if ( p->flags & BDF_START_ ) 2264 { 2265 /* The ENDFONT field was never reached or did not exist. */ 2266 if ( !( p->flags & BDF_GLYPHS_ ) ) 2267 { 2268 /* Error happened while parsing header. */ 2269 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); 2270 error = FT_THROW( Corrupted_Font_Header ); 2271 goto Fail; 2272 } 2273 else 2274 { 2275 /* Error happened when parsing glyphs. */ 2276 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); 2277 error = FT_THROW( Corrupted_Font_Glyphs ); 2278 goto Fail; 2279 } 2280 } 2281 2282 if ( !p->font && !error ) 2283 error = FT_THROW( Invalid_File_Format ); 2284 2285 *font = p->font; 2286 2287 Exit: 2288 if ( p ) 2289 { 2290 _bdf_list_done( &p->list ); 2291 2292 FT_FREE( p->glyph_name ); 2293 FT_FREE( p ); 2294 } 2295 2296 return error; 2297 2298 Fail: 2299 bdf_free_font( p->font ); 2300 2301 FT_FREE( p->font ); 2302 2303 goto Exit; 2304 } 2305 2306 2307 FT_LOCAL_DEF( void ) bdf_free_font(bdf_font_t * font)2308 bdf_free_font( bdf_font_t* font ) 2309 { 2310 bdf_property_t* prop; 2311 unsigned long i; 2312 bdf_glyph_t* glyphs; 2313 FT_Memory memory; 2314 2315 2316 if ( font == NULL ) 2317 return; 2318 2319 memory = font->memory; 2320 2321 FT_FREE( font->name ); 2322 2323 /* Free up the internal hash table of property names. */ 2324 if ( font->internal ) 2325 { 2326 ft_hash_str_free( (FT_Hash)font->internal, memory ); 2327 FT_FREE( font->internal ); 2328 } 2329 2330 /* Free up the comment info. */ 2331 FT_FREE( font->comments ); 2332 2333 /* Free up the properties. */ 2334 for ( i = 0; i < font->props_size; i++ ) 2335 { 2336 if ( font->props[i].format == BDF_ATOM ) 2337 FT_FREE( font->props[i].value.atom ); 2338 } 2339 2340 FT_FREE( font->props ); 2341 2342 /* Free up the character info. */ 2343 for ( i = 0, glyphs = font->glyphs; 2344 i < font->glyphs_used; i++, glyphs++ ) 2345 { 2346 FT_FREE( glyphs->name ); 2347 FT_FREE( glyphs->bitmap ); 2348 } 2349 2350 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; 2351 i++, glyphs++ ) 2352 { 2353 FT_FREE( glyphs->name ); 2354 FT_FREE( glyphs->bitmap ); 2355 } 2356 2357 FT_FREE( font->glyphs ); 2358 FT_FREE( font->unencoded ); 2359 2360 /* bdf_cleanup */ 2361 ft_hash_str_free( &(font->proptbl), memory ); 2362 2363 /* Free up the user defined properties. */ 2364 for ( prop = font->user_props, i = 0; 2365 i < font->nuser_props; i++, prop++ ) 2366 FT_FREE( prop->name ); 2367 2368 FT_FREE( font->user_props ); 2369 2370 /* FREE( font ); */ /* XXX Fixme */ 2371 } 2372 2373 2374 FT_LOCAL_DEF( bdf_property_t * ) bdf_get_font_property(bdf_font_t * font,const char * name)2375 bdf_get_font_property( bdf_font_t* font, 2376 const char* name ) 2377 { 2378 size_t* propid; 2379 2380 2381 if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 ) 2382 return 0; 2383 2384 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal ); 2385 2386 return propid ? ( font->props + *propid ) : 0; 2387 } 2388 2389 2390 /* END */ 2391