1 /* pcfread.c 2 3 FreeType font driver for pcf fonts 4 5 Copyright 2000-2010, 2012-2014 by 6 Francesco Zappa Nardelli 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 */ 26 27 28 #include <ft2build.h> 29 30 #include FT_INTERNAL_DEBUG_H 31 #include FT_INTERNAL_STREAM_H 32 #include FT_INTERNAL_OBJECTS_H 33 34 #include "pcf.h" 35 #include "pcfread.h" 36 37 #include "pcferror.h" 38 39 40 /*************************************************************************/ 41 /* */ 42 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 43 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 44 /* messages during execution. */ 45 /* */ 46 #undef FT_COMPONENT 47 #define FT_COMPONENT trace_pcfread 48 49 50 #ifdef FT_DEBUG_LEVEL_TRACE 51 static const char* const tableNames[] = 52 { 53 "prop", "accl", "mtrcs", "bmps", "imtrcs", 54 "enc", "swidth", "names", "accel" 55 }; 56 #endif 57 58 59 static 60 const FT_Frame_Field pcf_toc_header[] = 61 { 62 #undef FT_STRUCTURE 63 #define FT_STRUCTURE PCF_TocRec 64 65 FT_FRAME_START( 8 ), 66 FT_FRAME_ULONG_LE( version ), 67 FT_FRAME_ULONG_LE( count ), 68 FT_FRAME_END 69 }; 70 71 72 static 73 const FT_Frame_Field pcf_table_header[] = 74 { 75 #undef FT_STRUCTURE 76 #define FT_STRUCTURE PCF_TableRec 77 78 FT_FRAME_START( 16 ), 79 FT_FRAME_ULONG_LE( type ), 80 FT_FRAME_ULONG_LE( format ), 81 FT_FRAME_ULONG_LE( size ), /* rounded up to a multiple of 4 */ 82 FT_FRAME_ULONG_LE( offset ), 83 FT_FRAME_END 84 }; 85 86 87 static FT_Error pcf_read_TOC(FT_Stream stream,PCF_Face face)88 pcf_read_TOC( FT_Stream stream, 89 PCF_Face face ) 90 { 91 FT_Error error; 92 PCF_Toc toc = &face->toc; 93 PCF_Table tables; 94 95 FT_Memory memory = FT_FACE( face )->memory; 96 FT_UInt n; 97 98 FT_ULong size; 99 100 101 if ( FT_STREAM_SEEK( 0 ) || 102 FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) ) 103 return FT_THROW( Cannot_Open_Resource ); 104 105 if ( toc->version != PCF_FILE_VERSION || 106 toc->count == 0 ) 107 return FT_THROW( Invalid_File_Format ); 108 109 if ( stream->size < 16 ) 110 return FT_THROW( Invalid_File_Format ); 111 112 /* we need 16 bytes per TOC entry */ 113 if ( toc->count > stream->size >> 4 ) 114 { 115 FT_TRACE0(( "pcf_read_TOC: adjusting number of tables" 116 " (from %d to %d)\n", 117 toc->count, stream->size >> 4 )); 118 toc->count = stream->size >> 4; 119 } 120 121 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) 122 return FT_THROW( Out_Of_Memory ); 123 124 tables = face->toc.tables; 125 for ( n = 0; n < toc->count; n++ ) 126 { 127 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) 128 goto Exit; 129 tables++; 130 } 131 132 /* Sort tables and check for overlaps. Because they are almost */ 133 /* always ordered already, an in-place bubble sort with simultaneous */ 134 /* boundary checking seems appropriate. */ 135 tables = face->toc.tables; 136 137 for ( n = 0; n < toc->count - 1; n++ ) 138 { 139 FT_UInt i, have_change; 140 141 142 have_change = 0; 143 144 for ( i = 0; i < toc->count - 1 - n; i++ ) 145 { 146 PCF_TableRec tmp; 147 148 149 if ( tables[i].offset > tables[i + 1].offset ) 150 { 151 tmp = tables[i]; 152 tables[i] = tables[i + 1]; 153 tables[i + 1] = tmp; 154 155 have_change = 1; 156 } 157 158 if ( ( tables[i].size > tables[i + 1].offset ) || 159 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) 160 { 161 error = FT_THROW( Invalid_Offset ); 162 goto Exit; 163 } 164 } 165 166 if ( !have_change ) 167 break; 168 } 169 170 /* 171 * We now check whether the `size' and `offset' values are reasonable: 172 * `offset' + `size' must not exceed the stream size. 173 * 174 * Note, however, that X11's `pcfWriteFont' routine (used by the 175 * `bdftopcf' program to create PDF font files) has two special 176 * features. 177 * 178 * - It always assigns the accelerator table a size of 100 bytes in the 179 * TOC, regardless of its real size, which can vary between 34 and 72 180 * bytes. 181 * 182 * - Due to the way the routine is designed, it ships out the last font 183 * table with its real size, ignoring the TOC's size value. Since 184 * the TOC size values are always rounded up to a multiple of 4, the 185 * difference can be up to three bytes for all tables except the 186 * accelerator table, for which the difference can be as large as 66 187 * bytes. 188 * 189 */ 190 191 tables = face->toc.tables; 192 size = stream->size; 193 194 for ( n = 0; n < toc->count - 1; n++ ) 195 { 196 /* we need two checks to avoid overflow */ 197 if ( ( tables->size > size ) || 198 ( tables->offset > size - tables->size ) ) 199 { 200 error = FT_THROW( Invalid_Table ); 201 goto Exit; 202 } 203 tables++; 204 } 205 206 /* only check `tables->offset' for last table element ... */ 207 if ( ( tables->offset > size ) ) 208 { 209 error = FT_THROW( Invalid_Table ); 210 goto Exit; 211 } 212 /* ... and adjust `tables->size' to the real value if necessary */ 213 if ( tables->size > size - tables->offset ) 214 tables->size = size - tables->offset; 215 216 #ifdef FT_DEBUG_LEVEL_TRACE 217 218 { 219 FT_UInt i, j; 220 const char* name = "?"; 221 222 223 FT_TRACE4(( "pcf_read_TOC:\n" )); 224 225 FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); 226 227 tables = face->toc.tables; 228 for ( i = 0; i < toc->count; i++ ) 229 { 230 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); 231 j++ ) 232 if ( tables[i].type == (FT_UInt)( 1 << j ) ) 233 name = tableNames[j]; 234 235 FT_TRACE4(( " %d: type=%s, format=0x%X, " 236 "size=%ld (0x%lX), offset=%ld (0x%lX)\n", 237 i, name, 238 tables[i].format, 239 tables[i].size, tables[i].size, 240 tables[i].offset, tables[i].offset )); 241 } 242 } 243 244 #endif 245 246 return FT_Err_Ok; 247 248 Exit: 249 FT_FREE( face->toc.tables ); 250 return error; 251 } 252 253 254 #define PCF_METRIC_SIZE 12 255 256 static 257 const FT_Frame_Field pcf_metric_header[] = 258 { 259 #undef FT_STRUCTURE 260 #define FT_STRUCTURE PCF_MetricRec 261 262 FT_FRAME_START( PCF_METRIC_SIZE ), 263 FT_FRAME_SHORT_LE( leftSideBearing ), 264 FT_FRAME_SHORT_LE( rightSideBearing ), 265 FT_FRAME_SHORT_LE( characterWidth ), 266 FT_FRAME_SHORT_LE( ascent ), 267 FT_FRAME_SHORT_LE( descent ), 268 FT_FRAME_SHORT_LE( attributes ), 269 FT_FRAME_END 270 }; 271 272 273 static 274 const FT_Frame_Field pcf_metric_msb_header[] = 275 { 276 #undef FT_STRUCTURE 277 #define FT_STRUCTURE PCF_MetricRec 278 279 FT_FRAME_START( PCF_METRIC_SIZE ), 280 FT_FRAME_SHORT( leftSideBearing ), 281 FT_FRAME_SHORT( rightSideBearing ), 282 FT_FRAME_SHORT( characterWidth ), 283 FT_FRAME_SHORT( ascent ), 284 FT_FRAME_SHORT( descent ), 285 FT_FRAME_SHORT( attributes ), 286 FT_FRAME_END 287 }; 288 289 290 #define PCF_COMPRESSED_METRIC_SIZE 5 291 292 static 293 const FT_Frame_Field pcf_compressed_metric_header[] = 294 { 295 #undef FT_STRUCTURE 296 #define FT_STRUCTURE PCF_Compressed_MetricRec 297 298 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), 299 FT_FRAME_BYTE( leftSideBearing ), 300 FT_FRAME_BYTE( rightSideBearing ), 301 FT_FRAME_BYTE( characterWidth ), 302 FT_FRAME_BYTE( ascent ), 303 FT_FRAME_BYTE( descent ), 304 FT_FRAME_END 305 }; 306 307 308 static FT_Error pcf_get_metric(FT_Stream stream,FT_ULong format,PCF_Metric metric)309 pcf_get_metric( FT_Stream stream, 310 FT_ULong format, 311 PCF_Metric metric ) 312 { 313 FT_Error error = FT_Err_Ok; 314 315 316 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 317 { 318 const FT_Frame_Field* fields; 319 320 321 /* parsing normal metrics */ 322 fields = PCF_BYTE_ORDER( format ) == MSBFirst 323 ? pcf_metric_msb_header 324 : pcf_metric_header; 325 326 /* the following sets `error' but doesn't return in case of failure */ 327 (void)FT_STREAM_READ_FIELDS( fields, metric ); 328 } 329 else 330 { 331 PCF_Compressed_MetricRec compr; 332 333 334 /* parsing compressed metrics */ 335 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) 336 goto Exit; 337 338 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); 339 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); 340 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); 341 metric->ascent = (FT_Short)( compr.ascent - 0x80 ); 342 metric->descent = (FT_Short)( compr.descent - 0x80 ); 343 metric->attributes = 0; 344 } 345 346 Exit: 347 return error; 348 } 349 350 351 static FT_Error pcf_seek_to_table_type(FT_Stream stream,PCF_Table tables,FT_ULong ntables,FT_ULong type,FT_ULong * aformat,FT_ULong * asize)352 pcf_seek_to_table_type( FT_Stream stream, 353 PCF_Table tables, 354 FT_ULong ntables, /* same as PCF_Toc->count */ 355 FT_ULong type, 356 FT_ULong *aformat, 357 FT_ULong *asize ) 358 { 359 FT_Error error = FT_ERR( Invalid_File_Format ); 360 FT_ULong i; 361 362 363 for ( i = 0; i < ntables; i++ ) 364 if ( tables[i].type == type ) 365 { 366 if ( stream->pos > tables[i].offset ) 367 { 368 error = FT_THROW( Invalid_Stream_Skip ); 369 goto Fail; 370 } 371 372 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) 373 { 374 error = FT_THROW( Invalid_Stream_Skip ); 375 goto Fail; 376 } 377 378 *asize = tables[i].size; 379 *aformat = tables[i].format; 380 381 return FT_Err_Ok; 382 } 383 384 Fail: 385 *asize = 0; 386 return error; 387 } 388 389 390 static FT_Bool pcf_has_table_type(PCF_Table tables,FT_ULong ntables,FT_ULong type)391 pcf_has_table_type( PCF_Table tables, 392 FT_ULong ntables, /* same as PCF_Toc->count */ 393 FT_ULong type ) 394 { 395 FT_ULong i; 396 397 398 for ( i = 0; i < ntables; i++ ) 399 if ( tables[i].type == type ) 400 return TRUE; 401 402 return FALSE; 403 } 404 405 406 #define PCF_PROPERTY_SIZE 9 407 408 static 409 const FT_Frame_Field pcf_property_header[] = 410 { 411 #undef FT_STRUCTURE 412 #define FT_STRUCTURE PCF_ParsePropertyRec 413 414 FT_FRAME_START( PCF_PROPERTY_SIZE ), 415 FT_FRAME_LONG_LE( name ), 416 FT_FRAME_BYTE ( isString ), 417 FT_FRAME_LONG_LE( value ), 418 FT_FRAME_END 419 }; 420 421 422 static 423 const FT_Frame_Field pcf_property_msb_header[] = 424 { 425 #undef FT_STRUCTURE 426 #define FT_STRUCTURE PCF_ParsePropertyRec 427 428 FT_FRAME_START( PCF_PROPERTY_SIZE ), 429 FT_FRAME_LONG( name ), 430 FT_FRAME_BYTE( isString ), 431 FT_FRAME_LONG( value ), 432 FT_FRAME_END 433 }; 434 435 436 FT_LOCAL_DEF( PCF_Property ) pcf_find_property(PCF_Face face,const FT_String * prop)437 pcf_find_property( PCF_Face face, 438 const FT_String* prop ) 439 { 440 PCF_Property properties = face->properties; 441 FT_Bool found = 0; 442 int i; 443 444 445 for ( i = 0 ; i < face->nprops && !found; i++ ) 446 { 447 if ( !ft_strcmp( properties[i].name, prop ) ) 448 found = 1; 449 } 450 451 if ( found ) 452 return properties + i - 1; 453 else 454 return NULL; 455 } 456 457 458 static FT_Error pcf_get_properties(FT_Stream stream,PCF_Face face)459 pcf_get_properties( FT_Stream stream, 460 PCF_Face face ) 461 { 462 PCF_ParseProperty props = NULL; 463 PCF_Property properties = NULL; 464 FT_ULong nprops, i; 465 FT_ULong format, size; 466 FT_Error error; 467 FT_Memory memory = FT_FACE( face )->memory; 468 FT_ULong string_size; 469 FT_String* strings = NULL; 470 471 472 error = pcf_seek_to_table_type( stream, 473 face->toc.tables, 474 face->toc.count, 475 PCF_PROPERTIES, 476 &format, 477 &size ); 478 if ( error ) 479 goto Bail; 480 481 if ( FT_READ_ULONG_LE( format ) ) 482 goto Bail; 483 484 FT_TRACE4(( "pcf_get_properties:\n" )); 485 486 FT_TRACE4(( " format = %ld\n", format )); 487 488 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 489 goto Bail; 490 491 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 492 (void)FT_READ_ULONG( nprops ); 493 else 494 (void)FT_READ_ULONG_LE( nprops ); 495 if ( error ) 496 goto Bail; 497 498 FT_TRACE4(( " nprop = %d (truncate %d props)\n", 499 (int)nprops, nprops - (FT_ULong)(int)nprops )); 500 501 nprops = (FT_ULong)(int)nprops; 502 503 /* rough estimate */ 504 if ( nprops > size / PCF_PROPERTY_SIZE ) 505 { 506 error = FT_THROW( Invalid_Table ); 507 goto Bail; 508 } 509 510 face->nprops = (int)nprops; 511 512 if ( FT_NEW_ARRAY( props, nprops ) ) 513 goto Bail; 514 515 for ( i = 0; i < nprops; i++ ) 516 { 517 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 518 { 519 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) 520 goto Bail; 521 } 522 else 523 { 524 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) 525 goto Bail; 526 } 527 } 528 529 /* pad the property array */ 530 /* */ 531 /* clever here - nprops is the same as the number of odd-units read, */ 532 /* as only isStringProp are odd length (Keith Packard) */ 533 /* */ 534 if ( nprops & 3 ) 535 { 536 i = 4 - ( nprops & 3 ); 537 if ( FT_STREAM_SKIP( i ) ) 538 { 539 error = FT_THROW( Invalid_Stream_Skip ); 540 goto Bail; 541 } 542 } 543 544 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 545 (void)FT_READ_ULONG( string_size ); 546 else 547 (void)FT_READ_ULONG_LE( string_size ); 548 if ( error ) 549 goto Bail; 550 551 FT_TRACE4(( " string_size = %ld\n", string_size )); 552 553 /* rough estimate */ 554 if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) 555 { 556 error = FT_THROW( Invalid_Table ); 557 goto Bail; 558 } 559 560 /* allocate one more byte so that we have a final null byte */ 561 if ( FT_NEW_ARRAY( strings, string_size + 1 ) ) 562 goto Bail; 563 564 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); 565 if ( error ) 566 goto Bail; 567 568 if ( FT_NEW_ARRAY( properties, nprops ) ) 569 goto Bail; 570 571 face->properties = properties; 572 573 for ( i = 0; i < nprops; i++ ) 574 { 575 FT_Long name_offset = props[i].name; 576 577 578 if ( ( name_offset < 0 ) || 579 ( (FT_ULong)name_offset > string_size ) ) 580 { 581 error = FT_THROW( Invalid_Offset ); 582 goto Bail; 583 } 584 585 if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) 586 goto Bail; 587 588 FT_TRACE4(( " %s:", properties[i].name )); 589 590 properties[i].isString = props[i].isString; 591 592 if ( props[i].isString ) 593 { 594 FT_Long value_offset = props[i].value; 595 596 597 if ( ( value_offset < 0 ) || 598 ( (FT_ULong)value_offset > string_size ) ) 599 { 600 error = FT_THROW( Invalid_Offset ); 601 goto Bail; 602 } 603 604 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) 605 goto Bail; 606 607 FT_TRACE4(( " `%s'\n", properties[i].value.atom )); 608 } 609 else 610 { 611 properties[i].value.l = props[i].value; 612 613 FT_TRACE4(( " %d\n", properties[i].value.l )); 614 } 615 } 616 617 error = FT_Err_Ok; 618 619 Bail: 620 FT_FREE( props ); 621 FT_FREE( strings ); 622 623 return error; 624 } 625 626 627 static FT_Error pcf_get_metrics(FT_Stream stream,PCF_Face face)628 pcf_get_metrics( FT_Stream stream, 629 PCF_Face face ) 630 { 631 FT_Error error; 632 FT_Memory memory = FT_FACE( face )->memory; 633 FT_ULong format, size; 634 PCF_Metric metrics = NULL; 635 FT_ULong nmetrics, i; 636 637 638 error = pcf_seek_to_table_type( stream, 639 face->toc.tables, 640 face->toc.count, 641 PCF_METRICS, 642 &format, 643 &size ); 644 if ( error ) 645 return error; 646 647 if ( FT_READ_ULONG_LE( format ) ) 648 goto Bail; 649 650 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 651 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) 652 return FT_THROW( Invalid_File_Format ); 653 654 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 655 { 656 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 657 (void)FT_READ_ULONG( nmetrics ); 658 else 659 (void)FT_READ_ULONG_LE( nmetrics ); 660 } 661 else 662 { 663 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 664 (void)FT_READ_USHORT( nmetrics ); 665 else 666 (void)FT_READ_USHORT_LE( nmetrics ); 667 } 668 if ( error ) 669 return FT_THROW( Invalid_File_Format ); 670 671 face->nmetrics = nmetrics; 672 673 if ( !nmetrics ) 674 return FT_THROW( Invalid_Table ); 675 676 FT_TRACE4(( "pcf_get_metrics:\n" )); 677 678 FT_TRACE4(( " number of metrics: %d\n", nmetrics )); 679 680 /* rough estimate */ 681 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 682 { 683 if ( nmetrics > size / PCF_METRIC_SIZE ) 684 return FT_THROW( Invalid_Table ); 685 } 686 else 687 { 688 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) 689 return FT_THROW( Invalid_Table ); 690 } 691 692 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) 693 return FT_THROW( Out_Of_Memory ); 694 695 metrics = face->metrics; 696 for ( i = 0; i < nmetrics; i++, metrics++ ) 697 { 698 error = pcf_get_metric( stream, format, metrics ); 699 700 metrics->bits = 0; 701 702 FT_TRACE5(( " idx %d: width=%d, " 703 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", 704 i, 705 metrics->characterWidth, 706 metrics->leftSideBearing, 707 metrics->rightSideBearing, 708 metrics->ascent, 709 metrics->descent, 710 metrics->attributes )); 711 712 if ( error ) 713 break; 714 715 /* sanity checks -- those values are used in `PCF_Glyph_Load' to */ 716 /* compute a glyph's bitmap dimensions, thus setting them to zero in */ 717 /* case of an error disables this particular glyph only */ 718 if ( metrics->rightSideBearing < metrics->leftSideBearing || 719 metrics->ascent + metrics->descent < 0 ) 720 { 721 metrics->characterWidth = 0; 722 metrics->leftSideBearing = 0; 723 metrics->rightSideBearing = 0; 724 metrics->ascent = 0; 725 metrics->descent = 0; 726 727 FT_TRACE0(( "pcf_get_metrics:" 728 " invalid metrics for glyph %d\n", i )); 729 } 730 } 731 732 if ( error ) 733 FT_FREE( face->metrics ); 734 735 Bail: 736 return error; 737 } 738 739 740 static FT_Error pcf_get_bitmaps(FT_Stream stream,PCF_Face face)741 pcf_get_bitmaps( FT_Stream stream, 742 PCF_Face face ) 743 { 744 FT_Error error; 745 FT_Memory memory = FT_FACE( face )->memory; 746 FT_Long* offsets = NULL; 747 FT_Long bitmapSizes[GLYPHPADOPTIONS]; 748 FT_ULong format, size; 749 FT_ULong nbitmaps, i, sizebitmaps = 0; 750 751 752 error = pcf_seek_to_table_type( stream, 753 face->toc.tables, 754 face->toc.count, 755 PCF_BITMAPS, 756 &format, 757 &size ); 758 if ( error ) 759 return error; 760 761 error = FT_Stream_EnterFrame( stream, 8 ); 762 if ( error ) 763 return error; 764 765 format = FT_GET_ULONG_LE(); 766 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 767 nbitmaps = FT_GET_ULONG(); 768 else 769 nbitmaps = FT_GET_ULONG_LE(); 770 771 FT_Stream_ExitFrame( stream ); 772 773 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 774 return FT_THROW( Invalid_File_Format ); 775 776 FT_TRACE4(( "pcf_get_bitmaps:\n" )); 777 778 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); 779 780 if ( nbitmaps != face->nmetrics ) 781 return FT_THROW( Invalid_File_Format ); 782 783 if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) 784 return error; 785 786 for ( i = 0; i < nbitmaps; i++ ) 787 { 788 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 789 (void)FT_READ_LONG( offsets[i] ); 790 else 791 (void)FT_READ_LONG_LE( offsets[i] ); 792 793 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n", 794 i, offsets[i], offsets[i] )); 795 } 796 if ( error ) 797 goto Bail; 798 799 for ( i = 0; i < GLYPHPADOPTIONS; i++ ) 800 { 801 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 802 (void)FT_READ_LONG( bitmapSizes[i] ); 803 else 804 (void)FT_READ_LONG_LE( bitmapSizes[i] ); 805 if ( error ) 806 goto Bail; 807 808 sizebitmaps = (FT_ULong)bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; 809 810 FT_TRACE4(( " padding %d implies a size of %ld\n", 811 i, bitmapSizes[i] )); 812 } 813 814 FT_TRACE4(( " %d bitmaps, padding index %ld\n", 815 nbitmaps, 816 PCF_GLYPH_PAD_INDEX( format ) )); 817 FT_TRACE4(( " bitmap size = %d\n", sizebitmaps )); 818 819 FT_UNUSED( sizebitmaps ); /* only used for debugging */ 820 821 for ( i = 0; i < nbitmaps; i++ ) 822 { 823 /* rough estimate */ 824 if ( ( offsets[i] < 0 ) || 825 ( (FT_ULong)offsets[i] > size ) ) 826 { 827 FT_TRACE0(( "pcf_get_bitmaps:" 828 " invalid offset to bitmap data of glyph %d\n", i )); 829 } 830 else 831 face->metrics[i].bits = stream->pos + (FT_ULong)offsets[i]; 832 } 833 834 face->bitmapsFormat = format; 835 836 Bail: 837 FT_FREE( offsets ); 838 return error; 839 } 840 841 842 static FT_Error pcf_get_encodings(FT_Stream stream,PCF_Face face)843 pcf_get_encodings( FT_Stream stream, 844 PCF_Face face ) 845 { 846 FT_Error error; 847 FT_Memory memory = FT_FACE( face )->memory; 848 FT_ULong format, size; 849 int firstCol, lastCol; 850 int firstRow, lastRow; 851 FT_ULong nencoding; 852 int encodingOffset; 853 int i, j; 854 FT_ULong k; 855 PCF_Encoding encoding = NULL; 856 857 858 error = pcf_seek_to_table_type( stream, 859 face->toc.tables, 860 face->toc.count, 861 PCF_BDF_ENCODINGS, 862 &format, 863 &size ); 864 if ( error ) 865 return error; 866 867 error = FT_Stream_EnterFrame( stream, 14 ); 868 if ( error ) 869 return error; 870 871 format = FT_GET_ULONG_LE(); 872 873 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 874 { 875 firstCol = FT_GET_SHORT(); 876 lastCol = FT_GET_SHORT(); 877 firstRow = FT_GET_SHORT(); 878 lastRow = FT_GET_SHORT(); 879 face->defaultChar = FT_GET_SHORT(); 880 } 881 else 882 { 883 firstCol = FT_GET_SHORT_LE(); 884 lastCol = FT_GET_SHORT_LE(); 885 firstRow = FT_GET_SHORT_LE(); 886 lastRow = FT_GET_SHORT_LE(); 887 face->defaultChar = FT_GET_SHORT_LE(); 888 } 889 890 FT_Stream_ExitFrame( stream ); 891 892 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 893 return FT_THROW( Invalid_File_Format ); 894 895 /* sanity checks */ 896 if ( firstCol < 0 || 897 firstCol > lastCol || 898 lastCol > 0xFF || 899 firstRow < 0 || 900 firstRow > lastRow || 901 lastRow > 0xFF ) 902 return FT_THROW( Invalid_Table ); 903 904 FT_TRACE4(( "pdf_get_encodings:\n" )); 905 906 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", 907 firstCol, lastCol, firstRow, lastRow )); 908 909 nencoding = (FT_ULong)( lastCol - firstCol + 1 ) * 910 (FT_ULong)( lastRow - firstRow + 1 ); 911 912 if ( FT_NEW_ARRAY( encoding, nencoding ) ) 913 return FT_THROW( Out_Of_Memory ); 914 915 error = FT_Stream_EnterFrame( stream, 2 * nencoding ); 916 if ( error ) 917 goto Bail; 918 919 k = 0; 920 for ( i = firstRow; i <= lastRow; i++ ) 921 { 922 for ( j = firstCol; j <= lastCol; j++ ) 923 { 924 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 925 encodingOffset = FT_GET_SHORT(); 926 else 927 encodingOffset = FT_GET_SHORT_LE(); 928 929 if ( encodingOffset > -1 ) 930 { 931 encoding[k].enc = i * 256 + j; 932 encoding[k].glyph = (FT_UShort)encodingOffset; 933 934 FT_TRACE5(( " code %d (0x%04X): idx %d\n", 935 encoding[k].enc, encoding[k].enc, encoding[k].glyph )); 936 937 k++; 938 } 939 } 940 } 941 FT_Stream_ExitFrame( stream ); 942 943 if ( FT_RENEW_ARRAY( encoding, nencoding, k ) ) 944 goto Bail; 945 946 face->nencodings = k; 947 face->encodings = encoding; 948 949 return error; 950 951 Bail: 952 FT_FREE( encoding ); 953 return error; 954 } 955 956 957 static 958 const FT_Frame_Field pcf_accel_header[] = 959 { 960 #undef FT_STRUCTURE 961 #define FT_STRUCTURE PCF_AccelRec 962 963 FT_FRAME_START( 20 ), 964 FT_FRAME_BYTE ( noOverlap ), 965 FT_FRAME_BYTE ( constantMetrics ), 966 FT_FRAME_BYTE ( terminalFont ), 967 FT_FRAME_BYTE ( constantWidth ), 968 FT_FRAME_BYTE ( inkInside ), 969 FT_FRAME_BYTE ( inkMetrics ), 970 FT_FRAME_BYTE ( drawDirection ), 971 FT_FRAME_SKIP_BYTES( 1 ), 972 FT_FRAME_LONG_LE ( fontAscent ), 973 FT_FRAME_LONG_LE ( fontDescent ), 974 FT_FRAME_LONG_LE ( maxOverlap ), 975 FT_FRAME_END 976 }; 977 978 979 static 980 const FT_Frame_Field pcf_accel_msb_header[] = 981 { 982 #undef FT_STRUCTURE 983 #define FT_STRUCTURE PCF_AccelRec 984 985 FT_FRAME_START( 20 ), 986 FT_FRAME_BYTE ( noOverlap ), 987 FT_FRAME_BYTE ( constantMetrics ), 988 FT_FRAME_BYTE ( terminalFont ), 989 FT_FRAME_BYTE ( constantWidth ), 990 FT_FRAME_BYTE ( inkInside ), 991 FT_FRAME_BYTE ( inkMetrics ), 992 FT_FRAME_BYTE ( drawDirection ), 993 FT_FRAME_SKIP_BYTES( 1 ), 994 FT_FRAME_LONG ( fontAscent ), 995 FT_FRAME_LONG ( fontDescent ), 996 FT_FRAME_LONG ( maxOverlap ), 997 FT_FRAME_END 998 }; 999 1000 1001 static FT_Error pcf_get_accel(FT_Stream stream,PCF_Face face,FT_ULong type)1002 pcf_get_accel( FT_Stream stream, 1003 PCF_Face face, 1004 FT_ULong type ) 1005 { 1006 FT_ULong format, size; 1007 FT_Error error; 1008 PCF_Accel accel = &face->accel; 1009 1010 1011 error = pcf_seek_to_table_type( stream, 1012 face->toc.tables, 1013 face->toc.count, 1014 type, 1015 &format, 1016 &size ); 1017 if ( error ) 1018 goto Bail; 1019 1020 if ( FT_READ_ULONG_LE( format ) ) 1021 goto Bail; 1022 1023 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 1024 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 1025 goto Bail; 1026 1027 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 1028 { 1029 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) 1030 goto Bail; 1031 } 1032 else 1033 { 1034 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) 1035 goto Bail; 1036 } 1037 1038 error = pcf_get_metric( stream, 1039 format & ( ~PCF_FORMAT_MASK ), 1040 &(accel->minbounds) ); 1041 if ( error ) 1042 goto Bail; 1043 1044 error = pcf_get_metric( stream, 1045 format & ( ~PCF_FORMAT_MASK ), 1046 &(accel->maxbounds) ); 1047 if ( error ) 1048 goto Bail; 1049 1050 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 1051 { 1052 error = pcf_get_metric( stream, 1053 format & ( ~PCF_FORMAT_MASK ), 1054 &(accel->ink_minbounds) ); 1055 if ( error ) 1056 goto Bail; 1057 1058 error = pcf_get_metric( stream, 1059 format & ( ~PCF_FORMAT_MASK ), 1060 &(accel->ink_maxbounds) ); 1061 if ( error ) 1062 goto Bail; 1063 } 1064 else 1065 { 1066 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */ 1067 accel->ink_maxbounds = accel->maxbounds; 1068 } 1069 1070 Bail: 1071 return error; 1072 } 1073 1074 1075 static FT_Error pcf_interpret_style(PCF_Face pcf)1076 pcf_interpret_style( PCF_Face pcf ) 1077 { 1078 FT_Error error = FT_Err_Ok; 1079 FT_Face face = FT_FACE( pcf ); 1080 FT_Memory memory = face->memory; 1081 1082 PCF_Property prop; 1083 1084 size_t nn, len; 1085 char* strings[4] = { NULL, NULL, NULL, NULL }; 1086 size_t lengths[4]; 1087 1088 1089 face->style_flags = 0; 1090 1091 prop = pcf_find_property( pcf, "SLANT" ); 1092 if ( prop && prop->isString && 1093 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || 1094 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) 1095 { 1096 face->style_flags |= FT_STYLE_FLAG_ITALIC; 1097 strings[2] = ( *(prop->value.atom) == 'O' || 1098 *(prop->value.atom) == 'o' ) ? (char *)"Oblique" 1099 : (char *)"Italic"; 1100 } 1101 1102 prop = pcf_find_property( pcf, "WEIGHT_NAME" ); 1103 if ( prop && prop->isString && 1104 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) 1105 { 1106 face->style_flags |= FT_STYLE_FLAG_BOLD; 1107 strings[1] = (char*)"Bold"; 1108 } 1109 1110 prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); 1111 if ( prop && prop->isString && 1112 *(prop->value.atom) && 1113 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 1114 strings[3] = (char*)( prop->value.atom ); 1115 1116 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); 1117 if ( prop && prop->isString && 1118 *(prop->value.atom) && 1119 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 1120 strings[0] = (char*)( prop->value.atom ); 1121 1122 for ( len = 0, nn = 0; nn < 4; nn++ ) 1123 { 1124 lengths[nn] = 0; 1125 if ( strings[nn] ) 1126 { 1127 lengths[nn] = ft_strlen( strings[nn] ); 1128 len += lengths[nn] + 1; 1129 } 1130 } 1131 1132 if ( len == 0 ) 1133 { 1134 strings[0] = (char*)"Regular"; 1135 lengths[0] = ft_strlen( strings[0] ); 1136 len = lengths[0] + 1; 1137 } 1138 1139 { 1140 char* s; 1141 1142 1143 if ( FT_ALLOC( face->style_name, len ) ) 1144 return error; 1145 1146 s = face->style_name; 1147 1148 for ( nn = 0; nn < 4; nn++ ) 1149 { 1150 char* src = strings[nn]; 1151 1152 1153 len = lengths[nn]; 1154 1155 if ( src == NULL ) 1156 continue; 1157 1158 /* separate elements with a space */ 1159 if ( s != face->style_name ) 1160 *s++ = ' '; 1161 1162 ft_memcpy( s, src, len ); 1163 1164 /* need to convert spaces to dashes for */ 1165 /* add_style_name and setwidth_name */ 1166 if ( nn == 0 || nn == 3 ) 1167 { 1168 size_t mm; 1169 1170 1171 for ( mm = 0; mm < len; mm++ ) 1172 if ( s[mm] == ' ' ) 1173 s[mm] = '-'; 1174 } 1175 1176 s += len; 1177 } 1178 *s = 0; 1179 } 1180 1181 return error; 1182 } 1183 1184 1185 FT_LOCAL_DEF( FT_Error ) pcf_load_font(FT_Stream stream,PCF_Face face,FT_Long face_index)1186 pcf_load_font( FT_Stream stream, 1187 PCF_Face face, 1188 FT_Long face_index ) 1189 { 1190 FT_Face root = FT_FACE( face ); 1191 FT_Error error; 1192 FT_Memory memory = FT_FACE( face )->memory; 1193 FT_Bool hasBDFAccelerators; 1194 1195 1196 error = pcf_read_TOC( stream, face ); 1197 if ( error ) 1198 goto Exit; 1199 1200 root->num_faces = 1; 1201 root->face_index = 0; 1202 1203 /* If we are performing a simple font format check, exit immediately. */ 1204 if ( face_index < 0 ) 1205 return FT_Err_Ok; 1206 1207 error = pcf_get_properties( stream, face ); 1208 if ( error ) 1209 goto Exit; 1210 1211 /* Use the old accelerators if no BDF accelerators are in the file. */ 1212 hasBDFAccelerators = pcf_has_table_type( face->toc.tables, 1213 face->toc.count, 1214 PCF_BDF_ACCELERATORS ); 1215 if ( !hasBDFAccelerators ) 1216 { 1217 error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); 1218 if ( error ) 1219 goto Exit; 1220 } 1221 1222 /* metrics */ 1223 error = pcf_get_metrics( stream, face ); 1224 if ( error ) 1225 goto Exit; 1226 1227 /* bitmaps */ 1228 error = pcf_get_bitmaps( stream, face ); 1229 if ( error ) 1230 goto Exit; 1231 1232 /* encodings */ 1233 error = pcf_get_encodings( stream, face ); 1234 if ( error ) 1235 goto Exit; 1236 1237 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ 1238 if ( hasBDFAccelerators ) 1239 { 1240 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); 1241 if ( error ) 1242 goto Exit; 1243 } 1244 1245 /* XXX: TO DO: inkmetrics and glyph_names are missing */ 1246 1247 /* now construct the face object */ 1248 { 1249 PCF_Property prop; 1250 1251 1252 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | 1253 FT_FACE_FLAG_HORIZONTAL | 1254 FT_FACE_FLAG_FAST_GLYPHS; 1255 1256 if ( face->accel.constantWidth ) 1257 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 1258 1259 if ( ( error = pcf_interpret_style( face ) ) != 0 ) 1260 goto Exit; 1261 1262 prop = pcf_find_property( face, "FAMILY_NAME" ); 1263 if ( prop && prop->isString ) 1264 { 1265 if ( FT_STRDUP( root->family_name, prop->value.atom ) ) 1266 goto Exit; 1267 } 1268 else 1269 root->family_name = NULL; 1270 1271 /* 1272 * Note: We shift all glyph indices by +1 since we must 1273 * respect the convention that glyph 0 always corresponds 1274 * to the `missing glyph'. 1275 * 1276 * This implies bumping the number of `available' glyphs by 1. 1277 */ 1278 root->num_glyphs = (FT_Long)( face->nmetrics + 1 ); 1279 1280 root->num_fixed_sizes = 1; 1281 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) 1282 goto Exit; 1283 1284 { 1285 FT_Bitmap_Size* bsize = root->available_sizes; 1286 FT_Short resolution_x = 0, resolution_y = 0; 1287 1288 1289 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); 1290 1291 /* for simplicity, we take absolute values of integer properties */ 1292 1293 #if 0 1294 bsize->height = face->accel.maxbounds.ascent << 6; 1295 #endif 1296 1297 #ifdef FT_DEBUG_LEVEL_TRACE 1298 if ( face->accel.fontAscent + face->accel.fontDescent < 0 ) 1299 FT_TRACE0(( "pcf_load_font: negative height\n" )); 1300 #endif 1301 bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent + 1302 face->accel.fontDescent ) ); 1303 1304 prop = pcf_find_property( face, "AVERAGE_WIDTH" ); 1305 if ( prop ) 1306 { 1307 #ifdef FT_DEBUG_LEVEL_TRACE 1308 if ( prop->value.l < 0 ) 1309 FT_TRACE0(( "pcf_load_font: negative average width\n" )); 1310 #endif 1311 bsize->width = FT_ABS( (FT_Short)( ( prop->value.l ) + 5 ) / 10 ); 1312 } 1313 else 1314 bsize->width = (FT_Short)FT_MulDiv( bsize->height, 2, 3 ); 1315 1316 prop = pcf_find_property( face, "POINT_SIZE" ); 1317 if ( prop ) 1318 { 1319 #ifdef FT_DEBUG_LEVEL_TRACE 1320 if ( prop->value.l < 0 ) 1321 FT_TRACE0(( "pcf_load_font: negative point size\n" )); 1322 #endif 1323 /* convert from 722.7 decipoints to 72 points per inch */ 1324 bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), 1325 64 * 7200, 1326 72270L ); 1327 } 1328 1329 prop = pcf_find_property( face, "PIXEL_SIZE" ); 1330 if ( prop ) 1331 { 1332 #ifdef FT_DEBUG_LEVEL_TRACE 1333 if ( prop->value.l < 0 ) 1334 FT_TRACE0(( "pcf_load_font: negative pixel size\n" )); 1335 #endif 1336 bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; 1337 } 1338 1339 prop = pcf_find_property( face, "RESOLUTION_X" ); 1340 if ( prop ) 1341 { 1342 #ifdef FT_DEBUG_LEVEL_TRACE 1343 if ( prop->value.l < 0 ) 1344 FT_TRACE0(( "pcf_load_font: negative X resolution\n" )); 1345 #endif 1346 resolution_x = FT_ABS( (FT_Short)prop->value.l ); 1347 } 1348 1349 prop = pcf_find_property( face, "RESOLUTION_Y" ); 1350 if ( prop ) 1351 { 1352 #ifdef FT_DEBUG_LEVEL_TRACE 1353 if ( prop->value.l < 0 ) 1354 FT_TRACE0(( "pcf_load_font: negative Y resolution\n" )); 1355 #endif 1356 resolution_y = FT_ABS( (FT_Short)prop->value.l ); 1357 } 1358 1359 if ( bsize->y_ppem == 0 ) 1360 { 1361 bsize->y_ppem = bsize->size; 1362 if ( resolution_y ) 1363 bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); 1364 } 1365 if ( resolution_x && resolution_y ) 1366 bsize->x_ppem = FT_MulDiv( bsize->y_ppem, 1367 resolution_x, 1368 resolution_y ); 1369 else 1370 bsize->x_ppem = bsize->y_ppem; 1371 } 1372 1373 /* set up charset */ 1374 { 1375 PCF_Property charset_registry, charset_encoding; 1376 1377 1378 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); 1379 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); 1380 1381 if ( charset_registry && charset_registry->isString && 1382 charset_encoding && charset_encoding->isString ) 1383 { 1384 if ( FT_STRDUP( face->charset_encoding, 1385 charset_encoding->value.atom ) || 1386 FT_STRDUP( face->charset_registry, 1387 charset_registry->value.atom ) ) 1388 goto Exit; 1389 } 1390 } 1391 } 1392 1393 Exit: 1394 if ( error ) 1395 { 1396 /* This is done to respect the behaviour of the original */ 1397 /* PCF font driver. */ 1398 error = FT_THROW( Invalid_File_Format ); 1399 } 1400 1401 return error; 1402 } 1403 1404 1405 /* END */ 1406