1 /***************************************************************************/ 2 /* */ 3 /* ftstream.c */ 4 /* */ 5 /* I/O stream support (body). */ 6 /* */ 7 /* Copyright 2000-2001, 2002 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 = 0; 43 stream->read = 0; 44 stream->close = 0; 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 { 53 stream->close( stream ); 54 stream->close = NULL; 55 } 56 } 57 58 59 FT_BASE_DEF( FT_Error ) FT_Stream_Seek(FT_Stream stream,FT_ULong pos)60 FT_Stream_Seek( FT_Stream stream, 61 FT_ULong pos ) 62 { 63 FT_Error error = FT_Err_Ok; 64 65 66 stream->pos = pos; 67 68 if ( stream->read ) 69 { 70 if ( stream->read( stream, pos, 0, 0 ) ) 71 { 72 FT_ERROR(( "FT_Stream_Seek: invalid i/o; pos = 0x%lx, size = 0x%lx\n", 73 pos, stream->size )); 74 75 error = FT_Err_Invalid_Stream_Operation; 76 } 77 } 78 /* note that seeking to the first position after the file is valid */ 79 else if ( pos > stream->size ) 80 { 81 FT_ERROR(( "FT_Stream_Seek: invalid i/o; pos = 0x%lx, size = 0x%lx\n", 82 pos, stream->size )); 83 84 error = FT_Err_Invalid_Stream_Operation; 85 } 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 return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) ); 96 } 97 98 99 FT_BASE_DEF( FT_Long ) FT_Stream_Pos(FT_Stream stream)100 FT_Stream_Pos( FT_Stream stream ) 101 { 102 return stream->pos; 103 } 104 105 106 FT_BASE_DEF( FT_Error ) FT_Stream_Read(FT_Stream stream,FT_Byte * buffer,FT_ULong count)107 FT_Stream_Read( FT_Stream stream, 108 FT_Byte* buffer, 109 FT_ULong count ) 110 { 111 return FT_Stream_ReadAt( stream, stream->pos, buffer, count ); 112 } 113 114 115 FT_BASE_DEF( FT_Error ) FT_Stream_ReadAt(FT_Stream stream,FT_ULong pos,FT_Byte * buffer,FT_ULong count)116 FT_Stream_ReadAt( FT_Stream stream, 117 FT_ULong pos, 118 FT_Byte* buffer, 119 FT_ULong count ) 120 { 121 FT_Error error = FT_Err_Ok; 122 FT_ULong read_bytes; 123 124 125 if ( pos >= stream->size ) 126 { 127 FT_ERROR(( "FT_Stream_ReadAt: invalid i/o; pos = 0x%lx, size = 0x%lx\n", 128 pos, stream->size )); 129 130 return FT_Err_Invalid_Stream_Operation; 131 } 132 133 if ( stream->read ) 134 read_bytes = stream->read( stream, pos, buffer, count ); 135 else 136 { 137 read_bytes = stream->size - pos; 138 if ( read_bytes > count ) 139 read_bytes = count; 140 141 FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); 142 } 143 144 stream->pos = pos + read_bytes; 145 146 if ( read_bytes < count ) 147 { 148 FT_ERROR(( "FT_Stream_ReadAt:" )); 149 FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n", 150 count, read_bytes )); 151 152 error = FT_Err_Invalid_Stream_Operation; 153 } 154 155 return error; 156 } 157 158 159 FT_BASE_DEF( FT_Error ) FT_Stream_ExtractFrame(FT_Stream stream,FT_ULong count,FT_Byte ** pbytes)160 FT_Stream_ExtractFrame( FT_Stream stream, 161 FT_ULong count, 162 FT_Byte** pbytes ) 163 { 164 FT_Error error; 165 166 167 error = FT_Stream_EnterFrame( stream, count ); 168 if ( !error ) 169 { 170 *pbytes = (FT_Byte*)stream->cursor; 171 172 /* equivalent to FT_Stream_ExitFrame(), with no memory block release */ 173 stream->cursor = 0; 174 stream->limit = 0; 175 } 176 177 return error; 178 } 179 180 181 FT_BASE_DEF( void ) FT_Stream_ReleaseFrame(FT_Stream stream,FT_Byte ** pbytes)182 FT_Stream_ReleaseFrame( FT_Stream stream, 183 FT_Byte** pbytes ) 184 { 185 if ( stream->read ) 186 { 187 FT_Memory memory = stream->memory; 188 189 190 FT_FREE( *pbytes ); 191 } 192 *pbytes = 0; 193 } 194 195 196 FT_BASE_DEF( FT_Error ) FT_Stream_EnterFrame(FT_Stream stream,FT_ULong count)197 FT_Stream_EnterFrame( FT_Stream stream, 198 FT_ULong count ) 199 { 200 FT_Error error = FT_Err_Ok; 201 FT_ULong read_bytes; 202 203 204 /* check for nested frame access */ 205 FT_ASSERT( stream && stream->cursor == 0 ); 206 207 if ( stream->read ) 208 { 209 /* allocate the frame in memory */ 210 FT_Memory memory = stream->memory; 211 212 213 if ( FT_ALLOC( stream->base, count ) ) 214 goto Exit; 215 216 /* read it */ 217 read_bytes = stream->read( stream, stream->pos, 218 stream->base, count ); 219 if ( read_bytes < count ) 220 { 221 FT_ERROR(( "FT_Stream_EnterFrame:" )); 222 FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n", 223 count, read_bytes )); 224 225 FT_FREE( stream->base ); 226 error = FT_Err_Invalid_Stream_Operation; 227 } 228 stream->cursor = stream->base; 229 stream->limit = stream->cursor + count; 230 stream->pos += read_bytes; 231 } 232 else 233 { 234 /* check current and new position */ 235 if ( stream->pos >= stream->size || 236 stream->pos + count > stream->size ) 237 { 238 FT_ERROR(( "FT_Stream_EnterFrame:" )); 239 FT_ERROR(( " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", 240 stream->pos, count, stream->size )); 241 242 error = FT_Err_Invalid_Stream_Operation; 243 goto Exit; 244 } 245 246 /* set cursor */ 247 stream->cursor = stream->base + stream->pos; 248 stream->limit = stream->cursor + count; 249 stream->pos += count; 250 } 251 252 Exit: 253 return error; 254 } 255 256 257 FT_BASE_DEF( void ) FT_Stream_ExitFrame(FT_Stream stream)258 FT_Stream_ExitFrame( FT_Stream stream ) 259 { 260 /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ 261 /* that it is possible to access a frame of length 0 in */ 262 /* some weird fonts (usually, when accessing an array of */ 263 /* 0 records, like in some strange kern tables). */ 264 /* */ 265 /* In this case, the loader code handles the 0-length table */ 266 /* gracefully; however, stream.cursor is really set to 0 by the */ 267 /* FT_Stream_EnterFrame() call, and this is not an error. */ 268 /* */ 269 FT_ASSERT( stream ); 270 271 if ( stream->read ) 272 { 273 FT_Memory memory = stream->memory; 274 275 276 FT_FREE( stream->base ); 277 } 278 stream->cursor = 0; 279 stream->limit = 0; 280 } 281 282 283 FT_BASE_DEF( FT_Char ) FT_Stream_GetChar(FT_Stream stream)284 FT_Stream_GetChar( FT_Stream stream ) 285 { 286 FT_Char result; 287 288 289 FT_ASSERT( stream && stream->cursor ); 290 291 result = 0; 292 if ( stream->cursor < stream->limit ) 293 result = *stream->cursor++; 294 295 return result; 296 } 297 298 299 FT_BASE_DEF( FT_Short ) FT_Stream_GetShort(FT_Stream stream)300 FT_Stream_GetShort( FT_Stream stream ) 301 { 302 FT_Byte* p; 303 FT_Short result; 304 305 306 FT_ASSERT( stream && stream->cursor ); 307 308 result = 0; 309 p = stream->cursor; 310 if ( p + 1 < stream->limit ) 311 result = FT_NEXT_SHORT( p ); 312 stream->cursor = p; 313 314 return result; 315 } 316 317 318 FT_BASE_DEF( FT_Short ) FT_Stream_GetShortLE(FT_Stream stream)319 FT_Stream_GetShortLE( FT_Stream stream ) 320 { 321 FT_Byte* p; 322 FT_Short result; 323 324 325 FT_ASSERT( stream && stream->cursor ); 326 327 result = 0; 328 p = stream->cursor; 329 if ( p + 1 < stream->limit ) 330 result = FT_NEXT_SHORT_LE( p ); 331 stream->cursor = p; 332 333 return result; 334 } 335 336 337 FT_BASE_DEF( FT_Long ) FT_Stream_GetOffset(FT_Stream stream)338 FT_Stream_GetOffset( FT_Stream stream ) 339 { 340 FT_Byte* p; 341 FT_Long result; 342 343 344 FT_ASSERT( stream && stream->cursor ); 345 346 result = 0; 347 p = stream->cursor; 348 if ( p + 2 < stream->limit ) 349 result = FT_NEXT_OFF3( p ); 350 stream->cursor = p; 351 return result; 352 } 353 354 355 FT_BASE_DEF( FT_Long ) FT_Stream_GetLong(FT_Stream stream)356 FT_Stream_GetLong( FT_Stream stream ) 357 { 358 FT_Byte* p; 359 FT_Long result; 360 361 362 FT_ASSERT( stream && stream->cursor ); 363 364 result = 0; 365 p = stream->cursor; 366 if ( p + 3 < stream->limit ) 367 result = FT_NEXT_LONG( p ); 368 stream->cursor = p; 369 return result; 370 } 371 372 373 FT_BASE_DEF( FT_Long ) FT_Stream_GetLongLE(FT_Stream stream)374 FT_Stream_GetLongLE( FT_Stream stream ) 375 { 376 FT_Byte* p; 377 FT_Long result; 378 379 380 FT_ASSERT( stream && stream->cursor ); 381 382 result = 0; 383 p = stream->cursor; 384 if ( p + 3 < stream->limit ) 385 result = FT_NEXT_LONG_LE( p ); 386 stream->cursor = p; 387 return result; 388 } 389 390 391 FT_BASE_DEF( FT_Char ) FT_Stream_ReadChar(FT_Stream stream,FT_Error * error)392 FT_Stream_ReadChar( FT_Stream stream, 393 FT_Error* error ) 394 { 395 FT_Byte result = 0; 396 397 398 FT_ASSERT( stream ); 399 400 *error = FT_Err_Ok; 401 402 if ( stream->read ) 403 { 404 if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) 405 goto Fail; 406 } 407 else 408 { 409 if ( stream->pos < stream->size ) 410 result = stream->base[stream->pos]; 411 else 412 goto Fail; 413 } 414 stream->pos++; 415 416 return result; 417 418 Fail: 419 *error = FT_Err_Invalid_Stream_Operation; 420 FT_ERROR(( "FT_Stream_ReadChar: invalid i/o; pos = 0x%lx, size = 0x%lx\n", 421 stream->pos, stream->size )); 422 423 return 0; 424 } 425 426 427 FT_BASE_DEF( FT_Short ) FT_Stream_ReadShort(FT_Stream stream,FT_Error * error)428 FT_Stream_ReadShort( FT_Stream stream, 429 FT_Error* error ) 430 { 431 FT_Byte reads[2]; 432 FT_Byte* p = 0; 433 FT_Short result = 0; 434 435 436 FT_ASSERT( stream ); 437 438 *error = FT_Err_Ok; 439 440 if ( stream->pos + 1 < stream->size ) 441 { 442 if ( stream->read ) 443 { 444 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) 445 goto Fail; 446 447 p = reads; 448 } 449 else 450 { 451 p = stream->base + stream->pos; 452 } 453 454 if ( p ) 455 result = FT_NEXT_SHORT( p ); 456 } 457 else 458 goto Fail; 459 460 stream->pos += 2; 461 462 return result; 463 464 Fail: 465 *error = FT_Err_Invalid_Stream_Operation; 466 FT_ERROR(( "FT_Stream_ReadShort:" )); 467 FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 468 stream->pos, stream->size )); 469 470 return 0; 471 } 472 473 474 FT_BASE_DEF( FT_Short ) FT_Stream_ReadShortLE(FT_Stream stream,FT_Error * error)475 FT_Stream_ReadShortLE( FT_Stream stream, 476 FT_Error* error ) 477 { 478 FT_Byte reads[2]; 479 FT_Byte* p = 0; 480 FT_Short result = 0; 481 482 483 FT_ASSERT( stream ); 484 485 *error = FT_Err_Ok; 486 487 if ( stream->pos + 1 < stream->size ) 488 { 489 if ( stream->read ) 490 { 491 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) 492 goto Fail; 493 494 p = reads; 495 } 496 else 497 { 498 p = stream->base + stream->pos; 499 } 500 501 if ( p ) 502 result = FT_NEXT_SHORT_LE( p ); 503 } 504 else 505 goto Fail; 506 507 stream->pos += 2; 508 509 return result; 510 511 Fail: 512 *error = FT_Err_Invalid_Stream_Operation; 513 FT_ERROR(( "FT_Stream_ReadShortLE:" )); 514 FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 515 stream->pos, stream->size )); 516 517 return 0; 518 } 519 520 521 FT_BASE_DEF( FT_Long ) FT_Stream_ReadOffset(FT_Stream stream,FT_Error * error)522 FT_Stream_ReadOffset( FT_Stream stream, 523 FT_Error* error ) 524 { 525 FT_Byte reads[3]; 526 FT_Byte* p = 0; 527 FT_Long result = 0; 528 529 530 FT_ASSERT( stream ); 531 532 *error = FT_Err_Ok; 533 534 if ( stream->pos + 2 < stream->size ) 535 { 536 if ( stream->read ) 537 { 538 if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) 539 goto Fail; 540 541 p = reads; 542 } 543 else 544 { 545 p = stream->base + stream->pos; 546 } 547 548 if ( p ) 549 result = FT_NEXT_OFF3( p ); 550 } 551 else 552 goto Fail; 553 554 stream->pos += 3; 555 556 return result; 557 558 Fail: 559 *error = FT_Err_Invalid_Stream_Operation; 560 FT_ERROR(( "FT_Stream_ReadOffset:" )); 561 FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 562 stream->pos, stream->size )); 563 564 return 0; 565 } 566 567 568 FT_BASE_DEF( FT_Long ) FT_Stream_ReadLong(FT_Stream stream,FT_Error * error)569 FT_Stream_ReadLong( FT_Stream stream, 570 FT_Error* error ) 571 { 572 FT_Byte reads[4]; 573 FT_Byte* p = 0; 574 FT_Long result = 0; 575 576 577 FT_ASSERT( stream ); 578 579 *error = FT_Err_Ok; 580 581 if ( stream->pos + 3 < stream->size ) 582 { 583 if ( stream->read ) 584 { 585 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) 586 goto Fail; 587 588 p = reads; 589 } 590 else 591 { 592 p = stream->base + stream->pos; 593 } 594 595 if ( p ) 596 result = FT_NEXT_LONG( p ); 597 } 598 else 599 goto Fail; 600 601 stream->pos += 4; 602 603 return result; 604 605 Fail: 606 FT_ERROR(( "FT_Stream_ReadLong: invalid i/o; pos = 0x%lx, size = 0x%lx\n", 607 stream->pos, stream->size )); 608 *error = FT_Err_Invalid_Stream_Operation; 609 610 return 0; 611 } 612 613 614 FT_BASE_DEF( FT_Long ) FT_Stream_ReadLongLE(FT_Stream stream,FT_Error * error)615 FT_Stream_ReadLongLE( FT_Stream stream, 616 FT_Error* error ) 617 { 618 FT_Byte reads[4]; 619 FT_Byte* p = 0; 620 FT_Long result = 0; 621 622 623 FT_ASSERT( stream ); 624 625 *error = FT_Err_Ok; 626 627 if ( stream->pos + 3 < stream->size ) 628 { 629 if ( stream->read ) 630 { 631 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) 632 goto Fail; 633 634 p = reads; 635 } 636 else 637 { 638 p = stream->base + stream->pos; 639 } 640 641 if ( p ) 642 result = FT_NEXT_LONG_LE( p ); 643 } 644 else 645 goto Fail; 646 647 stream->pos += 4; 648 649 return result; 650 651 Fail: 652 FT_ERROR(( "FT_Stream_ReadLongLE:" )); 653 FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", 654 stream->pos, stream->size )); 655 *error = FT_Err_Invalid_Stream_Operation; 656 657 return 0; 658 } 659 660 661 FT_BASE_DEF( FT_Error ) FT_Stream_ReadFields(FT_Stream stream,const FT_Frame_Field * fields,void * structure)662 FT_Stream_ReadFields( FT_Stream stream, 663 const FT_Frame_Field* fields, 664 void* structure ) 665 { 666 FT_Error error; 667 FT_Bool frame_accessed = 0; 668 FT_Byte* cursor = stream->cursor; 669 670 671 if ( !fields || !stream ) 672 return FT_Err_Invalid_Argument; 673 674 error = FT_Err_Ok; 675 do 676 { 677 FT_ULong value; 678 FT_Int sign_shift; 679 FT_Byte* p; 680 681 682 switch ( fields->value ) 683 { 684 case ft_frame_start: /* access a new frame */ 685 error = FT_Stream_EnterFrame( stream, fields->offset ); 686 if ( error ) 687 goto Exit; 688 689 frame_accessed = 1; 690 cursor = stream->cursor; 691 fields++; 692 continue; /* loop! */ 693 694 case ft_frame_bytes: /* read a byte sequence */ 695 case ft_frame_skip: /* skip some bytes */ 696 { 697 FT_UInt len = fields->size; 698 699 700 if ( cursor + len > stream->limit ) 701 { 702 error = FT_Err_Invalid_Stream_Operation; 703 goto Exit; 704 } 705 706 if ( fields->value == ft_frame_bytes ) 707 { 708 p = (FT_Byte*)structure + fields->offset; 709 FT_MEM_COPY( p, cursor, len ); 710 } 711 cursor += len; 712 fields++; 713 continue; 714 } 715 716 case ft_frame_byte: 717 case ft_frame_schar: /* read a single byte */ 718 value = FT_NEXT_BYTE(cursor); 719 sign_shift = 24; 720 break; 721 722 case ft_frame_short_be: 723 case ft_frame_ushort_be: /* read a 2-byte big-endian short */ 724 value = FT_NEXT_USHORT(cursor); 725 sign_shift = 16; 726 break; 727 728 case ft_frame_short_le: 729 case ft_frame_ushort_le: /* read a 2-byte little-endian short */ 730 value = FT_NEXT_USHORT_LE(cursor); 731 sign_shift = 16; 732 break; 733 734 case ft_frame_long_be: 735 case ft_frame_ulong_be: /* read a 4-byte big-endian long */ 736 value = FT_NEXT_ULONG(cursor); 737 sign_shift = 0; 738 break; 739 740 case ft_frame_long_le: 741 case ft_frame_ulong_le: /* read a 4-byte little-endian long */ 742 value = FT_NEXT_ULONG_LE(cursor); 743 sign_shift = 0; 744 break; 745 746 case ft_frame_off3_be: 747 case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ 748 value = FT_NEXT_UOFF3(cursor); 749 sign_shift = 8; 750 break; 751 752 case ft_frame_off3_le: 753 case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ 754 value = FT_NEXT_UOFF3_LE(cursor); 755 sign_shift = 8; 756 break; 757 758 default: 759 /* otherwise, exit the loop */ 760 stream->cursor = cursor; 761 goto Exit; 762 } 763 764 /* now, compute the signed value is necessary */ 765 if ( fields->value & FT_FRAME_OP_SIGNED ) 766 value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); 767 768 /* finally, store the value in the object */ 769 770 p = (FT_Byte*)structure + fields->offset; 771 switch ( fields->size ) 772 { 773 case 1: 774 *(FT_Byte*)p = (FT_Byte)value; 775 break; 776 777 case 2: 778 *(FT_UShort*)p = (FT_UShort)value; 779 break; 780 781 case 4: 782 *(FT_UInt32*)p = (FT_UInt32)value; 783 break; 784 785 default: /* for 64-bit systems */ 786 *(FT_ULong*)p = (FT_ULong)value; 787 } 788 789 /* go to next field */ 790 fields++; 791 } 792 while ( 1 ); 793 794 Exit: 795 /* close the frame if it was opened by this read */ 796 if ( frame_accessed ) 797 FT_Stream_ExitFrame( stream ); 798 799 return error; 800 } 801 802 803 /* END */ 804