1 /**************************************************************************** 2 * 3 * ftstream.c 4 * 5 * I/O stream support (body). 6 * 7 * Copyright (C) 2000-2020 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, 0, 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_Char ) FT_Stream_GetChar(FT_Stream stream)351 FT_Stream_GetChar( FT_Stream stream ) 352 { 353 FT_Char result; 354 355 356 FT_ASSERT( stream && stream->cursor ); 357 358 result = 0; 359 if ( stream->cursor < stream->limit ) 360 result = (FT_Char)*stream->cursor++; 361 362 return result; 363 } 364 365 366 FT_BASE_DEF( FT_UShort ) FT_Stream_GetUShort(FT_Stream stream)367 FT_Stream_GetUShort( FT_Stream stream ) 368 { 369 FT_Byte* p; 370 FT_UShort 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_UShort ) FT_Stream_GetUShortLE(FT_Stream stream)386 FT_Stream_GetUShortLE( FT_Stream stream ) 387 { 388 FT_Byte* p; 389 FT_UShort 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_ULong ) FT_Stream_GetUOffset(FT_Stream stream)405 FT_Stream_GetUOffset( FT_Stream stream ) 406 { 407 FT_Byte* p; 408 FT_ULong 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_ULong ) FT_Stream_GetULong(FT_Stream stream)423 FT_Stream_GetULong( FT_Stream stream ) 424 { 425 FT_Byte* p; 426 FT_ULong 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_ULong ) FT_Stream_GetULongLE(FT_Stream stream)441 FT_Stream_GetULongLE( FT_Stream stream ) 442 { 443 FT_Byte* p; 444 FT_ULong 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_Char ) FT_Stream_ReadChar(FT_Stream stream,FT_Error * error)459 FT_Stream_ReadChar( FT_Stream stream, 460 FT_Error* error ) 461 { 462 FT_Byte result = 0; 463 464 465 FT_ASSERT( stream ); 466 467 *error = FT_Err_Ok; 468 469 if ( stream->read ) 470 { 471 if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) 472 goto Fail; 473 } 474 else 475 { 476 if ( stream->pos < stream->size ) 477 result = stream->base[stream->pos]; 478 else 479 goto Fail; 480 } 481 stream->pos++; 482 483 return (FT_Char)result; 484 485 Fail: 486 *error = FT_THROW( Invalid_Stream_Operation ); 487 FT_ERROR(( "FT_Stream_ReadChar:" 488 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 489 stream->pos, stream->size )); 490 491 return 0; 492 } 493 494 495 FT_BASE_DEF( FT_UShort ) FT_Stream_ReadUShort(FT_Stream stream,FT_Error * error)496 FT_Stream_ReadUShort( FT_Stream stream, 497 FT_Error* error ) 498 { 499 FT_Byte reads[2]; 500 FT_Byte* p = 0; 501 FT_UShort result = 0; 502 503 504 FT_ASSERT( stream ); 505 506 *error = FT_Err_Ok; 507 508 if ( stream->pos + 1 < stream->size ) 509 { 510 if ( stream->read ) 511 { 512 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) 513 goto Fail; 514 515 p = reads; 516 } 517 else 518 p = stream->base + stream->pos; 519 520 if ( p ) 521 result = FT_NEXT_USHORT( p ); 522 } 523 else 524 goto Fail; 525 526 stream->pos += 2; 527 528 return result; 529 530 Fail: 531 *error = FT_THROW( Invalid_Stream_Operation ); 532 FT_ERROR(( "FT_Stream_ReadUShort:" 533 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 534 stream->pos, stream->size )); 535 536 return 0; 537 } 538 539 540 FT_BASE_DEF( FT_UShort ) FT_Stream_ReadUShortLE(FT_Stream stream,FT_Error * error)541 FT_Stream_ReadUShortLE( FT_Stream stream, 542 FT_Error* error ) 543 { 544 FT_Byte reads[2]; 545 FT_Byte* p = 0; 546 FT_UShort result = 0; 547 548 549 FT_ASSERT( stream ); 550 551 *error = FT_Err_Ok; 552 553 if ( stream->pos + 1 < stream->size ) 554 { 555 if ( stream->read ) 556 { 557 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) 558 goto Fail; 559 560 p = reads; 561 } 562 else 563 p = stream->base + stream->pos; 564 565 if ( p ) 566 result = FT_NEXT_USHORT_LE( p ); 567 } 568 else 569 goto Fail; 570 571 stream->pos += 2; 572 573 return result; 574 575 Fail: 576 *error = FT_THROW( Invalid_Stream_Operation ); 577 FT_ERROR(( "FT_Stream_ReadUShortLE:" 578 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 579 stream->pos, stream->size )); 580 581 return 0; 582 } 583 584 585 FT_BASE_DEF( FT_ULong ) FT_Stream_ReadUOffset(FT_Stream stream,FT_Error * error)586 FT_Stream_ReadUOffset( FT_Stream stream, 587 FT_Error* error ) 588 { 589 FT_Byte reads[3]; 590 FT_Byte* p = 0; 591 FT_ULong result = 0; 592 593 594 FT_ASSERT( stream ); 595 596 *error = FT_Err_Ok; 597 598 if ( stream->pos + 2 < stream->size ) 599 { 600 if ( stream->read ) 601 { 602 if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) 603 goto Fail; 604 605 p = reads; 606 } 607 else 608 p = stream->base + stream->pos; 609 610 if ( p ) 611 result = FT_NEXT_UOFF3( p ); 612 } 613 else 614 goto Fail; 615 616 stream->pos += 3; 617 618 return result; 619 620 Fail: 621 *error = FT_THROW( Invalid_Stream_Operation ); 622 FT_ERROR(( "FT_Stream_ReadUOffset:" 623 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 624 stream->pos, stream->size )); 625 626 return 0; 627 } 628 629 630 FT_BASE_DEF( FT_ULong ) FT_Stream_ReadULong(FT_Stream stream,FT_Error * error)631 FT_Stream_ReadULong( FT_Stream stream, 632 FT_Error* error ) 633 { 634 FT_Byte reads[4]; 635 FT_Byte* p = 0; 636 FT_ULong result = 0; 637 638 639 FT_ASSERT( stream ); 640 641 *error = FT_Err_Ok; 642 643 if ( stream->pos + 3 < stream->size ) 644 { 645 if ( stream->read ) 646 { 647 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) 648 goto Fail; 649 650 p = reads; 651 } 652 else 653 p = stream->base + stream->pos; 654 655 if ( p ) 656 result = FT_NEXT_ULONG( p ); 657 } 658 else 659 goto Fail; 660 661 stream->pos += 4; 662 663 return result; 664 665 Fail: 666 *error = FT_THROW( Invalid_Stream_Operation ); 667 FT_ERROR(( "FT_Stream_ReadULong:" 668 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 669 stream->pos, stream->size )); 670 671 return 0; 672 } 673 674 675 FT_BASE_DEF( FT_ULong ) FT_Stream_ReadULongLE(FT_Stream stream,FT_Error * error)676 FT_Stream_ReadULongLE( FT_Stream stream, 677 FT_Error* error ) 678 { 679 FT_Byte reads[4]; 680 FT_Byte* p = 0; 681 FT_ULong result = 0; 682 683 684 FT_ASSERT( stream ); 685 686 *error = FT_Err_Ok; 687 688 if ( stream->pos + 3 < stream->size ) 689 { 690 if ( stream->read ) 691 { 692 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) 693 goto Fail; 694 695 p = reads; 696 } 697 else 698 p = stream->base + stream->pos; 699 700 if ( p ) 701 result = FT_NEXT_ULONG_LE( p ); 702 } 703 else 704 goto Fail; 705 706 stream->pos += 4; 707 708 return result; 709 710 Fail: 711 *error = FT_THROW( Invalid_Stream_Operation ); 712 FT_ERROR(( "FT_Stream_ReadULongLE:" 713 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 714 stream->pos, stream->size )); 715 716 return 0; 717 } 718 719 720 FT_BASE_DEF( FT_Error ) FT_Stream_ReadFields(FT_Stream stream,const FT_Frame_Field * fields,void * structure)721 FT_Stream_ReadFields( FT_Stream stream, 722 const FT_Frame_Field* fields, 723 void* structure ) 724 { 725 FT_Error error; 726 FT_Bool frame_accessed = 0; 727 FT_Byte* cursor; 728 729 730 if ( !fields ) 731 return FT_THROW( Invalid_Argument ); 732 733 if ( !stream ) 734 return FT_THROW( Invalid_Stream_Handle ); 735 736 cursor = stream->cursor; 737 738 error = FT_Err_Ok; 739 do 740 { 741 FT_ULong value; 742 FT_Int sign_shift; 743 FT_Byte* p; 744 745 746 switch ( fields->value ) 747 { 748 case ft_frame_start: /* access a new frame */ 749 error = FT_Stream_EnterFrame( stream, fields->offset ); 750 if ( error ) 751 goto Exit; 752 753 frame_accessed = 1; 754 cursor = stream->cursor; 755 fields++; 756 continue; /* loop! */ 757 758 case ft_frame_bytes: /* read a byte sequence */ 759 case ft_frame_skip: /* skip some bytes */ 760 { 761 FT_UInt len = fields->size; 762 763 764 if ( cursor + len > stream->limit ) 765 { 766 error = FT_THROW( Invalid_Stream_Operation ); 767 goto Exit; 768 } 769 770 if ( fields->value == ft_frame_bytes ) 771 { 772 p = (FT_Byte*)structure + fields->offset; 773 FT_MEM_COPY( p, cursor, len ); 774 } 775 cursor += len; 776 fields++; 777 continue; 778 } 779 780 case ft_frame_byte: 781 case ft_frame_schar: /* read a single byte */ 782 value = FT_NEXT_BYTE( cursor ); 783 sign_shift = 24; 784 break; 785 786 case ft_frame_short_be: 787 case ft_frame_ushort_be: /* read a 2-byte big-endian short */ 788 value = FT_NEXT_USHORT( cursor ); 789 sign_shift = 16; 790 break; 791 792 case ft_frame_short_le: 793 case ft_frame_ushort_le: /* read a 2-byte little-endian short */ 794 value = FT_NEXT_USHORT_LE( cursor ); 795 sign_shift = 16; 796 break; 797 798 case ft_frame_long_be: 799 case ft_frame_ulong_be: /* read a 4-byte big-endian long */ 800 value = FT_NEXT_ULONG( cursor ); 801 sign_shift = 0; 802 break; 803 804 case ft_frame_long_le: 805 case ft_frame_ulong_le: /* read a 4-byte little-endian long */ 806 value = FT_NEXT_ULONG_LE( cursor ); 807 sign_shift = 0; 808 break; 809 810 case ft_frame_off3_be: 811 case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ 812 value = FT_NEXT_UOFF3( cursor ); 813 sign_shift = 8; 814 break; 815 816 case ft_frame_off3_le: 817 case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ 818 value = FT_NEXT_UOFF3_LE( cursor ); 819 sign_shift = 8; 820 break; 821 822 default: 823 /* otherwise, exit the loop */ 824 stream->cursor = cursor; 825 goto Exit; 826 } 827 828 /* now, compute the signed value is necessary */ 829 if ( fields->value & FT_FRAME_OP_SIGNED ) 830 value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); 831 832 /* finally, store the value in the object */ 833 834 p = (FT_Byte*)structure + fields->offset; 835 switch ( fields->size ) 836 { 837 case ( 8 / FT_CHAR_BIT ): 838 *(FT_Byte*)p = (FT_Byte)value; 839 break; 840 841 case ( 16 / FT_CHAR_BIT ): 842 *(FT_UShort*)p = (FT_UShort)value; 843 break; 844 845 case ( 32 / FT_CHAR_BIT ): 846 *(FT_UInt32*)p = (FT_UInt32)value; 847 break; 848 849 default: /* for 64-bit systems */ 850 *(FT_ULong*)p = (FT_ULong)value; 851 } 852 853 /* go to next field */ 854 fields++; 855 } 856 while ( 1 ); 857 858 Exit: 859 /* close the frame if it was opened by this read */ 860 if ( frame_accessed ) 861 FT_Stream_ExitFrame( stream ); 862 863 return error; 864 } 865 866 867 /* END */ 868