bdflib.c (49632B)
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 * Builtin BDF font properties. 57 * 58 */ 59 60 /* List of most properties that might appear in a font. Doesn't include */ 61 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */ 62 63 static const bdf_property_t bdf_properties_[] = 64 { 65 { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, 66 { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, 67 { "AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, 68 { "AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, 69 { "CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, 70 { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, 71 { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, 72 { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, 73 { "COPYRIGHT", BDF_ATOM, 1, { 0 } }, 74 { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, 75 { "DESTINATION", BDF_CARDINAL, 1, { 0 } }, 76 { "DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } }, 77 { "END_SPACE", BDF_INTEGER, 1, { 0 } }, 78 { "FACE_NAME", BDF_ATOM, 1, { 0 } }, 79 { "FAMILY_NAME", BDF_ATOM, 1, { 0 } }, 80 { "FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, 81 { "FONT", BDF_ATOM, 1, { 0 } }, 82 { "FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } }, 83 { "FONT_ASCENT", BDF_INTEGER, 1, { 0 } }, 84 { "FONT_DESCENT", BDF_INTEGER, 1, { 0 } }, 85 { "FOUNDRY", BDF_ATOM, 1, { 0 } }, 86 { "FULL_NAME", BDF_ATOM, 1, { 0 } }, 87 { "ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } }, 88 { "MAX_SPACE", BDF_INTEGER, 1, { 0 } }, 89 { "MIN_SPACE", BDF_INTEGER, 1, { 0 } }, 90 { "NORM_SPACE", BDF_INTEGER, 1, { 0 } }, 91 { "NOTICE", BDF_ATOM, 1, { 0 } }, 92 { "PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, 93 { "POINT_SIZE", BDF_INTEGER, 1, { 0 } }, 94 { "QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, 95 { "RAW_ASCENT", BDF_INTEGER, 1, { 0 } }, 96 { "RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, 97 { "RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, 98 { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, 99 { "RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, 100 { "RAW_DESCENT", BDF_INTEGER, 1, { 0 } }, 101 { "RAW_END_SPACE", BDF_INTEGER, 1, { 0 } }, 102 { "RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, 103 { "RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } }, 104 { "RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } }, 105 { "RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } }, 106 { "RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, 107 { "RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } }, 108 { "RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } }, 109 { "RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } }, 110 { "RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, 111 { "RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, 112 { "RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, 113 { "RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, 114 { "RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 115 { "RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 116 { "RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 117 { "RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 118 { "RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 119 { "RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 120 { "RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, 121 { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, 122 { "RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } }, 123 { "RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } }, 124 { "RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } }, 125 { "RESOLUTION", BDF_INTEGER, 1, { 0 } }, 126 { "RESOLUTION_X", BDF_CARDINAL, 1, { 0 } }, 127 { "RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } }, 128 { "SETWIDTH_NAME", BDF_ATOM, 1, { 0 } }, 129 { "SLANT", BDF_ATOM, 1, { 0 } }, 130 { "SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, 131 { "SPACING", BDF_ATOM, 1, { 0 } }, 132 { "STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, 133 { "STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, 134 { "SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 135 { "SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 136 { "SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 137 { "SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 138 { "SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 139 { "SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 140 { "UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, 141 { "UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, 142 { "WEIGHT", BDF_CARDINAL, 1, { 0 } }, 143 { "WEIGHT_NAME", BDF_ATOM, 1, { 0 } }, 144 { "X_HEIGHT", BDF_INTEGER, 1, { 0 } }, 145 { "_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } }, 146 { "_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } }, 147 }; 148 149 static const unsigned long 150 num_bdf_properties_ = sizeof ( bdf_properties_ ) / 151 sizeof ( bdf_properties_[0] ); 152 153 /* Auto correction messages. */ 154 #define ACMSG1 "FONT_ASCENT property missing. " \ 155 "Added `FONT_ASCENT %hd'.\n" 156 #define ACMSG2 "FONT_DESCENT property missing. " \ 157 "Added `FONT_DESCENT %hd'.\n" 158 #define ACMSG3 "Font width != actual width. Old: %d New: %d.\n" 159 #define ACMSG4 "Font left bearing != actual left bearing. " \ 160 "Old: %hd New: %hd.\n" 161 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n" 162 #define ACMSG6 "Font descent != actual descent. Old: %d New: %d.\n" 163 #define ACMSG7 "Font height != actual height. Old: %d New: %d.\n" 164 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n" 165 #define ACMSG9 "SWIDTH field missing at line %lu. Set automatically.\n" 166 #define ACMSG10 "DWIDTH field missing at line %lu. Set to glyph width.\n" 167 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" 168 #define ACMSG13 "Glyph %lu extra rows removed.\n" 169 #define ACMSG14 "Glyph %lu extra columns removed.\n" 170 #define ACMSG15 "Incorrect glyph count: %lu indicated but %lu found.\n" 171 #define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n" 172 #define ACMSG17 "Adjusting number of glyphs to %lu.\n" 173 174 /* Error messages. */ 175 #define ERRMSG1 "[line %lu] Missing `%s' line.\n" 176 #define ERRMSG2 "[line %lu] Font header corrupted or missing fields.\n" 177 #define ERRMSG3 "[line %lu] Font glyphs corrupted or missing fields.\n" 178 #define ERRMSG4 "[line %lu] BBX too big.\n" 179 #define ERRMSG5 "[line %lu] `%s' value too big.\n" 180 #define ERRMSG6 "[line %lu] Input line too long.\n" 181 #define ERRMSG7 "[line %lu] Font name too long.\n" 182 #define ERRMSG8 "[line %lu] Invalid `%s' value.\n" 183 #define ERRMSG9 "[line %lu] Invalid keyword.\n" 184 185 /* Debug messages. */ 186 #define DBGMSG1 " [%6lu] %s" /* no \n */ 187 #define DBGMSG2 " (0x%lX)\n" 188 189 190 /************************************************************************** 191 * 192 * Utility types and functions. 193 * 194 */ 195 196 197 /* Structure used while loading BDF fonts. */ 198 199 typedef struct bdf_parse_t__ 200 { 201 unsigned long flags; 202 unsigned long cnt; 203 unsigned long row; 204 205 short minlb; 206 short maxlb; 207 short maxrb; 208 short maxas; 209 short maxds; 210 211 short rbearing; 212 213 char* glyph_name; 214 long glyph_enc; 215 216 bdf_glyph_t* glyph; 217 bdf_font_t* font; 218 219 FT_Memory memory; 220 unsigned long size; /* the stream size */ 221 222 } bdf_parse_t_; 223 224 225 /* Function type for parsing lines of a BDF font. */ 226 227 typedef FT_Error 228 (*bdf_line_func_t_)( char* line, 229 unsigned long linelen, 230 unsigned long lineno, 231 bdf_parse_t_* p, 232 void* next ); 233 234 235 #define setsbit( m, cc ) \ 236 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) ) 237 #define sbitset( m, cc ) \ 238 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) 239 240 241 static char* 242 bdf_strtok_( char* line, 243 int delim ) 244 { 245 while ( *line && *line != delim ) 246 line++; 247 248 if ( *line ) 249 *line++ = '\0'; 250 251 while ( *line && *line == delim ) 252 line++; 253 254 return line; 255 } 256 257 258 /* XXX: make this work with EBCDIC also */ 259 260 static const unsigned char a2i[128] = 261 { 262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 268 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 269 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 270 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 271 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 274 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 276 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 278 }; 279 280 static const unsigned char ddigits[32] = 281 { 282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 286 }; 287 288 289 /* Routine to convert a decimal ASCII string to an unsigned long integer. */ 290 static unsigned long 291 bdf_atoul_( const char* s ) 292 { 293 unsigned long v; 294 295 296 for ( v = 0; sbitset( ddigits, *s ); s++ ) 297 { 298 if ( v < ( FT_ULONG_MAX - 9 ) / 10 ) 299 v = v * 10 + a2i[(int)*s]; 300 else 301 { 302 v = FT_ULONG_MAX; 303 break; 304 } 305 } 306 307 return v; 308 } 309 310 311 /* Routine to convert a decimal ASCII string to a signed long integer. */ 312 static long 313 bdf_atol_( const char* s ) 314 { 315 long v, neg; 316 317 318 /* Check for a minus sign. */ 319 if ( *s == '-' ) 320 { 321 s++; 322 neg = -1; 323 } 324 else 325 neg = 1; 326 327 for ( v = 0; sbitset( ddigits, *s ); s++ ) 328 { 329 if ( v < ( FT_LONG_MAX - 9 ) / 10 ) 330 v = v * 10 + a2i[(int)*s]; 331 else 332 { 333 v = FT_LONG_MAX; 334 break; 335 } 336 } 337 338 return neg * v; 339 } 340 341 342 /* Routine to convert a decimal ASCII string to an unsigned short integer. */ 343 static unsigned short 344 bdf_atous_( const char* s ) 345 { 346 unsigned short v; 347 348 349 for ( v = 0; sbitset( ddigits, *s ); s++ ) 350 { 351 if ( v < ( FT_USHORT_MAX - 9 ) / 10 ) 352 v = (unsigned short)( v * 10 + a2i[(int)*s] ); 353 else 354 { 355 v = FT_USHORT_MAX; 356 break; 357 } 358 } 359 360 return v; 361 } 362 363 364 /* Routine to convert a decimal ASCII string to a signed short integer. */ 365 static short 366 bdf_atos_( const char* s ) 367 { 368 short v, neg; 369 370 371 /* Check for a minus. */ 372 if ( *s == '-' ) 373 { 374 s++; 375 neg = -1; 376 } 377 else 378 neg = 1; 379 380 for ( v = 0; sbitset( ddigits, *s ); s++ ) 381 { 382 if ( v < ( SHRT_MAX - 9 ) / 10 ) 383 v = (short)( v * 10 + a2i[(int)*s] ); 384 else 385 { 386 v = SHRT_MAX; 387 break; 388 } 389 } 390 391 return neg * v; 392 } 393 394 395 /* Routine to compare two glyphs by encoding so they can be sorted. */ 396 FT_COMPARE_DEF( int ) 397 by_encoding( const void* a, 398 const void* b ) 399 { 400 bdf_glyph_t *c1, *c2; 401 402 403 c1 = (bdf_glyph_t *)a; 404 c2 = (bdf_glyph_t *)b; 405 406 if ( c1->encoding < c2->encoding ) 407 return -1; 408 409 if ( c1->encoding > c2->encoding ) 410 return 1; 411 412 return 0; 413 } 414 415 416 static FT_Error 417 bdf_create_property( const char* name, 418 int format, 419 bdf_font_t* font ) 420 { 421 size_t n; 422 bdf_property_t* p; 423 FT_Memory memory = font->memory; 424 FT_Error error = FT_Err_Ok; 425 426 427 /* First check whether the property has */ 428 /* already been added or not. If it has, then */ 429 /* simply ignore it. */ 430 if ( ft_hash_str_lookup( name, &(font->proptbl) ) ) 431 goto Exit; 432 433 if ( FT_QRENEW_ARRAY( font->user_props, 434 font->nuser_props, 435 font->nuser_props + 1 ) ) 436 goto Exit; 437 438 p = font->user_props + font->nuser_props; 439 440 if ( FT_STRDUP( p->name, name ) ) 441 goto Exit; 442 443 p->format = format; 444 p->builtin = 0; 445 p->value.atom = NULL; /* nothing is ever stored here */ 446 447 n = num_bdf_properties_ + font->nuser_props; 448 449 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory ); 450 if ( error ) 451 goto Exit; 452 453 font->nuser_props++; 454 455 Exit: 456 return error; 457 } 458 459 460 static bdf_property_t* 461 bdf_get_property( const char* name, 462 bdf_font_t* font ) 463 { 464 size_t* propid; 465 466 467 if ( name == NULL || *name == 0 ) 468 return NULL; 469 470 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL ) 471 return NULL; 472 473 if ( *propid >= num_bdf_properties_ ) 474 return font->user_props + ( *propid - num_bdf_properties_ ); 475 476 return (bdf_property_t*)bdf_properties_ + *propid; 477 } 478 479 480 /************************************************************************** 481 * 482 * BDF font file parsing flags and functions. 483 * 484 */ 485 486 487 /* Parse flags. */ 488 489 #define BDF_START_ 0x0001U 490 #define BDF_FONT_NAME_ 0x0002U 491 #define BDF_SIZE_ 0x0004U 492 #define BDF_FONT_BBX_ 0x0008U 493 #define BDF_PROPS_ 0x0010U 494 #define BDF_GLYPHS_ 0x0020U 495 #define BDF_GLYPH_ 0x0040U 496 #define BDF_ENCODING_ 0x0080U 497 #define BDF_SWIDTH_ 0x0100U 498 #define BDF_DWIDTH_ 0x0200U 499 #define BDF_BBX_ 0x0400U 500 #define BDF_BITMAP_ 0x0800U 501 502 #define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \ 503 BDF_ENCODING_ | \ 504 BDF_SWIDTH_ | \ 505 BDF_DWIDTH_ | \ 506 BDF_BBX_ | \ 507 BDF_BITMAP_ ) 508 509 510 static FT_Error 511 bdf_add_comment_( bdf_font_t* font, 512 const char* comment, 513 unsigned long len ) 514 { 515 char* cp; 516 FT_Memory memory = font->memory; 517 FT_Error error = FT_Err_Ok; 518 519 520 /* Skip keyword COMMENT. */ 521 comment += 7; 522 len -= 7; 523 524 if ( len == 0 ) 525 goto Exit; 526 527 if ( FT_QRENEW_ARRAY( font->comments, 528 font->comments_len, 529 font->comments_len + len + 1 ) ) 530 goto Exit; 531 532 cp = font->comments + font->comments_len; 533 534 FT_MEM_COPY( cp, comment, len ); 535 cp[len] = '\0'; 536 537 font->comments_len += len + 1; 538 539 Exit: 540 return error; 541 } 542 543 544 /* Determine whether the property is an atom or not. If it is, then */ 545 /* clean it up so the double quotes are removed if they exist. */ 546 static int 547 bdf_is_atom_( char* line, 548 unsigned long linelen, 549 char** name, 550 char** value, 551 bdf_font_t* font ) 552 { 553 int hold; 554 char *sp, *ep; 555 bdf_property_t* p; 556 557 558 sp = ep = line; 559 560 while ( *ep && *ep != ' ' ) 561 ep++; 562 563 hold = *ep; 564 *ep = '\0'; 565 566 p = bdf_get_property( sp, font ); 567 568 /* If the property exists and is not an atom, just return here. */ 569 if ( p && p->format != BDF_ATOM ) 570 { 571 *ep = (char)hold; /* Undo NUL-termination. */ 572 return 0; 573 } 574 575 *name = sp; 576 577 /* The property is an atom. Trim all leading and trailing whitespace */ 578 /* and double quotes for the atom value. */ 579 sp = ep; 580 ep = line + linelen; 581 582 /* Trim the leading whitespace if it exists. */ 583 if ( sp < ep ) 584 do 585 sp++; 586 while ( *sp == ' ' ); 587 588 /* Trim the leading double quote if it exists. */ 589 if ( *sp == '"' ) 590 sp++; 591 592 *value = sp; 593 594 /* Trim the trailing whitespace if it exists. */ 595 if ( sp < ep ) 596 do 597 *ep-- = '\0'; 598 while ( *ep == ' ' ); 599 600 /* Trim the trailing double quote if it exists. */ 601 if ( *ep == '"' ) 602 *ep = '\0'; 603 604 return 1; 605 } 606 607 608 static FT_Error 609 bdf_add_property_( bdf_font_t* font, 610 const char* name, 611 char* value, 612 unsigned long lineno ) 613 { 614 size_t* propid; 615 bdf_property_t *prop, *fp; 616 FT_Memory memory = font->memory; 617 FT_Error error = FT_Err_Ok; 618 619 FT_UNUSED( lineno ); /* only used in debug mode */ 620 621 622 /* First, check whether the property already exists in the font. */ 623 if ( ( propid = ft_hash_str_lookup( name, font->internal ) ) != NULL ) 624 { 625 /* The property already exists in the font, so simply replace */ 626 /* the value of the property with the current value. */ 627 fp = font->props + *propid; 628 629 switch ( fp->format ) 630 { 631 case BDF_ATOM: 632 /* Delete the current atom if it exists. */ 633 FT_FREE( fp->value.atom ); 634 635 if ( value && value[0] != 0 ) 636 { 637 if ( FT_STRDUP( fp->value.atom, value ) ) 638 goto Exit; 639 } 640 break; 641 642 case BDF_INTEGER: 643 fp->value.l = bdf_atol_( value ); 644 break; 645 646 case BDF_CARDINAL: 647 fp->value.ul = bdf_atoul_( value ); 648 break; 649 650 default: 651 ; 652 } 653 654 goto Exit; 655 } 656 657 /* See whether this property type exists yet or not. */ 658 /* If not, create it. */ 659 propid = ft_hash_str_lookup( name, &(font->proptbl) ); 660 if ( !propid ) 661 { 662 error = bdf_create_property( name, BDF_ATOM, font ); 663 if ( error ) 664 goto Exit; 665 propid = ft_hash_str_lookup( name, &(font->proptbl) ); 666 } 667 668 /* Allocate another property if this is overflowing. */ 669 if ( font->props_used == font->props_size ) 670 { 671 if ( FT_QRENEW_ARRAY( font->props, 672 font->props_size, 673 font->props_size + 1 ) ) 674 goto Exit; 675 676 font->props_size++; 677 } 678 679 if ( *propid >= num_bdf_properties_ ) 680 prop = font->user_props + ( *propid - num_bdf_properties_ ); 681 else 682 prop = (bdf_property_t*)bdf_properties_ + *propid; 683 684 fp = font->props + font->props_used; 685 686 fp->name = prop->name; 687 fp->format = prop->format; 688 fp->builtin = prop->builtin; 689 690 switch ( prop->format ) 691 { 692 case BDF_ATOM: 693 fp->value.atom = NULL; 694 if ( value && value[0] ) 695 { 696 if ( FT_STRDUP( fp->value.atom, value ) ) 697 goto Exit; 698 } 699 break; 700 701 case BDF_INTEGER: 702 fp->value.l = bdf_atol_( value ); 703 break; 704 705 case BDF_CARDINAL: 706 fp->value.ul = bdf_atoul_( value ); 707 break; 708 } 709 710 /* Add the property to the font property table. */ 711 error = ft_hash_str_insert( fp->name, 712 font->props_used, 713 font->internal, 714 memory ); 715 if ( error ) 716 goto Exit; 717 718 font->props_used++; 719 720 Exit: 721 return error; 722 } 723 724 725 static FT_Error 726 bdf_parse_end_( char* line, 727 unsigned long linelen, 728 unsigned long lineno, 729 bdf_parse_t_* p, 730 void* next ) 731 { 732 /* a no-op; we ignore everything after `ENDFONT' */ 733 734 FT_UNUSED( line ); 735 FT_UNUSED( linelen ); 736 FT_UNUSED( lineno ); 737 FT_UNUSED( p ); 738 FT_UNUSED( next ); 739 740 return FT_Err_Ok; 741 } 742 743 744 /* Line function prototypes. */ 745 static FT_Error 746 bdf_parse_start_( char* line, 747 unsigned long linelen, 748 unsigned long lineno, 749 bdf_parse_t_* p, 750 void* next ); 751 752 753 static FT_Error 754 bdf_parse_glyphs_( char* line, 755 unsigned long linelen, 756 unsigned long lineno, 757 bdf_parse_t_* p, 758 void* next ); 759 760 761 /* Aggressively parse the glyph bitmaps. */ 762 static FT_Error 763 bdf_parse_bitmap_( char* line, 764 unsigned long linelen, 765 unsigned long lineno, 766 bdf_parse_t_* p, 767 void* next ) 768 { 769 bdf_glyph_t* glyph = p->glyph; 770 unsigned char* bp; 771 unsigned long i, nibbles; 772 int x; 773 774 FT_UNUSED( lineno ); /* only used in debug mode */ 775 776 777 nibbles = glyph->bpr << 1; 778 bp = glyph->bitmap + p->row * glyph->bpr; 779 780 if ( nibbles > linelen ) 781 { 782 FT_TRACE2(( "bdf_parse_bitmap_: " ACMSG16, glyph->encoding )); 783 nibbles = linelen; 784 } 785 786 for ( i = 0; i < nibbles; i++ ) 787 { 788 /* char to hex without checks */ 789 x = line[i]; 790 x += 9 * ( x & 0x40 ) >> 6; /* for [A-Fa-f] */ 791 x &= 0x0F; 792 793 if ( i & 1 ) 794 *bp++ |= x; 795 else 796 *bp = (unsigned char)( x << 4 ); 797 } 798 799 p->row++; 800 801 /* When done, go back to parsing glyphs */ 802 if ( p->row >= (unsigned long)glyph->bbx.height ) 803 *(bdf_line_func_t_*)next = bdf_parse_glyphs_; 804 805 return FT_Err_Ok; 806 } 807 808 809 /* Actually parse the glyph info. */ 810 static FT_Error 811 bdf_parse_glyphs_( char* line, 812 unsigned long linelen, 813 unsigned long lineno, 814 bdf_parse_t_* p, 815 void* next ) 816 { 817 bdf_font_t* font = p->font; 818 bdf_glyph_t* glyph; 819 FT_Memory memory = font->memory; 820 FT_Error error = FT_Err_Ok; 821 822 FT_UNUSED( lineno ); /* only used in debug mode */ 823 824 825 /* Check for a comment. */ 826 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) 827 { 828 if ( p->flags & BDF_KEEP_COMMENTS ) 829 error = bdf_add_comment_( font, line, linelen ); 830 831 goto Exit; 832 } 833 834 /* Check for the ENDFONT field. */ 835 if ( ft_strncmp( line, "ENDFONT", 7 ) == 0 ) 836 { 837 if ( p->flags & BDF_GLYPH_BITS_ ) 838 { 839 /* Missing ENDCHAR field. */ 840 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" )); 841 error = FT_THROW( Corrupted_Font_Glyphs ); 842 goto Exit; 843 } 844 845 /* Sort the glyphs by encoding. */ 846 ft_qsort( (char *)font->glyphs, 847 font->glyphs_used, 848 sizeof ( bdf_glyph_t ), 849 by_encoding ); 850 851 p->flags &= ~BDF_START_; 852 853 *(bdf_line_func_t_*)next = bdf_parse_end_; 854 855 goto Exit; 856 } 857 858 /* Check for the ENDCHAR field. */ 859 if ( ft_strncmp( line, "ENDCHAR", 7 ) == 0 ) 860 { 861 /* Free unused glyph_name */ 862 FT_FREE( p->glyph_name ); 863 864 p->glyph_enc = 0; 865 p->flags &= ~BDF_GLYPH_BITS_; 866 867 goto Exit; 868 } 869 870 /* Check whether a glyph is being scanned but should be */ 871 /* ignored because it is an unencoded glyph. */ 872 if ( p->flags & BDF_GLYPH_ && 873 p->glyph_enc == -1 && 874 !( p->flags & BDF_KEEP_UNENCODED ) ) 875 goto Exit; 876 877 /* Check for the STARTCHAR field. */ 878 if ( ft_strncmp( line, "STARTCHAR ", 10 ) == 0 ) 879 { 880 if ( p->flags & BDF_GLYPH_BITS_ ) 881 { 882 /* Missing ENDCHAR field. */ 883 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" )); 884 error = FT_THROW( Missing_Startchar_Field ); 885 goto Exit; 886 } 887 888 line = bdf_strtok_( line, ' ' ); 889 890 if ( FT_STRDUP( p->glyph_name, line ) ) 891 goto Exit; 892 893 p->flags |= BDF_GLYPH_; 894 895 FT_TRACE4(( DBGMSG1, lineno, line )); 896 897 goto Exit; 898 } 899 900 /* Check for the ENCODING field. */ 901 if ( ft_strncmp( line, "ENCODING ", 9 ) == 0 ) 902 { 903 if ( !( p->flags & BDF_GLYPH_ ) ) 904 { 905 /* Missing STARTCHAR field. */ 906 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" )); 907 error = FT_THROW( Missing_Startchar_Field ); 908 goto Exit; 909 } 910 911 line = bdf_strtok_( line, ' ' ); 912 913 p->glyph_enc = bdf_atol_( line ); 914 915 /* Normalize negative encoding values. The specification only */ 916 /* allows -1, but we can be more generous here. */ 917 if ( p->glyph_enc < -1 ) 918 p->glyph_enc = -1; 919 920 /* Check for alternative encoding format. */ 921 line = bdf_strtok_( line, ' ' ); 922 923 if ( p->glyph_enc == -1 && *line ) 924 p->glyph_enc = bdf_atol_( line ); 925 926 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L ) 927 p->glyph_enc = -1; 928 929 FT_TRACE4(( DBGMSG2, p->glyph_enc )); 930 931 if ( p->glyph_enc >= 0 ) 932 { 933 /* Make sure there are enough glyphs allocated in case the */ 934 /* number of characters happen to be wrong. */ 935 if ( font->glyphs_used == font->glyphs_size ) 936 { 937 if ( FT_RENEW_ARRAY( font->glyphs, 938 font->glyphs_size, 939 font->glyphs_size + 64 ) ) 940 goto Exit; 941 942 font->glyphs_size += 64; 943 } 944 945 glyph = font->glyphs + font->glyphs_used++; 946 glyph->name = p->glyph_name; 947 glyph->encoding = (unsigned long)p->glyph_enc; 948 } 949 else if ( p->flags & BDF_KEEP_UNENCODED ) 950 { 951 /* Allocate the next unencoded glyph. */ 952 if ( font->unencoded_used == font->unencoded_size ) 953 { 954 if ( FT_RENEW_ARRAY( font->unencoded , 955 font->unencoded_size, 956 font->unencoded_size + 4 ) ) 957 goto Exit; 958 959 font->unencoded_size += 4; 960 } 961 962 glyph = font->unencoded + font->unencoded_used; 963 glyph->name = p->glyph_name; 964 glyph->encoding = font->unencoded_used++; 965 } 966 else 967 { 968 /* Free up the glyph name if the unencoded shouldn't be */ 969 /* kept. */ 970 FT_FREE( p->glyph_name ); 971 glyph = NULL; 972 } 973 974 p->glyph_name = NULL; 975 p->glyph = glyph; 976 p->flags |= BDF_ENCODING_; 977 978 goto Exit; 979 } 980 981 if ( !( p->flags & BDF_ENCODING_ ) ) 982 goto Missing_Encoding; 983 984 /* Point at the glyph being constructed. */ 985 glyph = p->glyph; 986 987 /* Expect the SWIDTH (scalable width) field next. */ 988 if ( ft_strncmp( line, "SWIDTH ", 7 ) == 0 ) 989 { 990 line = bdf_strtok_( line, ' ' ); 991 glyph->swidth = bdf_atous_( line ); 992 993 p->flags |= BDF_SWIDTH_; 994 goto Exit; 995 } 996 997 /* Expect the DWIDTH (device width) field next. */ 998 if ( ft_strncmp( line, "DWIDTH ", 7 ) == 0 ) 999 { 1000 line = bdf_strtok_( line, ' ' ); 1001 glyph->dwidth = bdf_atous_( line ); 1002 1003 if ( !( p->flags & BDF_SWIDTH_ ) ) 1004 { 1005 /* Missing SWIDTH field. Emit an auto correction message and set */ 1006 /* the scalable width from the device width. */ 1007 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno )); 1008 1009 glyph->swidth = (unsigned short)FT_MulDiv( 1010 glyph->dwidth, 72000L, 1011 (FT_Long)( font->point_size * 1012 font->resolution_x ) ); 1013 } 1014 1015 p->flags |= BDF_DWIDTH_; 1016 goto Exit; 1017 } 1018 1019 /* Do not leak the bitmap or reset its size */ 1020 if ( p->flags & BDF_BITMAP_ ) 1021 goto Exit; 1022 1023 /* Expect the BBX field next. */ 1024 if ( ft_strncmp( line, "BBX ", 4 ) == 0 ) 1025 { 1026 line = bdf_strtok_( line, ' ' ); 1027 glyph->bbx.width = bdf_atous_( line ); 1028 line = bdf_strtok_( line, ' ' ); 1029 glyph->bbx.height = bdf_atous_( line ); 1030 line = bdf_strtok_( line, ' ' ); 1031 glyph->bbx.x_offset = bdf_atos_( line ); 1032 line = bdf_strtok_( line, ' ' ); 1033 glyph->bbx.y_offset = bdf_atos_( line ); 1034 1035 /* Generate the ascent and descent of the character. */ 1036 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); 1037 glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); 1038 1039 /* Determine the overall font bounding box as the characters are */ 1040 /* loaded so corrections can be done later if indicated. */ 1041 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); 1042 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); 1043 1044 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); 1045 1046 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); 1047 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); 1048 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); 1049 1050 if ( !( p->flags & BDF_DWIDTH_ ) ) 1051 { 1052 /* Missing DWIDTH field. Emit an auto correction message and set */ 1053 /* the device width to the glyph width. */ 1054 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno )); 1055 glyph->dwidth = glyph->bbx.width; 1056 } 1057 1058 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ 1059 /* value if necessary. */ 1060 if ( p->flags & BDF_CORRECT_METRICS ) 1061 { 1062 /* Determine the point size of the glyph. */ 1063 unsigned short sw = (unsigned short)FT_MulDiv( 1064 glyph->dwidth, 72000L, 1065 (FT_Long)( font->point_size * 1066 font->resolution_x ) ); 1067 1068 1069 if ( sw != glyph->swidth ) 1070 { 1071 glyph->swidth = sw; 1072 1073 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG8 )); 1074 } 1075 } 1076 1077 p->flags |= BDF_BBX_; 1078 goto Exit; 1079 } 1080 1081 /* And finally, gather up the bitmap. */ 1082 if ( ft_strncmp( line, "BITMAP", 6 ) == 0 ) 1083 { 1084 unsigned long bitmap_size; 1085 1086 1087 if ( !( p->flags & BDF_BBX_ ) ) 1088 { 1089 /* Missing BBX field. */ 1090 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" )); 1091 error = FT_THROW( Missing_Bbx_Field ); 1092 goto Exit; 1093 } 1094 1095 /* Allocate enough space for the bitmap. */ 1096 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; 1097 1098 bitmap_size = glyph->bpr * glyph->bbx.height; 1099 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU ) 1100 { 1101 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno )); 1102 error = FT_THROW( Bbx_Too_Big ); 1103 goto Exit; 1104 } 1105 else 1106 glyph->bytes = (unsigned short)bitmap_size; 1107 1108 if ( !bitmap_size || FT_ALLOC( glyph->bitmap, glyph->bytes ) ) 1109 goto Exit; 1110 1111 p->row = 0; 1112 p->flags |= BDF_BITMAP_; 1113 *(bdf_line_func_t_*)next = bdf_parse_bitmap_; 1114 1115 goto Exit; 1116 } 1117 1118 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno )); 1119 error = FT_THROW( Invalid_File_Format ); 1120 goto Exit; 1121 1122 Missing_Encoding: 1123 /* Missing ENCODING field. */ 1124 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" )); 1125 error = FT_THROW( Missing_Encoding_Field ); 1126 1127 Exit: 1128 if ( error && ( p->flags & BDF_GLYPH_ ) ) 1129 FT_FREE( p->glyph_name ); 1130 1131 return error; 1132 } 1133 1134 1135 /* Load the font properties. */ 1136 static FT_Error 1137 bdf_parse_properties_( char* line, 1138 unsigned long linelen, 1139 unsigned long lineno, 1140 bdf_parse_t_* p, 1141 void* next ) 1142 { 1143 bdf_font_t* font = p->font; 1144 FT_Error error = FT_Err_Ok; 1145 char* name; 1146 char* value; 1147 1148 FT_UNUSED( lineno ); 1149 1150 1151 /* Check for a comment. */ 1152 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) 1153 { 1154 if ( p->flags & BDF_KEEP_COMMENTS ) 1155 error = bdf_add_comment_( font, line, linelen ); 1156 1157 goto Exit; 1158 } 1159 1160 /* Check for the end of the properties. */ 1161 if ( ft_strncmp( line, "ENDPROPERTIES", 13 ) == 0 ) 1162 { 1163 *(bdf_line_func_t_*)next = bdf_parse_start_; 1164 1165 goto Exit; 1166 } 1167 1168 /* Ignore the _XFREE86_GLYPH_RANGES properties. */ 1169 if ( ft_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) 1170 goto Exit; 1171 1172 if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) ) 1173 { 1174 error = bdf_add_property_( font, name, value, lineno ); 1175 if ( error ) 1176 goto Exit; 1177 } 1178 else 1179 { 1180 value = bdf_strtok_( line, ' ' ); 1181 1182 error = bdf_add_property_( font, line, value, lineno ); 1183 if ( error ) 1184 goto Exit; 1185 } 1186 1187 Exit: 1188 return error; 1189 } 1190 1191 1192 /* Load the font header. */ 1193 static FT_Error 1194 bdf_parse_start_( char* line, 1195 unsigned long linelen, 1196 unsigned long lineno, 1197 bdf_parse_t_* p, 1198 void* next ) 1199 { 1200 bdf_font_t* font; 1201 FT_Memory memory = p->memory; 1202 FT_Error error = FT_Err_Ok; 1203 1204 FT_UNUSED( lineno ); /* only used in debug mode */ 1205 1206 1207 /* The first line must be STARTFONT. */ 1208 /* Otherwise, reject the font immediately. */ 1209 if ( !( p->flags & BDF_START_ ) ) 1210 { 1211 if ( ft_strncmp( line, "STARTFONT", 9 ) != 0 ) 1212 { 1213 error = FT_THROW( Missing_Startfont_Field ); 1214 goto Exit; 1215 } 1216 1217 p->flags |= BDF_START_; 1218 1219 if ( FT_NEW( p->font ) ) 1220 goto Exit; 1221 1222 p->font->memory = memory; 1223 1224 goto Exit; 1225 } 1226 1227 /* Point at the font being constructed. */ 1228 font = p->font; 1229 1230 /* Check for a comment. */ 1231 if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) 1232 { 1233 if ( p->flags & BDF_KEEP_COMMENTS ) 1234 error = bdf_add_comment_( font, line, linelen ); 1235 1236 goto Exit; 1237 } 1238 1239 /* Check for the start of the properties. */ 1240 if ( !( p->flags & BDF_PROPS_ ) && 1241 ft_strncmp( line, "STARTPROPERTIES ", 16 ) == 0 ) 1242 { 1243 line = bdf_strtok_( line, ' ' ); 1244 font->props_size = bdf_atoul_( line ); 1245 1246 if ( font->props_size < 2 ) 1247 font->props_size = 2; 1248 1249 /* We need at least 4 bytes per property. */ 1250 if ( font->props_size > p->size / 4 ) 1251 { 1252 font->props_size = 0; 1253 1254 FT_ERROR(( "bdf_parse_start_: " ERRMSG5, lineno, "STARTPROPERTIES" )); 1255 error = FT_THROW( Invalid_Argument ); 1256 goto Exit; 1257 } 1258 1259 if ( FT_NEW_ARRAY( font->props, font->props_size ) ) 1260 { 1261 font->props_size = 0; 1262 goto Exit; 1263 } 1264 1265 if ( FT_QNEW( font->internal ) ) 1266 goto Exit; 1267 error = ft_hash_str_init( font->internal, memory ); 1268 if ( error ) 1269 goto Exit; 1270 1271 /* preset common properties */ 1272 { 1273 bdf_property_t* prop = (bdf_property_t*)bdf_properties_; 1274 FT_Hash proptbl = &font->proptbl; 1275 size_t i; 1276 1277 1278 error = ft_hash_str_init( proptbl, memory ); 1279 if ( error ) 1280 goto Exit; 1281 for ( i = 0; i < num_bdf_properties_; i++, prop++ ) 1282 { 1283 error = ft_hash_str_insert( prop->name, i, proptbl, memory ); 1284 if ( error ) 1285 goto Exit; 1286 } 1287 } 1288 1289 p->flags |= BDF_PROPS_; 1290 1291 *(bdf_line_func_t_*)next = bdf_parse_properties_; 1292 1293 goto Exit; 1294 } 1295 1296 /* Check for the FONTBOUNDINGBOX field. */ 1297 if ( ft_strncmp( line, "FONTBOUNDINGBOX ", 16 ) == 0 ) 1298 { 1299 line = bdf_strtok_( line, ' ' ); 1300 font->bbx.width = bdf_atous_( line ); 1301 line = bdf_strtok_( line, ' ' ); 1302 font->bbx.height = bdf_atous_( line ); 1303 line = bdf_strtok_( line, ' ' ); 1304 font->bbx.x_offset = bdf_atos_( line ); 1305 line = bdf_strtok_( line, ' ' ); 1306 font->bbx.y_offset = bdf_atos_( line ); 1307 1308 font->bbx.ascent = (short)( font->bbx.height + 1309 font->bbx.y_offset ); 1310 1311 font->bbx.descent = (short)( -font->bbx.y_offset ); 1312 1313 p->flags |= BDF_FONT_BBX_; 1314 1315 goto Exit; 1316 } 1317 1318 /* The next thing to check for is the FONT field. */ 1319 if ( ft_strncmp( line, "FONT ", 5 ) == 0 ) 1320 { 1321 int i; 1322 1323 1324 line = bdf_strtok_( line, ' ' ); 1325 1326 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ 1327 FT_FREE( font->name ); 1328 1329 if ( FT_STRDUP( font->name, line ) ) 1330 goto Exit; 1331 1332 /* If the font name is an XLFD name, set the spacing to the one in */ 1333 /* the font name after the 11th dash. */ 1334 for ( i = 0; i < 11; i++ ) 1335 { 1336 while ( *line && *line != '-' ) 1337 line++; 1338 if ( *line ) 1339 line++; 1340 } 1341 1342 switch ( *line ) 1343 { 1344 case 'C': 1345 case 'c': 1346 font->spacing = BDF_CHARCELL; 1347 break; 1348 case 'M': 1349 case 'm': 1350 font->spacing = BDF_MONOWIDTH; 1351 break; 1352 case 'P': 1353 case 'p': 1354 default: 1355 font->spacing = BDF_PROPORTIONAL; 1356 break; 1357 } 1358 1359 p->flags |= BDF_FONT_NAME_; 1360 1361 goto Exit; 1362 } 1363 1364 /* Check for the SIZE field. */ 1365 if ( ft_strncmp( line, "SIZE ", 5 ) == 0 ) 1366 { 1367 line = bdf_strtok_( line, ' ' ); 1368 font->point_size = bdf_atoul_( line ); 1369 line = bdf_strtok_( line, ' ' ); 1370 font->resolution_x = bdf_atoul_( line ); 1371 line = bdf_strtok_( line, ' ' ); 1372 font->resolution_y = bdf_atoul_( line ); 1373 1374 /* Check for the bits per pixel field. */ 1375 line = bdf_strtok_( line, ' ' ); 1376 if ( *line ) 1377 { 1378 unsigned short bpp; 1379 1380 1381 bpp = bdf_atous_( line ); 1382 1383 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */ 1384 if ( bpp > 4 ) 1385 font->bpp = 8; 1386 else if ( bpp > 2 ) 1387 font->bpp = 4; 1388 else if ( bpp > 1 ) 1389 font->bpp = 2; 1390 else 1391 font->bpp = 1; 1392 1393 if ( font->bpp != bpp ) 1394 FT_TRACE2(( "bdf_parse_start_: " ACMSG11, font->bpp )); 1395 } 1396 else 1397 font->bpp = 1; 1398 1399 p->flags |= BDF_SIZE_; 1400 1401 goto Exit; 1402 } 1403 1404 /* Check for the CHARS field */ 1405 if ( ft_strncmp( line, "CHARS ", 6 ) == 0 ) 1406 { 1407 /* Check the header for completeness before parsing glyphs. */ 1408 if ( !( p->flags & BDF_FONT_NAME_ ) ) 1409 { 1410 /* Missing the FONT field. */ 1411 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" )); 1412 error = FT_THROW( Missing_Font_Field ); 1413 goto Exit; 1414 } 1415 if ( !( p->flags & BDF_SIZE_ ) ) 1416 { 1417 /* Missing the SIZE field. */ 1418 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" )); 1419 error = FT_THROW( Missing_Size_Field ); 1420 goto Exit; 1421 } 1422 if ( !( p->flags & BDF_FONT_BBX_ ) ) 1423 { 1424 /* Missing the FONTBOUNDINGBOX field. */ 1425 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); 1426 error = FT_THROW( Missing_Fontboundingbox_Field ); 1427 goto Exit; 1428 } 1429 1430 line = bdf_strtok_( line, ' ' ); 1431 p->cnt = font->glyphs_size = bdf_atoul_( line ); 1432 1433 /* We need at least 20 bytes per glyph. */ 1434 if ( p->cnt > p->size / 20 ) 1435 { 1436 p->cnt = font->glyphs_size = p->size / 20; 1437 FT_TRACE2(( "bdf_parse_start_: " ACMSG17, p->cnt )); 1438 } 1439 1440 /* Make sure the number of glyphs is non-zero. */ 1441 if ( p->cnt == 0 ) 1442 font->glyphs_size = 64; 1443 1444 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ 1445 /* number of code points available in Unicode). */ 1446 if ( p->cnt >= 0x110000UL ) 1447 { 1448 FT_ERROR(( "bdf_parse_start_: " ERRMSG5, lineno, "CHARS" )); 1449 error = FT_THROW( Invalid_Argument ); 1450 goto Exit; 1451 } 1452 1453 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) 1454 goto Exit; 1455 1456 p->flags |= BDF_GLYPHS_; 1457 1458 *(bdf_line_func_t_*)next = bdf_parse_glyphs_; 1459 1460 goto Exit; 1461 } 1462 1463 FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno )); 1464 error = FT_THROW( Invalid_File_Format ); 1465 1466 Exit: 1467 return error; 1468 } 1469 1470 1471 static FT_Error 1472 bdf_readstream_( FT_Stream stream, 1473 bdf_parse_t_* p, 1474 unsigned long* lno ) 1475 { 1476 bdf_line_func_t_ cb = bdf_parse_start_; 1477 unsigned long lineno, buf_size; 1478 unsigned long bytes, start, end, cursor, avail; 1479 char* buf = NULL; 1480 FT_Memory memory = stream->memory; 1481 FT_Error error = FT_Err_Ok; 1482 1483 1484 /* initial size and allocation of the input buffer */ 1485 buf_size = 1024; 1486 1487 if ( FT_QALLOC( buf, buf_size ) ) 1488 goto Exit; 1489 1490 lineno = 1; 1491 start = 0; 1492 cursor = 0; 1493 1494 Refill: 1495 bytes = FT_Stream_TryRead( stream, 1496 (FT_Byte*)buf + cursor, buf_size - cursor ); 1497 avail = cursor + bytes; 1498 1499 while ( bytes ) 1500 { 1501 /* try to find the start of the line */ 1502 while ( start < avail && buf[start] < ' ' ) 1503 start++; 1504 1505 /* try to find the end of the line */ 1506 end = start + 1; 1507 while ( end < avail && buf[end] >= ' ' ) 1508 end++; 1509 1510 /* if we hit the end of the buffer, try shifting its content */ 1511 /* or even resizing it */ 1512 if ( end >= avail ) 1513 { 1514 if ( start == 0 ) 1515 { 1516 /* this line is definitely too long; try resizing the input */ 1517 /* buffer a bit to handle it. */ 1518 FT_ULong new_size; 1519 1520 1521 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */ 1522 { 1523 FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno )); 1524 error = FT_THROW( Invalid_File_Format ); 1525 1526 goto Exit; 1527 } 1528 1529 new_size = buf_size * 4; 1530 if ( FT_QREALLOC( buf, buf_size, new_size ) ) 1531 goto Exit; 1532 1533 cursor = avail; 1534 buf_size = new_size; 1535 } 1536 else 1537 { 1538 cursor = avail - start; 1539 1540 FT_MEM_MOVE( buf, buf + start, cursor ); 1541 1542 start = 0; 1543 } 1544 goto Refill; 1545 } 1546 1547 /* NUL-terminate the line. */ 1548 buf[end] = 0; 1549 1550 if ( buf[start] != '#' ) 1551 { 1552 error = (*cb)( buf + start, end - start, lineno, p, (void*)&cb ); 1553 if ( error ) 1554 break; 1555 } 1556 1557 lineno += 1; 1558 start = end + 1; 1559 } 1560 1561 *lno = lineno; 1562 1563 Exit: 1564 FT_FREE( buf ); 1565 return error; 1566 } 1567 1568 1569 /************************************************************************** 1570 * 1571 * API. 1572 * 1573 */ 1574 1575 1576 FT_LOCAL_DEF( FT_Error ) 1577 bdf_load_font( FT_Stream stream, 1578 FT_Memory memory, 1579 unsigned long flags, 1580 bdf_font_t* *font ) 1581 { 1582 unsigned long lineno = 0; /* make compiler happy */ 1583 bdf_parse_t_ *p = NULL; 1584 1585 FT_Error error = FT_Err_Ok; 1586 1587 1588 if ( FT_NEW( p ) ) 1589 goto Exit; 1590 1591 p->flags = flags; /* comments, metrics, unencoded */ 1592 p->minlb = 32767; 1593 p->size = stream->size; 1594 p->memory = memory; /* only during font creation */ 1595 1596 error = bdf_readstream_( stream, p, &lineno ); 1597 if ( error ) 1598 goto Fail; 1599 1600 if ( p->font ) 1601 { 1602 /* If the number of glyphs loaded is not that of the original count, */ 1603 /* indicate the difference. */ 1604 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) 1605 { 1606 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, 1607 p->font->glyphs_used + p->font->unencoded_used )); 1608 } 1609 1610 /* Once the font has been loaded, adjust the overall font metrics if */ 1611 /* necessary. */ 1612 if ( p->flags & BDF_CORRECT_METRICS && 1613 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) 1614 { 1615 if ( p->maxrb - p->minlb != p->font->bbx.width ) 1616 { 1617 FT_TRACE2(( "bdf_load_font: " ACMSG3, 1618 p->font->bbx.width, p->maxrb - p->minlb )); 1619 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); 1620 } 1621 1622 if ( p->font->bbx.x_offset != p->minlb ) 1623 { 1624 FT_TRACE2(( "bdf_load_font: " ACMSG4, 1625 p->font->bbx.x_offset, p->minlb )); 1626 p->font->bbx.x_offset = p->minlb; 1627 } 1628 1629 if ( p->font->bbx.ascent != p->maxas ) 1630 { 1631 FT_TRACE2(( "bdf_load_font: " ACMSG5, 1632 p->font->bbx.ascent, p->maxas )); 1633 p->font->bbx.ascent = p->maxas; 1634 } 1635 1636 if ( p->font->bbx.descent != p->maxds ) 1637 { 1638 FT_TRACE2(( "bdf_load_font: " ACMSG6, 1639 p->font->bbx.descent, p->maxds )); 1640 p->font->bbx.descent = p->maxds; 1641 p->font->bbx.y_offset = (short)( -p->maxds ); 1642 } 1643 1644 if ( p->maxas + p->maxds != p->font->bbx.height ) 1645 { 1646 FT_TRACE2(( "bdf_load_font: " ACMSG7, 1647 p->font->bbx.height, p->maxas + p->maxds )); 1648 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); 1649 } 1650 } 1651 } 1652 1653 if ( p->flags & BDF_START_ ) 1654 { 1655 /* The ENDFONT field was never reached or did not exist. */ 1656 if ( !( p->flags & BDF_GLYPHS_ ) ) 1657 { 1658 /* Error happened while parsing header. */ 1659 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); 1660 error = FT_THROW( Corrupted_Font_Header ); 1661 goto Fail; 1662 } 1663 else 1664 { 1665 /* Error happened when parsing glyphs. */ 1666 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); 1667 error = FT_THROW( Corrupted_Font_Glyphs ); 1668 goto Fail; 1669 } 1670 } 1671 1672 if ( !p->font && !error ) 1673 error = FT_THROW( Invalid_File_Format ); 1674 1675 *font = p->font; 1676 1677 Exit: 1678 if ( p ) 1679 { 1680 FT_FREE( p->glyph_name ); 1681 FT_FREE( p ); 1682 } 1683 1684 return error; 1685 1686 Fail: 1687 bdf_free_font( p->font ); 1688 1689 FT_FREE( p->font ); 1690 1691 goto Exit; 1692 } 1693 1694 1695 FT_LOCAL_DEF( void ) 1696 bdf_free_font( bdf_font_t* font ) 1697 { 1698 bdf_property_t* prop; 1699 unsigned long i; 1700 bdf_glyph_t* glyphs; 1701 FT_Memory memory; 1702 1703 1704 if ( font == NULL ) 1705 return; 1706 1707 memory = font->memory; 1708 1709 FT_FREE( font->name ); 1710 1711 /* Free up the internal hash table of property names. */ 1712 if ( font->internal ) 1713 { 1714 ft_hash_str_free( font->internal, memory ); 1715 FT_FREE( font->internal ); 1716 } 1717 1718 /* Free up the comment info. */ 1719 FT_FREE( font->comments ); 1720 1721 /* Free up the properties. */ 1722 for ( i = 0; i < font->props_size; i++ ) 1723 { 1724 if ( font->props[i].format == BDF_ATOM ) 1725 FT_FREE( font->props[i].value.atom ); 1726 } 1727 1728 FT_FREE( font->props ); 1729 1730 /* Free up the character info. */ 1731 for ( i = 0, glyphs = font->glyphs; 1732 i < font->glyphs_used; i++, glyphs++ ) 1733 { 1734 FT_FREE( glyphs->name ); 1735 FT_FREE( glyphs->bitmap ); 1736 } 1737 1738 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; 1739 i++, glyphs++ ) 1740 { 1741 FT_FREE( glyphs->name ); 1742 FT_FREE( glyphs->bitmap ); 1743 } 1744 1745 FT_FREE( font->glyphs ); 1746 FT_FREE( font->unencoded ); 1747 1748 /* bdf_cleanup */ 1749 ft_hash_str_free( &(font->proptbl), memory ); 1750 1751 /* Free up the user defined properties. */ 1752 for ( prop = font->user_props, i = 0; 1753 i < font->nuser_props; i++, prop++ ) 1754 FT_FREE( prop->name ); 1755 1756 FT_FREE( font->user_props ); 1757 1758 /* FREE( font ); */ /* XXX Fixme */ 1759 } 1760 1761 1762 FT_LOCAL_DEF( bdf_property_t * ) 1763 bdf_get_font_property( bdf_font_t* font, 1764 const char* name ) 1765 { 1766 size_t* propid; 1767 1768 1769 if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 ) 1770 return 0; 1771 1772 propid = ft_hash_str_lookup( name, font->internal ); 1773 1774 return propid ? ( font->props + *propid ) : NULL; 1775 } 1776 1777 1778 /* END */