filesystem: make generic archive loading functions (with the exception of WADs). Do not alter global searchpath from archives.

This commit is contained in:
Alibek Omarov 2023-06-08 22:14:12 +03:00
parent 653eb00cc6
commit 0d6137ee40
7 changed files with 184 additions and 227 deletions

View File

@ -470,11 +470,19 @@ public:
bool AddPackFile( const char *path, const char *id ) override
{
char dir[MAX_VA_STRING], fullpath[MAX_VA_STRING];
const char *ext = COM_FileExtension( path );
Q_snprintf( fullpath, sizeof( fullpath ), "%s/%s", IdToDir( dir, sizeof( dir ), id ), path );
CopyAndFixSlashes( fullpath, path, sizeof( fullpath ));
IdToDir( dir, sizeof( dir ), id );
Q_snprintf( fullpath, sizeof( fullpath ), "%s/%s", dir, path );
COM_FixSlashes( fullpath );
return !!FS_AddPak_Fullpath( fullpath, nullptr, FS_CUSTOM_PATH );
for( const fs_archive_t *archive = g_archives; archive->ext; archive++ )
{
if( archive->type == SEARCHPATH_PAK && !Q_stricmp( ext, archive->ext ))
return FS_AddArchive_Fullpath( archive, fullpath, FS_CUSTOM_PATH );
}
return false;
}
FileHandle_t OpenFromCacheForRead( const char *path , const char *mode, const char *id ) override

View File

@ -480,29 +480,12 @@ void FS_InitDirectorySearchpath( searchpath_t *search, const char *path, int fla
FS_PopulateDirEntries( search->dir, path );
}
searchpath_t *FS_AddDir_Fullpath( const char *path, qboolean *already_loaded, int flags )
searchpath_t *FS_AddDir_Fullpath( const char *path, int flags )
{
searchpath_t *search;
for( search = fs_searchpaths; search; search = search->next )
{
if( search->type == SEARCHPATH_PLAIN && !Q_stricmp( search->filename, path ))
{
if( already_loaded )
*already_loaded = true;
return search;
}
}
if( already_loaded )
*already_loaded = false;
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ));
FS_InitDirectorySearchpath( search, path, flags );
search->next = fs_searchpaths;
fs_searchpaths = search;
Con_Printf( "Adding directory: %s\n", path );
return search;

View File

