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