2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 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.
14 Doom 3 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.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
34 #define MAX_PRINT_MSG 4096
41 int FS_WriteFloatString( char *buf, const char *fmt, va_list argPtr ) {
56 while ( (*fmt >= '0' && *fmt <= '9') ||
57 *fmt == '.' || *fmt == '-' || *fmt == '+' || *fmt == '#') {
67 f = va_arg( argPtr, double );
68 if ( format.Length() <= 2 ) {
69 // high precision floating point number without trailing zeros
70 sprintf( tmp, "%1.10f", f );
71 tmp.StripTrailing( '0' );
72 tmp.StripTrailing( '.' );
73 index += sprintf( buf+index, "%s", tmp.c_str() );
76 index += sprintf( buf+index, format.c_str(), f );
81 i = va_arg( argPtr, long );
82 index += sprintf( buf+index, format.c_str(), i );
85 u = va_arg( argPtr, unsigned long );
86 index += sprintf( buf+index, format.c_str(), u );
89 u = va_arg( argPtr, unsigned long );
90 index += sprintf( buf+index, format.c_str(), u );
93 u = va_arg( argPtr, unsigned long );
94 index += sprintf( buf+index, format.c_str(), u );
97 u = va_arg( argPtr, unsigned long );
98 index += sprintf( buf+index, format.c_str(), u );
101 i = va_arg( argPtr, long );
102 index += sprintf( buf+index, format.c_str(), (char) i );
105 str = va_arg( argPtr, char * );
106 index += sprintf( buf+index, format.c_str(), str );
109 index += sprintf( buf+index, format.c_str() );
112 common->Error( "FS_WriteFloatString: invalid format %s", format.c_str() );
121 index += sprintf( buf+index, "\t" );
124 index += sprintf( buf+index, "\v" );
127 index += sprintf( buf+index, "\n" );
130 index += sprintf( buf+index, "\\" );
133 common->Error( "FS_WriteFloatString: unknown escape character \'%c\'", *fmt );
139 index += sprintf( buf+index, "%c", *fmt );
149 =================================================================================
153 =================================================================================
161 const char *idFile::GetName( void ) {
170 const char *idFile::GetFullPath( void ) {
179 int idFile::Read( void *buffer, int len ) {
180 common->FatalError( "idFile::Read: cannot read from idFile" );
189 int idFile::Write( const void *buffer, int len ) {
190 common->FatalError( "idFile::Write: cannot write to idFile" );
199 int idFile::Length( void ) {
208 ID_TIME_T idFile::Timestamp( void ) {
217 int idFile::Tell( void ) {
226 void idFile::ForceFlush( void ) {
234 void idFile::Flush( void ) {
242 int idFile::Seek( long offset, fsOrigin_t origin ) {
251 void idFile::Rewind( void ) {
252 Seek( 0, FS_SEEK_SET );
260 int idFile::Printf( const char *fmt, ... ) {
261 char buf[MAX_PRINT_MSG];
265 va_start( argptr, fmt );
266 length = idStr::vsnPrintf( buf, MAX_PRINT_MSG-1, fmt, argptr );
269 // so notepad formats the lines correctly
271 work.Replace( "\n", "\r\n" );
273 return Write( work.c_str(), work.Length() );
281 int idFile::VPrintf( const char *fmt, va_list args ) {
282 char buf[MAX_PRINT_MSG];
285 length = idStr::vsnPrintf( buf, MAX_PRINT_MSG-1, fmt, args );
286 return Write( buf, length );
291 idFile::WriteFloatString
294 int idFile::WriteFloatString( const char *fmt, ... ) {
295 char buf[MAX_PRINT_MSG];
299 va_start( argPtr, fmt );
300 len = FS_WriteFloatString( buf, fmt, argPtr );
303 return Write( buf, len );
311 int idFile::ReadInt( int &value ) {
312 int result = Read( &value, sizeof( value ) );
313 value = LittleLong(value);
319 idFile::ReadUnsignedInt
322 int idFile::ReadUnsignedInt( unsigned int &value ) {
323 int result = Read( &value, sizeof( value ) );
324 value = LittleLong(value);
333 int idFile::ReadShort( short &value ) {
334 int result = Read( &value, sizeof( value ) );
335 value = LittleShort(value);
341 idFile::ReadUnsignedShort
344 int idFile::ReadUnsignedShort( unsigned short &value ) {
345 int result = Read( &value, sizeof( value ) );
346 value = LittleShort(value);
355 int idFile::ReadChar( char &value ) {
356 return Read( &value, sizeof( value ) );
361 idFile::ReadUnsignedChar
364 int idFile::ReadUnsignedChar( unsigned char &value ) {
365 return Read( &value, sizeof( value ) );
373 int idFile::ReadFloat( float &value ) {
374 int result = Read( &value, sizeof( value ) );
375 value = LittleFloat(value);
384 int idFile::ReadBool( bool &value ) {
386 int result = ReadUnsignedChar( c );
387 value = c ? true : false;
396 int idFile::ReadString( idStr &string ) {
402 string.Fill( ' ', len );
403 result = Read( &string[ 0 ], len );
413 int idFile::ReadVec2( idVec2 &vec ) {
414 int result = Read( &vec, sizeof( vec ) );
415 LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) );
424 int idFile::ReadVec3( idVec3 &vec ) {
425 int result = Read( &vec, sizeof( vec ) );
426 LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) );
435 int idFile::ReadVec4( idVec4 &vec ) {
436 int result = Read( &vec, sizeof( vec ) );
437 LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) );
446 int idFile::ReadVec6( idVec6 &vec ) {
447 int result = Read( &vec, sizeof( vec ) );
448 LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) );
457 int idFile::ReadMat3( idMat3 &mat ) {
458 int result = Read( &mat, sizeof( mat ) );
459 LittleRevBytes( &mat, sizeof(float), sizeof(mat)/sizeof(float) );
468 int idFile::WriteInt( const int value ) {
469 int v = LittleLong(value);
470 return Write( &v, sizeof( v ) );
475 idFile::WriteUnsignedInt
478 int idFile::WriteUnsignedInt( const unsigned int value ) {
479 unsigned int v = LittleLong(value);
480 return Write( &v, sizeof( v ) );
488 int idFile::WriteShort( const short value ) {
489 short v = LittleShort(value);
490 return Write( &v, sizeof( v ) );
495 idFile::WriteUnsignedShort
498 int idFile::WriteUnsignedShort( const unsigned short value ) {
499 unsigned short v = LittleShort(value);
500 return Write( &v, sizeof( v ) );
508 int idFile::WriteChar( const char value ) {
509 return Write( &value, sizeof( value ) );
514 idFile::WriteUnsignedChar
517 int idFile::WriteUnsignedChar( const unsigned char value ) {
518 return Write( &value, sizeof( value ) );
526 int idFile::WriteFloat( const float value ) {
527 float v = LittleFloat(value);
528 return Write( &v, sizeof( v ) );
536 int idFile::WriteBool( const bool value ) {
537 unsigned char c = value;
538 return WriteUnsignedChar( c );
546 int idFile::WriteString( const char *value ) {
549 len = strlen( value );
551 return Write( value, len );
559 int idFile::WriteVec2( const idVec2 &vec ) {
561 LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) );
562 return Write( &v, sizeof( v ) );
570 int idFile::WriteVec3( const idVec3 &vec ) {
572 LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) );
573 return Write( &v, sizeof( v ) );
581 int idFile::WriteVec4( const idVec4 &vec ) {
583 LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) );
584 return Write( &v, sizeof( v ) );
592 int idFile::WriteVec6( const idVec6 &vec ) {
594 LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) );
595 return Write( &v, sizeof( v ) );
603 int idFile::WriteMat3( const idMat3 &mat ) {
605 LittleRevBytes(&v, sizeof(float), sizeof(v)/sizeof(float) );
606 return Write( &v, sizeof( v ) );
610 =================================================================================
614 =================================================================================
620 idFile_Memory::idFile_Memory
623 idFile_Memory::idFile_Memory( void ) {
630 mode = ( 1 << FS_WRITE );
637 idFile_Memory::idFile_Memory
640 idFile_Memory::idFile_Memory( const char *name ) {
647 mode = ( 1 << FS_WRITE );
654 idFile_Memory::idFile_Memory
657 idFile_Memory::idFile_Memory( const char *name, char *data, int length ) {
664 mode = ( 1 << FS_WRITE );
671 idFile_Memory::idFile_Memory
674 idFile_Memory::idFile_Memory( const char *name, const char *data, int length ) {
681 mode = ( 1 << FS_READ );
682 filePtr = const_cast<char *>(data);
683 curPtr = const_cast<char *>(data);
688 idFile_Memory::~idFile_Memory
691 idFile_Memory::~idFile_Memory( void ) {
692 if ( filePtr && allocated > 0 && maxSize == 0 ) {
702 int idFile_Memory::Read( void *buffer, int len ) {
704 if ( !( mode & ( 1 << FS_READ ) ) ) {
705 common->FatalError( "idFile_Memory::Read: %s not opened in read mode", name.c_str() );
709 if ( curPtr + len > filePtr + fileSize ) {
710 len = filePtr + fileSize - curPtr;
712 memcpy( buffer, curPtr, len );
722 int idFile_Memory::Write( const void *buffer, int len ) {
724 if ( !( mode & ( 1 << FS_WRITE ) ) ) {
725 common->FatalError( "idFile_Memory::Write: %s not opened in write mode", name.c_str() );
729 int alloc = curPtr + len + 1 - filePtr - allocated; // need room for len+1
731 if ( maxSize != 0 ) {
732 common->Error( "idFile_Memory::Write: exceeded maximum size %d", maxSize );
735 int extra = granularity * ( 1 + alloc / granularity );
736 char *newPtr = (char *) Mem_Alloc( allocated + extra );
738 memcpy( newPtr, filePtr, allocated );
741 curPtr = newPtr + ( curPtr - filePtr );
747 memcpy( curPtr, buffer, len );
750 filePtr[ fileSize ] = 0; // len + 1
756 idFile_Memory::Length
759 int idFile_Memory::Length( void ) {
765 idFile_Memory::Timestamp
768 ID_TIME_T idFile_Memory::Timestamp( void ) {
777 int idFile_Memory::Tell( void ) {
778 return ( curPtr - filePtr );
783 idFile_Memory::ForceFlush
786 void idFile_Memory::ForceFlush( void ) {
794 void idFile_Memory::Flush( void ) {
801 returns zero on success and -1 on failure
804 int idFile_Memory::Seek( long offset, fsOrigin_t origin ) {
812 curPtr = filePtr + fileSize - offset;
816 curPtr = filePtr + offset;
820 common->FatalError( "idFile_Memory::Seek: bad origin for %s\n", name.c_str() );
824 if ( curPtr < filePtr ) {
828 if ( curPtr > filePtr + fileSize ) {
829 curPtr = filePtr + fileSize;
837 idFile_Memory::MakeReadOnly
840 void idFile_Memory::MakeReadOnly( void ) {
841 mode = ( 1 << FS_READ );
850 void idFile_Memory::Clear( bool freeMemory ) {
865 idFile_Memory::SetData
868 void idFile_Memory::SetData( const char *data, int length ) {
874 mode = ( 1 << FS_READ );
875 filePtr = const_cast<char *>(data);
876 curPtr = const_cast<char *>(data);
881 =================================================================================
885 =================================================================================
890 idFile_BitMsg::idFile_BitMsg
893 idFile_BitMsg::idFile_BitMsg( idBitMsg &msg ) {
895 mode = ( 1 << FS_WRITE );
901 idFile_BitMsg::idFile_BitMsg
904 idFile_BitMsg::idFile_BitMsg( const idBitMsg &msg ) {
906 mode = ( 1 << FS_READ );
907 this->msg = const_cast<idBitMsg *>(&msg);
912 idFile_BitMsg::~idFile_BitMsg
915 idFile_BitMsg::~idFile_BitMsg( void ) {
923 int idFile_BitMsg::Read( void *buffer, int len ) {
925 if ( !( mode & ( 1 << FS_READ ) ) ) {
926 common->FatalError( "idFile_BitMsg::Read: %s not opened in read mode", name.c_str() );
930 return msg->ReadData( buffer, len );
938 int idFile_BitMsg::Write( const void *buffer, int len ) {
940 if ( !( mode & ( 1 << FS_WRITE ) ) ) {
941 common->FatalError( "idFile_Memory::Write: %s not opened in write mode", name.c_str() );
945 msg->WriteData( buffer, len );
951 idFile_BitMsg::Length
954 int idFile_BitMsg::Length( void ) {
955 return msg->GetSize();
960 idFile_BitMsg::Timestamp
963 ID_TIME_T idFile_BitMsg::Timestamp( void ) {
972 int idFile_BitMsg::Tell( void ) {
973 if ( mode & FS_READ ) {
974 return msg->GetReadCount();
976 return msg->GetSize();
982 idFile_BitMsg::ForceFlush
985 void idFile_BitMsg::ForceFlush( void ) {
993 void idFile_BitMsg::Flush( void ) {
1000 returns zero on success and -1 on failure
1003 int idFile_BitMsg::Seek( long offset, fsOrigin_t origin ) {
1009 =================================================================================
1013 =================================================================================
1018 idFile_Permanent::idFile_Permanent
1021 idFile_Permanent::idFile_Permanent( void ) {
1031 idFile_Permanent::~idFile_Permanent
1034 idFile_Permanent::~idFile_Permanent( void ) {
1042 idFile_Permanent::Read
1044 Properly handles partial reads
1047 int idFile_Permanent::Read( void *buffer, int len ) {
1048 int block, remaining;
1053 if ( !(mode & ( 1 << FS_READ ) ) ) {
1054 common->FatalError( "idFile_Permanent::Read: %s not opened in read mode", name.c_str() );
1062 buf = (byte *)buffer;
1066 while( remaining ) {
1068 read = fread( buf, 1, block, o );
1070 // we might have been trying to read from a CD, which
1071 // sometimes returns a 0 read on windows
1076 fileSystem->AddToReadCount( len - remaining );
1077 return len-remaining;
1082 common->FatalError( "idFile_Permanent::Read: -1 bytes read from %s", name.c_str() );
1088 fileSystem->AddToReadCount( len );
1094 idFile_Permanent::Write
1096 Properly handles partial writes
1099 int idFile_Permanent::Write( const void *buffer, int len ) {
1100 int block, remaining;
1105 if ( !( mode & ( 1 << FS_WRITE ) ) ) {
1106 common->FatalError( "idFile_Permanent::Write: %s not opened in write mode", name.c_str() );
1114 buf = (byte *)buffer;
1118 while( remaining ) {
1120 written = fwrite( buf, 1, block, o );
1121 if ( written == 0 ) {
1126 common->Printf( "idFile_Permanent::Write: 0 bytes written to %s\n", name.c_str() );
1131 if ( written == -1 ) {
1132 common->Printf( "idFile_Permanent::Write: -1 bytes written to %s\n", name.c_str() );
1136 remaining -= written;
1138 fileSize += written;
1148 idFile_Permanent::ForceFlush
1151 void idFile_Permanent::ForceFlush( void ) {
1152 setvbuf( o, NULL, _IONBF, 0 );
1157 idFile_Permanent::Flush
1160 void idFile_Permanent::Flush( void ) {
1166 idFile_Permanent::Tell
1169 int idFile_Permanent::Tell( void ) {
1175 idFile_Permanent::Length
1178 int idFile_Permanent::Length( void ) {
1184 idFile_Permanent::Timestamp
1187 ID_TIME_T idFile_Permanent::Timestamp( void ) {
1188 return Sys_FileTimeStamp( o );
1193 idFile_Permanent::Seek
1195 returns zero on success and -1 on failure
1198 int idFile_Permanent::Seek( long offset, fsOrigin_t origin ) {
1216 common->FatalError( "idFile_Permanent::Seek: bad origin for %s\n", name.c_str() );
1221 return fseek( o, offset, _origin );
1226 =================================================================================
1230 =================================================================================
1235 idFile_InZip::idFile_InZip
1238 idFile_InZip::idFile_InZip( void ) {
1242 memset( &z, 0, sizeof( z ) );
1247 idFile_InZip::~idFile_InZip
1250 idFile_InZip::~idFile_InZip( void ) {
1251 unzCloseCurrentFile( z );
1259 Properly handles partial reads
1262 int idFile_InZip::Read( void *buffer, int len ) {
1263 int l = unzReadCurrentFile( z, buffer, len );
1264 fileSystem->AddToReadCount( l );
1273 int idFile_InZip::Write( const void *buffer, int len ) {
1274 common->FatalError( "idFile_InZip::Write: cannot write to the zipped file %s", name.c_str() );
1280 idFile_InZip::ForceFlush
1283 void idFile_InZip::ForceFlush( void ) {
1284 common->FatalError( "idFile_InZip::ForceFlush: cannot flush the zipped file %s", name.c_str() );
1292 void idFile_InZip::Flush( void ) {
1293 common->FatalError( "idFile_InZip::Flush: cannot flush the zipped file %s", name.c_str() );
1301 int idFile_InZip::Tell( void ) {
1302 return unztell( z );
1307 idFile_InZip::Length
1310 int idFile_InZip::Length( void ) {
1316 idFile_InZip::Timestamp
1319 ID_TIME_T idFile_InZip::Timestamp( void ) {
1327 returns zero on success and -1 on failure
1330 #define ZIP_SEEK_BUF_SIZE (1<<15)
1332 int idFile_InZip::Seek( long offset, fsOrigin_t origin ) {
1338 offset = fileSize - offset;
1341 // set the file position in the zip file (also sets the current file info)
1342 unzSetCurrentFileInfoPosition( z, zipFilePos );
1343 unzOpenCurrentFile( z );
1344 if ( offset <= 0 ) {
1349 buf = (char *) _alloca16( ZIP_SEEK_BUF_SIZE );
1350 for ( i = 0; i < ( offset - ZIP_SEEK_BUF_SIZE ); i += ZIP_SEEK_BUF_SIZE ) {
1351 res = unzReadCurrentFile( z, buf, ZIP_SEEK_BUF_SIZE );
1352 if ( res < ZIP_SEEK_BUF_SIZE ) {
1356 res = i + unzReadCurrentFile( z, buf, offset - i );
1357 return ( res == offset ) ? 0 : -1;
1360 common->FatalError( "idFile_InZip::Seek: bad origin for %s\n", name.c_str() );