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