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