@ -56,6 +56,23 @@ searchpath_t *fs_writepath;
static char fs_basedir[MAX_SYSPATH]; // base game directory
static char fs_gamedir[MAX_SYSPATH]; // game current directory
// add archives in specific order PAK -> PK3 -> WAD
// so raw WADs takes precedence over WADs included into PAKs and PK3s
const fs_archive_t g_archives[] =
{
{ "pak", SEARCHPATH_PAK, FS_AddPak_Fullpath, true },
{ "pk3", SEARCHPATH_ZIP, FS_AddZip_Fullpath, true },
{ "wad", SEARCHPATH_WAD, FS_AddWad_Fullpath, false },
{ NULL }, // end marker
};
// special fs_archive_t for plain directories
static const fs_archive_t g_directory_archive =
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
// static const fs_archive_t g_android_archive =
// { NULL, SEARCHPATH_ANDROID, FS_AddAndroid_Fullpath, false, false };
#ifdef XASH_REDUCE_FD
static file_t *fs_last_readfile;
static zip_t *fs_last_zip;
@ -278,23 +295,69 @@ void FS_CreatePath( char *path )
}
}
searchpath_t *FS_AddArchive_Fullpath( const fs_archive_t *archive, const char *file, int flags )
{
searchpath_t *search;
for( search = fs_searchpaths; search; search = search->next )
{
if( search->type == archive->type && !Q_stricmp( search->filename, file ))
return search; // already loaded
}
search = archive->pfnAddArchive_Fullpath( file, flags );
if( !search )
return NULL;
search->next = fs_searchpaths;
fs_searchpaths = search;
// time to add in search list all the wads from this archive
if( archive->load_wads )
{
stringlist_t list;
int i;
stringlistinit( &list );
search->pfnSearch( search, &list, "*.wad", true );
stringlistsort( &list ); // keep always sorted
for( i = 0; i < list.numstrings; i++ )
{
searchpath_t *wad;
char fullpath[MAX_SYSPATH];
Q_snprintf( fullpath, sizeof( fullpath ), "%s/%s", file, list.strings[i] );
if(( wad = FS_AddWad_Fullpath( fullpath, flags )))
{
wad->next = fs_searchpaths;
fs_searchpaths = wad;
}
}
stringlistfreecontents( &list );
}
return search;
}
/*
================
FS_AddArchive_Fullpath
================
*/
static searchpath_t *FS_AddArchive_Fullpath( const char *file, qboolean *already_loaded, int flags )
static searchpath_t *FS_AddExtras_Fullpath( const char *file, int flags )
{
const fs_archive_t *archive;
const char *ext = COM_FileExtension( file );
if( !Q_stricmp( ext, "pk3" ))
return FS_AddZip_Fullpath( file, already_loaded, flags );
else if ( !Q_stricmp( ext, "pak" ))
return FS_AddPak_Fullpath( file, already_loaded, flags );
for( archive = g_archives; archive->ext; archive++ )
{
if( !Q_stricmp( ext, archive->ext ))
return FS_AddArchive_Fullpath( archive, file, flags );
}
// skip wads, this function only meant to be used for extras
return NULL;
}
@ -308,6 +371,7 @@ then loads and adds pak1.pak pak2.pak ...
*/
void FS_AddGameDirectory( const char *dir, uint flags )
{
const fs_archive_t *archive;
stringlist_t list;
searchpath_t *search;
char fullpath[MAX_SYSPATH];
@ -317,48 +381,30 @@ void FS_AddGameDirectory( const char *dir, uint flags )
listdirectory( &list, dir );
stringlistsort( &list );
// add archives in specific order PAK -> PK3 -> WAD
// so raw WADs takes precedence over WADs included into PAKs and PK3s
for( i = 0; i < list.numstrings; i++ )
for( archive = g_archives; archive->ext; archive++ )
{
const char *ext = COM_FileExtension( list.strings[i] );
if( !Q_stricmp( ext, "pak" ))
{
Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", dir, list.strings[i] );
FS_AddPak_Fullpath( fullpath, NULL, flags );
}
}
for( i = 0; i < list.numstrings; i++ )
{
const char *ext = COM_FileExtension( list.strings[i] );
if( !Q_stricmp( ext, "pk3" ))
{
Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", dir, list.strings[i] );
FS_AddZip_Fullpath( fullpath, NULL, flags );
}
}
for( i = 0; i < list.numstrings; i++ )
{
const char *ext = COM_FileExtension( list.strings[i] );
if( !Q_stricmp( ext, "wad" ))
{
if( archive->type == SEARCHPATH_WAD ) // HACKHACK: wads need direct paths but only in this function
FS_AllowDirectPaths( true );
for( i = 0; i < list.numstrings; i++ )
{
const char *ext = COM_FileExtension( list.strings[i] );
if( Q_stricmp( ext, archive->ext ))
continue;
Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", dir, list.strings[i] );
FS_AddWad_Fullpath( fullpath, NULL, flags );
FS_AllowDirectPaths( false );
FS_AddArchive_Fullpath( archive, fullpath, flags );
}
FS_AllowDirectPaths( false );
}
stringlistfreecontents( &list );
// add the directory to the search path
// (unpacked files have the priority over packed files)
search = FS_AddDir_Fullpath( dir, NULL, flags );
search = FS_AddArchive_Fullpath( &g_directory_archive, dir, flags );
if( !FBitSet( flags, FS_NOWRITE_PATH ))
fs_writepath = search;
}
@ -1108,25 +1154,13 @@ void FS_Rescan( void )
FS_ClearSearchPath();
#if XASH_IOS
{
char buf[MAX_VA_STRING];
Q_snprintf( buf, sizeof( buf ), "%sextras.pak", SDL_GetBasePath() );
FS_AddPak_Fullpath( buf, NULL, extrasFlags );
Q_snprintf( buf, sizeof( buf ), "%sextras_%s.pak", SDL_GetBasePath(), GI->gamefolder );
FS_AddPak_Fullpath( buf, NULL, extrasFlags );
}
#else
str = getenv( "XASH3D_EXTRAS_PAK1" );
if( COM_CheckString( str ))
FS_AddArchive_Fullpath( str, NULL, extrasFlags );
FS_AddExtras_Fullpath( str, extrasFlags );
str = getenv( "XASH3D_EXTRAS_PAK2" );
if( COM_CheckString( str ))
FS_AddArchive_Fullpath( str, NULL, extrasFlags );
#endif
FS_AddExtras_Fullpath( str, extrasFlags );
if( Q_stricmp( GI->basedir, GI->gamefolder ))
FS_AddGameHierarchy( GI->basedir, 0 );

View File

@ -93,6 +93,16 @@ typedef struct searchpath_s
byte *(*pfnLoadFile)( struct searchpath_s *search, const char *path, int pack_ind, fs_offset_t *filesize );
} searchpath_t;
typedef searchpath_t *(*FS_ADDARCHIVE_FULLPATH)( const char *path, int flags );
typedef struct fs_archive_s
{
const char *ext;
int type;
FS_ADDARCHIVE_FULLPATH pfnAddArchive_Fullpath;
qboolean load_wads; // load wads from this archive
} fs_archive_t;
extern fs_globals_t FI;
extern searchpath_t *fs_searchpaths;
extern searchpath_t *fs_writepath;
@ -102,6 +112,7 @@ extern qboolean fs_ext_path;
extern char fs_rodir[MAX_SYSPATH];
extern char fs_rootdir[MAX_SYSPATH];
extern fs_api_t g_api;
extern const fs_archive_t g_archives[];
#define GI FI.GameInfo
@ -123,6 +134,7 @@ extern fs_api_t g_api;
//
qboolean FS_InitStdio( qboolean caseinsensitive, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir );
void FS_ShutdownStdio( void );
searchpath_t *FS_AddArchive_Fullpath( const fs_archive_t *archive, const char *file, int flags );
// search path utils
void FS_Rescan( void );
@ -193,22 +205,22 @@ searchpath_t *FS_FindFile( const char *name, int *index, char *fixedname, size_t
//
// pak.c
//
searchpath_t *FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loaded, int flags );
searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags );
//
// wad.c
//
searchpath_t *FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, int flags );
searchpath_t *FS_AddWad_Fullpath( const char *wadfile, int flags );
//
// zip.c
//
searchpath_t *FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int flags );
searchpath_t *FS_AddZip_Fullpath( const char *zipfile, int flags );
//
// dir.c
//
searchpath_t *FS_AddDir_Fullpath( const char *path, qboolean *already_loaded, int flags );
searchpath_t *FS_AddDir_Fullpath( const char *path, int flags );
qboolean FS_FixFileCase( dir_t *dir, const char *path, char *dst, const size_t len, qboolean createpath );
void FS_InitDirectorySearchpath( searchpath_t *search, const char *path, int flags );

