1 /***************************************************************************/ 2 /* */ 3 /* ftstream.c */ 4 /* */ 5 /* I/O stream support (body). */ 6 /* */ 7 /* Copyright 2000-2002, 2004-2006, 2008-2011 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_STREAM_H 21 #include FT_INTERNAL_DEBUG_H 22 23 24 /*************************************************************************/ 25 /* */ 26 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 27 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 28 /* messages during execution. */ 29 /* */ 30 #undef FT_COMPONENT 31 #define FT_COMPONENT trace_stream 32 33 34 FT_BASE_DEF( void ) FT_Stream_OpenMemory(FT_Stream stream,const FT_Byte * base,FT_ULong size)35 FT_Stream_OpenMemory( FT_Stream stream, 36 const FT_Byte* base, 37 FT_ULong size ) 38 { 39 stream->base = (FT_Byte*) base; 40 stream->size = size; 41 stream->pos = 0; 42 stream->cursor = 0; 43 stream->read = 0; 44 stream->close = 0; 45 } 46 47 48 FT_BASE_DEF( void ) FT_Stream_Close(FT_Stream stream)49 FT_Stream_Close( FT_Stream stream ) 50 { 51 if ( stream && stream->close ) 52 stream->close( stream ); 53 } 54 55 56 FT_BASE_DEF( FT_Error ) FT_Stream_Seek(FT_Stream stream,FT_ULong pos)57 FT_Stream_Seek( FT_Stream stream, 58 FT_ULong pos ) 59 { 60 FT_Error error = FT_Err_Ok; 61 62 63 if ( stream->read ) 64 { 65 if ( stream->read( stream, pos, 0, 0 ) ) 66 { 67 FT_ERROR(( "FT_Stream_Seek:" 68 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 69 pos, stream->size )); 70 71 error = FT_Err_Invalid_Stream_Operation; 72 } 73 } 74 /* note that seeking to the first position after the file is valid */ 75 else if ( pos > stream->size ) 76 { 77 FT_ERROR(( "FT_Stream_Seek:" 78 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 79 pos, stream->size )); 80 81 error = FT_Err_Invalid_Stream_Operation; 82 } 83 84 if ( !error ) 85 stream->pos = pos; 86 87 return error; 88 } 89 90 91 FT_BASE_DEF( FT_Error ) FT_Stream_Skip(FT_Stream stream,FT_Long distance)92 FT_Stream_Skip( FT_Stream stream, 93 FT_Long distance ) 94 { 95 if ( distance < 0 ) 96 return FT_Err_Invalid_Stream_Operation; 97 98 return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) ); 99 } 100 101 102 FT_BASE_DEF( FT_Long ) FT_Stream_Pos(FT_Stream stream)103 FT_Stream_Pos( FT_Stream stream ) 104 { 105 return stream->pos; 106 } 107 108 109 FT_BASE_DEF( FT_Error ) FT_Stream_Read(FT_Stream stream,FT_Byte * buffer,FT_ULong count)110 FT_Stream_Read( FT_Stream stream, 111 FT_Byte* buffer, 112 FT_ULong count ) 113 { 114 return FT_Stream_ReadAt( stream, stream->pos, buffer, count ); 115 } 116 117 118 FT_BASE_DEF( FT_Error ) FT_Stream_ReadAt(FT_Stream stream,FT_ULong pos,FT_Byte * buffer,FT_ULong count)119 FT_Stream_ReadAt( FT_Stream stream, 120 FT_ULong pos, 121 FT_Byte* buffer, 122 FT_ULong count ) 123 { 124 FT_Error error = FT_Err_Ok; 125 FT_ULong read_bytes; 126 127 128 if ( pos >= stream->size ) 129 { 130 FT_ERROR(( "FT_Stream_ReadAt:" 131 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 132 pos, stream->size )); 133 134 return FT_Err_Invalid_Stream_Operation; 135 } 136 137 if ( stream->read ) 138 read_bytes = stream->read( stream, pos, buffer, count ); 139 else 140 { 141 read_bytes = stream->size - pos; 142 if ( read_bytes > count ) 143 read_bytes = count; 144 145 FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); 146 } 147 148 stream->pos = pos + read_bytes; 149 150 if ( read_bytes < count ) 151 { 152 FT_ERROR(( "FT_Stream_ReadAt:" 153 " invalid read; expected %lu bytes, got %lu\n", 154 count, read_bytes )); 155 156 error = FT_Err_Invalid_Stream_Operation; 157 } 158 159 return error; 160 } 161 162 163 FT_BASE_DEF( FT_ULong ) FT_Stream_TryRead(FT_Stream stream,FT_Byte * buffer,FT_ULong count)164 FT_Stream_TryRead( FT_Stream stream, 165 FT_Byte* buffer, 166 FT_ULong count ) 167 { 168 FT_ULong read_bytes = 0; 169 170 171 if ( stream->pos >= stream->size ) 172 goto Exit; 173 174 if ( stream->read ) 175 read_bytes = stream->read( stream, stream->pos, buffer, count ); 176 else 177 { 178 read_bytes = stream->size - stream->pos; 179 if ( read_bytes > count ) 180 read_bytes = count; 181 182 FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes ); 183 } 184 185 stream->pos += read_bytes; 186 187 Exit: 188 return read_bytes; 189 } 190 191 192 FT_BASE_DEF( FT_Error ) FT_Stream_ExtractFrame(FT_Stream stream,FT_ULong count,FT_Byte ** pbytes)193 FT_Stream_ExtractFrame( FT_Stream stream, 194 FT_ULong count, 195 FT_Byte** pbytes ) 196 { 197 FT_Error error; 198 199 200 error = FT_Stream_EnterFrame( stream, count ); 201 if ( !error ) 202 { 203 *pbytes = (FT_Byte*)stream->cursor; 204 205 /* equivalent to FT_Stream_ExitFrame(), with no memory block release */ 206 stream->cursor = 0; 207 stream->limit = 0; 208 } 209 210 return error; 211 } 212 213 214 FT_BASE_DEF( void ) FT_Stream_ReleaseFrame(FT_Stream stream,FT_Byte ** pbytes)215 FT_Stream_ReleaseFrame( FT_Stream stream, 216 FT_Byte** pbytes ) 217 { 218 if ( stream && stream->read ) 219 { 220 FT_Memory memory = stream->memory; 221 222 #ifdef FT_DEBUG_MEMORY 223 ft_mem_free( memory, *pbytes ); 224 *pbytes = NULL; 225 #else 226 FT_FREE( *pbytes ); 227 #endif 228 } 229 *pbytes = 0; 230 } 231 232 233 FT_BASE_DEF( FT_Error ) FT_Stream_EnterFrame(FT_Stream stream,FT_ULong count)234 FT_Stream_EnterFrame( FT_Stream stream, 235 FT_ULong count ) 236 { 237 FT_Error error = FT_Err_Ok; 238 FT_ULong read_bytes; 239 240 241 /* check for nested frame access */ 242 FT_ASSERT( stream && stream->cursor == 0 ); 243 244 if ( stream->read ) 245 { 246 /* allocate the frame in memory */ 247 FT_Memory memory = stream->memory; 248 249 250 /* simple sanity check */ 251 if ( count > stream->size ) 252 { 253 FT_ERROR(( "FT_Stream_EnterFrame:" 254 " frame size (%lu) larger than stream size (%lu)\n", 255 count, stream->size )); 256 257 error = FT_Err_Invalid_Stream_Operation; 258 goto Exit; 259 } 260 261 #ifdef FT_DEBUG_MEMORY 262 /* assume _ft_debug_file and _ft_debug_lineno are already set */ 263 stream->base = (unsigned char*)ft_mem_qalloc( memory, count, &error ); 264 if ( error ) 265 goto Exit; 266 #else 267 if ( FT_QALLOC( stream->base, count ) ) 268 goto Exit; 269 #endif 270 /* read it */ 271 read_bytes = stream->read( stream, stream->pos, 272 stream->base, count ); 273 if ( read_bytes < count ) 274 { 275 FT_ERROR(( "FT_Stream_EnterFrame:" 276 " invalid read; expected %lu bytes, got %lu\n", 277 count, read_bytes )); 278 279 FT_FREE( stream->base ); 280 error = FT_Err_Invalid_Stream_Operation; 281 } 282 stream->cursor = stream->base; 283 stream->limit = stream->cursor + count; 284 stream->pos += read_bytes; 285 } 286 else 287 { 288 /* check current and new position */ 289 if ( stream->pos >= stream->size || 290 stream->size - stream->pos < count ) 291 { 292 FT_ERROR(( "FT_Stream_EnterFrame:" 293 " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", 294 stream->pos, count, stream->size )); 295 296 error = FT_Err_Invalid_Stream_Operation; 297 goto Exit; 298 } 299 300 /* set cursor */ 301 stream->cursor = stream->base + stream->pos; 302 stream->limit = stream->cursor + count; 303 stream->pos += count; 304 } 305 306 Exit: 307 return error; 308 } 309 310 311 FT_BASE_DEF( void ) FT_Stream_ExitFrame(FT_Stream stream)312 FT_Stream_ExitFrame( FT_Stream stream ) 313 { 314 /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ 315 /* that it is possible to access a frame of length 0 in */ 316 /* some weird fonts (usually, when accessing an array of */ 317 /* 0 records, like in some strange kern tables). */ 318 /* */ 319 /* In this case, the loader code handles the 0-length table */ 320 /* gracefully; however, stream.cursor is really set to 0 by the */ 321 /* FT_Stream_EnterFrame() call, and this is not an error. */ 322 /* */ 323 FT_ASSERT( stream ); 324 325 if ( stream->read ) 326 { 327 FT_Memory memory = stream->memory; 328 329 #ifdef FT_DEBUG_MEMORY 330 ft_mem_free( memory, stream->base ); 331 stream->base = NULL; 332 #else 333 FT_FREE( stream->base ); 334 #endif 335 } 336 stream->cursor = 0; 337 stream->limit = 0; 338 } 339 340 341 FT_BASE_DEF( FT_Char ) FT_Stream_GetChar(FT_Stream stream)342 FT_Stream_GetChar( FT_Stream stream ) 343 { 344 FT_Char result; 345 346 347 FT_ASSERT( stream && stream->cursor ); 348 349 result = 0; 350 if ( stream->cursor < stream->limit ) 351 result = *stream->cursor++; 352 353 return result; 354 } 355 356 357 FT_BASE_DEF( FT_UShort ) FT_Stream_GetUShort(FT_Stream stream)358 FT_Stream_GetUShort( FT_Stream stream ) 359 { 360 FT_Byte* p; 361 FT_Short result; 362 363 364 FT_ASSERT( stream && stream->cursor ); 365 366 result = 0; 367 p = stream->cursor; 368 if ( p + 1 < stream->limit ) 369 result = FT_NEXT_USHORT( p ); 370 stream->cursor = p; 371 372 return result; 373 } 374 375 376 FT_BASE_DEF( FT_UShort ) FT_Stream_GetUShortLE(FT_Stream stream)377 FT_Stream_GetUShortLE( FT_Stream stream ) 378 { 379 FT_Byte* p; 380 FT_Short result; 381 382 383 FT_ASSERT( stream && stream->cursor ); 384 385 result = 0; 386 p = stream->cursor; 387 if ( p + 1 < stream->limit ) 388 result = FT_NEXT_USHORT_LE( p ); 389 stream->cursor = p; 390 391 return result; 392 } 393 394 395 FT_BASE_DEF( FT_ULong ) FT_Stream_GetUOffset(FT_Stream stream)396 FT_Stream_GetUOffset( FT_Stream stream ) 397 { 398 FT_Byte* p; 399 FT_Long result; 400 401 402 FT_ASSERT( stream && stream->cursor ); 403 404 result = 0; 405 p = stream->cursor; 406 if ( p + 2 < stream->limit ) 407 result = FT_NEXT_UOFF3( p ); 408 stream->cursor = p; 409 return result; 410 } 411 412 413 FT_BASE_DEF( FT_ULong ) FT_Stream_GetULong(FT_Stream stream)414 FT_Stream_GetULong( FT_Stream stream ) 415 { 416 FT_Byte* p; 417 FT_Long result; 418 419 420 FT_ASSERT( stream && stream->cursor ); 421 422 result = 0; 423 p = stream->cursor; 424 if ( p + 3 < stream->limit ) 425 result = FT_NEXT_ULONG( p ); 426 stream->cursor = p; 427 return result; 428 } 429 430 431 FT_BASE_DEF( FT_ULong ) FT_Stream_GetULongLE(FT_Stream stream)432 FT_Stream_GetULongLE( FT_Stream stream ) 433 { 434 FT_Byte* p; 435 FT_Long result; 436 437 438 FT_ASSERT( stream && stream->cursor ); 439 440 result = 0; 441 p = stream->cursor; 442 if ( p + 3 < stream->limit ) 443 result = FT_NEXT_ULONG_LE( p ); 444 stream->cursor = p; 445 return result; 446 } 447 448 449 FT_BASE_DEF( FT_Char ) FT_Stream_ReadChar(FT_Stream stream,FT_Error * error)450 FT_Stream_ReadChar( FT_Stream stream, 451 FT_Error* error ) 452 { 453 FT_Byte result = 0; 454 455 456 FT_ASSERT( stream ); 457 458 *error = FT_Err_Ok; 459 460 if ( stream->read ) 461 { 462 if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) 463 goto Fail; 464 } 465 else 466 { 467 if ( stream->pos < stream->size ) 468 result = stream->base[stream->pos]; 469 else 470 goto Fail; 471 } 472 stream->pos++; 473 474 return result; 475 476 Fail: 477 *error = FT_Err_Invalid_Stream_Operation; 478 FT_ERROR(( "FT_Stream_ReadChar:" 479 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 480 stream->pos, stream->size )); 481 482 return 0; 483 } 484 485 486 FT_BASE_DEF( FT_UShort ) FT_Stream_ReadUShort(FT_Stream stream,FT_Error * error)487 FT_Stream_ReadUShort( FT_Stream stream, 488 FT_Error* error ) 489 { 490 FT_Byte reads[2]; 491 FT_Byte* p = 0; 492 FT_Short result = 0; 493 494 495 FT_ASSERT( stream ); 496 497 *error = FT_Err_Ok; 498 499 if ( stream->pos + 1 < stream->size ) 500 { 501 if ( stream->read ) 502 { 503 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) 504 goto Fail; 505 506 p = reads; 507 } 508 else 509 { 510 p = stream->base + stream->pos; 511 } 512 513 if ( p ) 514 result = FT_NEXT_USHORT( p ); 515 } 516 else 517 goto Fail; 518 519 stream->pos += 2; 520 521 return result; 522 523 Fail: 524 *error = FT_Err_Invalid_Stream_Operation; 525 FT_ERROR(( "FT_Stream_ReadUShort:" 526 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 527 stream->pos, stream->size )); 528 529 return 0; 530 } 531 532 533 FT_BASE_DEF( FT_UShort ) FT_Stream_ReadUShortLE(FT_Stream stream,FT_Error * error)534 FT_Stream_ReadUShortLE( FT_Stream stream, 535 FT_Error* error ) 536 { 537 FT_Byte reads[2]; 538 FT_Byte* p = 0; 539 FT_Short result = 0; 540 541 542 FT_ASSERT( stream ); 543 544 *error = FT_Err_Ok; 545 546 if ( stream->pos + 1 < stream->size ) 547 { 548 if ( stream->read ) 549 { 550 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) 551 goto Fail; 552 553 p = reads; 554 } 555 else 556 { 557 p = stream->base + stream->pos; 558 } 559 560 if ( p ) 561 result = FT_NEXT_USHORT_LE( p ); 562 } 563 else 564 goto Fail; 565 566 stream->pos += 2; 567 568 return result; 569 570 Fail: 571 *error = FT_Err_Invalid_Stream_Operation; 572 FT_ERROR(( "FT_Stream_ReadUShortLE:" 573 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 574 stream->pos, stream->size )); 575 576 return 0; 577 } 578 579 580 FT_BASE_DEF( FT_ULong ) FT_Stream_ReadUOffset(FT_Stream stream,FT_Error * error)581 FT_Stream_ReadUOffset( FT_Stream stream, 582 FT_Error* error ) 583 { 584 FT_Byte reads[3]; 585 FT_Byte* p = 0; 586 FT_Long result = 0; 587 588 589 FT_ASSERT( stream ); 590 591 *error = FT_Err_Ok; 592 593 if ( stream->pos + 2 < stream->size ) 594 { 595 if ( stream->read ) 596 { 597 if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) 598 goto Fail; 599 600 p = reads; 601 } 602 else 603 { 604 p = stream->base + stream->pos; 605 } 606 607 if ( p ) 608 result = FT_NEXT_UOFF3( p ); 609 } 610 else 611 goto Fail; 612 613 stream->pos += 3; 614 615 return result; 616 617 Fail: 618 *error = FT_Err_Invalid_Stream_Operation; 619 FT_ERROR(( "FT_Stream_ReadUOffset:" 620 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 621 stream->pos, stream->size )); 622 623 return 0; 624 } 625 626 627 FT_BASE_DEF( FT_ULong ) FT_Stream_ReadULong(FT_Stream stream,FT_Error * error)628 FT_Stream_ReadULong( FT_Stream stream, 629 FT_Error* error ) 630 { 631 FT_Byte reads[4]; 632 FT_Byte* p = 0; 633 FT_Long result = 0; 634 635 636 FT_ASSERT( stream ); 637 638 *error = FT_Err_Ok; 639 640 if ( stream->pos + 3 < stream->size ) 641 { 642 if ( stream->read ) 643 { 644 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) 645 goto Fail; 646 647 p = reads; 648 } 649 else 650 { 651 p = stream->base + stream->pos; 652 } 653 654 if ( p ) 655 result = FT_NEXT_ULONG( p ); 656 } 657 else 658 goto Fail; 659 660 stream->pos += 4; 661 662 return result; 663 664 Fail: 665 *error = FT_Err_Invalid_Stream_Operation; 666 FT_ERROR(( "FT_Stream_ReadULong:" 667 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 668 stream->pos, stream->size )); 669 670 return 0; 671 } 672 673 674 FT_BASE_DEF( FT_ULong ) FT_Stream_ReadULongLE(FT_Stream stream,FT_Error * error)675 FT_Stream_ReadULongLE( FT_Stream stream, 676 FT_Error* error ) 677 { 678 FT_Byte reads[4]; 679 FT_Byte* p = 0; 680 FT_Long result = 0; 681 682 683 FT_ASSERT( stream ); 684 685 *error = FT_Err_Ok; 686 687 if ( stream->pos + 3 < stream->size ) 688 { 689 if ( stream->read ) 690 { 691 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) 692 goto Fail; 693 694 p = reads; 695 } 696 else 697 { 698 p = stream->base + stream->pos; 699 } 700 701 if ( p ) 702 result = FT_NEXT_ULONG_LE( p ); 703 } 704 else 705 goto Fail; 706 707 stream->pos += 4; 708 709 return result; 710 711 Fail: 712 *error = FT_Err_Invalid_Stream_Operation; 713 FT_ERROR(( "FT_Stream_ReadULongLE:" 714 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 715 stream->pos, stream->size )); 716 717 return 0; 718 } 719 720 721 FT_BASE_DEF( FT_Error ) FT_Stream_ReadFields(FT_Stream stream,const FT_Frame_Field * fields,void * structure)722 FT_Stream_ReadFields( FT_Stream stream, 723 const FT_Frame_Field* fields, 724 void* structure ) 725 { 726 FT_Error error; 727 FT_Bool frame_accessed = 0; 728 FT_Byte* cursor; 729 730 if ( !fields || !stream ) 731 return FT_Err_Invalid_Argument; 732 733 cursor = stream->cursor; 734 735 error = FT_Err_Ok; 736 do 737 { 738 FT_ULong value; 739 FT_Int sign_shift; 740 FT_Byte* p; 741 742 743 switch ( fields->value ) 744 { 745 case ft_frame_start: /* access a new frame */ 746 error = FT_Stream_EnterFrame( stream, fields->offset ); 747 if ( error ) 748 goto Exit; 749 750 frame_accessed = 1; 751 cursor = stream->cursor; 752 fields++; 753 continue; /* loop! */ 754 755 case ft_frame_bytes: /* read a byte sequence */ 756 case ft_frame_skip: /* skip some bytes */ 757 { 758 FT_UInt len = fields->size; 759 760 761 if ( cursor + len > stream->limit ) 762 { 763 error = FT_Err_Invalid_Stream_Operation; 764 goto Exit; 765 } 766 767 if ( fields->value == ft_frame_bytes ) 768 { 769 p = (FT_Byte*)structure + fields->offset; 770 FT_MEM_COPY( p, cursor, len ); 771 } 772 cursor += len; 773 fields++; 774 continue; 775 } 776 777 case ft_frame_byte: 778 case ft_frame_schar: /* read a single byte */ 779 value = FT_NEXT_BYTE(cursor); 780 sign_shift = 24; 781 break; 782 783 case ft_frame_short_be: 784 case ft_frame_ushort_be: /* read a 2-byte big-endian short */ 785 value = FT_NEXT_USHORT(cursor); 786 sign_shift = 16; 787 break; 788 789 case ft_frame_short_le: 790 case ft_frame_ushort_le: /* read a 2-byte little-endian short */ 791 value = FT_NEXT_USHORT_LE(cursor); 792 sign_shift = 16; 793 break; 794 795 case ft_frame_long_be: 796 case ft_frame_ulong_be: /* read a 4-byte big-endian long */ 797 value = FT_NEXT_ULONG(cursor); 798 sign_shift = 0; 799 break; 800 801 case ft_frame_long_le: 802 case ft_frame_ulong_le: /* read a 4-byte little-endian long */ 803 value = FT_NEXT_ULONG_LE(cursor); 804 sign_shift = 0; 805 break; 806 807 case ft_frame_off3_be: 808 case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ 809 value = FT_NEXT_UOFF3(cursor); 810 sign_shift = 8; 811 break; 812 813 case ft_frame_off3_le: 814 case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ 815 value = FT_NEXT_UOFF3_LE(cursor); 816 sign_shift = 8; 817 break; 818 819 default: 820 /* otherwise, exit the loop */ 821 stream->cursor = cursor; 822 goto Exit; 823 } 824 825 /* now, compute the signed value is necessary */ 826 if ( fields->value & FT_FRAME_OP_SIGNED ) 827 value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); 828 829 /* finally, store the value in the object */ 830 831 p = (FT_Byte*)structure + fields->offset; 832 switch ( fields->size ) 833 { 834 case (8 / FT_CHAR_BIT): 835 *(FT_Byte*)p = (FT_Byte)value; 836 break; 837 838 case (16 / FT_CHAR_BIT): 839 *(FT_UShort*)p = (FT_UShort)value; 840 break; 841 842 case (32 / FT_CHAR_BIT): 843 *(FT_UInt32*)p = (FT_UInt32)value; 844 break; 845 846 default: /* for 64-bit systems */ 847 *(FT_ULong*)p = (FT_ULong)value; 848 } 849 850 /* go to next field */ 851 fields++; 852 } 853 while ( 1 ); 854 855 Exit: 856 /* close the frame if it was opened by this read */ 857 if ( frame_accessed ) 858 FT_Stream_ExitFrame( stream ); 859 860 return error; 861 } 862 863 864 /* END */ 865