1 /***************************************************************************/ 2 /* */ 3 /* psobjs.c */ 4 /* */ 5 /* Auxiliary functions for PostScript fonts (body). */ 6 /* */ 7 /* Copyright 1996-2001, 2002 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9 /* */ 10 /* This file is part of the FreeType project, and may only be used, */ 11 /* modified, and distributed under the terms of the FreeType project */ 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13 /* this file you indicate that you have read the license and */ 14 /* understand and accept it fully. */ 15 /* */ 16 /***************************************************************************/ 17 18 19 #include <ft2build.h> 20 #include FT_INTERNAL_POSTSCRIPT_AUX_H 21 #include FT_INTERNAL_DEBUG_H 22 23 #include "psobjs.h" 24 25 #include "psauxerr.h" 26 27 28 /*************************************************************************/ 29 /*************************************************************************/ 30 /***** *****/ 31 /***** PS_TABLE *****/ 32 /***** *****/ 33 /*************************************************************************/ 34 /*************************************************************************/ 35 36 /*************************************************************************/ 37 /* */ 38 /* <Function> */ 39 /* ps_table_new */ 40 /* */ 41 /* <Description> */ 42 /* Initializes a PS_Table. */ 43 /* */ 44 /* <InOut> */ 45 /* table :: The address of the target table. */ 46 /* */ 47 /* <Input> */ 48 /* count :: The table size = the maximum number of elements. */ 49 /* */ 50 /* memory :: The memory object to use for all subsequent */ 51 /* reallocations. */ 52 /* */ 53 /* <Return> */ 54 /* FreeType error code. 0 means success. */ 55 /* */ 56 FT_LOCAL_DEF( FT_Error ) ps_table_new(PS_Table table,FT_Int count,FT_Memory memory)57 ps_table_new( PS_Table table, 58 FT_Int count, 59 FT_Memory memory ) 60 { 61 FT_Error error; 62 63 64 table->memory = memory; 65 if ( FT_NEW_ARRAY( table->elements, count ) || 66 FT_NEW_ARRAY( table->lengths, count ) ) 67 goto Exit; 68 69 table->max_elems = count; 70 table->init = 0xDEADBEEFUL; 71 table->num_elems = 0; 72 table->block = 0; 73 table->capacity = 0; 74 table->cursor = 0; 75 76 *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; 77 78 Exit: 79 if ( error ) 80 FT_FREE( table->elements ); 81 82 return error; 83 } 84 85 86 static void shift_elements(PS_Table table,FT_Byte * old_base)87 shift_elements( PS_Table table, 88 FT_Byte* old_base ) 89 { 90 FT_Long delta = (FT_Long)( table->block - old_base ); 91 FT_Byte** offset = table->elements; 92 FT_Byte** limit = offset + table->max_elems; 93 94 95 for ( ; offset < limit; offset++ ) 96 { 97 if ( offset[0] ) 98 offset[0] += delta; 99 } 100 } 101 102 103 static FT_Error reallocate_t1_table(PS_Table table,FT_Long new_size)104 reallocate_t1_table( PS_Table table, 105 FT_Long new_size ) 106 { 107 FT_Memory memory = table->memory; 108 FT_Byte* old_base = table->block; 109 FT_Error error; 110 111 112 /* allocate new base block */ 113 if ( FT_ALLOC( table->block, new_size ) ) 114 return error; 115 116 /* copy elements and shift offsets */ 117 if (old_base ) 118 { 119 FT_MEM_COPY( table->block, old_base, table->capacity ); 120 shift_elements( table, old_base ); 121 FT_FREE( old_base ); 122 } 123 124 table->capacity = new_size; 125 126 return PSaux_Err_Ok; 127 } 128 129 130 /*************************************************************************/ 131 /* */ 132 /* <Function> */ 133 /* ps_table_add */ 134 /* */ 135 /* <Description> */ 136 /* Adds an object to a PS_Table, possibly growing its memory block. */ 137 /* */ 138 /* <InOut> */ 139 /* table :: The target table. */ 140 /* */ 141 /* <Input> */ 142 /* idx :: The index of the object in the table. */ 143 /* */ 144 /* object :: The address of the object to copy in memory. */ 145 /* */ 146 /* length :: The length in bytes of the source object. */ 147 /* */ 148 /* <Return> */ 149 /* FreeType error code. 0 means success. An error is returned if a */ 150 /* reallocation fails. */ 151 /* */ 152 FT_LOCAL_DEF( FT_Error ) ps_table_add(PS_Table table,FT_Int idx,void * object,FT_Int length)153 ps_table_add( PS_Table table, 154 FT_Int idx, 155 void* object, 156 FT_Int length ) 157 { 158 if ( idx < 0 || idx > table->max_elems ) 159 { 160 FT_ERROR(( "ps_table_add: invalid index\n" )); 161 return PSaux_Err_Invalid_Argument; 162 } 163 164 /* grow the base block if needed */ 165 if ( table->cursor + length > table->capacity ) 166 { 167 FT_Error error; 168 FT_Offset new_size = table->capacity; 169 FT_Long in_offset; 170 171 172 in_offset = (FT_Long)((FT_Byte*)object - table->block); 173 if ( (FT_ULong)in_offset >= table->capacity ) 174 in_offset = -1; 175 176 while ( new_size < table->cursor + length ) 177 { 178 /* increase size by 25% and round up to the nearest multiple of 1024 */ 179 new_size += (new_size >> 2) + 1; 180 new_size = ( new_size + 1023 ) & -1024; 181 } 182 183 error = reallocate_t1_table( table, new_size ); 184 if ( error ) 185 return error; 186 187 if ( in_offset >= 0 ) 188 object = table->block + in_offset; 189 } 190 191 /* add the object to the base block and adjust offset */ 192 table->elements[idx] = table->block + table->cursor; 193 table->lengths [idx] = length; 194 FT_MEM_COPY( table->block + table->cursor, object, length ); 195 196 table->cursor += length; 197 return PSaux_Err_Ok; 198 } 199 200 201 /*************************************************************************/ 202 /* */ 203 /* <Function> */ 204 /* ps_table_done */ 205 /* */ 206 /* <Description> */ 207 /* Finalizes a PS_TableRec (i.e., reallocate it to its current */ 208 /* cursor). */ 209 /* */ 210 /* <InOut> */ 211 /* table :: The target table. */ 212 /* */ 213 /* <Note> */ 214 /* This function does NOT release the heap's memory block. It is up */ 215 /* to the caller to clean it, or reference it in its own structures. */ 216 /* */ 217 FT_LOCAL_DEF( void ) ps_table_done(PS_Table table)218 ps_table_done( PS_Table table ) 219 { 220 FT_Memory memory = table->memory; 221 FT_Error error; 222 FT_Byte* old_base = table->block; 223 224 225 /* should never fail, because rec.cursor <= rec.size */ 226 if ( !old_base ) 227 return; 228 229 if ( FT_ALLOC( table->block, table->cursor ) ) 230 return; 231 FT_MEM_COPY( table->block, old_base, table->cursor ); 232 shift_elements( table, old_base ); 233 234 table->capacity = table->cursor; 235 FT_FREE( old_base ); 236 237 FT_UNUSED( error ); 238 } 239 240 241 FT_LOCAL_DEF( void ) ps_table_release(PS_Table table)242 ps_table_release( PS_Table table ) 243 { 244 FT_Memory memory = table->memory; 245 246 247 if ( (FT_ULong)table->init == 0xDEADBEEFUL ) 248 { 249 FT_FREE( table->block ); 250 FT_FREE( table->elements ); 251 FT_FREE( table->lengths ); 252 table->init = 0; 253 } 254 } 255 256 257 /*************************************************************************/ 258 /*************************************************************************/ 259 /***** *****/ 260 /***** T1 PARSER *****/ 261 /***** *****/ 262 /*************************************************************************/ 263 /*************************************************************************/ 264 265 266 #define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' ) 267 #define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' ) 268 269 #define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) ) 270 271 272 FT_LOCAL_DEF( void ) ps_parser_skip_spaces(PS_Parser parser)273 ps_parser_skip_spaces( PS_Parser parser ) 274 { 275 FT_Byte* cur = parser->cursor; 276 FT_Byte* limit = parser->limit; 277 278 279 while ( cur < limit ) 280 { 281 FT_Byte c = *cur; 282 283 284 if ( !IS_T1_SPACE( c ) ) 285 break; 286 cur++; 287 } 288 parser->cursor = cur; 289 } 290 291 292 FT_LOCAL_DEF( void ) ps_parser_skip_alpha(PS_Parser parser)293 ps_parser_skip_alpha( PS_Parser parser ) 294 { 295 FT_Byte* cur = parser->cursor; 296 FT_Byte* limit = parser->limit; 297 298 299 while ( cur < limit ) 300 { 301 FT_Byte c = *cur; 302 303 304 if ( IS_T1_SPACE( c ) ) 305 break; 306 cur++; 307 } 308 parser->cursor = cur; 309 } 310 311 312 FT_LOCAL_DEF( void ) ps_parser_to_token(PS_Parser parser,T1_Token token)313 ps_parser_to_token( PS_Parser parser, 314 T1_Token token ) 315 { 316 FT_Byte* cur; 317 FT_Byte* limit; 318 FT_Byte starter, ender; 319 FT_Int embed; 320 321 322 token->type = T1_TOKEN_TYPE_NONE; 323 token->start = 0; 324 token->limit = 0; 325 326 /* first of all, skip space */ 327 ps_parser_skip_spaces( parser ); 328 329 cur = parser->cursor; 330 limit = parser->limit; 331 332 if ( cur < limit ) 333 { 334 switch ( *cur ) 335 { 336 /************* check for strings ***********************/ 337 case '(': 338 token->type = T1_TOKEN_TYPE_STRING; 339 ender = ')'; 340 goto Lookup_Ender; 341 342 /************* check for programs/array ****************/ 343 case '{': 344 token->type = T1_TOKEN_TYPE_ARRAY; 345 ender = '}'; 346 goto Lookup_Ender; 347 348 /************* check for table/array ******************/ 349 case '[': 350 token->type = T1_TOKEN_TYPE_ARRAY; 351 ender = ']'; 352 353 Lookup_Ender: 354 embed = 1; 355 starter = *cur++; 356 token->start = cur; 357 while ( cur < limit ) 358 { 359 if ( *cur == starter ) 360 embed++; 361 else if ( *cur == ender ) 362 { 363 embed--; 364 if ( embed <= 0 ) 365 { 366 token->limit = cur++; 367 break; 368 } 369 } 370 cur++; 371 } 372 break; 373 374 /* **************** otherwise, it's any token **********/ 375 default: 376 token->start = cur++; 377 token->type = T1_TOKEN_TYPE_ANY; 378 while ( cur < limit && !IS_T1_SPACE( *cur ) ) 379 cur++; 380 381 token->limit = cur; 382 } 383 384 if ( !token->limit ) 385 { 386 token->start = 0; 387 token->type = T1_TOKEN_TYPE_NONE; 388 } 389 390 parser->cursor = cur; 391 } 392 } 393 394 395 FT_LOCAL_DEF( void ) ps_parser_to_token_array(PS_Parser parser,T1_Token tokens,FT_UInt max_tokens,FT_Int * pnum_tokens)396 ps_parser_to_token_array( PS_Parser parser, 397 T1_Token tokens, 398 FT_UInt max_tokens, 399 FT_Int* pnum_tokens ) 400 { 401 T1_TokenRec master; 402 403 404 *pnum_tokens = -1; 405 406 ps_parser_to_token( parser, &master ); 407 if ( master.type == T1_TOKEN_TYPE_ARRAY ) 408 { 409 FT_Byte* old_cursor = parser->cursor; 410 FT_Byte* old_limit = parser->limit; 411 T1_Token cur = tokens; 412 T1_Token limit = cur + max_tokens; 413 414 415 parser->cursor = master.start; 416 parser->limit = master.limit; 417 418 while ( parser->cursor < parser->limit ) 419 { 420 T1_TokenRec token; 421 422 423 ps_parser_to_token( parser, &token ); 424 if ( !token.type ) 425 break; 426 427 if ( cur < limit ) 428 *cur = token; 429 430 cur++; 431 } 432 433 *pnum_tokens = (FT_Int)( cur - tokens ); 434 435 parser->cursor = old_cursor; 436 parser->limit = old_limit; 437 } 438 } 439 440 441 static FT_Long T1Radix(FT_Long radixBase,FT_Byte ** cur,FT_Byte * limit)442 T1Radix( FT_Long radixBase, 443 FT_Byte** cur, 444 FT_Byte* limit ) 445 { 446 FT_Long result = 0; 447 FT_Byte radixEndChar0 = 448 (FT_Byte)( radixBase > 10 ? '9' + 1 : '0' + radixBase ); 449 FT_Byte radixEndChar1 = 450 (FT_Byte)( 'A' + radixBase - 10 ); 451 FT_Byte radixEndChar2 = 452 (FT_Byte)( 'a' + radixBase - 10 ); 453 454 455 while( *cur < limit ) 456 { 457 if ( (*cur)[0] >= '0' && (*cur)[0] < radixEndChar0 ) 458 result = result * radixBase + (*cur)[0] - '0'; 459 460 else if ( radixBase > 10 && 461 (*cur)[0] >= 'A' && (*cur)[0] < radixEndChar1 ) 462 result = result * radixBase + ( (*cur)[0] - 'A' + 10 ); 463 464 else if ( radixBase > 10 && 465 (*cur)[0] >= 'a' && (*cur)[0] < radixEndChar2 ) 466 result = result * radixBase + ( (*cur)[0] - 'a' + 10 ); 467 468 else 469 return result; 470 471 (*cur)++; 472 } 473 474 return result; 475 } 476 477 478 static FT_Long t1_toint(FT_Byte ** cursor,FT_Byte * limit)479 t1_toint( FT_Byte** cursor, 480 FT_Byte* limit ) 481 { 482 FT_Long result = 0; 483 FT_Byte* cur = *cursor; 484 FT_Byte c = '\0', d; 485 486 487 for ( ; cur < limit; cur++ ) 488 { 489 c = *cur; 490 d = (FT_Byte)( c - '0' ); 491 if ( d < 10 ) 492 break; 493 494 if ( c == '-' ) 495 { 496 cur++; 497 break; 498 } 499 } 500 501 if ( cur < limit ) 502 { 503 do 504 { 505 d = (FT_Byte)( cur[0] - '0' ); 506 if ( d >= 10 ) 507 { 508 if ( cur[0] == '#' ) 509 { 510 cur++; 511 result = T1Radix( result, &cur, limit ); 512 } 513 break; 514 } 515 516 result = result * 10 + d; 517 cur++; 518 519 } while ( cur < limit ); 520 521 if ( c == '-' ) 522 result = -result; 523 } 524 525 *cursor = cur; 526 return result; 527 } 528 529 530 static FT_Long t1_tofixed(FT_Byte ** cursor,FT_Byte * limit,FT_Long power_ten)531 t1_tofixed( FT_Byte** cursor, 532 FT_Byte* limit, 533 FT_Long power_ten ) 534 { 535 FT_Byte* cur = *cursor; 536 FT_Long num, divider, result; 537 FT_Int sign = 0; 538 FT_Byte d; 539 540 541 if ( cur >= limit ) 542 return 0; 543 544 /* first of all, check the sign */ 545 if ( *cur == '-' ) 546 { 547 sign = 1; 548 cur++; 549 } 550 551 /* then, read the integer part, if any */ 552 if ( *cur != '.' ) 553 result = t1_toint( &cur, limit ) << 16; 554 else 555 result = 0; 556 557 num = 0; 558 divider = 1; 559 560 if ( cur >= limit ) 561 goto Exit; 562 563 /* read decimal part, if any */ 564 if ( *cur == '.' && cur + 1 < limit ) 565 { 566 cur++; 567 568 for (;;) 569 { 570 d = (FT_Byte)( *cur - '0' ); 571 if ( d >= 10 ) 572 break; 573 574 if ( divider < 10000000L ) 575 { 576 num = num * 10 + d; 577 divider *= 10; 578 } 579 580 cur++; 581 if ( cur >= limit ) 582 break; 583 } 584 } 585 586 /* read exponent, if any */ 587 if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) ) 588 { 589 cur++; 590 power_ten += t1_toint( &cur, limit ); 591 } 592 593 Exit: 594 /* raise to power of ten if needed */ 595 while ( power_ten > 0 ) 596 { 597 result = result * 10; 598 num = num * 10; 599 power_ten--; 600 } 601 602 while ( power_ten < 0 ) 603 { 604 result = result / 10; 605 divider = divider * 10; 606 power_ten++; 607 } 608 609 if ( num ) 610 result += FT_DivFix( num, divider ); 611 612 if ( sign ) 613 result = -result; 614 615 *cursor = cur; 616 return result; 617 } 618 619 620 static FT_Int t1_tocoordarray(FT_Byte ** cursor,FT_Byte * limit,FT_Int max_coords,FT_Short * coords)621 t1_tocoordarray( FT_Byte** cursor, 622 FT_Byte* limit, 623 FT_Int max_coords, 624 FT_Short* coords ) 625 { 626 FT_Byte* cur = *cursor; 627 FT_Int count = 0; 628 FT_Byte c, ender; 629 630 631 if ( cur >= limit ) 632 goto Exit; 633 634 /* check for the beginning of an array; if not, only one number will */ 635 /* be read */ 636 c = *cur; 637 ender = 0; 638 639 if ( c == '[' ) 640 ender = ']'; 641 642 if ( c == '{' ) 643 ender = '}'; 644 645 if ( ender ) 646 cur++; 647 648 /* now, read the coordinates */ 649 for ( ; cur < limit; ) 650 { 651 /* skip whitespace in front of data */ 652 for (;;) 653 { 654 c = *cur; 655 if ( c != ' ' && c != '\t' ) 656 break; 657 658 cur++; 659 if ( cur >= limit ) 660 goto Exit; 661 } 662 663 if ( count >= max_coords || c == ender ) 664 break; 665 666 coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 ); 667 count++; 668 669 if ( !ender ) 670 break; 671 } 672 673 Exit: 674 *cursor = cur; 675 return count; 676 } 677 678 679 static FT_Int t1_tofixedarray(FT_Byte ** cursor,FT_Byte * limit,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)680 t1_tofixedarray( FT_Byte** cursor, 681 FT_Byte* limit, 682 FT_Int max_values, 683 FT_Fixed* values, 684 FT_Int power_ten ) 685 { 686 FT_Byte* cur = *cursor; 687 FT_Int count = 0; 688 FT_Byte c, ender; 689 690 691 if ( cur >= limit ) goto Exit; 692 693 /* check for the beginning of an array. If not, only one number will */ 694 /* be read */ 695 c = *cur; 696 ender = 0; 697 698 if ( c == '[' ) 699 ender = ']'; 700 701 if ( c == '{' ) 702 ender = '}'; 703 704 if ( ender ) 705 cur++; 706 707 /* now, read the values */ 708 for ( ; cur < limit; ) 709 { 710 /* skip whitespace in front of data */ 711 for (;;) 712 { 713 c = *cur; 714 if ( c != ' ' && c != '\t' ) 715 break; 716 717 cur++; 718 if ( cur >= limit ) 719 goto Exit; 720 } 721 722 if ( count >= max_values || c == ender ) 723 break; 724 725 values[count] = t1_tofixed( &cur, limit, power_ten ); 726 count++; 727 728 if ( !ender ) 729 break; 730 } 731 732 Exit: 733 *cursor = cur; 734 return count; 735 } 736 737 738 #if 0 739 740 static FT_String* 741 t1_tostring( FT_Byte** cursor, 742 FT_Byte* limit, 743 FT_Memory memory ) 744 { 745 FT_Byte* cur = *cursor; 746 FT_PtrDist len = 0; 747 FT_Int count; 748 FT_String* result; 749 FT_Error error; 750 751 752 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ 753 /* that simply doesn't begin with an opening parenthesis, even */ 754 /* though they have a closing one! E.g. "amuncial.pfb" */ 755 /* */ 756 /* We must deal with these ill-fated cases there. Note that */ 757 /* these fonts didn't work with the old Type 1 driver as the */ 758 /* notice/copyright was not recognized as a valid string token */ 759 /* and made the old token parser commit errors. */ 760 761 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) 762 cur++; 763 if ( cur + 1 >= limit ) 764 return 0; 765 766 if ( *cur == '(' ) 767 cur++; /* skip the opening parenthesis, if there is one */ 768 769 *cursor = cur; 770 count = 0; 771 772 /* then, count its length */ 773 for ( ; cur < limit; cur++ ) 774 { 775 if ( *cur == '(' ) 776 count++; 777 778 else if ( *cur == ')' ) 779 { 780 count--; 781 if ( count < 0 ) 782 break; 783 } 784 } 785 786 len = cur - *cursor; 787 if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) 788 return 0; 789 790 /* now copy the string */ 791 FT_MEM_COPY( result, *cursor, len ); 792 result[len] = '\0'; 793 *cursor = cur; 794 return result; 795 } 796 797 #endif /* 0 */ 798 799 800 static int t1_tobool(FT_Byte ** cursor,FT_Byte * limit)801 t1_tobool( FT_Byte** cursor, 802 FT_Byte* limit ) 803 { 804 FT_Byte* cur = *cursor; 805 FT_Bool result = 0; 806 807 808 /* return 1 if we find `true', 0 otherwise */ 809 if ( cur + 3 < limit && 810 cur[0] == 't' && 811 cur[1] == 'r' && 812 cur[2] == 'u' && 813 cur[3] == 'e' ) 814 { 815 result = 1; 816 cur += 5; 817 } 818 else if ( cur + 4 < limit && 819 cur[0] == 'f' && 820 cur[1] == 'a' && 821 cur[2] == 'l' && 822 cur[3] == 's' && 823 cur[4] == 'e' ) 824 { 825 result = 0; 826 cur += 6; 827 } 828 829 *cursor = cur; 830 return result; 831 } 832 833 834 /* Load a simple field (i.e. non-table) into the current list of objects */ 835 FT_LOCAL_DEF( FT_Error ) ps_parser_load_field(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)836 ps_parser_load_field( PS_Parser parser, 837 const T1_Field field, 838 void** objects, 839 FT_UInt max_objects, 840 FT_ULong* pflags ) 841 { 842 T1_TokenRec token; 843 FT_Byte* cur; 844 FT_Byte* limit; 845 FT_UInt count; 846 FT_UInt idx; 847 FT_Error error; 848 849 850 ps_parser_to_token( parser, &token ); 851 if ( !token.type ) 852 goto Fail; 853 854 count = 1; 855 idx = 0; 856 cur = token.start; 857 limit = token.limit; 858 859 /* we must detect arrays */ 860 if ( field->type == T1_FIELD_TYPE_BBOX ) 861 { 862 T1_TokenRec token2; 863 FT_Byte* old_cur = parser->cursor; 864 FT_Byte* old_limit = parser->limit; 865 866 867 parser->cursor = token.start; 868 parser->limit = token.limit; 869 870 ps_parser_to_token( parser, &token2 ); 871 parser->cursor = old_cur; 872 parser->limit = old_limit; 873 874 if ( token2.type == T1_TOKEN_TYPE_ARRAY ) 875 goto FieldArray; 876 } 877 else if ( token.type == T1_TOKEN_TYPE_ARRAY ) 878 { 879 FieldArray: 880 /* if this is an array, and we have no blend, an error occurs */ 881 if ( max_objects == 0 ) 882 goto Fail; 883 884 count = max_objects; 885 idx = 1; 886 } 887 888 for ( ; count > 0; count--, idx++ ) 889 { 890 FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; 891 FT_Long val; 892 FT_String* string; 893 894 895 switch ( field->type ) 896 { 897 case T1_FIELD_TYPE_BOOL: 898 val = t1_tobool( &cur, limit ); 899 goto Store_Integer; 900 901 case T1_FIELD_TYPE_FIXED: 902 val = t1_tofixed( &cur, limit, 3 ); 903 goto Store_Integer; 904 905 case T1_FIELD_TYPE_INTEGER: 906 val = t1_toint( &cur, limit ); 907 908 Store_Integer: 909 switch ( field->size ) 910 { 911 case 1: 912 *(FT_Byte*)q = (FT_Byte)val; 913 break; 914 915 case 2: 916 *(FT_UShort*)q = (FT_UShort)val; 917 break; 918 919 case 4: 920 *(FT_UInt32*)q = (FT_UInt32)val; 921 break; 922 923 default: /* for 64-bit systems */ 924 *(FT_Long*)q = val; 925 } 926 break; 927 928 case T1_FIELD_TYPE_STRING: 929 { 930 FT_Memory memory = parser->memory; 931 FT_UInt len = (FT_UInt)( limit - cur ); 932 933 934 if ( *(FT_String**)q ) 935 /* with synthetic fonts, it's possible to find a field twice */ 936 break; 937 938 if ( FT_ALLOC( string, len + 1 ) ) 939 goto Exit; 940 941 FT_MEM_COPY( string, cur, len ); 942 string[len] = 0; 943 944 *(FT_String**)q = string; 945 } 946 break; 947 948 case T1_FIELD_TYPE_BBOX: 949 { 950 FT_Fixed temp[4]; 951 FT_BBox* bbox = (FT_BBox*)q; 952 953 954 /* we need the '[' and ']' delimiters */ 955 token.start--; 956 token.limit++; 957 (void)t1_tofixedarray( &token.start, token.limit, 4, temp, 0 ); 958 959 bbox->xMin = FT_RoundFix( temp[0] ); 960 bbox->yMin = FT_RoundFix( temp[1] ); 961 bbox->xMax = FT_RoundFix( temp[2] ); 962 bbox->yMax = FT_RoundFix( temp[3] ); 963 } 964 break; 965 966 default: 967 /* an error occured */ 968 goto Fail; 969 } 970 } 971 972 #if 0 /* obsolete - keep for reference */ 973 if ( pflags ) 974 *pflags |= 1L << field->flag_bit; 975 #else 976 FT_UNUSED( pflags ); 977 #endif 978 979 error = PSaux_Err_Ok; 980 981 Exit: 982 return error; 983 984 Fail: 985 error = PSaux_Err_Invalid_File_Format; 986 goto Exit; 987 } 988 989 990 #define T1_MAX_TABLE_ELEMENTS 32 991 992 993 FT_LOCAL_DEF( FT_Error ) ps_parser_load_field_table(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)994 ps_parser_load_field_table( PS_Parser parser, 995 const T1_Field field, 996 void** objects, 997 FT_UInt max_objects, 998 FT_ULong* pflags ) 999 { 1000 T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; 1001 T1_Token token; 1002 FT_Int num_elements; 1003 FT_Error error = 0; 1004 FT_Byte* old_cursor; 1005 FT_Byte* old_limit; 1006 T1_FieldRec fieldrec = *(T1_Field)field; 1007 1008 1009 #if 1 1010 fieldrec.type = T1_FIELD_TYPE_INTEGER; 1011 if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 1012 fieldrec.type = T1_FIELD_TYPE_FIXED; 1013 #endif 1014 1015 ps_parser_to_token_array( parser, elements, 32, &num_elements ); 1016 if ( num_elements < 0 ) 1017 goto Fail; 1018 1019 if ( num_elements > T1_MAX_TABLE_ELEMENTS ) 1020 num_elements = T1_MAX_TABLE_ELEMENTS; 1021 1022 old_cursor = parser->cursor; 1023 old_limit = parser->limit; 1024 1025 /* we store the elements count */ 1026 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = 1027 (FT_Byte)num_elements; 1028 1029 /* we now load each element, adjusting the field.offset on each one */ 1030 token = elements; 1031 for ( ; num_elements > 0; num_elements--, token++ ) 1032 { 1033 parser->cursor = token->start; 1034 parser->limit = token->limit; 1035 ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 ); 1036 fieldrec.offset += fieldrec.size; 1037 } 1038 1039 #if 0 /* obsolete -- keep for reference */ 1040 if ( pflags ) 1041 *pflags |= 1L << field->flag_bit; 1042 #else 1043 FT_UNUSED( pflags ); 1044 #endif 1045 1046 parser->cursor = old_cursor; 1047 parser->limit = old_limit; 1048 1049 Exit: 1050 return error; 1051 1052 Fail: 1053 error = PSaux_Err_Invalid_File_Format; 1054 goto Exit; 1055 } 1056 1057 1058 FT_LOCAL_DEF( FT_Long ) ps_parser_to_int(PS_Parser parser)1059 ps_parser_to_int( PS_Parser parser ) 1060 { 1061 return t1_toint( &parser->cursor, parser->limit ); 1062 } 1063 1064 1065 FT_LOCAL_DEF( FT_Fixed ) ps_parser_to_fixed(PS_Parser parser,FT_Int power_ten)1066 ps_parser_to_fixed( PS_Parser parser, 1067 FT_Int power_ten ) 1068 { 1069 return t1_tofixed( &parser->cursor, parser->limit, power_ten ); 1070 } 1071 1072 1073 FT_LOCAL_DEF( FT_Int ) ps_parser_to_coord_array(PS_Parser parser,FT_Int max_coords,FT_Short * coords)1074 ps_parser_to_coord_array( PS_Parser parser, 1075 FT_Int max_coords, 1076 FT_Short* coords ) 1077 { 1078 return t1_tocoordarray( &parser->cursor, parser->limit, 1079 max_coords, coords ); 1080 } 1081 1082 1083 FT_LOCAL_DEF( FT_Int ) ps_parser_to_fixed_array(PS_Parser parser,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)1084 ps_parser_to_fixed_array( PS_Parser parser, 1085 FT_Int max_values, 1086 FT_Fixed* values, 1087 FT_Int power_ten ) 1088 { 1089 return t1_tofixedarray( &parser->cursor, parser->limit, 1090 max_values, values, power_ten ); 1091 } 1092 1093 1094 #if 0 1095 1096 FT_LOCAL_DEF( FT_String* ) 1097 T1_ToString( PS_Parser parser ) 1098 { 1099 return t1_tostring( &parser->cursor, parser->limit, parser->memory ); 1100 } 1101 1102 1103 FT_LOCAL_DEF( FT_Bool ) 1104 T1_ToBool( PS_Parser parser ) 1105 { 1106 return t1_tobool( &parser->cursor, parser->limit ); 1107 } 1108 1109 #endif /* 0 */ 1110 1111 1112 FT_LOCAL_DEF( void ) ps_parser_init(PS_Parser parser,FT_Byte * base,FT_Byte * limit,FT_Memory memory)1113 ps_parser_init( PS_Parser parser, 1114 FT_Byte* base, 1115 FT_Byte* limit, 1116 FT_Memory memory ) 1117 { 1118 parser->error = 0; 1119 parser->base = base; 1120 parser->limit = limit; 1121 parser->cursor = base; 1122 parser->memory = memory; 1123 parser->funcs = ps_parser_funcs; 1124 } 1125 1126 1127 FT_LOCAL_DEF( void ) ps_parser_done(PS_Parser parser)1128 ps_parser_done( PS_Parser parser ) 1129 { 1130 FT_UNUSED( parser ); 1131 } 1132 1133 1134 /*************************************************************************/ 1135 /*************************************************************************/ 1136 /***** *****/ 1137 /***** T1 BUILDER *****/ 1138 /***** *****/ 1139 /*************************************************************************/ 1140 /*************************************************************************/ 1141 1142 /*************************************************************************/ 1143 /* */ 1144 /* <Function> */ 1145 /* t1_builder_init */ 1146 /* */ 1147 /* <Description> */ 1148 /* Initializes a given glyph builder. */ 1149 /* */ 1150 /* <InOut> */ 1151 /* builder :: A pointer to the glyph builder to initialize. */ 1152 /* */ 1153 /* <Input> */ 1154 /* face :: The current face object. */ 1155 /* */ 1156 /* size :: The current size object. */ 1157 /* */ 1158 /* glyph :: The current glyph object. */ 1159 /* */ 1160 /* hinting :: Whether hinting should be applied. */ 1161 /* */ 1162 FT_LOCAL_DEF( void ) t1_builder_init(T1_Builder builder,FT_Face face,FT_Size size,FT_GlyphSlot glyph,FT_Bool hinting)1163 t1_builder_init( T1_Builder builder, 1164 FT_Face face, 1165 FT_Size size, 1166 FT_GlyphSlot glyph, 1167 FT_Bool hinting ) 1168 { 1169 builder->path_begun = 0; 1170 builder->load_points = 1; 1171 1172 builder->face = face; 1173 builder->glyph = glyph; 1174 builder->memory = face->memory; 1175 1176 if ( glyph ) 1177 { 1178 FT_GlyphLoader loader = glyph->internal->loader; 1179 1180 1181 builder->loader = loader; 1182 builder->base = &loader->base.outline; 1183 builder->current = &loader->current.outline; 1184 FT_GlyphLoader_Rewind( loader ); 1185 1186 builder->hints_globals = size->internal; 1187 builder->hints_funcs = 0; 1188 1189 if ( hinting ) 1190 builder->hints_funcs = glyph->internal->glyph_hints; 1191 } 1192 1193 if ( size ) 1194 { 1195 builder->scale_x = size->metrics.x_scale; 1196 builder->scale_y = size->metrics.y_scale; 1197 } 1198 1199 builder->pos_x = 0; 1200 builder->pos_y = 0; 1201 1202 builder->left_bearing.x = 0; 1203 builder->left_bearing.y = 0; 1204 builder->advance.x = 0; 1205 builder->advance.y = 0; 1206 1207 builder->funcs = t1_builder_funcs; 1208 } 1209 1210 1211 /*************************************************************************/ 1212 /* */ 1213 /* <Function> */ 1214 /* t1_builder_done */ 1215 /* */ 1216 /* <Description> */ 1217 /* Finalizes a given glyph builder. Its contents can still be used */ 1218 /* after the call, but the function saves important information */ 1219 /* within the corresponding glyph slot. */ 1220 /* */ 1221 /* <Input> */ 1222 /* builder :: A pointer to the glyph builder to finalize. */ 1223 /* */ 1224 FT_LOCAL_DEF( void ) t1_builder_done(T1_Builder builder)1225 t1_builder_done( T1_Builder builder ) 1226 { 1227 FT_GlyphSlot glyph = builder->glyph; 1228 1229 1230 if ( glyph ) 1231 glyph->outline = *builder->base; 1232 } 1233 1234 1235 /* check that there is enough space for `count' more points */ 1236 FT_LOCAL_DEF( FT_Error ) t1_builder_check_points(T1_Builder builder,FT_Int count)1237 t1_builder_check_points( T1_Builder builder, 1238 FT_Int count ) 1239 { 1240 return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 ); 1241 } 1242 1243 1244 /* add a new point, do not check space */ 1245 FT_LOCAL_DEF( void ) t1_builder_add_point(T1_Builder builder,FT_Pos x,FT_Pos y,FT_Byte flag)1246 t1_builder_add_point( T1_Builder builder, 1247 FT_Pos x, 1248 FT_Pos y, 1249 FT_Byte flag ) 1250 { 1251 FT_Outline* outline = builder->current; 1252 1253 1254 if ( builder->load_points ) 1255 { 1256 FT_Vector* point = outline->points + outline->n_points; 1257 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; 1258 1259 1260 if ( builder->shift ) 1261 { 1262 x >>= 16; 1263 y >>= 16; 1264 } 1265 point->x = x; 1266 point->y = y; 1267 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); 1268 1269 builder->last = *point; 1270 } 1271 outline->n_points++; 1272 } 1273 1274 1275 /* check space for a new on-curve point, then add it */ 1276 FT_LOCAL_DEF( FT_Error ) t1_builder_add_point1(T1_Builder builder,FT_Pos x,FT_Pos y)1277 t1_builder_add_point1( T1_Builder builder, 1278 FT_Pos x, 1279 FT_Pos y ) 1280 { 1281 FT_Error error; 1282 1283 1284 error = t1_builder_check_points( builder, 1 ); 1285 if ( !error ) 1286 t1_builder_add_point( builder, x, y, 1 ); 1287 1288 return error; 1289 } 1290 1291 1292 /* check room for a new contour, then add it */ 1293 FT_LOCAL_DEF( FT_Error ) t1_builder_add_contour(T1_Builder builder)1294 t1_builder_add_contour( T1_Builder builder ) 1295 { 1296 FT_Outline* outline = builder->current; 1297 FT_Error error; 1298 1299 1300 if ( !builder->load_points ) 1301 { 1302 outline->n_contours++; 1303 return PSaux_Err_Ok; 1304 } 1305 1306 error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 ); 1307 if ( !error ) 1308 { 1309 if ( outline->n_contours > 0 ) 1310 outline->contours[outline->n_contours - 1] = 1311 (short)( outline->n_points - 1 ); 1312 1313 outline->n_contours++; 1314 } 1315 1316 return error; 1317 } 1318 1319 1320 /* if a path was begun, add its first on-curve point */ 1321 FT_LOCAL_DEF( FT_Error ) t1_builder_start_point(T1_Builder builder,FT_Pos x,FT_Pos y)1322 t1_builder_start_point( T1_Builder builder, 1323 FT_Pos x, 1324 FT_Pos y ) 1325 { 1326 FT_Error error = 0; 1327 1328 1329 /* test whether we are building a new contour */ 1330 if ( !builder->path_begun ) 1331 { 1332 builder->path_begun = 1; 1333 error = t1_builder_add_contour( builder ); 1334 if ( !error ) 1335 error = t1_builder_add_point1( builder, x, y ); 1336 } 1337 return error; 1338 } 1339 1340 1341 /* close the current contour */ 1342 FT_LOCAL_DEF( void ) t1_builder_close_contour(T1_Builder builder)1343 t1_builder_close_contour( T1_Builder builder ) 1344 { 1345 FT_Outline* outline = builder->current; 1346 1347 1348 /* XXXX: We must not include the last point in the path if it */ 1349 /* is located on the first point. */ 1350 if ( outline->n_points > 1 ) 1351 { 1352 FT_Int first = 0; 1353 FT_Vector* p1 = outline->points + first; 1354 FT_Vector* p2 = outline->points + outline->n_points - 1; 1355 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; 1356 1357 1358 if ( outline->n_contours > 1 ) 1359 { 1360 first = outline->contours[outline->n_contours - 2] + 1; 1361 p1 = outline->points + first; 1362 } 1363 1364 /* `delete' last point only if it coincides with the first */ 1365 /* point and it is not a control point (which can happen). */ 1366 if ( p1->x == p2->x && p1->y == p2->y ) 1367 if ( *control == FT_CURVE_TAG_ON ) 1368 outline->n_points--; 1369 } 1370 1371 if ( outline->n_contours > 0 ) 1372 outline->contours[outline->n_contours - 1] = 1373 (short)( outline->n_points - 1 ); 1374 } 1375 1376 1377 /*************************************************************************/ 1378 /*************************************************************************/ 1379 /***** *****/ 1380 /***** OTHER *****/ 1381 /***** *****/ 1382 /*************************************************************************/ 1383 /*************************************************************************/ 1384 1385 FT_LOCAL_DEF( void ) t1_decrypt(FT_Byte * buffer,FT_Offset length,FT_UShort seed)1386 t1_decrypt( FT_Byte* buffer, 1387 FT_Offset length, 1388 FT_UShort seed ) 1389 { 1390 while ( length > 0 ) 1391 { 1392 FT_Byte plain; 1393 1394 1395 plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) ); 1396 seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 ); 1397 *buffer++ = plain; 1398 length--; 1399 } 1400 } 1401 1402 1403 /* END */ 1404