View File

@ -330,66 +330,35 @@ If keep_plain_dirs is set, the pack will be added AFTER the first sequence of
plain directories.
================
*/
searchpath_t *FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loaded, int flags )
searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags )
{
searchpath_t *search;
pack_t *pak = NULL;
const char *ext = COM_FileExtension( pakfile );
int i, errorcode = PAK_LOAD_COULDNT_OPEN;
searchpath_t *search;
pack_t *pak;
int i, errorcode = PAK_LOAD_COULDNT_OPEN;
for( search = fs_searchpaths; search; search = search->next )
{
if( search->type == SEARCHPATH_PAK && !Q_stricmp( search->filename, pakfile ))
{
if( already_loaded ) *already_loaded = true;
return search; // already loaded
}
}
pak = FS_LoadPackPAK( pakfile, &errorcode );
if( already_loaded )
*already_loaded = false;
if( !Q_stricmp( ext, "pak" ))
pak = FS_LoadPackPAK( pakfile, &errorcode );
if( pak )
{
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ));
Q_strncpy( search->filename, pakfile, sizeof( search->filename ));
search->pack = pak;
search->type = SEARCHPATH_PAK;
search->next = fs_searchpaths;
search->flags = flags;
search->pfnPrintInfo = FS_PrintInfo_PAK;
search->pfnClose = FS_Close_PAK;
search->pfnOpenFile = FS_OpenFile_PAK;
search->pfnFileTime = FS_FileTime_PAK;
search->pfnFindFile = FS_FindFile_PAK;
search->pfnSearch = FS_Search_PAK;
fs_searchpaths = search;
Con_Reportf( "Adding pakfile: %s (%i files)\n", pakfile, pak->numfiles );
// time to add in search list all the wads that contains in current pakfile (if do)
for( i = 0; i < pak->numfiles; i++ )
{
if( !Q_stricmp( COM_FileExtension( pak->files[i].name ), "wad" ))
{
char fullpath[MAX_SYSPATH];
Q_snprintf( fullpath, sizeof( fullpath ), "%s/%s", pakfile, pak->files[i].name );
FS_AddWad_Fullpath( fullpath, NULL, flags );
}
}
return search;
}
else
if( !pak )
{
if( errorcode != PAK_LOAD_NO_FILES )
Con_Reportf( S_ERROR "FS_AddPak_Fullpath: unable to load pak \"%s\"\n", pakfile );
return NULL;
}
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ));
Q_strncpy( search->filename, pakfile, sizeof( search->filename ));
search->pack = pak;
search->type = SEARCHPATH_PAK;
search->flags = flags;
search->pfnPrintInfo = FS_PrintInfo_PAK;
search->pfnClose = FS_Close_PAK;
search->pfnOpenFile = FS_OpenFile_PAK;
search->pfnFileTime = FS_FileTime_PAK;
search->pfnFindFile = FS_FindFile_PAK;
search->pfnSearch = FS_Search_PAK;
Con_Reportf( "Adding pakfile: %s (%i files)\n", pakfile, pak->numfiles );
return search;
}

