/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall This file is part of the IceTech GPL Source Code (?IceTech Source Code?). IceTech Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. IceTech Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with IceTech Source Code. If not, see . In addition, the IceTech 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 IceTech Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com =========================================================================== */ #include "precompiled.h" #pragma hdrstop #include "Unzip.h" #define MAX_PRINT_MSG 4096 #ifdef QUAKE4 #define FILE_SYNC_ID 518508557 // 0x1EE7D00D #define ID_FILE_TIMESTAMP_TYPE unsigned int #else #define ID_FILE_TIMESTAMP_TYPE ID_TIME_T #endif /* ================= FS_WriteFloatString ================= */ #ifdef QUAKE4 int FS_WriteFloatString( char *buf, int max, const char *fmt, va_list argPtr ) { int i; unsigned int u; double f; char *str; int index; idStr tmp, format; index = 0; while( *fmt && index < max ) { switch( *fmt ) { case '%': format = ""; format += *fmt++; while ( (*fmt >= '0' && *fmt <= '9') || *fmt == '.' || *fmt == '-' || *fmt == '+' || *fmt == '#') { format += *fmt++; } format += *fmt; switch( *fmt ) { case 'f': case 'e': case 'E': case 'g': case 'G': f = va_arg( argPtr, double ); if ( format.Length() <= 2 ) { // high precision floating point number without trailing zeros sprintf( tmp, "%1.10f", f ); tmp.StripTrailing( '0' ); tmp.StripTrailing( '.' ); index += idStr::snPrintf( buf + index, max - index, "%s", tmp.c_str() ); } else { index += idStr::snPrintf( buf + index, max - index, format.c_str(), f ); } break; case 'd': case 'i': i = va_arg( argPtr, int ); index += idStr::snPrintf( buf + index, max - index, format.c_str(), i ); break; case 'u': u = va_arg( argPtr, unsigned int ); index += idStr::snPrintf( buf + index, max - index, format.c_str(), u ); break; case 'o': u = va_arg( argPtr, unsigned int ); index += idStr::snPrintf( buf + index, max - index, format.c_str(), u ); break; case 'x': u = va_arg( argPtr, unsigned int ); index += idStr::snPrintf( buf + index, max - index, format.c_str(), u ); break; case 'X': u = va_arg( argPtr, unsigned int ); index += idStr::snPrintf( buf + index, max - index, format.c_str(), u ); break; case 'c': i = va_arg( argPtr, int ); index += idStr::snPrintf( buf + index, max - index, format.c_str(), (char) i ); break; case 's': str = va_arg( argPtr, char * ); index += idStr::snPrintf( buf + index, max - index, format.c_str(), str ); break; case '%': index += idStr::snPrintf( buf + index, max - index, format.c_str() ); break; default: common->Error( "FS_WriteFloatString: invalid format %s", format.c_str() ); break; } fmt++; break; case '\\': fmt++; switch( *fmt ) { case 't': index += idStr::snPrintf( buf + index, max - index, "\t" ); break; case 'v': index += idStr::snPrintf( buf + index, max - index, "\v" ); break; case 'n': index += idStr::snPrintf( buf + index, max - index, "\n" ); break; case '\\': index += idStr::snPrintf( buf + index, max - index, "\\" ); break; default: common->Error( "FS_WriteFloatString: unknown escape character \'%c\'", *fmt ); break; } fmt++; break; default: index += idStr::snPrintf( buf + index, max - index, "%c", *fmt ); fmt++; break; } } return index; } #else int FS_WriteFloatString( char *buf, const char *fmt, va_list argPtr ) { long i; unsigned long u; double f; char *str; int index; idStr tmp, format; index = 0; while( *fmt ) { switch( *fmt ) { case '%': format = ""; format += *fmt++; while ( (*fmt >= '0' && *fmt <= '9') || *fmt == '.' || *fmt == '-' || *fmt == '+' || *fmt == '#') { format += *fmt++; } format += *fmt; switch( *fmt ) { case 'f': case 'e': case 'E': case 'g': case 'G': f = va_arg( argPtr, double ); if ( format.Length() <= 2 ) { // high precision floating point number without trailing zeros sprintf( tmp, "%1.10f", f ); tmp.StripTrailing( '0' ); tmp.StripTrailing( '.' ); index += sprintf( buf+index, "%s", tmp.c_str() ); } else { index += sprintf( buf+index, format.c_str(), f ); } break; case 'd': case 'i': i = va_arg( argPtr, long ); index += sprintf( buf+index, format.c_str(), i ); break; case 'u': u = va_arg( argPtr, unsigned long ); index += sprintf( buf+index, format.c_str(), u ); break; case 'o': u = va_arg( argPtr, unsigned long ); index += sprintf( buf+index, format.c_str(), u ); break; case 'x': u = va_arg( argPtr, unsigned long ); index += sprintf( buf+index, format.c_str(), u ); break; case 'X': u = va_arg( argPtr, unsigned long ); index += sprintf( buf+index, format.c_str(), u ); break; case 'c': i = va_arg( argPtr, long ); index += sprintf( buf+index, format.c_str(), (char) i ); break; case 's': str = va_arg( argPtr, char * ); index += sprintf( buf+index, format.c_str(), str ); break; case '%': index += sprintf( buf+index, format.c_str() ); break; default: common->Error( "FS_WriteFloatString: invalid format %s", format.c_str() ); break; } fmt++; break; case '\\': fmt++; switch( *fmt ) { case 't': index += sprintf( buf+index, "\t" ); break; case 'v': index += sprintf( buf+index, "\v" ); break; case 'n': index += sprintf( buf+index, "\n" ); break; case '\\': index += sprintf( buf+index, "\\" ); break; default: common->Error( "FS_WriteFloatString: unknown escape character \'%c\'", *fmt ); break; } fmt++; break; default: index += sprintf( buf+index, "%c", *fmt ); fmt++; break; } } return index; } #endif #ifdef QUAKE4 #define IDFILE_COMMON idFile_Common #else #define IDFILE_COMMON idFile #endif /* ================================================================================= idFile ================================================================================= */ /* ================= IDFILE_COMMON::GetName ================= */ const char *IDFILE_COMMON::GetName( void ) { return ""; } /* ================= IDFILE_COMMON::GetFullPath ================= */ const char *IDFILE_COMMON::GetFullPath( void ) { return ""; } /* ================= IDFILE_COMMON::Read ================= */ int IDFILE_COMMON::Read( void *buffer, int len ) { #ifdef QUAKE4 common->FatalError( "idFile_Common::Read: cannot read from idFile_Common" ); #else common->FatalError( "idFile::Read: cannot read from idFile" ); #endif return 0; } /* ================= IDFILE_COMMON::Write ================= */ int IDFILE_COMMON::Write( const void *buffer, int len ) { #ifdef QUAKE4 common->FatalError( "idFile_Common::Write: cannot write to idFile_Common" ); #else common->FatalError( "idFile::Write: cannot write to idFile" ); #endif return 0; } /* ================= IDFILE_COMMON::Length ================= */ int IDFILE_COMMON::Length( void ) { return 0; } /* ================= IDFILE_COMMON::Timestamp ================= */ ID_FILE_TIMESTAMP_TYPE IDFILE_COMMON::Timestamp( void ) { return 0; } /* ================= IDFILE_COMMON::Tell ================= */ int IDFILE_COMMON::Tell( void ) { return 0; } /* ================= IDFILE_COMMON::ForceFlush ================= */ void IDFILE_COMMON::ForceFlush( void ) { } /* ================= IDFILE_COMMON::Flush ================= */ void IDFILE_COMMON::Flush( void ) { } /* ================= IDFILE_COMMON::Seek ================= */ int IDFILE_COMMON::Seek( long offset, fsOrigin_t origin ) { return -1; } /* ================= IDFILE_COMMON::Rewind ================= */ void IDFILE_COMMON::Rewind( void ) { Seek( 0, FS_SEEK_SET ); } /* ================= IDFILE_COMMON::Printf ================= */ int IDFILE_COMMON::Printf( const char *fmt, ... ) { char buf[MAX_PRINT_MSG]; int length; va_list argptr; va_start( argptr, fmt ); length = idStr::vsnPrintf( buf, MAX_PRINT_MSG-1, fmt, argptr ); va_end( argptr ); // so notepad formats the lines correctly idStr work( buf ); work.Replace( "\n", "\r\n" ); return Write( work.c_str(), work.Length() ); } /* ================= IDFILE_COMMON::VPrintf ================= */ int IDFILE_COMMON::VPrintf( const char *fmt, va_list args ) { char buf[MAX_PRINT_MSG]; int length; length = idStr::vsnPrintf( buf, MAX_PRINT_MSG-1, fmt, args ); return Write( buf, length ); } /* ================= IDFILE_COMMON::WriteFloatString ================= */ int IDFILE_COMMON::WriteFloatString( const char *fmt, ... ) { char buf[MAX_PRINT_MSG]; int len; va_list argPtr; va_start( argPtr, fmt ); #ifdef QUAKE4 len = FS_WriteFloatString( buf, sizeof( buf ), fmt, argPtr ); #else len = FS_WriteFloatString( buf, fmt, argPtr ); #endif va_end( argPtr ); return Write( buf, len ); } /* ================= IDFILE_COMMON::ReadInt ================= */ int IDFILE_COMMON::ReadInt( int &value ) { int result = Read( &value, sizeof( value ) ); value = LittleLong(value); return result; } /* ================= IDFILE_COMMON::ReadUnsignedInt ================= */ int IDFILE_COMMON::ReadUnsignedInt( unsigned int &value ) { int result = Read( &value, sizeof( value ) ); value = LittleLong(value); return result; } /* ================= IDFILE_COMMON::ReadShort ================= */ int IDFILE_COMMON::ReadShort( short &value ) { int result = Read( &value, sizeof( value ) ); value = LittleShort(value); return result; } /* ================= IDFILE_COMMON::ReadUnsignedShort ================= */ int IDFILE_COMMON::ReadUnsignedShort( unsigned short &value ) { int result = Read( &value, sizeof( value ) ); value = LittleShort(value); return result; } /* ================= IDFILE_COMMON::ReadChar ================= */ int IDFILE_COMMON::ReadChar( char &value ) { return Read( &value, sizeof( value ) ); } /* ================= IDFILE_COMMON::ReadUnsignedChar ================= */ int IDFILE_COMMON::ReadUnsignedChar( unsigned char &value ) { return Read( &value, sizeof( value ) ); } /* ================= IDFILE_COMMON::ReadFloat ================= */ int IDFILE_COMMON::ReadFloat( float &value ) { int result = Read( &value, sizeof( value ) ); value = LittleFloat(value); return result; } /* ================= IDFILE_COMMON::ReadBool ================= */ int IDFILE_COMMON::ReadBool( bool &value ) { unsigned char c; int result = ReadUnsignedChar( c ); value = c ? true : false; return result; } /* ================= IDFILE_COMMON::ReadString ================= */ int IDFILE_COMMON::ReadString( idStr &string ) { int len; int result = 0; ReadInt( len ); if ( len >= 0 ) { string.Fill( ' ', len ); result = Read( &string[ 0 ], len ); } return result; } /* ================= IDFILE_COMMON::ReadVec2 ================= */ int IDFILE_COMMON::ReadVec2( idVec2 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } /* ================= IDFILE_COMMON::ReadVec3 ================= */ int IDFILE_COMMON::ReadVec3( idVec3 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } /* ================= IDFILE_COMMON::ReadVec4 ================= */ int IDFILE_COMMON::ReadVec4( idVec4 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } #ifdef QUAKE4 /* ================= idFile_Common::ReadVec5 ================= */ int IDFILE_COMMON::ReadVec5( idVec5 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } #endif /* ================= IDFILE_COMMON::ReadVec6 ================= */ int IDFILE_COMMON::ReadVec6( idVec6 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } /* ================= IDFILE_COMMON::ReadMat3 ================= */ int IDFILE_COMMON::ReadMat3( idMat3 &mat ) { int result = Read( &mat, sizeof( mat ) ); LittleRevBytes( &mat, sizeof(float), sizeof(mat)/sizeof(float) ); return result; } #ifdef QUAKE4 /* ================= idFile_Common::ReadBounds ================= */ int IDFILE_COMMON::ReadBounds( idBounds &bounds ) { int result = Read( &bounds, sizeof( bounds ) ); LittleRevBytes( &bounds, sizeof(float), sizeof(bounds)/sizeof(float) ); return result; } #endif /* ================= IDFILE_COMMON::WriteInt ================= */ int IDFILE_COMMON::WriteInt( const int value ) { int v = LittleLong(value); return Write( &v, sizeof( v ) ); } /* ================= IDFILE_COMMON::WriteUnsignedInt ================= */ int IDFILE_COMMON::WriteUnsignedInt( const unsigned int value ) { unsigned int v = LittleLong(value); return Write( &v, sizeof( v ) ); } /* ================= IDFILE_COMMON::WriteShort ================= */ int IDFILE_COMMON::WriteShort( const short value ) { short v = LittleShort(value); return Write( &v, sizeof( v ) ); } /* ================= IDFILE_COMMON::WriteUnsignedShort ================= */ int IDFILE_COMMON::WriteUnsignedShort( const unsigned short value ) { unsigned short v = LittleShort(value); return Write( &v, sizeof( v ) ); } /* ================= IDFILE_COMMON::WriteChar ================= */ int IDFILE_COMMON::WriteChar( const char value ) { return Write( &value, sizeof( value ) ); } /* ================= IDFILE_COMMON::WriteUnsignedChar ================= */ int IDFILE_COMMON::WriteUnsignedChar( const unsigned char value ) { return Write( &value, sizeof( value ) ); } /* ================= IDFILE_COMMON::WriteFloat ================= */ int IDFILE_COMMON::WriteFloat( const float value ) { float v = LittleFloat(value); return Write( &v, sizeof( v ) ); } /* ================= IDFILE_COMMON::WriteBool ================= */ int IDFILE_COMMON::WriteBool( const bool value ) { unsigned char c = value; return WriteUnsignedChar( c ); } /* ================= IDFILE_COMMON::WriteString ================= */ int IDFILE_COMMON::WriteString( const char *value ) { int len; len = strlen( value ); WriteInt( len ); return Write( value, len ); } /* ================= IDFILE_COMMON::WriteVec2 ================= */ int IDFILE_COMMON::WriteVec2( const idVec2 &vec ) { idVec2 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================= IDFILE_COMMON::WriteVec3 ================= */ int IDFILE_COMMON::WriteVec3( const idVec3 &vec ) { idVec3 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================= IDFILE_COMMON::WriteVec4 ================= */ int IDFILE_COMMON::WriteVec4( const idVec4 &vec ) { idVec4 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } #ifdef QUAKE4 /* ================= idFile_Common::WriteVec5 ================= */ int IDFILE_COMMON::WriteVec5( const idVec5 &vec ) { idVec5 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } #endif /* ================= IDFILE_COMMON::WriteVec6 ================= */ int IDFILE_COMMON::WriteVec6( const idVec6 &vec ) { idVec6 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================= IDFILE_COMMON::WriteMat3 ================= */ int IDFILE_COMMON::WriteMat3( const idMat3 &mat ) { idMat3 v = mat; LittleRevBytes(&v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } #ifdef QUAKE4 /* ================= idFile_Common::WriteBounds ================= */ int IDFILE_COMMON::WriteBounds( const idBounds &bounds ) { idBounds v = bounds; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================= idFile_Common::WriteNumericStructArray ================= */ void IDFILE_COMMON::WriteNumericStructArray( int numStructElements, int tokenSubTypeStructElements[], int arrayCount, byte *arrayStorage, const char *prepend ) { for ( int arrayIndex = 0; arrayIndex < arrayCount; arrayIndex++ ) { WriteFloatString( prepend ); for ( int elementIndex = 0; elementIndex < numStructElements; elementIndex++, arrayStorage += sizeof( int ) ) { if ( (signed char) tokenSubTypeStructElements[ elementIndex ] >= 0 ) { WriteFloatString( "%u ", *(unsigned int *)arrayStorage ); } else { WriteFloatString( "%f ", *(float *)arrayStorage ); } } WriteFloatString( "\n" ); } } /* ================= idFile_Common::WriteSyncId ================= */ void IDFILE_COMMON::WriteSyncId( void ) { WriteInt( FILE_SYNC_ID ); } /* ================= idFile_Common::ReadSyncId ================= */ void IDFILE_COMMON::ReadSyncId( const char *detail, const char *classname ) { int num; ReadInt( num ); if ( num != FILE_SYNC_ID ) { if ( classname ) { common->Error( "File synchronisation problem: %s in class %s", detail, classname ); } else { common->Error( "File synchronisation problem: %s", detail ); } } } #endif #undef IDFILE_COMMON /* ================================================================================= idFile_Memory ================================================================================= */ /* ================= idFile_Memory::idFile_Memory ================= */ idFile_Memory::idFile_Memory( void ) { name = "*unknown*"; maxSize = 0; fileSize = 0; allocated = 0; granularity = 16384; mode = ( 1 << FS_WRITE ); filePtr = NULL; curPtr = NULL; } /* ================= idFile_Memory::idFile_Memory ================= */ idFile_Memory::idFile_Memory( const char *name ) { this->name = name; maxSize = 0; fileSize = 0; allocated = 0; granularity = 16384; mode = ( 1 << FS_WRITE ); filePtr = NULL; curPtr = NULL; } /* ================= idFile_Memory::idFile_Memory ================= */ idFile_Memory::idFile_Memory( const char *name, char *data, int length ) { this->name = name; maxSize = length; fileSize = 0; allocated = length; granularity = 16384; mode = ( 1 << FS_WRITE ); filePtr = data; curPtr = data; } /* ================= idFile_Memory::idFile_Memory ================= */ idFile_Memory::idFile_Memory( const char *name, const char *data, int length ) { this->name = name; maxSize = 0; fileSize = length; allocated = 0; granularity = 16384; mode = ( 1 << FS_READ ); filePtr = const_cast(data); curPtr = const_cast(data); } /* ================= idFile_Memory::~idFile_Memory ================= */ idFile_Memory::~idFile_Memory( void ) { if ( filePtr && allocated > 0 && maxSize == 0 ) { Mem_Free( filePtr ); } } /* ================= idFile_Memory::Read ================= */ int idFile_Memory::Read( void *buffer, int len ) { if ( !( mode & ( 1 << FS_READ ) ) ) { common->FatalError( "idFile_Memory::Read: %s not opened in read mode", name.c_str() ); return 0; } if ( curPtr + len > filePtr + fileSize ) { len = filePtr + fileSize - curPtr; } #ifdef QUAKE4 SIMDProcessor->Memcpy( buffer, curPtr, len ); #else memcpy( buffer, curPtr, len ); #endif curPtr += len; return len; } /* ================= idFile_Memory::Write ================= */ int idFile_Memory::Write( const void *buffer, int len ) { if ( !( mode & ( 1 << FS_WRITE ) ) ) { common->FatalError( "idFile_Memory::Write: %s not opened in write mode", name.c_str() ); return 0; } int alloc = curPtr + len + 1 - filePtr - allocated; // need room for len+1 if ( alloc > 0 ) { if ( maxSize != 0 ) { common->Error( "idFile_Memory::Write: exceeded maximum size %d", maxSize ); return 0; } int extra = granularity * ( 1 + alloc / granularity ); #ifdef QUAKE4 char *newPtr = (char *) Mem_Alloc( allocated + extra ); #else char *newPtr = (char *) Mem_Alloc( allocated + extra ); #endif if ( allocated ) { #ifdef QUAKE4 SIMDProcessor->Memcpy( newPtr, filePtr, allocated ); #else memcpy( newPtr, filePtr, allocated ); #endif } allocated += extra; curPtr = newPtr + ( curPtr - filePtr ); if ( filePtr ) { Mem_Free( filePtr ); } filePtr = newPtr; } #ifdef QUAKE4 SIMDProcessor->Memcpy( curPtr, buffer, len ); #else memcpy( curPtr, buffer, len ); #endif curPtr += len; fileSize += len; filePtr[ fileSize ] = 0; // len + 1 return len; } /* ================= idFile_Memory::Length ================= */ int idFile_Memory::Length( void ) { return fileSize; } /* ================= idFile_Memory::Timestamp ================= */ ID_FILE_TIMESTAMP_TYPE idFile_Memory::Timestamp( void ) { return 0; } /* ================= idFile_Memory::Tell ================= */ int idFile_Memory::Tell( void ) { return ( curPtr - filePtr ); } /* ================= idFile_Memory::ForceFlush ================= */ void idFile_Memory::ForceFlush( void ) { } /* ================= idFile_Memory::Flush ================= */ void idFile_Memory::Flush( void ) { } /* ================= idFile_Memory::Seek returns zero on success and -1 on failure ================= */ int idFile_Memory::Seek( long offset, fsOrigin_t origin ) { switch( origin ) { case FS_SEEK_CUR: { curPtr += offset; break; } case FS_SEEK_END: { curPtr = filePtr + fileSize - offset; break; } case FS_SEEK_SET: { curPtr = filePtr + offset; break; } default: { common->FatalError( "idFile_Memory::Seek: bad origin for %s\n", name.c_str() ); return -1; } } if ( curPtr < filePtr ) { curPtr = filePtr; return -1; } if ( curPtr > filePtr + fileSize ) { curPtr = filePtr + fileSize; return -1; } return 0; } #ifdef QUAKE4 /* ================= idFile_Memory::Rewind ================= */ void idFile_Memory::Rewind( void ) { mode = ( 1 << FS_READ ); Seek( 0, FS_SEEK_SET ); } #endif /* ================= idFile_Memory::MakeReadOnly ================= */ void idFile_Memory::MakeReadOnly( void ) { mode = ( 1 << FS_READ ); Rewind(); } /* ================= idFile_Memory::Clear ================= */ void idFile_Memory::Clear( bool freeMemory ) { fileSize = 0; granularity = 16384; if ( freeMemory ) { allocated = 0; Mem_Free( filePtr ); filePtr = NULL; curPtr = NULL; } else { curPtr = filePtr; } } /* ================= idFile_Memory::SetData ================= */ void idFile_Memory::SetData( const char *data, int length ) { maxSize = 0; fileSize = length; allocated = 0; granularity = 16384; mode = ( 1 << FS_READ ); filePtr = const_cast(data); curPtr = const_cast(data); } /* ================================================================================= idFile_BitMsg ================================================================================= */ /* ================= idFile_BitMsg::idFile_BitMsg ================= */ idFile_BitMsg::idFile_BitMsg( idBitMsg &msg ) { name = "*unknown*"; mode = ( 1 << FS_WRITE ); this->msg = &msg; } /* ================= idFile_BitMsg::idFile_BitMsg ================= */ idFile_BitMsg::idFile_BitMsg( const idBitMsg &msg ) { name = "*unknown*"; mode = ( 1 << FS_READ ); this->msg = const_cast(&msg); } /* ================= idFile_BitMsg::~idFile_BitMsg ================= */ idFile_BitMsg::~idFile_BitMsg( void ) { } /* ================= idFile_BitMsg::Read ================= */ int idFile_BitMsg::Read( void *buffer, int len ) { if ( !( mode & ( 1 << FS_READ ) ) ) { common->FatalError( "idFile_BitMsg::Read: %s not opened in read mode", name.c_str() ); return 0; } return msg->ReadData( buffer, len ); } /* ================= idFile_BitMsg::Write ================= */ int idFile_BitMsg::Write( const void *buffer, int len ) { if ( !( mode & ( 1 << FS_WRITE ) ) ) { common->FatalError( "idFile_Memory::Write: %s not opened in write mode", name.c_str() ); return 0; } msg->WriteData( buffer, len ); return len; } /* ================= idFile_BitMsg::Length ================= */ int idFile_BitMsg::Length( void ) { return msg->GetSize(); } /* ================= idFile_BitMsg::Timestamp ================= */ ID_FILE_TIMESTAMP_TYPE idFile_BitMsg::Timestamp( void ) { return 0; } /* ================= idFile_BitMsg::Tell ================= */ int idFile_BitMsg::Tell( void ) { #ifdef QUAKE4 if ( mode & ( 1 << FS_READ ) ) { #else if ( mode & FS_READ ) { #endif return msg->GetReadCount(); } else { return msg->GetSize(); } } /* ================= idFile_BitMsg::ForceFlush ================= */ void idFile_BitMsg::ForceFlush( void ) { } /* ================= idFile_BitMsg::Flush ================= */ void idFile_BitMsg::Flush( void ) { } /* ================= idFile_BitMsg::Seek returns zero on success and -1 on failure ================= */ int idFile_BitMsg::Seek( long offset, fsOrigin_t origin ) { return -1; } /* ================================================================================= idFile_Permanent ================================================================================= */ /* ================= idFile_Permanent::idFile_Permanent ================= */ idFile_Permanent::idFile_Permanent( void ) { name = "invalid"; o = NULL; mode = 0; fileSize = 0; handleSync = false; } /* ================= idFile_Permanent::~idFile_Permanent ================= */ idFile_Permanent::~idFile_Permanent( void ) { if ( o ) { #ifdef QUAKE4 sys->FClose( o ); #else fclose( o ); #endif } } /* ================= idFile_Permanent::Read Properly handles partial reads ================= */ int idFile_Permanent::Read( void *buffer, int len ) { int block, remaining; int read; byte * buf; int tries; if ( !(mode & ( 1 << FS_READ ) ) ) { common->FatalError( "idFile_Permanent::Read: %s not opened in read mode", name.c_str() ); return 0; } if ( !o ) { return 0; } buf = (byte *)buffer; remaining = len; tries = 0; while( remaining ) { block = remaining; #ifdef QUAKE4 read = sys->FRead( buf, 1, block, o ); #else read = fread( buf, 1, block, o ); #endif if ( read == 0 ) { // we might have been trying to read from a CD, which // sometimes returns a 0 read on windows if ( !tries ) { tries = 1; } else { fileSystem->AddToReadCount( len - remaining ); return len-remaining; } } if ( read == -1 ) { common->FatalError( "idFile_Permanent::Read: -1 bytes read from %s", name.c_str() ); } remaining -= read; buf += read; } fileSystem->AddToReadCount( len ); return len; } /* ================= idFile_Permanent::Write Properly handles partial writes ================= */ int idFile_Permanent::Write( const void *buffer, int len ) { int block, remaining; int written; byte * buf; int tries; if ( !( mode & ( 1 << FS_WRITE ) ) ) { common->FatalError( "idFile_Permanent::Write: %s not opened in write mode", name.c_str() ); return 0; } if ( !o ) { return 0; } buf = (byte *)buffer; remaining = len; tries = 0; while( remaining ) { block = remaining; #ifdef QUAKE4 written = sys->FWrite( buf, 1, block, o ); #else written = fwrite( buf, 1, block, o ); #endif if ( written == 0 ) { if ( !tries ) { tries = 1; } else { common->Printf( "idFile_Permanent::Write: 0 bytes written to %s\n", name.c_str() ); return 0; } } if ( written == -1 ) { common->Printf( "idFile_Permanent::Write: -1 bytes written to %s\n", name.c_str() ); return 0; } remaining -= written; buf += written; fileSize += written; } if ( handleSync ) { #ifdef QUAKE4 sys->FFlush( o ); #else fflush( o ); #endif } return len; } /* ================= idFile_Permanent::ForceFlush ================= */ void idFile_Permanent::ForceFlush( void ) { #ifdef QUAKE4 sys->SetVBuf( o, NULL, _IONBF, 0 ); #else setvbuf( o, NULL, _IONBF, 0 ); #endif } /* ================= idFile_Permanent::Flush ================= */ void idFile_Permanent::Flush( void ) { #ifdef QUAKE4 sys->FFlush( o ); #else fflush( o ); #endif } /* ================= idFile_Permanent::Tell ================= */ int idFile_Permanent::Tell( void ) { #ifdef QUAKE4 return sys->FTell( o ); #else return ftell( o ); #endif } /* ================ idFile_Permanent::Length ================ */ int idFile_Permanent::Length( void ) { return fileSize; } /* ================ idFile_Permanent::Timestamp ================ */ ID_FILE_TIMESTAMP_TYPE idFile_Permanent::Timestamp( void ) { #ifdef QUAKE4 return sys->FileTimeStamp( o ); #else return Sys_FileTimeStamp( o ); #endif } /* ================= idFile_Permanent::Seek returns zero on success and -1 on failure ================= */ int idFile_Permanent::Seek( long offset, fsOrigin_t origin ) { int _origin; switch( origin ) { case FS_SEEK_CUR: { _origin = SEEK_CUR; break; } case FS_SEEK_END: { _origin = SEEK_END; break; } case FS_SEEK_SET: { _origin = SEEK_SET; break; } default: { _origin = SEEK_CUR; common->FatalError( "idFile_Permanent::Seek: bad origin for %s\n", name.c_str() ); break; } } #ifdef QUAKE4 return sys->FSeek( o, offset, _origin ); #else return fseek( o, offset, _origin ); #endif } #ifdef QUAKE4 /* ================================================================================= idFile_ASCII ================================================================================= */ /* ================= idFile_ASCII::idFile_ASCII ================= */ idFile_ASCII::idFile_ASCII( void ) { inside = 0; } /* ================= idFile_ASCII::Read ================= */ int idFile_ASCII::Read( void *buffer, int len ) { return idFile_Permanent::Read( buffer, len ); } /* ================= idFile_ASCII::Write ================= */ int idFile_ASCII::Write( const void *buffer, int len ) { const byte *buf; if ( inside ) { return idFile_Permanent::Write( buffer, len ); } buf = (const byte *) buffer; inside = 1; WriteFloatString( "len=%d ", len ); for ( int i = 0; i < len; i++ ) { WriteFloatString( "%02x", buf[ i ] ); } WriteFloatString( "\r\n" ); inside--; return 0; } int idFile_ASCII::ReadInt( int &value ) { return idFile_Common::ReadInt( value ); } int idFile_ASCII::ReadUnsignedInt( unsigned int &value ) { return idFile_Common::ReadUnsignedInt( value ); } int idFile_ASCII::ReadShort( short &value ) { return idFile_Common::ReadShort( value ); } int idFile_ASCII::ReadUnsignedShort( unsigned short &value ) { return idFile_Common::ReadUnsignedShort( value ); } int idFile_ASCII::ReadChar( char &value ) { return idFile_Common::ReadChar( value ); } int idFile_ASCII::ReadUnsignedChar( unsigned char &value ) { return idFile_Common::ReadUnsignedChar( value ); } int idFile_ASCII::ReadFloat( float &value ) { return idFile_Common::ReadFloat( value ); } int idFile_ASCII::ReadBool( bool &value ) { return idFile_Common::ReadBool( value ); } int idFile_ASCII::ReadString( idStr &string ) { return idFile_Common::ReadString( string ); } int idFile_ASCII::ReadVec2( idVec2 &vec ) { return idFile_Common::ReadVec2( vec ); } int idFile_ASCII::ReadVec3( idVec3 &vec ) { return idFile_Common::ReadVec3( vec ); } int idFile_ASCII::ReadVec4( idVec4 &vec ) { return idFile_Common::ReadVec4( vec ); } int idFile_ASCII::ReadVec5( idVec5 &vec ) { return idFile_Common::ReadVec5( vec ); } int idFile_ASCII::ReadVec6( idVec6 &vec ) { return idFile_Common::ReadVec6( vec ); } int idFile_ASCII::ReadMat3( idMat3 &mat ) { return idFile_Common::ReadMat3( mat ); } int idFile_ASCII::WriteInt( const int value ) { inside++; WriteFloatString( "Integer: %d\r\n", value ); inside--; return 0; } int idFile_ASCII::WriteUnsignedInt( const unsigned int value ) { inside++; WriteFloatString( "Unsigned: %u\r\n", value ); inside--; return 0; } int idFile_ASCII::WriteShort( const short value ) { inside++; WriteFloatString( "Short: %d\r\n", value ); inside--; return 0; } int idFile_ASCII::WriteUnsignedShort( unsigned short value ) { inside++; WriteFloatString( "Unsigned Short: %u\r\n", value ); inside--; return 0; } int idFile_ASCII::WriteChar( const char value ) { inside++; WriteFloatString( "Char: %d\r\n", value ); inside--; return 0; } int idFile_ASCII::WriteUnsignedChar( const unsigned char value ) { inside++; WriteFloatString( "Byte: %u\r\n", value ); inside--; return 0; } int idFile_ASCII::WriteFloat( const float value ) { inside++; WriteFloatString( "Float: %f\r\n", value ); inside--; return 0; } int idFile_ASCII::WriteBool( const bool value ) { inside++; WriteFloatString( "Bool: %s\r\n", value ? "true" : "false" ); inside--; return 0; } int idFile_ASCII::WriteString( const char *string ) { inside++; WriteFloatString( "String: len=%d %s\r\n", (int) strlen( string ), string ); inside--; return 0; } int idFile_ASCII::WriteVec2( const idVec2 &vec ) { inside++; WriteFloatString( "Vec2: %f %f\r\n", vec.x, vec.y ); inside--; return 0; } int idFile_ASCII::WriteVec3( const idVec3 &vec ) { inside++; WriteFloatString( "Vec3: %f %f %f\r\n", vec.x, vec.y, vec.z ); inside--; return 0; } int idFile_ASCII::WriteVec4( const idVec4 &vec ) { inside++; WriteFloatString( "Vec4: %f %f %f %f\r\n", vec.x, vec.y, vec.z, vec.w ); inside--; return 0; } int idFile_ASCII::WriteVec5( const idVec5 &vec ) { inside++; WriteFloatString( "Vec5: %f %f %f %f %f\r\n", vec.x, vec.y, vec.z, vec.s, vec.t ); inside--; return 0; } int idFile_ASCII::WriteVec6( const idVec6 &vec ) { inside++; WriteFloatString( "Vec6: %f %f %f %f %f %f\r\n", vec[0], vec[1], vec[2], vec[3], vec[4], vec[5] ); inside--; return 0; } int idFile_ASCII::WriteMat3( const idMat3 &mat ) { inside++; WriteFloatString( "Mat3: ( %f %f %f ) ( %f %f %f ) ( %f %f %f )\r\n", mat[0].x, mat[0].y, mat[0].z, mat[1].x, mat[1].y, mat[1].z, mat[2].x, mat[2].y, mat[2].z ); inside--; return 0; } void idFile_ASCII::WriteNumericStructArray( int numStructElements, int tokenSubTypeStructElements[], int arrayCount, byte *arrayStorage, const char *prepend ) { } void idFile_ASCII::WriteSyncId( void ) { inside++; WriteFloatString( "==========\r\n" ); inside--; } void idFile_ASCII::ReadSyncId( const char *detail, const char *classname ) { idFile_Common::ReadSyncId( detail, classname ); } #endif /* QUAKE4 */ /* ================================================================================= idFile_InZip ================================================================================= */ /* ================= idFile_InZip::idFile_InZip ================= */ idFile_InZip::idFile_InZip( void ) { name = "invalid"; zipFilePos = 0; fileSize = 0; memset( &z, 0, sizeof( z ) ); } /* ================= idFile_InZip::~idFile_InZip ================= */ idFile_InZip::~idFile_InZip( void ) { unzCloseCurrentFile( z ); unzClose( z ); } /* ================= idFile_InZip::Read Properly handles partial reads ================= */ int idFile_InZip::Read( void *buffer, int len ) { int l = unzReadCurrentFile( z, buffer, len ); fileSystem->AddToReadCount( l ); return l; } /* ================= idFile_InZip::Write ================= */ int idFile_InZip::Write( const void *buffer, int len ) { common->FatalError( "idFile_InZip::Write: cannot write to the zipped file %s", name.c_str() ); return 0; } /* ================= idFile_InZip::ForceFlush ================= */ void idFile_InZip::ForceFlush( void ) { common->FatalError( "idFile_InZip::ForceFlush: cannot flush the zipped file %s", name.c_str() ); } /* ================= idFile_InZip::Flush ================= */ void idFile_InZip::Flush( void ) { common->FatalError( "idFile_InZip::Flush: cannot flush the zipped file %s", name.c_str() ); } /* ================= idFile_InZip::Tell ================= */ int idFile_InZip::Tell( void ) { return unztell( z ); } /* ================ idFile_InZip::Length ================ */ int idFile_InZip::Length( void ) { return fileSize; } /* ================ idFile_InZip::Timestamp ================ */ ID_FILE_TIMESTAMP_TYPE idFile_InZip::Timestamp( void ) { return 0; } /* ================= idFile_InZip::Seek returns zero on success and -1 on failure ================= */ #define ZIP_SEEK_BUF_SIZE (1<<15) int idFile_InZip::Seek( long offset, fsOrigin_t origin ) { int res, i; char *buf; switch( origin ) { case FS_SEEK_END: { offset = fileSize - offset; } case FS_SEEK_SET: { // set the file position in the zip file (also sets the current file info) unzSetCurrentFileInfoPosition( z, zipFilePos ); unzOpenCurrentFile( z ); if ( offset <= 0 ) { return 0; } } case FS_SEEK_CUR: { buf = (char *) _alloca16( ZIP_SEEK_BUF_SIZE ); for ( i = 0; i < ( offset - ZIP_SEEK_BUF_SIZE ); i += ZIP_SEEK_BUF_SIZE ) { res = unzReadCurrentFile( z, buf, ZIP_SEEK_BUF_SIZE ); if ( res < ZIP_SEEK_BUF_SIZE ) { return -1; } } res = i + unzReadCurrentFile( z, buf, offset - i ); return ( res == offset ) ? 0 : -1; } default: { common->FatalError( "idFile_InZip::Seek: bad origin for %s\n", name.c_str() ); break; } } return -1; } #undef ID_FILE_TIMESTAMP_TYPE #ifdef QUAKE4 #undef FILE_SYNC_ID #endif