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