View File

@ -635,52 +635,35 @@ static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, f
FS_AddWad_Fullpath
====================
*/
searchpath_t *FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, int flags )
searchpath_t *FS_AddWad_Fullpath( const char *wadfile, int flags )
{
searchpath_t *search;
wfile_t *wad = NULL;
const char *ext = COM_FileExtension( wadfile );
int errorcode = WAD_LOAD_COULDNT_OPEN;
searchpath_t *search;
wfile_t *wad;
int errorcode = WAD_LOAD_COULDNT_OPEN;
for( search = fs_searchpaths; search; search = search->next )
wad = W_Open( wadfile, &errorcode );
if( !wad )
{
if( search->type == SEARCHPATH_WAD && !Q_stricmp( search->filename, wadfile ))
{
if( already_loaded ) *already_loaded = true;
return search; // already loaded
}
if( errorcode != WAD_LOAD_NO_FILES )
Con_Reportf( S_ERROR "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile );
return NULL;
}
if( already_loaded )
*already_loaded = false;
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ));
Q_strncpy( search->filename, wadfile, sizeof( search->filename ));
search->wad = wad;
search->type = SEARCHPATH_WAD;
search->flags = flags;
if( !Q_stricmp( ext, "wad" ))
wad = W_Open( wadfile, &errorcode );
search->pfnPrintInfo = FS_PrintInfo_WAD;
search->pfnClose = FS_Close_WAD;
search->pfnOpenFile = FS_OpenFile_WAD;
search->pfnFileTime = FS_FileTime_WAD;
search->pfnFindFile = FS_FindFile_WAD;
search->pfnSearch = FS_Search_WAD;
search->pfnLoadFile = W_ReadLump;
if( wad )
{
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ));
Q_strncpy( search->filename, wadfile, sizeof( search->filename ));
search->wad = wad;
search->type = SEARCHPATH_WAD;
search->next = fs_searchpaths;
search->flags = flags;
search->pfnPrintInfo = FS_PrintInfo_WAD;
search->pfnClose = FS_Close_WAD;
search->pfnOpenFile = FS_OpenFile_WAD;
search->pfnFileTime = FS_FileTime_WAD;
search->pfnFindFile = FS_FindFile_WAD;
search->pfnSearch = FS_Search_WAD;
search->pfnLoadFile = W_ReadLump;
fs_searchpaths = search;
Con_Reportf( "Adding wadfile: %s (%i files)\n", wadfile, wad->numlumps );
return search;
}
if( errorcode != WAD_LOAD_NO_FILES )
Con_Reportf( S_ERROR "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile );
return NULL;
Con_Reportf( "Adding wadfile: %s (%i files)\n", wadfile, wad->numlumps );
return search;
}

