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