DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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