View File

@ -664,68 +664,36 @@ FS_AddZip_Fullpath
===========
*/
searchpath_t *FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int flags )
searchpath_t *FS_AddZip_Fullpath( const char *zipfile, int flags )
{
searchpath_t *search;
zip_t *zip = NULL;
const char *ext = COM_FileExtension( zipfile );
int errorcode = ZIP_LOAD_COULDNT_OPEN;
searchpath_t *search;
zip_t *zip;
int i, errorcode = ZIP_LOAD_COULDNT_OPEN;
for( search = fs_searchpaths; search; search = search->next )
{
if( search->type == SEARCHPATH_ZIP && !Q_stricmp( search->filename, zipfile ))
{
if( already_loaded ) *already_loaded = true;
return search; // already loaded
}
}
zip = FS_LoadZip( zipfile, &errorcode );
if( already_loaded ) *already_loaded = false;
if( !Q_stricmp( ext, "pk3" ) )
zip = FS_LoadZip( zipfile, &errorcode );
if( zip )
{
string fullpath;
int i;
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ) );
Q_strncpy( search->filename, zipfile, sizeof( search->filename ));
search->zip = zip;
search->type = SEARCHPATH_ZIP;
search->next = fs_searchpaths;
search->flags = flags;
search->pfnPrintInfo = FS_PrintInfo_ZIP;
search->pfnClose = FS_Close_ZIP;
search->pfnOpenFile = FS_OpenFile_ZIP;
search->pfnFileTime = FS_FileTime_ZIP;
search->pfnFindFile = FS_FindFile_ZIP;
search->pfnSearch = FS_Search_ZIP;
search->pfnLoadFile = FS_LoadZIPFile;
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 search;
}
else
if( !zip )
{
if( errorcode != ZIP_LOAD_NO_FILES )
Con_Reportf( S_ERROR "FS_AddZip_Fullpath: unable to load zip \"%s\"\n", zipfile );
return NULL;
}
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ) );
Q_strncpy( search->filename, zipfile, sizeof( search->filename ));
search->zip = zip;
search->type = SEARCHPATH_ZIP;
search->flags = flags;
search->pfnPrintInfo = FS_PrintInfo_ZIP;
search->pfnClose = FS_Close_ZIP;
search->pfnOpenFile = FS_OpenFile_ZIP;
search->pfnFileTime = FS_FileTime_ZIP;
search->pfnFindFile = FS_FindFile_ZIP;
search->pfnSearch = FS_Search_ZIP;
search->pfnLoadFile = FS_LoadZIPFile;
Con_Reportf( "Adding zipfile: %s (%i files)\n", zipfile, zip->numfiles );
return search;
}