File.cpp (36259B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #include "../idlib/precompiled.h" 30 #pragma hdrstop 31 32 #include "Unzip.h" 33 34 /* 35 ================= 36 FS_WriteFloatString 37 ================= 38 */ 39 int FS_WriteFloatString( char *buf, const char *fmt, va_list argPtr ) { 40 long i; 41 unsigned long u; 42 double f; 43 char *str; 44 int index; 45 idStr tmp, format; 46 47 index = 0; 48 49 while( *fmt ) { 50 switch( *fmt ) { 51 case '%': 52 format = ""; 53 format += *fmt++; 54 while ( (*fmt >= '0' && *fmt <= '9') || 55 *fmt == '.' || *fmt == '-' || *fmt == '+' || *fmt == '#') { 56 format += *fmt++; 57 } 58 format += *fmt; 59 switch( *fmt ) { 60 case 'f': 61 case 'e': 62 case 'E': 63 case 'g': 64 case 'G': 65 f = va_arg( argPtr, double ); 66 if ( format.Length() <= 2 ) { 67 // high precision floating point number without trailing zeros 68 sprintf( tmp, "%1.10f", f ); 69 tmp.StripTrailing( '0' ); 70 tmp.StripTrailing( '.' ); 71 index += sprintf( buf+index, "%s", tmp.c_str() ); 72 } 73 else { 74 index += sprintf( buf+index, format.c_str(), f ); 75 } 76 break; 77 case 'd': 78 case 'i': 79 i = va_arg( argPtr, long ); 80 index += sprintf( buf+index, format.c_str(), i ); 81 break; 82 case 'u': 83 u = va_arg( argPtr, unsigned long ); 84 index += sprintf( buf+index, format.c_str(), u ); 85 break; 86 case 'o': 87 u = va_arg( argPtr, unsigned long ); 88 index += sprintf( buf+index, format.c_str(), u ); 89 break; 90 case 'x': 91 u = va_arg( argPtr, unsigned long ); 92 index += sprintf( buf+index, format.c_str(), u ); 93 break; 94 case 'X': 95 u = va_arg( argPtr, unsigned long ); 96 index += sprintf( buf+index, format.c_str(), u ); 97 break; 98 case 'c': 99 i = va_arg( argPtr, long ); 100 index += sprintf( buf+index, format.c_str(), (char) i ); 101 break; 102 case 's': 103 str = va_arg( argPtr, char * ); 104 index += sprintf( buf+index, format.c_str(), str ); 105 break; 106 case '%': 107 index += sprintf( buf+index, format.c_str() ); //-V618 108 break; 109 default: 110 common->Error( "FS_WriteFloatString: invalid format %s", format.c_str() ); 111 break; 112 } 113 fmt++; 114 break; 115 case '\\': 116 fmt++; 117 switch( *fmt ) { 118 case 't': 119 index += sprintf( buf+index, "\t" ); 120 break; 121 case 'v': 122 index += sprintf( buf+index, "\v" ); 123 break; 124 case 'n': 125 index += sprintf( buf+index, "\n" ); 126 break; 127 case '\\': 128 index += sprintf( buf+index, "\\" ); 129 break; 130 default: 131 common->Error( "FS_WriteFloatString: unknown escape character \'%c\'", *fmt ); 132 break; 133 } 134 fmt++; 135 break; 136 default: 137 index += sprintf( buf+index, "%c", *fmt ); 138 fmt++; 139 break; 140 } 141 } 142 143 return index; 144 } 145 146 /* 147 ================================================================================= 148 149 idFile 150 151 ================================================================================= 152 */ 153 154 /* 155 ================= 156 idFile::GetName 157 ================= 158 */ 159 const char *idFile::GetName() const { 160 return ""; 161 } 162 163 /* 164 ================= 165 idFile::GetFullPath 166 ================= 167 */ 168 const char *idFile::GetFullPath() const { 169 return ""; 170 } 171 172 /* 173 ================= 174 idFile::Read 175 ================= 176 */ 177 int idFile::Read( void *buffer, int len ) { 178 common->FatalError( "idFile::Read: cannot read from idFile" ); 179 return 0; 180 } 181 182 /* 183 ================= 184 idFile::Write 185 ================= 186 */ 187 int idFile::Write( const void *buffer, int len ) { 188 common->FatalError( "idFile::Write: cannot write to idFile" ); 189 return 0; 190 } 191 192 /* 193 ================= 194 idFile::Length 195 ================= 196 */ 197 int idFile::Length() const { 198 return 0; 199 } 200 201 /* 202 ================= 203 idFile::Timestamp 204 ================= 205 */ 206 ID_TIME_T idFile::Timestamp() const { 207 return 0; 208 } 209 210 /* 211 ================= 212 idFile::Tell 213 ================= 214 */ 215 int idFile::Tell() const { 216 return 0; 217 } 218 219 /* 220 ================= 221 idFile::ForceFlush 222 ================= 223 */ 224 void idFile::ForceFlush() { 225 } 226 227 /* 228 ================= 229 idFile::Flush 230 ================= 231 */ 232 void idFile::Flush() { 233 } 234 235 /* 236 ================= 237 idFile::Seek 238 ================= 239 */ 240 int idFile::Seek( long offset, fsOrigin_t origin ) { 241 return -1; 242 } 243 244 /* 245 ================= 246 idFile::Rewind 247 ================= 248 */ 249 void idFile::Rewind() { 250 Seek( 0, FS_SEEK_SET ); 251 } 252 253 /* 254 ================= 255 idFile::Printf 256 ================= 257 */ 258 int idFile::Printf( const char *fmt, ... ) { 259 char buf[MAX_PRINT_MSG]; 260 int length; 261 va_list argptr; 262 263 va_start( argptr, fmt ); 264 length = idStr::vsnPrintf( buf, MAX_PRINT_MSG-1, fmt, argptr ); 265 va_end( argptr ); 266 267 // so notepad formats the lines correctly 268 idStr work( buf ); 269 work.Replace( "\n", "\r\n" ); 270 271 return Write( work.c_str(), work.Length() ); 272 } 273 274 /* 275 ================= 276 idFile::VPrintf 277 ================= 278 */ 279 int idFile::VPrintf( const char *fmt, va_list args ) { 280 char buf[MAX_PRINT_MSG]; 281 int length; 282 283 length = idStr::vsnPrintf( buf, MAX_PRINT_MSG-1, fmt, args ); 284 return Write( buf, length ); 285 } 286 287 /* 288 ================= 289 idFile::WriteFloatString 290 ================= 291 */ 292 int idFile::WriteFloatString( const char *fmt, ... ) { 293 char buf[MAX_PRINT_MSG]; 294 int len; 295 va_list argPtr; 296 297 va_start( argPtr, fmt ); 298 len = FS_WriteFloatString( buf, fmt, argPtr ); 299 va_end( argPtr ); 300 301 return Write( buf, len ); 302 } 303 304 /* 305 ================= 306 idFile::ReadInt 307 ================= 308 */ 309 int idFile::ReadInt( int &value ) { 310 int result = Read( &value, sizeof( value ) ); 311 value = LittleLong(value); 312 return result; 313 } 314 315 /* 316 ================= 317 idFile::ReadUnsignedInt 318 ================= 319 */ 320 int idFile::ReadUnsignedInt( unsigned int &value ) { 321 int result = Read( &value, sizeof( value ) ); 322 value = LittleLong(value); 323 return result; 324 } 325 326 /* 327 ================= 328 idFile::ReadShort 329 ================= 330 */ 331 int idFile::ReadShort( short &value ) { 332 int result = Read( &value, sizeof( value ) ); 333 value = LittleShort(value); 334 return result; 335 } 336 337 /* 338 ================= 339 idFile::ReadUnsignedShort 340 ================= 341 */ 342 int idFile::ReadUnsignedShort( unsigned short &value ) { 343 int result = Read( &value, sizeof( value ) ); 344 value = LittleShort(value); 345 return result; 346 } 347 348 /* 349 ================= 350 idFile::ReadChar 351 ================= 352 */ 353 int idFile::ReadChar( char &value ) { 354 return Read( &value, sizeof( value ) ); 355 } 356 357 /* 358 ================= 359 idFile::ReadUnsignedChar 360 ================= 361 */ 362 int idFile::ReadUnsignedChar( unsigned char &value ) { 363 return Read( &value, sizeof( value ) ); 364 } 365 366 /* 367 ================= 368 idFile::ReadFloat 369 ================= 370 */ 371 int idFile::ReadFloat( float &value ) { 372 int result = Read( &value, sizeof( value ) ); 373 value = LittleFloat(value); 374 return result; 375 } 376 377 /* 378 ================= 379 idFile::ReadBool 380 ================= 381 */ 382 int idFile::ReadBool( bool &value ) { 383 unsigned char c; 384 int result = ReadUnsignedChar( c ); 385 value = c ? true : false; 386 return result; 387 } 388 389 /* 390 ================= 391 idFile::ReadString 392 ================= 393 */ 394 int idFile::ReadString( idStr &string ) { 395 int len; 396 int result = 0; 397 398 ReadInt( len ); 399 if ( len >= 0 ) { 400 string.Fill( ' ', len ); 401 result = Read( &string[ 0 ], len ); 402 } 403 return result; 404 } 405 406 /* 407 ================= 408 idFile::ReadVec2 409 ================= 410 */ 411 int idFile::ReadVec2( idVec2 &vec ) { 412 int result = Read( &vec, sizeof( vec ) ); 413 LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); 414 return result; 415 } 416 417 /* 418 ================= 419 idFile::ReadVec3 420 ================= 421 */ 422 int idFile::ReadVec3( idVec3 &vec ) { 423 int result = Read( &vec, sizeof( vec ) ); 424 LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); 425 return result; 426 } 427 428 /* 429 ================= 430 idFile::ReadVec4 431 ================= 432 */ 433 int idFile::ReadVec4( idVec4 &vec ) { 434 int result = Read( &vec, sizeof( vec ) ); 435 LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); 436 return result; 437 } 438 439 /* 440 ================= 441 idFile::ReadVec6 442 ================= 443 */ 444 int idFile::ReadVec6( idVec6 &vec ) { 445 int result = Read( &vec, sizeof( vec ) ); 446 LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); 447 return result; 448 } 449 450 /* 451 ================= 452 idFile::ReadMat3 453 ================= 454 */ 455 int idFile::ReadMat3( idMat3 &mat ) { 456 int result = Read( &mat, sizeof( mat ) ); 457 LittleRevBytes( &mat, sizeof(float), sizeof(mat)/sizeof(float) ); 458 return result; 459 } 460 461 /* 462 ================= 463 idFile::WriteInt 464 ================= 465 */ 466 int idFile::WriteInt( const int value ) { 467 int v = LittleLong(value); 468 return Write( &v, sizeof( v ) ); 469 } 470 471 /* 472 ================= 473 idFile::WriteUnsignedInt 474 ================= 475 */ 476 int idFile::WriteUnsignedInt( const unsigned int value ) { 477 unsigned int v = LittleLong(value); 478 return Write( &v, sizeof( v ) ); 479 } 480 481 /* 482 ================= 483 idFile::WriteShort 484 ================= 485 */ 486 int idFile::WriteShort( const short value ) { 487 short v = LittleShort(value); 488 return Write( &v, sizeof( v ) ); 489 } 490 491 /* 492 ================= 493 idFile::WriteUnsignedShort 494 ================= 495 */ 496 int idFile::WriteUnsignedShort( const unsigned short value ) { 497 unsigned short v = LittleShort(value); 498 return Write( &v, sizeof( v ) ); 499 } 500 501 /* 502 ================= 503 idFile::WriteChar 504 ================= 505 */ 506 int idFile::WriteChar( const char value ) { 507 return Write( &value, sizeof( value ) ); 508 } 509 510 /* 511 ================= 512 idFile::WriteUnsignedChar 513 ================= 514 */ 515 int idFile::WriteUnsignedChar( const unsigned char value ) { 516 return Write( &value, sizeof( value ) ); 517 } 518 519 /* 520 ================= 521 idFile::WriteFloat 522 ================= 523 */ 524 int idFile::WriteFloat( const float value ) { 525 float v = LittleFloat(value); 526 return Write( &v, sizeof( v ) ); 527 } 528 529 /* 530 ================= 531 idFile::WriteBool 532 ================= 533 */ 534 int idFile::WriteBool( const bool value ) { 535 unsigned char c = value; 536 return WriteUnsignedChar( c ); 537 } 538 539 /* 540 ================= 541 idFile::WriteString 542 ================= 543 */ 544 int idFile::WriteString( const char *value ) { 545 int len = strlen( value ); 546 WriteInt( len ); 547 return Write( value, len ); 548 } 549 550 /* 551 ================= 552 idFile::WriteVec2 553 ================= 554 */ 555 int idFile::WriteVec2( const idVec2 &vec ) { 556 idVec2 v = vec; 557 LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); 558 return Write( &v, sizeof( v ) ); 559 } 560 561 /* 562 ================= 563 idFile::WriteVec3 564 ================= 565 */ 566 int idFile::WriteVec3( const idVec3 &vec ) { 567 idVec3 v = vec; 568 LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); 569 return Write( &v, sizeof( v ) ); 570 } 571 572 /* 573 ================= 574 idFile::WriteVec4 575 ================= 576 */ 577 int idFile::WriteVec4( const idVec4 &vec ) { 578 idVec4 v = vec; 579 LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); 580 return Write( &v, sizeof( v ) ); 581 } 582 583 /* 584 ================= 585 idFile::WriteVec6 586 ================= 587 */ 588 int idFile::WriteVec6( const idVec6 &vec ) { 589 idVec6 v = vec; 590 LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); 591 return Write( &v, sizeof( v ) ); 592 } 593 594 /* 595 ================= 596 idFile::WriteMat3 597 ================= 598 */ 599 int idFile::WriteMat3( const idMat3 &mat ) { 600 idMat3 v = mat; 601 LittleRevBytes(&v, sizeof(float), sizeof(v)/sizeof(float) ); 602 return Write( &v, sizeof( v ) ); 603 } 604 605 /* 606 ================================================================================= 607 608 idFile_Memory 609 610 ================================================================================= 611 */ 612 613 614 /* 615 ================= 616 idFile_Memory::idFile_Memory 617 ================= 618 */ 619 idFile_Memory::idFile_Memory() { 620 name = "*unknown*"; 621 maxSize = 0; 622 fileSize = 0; 623 allocated = 0; 624 granularity = 16384; 625 626 mode = ( 1 << FS_WRITE ); 627 filePtr = NULL; 628 curPtr = NULL; 629 } 630 631 /* 632 ================= 633 idFile_Memory::idFile_Memory 634 ================= 635 */ 636 idFile_Memory::idFile_Memory( const char *name ) { 637 this->name = name; 638 maxSize = 0; 639 fileSize = 0; 640 allocated = 0; 641 granularity = 16384; 642 643 mode = ( 1 << FS_WRITE ); 644 filePtr = NULL; 645 curPtr = NULL; 646 } 647 648 /* 649 ================= 650 idFile_Memory::idFile_Memory 651 ================= 652 */ 653 idFile_Memory::idFile_Memory( const char *name, char *data, int length ) { 654 this->name = name; 655 maxSize = length; 656 fileSize = 0; 657 allocated = length; 658 granularity = 16384; 659 660 mode = ( 1 << FS_WRITE ); 661 filePtr = data; 662 curPtr = data; 663 } 664 665 /* 666 ================= 667 idFile_Memory::idFile_Memory 668 ================= 669 */ 670 idFile_Memory::idFile_Memory( const char *name, const char *data, int length ) { 671 this->name = name; 672 maxSize = 0; 673 fileSize = length; 674 allocated = 0; 675 granularity = 16384; 676 677 mode = ( 1 << FS_READ ); 678 filePtr = const_cast<char *>(data); 679 curPtr = const_cast<char *>(data); 680 } 681 682 /* 683 ================= 684 idFile_Memory::TakeDataOwnership 685 686 this also makes the file read only 687 ================= 688 */ 689 void idFile_Memory::TakeDataOwnership() { 690 if ( filePtr != NULL && fileSize > 0 ) { 691 maxSize = 0; 692 mode = ( 1 << FS_READ ); 693 allocated = fileSize; 694 } 695 } 696 697 /* 698 ================= 699 idFile_Memory::~idFile_Memory 700 ================= 701 */ 702 idFile_Memory::~idFile_Memory() { 703 if ( filePtr && allocated > 0 && maxSize == 0 ) { 704 Mem_Free( filePtr ); 705 } 706 } 707 708 /* 709 ================= 710 idFile_Memory::Read 711 ================= 712 */ 713 int idFile_Memory::Read( void *buffer, int len ) { 714 715 if ( !( mode & ( 1 << FS_READ ) ) ) { 716 common->FatalError( "idFile_Memory::Read: %s not opened in read mode", name.c_str() ); 717 return 0; 718 } 719 720 if ( curPtr + len > filePtr + fileSize ) { 721 len = filePtr + fileSize - curPtr; 722 } 723 memcpy( buffer, curPtr, len ); 724 curPtr += len; 725 return len; 726 } 727 728 idCVar memcpyImpl( "memcpyImpl", "0", 0, "Which implementation of memcpy to use for idFile_Memory::Write() [0/1 - standard (1 eliminates branch misprediction), 2 - auto-vectorized]" ); 729 void * memcpy2( void * __restrict b, const void * __restrict a, size_t n ) { 730 char * s1 = (char *)b; 731 const char * s2 = (const char *)a; 732 for ( ; 0 < n; --n ) { 733 *s1++ = *s2++; 734 } 735 return b; 736 } 737 738 /* 739 ================= 740 idFile_Memory::Write 741 ================= 742 */ 743 idHashTableT< int, int > histogram; 744 CONSOLE_COMMAND( outputHistogram, "", 0 ) { 745 for ( int i = 0; i < histogram.Num(); i++ ) { 746 int key; 747 histogram.GetIndexKey( i, key ); 748 int * value = histogram.GetIndex( i ); 749 750 idLib::Printf( "%d\t%d\n", key, *value ); 751 } 752 } 753 754 CONSOLE_COMMAND( clearHistogram, "", 0 ) { 755 histogram.Clear(); 756 } 757 758 int idFile_Memory::Write( const void *buffer, int len ) { 759 if ( len == 0 ) { 760 // ~4% falls into this case for some reason... 761 return 0; 762 } 763 764 if ( !( mode & ( 1 << FS_WRITE ) ) ) { 765 common->FatalError( "idFile_Memory::Write: %s not opened in write mode", name.c_str() ); 766 return 0; 767 } 768 769 int alloc = curPtr + len + 1 - filePtr - allocated; // need room for len+1 770 if ( alloc > 0 ) { 771 if ( maxSize != 0 ) { 772 common->Error( "idFile_Memory::Write: exceeded maximum size %d", maxSize ); 773 return 0; 774 } 775 int extra = granularity * ( 1 + alloc / granularity ); 776 char *newPtr = (char *) Mem_Alloc( allocated + extra, TAG_IDFILE ); 777 if ( allocated ) { 778 memcpy( newPtr, filePtr, allocated ); 779 } 780 allocated += extra; 781 curPtr = newPtr + ( curPtr - filePtr ); 782 if ( filePtr ) { 783 Mem_Free( filePtr ); 784 } 785 filePtr = newPtr; 786 } 787 788 //memcpy( curPtr, buffer, len ); 789 memcpy2( curPtr, buffer, len ); 790 791 #if 0 792 if ( memcpyImpl.GetInteger() == 0 ) { 793 memcpy( curPtr, buffer, len ); 794 } else if ( memcpyImpl.GetInteger() == 1 ) { 795 memcpy( curPtr, buffer, len ); 796 } else if ( memcpyImpl.GetInteger() == 2 ) { 797 memcpy2( curPtr, buffer, len ); 798 } 799 #endif 800 801 #if 0 802 int * value; 803 if ( histogram.Get( len, &value ) && value != NULL ) { 804 (*value)++; 805 } else { 806 histogram.Set( len, 1 ); 807 } 808 #endif 809 810 curPtr += len; 811 fileSize += len; 812 filePtr[ fileSize ] = 0; // len + 1 813 return len; 814 } 815 816 /* 817 ================= 818 idFile_Memory::Length 819 ================= 820 */ 821 int idFile_Memory::Length() const { 822 return fileSize; 823 } 824 825 /* 826 ======================== 827 idFile_Memory::SetLength 828 ======================== 829 */ 830 void idFile_Memory::SetLength( size_t len ) { 831 PreAllocate( len ); 832 fileSize = len; 833 } 834 835 /* 836 ======================== 837 idFile_Memory::PreAllocate 838 ======================== 839 */ 840 void idFile_Memory::PreAllocate( size_t len ) { 841 if ( len > allocated ) { 842 if ( maxSize != 0 ) { 843 idLib::Error( "idFile_Memory::SetLength: exceeded maximum size %d", maxSize ); 844 } 845 char * newPtr = (char *)Mem_Alloc( len, TAG_IDFILE ); 846 if ( allocated > 0 ) { 847 memcpy( newPtr, filePtr, allocated ); 848 } 849 allocated = len; 850 curPtr = newPtr + ( curPtr - filePtr ); 851 if ( filePtr != NULL ) { 852 Mem_Free( filePtr ); 853 } 854 filePtr = newPtr; 855 } 856 } 857 858 /* 859 ================= 860 idFile_Memory::Timestamp 861 ================= 862 */ 863 ID_TIME_T idFile_Memory::Timestamp() const { 864 return 0; 865 } 866 867 /* 868 ================= 869 idFile_Memory::Tell 870 ================= 871 */ 872 int idFile_Memory::Tell() const { 873 return ( curPtr - filePtr ); 874 } 875 876 /* 877 ================= 878 idFile_Memory::ForceFlush 879 ================= 880 */ 881 void idFile_Memory::ForceFlush() { 882 } 883 884 /* 885 ================= 886 idFile_Memory::Flush 887 ================= 888 */ 889 void idFile_Memory::Flush() { 890 } 891 892 /* 893 ================= 894 idFile_Memory::Seek 895 896 returns zero on success and -1 on failure 897 ================= 898 */ 899 int idFile_Memory::Seek( long offset, fsOrigin_t origin ) { 900 901 switch( origin ) { 902 case FS_SEEK_CUR: { 903 curPtr += offset; 904 break; 905 } 906 case FS_SEEK_END: { 907 curPtr = filePtr + fileSize - offset; 908 break; 909 } 910 case FS_SEEK_SET: { 911 curPtr = filePtr + offset; 912 break; 913 } 914 default: { 915 common->FatalError( "idFile_Memory::Seek: bad origin for %s\n", name.c_str() ); 916 return -1; 917 } 918 } 919 if ( curPtr < filePtr ) { 920 curPtr = filePtr; 921 return -1; 922 } 923 if ( curPtr > filePtr + fileSize ) { 924 curPtr = filePtr + fileSize; 925 return -1; 926 } 927 return 0; 928 } 929 930 /* 931 ======================== 932 idFile_Memory::SetMaxLength 933 ======================== 934 */ 935 void idFile_Memory::SetMaxLength( size_t len ) { 936 size_t oldLength = fileSize; 937 938 SetLength( len ); 939 940 maxSize = len; 941 fileSize = oldLength; 942 } 943 944 /* 945 ================= 946 idFile_Memory::MakeReadOnly 947 ================= 948 */ 949 void idFile_Memory::MakeReadOnly() { 950 mode = ( 1 << FS_READ ); 951 Rewind(); 952 } 953 954 /* 955 ======================== 956 idFile_Memory::MakeWritable 957 ======================== 958 */ 959 void idFile_Memory::MakeWritable() { 960 mode = ( 1 << FS_WRITE ); 961 Rewind(); 962 } 963 964 /* 965 ================= 966 idFile_Memory::Clear 967 ================= 968 */ 969 void idFile_Memory::Clear( bool freeMemory ) { 970 fileSize = 0; 971 granularity = 16384; 972 if ( freeMemory ) { 973 allocated = 0; 974 Mem_Free( filePtr ); 975 filePtr = NULL; 976 curPtr = NULL; 977 } else { 978 curPtr = filePtr; 979 } 980 } 981 982 /* 983 ================= 984 idFile_Memory::SetData 985 ================= 986 */ 987 void idFile_Memory::SetData( const char *data, int length ) { 988 maxSize = 0; 989 fileSize = length; 990 allocated = 0; 991 granularity = 16384; 992 993 mode = ( 1 << FS_READ ); 994 filePtr = const_cast<char *>(data); 995 curPtr = const_cast<char *>(data); 996 } 997 998 /* 999 ======================== 1000 idFile_Memory::TruncateData 1001 ======================== 1002 */ 1003 void idFile_Memory::TruncateData( size_t len ) { 1004 if ( len > allocated ) { 1005 idLib::Error( "idFile_Memory::TruncateData: len (%d) exceeded allocated size (%d)", len, allocated ); 1006 } else { 1007 fileSize = len; 1008 } 1009 } 1010 1011 /* 1012 ================================================================================= 1013 1014 idFile_BitMsg 1015 1016 ================================================================================= 1017 */ 1018 1019 /* 1020 ================= 1021 idFile_BitMsg::idFile_BitMsg 1022 ================= 1023 */ 1024 idFile_BitMsg::idFile_BitMsg( idBitMsg &msg ) { 1025 name = "*unknown*"; 1026 mode = ( 1 << FS_WRITE ); 1027 this->msg = &msg; 1028 } 1029 1030 /* 1031 ================= 1032 idFile_BitMsg::idFile_BitMsg 1033 ================= 1034 */ 1035 idFile_BitMsg::idFile_BitMsg( const idBitMsg &msg ) { 1036 name = "*unknown*"; 1037 mode = ( 1 << FS_READ ); 1038 this->msg = const_cast<idBitMsg *>(&msg); 1039 } 1040 1041 /* 1042 ================= 1043 idFile_BitMsg::~idFile_BitMsg 1044 ================= 1045 */ 1046 idFile_BitMsg::~idFile_BitMsg() { 1047 } 1048 1049 /* 1050 ================= 1051 idFile_BitMsg::Read 1052 ================= 1053 */ 1054 int idFile_BitMsg::Read( void *buffer, int len ) { 1055 1056 if ( !( mode & ( 1 << FS_READ ) ) ) { 1057 common->FatalError( "idFile_BitMsg::Read: %s not opened in read mode", name.c_str() ); 1058 return 0; 1059 } 1060 1061 return msg->ReadData( buffer, len ); 1062 } 1063 1064 /* 1065 ================= 1066 idFile_BitMsg::Write 1067 ================= 1068 */ 1069 int idFile_BitMsg::Write( const void *buffer, int len ) { 1070 1071 if ( !( mode & ( 1 << FS_WRITE ) ) ) { 1072 common->FatalError( "idFile_Memory::Write: %s not opened in write mode", name.c_str() ); 1073 return 0; 1074 } 1075 1076 msg->WriteData( buffer, len ); 1077 return len; 1078 } 1079 1080 /* 1081 ================= 1082 idFile_BitMsg::Length 1083 ================= 1084 */ 1085 int idFile_BitMsg::Length() const { 1086 return msg->GetSize(); 1087 } 1088 1089 /* 1090 ================= 1091 idFile_BitMsg::Timestamp 1092 ================= 1093 */ 1094 ID_TIME_T idFile_BitMsg::Timestamp() const { 1095 return 0; 1096 } 1097 1098 /* 1099 ================= 1100 idFile_BitMsg::Tell 1101 ================= 1102 */ 1103 int idFile_BitMsg::Tell() const { 1104 if ( mode == FS_READ ) { 1105 return msg->GetReadCount(); 1106 } else { 1107 return msg->GetSize(); 1108 } 1109 } 1110 1111 /* 1112 ================= 1113 idFile_BitMsg::ForceFlush 1114 ================= 1115 */ 1116 void idFile_BitMsg::ForceFlush() { 1117 } 1118 1119 /* 1120 ================= 1121 idFile_BitMsg::Flush 1122 ================= 1123 */ 1124 void idFile_BitMsg::Flush() { 1125 } 1126 1127 /* 1128 ================= 1129 idFile_BitMsg::Seek 1130 1131 returns zero on success and -1 on failure 1132 ================= 1133 */ 1134 int idFile_BitMsg::Seek( long offset, fsOrigin_t origin ) { 1135 return -1; 1136 } 1137 1138 1139 /* 1140 ================================================================================= 1141 1142 idFile_Permanent 1143 1144 ================================================================================= 1145 */ 1146 1147 /* 1148 ================= 1149 idFile_Permanent::idFile_Permanent 1150 ================= 1151 */ 1152 idFile_Permanent::idFile_Permanent() { 1153 name = "invalid"; 1154 o = NULL; 1155 mode = 0; 1156 fileSize = 0; 1157 handleSync = false; 1158 } 1159 1160 /* 1161 ================= 1162 idFile_Permanent::~idFile_Permanent 1163 ================= 1164 */ 1165 idFile_Permanent::~idFile_Permanent() { 1166 if ( o ) { 1167 CloseHandle( o ); 1168 } 1169 } 1170 1171 /* 1172 ================= 1173 idFile_Permanent::Read 1174 1175 Properly handles partial reads 1176 ================= 1177 */ 1178 int idFile_Permanent::Read( void *buffer, int len ) { 1179 int block, remaining; 1180 int read; 1181 byte * buf; 1182 int tries; 1183 1184 if ( !(mode & ( 1 << FS_READ ) ) ) { 1185 common->FatalError( "idFile_Permanent::Read: %s not opened in read mode", name.c_str() ); 1186 return 0; 1187 } 1188 1189 if ( !o ) { 1190 return 0; 1191 } 1192 1193 buf = (byte *)buffer; 1194 1195 remaining = len; 1196 tries = 0; 1197 while( remaining ) { 1198 block = remaining; 1199 DWORD bytesRead; 1200 if ( !ReadFile( o, buf, block, &bytesRead, NULL ) ) { 1201 idLib::Warning( "idFile_Permanent::Read failed with %d from %s", GetLastError(), name.c_str() ); 1202 } 1203 read = bytesRead; 1204 if ( read == 0 ) { 1205 // we might have been trying to read from a CD, which 1206 // sometimes returns a 0 read on windows 1207 if ( !tries ) { 1208 tries = 1; 1209 } 1210 else { 1211 return len-remaining; 1212 } 1213 } 1214 1215 if ( read == -1 ) { 1216 common->FatalError( "idFile_Permanent::Read: -1 bytes read from %s", name.c_str() ); 1217 } 1218 1219 remaining -= read; 1220 buf += read; 1221 } 1222 return len; 1223 } 1224 1225 /* 1226 ================= 1227 idFile_Permanent::Write 1228 1229 Properly handles partial writes 1230 ================= 1231 */ 1232 int idFile_Permanent::Write( const void *buffer, int len ) { 1233 int block, remaining; 1234 int written; 1235 byte * buf; 1236 int tries; 1237 1238 if ( !( mode & ( 1 << FS_WRITE ) ) ) { 1239 common->FatalError( "idFile_Permanent::Write: %s not opened in write mode", name.c_str() ); 1240 return 0; 1241 } 1242 1243 if ( !o ) { 1244 return 0; 1245 } 1246 1247 buf = (byte *)buffer; 1248 1249 remaining = len; 1250 tries = 0; 1251 while( remaining ) { 1252 block = remaining; 1253 DWORD bytesWritten; 1254 WriteFile( o, buf, block, &bytesWritten, NULL ); 1255 written = bytesWritten; 1256 if ( written == 0 ) { 1257 if ( !tries ) { 1258 tries = 1; 1259 } 1260 else { 1261 common->Printf( "idFile_Permanent::Write: 0 bytes written to %s\n", name.c_str() ); 1262 return 0; 1263 } 1264 } 1265 1266 if ( written == -1 ) { 1267 common->Printf( "idFile_Permanent::Write: -1 bytes written to %s\n", name.c_str() ); 1268 return 0; 1269 } 1270 1271 remaining -= written; 1272 buf += written; 1273 fileSize += written; 1274 } 1275 if ( handleSync ) { 1276 Flush(); 1277 } 1278 return len; 1279 } 1280 1281 /* 1282 ================= 1283 idFile_Permanent::ForceFlush 1284 ================= 1285 */ 1286 void idFile_Permanent::ForceFlush() { 1287 FlushFileBuffers( o ); 1288 } 1289 1290 /* 1291 ================= 1292 idFile_Permanent::Flush 1293 ================= 1294 */ 1295 void idFile_Permanent::Flush() { 1296 FlushFileBuffers( o ); 1297 } 1298 1299 /* 1300 ================= 1301 idFile_Permanent::Tell 1302 ================= 1303 */ 1304 int idFile_Permanent::Tell() const { 1305 return SetFilePointer( o, 0, NULL, FILE_CURRENT ); 1306 } 1307 1308 /* 1309 ================ 1310 idFile_Permanent::Length 1311 ================ 1312 */ 1313 int idFile_Permanent::Length() const { 1314 return fileSize; 1315 } 1316 1317 /* 1318 ================ 1319 idFile_Permanent::Timestamp 1320 ================ 1321 */ 1322 ID_TIME_T idFile_Permanent::Timestamp() const { 1323 ID_TIME_T ts = Sys_FileTimeStamp( o ); 1324 return ts; 1325 } 1326 1327 /* 1328 ================= 1329 idFile_Permanent::Seek 1330 1331 returns zero on success and -1 on failure 1332 ================= 1333 */ 1334 int idFile_Permanent::Seek( long offset, fsOrigin_t origin ) { 1335 int retVal = INVALID_SET_FILE_POINTER; 1336 switch( origin ) { 1337 case FS_SEEK_CUR: retVal = SetFilePointer( o, offset, NULL, FILE_CURRENT ); break; 1338 case FS_SEEK_END: retVal = SetFilePointer( o, offset, NULL, FILE_END ); break; 1339 case FS_SEEK_SET: retVal = SetFilePointer( o, offset, NULL, FILE_BEGIN ); break; 1340 } 1341 return ( retVal == INVALID_SET_FILE_POINTER ) ? -1 : 0; 1342 } 1343 1344 #if 1 1345 /* 1346 ================================================================================= 1347 1348 idFile_Cached 1349 1350 ================================================================================= 1351 */ 1352 1353 /* 1354 ================= 1355 idFile_Cached::idFile_Cached 1356 ================= 1357 */ 1358 idFile_Cached::idFile_Cached() : idFile_Permanent() { 1359 internalFilePos = 0; 1360 bufferedStartOffset = 0; 1361 bufferedEndOffset = 0; 1362 buffered = NULL; 1363 } 1364 1365 /* 1366 ================= 1367 idFile_Cached::~idFile_Cached 1368 ================= 1369 */ 1370 idFile_Cached::~idFile_Cached() { 1371 Mem_Free( buffered ); 1372 } 1373 1374 /* 1375 ================= 1376 idFile_ReadBuffered::BufferData 1377 1378 Buffer a section of the file 1379 ================= 1380 */ 1381 void idFile_Cached::CacheData( uint64 offset, uint64 length ) { 1382 Mem_Free( buffered ); 1383 bufferedStartOffset = offset; 1384 bufferedEndOffset = offset + length; 1385 buffered = ( byte* )Mem_Alloc( length, TAG_RESOURCE ); 1386 if ( buffered == NULL ) { 1387 return; 1388 } 1389 int internalFilePos = idFile_Permanent::Tell(); 1390 idFile_Permanent::Seek( offset, FS_SEEK_SET ); 1391 idFile_Permanent::Read( buffered, length ); 1392 idFile_Permanent::Seek( internalFilePos, FS_SEEK_SET ); 1393 } 1394 1395 /* 1396 ================= 1397 idFile_ReadBuffered::Read 1398 1399 ================= 1400 */ 1401 int idFile_Cached::Read( void *buffer, int len ) { 1402 if ( internalFilePos >= bufferedStartOffset && internalFilePos + len < bufferedEndOffset ) { 1403 // this is in the buffer 1404 memcpy( buffer, (void*)&buffered[ internalFilePos - bufferedStartOffset ], len ); 1405 internalFilePos += len; 1406 return len; 1407 } 1408 int read = idFile_Permanent::Read( buffer, len ); 1409 if ( read != -1 ) { 1410 internalFilePos += ( int64 )read; 1411 } 1412 return read; 1413 } 1414 1415 1416 1417 /* 1418 ================= 1419 idFile_Cached::Tell 1420 ================= 1421 */ 1422 int idFile_Cached::Tell() const { 1423 return internalFilePos; 1424 } 1425 1426 /* 1427 ================= 1428 idFile_Cached::Seek 1429 1430 returns zero on success and -1 on failure 1431 ================= 1432 */ 1433 int idFile_Cached::Seek( long offset, fsOrigin_t origin ) { 1434 if ( origin == FS_SEEK_SET && offset >= bufferedStartOffset && offset < bufferedEndOffset ) { 1435 // don't do anything to the actual file ptr, just update or internal position 1436 internalFilePos = offset; 1437 return 0; 1438 } 1439 1440 int retVal = idFile_Permanent::Seek( offset, origin ); 1441 internalFilePos = idFile_Permanent::Tell(); 1442 return retVal; 1443 } 1444 #endif 1445 1446 /* 1447 ================================================================================= 1448 1449 idFile_InZip 1450 1451 ================================================================================= 1452 */ 1453 1454 /* 1455 ================= 1456 idFile_InZip::idFile_InZip 1457 ================= 1458 */ 1459 idFile_InZip::idFile_InZip() { 1460 name = "invalid"; 1461 zipFilePos = 0; 1462 fileSize = 0; 1463 memset( &z, 0, sizeof( z ) ); 1464 } 1465 1466 /* 1467 ================= 1468 idFile_InZip::~idFile_InZip 1469 ================= 1470 */ 1471 idFile_InZip::~idFile_InZip() { 1472 unzCloseCurrentFile( z ); 1473 unzClose( z ); 1474 } 1475 1476 /* 1477 ================= 1478 idFile_InZip::Read 1479 1480 Properly handles partial reads 1481 ================= 1482 */ 1483 int idFile_InZip::Read( void *buffer, int len ) { 1484 int l = unzReadCurrentFile( z, buffer, len ); 1485 return l; 1486 } 1487 1488 /* 1489 ================= 1490 idFile_InZip::Write 1491 ================= 1492 */ 1493 int idFile_InZip::Write( const void *buffer, int len ) { 1494 common->FatalError( "idFile_InZip::Write: cannot write to the zipped file %s", name.c_str() ); 1495 return 0; 1496 } 1497 1498 /* 1499 ================= 1500 idFile_InZip::ForceFlush 1501 ================= 1502 */ 1503 void idFile_InZip::ForceFlush() { 1504 common->FatalError( "idFile_InZip::ForceFlush: cannot flush the zipped file %s", name.c_str() ); 1505 } 1506 1507 /* 1508 ================= 1509 idFile_InZip::Flush 1510 ================= 1511 */ 1512 void idFile_InZip::Flush() { 1513 common->FatalError( "idFile_InZip::Flush: cannot flush the zipped file %s", name.c_str() ); 1514 } 1515 1516 /* 1517 ================= 1518 idFile_InZip::Tell 1519 ================= 1520 */ 1521 int idFile_InZip::Tell() const { 1522 return unztell( z ); 1523 } 1524 1525 /* 1526 ================ 1527 idFile_InZip::Length 1528 ================ 1529 */ 1530 int idFile_InZip::Length() const { 1531 return fileSize; 1532 } 1533 1534 /* 1535 ================ 1536 idFile_InZip::Timestamp 1537 ================ 1538 */ 1539 ID_TIME_T idFile_InZip::Timestamp() const { 1540 return 0; 1541 } 1542 1543 /* 1544 ================= 1545 idFile_InZip::Seek 1546 1547 returns zero on success and -1 on failure 1548 ================= 1549 */ 1550 #define ZIP_SEEK_BUF_SIZE (1<<15) 1551 1552 int idFile_InZip::Seek( long offset, fsOrigin_t origin ) { 1553 int res, i; 1554 char *buf; 1555 1556 switch( origin ) { 1557 case FS_SEEK_END: { 1558 offset = fileSize - offset; 1559 } 1560 case FS_SEEK_SET: { 1561 // set the file position in the zip file (also sets the current file info) 1562 unzSetCurrentFileInfoPosition( z, zipFilePos ); 1563 unzOpenCurrentFile( z ); 1564 if ( offset <= 0 ) { 1565 return 0; 1566 } 1567 } 1568 case FS_SEEK_CUR: { 1569 buf = (char *) _alloca16( ZIP_SEEK_BUF_SIZE ); 1570 for ( i = 0; i < ( offset - ZIP_SEEK_BUF_SIZE ); i += ZIP_SEEK_BUF_SIZE ) { 1571 res = unzReadCurrentFile( z, buf, ZIP_SEEK_BUF_SIZE ); 1572 if ( res < ZIP_SEEK_BUF_SIZE ) { 1573 return -1; 1574 } 1575 } 1576 res = i + unzReadCurrentFile( z, buf, offset - i ); 1577 return ( res == offset ) ? 0 : -1; 1578 } 1579 default: { 1580 common->FatalError( "idFile_InZip::Seek: bad origin for %s\n", name.c_str() ); 1581 break; 1582 } 1583 } 1584 return -1; 1585 } 1586 1587 #if 1 1588 1589 /* 1590 ================================================================================= 1591 1592 idFile_InnerResource 1593 1594 ================================================================================= 1595 */ 1596 1597 /* 1598 ================= 1599 idFile_InnerResource::idFile_InnerResource 1600 ================= 1601 */ 1602 idFile_InnerResource::idFile_InnerResource( const char *_name, idFile *rezFile, int _offset, int _len ) { 1603 name = _name; 1604 offset = _offset; 1605 length = _len; 1606 resourceFile = rezFile; 1607 internalFilePos = 0; 1608 resourceBuffer = NULL; 1609 } 1610 1611 /* 1612 ================= 1613 idFile_InnerResource::~idFile_InnerResource 1614 ================= 1615 */ 1616 idFile_InnerResource::~idFile_InnerResource() { 1617 if ( resourceBuffer != NULL ) { 1618 fileSystem->FreeResourceBuffer(); 1619 } 1620 } 1621 1622 /* 1623 ================= 1624 idFile_InnerResource::Read 1625 1626 Properly handles partial reads 1627 ================= 1628 */ 1629 int idFile_InnerResource::Read( void *buffer, int len ) { 1630 if ( resourceFile == NULL ) { 1631 return 0; 1632 } 1633 1634 if ( internalFilePos + len > length ) { 1635 len = length - internalFilePos; 1636 } 1637 1638 int read = 0; //fileSystem->ReadFromBGL( resourceFile, (byte*)buffer, offset + internalFilePos, len ); 1639 1640 if ( read != len ) { 1641 if ( resourceBuffer != NULL ) { 1642 memcpy( buffer, &resourceBuffer[ internalFilePos ], len ); 1643 read = len; 1644 } else { 1645 read = fileSystem->ReadFromBGL( resourceFile, buffer, offset + internalFilePos, len ); 1646 } 1647 } 1648 1649 internalFilePos += read; 1650 1651 return read; 1652 } 1653 1654 /* 1655 ================= 1656 idFile_InnerResource::Tell 1657 ================= 1658 */ 1659 int idFile_InnerResource::Tell() const { 1660 return internalFilePos; 1661 } 1662 1663 1664 /* 1665 ================= 1666 idFile_InnerResource::Seek 1667 1668 returns zero on success and -1 on failure 1669 ================= 1670 */ 1671 1672 int idFile_InnerResource::Seek( long offset, fsOrigin_t origin ) { 1673 switch( origin ) { 1674 case FS_SEEK_END: { 1675 internalFilePos = length - offset - 1; 1676 return 0; 1677 } 1678 case FS_SEEK_SET: { 1679 internalFilePos = offset; 1680 if ( internalFilePos >= 0 && internalFilePos < length ) { 1681 return 0; 1682 } 1683 return -1; 1684 } 1685 case FS_SEEK_CUR: { 1686 internalFilePos += offset; 1687 if ( internalFilePos >= 0 && internalFilePos < length ) { 1688 return 0; 1689 } 1690 return -1; 1691 } 1692 default: { 1693 common->FatalError( "idFile_InnerResource::Seek: bad origin for %s\n", name.c_str() ); 1694 break; 1695 } 1696 } 1697 return -1; 1698 } 1699 #endif 1700 1701 /* 1702 ================================================================================================ 1703 1704 idFileLocal 1705 1706 ================================================================================================ 1707 */ 1708 1709 /* 1710 ======================== 1711 idFileLocal::~idFileLocal 1712 1713 Destructor that will destroy (close) the managed file when this wrapper class goes out of scope. 1714 ======================== 1715 */ 1716 idFileLocal::~idFileLocal() { 1717 if ( file != NULL ) { 1718 delete file; 1719 file = NULL; 1720 } 1721 } 1722 1723 static const char * testEndianNessFilename = "temp.bin"; 1724 struct testEndianNess_t { 1725 testEndianNess_t() { 1726 a = 0x12345678; 1727 b = 0x12345678; 1728 c = 3.0f; 1729 d = -4.0f; 1730 e = "test"; 1731 f = idVec3( 1.0f, 2.0f, -3.0f ); 1732 g = false; 1733 h = true; 1734 for ( int index = 0; index < sizeof( i ); index++ ) { 1735 i[index] = 0x37; 1736 } 1737 } 1738 bool operator==( testEndianNess_t & test ) const { 1739 return a == test.a && 1740 b == test.b && 1741 c == test.c && 1742 d == test.d && 1743 e == test.e && 1744 f == test.f && 1745 g == test.g && 1746 h == test.h && 1747 ( memcmp( i, test.i, sizeof( i ) ) == 0 ); 1748 } 1749 int a; 1750 unsigned int b; 1751 float c; 1752 float d; 1753 idStr e; 1754 idVec3 f; 1755 bool g; 1756 bool h; 1757 byte i[10]; 1758 }; 1759 CONSOLE_COMMAND( testEndianNessWrite, "Tests the read/write compatibility between platforms", 0 ) { 1760 idFileLocal file( fileSystem->OpenFileWrite( testEndianNessFilename ) ); 1761 if ( file == NULL ) { 1762 idLib::Printf( "Couldn't open the %s testfile.\n", testEndianNessFilename ); 1763 return; 1764 } 1765 1766 testEndianNess_t testData; 1767 1768 file->WriteBig( testData.a ); 1769 file->WriteBig( testData.b ); 1770 file->WriteFloat( testData.c ); 1771 file->WriteFloat( testData.d ); 1772 file->WriteString( testData.e ); 1773 file->WriteVec3( testData.f ); 1774 file->WriteBig( testData.g ); 1775 file->WriteBig( testData.h ); 1776 file->Write( testData.i, sizeof( testData.i )/ sizeof( testData.i[0] ) ); 1777 } 1778 1779 CONSOLE_COMMAND( testEndianNessRead, "Tests the read/write compatibility between platforms", 0 ) { 1780 idFileLocal file( fileSystem->OpenFileRead( testEndianNessFilename ) ); 1781 if ( file == NULL ) { 1782 idLib::Printf( "Couldn't find the %s testfile.\n", testEndianNessFilename ); 1783 return; 1784 } 1785 1786 testEndianNess_t srcData; 1787 testEndianNess_t testData; 1788 1789 memset( &testData, 0, sizeof( testData ) ); 1790 1791 file->ReadBig( testData.a ); 1792 file->ReadBig( testData.b ); 1793 file->ReadFloat( testData.c ); 1794 file->ReadFloat( testData.d ); 1795 file->ReadString( testData.e ); 1796 file->ReadVec3( testData.f ); 1797 file->ReadBig( testData.g ); 1798 file->ReadBig( testData.h ); 1799 file->Read( testData.i, sizeof( testData.i )/ sizeof( testData.i[0] ) ); 1800 1801 assert( srcData == testData ); 1802 } 1803 1804 CONSOLE_COMMAND( testEndianNessReset, "Tests the read/write compatibility between platforms", 0 ) { 1805 fileSystem->RemoveFile( testEndianNessFilename ); 1806 } 1807 1808