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
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#elif XASH_DOS4GW
|
||||
#include <direct.h>
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
@ -61,6 +64,8 @@ GNU General Public License for more details.
|
||||
#define ZIP_LOAD_NO_FILES 5
|
||||
#define ZIP_LOAD_CORRUPTED 6
|
||||
|
||||
#define XASH_REDUCE_FD
|
||||
|
||||
typedef struct stringlist_s
|
||||
{
|
||||
// maxstrings changes as needed, causing reallocation of strings[] array
|
||||
@ -86,6 +91,11 @@ struct file_s
|
||||
// contents buffer
|
||||
fs_offset_t buff_ind, buff_len; // buffer current index and length
|
||||
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
|
||||
@ -114,13 +124,13 @@ typedef struct zipfile_s
|
||||
fs_offset_t offset; // offset of local file header
|
||||
fs_offset_t size; //original file size
|
||||
fs_offset_t compressed_size; // compressed file size
|
||||
unsigned short flags;
|
||||
} zipfile_t;
|
||||
|
||||
typedef struct zip_s
|
||||
{
|
||||
string filename;
|
||||
byte *mempool;
|
||||
file_t *handle;
|
||||
int handle;
|
||||
int numfiles;
|
||||
time_t filetime;
|
||||
zipfile_t *files;
|
||||
@ -136,18 +146,82 @@ typedef struct searchpath_s
|
||||
struct searchpath_s *next;
|
||||
} searchpath_t;
|
||||
|
||||
byte *fs_mempool;
|
||||
searchpath_t *fs_searchpaths = NULL; // chain
|
||||
searchpath_t fs_directpath; // static direct path
|
||||
char fs_basedir[MAX_SYSPATH]; // base game directory
|
||||
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 byte *fs_mempool;
|
||||
static searchpath_t *fs_searchpaths = NULL; // chain
|
||||
static searchpath_t fs_directpath; // static direct path
|
||||
static char fs_basedir[MAX_SYSPATH]; // base game directory
|
||||
static char fs_gamedir[MAX_SYSPATH]; // game current directory
|
||||
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
|
||||
qboolean fs_caseinsensitive = true; // try to search missing files
|
||||
static qboolean fs_caseinsensitive = true; // try to search missing files
|
||||
#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 searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly );
|
||||
@ -281,11 +355,9 @@ static void listdirectory( stringlist_t *list, const char *path, qboolean lowerc
|
||||
closedir( dir );
|
||||
#endif
|
||||
|
||||
// seems not needed anymore
|
||||
#if 0
|
||||
// convert names to lowercase because windows doesn't care, but pattern matching code often does
|
||||
if( lowercase )
|
||||
listlowercase( list );
|
||||
#if XASH_DOS4GW
|
||||
// convert names to lowercase because 8.3 always in CAPS
|
||||
listlowercase( list );
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -296,6 +368,7 @@ OTHER PRIVATE FUNCTIONS
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
FS_FixFileCase
|
||||
@ -305,7 +378,36 @@ emulate WIN32 FS behaviour when opening local file
|
||||
*/
|
||||
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;
|
||||
char path2[PATH_MAX], *fname;
|
||||
|
||||
@ -567,52 +669,41 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error )
|
||||
for( i = 0; i < numpackfiles; i++ )
|
||||
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;
|
||||
Mem_Free( info );
|
||||
|
||||
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 )
|
||||
{
|
||||
int numpackfiles = 0, i;
|
||||
zip_cdf_header_t header_cdf;
|
||||
zip_header_eocd_t header_eocd;
|
||||
uint signature;
|
||||
fs_offset_t filepos = 0;
|
||||
fs_offset_t filepos = 0, length;
|
||||
zipfile_t *info = NULL;
|
||||
char filename_buffer[MAX_SYSPATH];
|
||||
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( !zip->handle )
|
||||
if( zip->handle < 0 )
|
||||
{
|
||||
const char *fzipfile = FS_FixFileCase( zipfile );
|
||||
if( fzipfile != zipfile )
|
||||
zip->handle = FS_Open( fzipfile, "rb", true );
|
||||
zip->handle = open( fzipfile, O_RDONLY|O_BINARY );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( !zip->handle )
|
||||
if( zip->handle < 0 )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
@ -634,7 +727,9 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
||||
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 )
|
||||
{
|
||||
@ -659,13 +754,13 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
||||
}
|
||||
|
||||
// Find oecd
|
||||
FS_Seek( zip->handle, 0, SEEK_SET );
|
||||
filepos = zip->handle->real_length;
|
||||
lseek( zip->handle, 0, SEEK_SET );
|
||||
filepos = length;
|
||||
|
||||
while ( filepos > 0 )
|
||||
{
|
||||
FS_Seek( zip->handle, filepos, SEEK_SET );
|
||||
FS_Read( zip->handle, (void *)&signature, sizeof( signature ) );
|
||||
lseek( zip->handle, filepos, SEEK_SET );
|
||||
read( zip->handle, &signature, sizeof( signature ) );
|
||||
|
||||
if( signature == ZIP_HEADER_EOCD )
|
||||
break;
|
||||
@ -675,7 +770,7 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
||||
|
||||
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 )
|
||||
*error = ZIP_LOAD_BAD_HEADER;
|
||||
@ -684,19 +779,17 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
||||
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
|
||||
|
||||
FS_Seek( zip->handle, header_eocd.central_directory_offset, SEEK_SET );
|
||||
lseek( zip->handle, header_eocd.central_directory_offset, SEEK_SET );
|
||||
|
||||
// Calc count of files in archive
|
||||
|
||||
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++ )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
@ -710,16 +803,10 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
||||
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 );
|
||||
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 );
|
||||
|
||||
info[numpackfiles].size = header_cdf.uncompressed_size;
|
||||
@ -728,29 +815,40 @@ static zip_t *FS_LoadZip( const char *zipfile, int *error )
|
||||
numpackfiles++;
|
||||
}
|
||||
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 )
|
||||
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 )
|
||||
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 ) );
|
||||
zip->mempool = Mem_AllocPool( zipfile );
|
||||
zip->filetime = FS_SysFileTime( zipfile );
|
||||
zip->numfiles = 0;
|
||||
zip->files = (zipfile_t *)Mem_Calloc( fs_mempool, sizeof( zipfile_t ) * numpackfiles );
|
||||
zip->numfiles = numpackfiles;
|
||||
zip->files = info;
|
||||
|
||||
for( i = 0; i < numpackfiles; i++ )
|
||||
FS_AddFileToZip( info[i].name, zip, info[i].offset, info[i].size, info[i].compressed_size );
|
||||
#ifdef XASH_REDUCE_FD
|
||||
// will reopen when needed
|
||||
close(zip->handle);
|
||||
zip->handle = -1;
|
||||
#endif
|
||||
|
||||
if( error )
|
||||
*error = ZIP_LOAD_OK;
|
||||
|
||||
Mem_Free( info );
|
||||
|
||||
return zip;
|
||||
}
|
||||
|
||||
@ -759,10 +857,12 @@ void Zip_Close( zip_t *zip )
|
||||
if( !zip )
|
||||
return;
|
||||
|
||||
Mem_FreePool( &zip->mempool );
|
||||
Mem_Free( zip->files );
|
||||
|
||||
if( zip->handle != NULL )
|
||||
FS_Close( zip->handle );
|
||||
FS_EnsureOpenZip( NULL );
|
||||
|
||||
if( zip->handle >= 0 )
|
||||
close( zip->handle );
|
||||
|
||||
Mem_Free( zip );
|
||||
}
|
||||
@ -771,7 +871,6 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game
|
||||
{
|
||||
searchpath_t *search;
|
||||
int index;
|
||||
zip_header_t header;
|
||||
zipfile_t *file = NULL;
|
||||
byte *compressed_buffer = NULL, *decompressed_buffer = NULL;
|
||||
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];
|
||||
|
||||
FS_Seek( search->zip->handle, file->offset, SEEK_SET );
|
||||
FS_Read( search->zip->handle, (void*)&header, sizeof( header ) );
|
||||
FS_EnsureOpenZip( search->zip );
|
||||
|
||||
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 )
|
||||
{
|
||||
Con_Reportf( S_ERROR "Zip_LoadFile: %s signature error\n", file->name );
|
||||
return NULL;
|
||||
}
|
||||
}*/
|
||||
|
||||
if( header.compression_flags == ZIP_COMPRESSION_NO_COMPRESSION )
|
||||
if( file->flags == ZIP_COMPRESSION_NO_COMPRESSION )
|
||||
{
|
||||
if( header.filename_len )
|
||||
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 = Mem_Malloc( fs_mempool, file->size + 1 );
|
||||
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_ProcessBuffer( &test_crc, decompressed_buffer, file->size );
|
||||
|
||||
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 );
|
||||
Mem_Free( decompressed_buffer );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
if( sizeptr ) *sizeptr = file->size;
|
||||
|
||||
FS_EnsureOpenZip( NULL );
|
||||
return decompressed_buffer;
|
||||
}
|
||||
else if( header.compression_flags == ZIP_COMPRESSION_DEFLATED )
|
||||
else if( file->flags == ZIP_COMPRESSION_DEFLATED )
|
||||
{
|
||||
if( header.filename_len )
|
||||
FS_Seek( search->zip->handle, header.filename_len, SEEK_CUR );
|
||||
|
||||
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 );
|
||||
compressed_buffer = Mem_Malloc( fs_mempool, file->compressed_size + 1 );
|
||||
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
|
||||
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 ) );
|
||||
|
||||
@ -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 )
|
||||
{
|
||||
Mem_Free( compressed_buffer ); // finaly free compressed buffer
|
||||
|
||||
#if 0
|
||||
CRC32_Init( &test_crc );
|
||||
CRC32_ProcessBuffer( &test_crc, decompressed_buffer, file->size );
|
||||
|
||||
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 );
|
||||
Mem_Free( decompressed_buffer );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
if( sizeptr ) *sizeptr = file->size;
|
||||
|
||||
FS_EnsureOpenZip( NULL );
|
||||
return decompressed_buffer;
|
||||
}
|
||||
else
|
||||
@ -896,6 +990,7 @@ static byte *Zip_LoadFile( const char *path, fs_offset_t *sizeptr, qboolean game
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FS_EnsureOpenZip( 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" ))
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
@ -1036,6 +1131,9 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int
|
||||
|
||||
if( zip )
|
||||
{
|
||||
string fullpath;
|
||||
int i;
|
||||
|
||||
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ) );
|
||||
search->zip = zip;
|
||||
search->next = fs_searchpaths;
|
||||
@ -1043,6 +1141,16 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int
|
||||
fs_searchpaths = search;
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
@ -1070,7 +1178,6 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
||||
|
||||
if( !FBitSet( flags, FS_NOWRITE_PATH ))
|
||||
Q_strncpy( fs_writedir, dir, sizeof( fs_writedir ));
|
||||
|
||||
stringlistinit( &list );
|
||||
listdirectory( &list, dir, false );
|
||||
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 );
|
||||
|
||||
// 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 );
|
||||
FS_AllowDirectPaths( false );
|
||||
|
||||
@ -1197,6 +1304,8 @@ void FS_ClearSearchPath( void )
|
||||
{
|
||||
if( search->pack->files )
|
||||
Mem_Free( search->pack->files );
|
||||
if( search->pack->handle >= 0 )
|
||||
close( search->pack->handle );
|
||||
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 );
|
||||
if( ffilepath != filepath )
|
||||
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
|
||||
|
||||
if( file->handle < 0 )
|
||||
@ -2127,14 +2240,62 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
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 );
|
||||
|
||||
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 )
|
||||
{
|
||||
dpackfile_t *pfile;
|
||||
int dup_handle;
|
||||
file_t *file;
|
||||
|
||||
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;
|
||||
|
||||
dup_handle = dup( pack->handle );
|
||||
|
||||
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;
|
||||
return FS_OpenHandle( zip->filename, zip->handle, pfile->offset, pfile->size );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2431,6 +2594,8 @@ file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedi
|
||||
return FS_OpenPackedFile( search->pack, pack_ind );
|
||||
else if( search->wad )
|
||||
return NULL; // let W_LoadFile get lump correctly
|
||||
else if( search->zip )
|
||||
return FS_OpenZipFile( search->zip, pack_ind );
|
||||
else if( pack_ind < 0 )
|
||||
{
|
||||
char path [MAX_SYSPATH];
|
||||
@ -2495,8 +2660,11 @@ int FS_Close( file_t *file )
|
||||
{
|
||||
if( !file ) return 0;
|
||||
|
||||
if( close( file->handle ))
|
||||
return EOF;
|
||||
FS_BackupFileName( file, NULL, 0 );
|
||||
|
||||
if( file->handle >= 0 )
|
||||
if( close( file->handle ))
|
||||
return EOF;
|
||||
|
||||
Mem_Free( file );
|
||||
return 0;
|
||||
@ -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
|
||||
|
||||
FS_EnsureOpenFile( file );
|
||||
// we must take care to not read after the end of the file
|
||||
count = file->real_length - file->position;
|
||||
|
||||
@ -2784,6 +2953,7 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence )
|
||||
return 0;
|
||||
}
|
||||
|
||||
FS_EnsureOpenFile( file );
|
||||
// Purge cached data
|
||||
FS_Purge( file );
|
||||
|
||||
@ -2853,6 +3023,7 @@ byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamediro
|
||||
if( file )
|
||||
{
|
||||
filesize = file->real_length;
|
||||
|
||||
buf = (byte *)Mem_Malloc( fs_mempool, filesize + 1 );
|
||||
buf[filesize] = '\0';
|
||||
FS_Read( file, buf, filesize );
|
||||
|
Loading…
x
Reference in New Issue
Block a user