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