mirror of
https://github.com/YGGverse/xash3d-fwgs.git
synced 2025-01-17 18:40:02 +00:00
filesystem: refactor zip/pak loading, partially fix reading files from zip, add option to reduce FD usage, remove dup() dependency
This commit is contained in:
parent
70cddcb9ca
commit
22c148a39e
@ -20,6 +20,9 @@ GNU General Public License for more details.
|
|||||||
#if XASH_WIN32
|
#if XASH_WIN32
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#elif XASH_DOS4GW
|
||||||
|
#include <direct.h>
|
||||||
|
#include <errno.h>
|
||||||
#else
|
#else
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -61,6 +64,8 @@ GNU General Public License for more details.
|
|||||||
#define ZIP_LOAD_NO_FILES 5
|
#define ZIP_LOAD_NO_FILES 5
|
||||||
#define ZIP_LOAD_CORRUPTED 6
|
#define ZIP_LOAD_CORRUPTED 6
|
||||||
|
|
||||||
|
#define XASH_REDUCE_FD
|
||||||
|
|
||||||
typedef struct stringlist_s
|
typedef struct stringlist_s
|
||||||
{
|
{
|
||||||
// maxstrings changes as needed, causing reallocation of strings[] array
|
// maxstrings changes as needed, causing reallocation of strings[] array
|
||||||
@ -86,6 +91,11 @@ struct file_s
|
|||||||
// contents buffer
|
// contents buffer
|
||||||
fs_offset_t buff_ind, buff_len; // buffer current index and length
|
fs_offset_t buff_ind, buff_len; // buffer current index and length
|
||||||
byte buff[FILE_BUFF_SIZE]; // intermediate buffer
|
byte buff[FILE_BUFF_SIZE]; // intermediate buffer
|
||||||
|
#ifdef XASH_REDUCE_FD
|
||||||
|
const char *backup_path;
|
||||||
|
fs_offset_t *backup_position;
|
||||||
|
uint backup_options;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wfile_s
|
struct wfile_s
|
||||||
@ -114,13 +124,13 @@ typedef struct zipfile_s
|
|||||||
fs_offset_t offset; // offset of local file header
|
fs_offset_t offset; // offset of local file header
|
||||||
fs_offset_t size; //original file size
|
fs_offset_t size; //original file size
|
||||||
fs_offset_t compressed_size; // compressed file size
|
fs_offset_t compressed_size; // compressed file size
|
||||||
|
unsigned short flags;
|
||||||
} zipfile_t;
|
} zipfile_t;
|
||||||
|
|
||||||
typedef struct zip_s
|
typedef struct zip_s
|
||||||
{
|
{
|
||||||
string filename;
|
string filename;
|
||||||
byte *mempool;
|
int handle;
|
||||||
file_t *handle;
|
|
||||||
int numfiles;
|
int numfiles;
|
||||||
time_t filetime;
|
time_t filetime;
|
||||||
zipfile_t *files;
|
zipfile_t *files;
|
||||||
@ -136,18 +146,82 @@ typedef struct searchpath_s
|
|||||||
struct searchpath_s *next;
|
struct searchpath_s *next;
|
||||||
} searchpath_t;
|
} searchpath_t;
|
||||||
|
|
||||||
byte *fs_mempool;
|
static byte *fs_mempool;
|
||||||
searchpath_t *fs_searchpaths = NULL; // chain
|
static searchpath_t *fs_searchpaths = NULL; // chain
|
||||||
searchpath_t fs_directpath; // static direct path
|
static searchpath_t fs_directpath; // static direct path
|
||||||
char fs_basedir[MAX_SYSPATH]; // base game directory
|
static char fs_basedir[MAX_SYSPATH]; // base game directory
|
||||||
char fs_gamedir[MAX_SYSPATH]; // game current directory
|
static char fs_gamedir[MAX_SYSPATH]; // game current directory
|
||||||
char fs_writedir[MAX_SYSPATH]; // path that game allows to overwrite, delete and rename files (and create new of course)
|
static char fs_writedir[MAX_SYSPATH]; // path that game allows to overwrite, delete and rename files (and create new of course)
|
||||||
|
|
||||||
qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
|
static qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
|
||||||
#if !XASH_WIN32
|
#if !XASH_WIN32
|
||||||
qboolean fs_caseinsensitive = true; // try to search missing files
|
static qboolean fs_caseinsensitive = true; // try to search missing files
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef XASH_REDUCE_FD
|
||||||
|
static file_t *fs_last_readfile;
|
||||||
|
static zip_t *fs_last_zip;
|
||||||
|
static pack_t *fs_last_pak;
|
||||||
|
|
||||||
|
static void FS_EnsureOpenFile( file_t *file )
|
||||||
|
{
|
||||||
|
if( fs_last_readfile == file )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( !file->backup_path )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( fs_last_readfile && (fs_last_readfile->handle != -1) )
|
||||||
|
{
|
||||||
|
fs_last_readfile->backup_position = lseek( fs_last_readfile->handle, 0, SEEK_CUR );
|
||||||
|
close( fs_last_readfile->handle );
|
||||||
|
fs_last_readfile->handle = -1;
|
||||||
|
}
|
||||||
|
fs_last_readfile = file;
|
||||||
|
if( file && (file->handle == -1) )
|
||||||
|
{
|
||||||
|
file->handle = open( file->backup_path, file->backup_options );
|
||||||
|
lseek( file->handle, file->backup_position, SEEK_SET );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FS_BackupFileName( file_t *file, const char *path, uint options )
|
||||||
|
{
|
||||||
|
if( path == NULL )
|
||||||
|
{
|
||||||
|
if( file->backup_path )
|
||||||
|
Mem_Free( file->backup_path );
|
||||||
|
if( file == fs_last_readfile )
|
||||||
|
FS_EnsureOpenFile( NULL );
|
||||||
|
}
|
||||||
|
else if( options == O_RDONLY || options == (O_RDONLY|O_BINARY) )
|
||||||
|
{
|
||||||
|
file->backup_path = copystring( path );
|
||||||
|
file->backup_options = options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
static void FS_EnsureOpenFile( file_t *file ) {}
|
||||||
|
static void FS_EnsureOpenZip( zip_t *zip ) {}
|
||||||
|
static void FS_BackupFileName( file_t *file, const char *path, uint options ) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void FS_InitMemory( void );
|
static void FS_InitMemory( void );
|
||||||
static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly );
|
static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly );
|
||||||
@ -281,10 +355,8 @@ static void listdirectory( stringlist_t *list, const char *path, qboolean lowerc
|
|||||||
closedir( dir );
|
closedir( dir );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// seems not needed anymore
|
#if XASH_DOS4GW
|
||||||
#if 0
|
// convert names to lowercase because 8.3 always in CAPS
|
||||||
// convert names to lowercase because windows doesn't care, but pattern matching code often does
|
|
||||||
if( lowercase )
|
|
||||||
listlowercase( list );
|
listlowercase( list );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -296,6 +368,7 @@ OTHER PRIVATE FUNCTIONS
|
|||||||
|
|
||||||
=============================================================================
|
=============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
FS_FixFileCase
|
FS_FixFileCase
|
||||||
@ -305,7 +378,36 @@ emulate WIN32 FS behaviour when opening local file
|
|||||||
*/
|
*/
|
||||||
static const char *FS_FixFileCase( const char *path )
|
static const char *FS_FixFileCase( const char *path )
|
||||||
{
|
{
|
||||||
#if !XASH_WIN32 && !XASH_IOS // assume case insensitive
|
#if defined __DOS__ & !defined __WATCOM_LFN__
|
||||||
|
// not fix, but convert to 8.3 CAPS and rotate slashes
|
||||||
|
// it is still recommended to package game data
|
||||||
|
static char out[PATH_MAX];
|
||||||
|
int i = 0;
|
||||||
|
int last = 0;
|
||||||
|
while(*path)
|
||||||
|
{
|
||||||
|
char c = *path++;
|
||||||
|
|
||||||
|
if(c == '/') c = '\\';
|
||||||
|
else c = toupper(c);
|
||||||
|
out[i++] = c;
|
||||||
|
if(c == '\\' || c == '.')
|
||||||
|
{
|
||||||
|
if( i - last > 8 )
|
||||||
|
{
|
||||||
|
char *l = &out[last];
|
||||||
|
l[6] = '~';
|
||||||
|
l[7] = '1';
|
||||||
|
l[8] = c;
|
||||||
|
i = last + 9;
|
||||||
|
}
|
||||||
|
last = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out[i] = 0;
|
||||||
|
return out;
|
||||||
|
#elif !XASH_WIN32 && !XASH_IOS // assume case insensitive
|
||||||
DIR *dir; struct dirent *entry;
|
DIR *dir; struct dirent *entry;
|
||||||
char path2[PATH_MAX], *fname;
|
char path2[PATH_MAX], *fname;
|
||||||
|
|
||||||
@ -567,52 +669,41 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error )
|
|||||||
for( i = 0; i < numpackfiles; i++ )
|
for( i = 0; i < numpackfiles; i++ )
|
||||||
FS_AddFileToPack( info[i].name, pack, info[i].filepos, info[i].filelen );
|
FS_AddFileToPack( info[i].name, pack, info[i].filepos, info[i].filelen );
|
||||||
|
|
||||||
|
#ifdef XASH_REDUCE_FD
|
||||||
|
// will reopen when needed
|
||||||
|
close(pack->handle);
|
||||||
|
pack->handle = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
if( error ) *error = PAK_LOAD_OK;
|
if( error ) *error = PAK_LOAD_OK;
|
||||||
Mem_Free( info );
|
Mem_Free( info );
|
||||||
|
|
||||||
return pack;
|
return pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
static zipfile_t *FS_AddFileToZip( const char *name, zip_t *zip, fs_offset_t offset, fs_offset_t size, fs_offset_t compressed_size)
|
|
||||||
{
|
|
||||||
zipfile_t *zipfile = NULL;
|
|
||||||
|
|
||||||
zipfile = &zip->files[zip->numfiles];
|
|
||||||
|
|
||||||
Q_strncpy( zipfile->name, name, MAX_SYSPATH );
|
|
||||||
|
|
||||||
zipfile->size = size;
|
|
||||||
zipfile->offset = offset;
|
|
||||||
zipfile->compressed_size = compressed_size;
|
|
||||||
|
|
||||||
zip->numfiles++;
|
|
||||||
|
|
||||||
return zipfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
||||||
{
|
{
|
||||||
int numpackfiles = 0, i;
|
int numpackfiles = 0, i;
|
||||||
zip_cdf_header_t header_cdf;
|
zip_cdf_header_t header_cdf;
|
||||||
zip_header_eocd_t header_eocd;
|
zip_header_eocd_t header_eocd;
|
||||||
uint signature;
|
uint signature;
|
||||||
fs_offset_t filepos = 0;
|
fs_offset_t filepos = 0, length;
|
||||||
zipfile_t *info = NULL;
|
zipfile_t *info = NULL;
|
||||||
char filename_buffer[MAX_SYSPATH];
|
char filename_buffer[MAX_SYSPATH];
|
||||||
zip_t *zip = (zip_t *)Mem_Calloc( fs_mempool, sizeof( zip_t ) );
|
zip_t *zip = (zip_t *)Mem_Calloc( fs_mempool, sizeof( zip_t ) );
|
||||||
|
|
||||||
zip->handle = FS_Open( zipfile, "rb", true );
|
zip->handle = open( zipfile, O_RDONLY|O_BINARY );
|
||||||
|
|
||||||
#if !XASH_WIN32
|
#if !XASH_WIN32
|
||||||
if( !zip->handle )
|
if( zip->handle < 0 )
|
||||||
{
|
{
|
||||||
const char *fzipfile = FS_FixFileCase( zipfile );
|
const char *fzipfile = FS_FixFileCase( zipfile );
|
||||||
if( fzipfile != zipfile )
|
if( fzipfile != zipfile )
|
||||||
zip->handle = FS_Open( fzipfile, "rb", true );
|
zip->handle = open( fzipfile, O_RDONLY|O_BINARY );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( !zip->handle )
|
if( zip->handle < 0 )
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "%s couldn't open\n", zipfile );
|
Con_Reportf( S_ERROR "%s couldn't open\n", zipfile );
|
||||||
|
|
||||||
@ -623,7 +714,9 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( FS_FileLength( zip->handle ) > UINT_MAX )
|
length = lseek( zip->handle, 0, SEEK_END );
|
||||||
|
|
||||||
|
if( length > UINT_MAX )
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "%s bigger than 4GB.\n", zipfile );
|
Con_Reportf( S_ERROR "%s bigger than 4GB.\n", zipfile );
|
||||||
|
|
||||||
@ -634,7 +727,9 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FS_Read( zip->handle, (void *)&signature, sizeof( uint ) );
|
lseek( zip->handle, 0, SEEK_SET );
|
||||||
|
|
||||||
|
read( zip->handle, &signature, sizeof( signature ) );
|
||||||
|
|
||||||
if( signature == ZIP_HEADER_EOCD )
|
if( signature == ZIP_HEADER_EOCD )
|
||||||
{
|
{
|
||||||
@ -659,13 +754,13 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find oecd
|
// Find oecd
|
||||||
FS_Seek( zip->handle, 0, SEEK_SET );
|
lseek( zip->handle, 0, SEEK_SET );
|
||||||
filepos = zip->handle->real_length;
|
filepos = length;
|
||||||
|
|
||||||
while ( filepos > 0 )
|
while ( filepos > 0 )
|
||||||
{
|
{
|
||||||
FS_Seek( zip->handle, filepos, SEEK_SET );
|
lseek( zip->handle, filepos, SEEK_SET );
|
||||||
FS_Read( zip->handle, (void *)&signature, sizeof( signature ) );
|
read( zip->handle, &signature, sizeof( signature ) );
|
||||||
|
|
||||||
if( signature == ZIP_HEADER_EOCD )
|
if( signature == ZIP_HEADER_EOCD )
|
||||||
break;
|
break;
|
||||||
@ -675,7 +770,7 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||||||
|
|
||||||
if( ZIP_HEADER_EOCD != signature )
|
if( ZIP_HEADER_EOCD != signature )
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "Cannot find EOCD in %s. Zip file corrupted.\n", zipfile );
|
Con_Reportf( S_ERROR "cannot find EOCD in %s. Zip file corrupted.\n", zipfile );
|
||||||
|
|
||||||
if( error )
|
if( error )
|
||||||
*error = ZIP_LOAD_BAD_HEADER;
|
*error = ZIP_LOAD_BAD_HEADER;
|
||||||
@ -684,19 +779,17 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FS_Read( zip->handle, (void *)&header_eocd, sizeof( zip_header_eocd_t ) );
|
read( zip->handle, &header_eocd, sizeof( zip_header_eocd_t ) );
|
||||||
|
|
||||||
// Move to CDF start
|
// 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
|
// Calc count of files in archive
|
||||||
|
|
||||||
info = (zipfile_t *)Mem_Calloc( fs_mempool, sizeof( zipfile_t ) * header_eocd.total_central_directory_record );
|
info = (zipfile_t *)Mem_Calloc( fs_mempool, sizeof( zipfile_t ) * header_eocd.total_central_directory_record );
|
||||||
|
|
||||||
for( i = 0; i < header_eocd.total_central_directory_record; i++ )
|
for( i = 0; i < header_eocd.total_central_directory_record; i++ )
|
||||||
{
|
{
|
||||||
FS_Read( zip->handle, (void *)&header_cdf, sizeof( header_cdf ) );
|
read( zip->handle, &header_cdf, sizeof( header_cdf ) );
|
||||||
|
|
||||||
if( header_cdf.signature != ZIP_HEADER_CDF )
|
if( header_cdf.signature != ZIP_HEADER_CDF )
|
||||||
{
|
{
|
||||||
@ -710,16 +803,10 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( header_cdf.uncompressed_size && header_cdf.filename_len )
|
if( header_cdf.uncompressed_size && header_cdf.filename_len && ( header_cdf.filename_len < MAX_SYSPATH ) )
|
||||||
{
|
{
|
||||||
if(header_cdf.filename_len > MAX_SYSPATH) // ignore files with bigger than 1024 bytes
|
|
||||||
{
|
|
||||||
Con_Reportf( S_WARN "File name bigger than buffer. Ignored.\n" );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset( &filename_buffer, '\0', MAX_SYSPATH );
|
memset( &filename_buffer, '\0', MAX_SYSPATH );
|
||||||
FS_Read( zip->handle, &filename_buffer, header_cdf.filename_len );
|
read( zip->handle, &filename_buffer, header_cdf.filename_len );
|
||||||
Q_strncpy( info[numpackfiles].name, filename_buffer, MAX_SYSPATH );
|
Q_strncpy( info[numpackfiles].name, filename_buffer, MAX_SYSPATH );
|
||||||
|
|
||||||
info[numpackfiles].size = header_cdf.uncompressed_size;
|
info[numpackfiles].size = header_cdf.uncompressed_size;
|
||||||
@ -728,29 +815,40 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
|||||||
numpackfiles++;
|
numpackfiles++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
FS_Seek( zip->handle, header_cdf.filename_len, SEEK_CUR );
|
lseek( zip->handle, header_cdf.filename_len, SEEK_CUR );
|
||||||
|
|
||||||
if( header_cdf.extrafield_len )
|
if( header_cdf.extrafield_len )
|
||||||
FS_Seek( zip->handle, header_cdf.extrafield_len, SEEK_CUR );
|
lseek( zip->handle, header_cdf.extrafield_len, SEEK_CUR );
|
||||||
|
|
||||||
if( header_cdf.file_commentary_len )
|
if( header_cdf.file_commentary_len )
|
||||||
FS_Seek( zip->handle, header_cdf.file_commentary_len, SEEK_CUR );
|
lseek( zip->handle, header_cdf.file_commentary_len, SEEK_CUR );
|
||||||
|
}
|
||||||
|
|
||||||
|
// recalculate offsets
|
||||||
|
for( i = 0; i < numpackfiles; i++ )
|
||||||
|
{
|
||||||
|
zip_header_t header;
|
||||||
|
|
||||||
|
lseek( zip->handle, info[i].offset, SEEK_SET );
|
||||||
|
read( zip->handle, &header, sizeof( header ) );
|
||||||
|
info[i].flags = header.compression_flags;
|
||||||
|
info[i].offset = info[i].offset + header.filename_len + header.extrafield_len + sizeof( header );
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_strncpy( zip->filename, zipfile, sizeof( zip->filename ) );
|
Q_strncpy( zip->filename, zipfile, sizeof( zip->filename ) );
|
||||||
zip->mempool = Mem_AllocPool( zipfile );
|
|
||||||
zip->filetime = FS_SysFileTime( zipfile );
|
zip->filetime = FS_SysFileTime( zipfile );
|
||||||
zip->numfiles = 0;
|
zip->numfiles = numpackfiles;
|
||||||
zip->files = (zipfile_t *)Mem_Calloc( fs_mempool, sizeof( zipfile_t ) * numpackfiles );
|
zip->files = info;
|
||||||
|
|
||||||
for( i = 0; i < numpackfiles; i++ )
|
#ifdef XASH_REDUCE_FD
|
||||||
FS_AddFileToZip( info[i].name, zip, info[i].offset, info[i].size, info[i].compressed_size );
|
// will reopen when needed
|
||||||
|
close(zip->handle);
|
||||||
|
zip->handle = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
if( error )
|
if( error )
|
||||||
*error = ZIP_LOAD_OK;
|
*error = ZIP_LOAD_OK;
|
||||||
|
|
||||||
Mem_Free( info );
|
|
||||||
|
|
||||||
return zip;
|
return zip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,10 +857,12 @@ void Zip_Close( zip_t *zip )
|
|||||||
if( !zip )
|
if( !zip )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Mem_FreePool( &zip->mempool );
|
Mem_Free( zip->files );
|
||||||
|
|
||||||
if( zip->handle != NULL )
|
FS_EnsureOpenZip( NULL );
|
||||||
FS_Close( zip->handle );
|
|
||||||
|
if( zip->handle >= 0 )
|
||||||
|
close( zip->handle );
|
||||||
|
|
||||||
Mem_Free( zip );
|
Mem_Free( zip );
|
||||||
}
|
}
|
||||||
@ -771,7 +871,6 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game
|
|||||||
{
|
{
|
||||||
searchpath_t *search;
|
searchpath_t *search;
|
||||||
int index;
|
int index;
|
||||||
zip_header_t header;
|
|
||||||
zipfile_t *file = NULL;
|
zipfile_t *file = NULL;
|
||||||
byte *compressed_buffer = NULL, *decompressed_buffer = NULL;
|
byte *compressed_buffer = NULL, *decompressed_buffer = NULL;
|
||||||
int zlib_result = 0;
|
int zlib_result = 0;
|
||||||
@ -787,57 +886,51 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game
|
|||||||
|
|
||||||
file = &search->zip->files[index];
|
file = &search->zip->files[index];
|
||||||
|
|
||||||
FS_Seek( search->zip->handle, file->offset, SEEK_SET );
|
FS_EnsureOpenZip( search->zip );
|
||||||
FS_Read( search->zip->handle, (void*)&header, sizeof( header ) );
|
|
||||||
|
if( lseek( search->zip->handle, file->offset, SEEK_SET ) == -1 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*if( read( search->zip->handle, &header, sizeof( header ) ) < 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if( header.signature != ZIP_HEADER_LF )
|
if( header.signature != ZIP_HEADER_LF )
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "Zip_LoadFile: %s signature error\n", file->name );
|
Con_Reportf( S_ERROR "Zip_LoadFile: %s signature error\n", file->name );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if( header.compression_flags == ZIP_COMPRESSION_NO_COMPRESSION )
|
if( file->flags == ZIP_COMPRESSION_NO_COMPRESSION )
|
||||||
{
|
{
|
||||||
if( header.filename_len )
|
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
|
||||||
FS_Seek( search->zip->handle, header.filename_len, SEEK_CUR );
|
|
||||||
|
|
||||||
if( header.extrafield_len )
|
|
||||||
FS_Seek( search->zip->handle, header.extrafield_len, SEEK_CUR );
|
|
||||||
|
|
||||||
decompressed_buffer = Mem_Malloc( search->zip->mempool, file->size + 1 );
|
|
||||||
decompressed_buffer[file->size] = '\0';
|
decompressed_buffer[file->size] = '\0';
|
||||||
|
|
||||||
FS_Read( search->zip->handle, decompressed_buffer, file->size );
|
read( search->zip->handle, decompressed_buffer, file->size );
|
||||||
|
#if 0
|
||||||
CRC32_Init( &test_crc );
|
CRC32_Init( &test_crc );
|
||||||
CRC32_ProcessBuffer( &test_crc, decompressed_buffer, file->size );
|
CRC32_ProcessBuffer( &test_crc, decompressed_buffer, file->size );
|
||||||
|
|
||||||
final_crc = CRC32_Final( test_crc );
|
final_crc = CRC32_Final( test_crc );
|
||||||
|
|
||||||
if( final_crc != header.crc32 )
|
if( final_crc != file->crc32 )
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
|
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
|
||||||
Mem_Free( decompressed_buffer );
|
Mem_Free( decompressed_buffer );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if( sizeptr ) *sizeptr = file->size;
|
if( sizeptr ) *sizeptr = file->size;
|
||||||
|
|
||||||
|
FS_EnsureOpenZip( NULL );
|
||||||
return decompressed_buffer;
|
return decompressed_buffer;
|
||||||
}
|
}
|
||||||
else if( header.compression_flags == ZIP_COMPRESSION_DEFLATED )
|
else if( file->flags == ZIP_COMPRESSION_DEFLATED )
|
||||||
{
|
{
|
||||||
if( header.filename_len )
|
compressed_buffer = Mem_Malloc( fs_mempool, file->compressed_size + 1 );
|
||||||
FS_Seek( search->zip->handle, header.filename_len, SEEK_CUR );
|
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
|
||||||
|
|
||||||
if( header.extrafield_len )
|
|
||||||
FS_Seek( search->zip->handle, header.extrafield_len, SEEK_CUR );
|
|
||||||
|
|
||||||
compressed_buffer = Mem_Malloc( search->zip->mempool, file->compressed_size + 1 );
|
|
||||||
decompressed_buffer = Mem_Malloc( search->zip->mempool, file->size + 1 );
|
|
||||||
decompressed_buffer[file->size] = '\0';
|
decompressed_buffer[file->size] = '\0';
|
||||||
|
|
||||||
FS_Read( search->zip->handle, compressed_buffer, file->compressed_size );
|
read( search->zip->handle, compressed_buffer, file->compressed_size );
|
||||||
|
|
||||||
memset( &decompress_stream, 0, sizeof( decompress_stream ) );
|
memset( &decompress_stream, 0, sizeof( decompress_stream ) );
|
||||||
|
|
||||||
@ -864,21 +957,22 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game
|
|||||||
if( zlib_result == Z_OK || zlib_result == Z_STREAM_END )
|
if( zlib_result == Z_OK || zlib_result == Z_STREAM_END )
|
||||||
{
|
{
|
||||||
Mem_Free( compressed_buffer ); // finaly free compressed buffer
|
Mem_Free( compressed_buffer ); // finaly free compressed buffer
|
||||||
|
#if 0
|
||||||
CRC32_Init( &test_crc );
|
CRC32_Init( &test_crc );
|
||||||
CRC32_ProcessBuffer( &test_crc, decompressed_buffer, file->size );
|
CRC32_ProcessBuffer( &test_crc, decompressed_buffer, file->size );
|
||||||
|
|
||||||
final_crc = CRC32_Final( test_crc );
|
final_crc = CRC32_Final( test_crc );
|
||||||
|
|
||||||
if( final_crc != header.crc32 )
|
if( final_crc != file->crc32 )
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
|
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
|
||||||
Mem_Free( decompressed_buffer );
|
Mem_Free( decompressed_buffer );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if( sizeptr ) *sizeptr = file->size;
|
if( sizeptr ) *sizeptr = file->size;
|
||||||
|
|
||||||
|
FS_EnsureOpenZip( NULL );
|
||||||
return decompressed_buffer;
|
return decompressed_buffer;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -896,6 +990,7 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FS_EnsureOpenZip( NULL );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -998,7 +1093,7 @@ static qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loade
|
|||||||
{
|
{
|
||||||
if( !Q_stricmp( COM_FileExtension( pak->files[i].name ), "wad" ))
|
if( !Q_stricmp( COM_FileExtension( pak->files[i].name ), "wad" ))
|
||||||
{
|
{
|
||||||
Q_sprintf( fullpath, "%s/%s", pakfile, pak->files[i].name );
|
Q_snprintf( fullpath, MAX_STRING, "%s/%s", pakfile, pak->files[i].name );
|
||||||
FS_AddWad_Fullpath( fullpath, NULL, flags );
|
FS_AddWad_Fullpath( fullpath, NULL, flags );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1036,6 +1131,9 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int
|
|||||||
|
|
||||||
if( zip )
|
if( zip )
|
||||||
{
|
{
|
||||||
|
string fullpath;
|
||||||
|
int i;
|
||||||
|
|
||||||
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ) );
|
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ) );
|
||||||
search->zip = zip;
|
search->zip = zip;
|
||||||
search->next = fs_searchpaths;
|
search->next = fs_searchpaths;
|
||||||
@ -1043,6 +1141,16 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int
|
|||||||
fs_searchpaths = search;
|
fs_searchpaths = search;
|
||||||
|
|
||||||
Con_Reportf( "Adding zipfile: %s (%i files)\n", zipfile, zip->numfiles );
|
Con_Reportf( "Adding zipfile: %s (%i files)\n", zipfile, zip->numfiles );
|
||||||
|
|
||||||
|
// time to add in search list all the wads that contains in current pakfile (if do)
|
||||||
|
for( i = 0; i < zip->numfiles; i++ )
|
||||||
|
{
|
||||||
|
if( !Q_stricmp( COM_FileExtension( zip->files[i].name ), "wad" ))
|
||||||
|
{
|
||||||
|
Q_snprintf( fullpath, MAX_STRING, "%s/%s", zipfile, zip->files[i].name );
|
||||||
|
FS_AddWad_Fullpath( fullpath, NULL, flags );
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1070,7 +1178,6 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
|||||||
|
|
||||||
if( !FBitSet( flags, FS_NOWRITE_PATH ))
|
if( !FBitSet( flags, FS_NOWRITE_PATH ))
|
||||||
Q_strncpy( fs_writedir, dir, sizeof( fs_writedir ));
|
Q_strncpy( fs_writedir, dir, sizeof( fs_writedir ));
|
||||||
|
|
||||||
stringlistinit( &list );
|
stringlistinit( &list );
|
||||||
listdirectory( &list, dir, false );
|
listdirectory( &list, dir, false );
|
||||||
stringlistsort( &list );
|
stringlistsort( &list );
|
||||||
@ -1085,6 +1192,16 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add any Zip package in the directory
|
||||||
|
for( i = 0; i < list.numstrings; i++ )
|
||||||
|
{
|
||||||
|
if( !Q_stricmp( COM_FileExtension( list.strings[i] ), "zip" ) || !Q_stricmp( COM_FileExtension( list.strings[i] ), "pk3" ))
|
||||||
|
{
|
||||||
|
Q_sprintf( fullpath, "%s%s", dir, list.strings[i] );
|
||||||
|
FS_AddZip_Fullpath( fullpath, NULL, flags );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FS_AllowDirectPaths( true );
|
FS_AllowDirectPaths( true );
|
||||||
|
|
||||||
// add any WAD package in the directory
|
// add any WAD package in the directory
|
||||||
@ -1097,16 +1214,6 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add any Zip package in the directory
|
|
||||||
for( i = 0; i < list.numstrings; i++ )
|
|
||||||
{
|
|
||||||
if( !Q_stricmp( COM_FileExtension( list.strings[i] ), "zip" ) || !Q_stricmp( COM_FileExtension( list.strings[i] ), "pk3" ))
|
|
||||||
{
|
|
||||||
Q_sprintf( fullpath, "%s%s", dir, list.strings[i] );
|
|
||||||
FS_AddZip_Fullpath( fullpath, NULL, flags );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stringlistfreecontents( &list );
|
stringlistfreecontents( &list );
|
||||||
FS_AllowDirectPaths( false );
|
FS_AllowDirectPaths( false );
|
||||||
|
|
||||||
@ -1197,6 +1304,8 @@ void FS_ClearSearchPath( void )
|
|||||||
{
|
{
|
||||||
if( search->pack->files )
|
if( search->pack->files )
|
||||||
Mem_Free( search->pack->files );
|
Mem_Free( search->pack->files );
|
||||||
|
if( search->pack->handle >= 0 )
|
||||||
|
close( search->pack->handle );
|
||||||
Mem_Free( search->pack );
|
Mem_Free( search->pack );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2118,7 +2227,11 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode )
|
|||||||
const char *ffilepath = FS_FixFileCase( filepath );
|
const char *ffilepath = FS_FixFileCase( filepath );
|
||||||
if( ffilepath != filepath )
|
if( ffilepath != filepath )
|
||||||
file->handle = open( ffilepath, mod|opt, 0666 );
|
file->handle = open( ffilepath, mod|opt, 0666 );
|
||||||
|
if( file->handle >= 0 )
|
||||||
|
FS_BackupFileName( file, ffilepath, mod|opt );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
FS_BackupFileName( file, filepath, mod|opt );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( file->handle < 0 )
|
if( file->handle < 0 )
|
||||||
@ -2127,14 +2240,62 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
file->real_length = lseek( file->handle, 0, SEEK_END );
|
file->real_length = lseek( file->handle, 0, SEEK_END );
|
||||||
|
|
||||||
|
// uncomment do disable write
|
||||||
|
//if( opt & O_CREAT )
|
||||||
|
// return NULL;
|
||||||
|
|
||||||
// For files opened in append mode, we start at the end of the file
|
// For files opened in append mode, we start at the end of the file
|
||||||
if( mod & O_APPEND ) file->position = file->real_length;
|
if( opt & O_APPEND ) file->position = file->real_length;
|
||||||
else lseek( file->handle, 0, SEEK_SET );
|
else lseek( file->handle, 0, SEEK_SET );
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
static int FS_DuplicateHandle( const char *filename, int handle, fs_offset_t pos )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_DUP
|
||||||
|
return dup( handle );
|
||||||
|
#else
|
||||||
|
int newhandle = open( filename, O_RDONLY|O_BINARY );
|
||||||
|
lseek( newhandle, pos, SEEK_SET );
|
||||||
|
return newhandle;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int FS_OpenHandle( const char *syspath, 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 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( lseek( file->handle, offset, SEEK_SET ) == -1 )
|
||||||
|
{
|
||||||
|
Mem_Free( file );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
file->backup_position = offset;
|
||||||
|
file->backup_path = copystring( syspath );
|
||||||
|
file->backup_options = O_RDONLY|O_BINARY;
|
||||||
|
file->handle = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
file->real_length = len;
|
||||||
|
file->offset = offset;
|
||||||
|
file->position = 0;
|
||||||
|
file->ungetc = EOF;
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===========
|
===========
|
||||||
@ -2146,27 +2307,29 @@ Open a packed file using its package file descriptor
|
|||||||
file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind )
|
file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind )
|
||||||
{
|
{
|
||||||
dpackfile_t *pfile;
|
dpackfile_t *pfile;
|
||||||
int dup_handle;
|
|
||||||
file_t *file;
|
|
||||||
|
|
||||||
pfile = &pack->files[pack_ind];
|
pfile = &pack->files[pack_ind];
|
||||||
|
|
||||||
if( lseek( pack->handle, pfile->filepos, SEEK_SET ) == -1 )
|
return FS_OpenHandle( pack->filename, pack->handle, pfile->filepos, pfile->filelen );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===========
|
||||||
|
FS_OpenZipFile
|
||||||
|
|
||||||
|
Open a packed file using its package file descriptor
|
||||||
|
===========
|
||||||
|
*/
|
||||||
|
file_t *FS_OpenZipFile( zip_t *zip, int pack_ind )
|
||||||
|
{
|
||||||
|
zipfile_t *pfile;
|
||||||
|
pfile = &zip->files[pack_ind];
|
||||||
|
|
||||||
|
// compressed files handled in Zip_LoadFile
|
||||||
|
if( pfile->flags != ZIP_COMPRESSION_NO_COMPRESSION )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
dup_handle = dup( pack->handle );
|
return FS_OpenHandle( zip->filename, zip->handle, pfile->offset, pfile->size );
|
||||||
|
|
||||||
if( dup_handle < 0 )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
file = (file_t *)Mem_Calloc( fs_mempool, sizeof( *file ));
|
|
||||||
file->handle = dup_handle;
|
|
||||||
file->real_length = pfile->filelen;
|
|
||||||
file->offset = pfile->filepos;
|
|
||||||
file->position = 0;
|
|
||||||
file->ungetc = EOF;
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2431,6 +2594,8 @@ file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedi
|
|||||||
return FS_OpenPackedFile( search->pack, pack_ind );
|
return FS_OpenPackedFile( search->pack, pack_ind );
|
||||||
else if( search->wad )
|
else if( search->wad )
|
||||||
return NULL; // let W_LoadFile get lump correctly
|
return NULL; // let W_LoadFile get lump correctly
|
||||||
|
else if( search->zip )
|
||||||
|
return FS_OpenZipFile( search->zip, pack_ind );
|
||||||
else if( pack_ind < 0 )
|
else if( pack_ind < 0 )
|
||||||
{
|
{
|
||||||
char path [MAX_SYSPATH];
|
char path [MAX_SYSPATH];
|
||||||
@ -2495,6 +2660,9 @@ int FS_Close( file_t *file )
|
|||||||
{
|
{
|
||||||
if( !file ) return 0;
|
if( !file ) return 0;
|
||||||
|
|
||||||
|
FS_BackupFileName( file, NULL, 0 );
|
||||||
|
|
||||||
|
if( file->handle >= 0 )
|
||||||
if( close( file->handle ))
|
if( close( file->handle ))
|
||||||
return EOF;
|
return EOF;
|
||||||
|
|
||||||
@ -2575,6 +2743,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
|
|||||||
|
|
||||||
// NOTE: at this point, the read buffer is always empty
|
// NOTE: at this point, the read buffer is always empty
|
||||||
|
|
||||||
|
FS_EnsureOpenFile( file );
|
||||||
// we must take care to not read after the end of the file
|
// we must take care to not read after the end of the file
|
||||||
count = file->real_length - file->position;
|
count = file->real_length - file->position;
|
||||||
|
|
||||||
@ -2784,6 +2953,7 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FS_EnsureOpenFile( file );
|
||||||
// Purge cached data
|
// Purge cached data
|
||||||
FS_Purge( file );
|
FS_Purge( file );
|
||||||
|
|
||||||
@ -2853,6 +3023,7 @@ byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamediro
|
|||||||
if( file )
|
if( file )
|
||||||
{
|
{
|
||||||
filesize = file->real_length;
|
filesize = file->real_length;
|
||||||
|
|
||||||
buf = (byte *)Mem_Malloc( fs_mempool, filesize + 1 );
|
buf = (byte *)Mem_Malloc( fs_mempool, filesize + 1 );
|
||||||
buf[filesize] = '\0';
|
buf[filesize] = '\0';
|
||||||
FS_Read( file, buf, filesize );
|
FS_Read( file, buf, filesize );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user