2014-06-01 17:55:23 +00:00
/*
2018-09-02 00:57:29 +00:00
* This file is part of the DXX - Rebirth project < https : //www.dxx-rebirth.com/>.
2014-06-01 17:55:23 +00:00
* It is copyright by its individual contributors , as recorded in the
* project ' s Git history . See COPYING . txt at the top level for license
* terms and a link to the Git history .
*/
2010-08-09 14:04:22 +00:00
/*
*
* Some simple physfs extensions
*
*/
2015-10-18 00:34:00 +00:00
# include <cstdlib>
2010-08-09 14:04:22 +00:00
# if !defined(macintosh) && !defined(_MSC_VER)
# include <sys/param.h>
# endif
2015-09-13 20:23:05 +00:00
# if defined(__APPLE__) && defined(__MACH__)
2010-08-09 14:04:22 +00:00
# include <sys/mount.h>
# include <unistd.h> // for chdir hack
2019-10-23 03:02:16 +00:00
# include <ApplicationServices/ApplicationServices.h>
2010-08-09 14:04:22 +00:00
# endif
2013-03-03 19:41:09 +00:00
# include "args.h"
2010-08-15 06:57:51 +00:00
# include "newdemo.h"
2013-12-26 04:18:28 +00:00
# include "console.h"
# include "strutil.h"
# include "ignorecase.h"
2015-04-19 04:18:49 +00:00
# include "physfs_list.h"
2010-08-09 14:04:22 +00:00
2015-04-26 20:15:51 +00:00
# include "compiler-range_for.h"
2017-02-19 19:33:36 +00:00
# include "compiler-poison.h"
2020-06-10 02:25:32 +00:00
# include "partial_range.h"
2014-09-07 19:26:17 +00:00
2015-12-13 18:00:49 +00:00
namespace dcx {
2015-12-13 18:00:48 +00:00
2020-05-02 21:18:42 +00:00
const std : : array < file_extension_t , 1 > archive_exts { { " dxa " } } ;
2013-11-26 22:19:52 +00:00
2016-01-09 16:38:14 +00:00
char * PHYSFSX_fgets_t : : get ( char * const buf , std : : size_t n , PHYSFS_File * const fp )
2014-05-24 23:02:45 +00:00
{
PHYSFS_sint64 r = PHYSFS_read ( fp , buf , sizeof ( * buf ) , n - 1 ) ;
if ( r < = 0 )
2015-01-12 00:26:02 +00:00
return DXX_POISON_MEMORY ( buf , buf + n , 0xcc ) , nullptr ;
2014-05-24 23:02:45 +00:00
char * p = buf ;
2014-12-20 04:36:10 +00:00
const auto cleanup = [ & ] {
2015-01-12 00:26:02 +00:00
return * p = 0 , DXX_POISON_MEMORY ( p + 1 , buf + n , 0xcc ) , p ;
2014-12-20 04:36:10 +00:00
} ;
2015-10-09 02:46:11 +00:00
char * const e = & buf [ r ] ;
for ( ; ; )
2014-05-24 23:02:45 +00:00
{
if ( p = = e )
{
2014-12-20 04:36:10 +00:00
return cleanup ( ) ;
2014-05-24 23:02:45 +00:00
}
2014-06-28 23:30:46 +00:00
char c = * p ;
2014-05-24 23:02:45 +00:00
if ( c = = 0 )
break ;
if ( c = = ' \n ' )
{
break ;
}
else if ( c = = ' \r ' )
{
2014-06-28 23:30:46 +00:00
* p = 0 ;
2014-07-02 02:29:35 +00:00
if ( + + p ! = e & & * p ! = ' \n ' )
2014-06-28 23:30:46 +00:00
- - p ;
2014-05-24 23:02:45 +00:00
break ;
}
2014-06-28 23:30:46 +00:00
+ + p ;
2014-05-24 23:02:45 +00:00
}
2015-10-09 02:46:11 +00:00
PHYSFS_seek ( fp , PHYSFS_tell ( fp ) + p - e + 1 ) ;
2014-12-20 04:36:10 +00:00
return cleanup ( ) ;
2014-05-24 23:02:45 +00:00
}
2015-08-14 03:02:04 +00:00
int PHYSFSX_checkMatchingExtension ( const char * filename , const partial_range_t < const file_extension_t * > range )
2013-11-26 22:10:57 +00:00
{
const char * ext = strrchr ( filename , ' . ' ) ;
if ( ! ext )
return 0 ;
2013-11-26 22:19:52 +00:00
+ + ext ;
2015-08-14 03:02:04 +00:00
// see if the file is of a type we want
range_for ( auto & k , range )
2013-11-26 22:10:57 +00:00
{
2015-08-14 03:02:04 +00:00
if ( ! d_stricmp ( ext , k ) )
2013-11-26 22:10:57 +00:00
return 1 ;
}
2015-02-14 22:48:28 +00:00
return 0 ;
2013-11-26 22:10:57 +00:00
}
2015-12-13 18:00:48 +00:00
}
2015-12-13 18:00:49 +00:00
namespace dsx {
2015-12-13 18:00:48 +00:00
2010-08-09 14:04:22 +00:00
// Initialise PhysicsFS, set up basic search paths and add arguments from .ini file.
// The .ini file can be in either the user directory or the same directory as the program.
// The user directory is searched first.
2015-01-28 03:42:53 +00:00
bool PHYSFSX_init ( int argc , char * argv [ ] )
2010-08-09 14:04:22 +00:00
{
2012-05-14 10:20:30 +00:00
# if defined(__unix__) || defined(__APPLE__) || defined(__MACH__)
2010-09-25 13:55:22 +00:00
char fullPath [ PATH_MAX + 5 ] ;
2012-05-14 10:20:30 +00:00
# endif
2010-08-09 14:04:22 +00:00
# ifdef macintosh // Mac OS 9
char base_dir [ PATH_MAX ] ;
int bundle = 0 ;
# else
# define base_dir PHYSFS_getBaseDir()
# endif
2018-12-08 23:36:18 +00:00
if ( ! PHYSFS_init ( argv [ 0 ] ) )
Error ( " Failed to init PhysFS: %s " , PHYSFS_getLastError ( ) ) ;
2010-08-09 14:04:22 +00:00
PHYSFS_permitSymbolicLinks ( 1 ) ;
# ifdef macintosh
strcpy ( base_dir , PHYSFS_getBaseDir ( ) ) ;
if ( strstr ( base_dir , " .app:Contents:MacOSClassic " ) ) // the Mac OS 9 program is still in the .app bundle
{
char * p ;
bundle = 1 ;
if ( base_dir [ strlen ( base_dir ) - 1 ] = = ' : ' )
base_dir [ strlen ( base_dir ) - 1 ] = ' \0 ' ;
p = strrchr ( base_dir , ' : ' ) ; * p = ' \0 ' ; // path to 'Contents'
p = strrchr ( base_dir , ' : ' ) ; * p = ' \0 ' ; // path to bundle
p = strrchr ( base_dir , ' : ' ) ; * p = ' \0 ' ; // path to directory containing bundle
}
# endif
# if (defined(__APPLE__) && defined(__MACH__)) // others?
chdir ( base_dir ) ; // make sure relative hogdir paths work
# endif
2015-09-22 02:28:38 +00:00
const char * writedir ;
2010-08-09 14:04:22 +00:00
# if defined(__unix__)
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
# define DESCENT_PATH_NUMBER "1"
# elif defined(DXX_BUILD_DESCENT_II)
# define DESCENT_PATH_NUMBER "2"
# endif
2015-10-18 00:34:00 +00:00
const auto & home_environ_var = " D " DESCENT_PATH_NUMBER " X_REBIRTH_HOME " ;
const char * path = getenv ( home_environ_var ) ;
if ( ! path )
{
path = getenv ( & home_environ_var [ 4 ] ) ;
if ( ! path )
2010-08-09 14:04:22 +00:00
# if !(defined(__APPLE__) && defined(__MACH__))
2013-03-03 01:03:33 +00:00
path = " ~/.d " DESCENT_PATH_NUMBER " x-rebirth/ " ;
2010-08-09 14:04:22 +00:00
# else
2013-03-03 01:03:33 +00:00
path = " ~/Library/Preferences/D " DESCENT_PATH_NUMBER " X Rebirth/ " ;
2010-08-09 14:04:22 +00:00
# endif
2015-10-18 00:34:00 +00:00
}
2010-08-09 14:04:22 +00:00
if ( path [ 0 ] = = ' ~ ' ) // yes, this tilde can be put before non-unix paths.
{
const char * home = PHYSFS_getUserDir ( ) ;
path + + ;
2019-05-06 00:36:16 +00:00
// prepend home to the path
2010-08-09 14:04:22 +00:00
if ( * path = = * PHYSFS_getDirSeparator ( ) )
path + + ;
2019-05-06 00:36:16 +00:00
snprintf ( fullPath , sizeof ( fullPath ) , " %s%s " , home , path ) ;
2010-08-09 14:04:22 +00:00
}
else
2019-05-06 00:36:16 +00:00
{
fullPath [ sizeof ( fullPath ) - 1 ] = 0 ;
strncpy ( fullPath , path , sizeof ( fullPath ) - 1 ) ;
}
2010-08-09 14:04:22 +00:00
PHYSFS_setWriteDir ( fullPath ) ;
2015-09-22 02:28:38 +00:00
if ( ! ( writedir = PHYSFS_getWriteDir ( ) ) )
2010-08-09 14:04:22 +00:00
{ // need to make it
char * p ;
char ancestor [ PATH_MAX + 5 ] ; // the directory which actually exists
char child [ PATH_MAX + 5 ] ; // the directory relative to the above we're trying to make
strcpy ( ancestor , fullPath ) ;
2015-09-22 02:28:38 +00:00
const auto separator = * PHYSFS_getDirSeparator ( ) ;
while ( ! PHYSFS_getWriteDir ( ) & & ( p = strrchr ( ancestor , separator ) ) )
2010-08-09 14:04:22 +00:00
{
if ( p [ 1 ] = = 0 )
{ // separator at the end (intended here, for safety)
* p = 0 ; // kill this separator
2015-09-22 02:28:38 +00:00
if ( ! ( p = strrchr ( ancestor , separator ) ) )
2010-08-09 14:04:22 +00:00
break ; // give up, this is (usually) the root directory
}
p [ 1 ] = 0 ; // go to parent
PHYSFS_setWriteDir ( ancestor ) ;
}
strcpy ( child , fullPath + strlen ( ancestor ) ) ;
2015-09-22 02:28:38 +00:00
if ( separator ! = ' / ' )
for ( p = child ; ( p = strchr ( p , separator ) ) ; p + + )
* p = ' / ' ;
2010-08-09 14:04:22 +00:00
PHYSFS_mkdir ( child ) ;
PHYSFS_setWriteDir ( fullPath ) ;
2015-09-22 02:28:38 +00:00
writedir = PHYSFS_getWriteDir ( ) ;
2010-08-09 14:04:22 +00:00
}
2013-12-28 18:16:19 +00:00
con_printf ( CON_DEBUG , " PHYSFS: append write directory \" %s \" to search path " , writedir ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_mount ( writedir , nullptr , 1 ) ;
2010-08-09 14:04:22 +00:00
# endif
2013-12-28 18:16:19 +00:00
con_printf ( CON_DEBUG , " PHYSFS: temporarily append base directory \" %s \" to search path " , base_dir ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_mount ( base_dir , nullptr , 1 ) ;
2015-01-28 03:42:53 +00:00
if ( ! InitArgs ( argc , argv ) )
return false ;
2020-12-27 22:03:09 +00:00
PHYSFS_unmount ( base_dir ) ;
2010-08-09 14:04:22 +00:00
if ( ! PHYSFS_getWriteDir ( ) )
{
PHYSFS_setWriteDir ( base_dir ) ;
2015-09-22 02:28:38 +00:00
if ( ! ( writedir = PHYSFS_getWriteDir ( ) ) )
2010-08-09 14:04:22 +00:00
Error ( " can't set write dir: %s \n " , PHYSFS_getLastError ( ) ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_mount ( writedir , nullptr , 0 ) ;
2010-08-09 14:04:22 +00:00
}
2011-06-01 07:59:55 +00:00
//tell PHYSFS where hogdir is
2015-12-24 04:01:26 +00:00
if ( ! CGameArg . SysHogDir . empty ( ) )
2013-12-28 18:16:19 +00:00
{
2015-12-24 04:01:26 +00:00
const auto p = CGameArg . SysHogDir . c_str ( ) ;
con_printf ( CON_DEBUG , " PHYSFS: append argument hog directory \" %s \" to search path " , p ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_mount ( p , nullptr , 1 ) ;
2013-12-28 18:16:19 +00:00
}
2018-09-14 02:20:55 +00:00
# if DXX_USE_SHAREPATH
2019-01-20 05:36:56 +00:00
else if ( ! GameArg . SysNoHogDir )
2013-12-28 18:16:19 +00:00
{
2018-09-14 02:20:55 +00:00
con_puts ( CON_DEBUG , " PHYSFS: append sharepath directory \" " DXX_SHAREPATH " \" to search path " ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_mount ( DXX_SHAREPATH , nullptr , 1 ) ;
2013-12-28 18:16:19 +00:00
}
2018-12-30 00:43:58 +00:00
else
{
con_puts ( CON_DEBUG , " PHYSFS: skipping built-in sharepath \" " DXX_SHAREPATH " \" " ) ;
}
# else
else
{
con_puts ( CON_DEBUG , " PHYSFS: no built-in sharepath " ) ;
}
2010-08-09 14:04:22 +00:00
# endif
2021-06-28 03:37:49 +00:00
std : : array < char , PATH_MAX > pathname ;
PHYSFSX_addRelToSearchPath ( " data " , pathname , physfs_search_path : : append ) ; // 'Data' subdirectory
2010-09-25 03:35:23 +00:00
2010-08-09 14:04:22 +00:00
// For Macintosh, add the 'Resources' directory in the .app bundle to the searchpaths
# if defined(__APPLE__) && defined(__MACH__)
{
2018-08-21 19:40:25 +00:00
CFBundleRef mainBundle = CFBundleGetMainBundle ( ) ;
2018-08-24 03:29:03 +00:00
if ( mainBundle )
{
2018-08-21 19:40:25 +00:00
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL ( mainBundle ) ;
2018-08-24 03:29:03 +00:00
if ( resourcesURL )
{
if ( CFURLGetFileSystemRepresentation ( resourcesURL , TRUE , reinterpret_cast < uint8_t * > ( fullPath ) , sizeof ( fullPath ) ) )
{
2018-08-21 19:40:25 +00:00
con_printf ( CON_DEBUG , " PHYSFS: append resources directory \" %s \" to search path " , fullPath ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_mount ( fullPath , nullptr , 1 ) ;
2018-08-21 19:40:25 +00:00
}
CFRelease ( resourcesURL ) ;
}
2010-08-09 14:04:22 +00:00
}
}
# elif defined(macintosh)
if ( bundle )
{
base_dir [ strlen ( base_dir ) ] = ' : ' ; // go back in the bundle
base_dir [ strlen ( base_dir ) ] = ' : ' ; // go back in 'Contents'
strncat ( base_dir , " :Resources: " , PATH_MAX - 1 - strlen ( base_dir ) ) ;
base_dir [ PATH_MAX - 1 ] = ' \0 ' ;
2013-12-28 18:16:19 +00:00
con_printf ( CON_DEBUG , " PHYSFS: append bundle directory \" %s \" to search path " , base_dir ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_mount ( base_dir , nullptr , 1 ) ;
2010-08-09 14:04:22 +00:00
}
# endif
2015-01-28 03:42:53 +00:00
return true ;
2010-08-09 14:04:22 +00:00
}
2021-06-28 03:37:49 +00:00
# if defined(DXX_BUILD_DESCENT_II)
RAIIPHYSFS_ComputedPathMount make_PHYSFSX_ComputedPathMount ( const char * const name1 , const char * const name2 , physfs_search_path position )
{
auto pathname = std : : make_unique < std : : array < char , PATH_MAX > > ( ) ;
2021-07-25 23:00:56 +00:00
if ( PHYSFSX_addRelToSearchPath ( name1 , * pathname . get ( ) , position ) = = PHYSFS_ERR_OK | |
PHYSFSX_addRelToSearchPath ( name2 , * pathname . get ( ) , position ) = = PHYSFS_ERR_OK )
2021-06-28 03:37:49 +00:00
return RAIIPHYSFS_ComputedPathMount ( std : : move ( pathname ) ) ;
return nullptr ;
}
# endif
2015-12-13 18:00:48 +00:00
}
2015-12-13 18:00:49 +00:00
namespace dcx {
2015-12-13 18:00:48 +00:00
2012-03-03 08:03:03 +00:00
// Add a searchpath, but that searchpath is relative to an existing searchpath
// It will add the first one it finds and return 1, if it doesn't find any it returns 0
2021-07-25 23:00:56 +00:00
PHYSFS_ErrorCode PHYSFSX_addRelToSearchPath ( const char * relname , std : : array < char , PATH_MAX > & pathname , physfs_search_path add_to_end )
2011-06-01 07:59:55 +00:00
{
2016-08-06 19:55:25 +00:00
char relname2 [ PATH_MAX ] ;
2011-06-01 07:59:55 +00:00
2012-06-01 10:46:03 +00:00
snprintf ( relname2 , sizeof ( relname2 ) , " %s " , relname ) ;
2012-03-03 08:03:03 +00:00
PHYSFSEXT_locateCorrectCase ( relname2 ) ;
2011-06-01 07:59:55 +00:00
2012-03-03 08:03:03 +00:00
if ( ! PHYSFSX_getRealPath ( relname2 , pathname ) )
2016-12-17 18:39:18 +00:00
{
2021-07-25 23:00:56 +00:00
/* This failure is not reported as an error, because callers
* probe for files that users may not have , and do not need .
*/
2016-12-17 18:39:18 +00:00
con_printf ( CON_DEBUG , " PHYSFS: ignoring map request: no canonical path for relative name \" %s \" " , relname2 ) ;
2021-07-25 23:00:56 +00:00
return PHYSFS_ERR_OK ;
2016-12-17 18:39:18 +00:00
}
2011-06-01 07:59:55 +00:00
2021-06-28 03:37:49 +00:00
auto r = PHYSFS_mount ( pathname . data ( ) , nullptr , static_cast < int > ( add_to_end ) ) ;
const auto action = add_to_end ! = physfs_search_path : : prepend ? " append " : " insert " ;
2016-12-17 18:39:18 +00:00
if ( r )
2021-07-25 23:00:56 +00:00
{
2016-12-17 18:39:18 +00:00
con_printf ( CON_DEBUG , " PHYSFS: %s canonical directory \" %s \" to search path from relative name \" %s \" " , action , pathname . data ( ) , relname ) ;
2021-07-25 23:00:56 +00:00
return PHYSFS_ERR_OK ;
}
2016-12-17 18:39:18 +00:00
else
2021-07-25 23:00:56 +00:00
{
const auto err = PHYSFS_getLastErrorCode ( ) ;
con_printf ( CON_VERBOSE , " PHYSFS: failed to %s canonical directory \" %s \" to search path from relative name \" %s \" : \" %s \" " , action , pathname . data ( ) , relname , PHYSFS_getErrorByCode ( err ) ) ;
return err ;
}
2011-06-01 07:59:55 +00:00
}
2021-07-25 23:00:56 +00:00
void PHYSFSX_removeRelFromSearchPath ( const char * relname )
2011-06-01 07:59:55 +00:00
{
2016-08-06 19:55:25 +00:00
char relname2 [ PATH_MAX ] ;
2011-06-01 07:59:55 +00:00
2012-06-01 10:46:03 +00:00
snprintf ( relname2 , sizeof ( relname2 ) , " %s " , relname ) ;
2012-03-03 08:03:03 +00:00
PHYSFSEXT_locateCorrectCase ( relname2 ) ;
2011-06-01 07:59:55 +00:00
2020-05-02 21:18:42 +00:00
std : : array < char , PATH_MAX > pathname ;
2012-03-03 08:03:03 +00:00
if ( ! PHYSFSX_getRealPath ( relname2 , pathname ) )
2016-12-17 18:39:18 +00:00
{
con_printf ( CON_DEBUG , " PHYSFS: ignoring unmap request: no canonical path for relative name \" %s \" " , relname2 ) ;
2021-07-25 23:00:56 +00:00
return ;
2016-12-17 18:39:18 +00:00
}
2020-12-27 22:03:09 +00:00
auto r = PHYSFS_unmount ( pathname . data ( ) ) ;
2016-12-17 18:39:18 +00:00
if ( r )
con_printf ( CON_DEBUG , " PHYSFS: unmap canonical directory \" %s \" (relative name \" %s \" ) " , pathname . data ( ) , relname ) ;
else
con_printf ( CON_VERBOSE , " PHYSFS: failed to unmap canonical directory \" %s \" (relative name \" %s \" ): \" %s \" " , pathname . data ( ) , relname , PHYSFS_getLastError ( ) ) ;
2011-06-01 07:59:55 +00:00
}
2012-07-22 23:17:54 +00:00
int PHYSFSX_fsize ( const char * hogname )
2011-06-01 07:59:55 +00:00
{
char hogname2 [ PATH_MAX ] ;
2012-06-01 10:46:03 +00:00
snprintf ( hogname2 , sizeof ( hogname2 ) , " %s " , hogname ) ;
2011-06-01 07:59:55 +00:00
PHYSFSEXT_locateCorrectCase ( hogname2 ) ;
2015-01-17 18:31:42 +00:00
if ( RAIIPHYSFS_File fp { PHYSFS_openRead ( hogname2 ) } )
return PHYSFS_fileLength ( fp ) ;
return - 1 ;
2011-06-01 07:59:55 +00:00
}
2010-11-26 11:50:18 +00:00
void PHYSFSX_listSearchPathContent ( )
{
2017-12-05 05:29:55 +00:00
con_puts ( CON_DEBUG , " PHYSFS: Listing contents of Search Path. " ) ;
2015-05-09 17:38:57 +00:00
PHYSFSX_uncounted_list list { PHYSFS_getSearchPath ( ) } ;
2015-04-26 20:15:51 +00:00
range_for ( const auto i , list )
con_printf ( CON_DEBUG , " PHYSFS: [%s] is in the Search Path. " , i ) ;
2015-04-26 20:15:50 +00:00
list . reset ( ) ;
list . reset ( PHYSFS_enumerateFiles ( " " ) ) ;
2015-04-26 20:15:51 +00:00
range_for ( const auto i , list )
con_printf ( CON_DEBUG , " PHYSFS: * We've got [%s]. " , i ) ;
2010-11-26 11:50:18 +00:00
}
2015-12-13 18:00:48 +00:00
}
2015-12-13 18:00:49 +00:00
namespace dsx {
2015-12-13 18:00:48 +00:00
2010-11-26 11:50:18 +00:00
// checks which archives are supported by PhysFS. Return 0 if some essential (HOG) is not supported
int PHYSFSX_checkSupportedArchiveTypes ( )
{
2013-03-03 01:03:33 +00:00
int hog_sup = 0 ;
# ifdef DXX_BUILD_DESCENT_II
int mvl_sup = 0 ;
# endif
2010-11-26 11:50:18 +00:00
2017-12-05 05:29:55 +00:00
con_puts ( CON_DEBUG , " PHYSFS: Checking supported archive types. " ) ;
2015-07-18 21:01:55 +00:00
range_for ( const auto i , make_null_sentinel_array ( PHYSFS_supportedArchiveTypes ( ) ) )
2010-11-26 11:50:18 +00:00
{
2015-07-18 21:01:55 +00:00
const auto iextension = i - > extension ;
con_printf ( CON_DEBUG , " PHYSFS: Supported archive: [%s], which is [%s]. " , iextension , i - > description ) ;
if ( ! d_stricmp ( iextension , " HOG " ) )
2010-11-26 11:50:18 +00:00
hog_sup = 1 ;
2013-03-03 01:03:33 +00:00
# ifdef DXX_BUILD_DESCENT_II
2015-07-18 21:01:55 +00:00
else if ( ! d_stricmp ( iextension , " MVL " ) )
2010-11-26 11:50:18 +00:00
mvl_sup = 1 ;
2013-03-03 01:03:33 +00:00
# endif
2010-11-26 11:50:18 +00:00
}
if ( ! hog_sup )
2017-12-05 05:29:55 +00:00
con_puts ( CON_CRITICAL , " PHYSFS: HOG not supported. The game will not work without! " ) ;
2013-03-03 01:03:33 +00:00
# ifdef DXX_BUILD_DESCENT_II
2010-11-26 11:50:18 +00:00
if ( ! mvl_sup )
2017-12-05 05:29:55 +00:00
con_puts ( CON_URGENT , " PHYSFS: MVL not supported. Won't be able to play movies! " ) ;
2013-03-03 01:03:33 +00:00
# endif
2010-11-26 11:50:18 +00:00
return hog_sup ;
}
2015-12-13 18:00:48 +00:00
}
2015-12-13 18:00:49 +00:00
namespace dcx {
2015-12-13 18:00:48 +00:00
2021-06-28 03:37:49 +00:00
int PHYSFSX_getRealPath ( const char * stdPath , std : : array < char , PATH_MAX > & realPath )
2010-08-09 14:04:22 +00:00
{
2021-06-28 03:37:49 +00:00
DXX_POISON_MEMORY ( realPath . data ( ) , realPath . size ( ) , 0xdd ) ;
2010-08-09 14:04:22 +00:00
const char * realDir = PHYSFS_getRealDir ( stdPath ) ;
if ( ! realDir )
{
realDir = PHYSFS_getWriteDir ( ) ;
if ( ! realDir )
return 0 ;
}
2015-10-11 22:21:00 +00:00
const auto realDirSize = strlen ( realDir ) ;
2021-06-28 03:37:49 +00:00
if ( realDirSize > = realPath . size ( ) )
2015-10-11 22:21:00 +00:00
return 0 ;
auto mountpoint = PHYSFS_getMountPoint ( realDir ) ;
if ( ! mountpoint )
return 0 ;
2021-06-28 03:37:49 +00:00
std : : copy_n ( realDir , realDirSize + 1 , realPath . begin ( ) ) ;
2015-10-11 22:21:00 +00:00
# ifdef _unix__
auto & sep = " / " ;
assert ( ! strcmp ( PHYSFS_getDirSeparator ( ) , sep ) ) ;
# else
const auto sep = PHYSFS_getDirSeparator ( ) ;
# endif
const auto sepSize = strlen ( sep ) ;
auto realPathUsed = realDirSize ;
if ( realDirSize > = sepSize )
2010-08-09 14:04:22 +00:00
{
2021-06-28 03:37:49 +00:00
const auto p = std : : next ( realPath . begin ( ) , realDirSize - sepSize ) ;
2010-08-09 14:04:22 +00:00
if ( strcmp ( p , sep ) ) // no sep at end of realPath
{
2015-10-11 22:21:00 +00:00
realPathUsed + = sepSize ;
std : : copy_n ( sep , sepSize , & realPath [ realDirSize ] ) ;
2010-08-09 14:04:22 +00:00
}
}
2015-10-11 22:21:00 +00:00
if ( * mountpoint = = ' / ' )
+ + mountpoint ;
if ( * stdPath = = ' / ' )
+ + stdPath ;
const auto ml = strlen ( mountpoint ) ;
if ( ! strncmp ( mountpoint , stdPath , ml ) )
stdPath + = ml ;
else
{
/* Virtual path is not under the virtual mount point that
* provides the path .
*/
assert ( false ) ;
}
const auto stdPathLen = strlen ( stdPath ) + 1 ;
2021-06-28 03:37:49 +00:00
if ( realPathUsed + stdPathLen > = realPath . size ( ) )
2015-10-11 22:21:00 +00:00
return 0 ;
# ifdef __unix__
/* Separator is "/" and physfs internal separator is "/". Copy
* through .
*/
std : : copy_n ( stdPath , stdPathLen , & realPath [ realPathUsed ] ) ;
# else
/* Separator might be / on non-unix, but the fallback path works
* regardless of whether separator is " / " .
*/
const auto csep = * sep ;
const auto a = [ csep ] ( char c ) {
return c = = ' / ' ? csep : c ;
} ;
std : : transform ( stdPath , & stdPath [ stdPathLen ] , & realPath [ realPathUsed ] , a ) ;
# endif
2010-08-09 14:04:22 +00:00
return 1 ;
}
2012-07-22 23:17:54 +00:00
int PHYSFSX_rename ( const char * oldpath , const char * newpath )
2010-08-09 14:04:22 +00:00
{
2020-05-02 21:18:42 +00:00
std : : array < char , PATH_MAX > old , n ;
2010-08-09 14:04:22 +00:00
PHYSFSX_getRealPath ( oldpath , old ) ;
2012-11-18 18:21:50 +00:00
PHYSFSX_getRealPath ( newpath , n ) ;
2016-08-06 19:55:25 +00:00
return ( rename ( old . data ( ) , n . data ( ) ) = = 0 ) ;
2010-08-09 14:04:22 +00:00
}
2015-01-23 03:55:05 +00:00
template < typename F >
2015-05-09 17:38:57 +00:00
static inline PHYSFSX_uncounted_list PHYSFSX_findPredicateFiles ( const char * path , F f )
2010-08-09 14:04:22 +00:00
{
2015-05-09 17:38:57 +00:00
PHYSFSX_uncounted_list list { PHYSFS_enumerateFiles ( path ) } ;
2015-01-23 03:55:05 +00:00
if ( ! list )
return nullptr ; // out of memory: not so good
2015-01-23 03:55:05 +00:00
char * * j = list . get ( ) ;
2015-04-26 20:15:51 +00:00
range_for ( const auto i , list )
2010-08-09 14:04:22 +00:00
{
2015-04-26 20:15:51 +00:00
if ( f ( i ) )
* j + + = i ;
2010-08-09 14:04:22 +00:00
else
2015-04-26 20:15:51 +00:00
free ( i ) ;
2010-08-09 14:04:22 +00:00
}
* j = NULL ;
2015-02-05 03:03:49 +00:00
char * * r = reinterpret_cast < char * * > ( realloc ( list . get ( ) , ( j - list . get ( ) + 1 ) * sizeof ( char * ) ) ) ; // save a bit of memory (or a lot?)
2013-10-20 02:34:43 +00:00
if ( r )
2015-01-23 03:55:05 +00:00
{
list . release ( ) ;
list . reset ( r ) ;
}
2010-08-09 14:04:22 +00:00
return list ;
}
2015-01-23 03:55:05 +00:00
// Find files at path that have an extension listed in exts
// The extension list exts must be NULL-terminated, with each ext beginning with a '.'
2016-01-29 04:05:47 +00:00
PHYSFSX_uncounted_list PHYSFSX_findFiles ( const char * path , const partial_range_t < const file_extension_t * > exts )
2015-01-23 03:55:05 +00:00
{
const auto predicate = [ & ] ( const char * i ) {
2016-01-29 04:05:47 +00:00
return PHYSFSX_checkMatchingExtension ( i , exts ) ;
2015-01-23 03:55:05 +00:00
} ;
return PHYSFSX_findPredicateFiles ( path , predicate ) ;
}
2010-08-09 14:04:22 +00:00
// Same function as above but takes a real directory as second argument, only adding files originating from this directory.
// This can be used to further seperate files in search path but it must be made sure realpath is properly formatted.
2016-01-29 04:05:47 +00:00
PHYSFSX_uncounted_list PHYSFSX_findabsoluteFiles ( const char * path , const char * realpath , const partial_range_t < const file_extension_t * > exts )
2010-08-09 14:04:22 +00:00
{
2015-01-23 03:55:05 +00:00
const auto predicate = [ & ] ( const char * i ) {
2016-01-29 04:05:47 +00:00
return PHYSFSX_checkMatchingExtension ( i , exts ) & & ( ! strcmp ( PHYSFS_getRealDir ( i ) , realpath ) ) ;
2015-01-23 03:55:05 +00:00
} ;
return PHYSFSX_findPredicateFiles ( path , predicate ) ;
2010-08-09 14:04:22 +00:00
}
2015-05-09 17:39:02 +00:00
int PHYSFSX_exists_ignorecase ( const char * filename )
2011-06-01 07:59:55 +00:00
{
char filename2 [ PATH_MAX ] ;
2012-06-01 10:46:03 +00:00
snprintf ( filename2 , sizeof ( filename2 ) , " %s " , filename ) ;
2018-06-13 02:02:58 +00:00
return ! PHYSFSEXT_locateCorrectCase ( filename2 ) ;
2011-06-01 07:59:55 +00:00
}
2010-08-09 14:04:22 +00:00
//Open a file for reading, set up a buffer
2021-07-25 23:00:56 +00:00
std : : pair < RAIIPHYSFS_File , PHYSFS_ErrorCode > PHYSFSX_openReadBuffered ( const char * filename )
2010-08-09 14:04:22 +00:00
{
PHYSFS_uint64 bufSize ;
char filename2 [ PATH_MAX ] ;
2020-05-28 03:21:22 +00:00
#if 0
2010-08-09 14:04:22 +00:00
if ( filename [ 0 ] = = ' \x01 ' )
{
//FIXME: don't look in dir, only in hogfile
filename + + ;
}
2020-05-28 03:21:22 +00:00
# endif
2012-06-01 10:46:03 +00:00
snprintf ( filename2 , sizeof ( filename2 ) , " %s " , filename ) ;
2010-08-09 14:04:22 +00:00
PHYSFSEXT_locateCorrectCase ( filename2 ) ;
2015-01-17 18:31:42 +00:00
RAIIPHYSFS_File fp { PHYSFS_openRead ( filename2 ) } ;
2010-08-09 14:04:22 +00:00
if ( ! fp )
2021-07-25 23:00:56 +00:00
return { nullptr , PHYSFS_getLastErrorCode ( ) } ;
2010-08-09 14:04:22 +00:00
bufSize = PHYSFS_fileLength ( fp ) ;
while ( ! PHYSFS_setBuffer ( fp , bufSize ) & & bufSize )
bufSize / = 2 ; // even if the error isn't memory full, for a 20MB file it'll only do this 8 times
2021-07-25 23:00:56 +00:00
return { std : : move ( fp ) , PHYSFS_ERR_OK } ;
2010-08-09 14:04:22 +00:00
}
//Open a file for writing, set up a buffer
2021-07-25 23:00:56 +00:00
std : : pair < RAIIPHYSFS_File , PHYSFS_ErrorCode > PHYSFSX_openWriteBuffered ( const char * filename )
2010-08-09 14:04:22 +00:00
{
PHYSFS_uint64 bufSize = 1024 * 1024 ; // hmm, seems like an OK size.
2015-01-17 18:31:42 +00:00
RAIIPHYSFS_File fp { PHYSFS_openWrite ( filename ) } ;
2010-08-09 14:04:22 +00:00
if ( ! fp )
2021-07-25 23:00:56 +00:00
return { nullptr , PHYSFS_getLastErrorCode ( ) } ;
2010-08-09 14:04:22 +00:00
while ( ! PHYSFS_setBuffer ( fp , bufSize ) & & bufSize )
bufSize / = 2 ;
2021-07-25 23:00:56 +00:00
return { std : : move ( fp ) , PHYSFS_ERR_OK } ;
2010-08-09 14:04:22 +00:00
}
2010-09-25 03:35:23 +00:00
/*
* Add archives to the game .
* 1 ) archives from Sharepath / Data to extend / replace builtin game content
* 2 ) archived demos
*/
2010-08-15 06:57:51 +00:00
void PHYSFSX_addArchiveContent ( )
{
2014-09-26 02:42:12 +00:00
int content_updated = 0 ;
2010-08-15 06:57:51 +00:00
2017-12-05 05:29:55 +00:00
con_puts ( CON_DEBUG , " PHYSFS: Adding archives to the game. " ) ;
2010-08-15 06:57:51 +00:00
// find files in Searchpath ...
2015-01-23 03:55:05 +00:00
auto list = PHYSFSX_findFiles ( " " , archive_exts ) ;
2010-08-15 06:57:51 +00:00
// if found, add them...
2015-04-26 20:15:51 +00:00
range_for ( const auto i , list )
2010-08-15 06:57:51 +00:00
{
2020-05-02 21:18:42 +00:00
std : : array < char , PATH_MAX > realfile ;
2015-04-26 20:15:51 +00:00
PHYSFSX_getRealPath ( i , realfile ) ;
2020-12-27 22:03:09 +00:00
if ( PHYSFS_mount ( realfile . data ( ) , nullptr , 0 ) )
2010-11-26 11:50:18 +00:00
{
2016-08-06 19:55:25 +00:00
con_printf ( CON_DEBUG , " PHYSFS: Added %s to Search Path " , realfile . data ( ) ) ;
2010-11-26 11:50:18 +00:00
content_updated = 1 ;
}
2010-08-15 06:57:51 +00:00
}
2010-10-10 10:48:24 +00:00
# if PHYSFS_VER_MAJOR >= 2
2015-01-23 03:55:05 +00:00
list . reset ( ) ;
2010-08-15 06:57:51 +00:00
// find files in DEMO_DIR ...
list = PHYSFSX_findFiles ( DEMO_DIR , archive_exts ) ;
// if found, add them...
2015-04-26 20:15:51 +00:00
range_for ( const auto i , list )
2010-08-15 06:57:51 +00:00
{
2016-08-06 19:55:25 +00:00
char demofile [ PATH_MAX ] ;
2015-04-26 20:15:51 +00:00
snprintf ( demofile , sizeof ( demofile ) , DEMO_DIR " %s " , i ) ;
2020-05-02 21:18:42 +00:00
std : : array < char , PATH_MAX > realfile ;
2013-12-08 17:18:14 +00:00
PHYSFSX_getRealPath ( demofile , realfile ) ;
2016-08-06 19:55:25 +00:00
if ( PHYSFS_mount ( realfile . data ( ) , DEMO_DIR , 0 ) )
2010-11-26 11:50:18 +00:00
{
2016-08-06 19:55:25 +00:00
con_printf ( CON_DEBUG , " PHYSFS: Added %s to " DEMO_DIR , realfile . data ( ) ) ;
2010-11-26 11:50:18 +00:00
content_updated = 1 ;
}
2010-08-15 06:57:51 +00:00
}
2011-09-26 17:15:43 +00:00
# endif
2015-01-23 03:55:05 +00:00
list . reset ( ) ;
2010-11-26 11:50:18 +00:00
if ( content_updated )
{
2017-12-05 05:29:55 +00:00
con_puts ( CON_DEBUG , " Game content updated! " ) ;
2010-11-26 11:50:18 +00:00
PHYSFSX_listSearchPathContent ( ) ;
}
2010-08-15 06:57:51 +00:00
}
// Removes content added above when quitting game
void PHYSFSX_removeArchiveContent ( )
{
// find files in Searchpath ...
2015-01-23 03:55:05 +00:00
auto list = PHYSFSX_findFiles ( " " , archive_exts ) ;
2010-08-15 06:57:51 +00:00
// if found, remove them...
2015-04-26 20:15:51 +00:00
range_for ( const auto i , list )
2010-08-15 06:57:51 +00:00
{
2020-05-02 21:18:42 +00:00
std : : array < char , PATH_MAX > realfile ;
2015-04-26 20:15:51 +00:00
PHYSFSX_getRealPath ( i , realfile ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_unmount ( realfile . data ( ) ) ;
2010-08-15 06:57:51 +00:00
}
2015-01-23 03:55:05 +00:00
list . reset ( ) ;
2010-08-15 06:57:51 +00:00
// find files in DEMO_DIR ...
list = PHYSFSX_findFiles ( DEMO_DIR , archive_exts ) ;
// if found, remove them...
2015-04-26 20:15:51 +00:00
range_for ( const auto i , list )
2010-08-15 06:57:51 +00:00
{
2016-08-06 19:55:25 +00:00
char demofile [ PATH_MAX ] ;
2015-04-26 20:15:51 +00:00
snprintf ( demofile , sizeof ( demofile ) , DEMO_DIR " %s " , i ) ;
2020-05-02 21:18:42 +00:00
std : : array < char , PATH_MAX > realfile ;
2013-12-08 17:18:14 +00:00
PHYSFSX_getRealPath ( demofile , realfile ) ;
2020-12-27 22:03:09 +00:00
PHYSFS_unmount ( realfile . data ( ) ) ;
2010-08-15 06:57:51 +00:00
}
}
2015-12-13 18:00:48 +00:00
2016-10-17 03:49:31 +00:00
void PHYSFSX_read_helper_report_error ( const char * const filename , const unsigned line , const char * const func , PHYSFS_File * const file )
{
( Error ) ( filename , line , func , " reading at %lu " , static_cast < unsigned long > ( ( PHYSFS_tell ) ( file ) ) ) ;
}
2021-06-28 03:37:49 +00:00
RAIIPHYSFS_ComputedPathMount make_PHYSFSX_ComputedPathMount ( const char * const name , physfs_search_path position )
{
auto pathname = std : : make_unique < std : : array < char , PATH_MAX > > ( ) ;
2021-07-25 23:00:56 +00:00
if ( PHYSFSX_addRelToSearchPath ( name , * pathname . get ( ) , position ) = = PHYSFS_ERR_OK )
2021-06-28 03:37:49 +00:00
return RAIIPHYSFS_ComputedPathMount ( std : : move ( pathname ) ) ;
return nullptr ;
}
2015-12-13 18:00:48 +00:00
}