1 /**************************************************************************** 2 * 3 * ftstream.c 4 * 5 * I/O stream support (body). 6 * 7 * Copyright (C) 2000-2019 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 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 = NULL; 43 stream->read = NULL; 44 stream->close = NULL; 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_THROW( 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_THROW( 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_THROW( Invalid_Stream_Operation ); 97 98 return FT_Stream_Seek( stream, stream->pos + (FT_ULong)distance ); 99 } 100 101 102 FT_BASE_DEF( FT_ULong ) 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_THROW( 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_THROW( 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 = NULL; 207 stream->limit = NULL; 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 223 #ifdef FT_DEBUG_MEMORY 224 ft_mem_free( memory, *pbytes ); 225 #else 226 FT_FREE( *pbytes ); 227 #endif 228 } 229 230 *pbytes = NULL; 231 } 232 233 234 FT_BASE_DEF( FT_Error ) FT_Stream_EnterFrame(FT_Stream stream,FT_ULong count)235 FT_Stream_EnterFrame( FT_Stream stream, 236 FT_ULong count ) 237 { 238 FT_Error error = FT_Err_Ok; 239 FT_ULong read_bytes; 240 241 242 FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count )); 243 244 /* check for nested frame access */ 245 FT_ASSERT( stream && stream->cursor == 0 ); 246 247 if ( stream->read ) 248 { 249 /* allocate the frame in memory */ 250 FT_Memory memory = stream->memory; 251 252 253 /* simple sanity check */ 254 if ( count > stream->size ) 255 { 256 FT_ERROR(( "FT_Stream_EnterFrame:" 257 " frame size (%lu) larger than stream size (%lu)\n", 258 count, stream->size )); 259 260 error = FT_THROW( Invalid_Stream_Operation ); 261 goto Exit; 262 } 263 264 #ifdef FT_DEBUG_MEMORY 265 /* assume _ft_debug_file and _ft_debug_lineno are already set */ 266 stream->base = (unsigned char*)ft_mem_qalloc( memory, 267 (FT_Long)count, 268 &error ); 269 if ( error ) 270 goto Exit; 271 #else 272 if ( FT_QALLOC( stream->base, count ) ) 273 goto Exit; 274 #endif 275 /* read it */ 276 read_bytes = stream->read( stream, stream->pos, 277 stream->base, count ); 278 if ( read_bytes < count ) 279 { 280 FT_ERROR(( "FT_Stream_EnterFrame:" 281 " invalid read; expected %lu bytes, got %lu\n", 282 count, read_bytes )); 283 284 FT_FREE( stream->base ); 285 error = FT_THROW( Invalid_Stream_Operation ); 286 } 287 288 stream->cursor = stream->base; 289 stream->limit = stream->cursor + count; 290 stream->pos += read_bytes; 291 } 292 else 293 { 294 /* check current and new position */ 295 if ( stream->pos >= stream->size || 296 stream->size - stream->pos < count ) 297 { 298 FT_ERROR(( "FT_Stream_EnterFrame:" 299 " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", 300 stream->pos, count, stream->size )); 301 302 error = FT_THROW( Invalid_Stream_Operation ); 303 goto Exit; 304 } 305 306 /* set cursor */ 307 stream->cursor = stream->base + stream->pos; 308 stream->limit = stream->cursor + count; 309 stream->pos += count; 310 } 311 312 Exit: 313 return error; 314 } 315 316 317 FT_BASE_DEF( void ) FT_Stream_ExitFrame(FT_Stream stream)318 FT_Stream_ExitFrame( FT_Stream stream ) 319 { 320 /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ 321 /* that it is possible to access a frame of length 0 in */ 322 /* some weird fonts (usually, when accessing an array of */ 323 /* 0 records, like in some strange kern tables). */ 324 /* */ 325 /* In this case, the loader code handles the 0-length table */ 326 /* gracefully; however, stream.cursor is really set to 0 by the */ 327 /* FT_Stream_EnterFrame() call, and this is not an error. */ 328 329 FT_TRACE7(( "FT_Stream_ExitFrame\n" )); 330 331 FT_ASSERT( stream ); 332 333 if ( stream->read ) 334 { 335 FT_Memory memory = stream->memory; 336 337 338 #ifdef FT_DEBUG_MEMORY 339 ft_mem_free( memory, stream->base ); 340 stream->base = NULL; 341 #else 342 FT_FREE( stream->base ); 343 #endif 344 } 345 346 stream->cursor = NULL; 347 stream->limit = NULL; 348 } 349 350 351 FT_BASE_DEF( FT_Char ) FT_Stream_GetChar(FT_Stream stream)352 FT_Stream_GetChar( FT_Stream stream ) 353 { 354 FT_Char result; 355 356 357 FT_ASSERT( stream && stream->cursor ); 358 359 result = 0; 360 if ( stream->cursor < stream->limit ) 361 result = (FT_Char)*stream->cursor++; 362 363 return result; 364 } 365 366 367 FT_BASE_DEF( FT_UShort ) FT_Stream_GetUShort(FT_Stream stream)368 FT_Stream_GetUShort( FT_Stream stream ) 369 { 370 FT_Byte* p; 371 FT_UShort result; 372 373 374 FT_ASSERT( stream && stream->cursor ); 375 376 result = 0; 377 p = stream->cursor; 378 if ( p + 1 < stream->limit ) 379 result = FT_NEXT_USHORT( p ); 380 stream->cursor = p; 381 382 return result; 383 } 384 385 386 FT_BASE_DEF( FT_UShort ) FT_Stream_GetUShortLE(FT_Stream stream)387 FT_Stream_GetUShortLE( FT_Stream stream ) 388 { 389 FT_Byte* p; 390 FT_UShort result; 391 392 393 FT_ASSERT( stream && stream->cursor ); 394 395 result = 0; 396 p = stream->cursor; 397 if ( p + 1 < stream->limit ) 398 result = FT_NEXT_USHORT_LE( p ); 399 stream->cursor = p; 400 401 return result; 402 } 403 404 405 FT_BASE_DEF( FT_ULong ) FT_Stream_GetUOffset(FT_Stream stream)406 FT_Stream_GetUOffset( FT_Stream stream ) 407 { 408 FT_Byte* p; 409 FT_ULong result; 410 411 412 FT_ASSERT( stream && stream->cursor ); 413 414 result = 0; 415 p = stream->cursor; 416 if ( p + 2 < stream->limit ) 417 result = FT_NEXT_UOFF3( p ); 418 stream->cursor = p; 419 return result; 420 } 421 422 423 FT_BASE_DEF( FT_ULong ) FT_Stream_GetULong(FT_Stream stream)424 FT_Stream_GetULong( FT_Stream stream ) 425 { 426 FT_Byte* p; 427 FT_ULong result; 428 429 430 FT_ASSERT( stream && stream->cursor ); 431 432 result = 0; 433 p = stream->cursor; 434 if ( p + 3 < stream->limit ) 435 result = FT_NEXT_ULONG( p ); 436 stream->cursor = p; 437 return result; 438 } 439 440 441 FT_BASE_DEF( FT_ULong ) FT_Stream_GetULongLE(FT_Stream stream)442 FT_Stream_GetULongLE( FT_Stream stream ) 443 { 444 FT_Byte* p; 445 FT_ULong result; 446 447 448 FT_ASSERT( stream && stream->cursor ); 449 450 result = 0; 451 p = stream->cursor; 452 if ( p + 3 < stream->limit ) 453 result = FT_NEXT_ULONG_LE( p ); 454 stream->cursor = p; 455 return result; 456 } 457 458 459 FT_BASE_DEF( FT_Char ) FT_Stream_ReadChar(FT_Stream stream,FT_Error * error)460 FT_Stream_ReadChar( FT_Stream stream, 461 FT_Error* error ) 462 { 463 FT_Byte result = 0; 464 465 466 FT_ASSERT( stream ); 467 468 *error = FT_Err_Ok; 469 470 if ( stream->read ) 471 { 472 if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) 473 goto Fail; 474 } 475 else 476 { 477 if ( stream->pos < stream->size ) 478 result = stream->base[stream->pos]; 479 else 480 goto Fail; 481 } 482 stream->pos++; 483 484 return (FT_Char)result; 485 486 Fail: 487 *error = FT_THROW( Invalid_Stream_Operation ); 488 FT_ERROR(( "FT_Stream_ReadChar:" 489 " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 490 stream->pos, stream->size )); 491 492 return 0; 493 } 494 495 496 FT_BASE_DEF( FT_UShort ) 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 = 0; 502 FT_UShort result = 0; 503 504 505 FT_ASSERT( stream ); 506 507 *error = FT_Err_Ok; 508 509 if ( stream->pos + 1 < stream->size ) 510 { 511 if ( stream->read ) 512 { 513 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) 514 goto Fail; 515 516 p = reads; 517 } 518 else 519 p = stream->base + stream->pos; 520 521 if ( p ) 522 result = FT_NEXT_USHORT( p ); 523 } 524 else 525 goto Fail; 526 527 stream->pos += 2; 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 0; 538 } 539 540 541 FT_BASE_DEF( FT_UShort ) 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 = 0; 547 FT_UShort result = 0; 548 549 550 FT_ASSERT( stream ); 551 552 *error = FT_Err_Ok; 553 554 if ( stream->pos + 1 < stream->size ) 555 { 556 if ( stream->read ) 557 { 558 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) 559 goto Fail; 560 561 p = reads; 562 } 563 else 564 p = stream->base + stream->pos; 565 566 if ( p ) 567 result = FT_NEXT_USHORT_LE( p ); 568 } 569 else 570 goto Fail; 571 572 stream->pos += 2; 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 0; 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 = 0; 592 FT_ULong result = 0; 593 594 595 FT_ASSERT( stream ); 596 597 *error = FT_Err_Ok; 598 599 if ( stream->pos + 2 < stream->size ) 600 { 601 if ( stream->read ) 602 { 603 if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) 604 goto Fail; 605 606 p = reads; 607 } 608 else 609 p = stream->base + stream->pos; 610 611 if ( p ) 612 result = FT_NEXT_UOFF3( p ); 613 } 614 else 615 goto Fail; 616 617 stream->pos += 3; 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 0; 628 } 629 630 631 FT_BASE_DEF( FT_ULong ) 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 = 0; 637 FT_ULong result = 0; 638 639 640 FT_ASSERT( stream ); 641 642 *error = FT_Err_Ok; 643 644 if ( stream->pos + 3 < stream->size ) 645 { 646 if ( stream->read ) 647 { 648 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) 649 goto Fail; 650 651 p = reads; 652 } 653 else 654 p = stream->base + stream->pos; 655 656 if ( p ) 657 result = FT_NEXT_ULONG( p ); 658 } 659 else 660 goto Fail; 661 662 stream->pos += 4; 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 0; 673 } 674 675 676 FT_BASE_DEF( FT_ULong ) 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 = 0; 682 FT_ULong result = 0; 683 684 685 FT_ASSERT( stream ); 686 687 *error = FT_Err_Ok; 688 689 if ( stream->pos + 3 < stream->size ) 690 { 691 if ( stream->read ) 692 { 693 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) 694 goto Fail; 695 696 p = reads; 697 } 698 else 699 p = stream->base + stream->pos; 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_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 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 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