/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 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. Doom 3 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 Doom 3 Source Code. If not, see . 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. 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. =========================================================================== */ #include "sys/platform.h" #include "framework/Unzip.h" #include "framework/FileSystem.h" #include "framework/File.h" #define MAX_PRINT_MSG 4096 /* ================= FS_WriteFloatString ================= */ int FS_WriteFloatString( char *buf, const char *fmt, va_list argPtr ) { int i; unsigned int 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, int ); index += sprintf( buf+index, format.c_str(), i ); break; case 'u': u = va_arg( argPtr, unsigned int ); index += sprintf( buf+index, format.c_str(), u ); break; case 'o': u = va_arg( argPtr, unsigned int ); index += sprintf( buf+index, format.c_str(), u ); break; case 'x': u = va_arg( argPtr, unsigned int ); index += sprintf( buf+index, format.c_str(), u ); break; case 'X': u = va_arg( argPtr, unsigned int ); index += sprintf( buf+index, format.c_str(), u ); break; case 'c': i = va_arg( argPtr, int ); 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; } /* ================================================================================= idFile ================================================================================= */ /* ================= idFile::GetName ================= */ const char *idFile::GetName( void ) { return ""; } /* ================= idFile::GetFullPath ================= */ const char *idFile::GetFullPath( void ) { return ""; } /* ================= idFile::Read ================= */ int idFile::Read( void *buffer, int len ) { common->FatalError( "idFile::Read: cannot read from idFile" ); return 0; } /* ================= idFile::Write ================= */ int idFile::Write( const void *buffer, int len ) { common->FatalError( "idFile::Write: cannot write to idFile" ); return 0; } /* ================= idFile::Length ================= */ int idFile::Length( void ) { return 0; } /* ================= idFile::Timestamp ================= */ ID_TIME_T idFile::Timestamp( void ) { return 0; } /* ================= idFile::Tell ================= */ int idFile::Tell( void ) { return 0; } /* ================= idFile::ForceFlush ================= */ void idFile::ForceFlush( void ) { } /* ================= idFile::Flush ================= */ void idFile::Flush( void ) { } /* ================= idFile::Seek ================= */ int idFile::Seek( long offset, fsOrigin_t origin ) { return -1; } /* ================= idFile::Rewind ================= */ void idFile::Rewind( void ) { Seek( 0, FS_SEEK_SET ); } /* ================= idFile::Printf ================= */ int idFile::Printf( const char *fmt, ... ) { char buf[MAX_PRINT_MSG]; va_list argptr; va_start( argptr, fmt ); 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::VPrintf ================= */ int idFile::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::WriteFloatString ================= */ int idFile::WriteFloatString( const char *fmt, ... ) { char buf[MAX_PRINT_MSG]; int len; va_list argPtr; va_start( argPtr, fmt ); len = FS_WriteFloatString( buf, fmt, argPtr ); va_end( argPtr ); return Write( buf, len ); } /* ================= idFile::ReadInt ================= */ int idFile::ReadInt( int &value ) { int result = Read( &value, sizeof( value ) ); value = LittleInt(value); return result; } /* ================= idFile::ReadUnsignedInt ================= */ int idFile::ReadUnsignedInt( unsigned int &value ) { int result = Read( &value, sizeof( value ) ); value = LittleInt(value); return result; } /* ================= idFile::ReadShort ================= */ int idFile::ReadShort( short &value ) { int result = Read( &value, sizeof( value ) ); value = LittleShort(value); return result; } /* ================= idFile::ReadUnsignedShort ================= */ int idFile::ReadUnsignedShort( unsigned short &value ) { int result = Read( &value, sizeof( value ) ); value = LittleShort(value); return result; } /* ================= idFile::ReadChar ================= */ int idFile::ReadChar( char &value ) { return Read( &value, sizeof( value ) ); } /* ================= idFile::ReadUnsignedChar ================= */ int idFile::ReadUnsignedChar( unsigned char &value ) { return Read( &value, sizeof( value ) ); } /* ================= idFile::ReadFloat ================= */ int idFile::ReadFloat( float &value ) { int result = Read( &value, sizeof( value ) ); value = LittleFloat(value); return result; } /* ================= idFile::ReadBool ================= */ int idFile::ReadBool( bool &value ) { unsigned char c; int result = ReadUnsignedChar( c ); value = c ? true : false; return result; } /* ================= idFile::ReadString ================= */ int idFile::ReadString( idStr &string ) { int len; int result = 0; ReadInt( len ); if ( len >= 0 ) { string.Fill( ' ', len ); result = Read( &string[ 0 ], len ); } return result; } /* ================= idFile::ReadVec2 ================= */ int idFile::ReadVec2( idVec2 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } /* ================= idFile::ReadVec3 ================= */ int idFile::ReadVec3( idVec3 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } /* ================= idFile::ReadVec4 ================= */ int idFile::ReadVec4( idVec4 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } /* ================= idFile::ReadVec6 ================= */ int idFile::ReadVec6( idVec6 &vec ) { int result = Read( &vec, sizeof( vec ) ); LittleRevBytes( &vec, sizeof(float), sizeof(vec)/sizeof(float) ); return result; } /* ================= idFile::ReadMat3 ================= */ int idFile::ReadMat3( idMat3 &mat ) { int result = Read( &mat, sizeof( mat ) ); LittleRevBytes( &mat, sizeof(float), sizeof(mat)/sizeof(float) ); return result; } /* ================= idFile::WriteInt ================= */ int idFile::WriteInt( const int value ) { int v = LittleInt(value); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteUnsignedInt ================= */ int idFile::WriteUnsignedInt( const unsigned int value ) { unsigned int v = LittleInt(value); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteShort ================= */ int idFile::WriteShort( const short value ) { short v = LittleShort(value); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteUnsignedShort ================= */ int idFile::WriteUnsignedShort( const unsigned short value ) { unsigned short v = LittleShort(value); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteChar ================= */ int idFile::WriteChar( const char value ) { return Write( &value, sizeof( value ) ); } /* ================= idFile::WriteUnsignedChar ================= */ int idFile::WriteUnsignedChar( const unsigned char value ) { return Write( &value, sizeof( value ) ); } /* ================= idFile::WriteFloat ================= */ int idFile::WriteFloat( const float value ) { float v = LittleFloat(value); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteBool ================= */ int idFile::WriteBool( const bool value ) { unsigned char c = value; return WriteUnsignedChar( c ); } /* ================= idFile::WriteString ================= */ int idFile::WriteString( const char *value ) { int len; len = strlen( value ); WriteInt( len ); return Write( value, len ); } /* ================= idFile::WriteVec2 ================= */ int idFile::WriteVec2( const idVec2 &vec ) { idVec2 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteVec3 ================= */ int idFile::WriteVec3( const idVec3 &vec ) { idVec3 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteVec4 ================= */ int idFile::WriteVec4( const idVec4 &vec ) { idVec4 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteVec6 ================= */ int idFile::WriteVec6( const idVec6 &vec ) { idVec6 v = vec; LittleRevBytes( &v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================= idFile::WriteMat3 ================= */ int idFile::WriteMat3( const idMat3 &mat ) { idMat3 v = mat; LittleRevBytes(&v, sizeof(float), sizeof(v)/sizeof(float) ); return Write( &v, sizeof( v ) ); } /* ================================================================================= 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; } memcpy( buffer, curPtr, len ); 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 ); char *newPtr = (char *) Mem_Alloc( allocated + extra ); if ( allocated ) { memcpy( newPtr, filePtr, allocated ); } allocated += extra; curPtr = newPtr + ( curPtr - filePtr ); if ( filePtr ) { Mem_Free( filePtr ); } filePtr = newPtr; } memcpy( curPtr, buffer, len ); 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_TIME_T 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; } /* ================= 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_TIME_T idFile_BitMsg::Timestamp( void ) { return 0; } /* ================= idFile_BitMsg::Tell ================= */ int idFile_BitMsg::Tell( void ) { if ( mode & FS_READ ) { 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 ) { fclose( o ); } } /* ================= 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; read = fread( buf, 1, block, o ); 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; written = fwrite( buf, 1, block, o ); 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 ) { fflush( o ); } return len; } /* ================= idFile_Permanent::ForceFlush ================= */ void idFile_Permanent::ForceFlush( void ) { setvbuf( o, NULL, _IONBF, 0 ); } /* ================= idFile_Permanent::Flush ================= */ void idFile_Permanent::Flush( void ) { fflush( o ); } /* ================= idFile_Permanent::Tell ================= */ int idFile_Permanent::Tell( void ) { return ftell( o ); } /* ================ idFile_Permanent::Length ================ */ int idFile_Permanent::Length( void ) { return fileSize; } /* ================ idFile_Permanent::Timestamp ================ */ ID_TIME_T idFile_Permanent::Timestamp( void ) { return Sys_FileTimeStamp( o ); } /* ================= 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; } } return fseek( o, offset, _origin ); } /* ================================================================================= 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_TIME_T 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) unzSetOffset64(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; }