filesystem: load on-disk archives like PAK and PK3 through VFS (disk-only for now)
* Track from which archive the file has been opened and provide needed functions for it
This commit is contained in:
parent
64aa476330
commit
ec107dfba5
8 changed files with 145 additions and 135 deletions
|
@ -227,6 +227,7 @@ static file_t *FS_OpenFile_AndroidAssets( searchpath_t *search, const char *file
|
|||
|
||||
file->position = 0;
|
||||
file->ungetc = EOF;
|
||||
file->searchpath = search;
|
||||
|
||||
AAsset_close( assets );
|
||||
|
||||
|
|
|
@ -457,10 +457,14 @@ static int FS_FileTime_DIR( searchpath_t *search, const char *filename )
|
|||
|
||||
static file_t *FS_OpenFile_DIR( searchpath_t *search, const char *filename, const char *mode, int pack_ind )
|
||||
{
|
||||
file_t *f;
|
||||
char path[MAX_SYSPATH];
|
||||
|
||||
Q_snprintf( path, sizeof( path ), "%s%s", search->filename, filename );
|
||||
return FS_SysOpen( path, mode );
|
||||
f = FS_SysOpen( path, mode );
|
||||
f->searchpath = search;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void FS_InitDirectorySearchpath( searchpath_t *search, const char *path, int flags )
|
||||
|
|
|
@ -1162,13 +1162,13 @@ void FS_AddGameHierarchy( const char *dir, uint flags )
|
|||
if( COM_CheckStringEmpty( fs_rodir ) )
|
||||
{
|
||||
// append new flags to rodir, except FS_GAMEDIR_PATH and FS_CUSTOM_PATH
|
||||
uint newFlags = FS_NOWRITE_PATH | (flags & (~FS_GAMEDIR_PATH|FS_CUSTOM_PATH));
|
||||
uint new_flags = FS_NOWRITE_PATH | (flags & (~FS_GAMEDIR_PATH|FS_CUSTOM_PATH));
|
||||
if( isGameDir )
|
||||
newFlags |= FS_GAMERODIR_PATH;
|
||||
SetBits( new_flags, FS_GAMERODIR_PATH );
|
||||
|
||||
FS_AllowDirectPaths( true );
|
||||
Q_snprintf( buf, sizeof( buf ), "%s/%s/", fs_rodir, dir );
|
||||
FS_AddGameDirectory( buf, newFlags );
|
||||
FS_AddGameDirectory( buf, new_flags );
|
||||
FS_AllowDirectPaths( false );
|
||||
}
|
||||
|
||||
|
@ -1226,7 +1226,7 @@ void FS_LoadGameInfo( const char *rootfolder )
|
|||
int i;
|
||||
|
||||
// lock uplevel of gamedir for read\write
|
||||
fs_ext_path = false;
|
||||
FS_AllowDirectPaths( false );
|
||||
|
||||
if( rootfolder ) Q_strncpy( fs_gamedir, rootfolder, sizeof( fs_gamedir ));
|
||||
Con_Reportf( "%s( %s )\n", __func__, fs_gamedir );
|
||||
|
@ -1312,7 +1312,7 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
|
|||
if( !COM_CheckString( dllname ))
|
||||
return false;
|
||||
|
||||
fs_ext_path = directpath;
|
||||
FS_AllowDirectPaths( directpath );
|
||||
|
||||
// HACKHACK remove relative path to game folder
|
||||
if( !Q_strnicmp( dllname, "..", 2 ))
|
||||
|
@ -1344,7 +1344,7 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
|
|||
}
|
||||
else if( !directpath )
|
||||
{
|
||||
fs_ext_path = false;
|
||||
FS_AllowDirectPaths( false );
|
||||
|
||||
// trying check also 'bin' folder for indirect paths
|
||||
search = FS_FindFile( dllname, &index, fixedname, sizeof( fixedname ), false );
|
||||
|
@ -1389,7 +1389,7 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
|
|||
dllInfo->custom_loader = false;
|
||||
}
|
||||
}
|
||||
fs_ext_path = false; // always reset direct paths
|
||||
FS_AllowDirectPaths( false ); // always reset direct paths
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1704,7 +1704,7 @@ file_t *FS_SysOpen( const char *filepath, const char *mode )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
file->searchpath = NULL;
|
||||
file->real_length = lseek( file->handle, 0, SEEK_END );
|
||||
|
||||
// uncomment do disable write
|
||||
|
@ -1730,16 +1730,23 @@ static int FS_DuplicateHandle( const char *filename, int handle, fs_offset_t pos
|
|||
}
|
||||
*/
|
||||
|
||||
file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offset, fs_offset_t len )
|
||||
file_t *FS_OpenHandle( searchpath_t *searchpath, int handle, fs_offset_t offset, fs_offset_t len )
|
||||
{
|
||||
file_t *file = (file_t *)Mem_Calloc( fs_mempool, sizeof( file_t ));
|
||||
#ifndef XASH_REDUCE_FD
|
||||
#ifdef HAVE_DUP
|
||||
file->handle = dup( handle );
|
||||
#else
|
||||
file->handle = open( syspath, O_RDONLY|O_BINARY );
|
||||
file->handle = open( searchpath->filename, O_RDONLY|O_BINARY );
|
||||
#endif
|
||||
|
||||
if( file->handle < 0 )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: couldn't create fd for %s:0x%lx: %s\n", __func__, searchpath->filename, (long)offset, strerror( errno ));
|
||||
Mem_Free( file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( lseek( file->handle, offset, SEEK_SET ) == -1 )
|
||||
{
|
||||
Mem_Free( file );
|
||||
|
@ -1757,6 +1764,7 @@ file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offset, fs_o
|
|||
file->offset = offset;
|
||||
file->position = 0;
|
||||
file->ungetc = EOF;
|
||||
file->searchpath = searchpath;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
@ -2333,6 +2341,8 @@ int FS_Gets( file_t *file, char *string, size_t bufsize )
|
|||
FS_Seek
|
||||
|
||||
Move the position index in a file
|
||||
NOTE: when porting code, check return value!
|
||||
NOTE: it's not compatible with lseek!
|
||||
====================
|
||||
*/
|
||||
int FS_Seek( file_t *file, fs_offset_t offset, int whence )
|
||||
|
@ -2913,6 +2923,14 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
|
|||
return search;
|
||||
}
|
||||
|
||||
static const char *FS_ArchivePath( file_t *f )
|
||||
{
|
||||
if( f->searchpath )
|
||||
return f->searchpath->filename;
|
||||
|
||||
return "plain";
|
||||
}
|
||||
|
||||
void FS_InitMemory( void )
|
||||
{
|
||||
fs_mempool = Mem_AllocPool( "FileSystem Pool" );
|
||||
|
|
|
@ -191,9 +191,8 @@ typedef struct fs_api_t
|
|||
qboolean (*SysFileExists)( const char *path );
|
||||
const char *(*GetDiskPath)( const char *name, qboolean gamedironly );
|
||||
|
||||
// reserved
|
||||
void (*Unused0)( void );
|
||||
void *(*MountArchive_Fullpath)( const char *path, int flags );
|
||||
const char *(*ArchivePath)( file_t *f ); // returns path to archive from which file was opened or "plain"
|
||||
void *(*MountArchive_Fullpath)( const char *path, int flags ); // mounts the archive by path, if supported
|
||||
|
||||
qboolean (*GetFullDiskPath)( char *buffer, size_t size, const char *name, qboolean gamedironly );
|
||||
|
||||
|
|
|
@ -31,28 +31,30 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
typedef struct searchpath_s searchpath_t;
|
||||
typedef struct dir_s dir_t;
|
||||
typedef struct zip_s zip_t;
|
||||
typedef struct pack_s pack_t;
|
||||
typedef struct wfile_s wfile_t;
|
||||
#if XASH_ANDROID
|
||||
typedef struct android_assets_s android_assets_t;
|
||||
// typedef struct android_saf_s android_saf_t;
|
||||
#endif
|
||||
|
||||
#define FILE_BUFF_SIZE (2048)
|
||||
#define FILE_BUFF_SIZE (2048)
|
||||
|
||||
struct file_s
|
||||
{
|
||||
int handle; // file descriptor
|
||||
int ungetc; // single stored character from ungetc, cleared to EOF when read
|
||||
fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
|
||||
fs_offset_t position; // current position in the file
|
||||
fs_offset_t offset; // offset into the package (0 if external file)
|
||||
time_t filetime; // pak, wad or real filetime
|
||||
// contents buffer
|
||||
fs_offset_t buff_ind, buff_len; // buffer current index and length
|
||||
byte buff[FILE_BUFF_SIZE]; // intermediate buffer
|
||||
int handle; // file descriptor
|
||||
int ungetc; // single stored character from ungetc, cleared to EOF when read
|
||||
time_t filetime; // pak, wad or real filetime
|
||||
searchpath_t *searchpath;
|
||||
fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
|
||||
fs_offset_t position; // current position in the file
|
||||
fs_offset_t offset; // offset into the package (0 if external file)
|
||||
|
||||
// contents buffer
|
||||
fs_offset_t buff_ind; // buffer current index
|
||||
fs_offset_t buff_len; // buffer current length
|
||||
byte buff[FILE_BUFF_SIZE]; // intermediate buffer
|
||||
|
||||
#ifdef XASH_REDUCE_FD
|
||||
const char *backup_path;
|
||||
fs_offset_t backup_position;
|
||||
|
@ -80,9 +82,9 @@ typedef struct stringlist_s
|
|||
|
||||
typedef struct searchpath_s
|
||||
{
|
||||
string filename;
|
||||
searchpathtype_t type;
|
||||
int flags;
|
||||
string filename;
|
||||
searchpathtype_t type;
|
||||
int flags;
|
||||
|
||||
union
|
||||
{
|
||||
|
@ -90,9 +92,7 @@ typedef struct searchpath_s
|
|||
pack_t *pack;
|
||||
wfile_t *wad;
|
||||
zip_t *zip;
|
||||
#if XASH_ANDROID
|
||||
android_assets_t *assets;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct searchpath_s *next;
|
||||
|
@ -211,7 +211,7 @@ qboolean FS_SysFileOrFolderExists( const char *path );
|
|||
file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedironly );
|
||||
|
||||
int FS_SysFileTime( const char *filename );
|
||||
file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offset, fs_offset_t len );
|
||||
file_t *FS_OpenHandle( searchpath_t *search, int handle, fs_offset_t offset, fs_offset_t len );
|
||||
file_t *FS_SysOpen( const char *filepath, const char *mode );
|
||||
searchpath_t *FS_FindFile( const char *name, int *index, char *fixedname, size_t len, qboolean gamedironly );
|
||||
qboolean FS_FullPathToRelativePath( char *dst, const char *src, size_t size );
|
||||
|
|
|
@ -67,9 +67,8 @@ typedef struct
|
|||
|
||||
struct pack_s
|
||||
{
|
||||
int handle;
|
||||
file_t *handle;
|
||||
int numfiles;
|
||||
time_t filetime; // common for all packed files
|
||||
dpackfile_t files[1]; // flexible
|
||||
};
|
||||
|
||||
|
@ -99,27 +98,29 @@ of the list so they override previous pack files.
|
|||
static pack_t *FS_LoadPackPAK( const char *packfile, int *error )
|
||||
{
|
||||
dpackheader_t header;
|
||||
int packhandle;
|
||||
file_t *packhandle;
|
||||
int numpackfiles;
|
||||
pack_t *pack;
|
||||
fs_size_t c;
|
||||
|
||||
packhandle = open( packfile, O_RDONLY|O_BINARY );
|
||||
// TODO: use FS_Open to allow PK3 to be included into other archives
|
||||
// Currently, it doesn't work with rodir due to FS_FindFile logic
|
||||
packhandle = FS_SysOpen( packfile, "rb" );
|
||||
|
||||
if( packhandle < 0 )
|
||||
if( packhandle == NULL )
|
||||
{
|
||||
Con_Reportf( "%s couldn't open: %s\n", packfile, strerror( errno ));
|
||||
if( error ) *error = PAK_LOAD_COULDNT_OPEN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c = read( packhandle, (void *)&header, sizeof( header ));
|
||||
c = FS_Read( packhandle, (void *)&header, sizeof( header ));
|
||||
|
||||
if( c != sizeof( header ) || header.ident != IDPACKV1HEADER )
|
||||
{
|
||||
Con_Reportf( "%s is not a packfile. Ignored.\n", packfile );
|
||||
if( error ) *error = PAK_LOAD_BAD_HEADER;
|
||||
close( packhandle );
|
||||
FS_Close( packhandle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -127,7 +128,7 @@ static pack_t *FS_LoadPackPAK( const char *packfile, int *error )
|
|||
{
|
||||
Con_Reportf( S_ERROR "%s has an invalid directory size. Ignored.\n", packfile );
|
||||
if( error ) *error = PAK_LOAD_BAD_FOLDERS;
|
||||
close( packhandle );
|
||||
FS_Close( packhandle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -137,7 +138,7 @@ static pack_t *FS_LoadPackPAK( const char *packfile, int *error )
|
|||
{
|
||||
Con_Reportf( S_ERROR "%s has too many files ( %i ). Ignored.\n", packfile, numpackfiles );
|
||||
if( error ) *error = PAK_LOAD_TOO_MANY_FILES;
|
||||
close( packhandle );
|
||||
FS_Close( packhandle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -145,26 +146,25 @@ static pack_t *FS_LoadPackPAK( const char *packfile, int *error )
|
|||
{
|
||||
Con_Reportf( "%s has no files. Ignored.\n", packfile );
|
||||
if( error ) *error = PAK_LOAD_NO_FILES;
|
||||
close( packhandle );
|
||||
FS_Close( packhandle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pack = (pack_t *)Mem_Calloc( fs_mempool, sizeof( pack_t ) + sizeof( dpackfile_t ) * ( numpackfiles - 1 ));
|
||||
lseek( packhandle, header.dirofs, SEEK_SET );
|
||||
FS_Seek( packhandle, header.dirofs, SEEK_SET );
|
||||
|
||||
if( header.dirlen != read( packhandle, (void *)pack->files, header.dirlen ))
|
||||
if( header.dirlen != FS_Read( packhandle, (void *)pack->files, header.dirlen ))
|
||||
{
|
||||
Con_Reportf( "%s is an incomplete PAK, not loading\n", packfile );
|
||||
if( error )
|
||||
*error = PAK_LOAD_CORRUPTED;
|
||||
close( packhandle );
|
||||
FS_Close( packhandle );
|
||||
Mem_Free( pack );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TODO: validate directory?
|
||||
|
||||
pack->filetime = FS_SysFileTime( packfile );
|
||||
pack->handle = packhandle;
|
||||
pack->numfiles = numpackfiles;
|
||||
qsort( pack->files, pack->numfiles, sizeof( pack->files[0] ), FS_SortPak );
|
||||
|
@ -194,7 +194,7 @@ static file_t *FS_OpenFile_PAK( searchpath_t *search, const char *filename, cons
|
|||
|
||||
pfile = &search->pack->files[pack_ind];
|
||||
|
||||
return FS_OpenHandle( search->filename, search->pack->handle, pfile->filepos, pfile->filelen );
|
||||
return FS_OpenHandle( search, search->pack->handle->handle, pfile->filepos, pfile->filelen );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -288,7 +288,7 @@ FS_FileTime_PAK
|
|||
*/
|
||||
static int FS_FileTime_PAK( searchpath_t *search, const char *filename )
|
||||
{
|
||||
return search->pack->filetime;
|
||||
return search->pack->handle->filetime;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -299,7 +299,9 @@ FS_PrintInfo_PAK
|
|||
*/
|
||||
static void FS_PrintInfo_PAK( searchpath_t *search, char *dst, size_t size )
|
||||
{
|
||||
Q_snprintf( dst, size, "%s (%i files)", search->filename, search->pack->numfiles );
|
||||
if( search->pack->handle->searchpath )
|
||||
Q_snprintf( dst, size, "%s (%i files)" S_CYAN " from %s" S_DEFAULT, search->filename, search->pack->numfiles, search->pack->handle->searchpath->filename );
|
||||
else Q_snprintf( dst, size, "%s (%i files)", search->filename, search->pack->numfiles );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -310,8 +312,8 @@ FS_Close_PAK
|
|||
*/
|
||||
static void FS_Close_PAK( searchpath_t *search )
|
||||
{
|
||||
if( search->pack->handle >= 0 )
|
||||
close( search->pack->handle );
|
||||
if( search->pack->handle != NULL )
|
||||
FS_Close( search->pack->handle );
|
||||
Mem_Free( search->pack );
|
||||
}
|
||||
|
||||
|
|
|
@ -415,7 +415,9 @@ FS_PrintInfo_WAD
|
|||
*/
|
||||
static void FS_PrintInfo_WAD( searchpath_t *search, char *dst, size_t size )
|
||||
{
|
||||
Q_snprintf( dst, size, "%s (%i files)", search->filename, search->wad->numlumps );
|
||||
if( search->wad->handle->searchpath )
|
||||
Q_snprintf( dst, size, "%s (%i files)" S_CYAN " from %s" S_DEFAULT, search->filename, search->wad->numlumps, search->wad->handle->searchpath->filename );
|
||||
else Q_snprintf( dst, size, "%s (%i files)", search->filename, search->wad->numlumps );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
148
filesystem/zip.c
148
filesystem/zip.c
|
@ -123,33 +123,13 @@ typedef struct zipfile_s
|
|||
|
||||
struct zip_s
|
||||
{
|
||||
int handle;
|
||||
file_t *handle;
|
||||
int numfiles;
|
||||
time_t filetime;
|
||||
zipfile_t *files;
|
||||
zipfile_t files[1]; // flexible
|
||||
};
|
||||
|
||||
// #define ENABLE_CRC_CHECK // known to be buggy because of possible libpublic crc32 bug, disabled
|
||||
|
||||
#ifdef XASH_REDUCE_FD
|
||||
static void FS_EnsureOpenZip( zip_t *zip )
|
||||
{
|
||||
if( fs_last_zip == zip )
|
||||
return;
|
||||
|
||||
if( fs_last_zip && (fs_last_zip->handle != -1) )
|
||||
{
|
||||
close( fs_last_zip->handle );
|
||||
fs_last_zip->handle = -1;
|
||||
}
|
||||
fs_last_zip = zip;
|
||||
if( zip && (zip->handle == -1) )
|
||||
zip->handle = open( zip->filename, O_RDONLY|O_BINARY );
|
||||
}
|
||||
#else
|
||||
static void FS_EnsureOpenZip( zip_t *zip ) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
============
|
||||
FS_CloseZIP
|
||||
|
@ -157,13 +137,8 @@ FS_CloseZIP
|
|||
*/
|
||||
static void FS_CloseZIP( zip_t *zip )
|
||||
{
|
||||
if( zip->files )
|
||||
Mem_Free( zip->files );
|
||||
|
||||
FS_EnsureOpenZip( NULL );
|
||||
|
||||
if( zip->handle >= 0 )
|
||||
close( zip->handle );
|
||||
if( zip->handle != NULL )
|
||||
FS_Close( zip->handle );
|
||||
|
||||
Mem_Free( zip );
|
||||
}
|
||||
|
@ -185,7 +160,7 @@ FS_SortZip
|
|||
*/
|
||||
static int FS_SortZip( const void *a, const void *b )
|
||||
{
|
||||
return Q_stricmp( ( ( zipfile_t* )a )->name, ( ( zipfile_t* )b )->name );
|
||||
return Q_stricmp(((zipfile_t *)a )->name, ((zipfile_t *)b )->name );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -199,15 +174,17 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
zip_cdf_header_t header_cdf;
|
||||
zip_header_eocd_t header_eocd;
|
||||
uint32_t signature;
|
||||
fs_offset_t filepos = 0, length;
|
||||
fs_offset_t filepos = 0;
|
||||
zipfile_t *info = NULL;
|
||||
char filename_buffer[MAX_SYSPATH];
|
||||
zip_t *zip = (zip_t *)Mem_Calloc( fs_mempool, sizeof( *zip ));
|
||||
fs_size_t c;
|
||||
|
||||
zip->handle = open( zipfile, O_RDONLY|O_BINARY );
|
||||
// TODO: use FS_Open to allow PK3 to be included into other archives
|
||||
// Currently, it doesn't work with rodir due to FS_FindFile logic
|
||||
zip->handle = FS_SysOpen( zipfile, "rb" );
|
||||
|
||||
if( zip->handle < 0 )
|
||||
if( zip->handle == NULL )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s couldn't open\n", zipfile );
|
||||
|
||||
|
@ -218,9 +195,7 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
length = lseek( zip->handle, 0, SEEK_END );
|
||||
|
||||
if( length > UINT_MAX )
|
||||
if( zip->handle->real_length > UINT32_MAX )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s bigger than 4GB.\n", zipfile );
|
||||
|
||||
|
@ -231,9 +206,9 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
lseek( zip->handle, 0, SEEK_SET );
|
||||
FS_Seek( zip->handle, 0, SEEK_SET );
|
||||
|
||||
c = read( zip->handle, &signature, sizeof( signature ) );
|
||||
c = FS_Read( zip->handle, &signature, sizeof( signature ));
|
||||
|
||||
if( c != sizeof( signature ) || signature == ZIP_HEADER_EOCD )
|
||||
{
|
||||
|
@ -258,13 +233,12 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
}
|
||||
|
||||
// Find oecd
|
||||
lseek( zip->handle, 0, SEEK_SET );
|
||||
filepos = length;
|
||||
filepos = zip->handle->real_length;
|
||||
|
||||
while ( filepos > 0 )
|
||||
while( filepos > 0 )
|
||||
{
|
||||
lseek( zip->handle, filepos, SEEK_SET );
|
||||
c = read( zip->handle, &signature, sizeof( signature ) );
|
||||
FS_Seek( zip->handle, filepos, SEEK_SET );
|
||||
c = FS_Read( zip->handle, &signature, sizeof( signature ));
|
||||
|
||||
if( c == sizeof( signature ) && signature == ZIP_HEADER_EOCD )
|
||||
break;
|
||||
|
@ -283,7 +257,7 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
c = read( zip->handle, &header_eocd, sizeof( header_eocd ) );
|
||||
c = FS_Read( zip->handle, &header_eocd, sizeof( header_eocd ));
|
||||
|
||||
if( c != sizeof( header_eocd ))
|
||||
{
|
||||
|
@ -296,15 +270,27 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if( header_eocd.total_central_directory_record == 0 ) // refuse to load empty ZIP archives
|
||||
{
|
||||
Con_Reportf( S_WARN "%s has no files (total records is zero). Ignored.\n", zipfile );
|
||||
|
||||
if( error )
|
||||
*error = ZIP_LOAD_NO_FILES;
|
||||
|
||||
FS_CloseZIP( zip );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Move to CDF start
|
||||
lseek( zip->handle, header_eocd.central_directory_offset, SEEK_SET );
|
||||
FS_Seek( zip->handle, header_eocd.central_directory_offset, SEEK_SET );
|
||||
|
||||
// Calc count of files in archive
|
||||
info = (zipfile_t *)Mem_Calloc( fs_mempool, sizeof( *info ) * header_eocd.total_central_directory_record );
|
||||
zip = (zip_t *)Mem_Realloc( fs_mempool, zip, sizeof( *zip ) + sizeof( *info ) * ( header_eocd.total_central_directory_record - 1 ));
|
||||
info = zip->files;
|
||||
|
||||
for( i = 0; i < header_eocd.total_central_directory_record; i++ )
|
||||
{
|
||||
c = read( zip->handle, &header_cdf, sizeof( header_cdf ) );
|
||||
c = FS_Read( zip->handle, &header_cdf, sizeof( header_cdf ));
|
||||
|
||||
if( c != sizeof( header_cdf ) || header_cdf.signature != ZIP_HEADER_CDF )
|
||||
{
|
||||
|
@ -318,10 +304,10 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if( header_cdf.uncompressed_size && header_cdf.filename_len && ( header_cdf.filename_len < MAX_SYSPATH ) )
|
||||
if( header_cdf.uncompressed_size && header_cdf.filename_len && header_cdf.filename_len < sizeof( filename_buffer ))
|
||||
{
|
||||
memset( &filename_buffer, '\0', MAX_SYSPATH );
|
||||
c = read( zip->handle, &filename_buffer, header_cdf.filename_len );
|
||||
memset( &filename_buffer, '\0', sizeof( filename_buffer ));
|
||||
c = FS_Read( zip->handle, &filename_buffer, header_cdf.filename_len );
|
||||
|
||||
if( c != header_cdf.filename_len )
|
||||
{
|
||||
|
@ -335,21 +321,32 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
Q_strncpy( info[numpackfiles].name, filename_buffer, MAX_SYSPATH );
|
||||
|
||||
Q_strncpy( info[numpackfiles].name, filename_buffer, sizeof( info[numpackfiles].name ));
|
||||
info[numpackfiles].size = header_cdf.uncompressed_size;
|
||||
info[numpackfiles].compressed_size = header_cdf.compressed_size;
|
||||
info[numpackfiles].offset = header_cdf.local_header_offset;
|
||||
numpackfiles++;
|
||||
}
|
||||
else
|
||||
lseek( zip->handle, header_cdf.filename_len, SEEK_CUR );
|
||||
FS_Seek( zip->handle, header_cdf.filename_len, SEEK_CUR );
|
||||
|
||||
if( header_cdf.extrafield_len )
|
||||
lseek( zip->handle, header_cdf.extrafield_len, SEEK_CUR );
|
||||
FS_Seek( zip->handle, header_cdf.extrafield_len, SEEK_CUR );
|
||||
|
||||
if( header_cdf.file_commentary_len )
|
||||
lseek( zip->handle, header_cdf.file_commentary_len, SEEK_CUR );
|
||||
FS_Seek( zip->handle, header_cdf.file_commentary_len, SEEK_CUR );
|
||||
}
|
||||
|
||||
// refuse to load empty files again
|
||||
if( numpackfiles == 0 )
|
||||
{
|
||||
Con_Reportf( S_WARN "%s has no files (recalculated). Ignored.\n", zipfile );
|
||||
|
||||
if( error )
|
||||
*error = ZIP_LOAD_NO_FILES;
|
||||
|
||||
FS_CloseZIP( zip );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// recalculate offsets
|
||||
|
@ -357,8 +354,8 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
{
|
||||
zip_header_t header;
|
||||
|
||||
lseek( zip->handle, info[i].offset, SEEK_SET );
|
||||
c = read( zip->handle, &header, sizeof( header ) );
|
||||
FS_Seek( zip->handle, info[i].offset, SEEK_SET );
|
||||
c = FS_Read( zip->handle, &header, sizeof( header ) );
|
||||
|
||||
if( c != sizeof( header ))
|
||||
{
|
||||
|
@ -376,18 +373,9 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||
info[i].offset = info[i].offset + header.filename_len + header.extrafield_len + sizeof( header );
|
||||
}
|
||||
|
||||
zip->filetime = FS_SysFileTime( zipfile );
|
||||
zip->numfiles = numpackfiles;
|
||||
zip->files = info;
|
||||
|
||||
qsort( zip->files, zip->numfiles, sizeof( *zip->files ), FS_SortZip );
|
||||
|
||||
#ifdef XASH_REDUCE_FD
|
||||
// will reopen when needed
|
||||
close(zip->handle);
|
||||
zip->handle = -1;
|
||||
#endif
|
||||
|
||||
if( error )
|
||||
*error = ZIP_LOAD_OK;
|
||||
|
||||
|
@ -403,8 +391,7 @@ Open a packed file using its package file descriptor
|
|||
*/
|
||||
static file_t *FS_OpenFile_ZIP( searchpath_t *search, const char *filename, const char *mode, int pack_ind )
|
||||
{
|
||||
zipfile_t *pfile;
|
||||
pfile = &search->zip->files[pack_ind];
|
||||
zipfile_t *pfile = &search->zip->files[pack_ind];
|
||||
|
||||
// compressed files handled in Zip_LoadFile
|
||||
if( pfile->flags != ZIP_COMPRESSION_NO_COMPRESSION )
|
||||
|
@ -413,7 +400,7 @@ static file_t *FS_OpenFile_ZIP( searchpath_t *search, const char *filename, cons
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return FS_OpenHandle( search->filename, search->zip->handle, pfile->offset, pfile->size );
|
||||
return FS_OpenHandle( search, search->zip->handle->handle, pfile->offset, pfile->size );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -437,12 +424,10 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
|||
|
||||
file = &search->zip->files[pack_ind];
|
||||
|
||||
FS_EnsureOpenZip( search->zip );
|
||||
|
||||
if( lseek( search->zip->handle, file->offset, SEEK_SET ) == -1 )
|
||||
if( FS_Seek( search->zip->handle, file->offset, SEEK_SET ) == -1 )
|
||||
return NULL;
|
||||
|
||||
/*if( read( search->zip->handle, &header, sizeof( header ) ) < 0 )
|
||||
/*if( FS_Read( search->zip->handle, &header, sizeof( header )) < 0 )
|
||||
return NULL;
|
||||
|
||||
if( header.signature != ZIP_HEADER_LF )
|
||||
|
@ -451,7 +436,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
|||
return NULL;
|
||||
}*/
|
||||
|
||||
decompressed_buffer = pfnAlloc( file->size + 1 );
|
||||
decompressed_buffer = (byte *)pfnAlloc( file->size + 1 );
|
||||
if( unlikely( !decompressed_buffer ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: can't alloc %li bytes, no free memory\n", __func__, (long)file->size + 1 );
|
||||
|
@ -461,7 +446,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
|||
|
||||
if( file->flags == ZIP_COMPRESSION_NO_COMPRESSION )
|
||||
{
|
||||
c = read( search->zip->handle, decompressed_buffer, file->size );
|
||||
c = FS_Read( search->zip->handle, decompressed_buffer, file->size );
|
||||
if( c != file->size )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: %s size doesn't match\n", __func__, file->name );
|
||||
|
@ -484,14 +469,13 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
|||
|
||||
if( sizeptr ) *sizeptr = file->size;
|
||||
|
||||
FS_EnsureOpenZip( NULL );
|
||||
return decompressed_buffer;
|
||||
}
|
||||
else if( file->flags == ZIP_COMPRESSION_DEFLATED )
|
||||
{
|
||||
compressed_buffer = Mem_Malloc( fs_mempool, file->compressed_size + 1 );
|
||||
compressed_buffer = (byte *)Mem_Malloc( fs_mempool, file->compressed_size + 1 );
|
||||
|
||||
c = read( search->zip->handle, compressed_buffer, file->compressed_size );
|
||||
c = FS_Read( search->zip->handle, compressed_buffer, file->compressed_size );
|
||||
if( c != file->compressed_size )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: %s compressed size doesn't match\n", __func__, file->name );
|
||||
|
@ -538,7 +522,6 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
|||
#endif
|
||||
if( sizeptr ) *sizeptr = file->size;
|
||||
|
||||
FS_EnsureOpenZip( NULL );
|
||||
return decompressed_buffer;
|
||||
}
|
||||
else
|
||||
|
@ -557,7 +540,6 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
|||
return NULL;
|
||||
}
|
||||
|
||||
FS_EnsureOpenZip( NULL );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -569,7 +551,7 @@ FS_FileTime_ZIP
|
|||
*/
|
||||
static int FS_FileTime_ZIP( searchpath_t *search, const char *filename )
|
||||
{
|
||||
return search->zip->filetime;
|
||||
return search->zip->handle->filetime;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -580,7 +562,9 @@ FS_PrintInfo_ZIP
|
|||
*/
|
||||
static void FS_PrintInfo_ZIP( searchpath_t *search, char *dst, size_t size )
|
||||
{
|
||||
Q_snprintf( dst, size, "%s (%i files)", search->filename, search->zip->numfiles );
|
||||
if( search->zip->handle->searchpath )
|
||||
Q_snprintf( dst, size, "%s (%i files)" S_CYAN " from %s" S_DEFAULT, search->filename, search->zip->numfiles, search->zip->handle->searchpath->filename );
|
||||
else Q_snprintf( dst, size, "%s (%i files)", search->filename, search->zip->numfiles );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue