cidparse.c revision a1be2dcee38dd4448a365fd8932c52cca52f5445
1/***************************************************************************/ 2/* */ 3/* cidparse.c */ 4/* */ 5/* CID-keyed Type1 parser (body). */ 6/* */ 7/* Copyright 1996-2000 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 <freetype/internal/ftdebug.h> 20#include <freetype/internal/ftcalc.h> 21#include <freetype/internal/ftobjs.h> 22#include <freetype/internal/ftstream.h> 23#include <freetype/internal/t1errors.h> 24#include <cidparse.h> 25 26#include <string.h> /* for strncmp() */ 27 28 29 /*************************************************************************/ 30 /* */ 31 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 32 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 33 /* messages during execution. */ 34 /* */ 35#undef FT_COMPONENT 36#define FT_COMPONENT trace_cidparse 37 38 39#if 0 40 41 /*************************************************************************/ 42 /*************************************************************************/ 43 /*************************************************************************/ 44 /***** *****/ 45 /***** IMPLEMENTATION OF CID_TABLE OBJECT *****/ 46 /***** *****/ 47 /*************************************************************************/ 48 /*************************************************************************/ 49 /*************************************************************************/ 50 51 52 /*************************************************************************/ 53 /* */ 54 /* <Function> */ 55 /* CID_New_Table */ 56 /* */ 57 /* <Description> */ 58 /* Initializes a CID_Table. */ 59 /* */ 60 /* <InOut> */ 61 /* table :: The address of the target table. */ 62 /* */ 63 /* <Input> */ 64 /* count :: The table size, i.e., the maximal number of elements. */ 65 /* */ 66 /* memory :: The memory object to be used for all subsequent */ 67 /* reallocations. */ 68 /* */ 69 /* <Return> */ 70 /* FreeType error code. 0 means success. */ 71 /* */ 72 LOCAL_FUNC 73 FT_Error CID_New_Table( CID_Table* table, 74 FT_Int count, 75 FT_Memory memory ) 76 { 77 FT_Error error; 78 79 80 table->memory = memory; 81 if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) || 82 ALLOC_ARRAY( table->lengths, count, FT_Byte* ) ) 83 goto Exit; 84 85 table->max_elems = count; 86 table->init = 0xDEADBEEFL; 87 table->num_elems = 0; 88 table->block = 0; 89 table->capacity = 0; 90 table->cursor = 0; 91 92 Exit: 93 if ( error ) 94 FREE( table->elements ); 95 96 return error; 97 } 98 99 100 static 101 void shift_elements( CID_Table* table, 102 FT_Byte* old_base ) 103 { 104 FT_Long delta = table->block - old_base; 105 FT_Byte** offset = table->elements; 106 FT_Byte** limit = offset + table->max_elems; 107 108 109 if ( delta ) 110 for ( ; offset < limit; offset++ ) 111 { 112 if ( offset[0] ) 113 offset[0] += delta; 114 } 115 } 116 117 118 static 119 FT_Error reallocate_t1_table( CID_Table* table, 120 FT_Int new_size ) 121 { 122 FT_Memory memory = table->memory; 123 FT_Byte* old_base = table->block; 124 FT_Error error; 125 126 127 /* realloc the base block */ 128 if ( REALLOC( table->block, table->capacity, new_size ) ) 129 return error; 130 131 table->capacity = new_size; 132 133 /* shift all offsets when needed */ 134 if ( old_base ) 135 shift_elements( table, old_base ); 136 137 return T1_Err_Ok; 138 } 139 140 141 /*************************************************************************/ 142 /* */ 143 /* <Function> */ 144 /* CID_Add_Table */ 145 /* */ 146 /* <Description> */ 147 /* Adds an object to a CID_Table, possibly growing its memory block. */ 148 /* */ 149 /* <InOut> */ 150 /* table :: The target table. */ 151 /* */ 152 /* <Input> */ 153 /* index :: The index of the object in the table. */ 154 /* */ 155 /* object :: The address of the object to copy in the memory. */ 156 /* */ 157 /* length :: The length in bytes of the source object. */ 158 /* */ 159 /* <Return> */ 160 /* FreeType error code. 0 means success. An error is returned if */ 161 /* reallocation fails. */ 162 /* */ 163 LOCAL_FUNC 164 FT_Error CID_Add_Table( CID_Table* table, 165 FT_Int index, 166 void* object, 167 FT_Int length ) 168 { 169 if ( index < 0 || index > table->max_elems ) 170 { 171 FT_ERROR(( "CID_Add_Table: invalid index\n" )); 172 return T1_Err_Syntax_Error; 173 } 174 175 /* grow the base block if needed */ 176 if ( table->cursor + length > table->capacity ) 177 { 178 FT_Error error; 179 FT_Int new_size = table->capacity; 180 181 182 while ( new_size < table->cursor + length ) 183 new_size += 1024; 184 185 error = reallocate_t1_table( table, new_size ); 186 if ( error ) 187 return error; 188 } 189 190 /* add the object to the base block and adjust offset */ 191 table->elements[index] = table->block + table->cursor; 192 table->lengths [index] = length; 193 194 MEM_Copy( table->block + table->cursor, object, length ); 195 196 table->cursor += length; 197 198 return T1_Err_Ok; 199 } 200 201 202 /*************************************************************************/ 203 /* */ 204 /* <Function> */ 205 /* CID_Done_Table */ 206 /* */ 207 /* <Description> */ 208 /* Finalizes a CID_Table (reallocate it to its current 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 LOCAL_FUNC 218 void CID_Done_Table( CID_Table* table ) 219 { 220 FT_Memory memory = table->memory; 221 FT_Error error; 222 FT_Byte* old_base; 223 224 225 /* should never fail, as rec.cursor <= rec.size */ 226 old_base = table->block; 227 if ( !old_base ) 228 return; 229 230 (void)REALLOC( table->block, table->capacity, table->cursor ); 231 table->capacity = table->cursor; 232 233 if ( old_base != table->block ) 234 shift_elements( table, old_base ); 235 } 236 237 238 LOCAL_FUNC 239 void CID_Release_Table( CID_Table* table ) 240 { 241 FT_Memory memory = table->memory; 242 243 244 if ( table->init == 0xDEADBEEFL ) 245 { 246 FREE( table->block ); 247 FREE( table->elements ); 248 FREE( table->lengths ); 249 table->init = 0; 250 } 251 } 252 253#endif /* 0 */ 254 255 256 /*************************************************************************/ 257 /*************************************************************************/ 258 /*************************************************************************/ 259 /***** *****/ 260 /***** INPUT STREAM PARSER *****/ 261 /***** *****/ 262 /*************************************************************************/ 263 /*************************************************************************/ 264 /*************************************************************************/ 265 266 267#define IS_CID_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' ) 268#define IS_CID_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' ) 269 270#define IS_CID_SPACE( c ) ( IS_CID_WHITESPACE( c ) || IS_CID_LINESPACE( c ) ) 271 272 273 LOCAL_FUNC 274 void CID_Skip_Spaces( CID_Parser* parser ) 275 { 276 FT_Byte* cur = parser->cursor; 277 FT_Byte* limit = parser->limit; 278 279 280 while ( cur < limit ) 281 { 282 FT_Byte c = *cur; 283 284 285 if ( !IS_CID_SPACE( c ) ) 286 break; 287 cur++; 288 } 289 290 parser->cursor = cur; 291 } 292 293 294 LOCAL_FUNC 295 void CID_ToToken( CID_Parser* parser, 296 CID_Token_Rec* token ) 297 { 298 FT_Byte* cur; 299 FT_Byte* limit; 300 FT_Byte starter, ender; 301 FT_Int embed; 302 303 304 token->type = t1_token_none; 305 token->start = 0; 306 token->limit = 0; 307 308 /* first of all, skip space */ 309 CID_Skip_Spaces( parser ); 310 311 cur = parser->cursor; 312 limit = parser->limit; 313 314 if ( cur < limit ) 315 { 316 switch ( *cur ) 317 { 318 /************* check for strings ***********************/ 319 case '(': 320 token->type = t1_token_string; 321 ender = ')'; 322 goto Lookup_Ender; 323 324 /************* check for programs/array ****************/ 325 case '{': 326 token->type = t1_token_array; 327 ender = '}'; 328 goto Lookup_Ender; 329 330 /************* check for table/array ******************/ 331 case '[': 332 token->type = t1_token_array; 333 ender = ']'; 334 335 Lookup_Ender: 336 embed = 1; 337 starter = *cur++; 338 token->start = cur; 339 340 while ( cur < limit ) 341 { 342 if ( *cur == starter ) 343 embed++; 344 else if ( *cur == ender ) 345 { 346 embed--; 347 if ( embed <= 0 ) 348 { 349 token->limit = cur++; 350 break; 351 } 352 } 353 cur++; 354 } 355 break; 356 357 /* **************** otherwise, it's any token **********/ 358 default: 359 token->start = cur++; 360 token->type = t1_token_any; 361 while ( cur < limit && !IS_CID_SPACE( *cur ) ) 362 cur++; 363 364 token->limit = cur; 365 } 366 367 if ( !token->limit ) 368 { 369 token->start = 0; 370 token->type = t1_token_none; 371 } 372 373 parser->cursor = cur; 374 } 375 } 376 377 378 LOCAL_FUNC 379 void CID_ToTokenArray( CID_Parser* parser, 380 CID_Token_Rec* tokens, 381 FT_UInt max_tokens, 382 FT_Int* pnum_tokens ) 383 { 384 CID_Token_Rec master; 385 386 387 *pnum_tokens = -1; 388 389 CID_ToToken( parser, &master ); 390 391 if ( master.type == t1_token_array ) 392 { 393 FT_Byte* old_cursor = parser->cursor; 394 FT_Byte* old_limit = parser->limit; 395 CID_Token_Rec* cur = tokens; 396 CID_Token_Rec* limit = cur + max_tokens; 397 398 399 parser->cursor = master.start; 400 parser->limit = master.limit; 401 402 while ( parser->cursor < parser->limit ) 403 { 404 CID_Token_Rec token; 405 406 407 CID_ToToken( parser, &token ); 408 if ( !token.type ) 409 break; 410 411 if ( cur < limit ) 412 *cur = token; 413 414 cur++; 415 } 416 417 *pnum_tokens = cur - tokens; 418 419 parser->cursor = old_cursor; 420 parser->limit = old_limit; 421 } 422 } 423 424 425 static 426 FT_Long t1_toint( FT_Byte** cursor, 427 FT_Byte* limit ) 428 { 429 FT_Long result = 0; 430 FT_Byte* cur = *cursor; 431 FT_Byte c, d; 432 433 434 for ( ; cur < limit; cur++ ) 435 { 436 c = *cur; 437 d = (FT_Byte)( c - '0' ); 438 if ( d < 10 ) 439 break; 440 441 if ( c == '-' ) 442 { 443 cur++; 444 break; 445 } 446 } 447 448 if ( cur < limit ) 449 { 450 do 451 { 452 d = (FT_Byte)( cur[0] - '0' ); 453 if ( d >= 10 ) 454 break; 455 456 result = result * 10 + d; 457 cur++; 458 459 } while ( cur < limit ); 460 461 if ( c == '-' ) 462 result = -result; 463 } 464 465 *cursor = cur; 466 467 return result; 468 } 469 470 471 static 472 FT_Long t1_tofixed( FT_Byte** cursor, 473 FT_Byte* limit, 474 FT_Long power_ten ) 475 { 476 FT_Byte* cur = *cursor; 477 FT_Long num, divider, result; 478 FT_Int sign = 0; 479 FT_Byte d; 480 481 482 if ( cur >= limit ) 483 return 0; 484 485 /* first of all, read the integer part */ 486 result = t1_toint( &cur, limit ) << 16; 487 num = 0; 488 divider = 1; 489 490 if ( result < 0 ) 491 { 492 sign = 1; 493 result = -result; 494 } 495 496 if ( cur >= limit ) 497 goto Exit; 498 499 /* read decimal part, if any */ 500 if ( *cur == '.' && cur + 1 < limit ) 501 { 502 cur++; 503 504 for (;;) 505 { 506 d = (FT_Byte)( *cur - '0' ); 507 if ( d >= 10 ) break; 508 509 if ( divider < 10000000L ) 510 { 511 num = num * 10 + d; 512 divider *= 10; 513 } 514 515 cur++; 516 if ( cur >= limit ) 517 break; 518 } 519 } 520 521 /* read exponent, if any */ 522 if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) ) 523 { 524 cur++; 525 power_ten += t1_toint( &cur, limit ); 526 } 527 528 Exit: 529 /* raise to power of ten if needed */ 530 while ( power_ten > 0 ) 531 { 532 result = result * 10; 533 num = num * 10; 534 power_ten--; 535 } 536 537 while ( power_ten < 0 ) 538 { 539 result = result / 10; 540 divider = divider * 10; 541 power_ten++; 542 } 543 544 if ( num ) 545 result += FT_DivFix( num, divider ); 546 547 if ( sign ) 548 result = -result; 549 550 *cursor = cur; 551 552 return result; 553 } 554 555 556 static 557 int t1_tobool( FT_Byte** cursor, 558 FT_Byte* limit ) 559 { 560 FT_Byte* cur = *cursor; 561 FT_Bool result = 0; 562 563 564 /* return 1 if we find a "true", 0 otherwise */ 565 if ( cur + 3 < limit && 566 cur[0] == 't' && 567 cur[1] == 'r' && 568 cur[2] == 'u' && 569 cur[3] == 'e' ) 570 { 571 result = 1; 572 cur += 5; 573 } 574 else if ( cur + 4 < limit && 575 cur[0] == 'f' && 576 cur[1] == 'a' && 577 cur[2] == 'l' && 578 cur[3] == 's' && 579 cur[4] == 'e' ) 580 { 581 result = 0; 582 cur += 6; 583 } 584 *cursor = cur; 585 return result; 586 } 587 588 589 static 590 FT_Int t1_tocoordarray( FT_Byte** cursor, 591 FT_Byte* limit, 592 FT_Int max_coords, 593 FT_Short* coords ) 594 { 595 FT_Byte* cur = *cursor; 596 FT_Int count = 0; 597 FT_Byte c, ender; 598 599 600 if ( cur >= limit ) 601 goto Exit; 602 603 /* check for the beginning of an array. */ 604 /* If not, only one number will be read */ 605 c = *cur; 606 ender = 0; 607 608 if ( c == '[' ) 609 ender = ']'; 610 611 if ( c == '{' ) 612 ender = '}'; 613 614 if ( ender ) 615 cur++; 616 617 /* now, read the coordinates */ 618 for ( ; cur < limit; ) 619 { 620 /* skip whitespace in front of data */ 621 for (;;) 622 { 623 c = *cur; 624 if ( c != ' ' && c != '\t' ) 625 break; 626 627 cur++; 628 if ( cur >= limit ) 629 goto Exit; 630 } 631 632 if ( count >= max_coords || c == ender ) 633 break; 634 635 coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 ); 636 count++; 637 638 if ( !ender ) 639 break; 640 } 641 642 Exit: 643 *cursor = cur; 644 return count; 645 } 646 647 648 static 649 FT_Int t1_tofixedarray( FT_Byte** cursor, 650 FT_Byte* limit, 651 FT_Int max_values, 652 FT_Fixed* values, 653 FT_Int power_ten ) 654 { 655 FT_Byte* cur = *cursor; 656 FT_Int count = 0; 657 FT_Byte c, ender; 658 659 660 if ( cur >= limit ) 661 goto Exit; 662 663 /* check for the beginning of an array. */ 664 /* If not, only one number will be read */ 665 c = *cur; 666 ender = 0; 667 668 if ( c == '[' ) 669 ender = ']'; 670 671 if ( c == '{' ) 672 ender = '}'; 673 674 if ( ender ) 675 cur++; 676 677 /* now, read the values */ 678 for ( ; cur < limit; ) 679 { 680 /* skip whitespace in front of data */ 681 for (;;) 682 { 683 c = *cur; 684 if ( c != ' ' && c != '\t' ) 685 break; 686 687 cur++; 688 if ( cur >= limit ) 689 goto Exit; 690 } 691 692 if ( count >= max_values || c == ender ) 693 break; 694 695 values[count] = t1_tofixed( &cur, limit, power_ten ); 696 count++; 697 698 if ( !ender ) 699 break; 700 } 701 702 Exit: 703 *cursor = cur; 704 705 return count; 706 } 707 708 709 710 /* Loads a simple field (i.e. non-table) into the current */ 711 /* list of objects */ 712 LOCAL_FUNC 713 FT_Error CID_Load_Field( CID_Parser* parser, 714 const CID_Field_Rec* field, 715 void* object ) 716 { 717 CID_Token_Rec token; 718 FT_Byte* cur; 719 FT_Byte* limit; 720 FT_UInt count; 721 FT_UInt index; 722 FT_Error error; 723 724 725 CID_ToToken( parser, &token ); 726 if ( !token.type ) 727 goto Fail; 728 729 count = 1; 730 index = 0; 731 cur = token.start; 732 limit = token.limit; 733 734 { 735 FT_Byte* q = (FT_Byte*)object + field->offset; 736 FT_Long val; 737 FT_String* string; 738 739 740 switch ( field->type ) 741 { 742 case t1_field_bool: 743 val = t1_tobool( &cur, limit ); 744 goto Store_Integer; 745 746 case t1_field_fixed: 747 val = t1_tofixed( &cur, limit, 0 ); 748 goto Store_Integer; 749 750 case t1_field_integer: 751 val = t1_toint( &cur, limit ); 752 753 Store_Integer: 754 switch ( field->size ) 755 { 756 case 1: 757 *(FT_Byte*)q = (FT_Byte)val; 758 break; 759 760 case 2: 761 *(FT_UShort*)q = (FT_UShort)val; 762 break; 763 764 default: 765 *(FT_Long*)q = val; 766 } 767 break; 768 769 case t1_field_string: 770 { 771 FT_Memory memory = parser->memory; 772 FT_UInt len = limit-cur; 773 774 775 if ( ALLOC( string, len + 1 ) ) 776 goto Exit; 777 778 MEM_Copy( string, cur, len ); 779 string[len] = 0; 780 781 *(FT_String**)q = string; 782 } 783 break; 784 785 default: 786 /* an error occured */ 787 goto Fail; 788 } 789 } 790 791 error = 0; 792 793 Exit: 794 return error; 795 796 Fail: 797 error = T1_Err_Invalid_File_Format; 798 goto Exit; 799 } 800 801 802#define T1_MAX_TABLE_ELEMENTS 32 803 804 805 LOCAL_FUNC 806 FT_Error CID_Load_Field_Table( CID_Parser* parser, 807 const CID_Field_Rec* field, 808 void* object ) 809 { 810 CID_Token_Rec elements[T1_MAX_TABLE_ELEMENTS]; 811 CID_Token_Rec* token; 812 FT_Int num_elements; 813 FT_Error error = 0; 814 FT_Byte* old_cursor; 815 FT_Byte* old_limit; 816 CID_Field_Rec fieldrec = *(CID_Field_Rec*)field; 817 818 819 fieldrec.type = t1_field_integer; 820 if ( field->type == t1_field_fixed_array ) 821 fieldrec.type = t1_field_fixed; 822 823 CID_ToTokenArray( parser, elements, 32, &num_elements ); 824 if ( num_elements < 0 ) 825 goto Fail; 826 827 if ( num_elements > T1_MAX_TABLE_ELEMENTS ) 828 num_elements = T1_MAX_TABLE_ELEMENTS; 829 830 old_cursor = parser->cursor; 831 old_limit = parser->limit; 832 833 /* we store the elements count */ 834 if ( field->count_offset ) 835 *(FT_Byte*)( (FT_Byte*)object + field->count_offset ) = num_elements; 836 837 /* we now load each element, adjusting the field.offset on each one */ 838 token = elements; 839 for ( ; num_elements > 0; num_elements--, token++ ) 840 { 841 parser->cursor = token->start; 842 parser->limit = token->limit; 843 CID_Load_Field( parser, &fieldrec, object ); 844 fieldrec.offset += fieldrec.size; 845 } 846 847 parser->cursor = old_cursor; 848 parser->limit = old_limit; 849 850 Exit: 851 return error; 852 853 Fail: 854 error = T1_Err_Invalid_File_Format; 855 goto Exit; 856 } 857 858 859 LOCAL_FUNC 860 FT_Long CID_ToInt( CID_Parser* parser ) 861 { 862 return t1_toint( &parser->cursor, parser->limit ); 863 } 864 865 866 LOCAL_FUNC 867 FT_Int CID_ToCoordArray( CID_Parser* parser, 868 FT_Int max_coords, 869 FT_Short* coords ) 870 { 871 return t1_tocoordarray( &parser->cursor, parser->limit, 872 max_coords, coords ); 873 } 874 875 876 LOCAL_FUNC 877 FT_Int CID_ToFixedArray( CID_Parser* parser, 878 FT_Int max_values, 879 FT_Fixed* values, 880 FT_Int power_ten ) 881 { 882 return t1_tofixedarray( &parser->cursor, parser->limit, 883 max_values, values, power_ten ); 884 } 885 886 887#if 0 888 889 /* return the value of an hexadecimal digit */ 890 static 891 int hexa_value( char c ) 892 { 893 unsigned int d; 894 895 896 d = (unsigned int)( c - '0' ); 897 if ( d <= 9 ) 898 return (int)d; 899 900 d = (unsigned int)( c - 'a' ); 901 if ( d <= 5 ) 902 return (int)( d + 10 ); 903 904 d = (unsigned int)( c - 'A' ); 905 if ( d <= 5 ) 906 return (int)( d + 10 ); 907 908 return -1; 909 } 910 911#endif /* 0 */ 912 913 914 LOCAL_FUNC 915 FT_Error CID_New_Parser( CID_Parser* parser, 916 FT_Stream stream, 917 FT_Memory memory ) 918 { 919 FT_Error error; 920 FT_ULong base_offset, offset, ps_len; 921 FT_Byte buffer[256 + 10]; 922 FT_Int buff_len; 923 924 925 MEM_Set( parser, 0, sizeof ( *parser ) ); 926 parser->stream = stream; 927 parser->memory = memory; 928 929 base_offset = FILE_Pos(); 930 931 /* first of all, check the font format in the header */ 932 if ( ACCESS_Frame( 31 ) ) 933 goto Exit; 934 935 if ( strncmp( stream->cursor, "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) 936 { 937 FT_TRACE2(( "[not a valid CID-keyed font]\n" )); 938 error = FT_Err_Unknown_File_Format; 939 } 940 941 FORGET_Frame(); 942 if ( error ) 943 goto Exit; 944 945 /* now, read the rest of the file, until we find a `StartData' */ 946 buff_len = 256; 947 for (;;) 948 { 949 FT_Byte *p, *limit = buffer + 256; 950 951 /* fill input buffer */ 952 buff_len -= 256; 953 if ( buff_len > 0 ) 954 MEM_Move( buffer, limit, buff_len ); 955 956 if ( FILE_Read( buffer, 256 + 10 - buff_len ) ) 957 goto Exit; 958 959 buff_len = 256 + 10; 960 961 /* look for "StartData" */ 962 for ( p = buffer; p < limit; p++ ) 963 { 964 if ( p[0] == 'S' && strncmp( (char*)p, "StartData", 9 ) == 0 ) 965 { 966 /* save offset of binary data after "StartData" */ 967 offset = FILE_Pos() - ( limit - p ) + 10; 968 goto Found; 969 } 970 } 971 } 972 973 Found: 974 /* all right, we found the start of the binary data. We will now */ 975 /* rewind and extract the frame of corresponding to the Postscript */ 976 /* section */ 977 978 ps_len = offset - base_offset; 979 if ( FILE_Seek( base_offset ) || 980 EXTRACT_Frame( ps_len, parser->postscript ) ) 981 goto Exit; 982 983 parser->data_offset = offset; 984 parser->postscript_len = ps_len; 985 parser->cursor = parser->postscript; 986 parser->limit = parser->cursor + ps_len; 987 parser->num_dict = -1; 988 989 Exit: 990 return error; 991 } 992 993 994 LOCAL_FUNC 995 void CID_Done_Parser( CID_Parser* parser ) 996 { 997 /* always free the private dictionary */ 998 if ( parser->postscript ) 999 { 1000 FT_Stream stream = parser->stream; 1001 1002 1003 RELEASE_Frame( parser->postscript ); 1004 } 1005 } 1006 1007 1008/* END */ 1009