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