2014-06-01 17:55:23 +00:00
|
|
|
/*
|
|
|
|
* This file is part of the DXX-Rebirth project <http://www.dxx-rebirth.com/>.
|
|
|
|
* 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
|
|
|
|
#include <HIServices/Processes.h>
|
|
|
|
#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"
|
2014-09-07 19:26:17 +00:00
|
|
|
#include "poison.h"
|
|
|
|
|
2015-12-13 18:00:49 +00:00
|
|
|
namespace dcx {
|
2015-12-13 18:00:48 +00:00
|
|
|
|
2015-03-22 18:49:21 +00:00
|
|
|
const 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
|
|
|
|
|
|
|
|
PHYSFS_init(argv[0]);
|
|
|
|
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();
|
|
|
|
|
|
|
|
strcpy(fullPath, home); // prepend home to the path
|
|
|
|
path++;
|
|
|
|
if (*path == *PHYSFS_getDirSeparator())
|
|
|
|
path++;
|
|
|
|
strncat(fullPath, path, PATH_MAX + 5 - strlen(home));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strncpy(fullPath, path, PATH_MAX + 5);
|
|
|
|
|
|
|
|
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);
|
|
|
|
PHYSFS_addToSearchPath(writedir, 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);
|
2010-08-09 14:04:22 +00:00
|
|
|
PHYSFS_addToSearchPath(base_dir, 1);
|
2015-01-28 03:42:53 +00:00
|
|
|
if (!InitArgs( argc,argv ))
|
|
|
|
return false;
|
2010-08-09 14:04:22 +00:00
|
|
|
PHYSFS_removeFromSearchPath(base_dir);
|
|
|
|
|
|
|
|
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());
|
2015-09-22 02:28:38 +00:00
|
|
|
PHYSFS_addToSearchPath(writedir, 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);
|
|
|
|
PHYSFS_addToSearchPath(p, 1);
|
2013-12-28 18:16:19 +00:00
|
|
|
}
|
2010-08-09 14:04:22 +00:00
|
|
|
#if defined(__unix__)
|
2015-11-24 04:05:35 +00:00
|
|
|
else if (!CGameArg.SysNoHogDir)
|
2013-12-28 18:16:19 +00:00
|
|
|
{
|
|
|
|
con_printf(CON_DEBUG, "PHYSFS: append sharepath directory \"" SHAREPATH "\" to search path");
|
2010-08-09 14:04:22 +00:00
|
|
|
PHYSFS_addToSearchPath(SHAREPATH, 1);
|
2013-12-28 18:16:19 +00:00
|
|
|
}
|
2010-08-09 14:04:22 +00:00
|
|
|
#endif
|
|
|
|
|
2012-03-03 08:03:03 +00:00
|
|
|
PHYSFSX_addRelToSearchPath("data", 1); // '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__)
|
|
|
|
{
|
|
|
|
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
|
|
|
FSRef fsref;
|
|
|
|
OSStatus err;
|
|
|
|
|
|
|
|
err = GetProcessBundleLocation(&psn, &fsref);
|
|
|
|
if (err == noErr)
|
|
|
|
err = FSRefMakePath(&fsref, (ubyte *)fullPath, PATH_MAX);
|
|
|
|
|
|
|
|
if (err == noErr)
|
|
|
|
{
|
|
|
|
strncat(fullPath, "/Contents/Resources/", PATH_MAX + 4 - strlen(fullPath));
|
|
|
|
fullPath[PATH_MAX + 4] = '\0';
|
2013-12-28 18:16:19 +00:00
|
|
|
con_printf(CON_DEBUG, "PHYSFS: append resources directory \"%s\" to search path", fullPath);
|
2010-08-09 14:04:22 +00:00
|
|
|
PHYSFS_addToSearchPath(fullPath, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#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);
|
2010-08-09 14:04:22 +00:00
|
|
|
PHYSFS_addToSearchPath(base_dir, 1);
|
|
|
|
}
|
|
|
|
#endif
|
2015-01-28 03:42:53 +00:00
|
|
|
return true;
|
2010-08-09 14:04:22 +00:00
|
|
|
}
|
|
|
|
|
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
|
2012-07-22 23:17:54 +00:00
|
|
|
int PHYSFSX_addRelToSearchPath(const char *relname, int add_to_end)
|
2011-06-01 07:59:55 +00:00
|
|
|
{
|
2012-03-03 08:03:03 +00:00
|
|
|
char relname2[PATH_MAX], pathname[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))
|
2011-06-01 07:59:55 +00:00
|
|
|
return 0;
|
|
|
|
|
2013-12-28 18:16:19 +00:00
|
|
|
con_printf(CON_DEBUG, "PHYSFS: %s canonical directory \"%s\" to search path from relative name \"%s\"", add_to_end ? "append" : "set", pathname, relname);
|
2011-06-01 07:59:55 +00:00
|
|
|
return PHYSFS_addToSearchPath(pathname, add_to_end);
|
|
|
|
}
|
|
|
|
|
2012-07-22 23:17:54 +00:00
|
|
|
int PHYSFSX_removeRelFromSearchPath(const char *relname)
|
2011-06-01 07:59:55 +00:00
|
|
|
{
|
2012-03-03 08:03:03 +00:00
|
|
|
char relname2[PATH_MAX], pathname[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))
|
2011-06-01 07:59:55 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return PHYSFS_removeFromSearchPath(pathname);
|
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
{
|
2013-12-07 00:47:27 +00:00
|
|
|
con_printf(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
|
|
|
|
2013-12-07 00:47:27 +00:00
|
|
|
con_printf(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)
|
2013-12-07 00:47:27 +00:00
|
|
|
con_printf(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)
|
2013-12-07 00:47:27 +00:00
|
|
|
con_printf(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
|
|
|
|
2015-10-11 22:21:00 +00:00
|
|
|
int PHYSFSX_getRealPath(const char *stdPath, char *realPath, const std::size_t outSize)
|
2010-08-09 14:04:22 +00:00
|
|
|
{
|
2015-10-11 22:21:00 +00:00
|
|
|
DXX_POISON_MEMORY(realPath, outSize, 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);
|
|
|
|
if (realDirSize >= outSize)
|
|
|
|
return 0;
|
|
|
|
auto mountpoint = PHYSFS_getMountPoint(realDir);
|
|
|
|
if (!mountpoint)
|
|
|
|
return 0;
|
2015-10-24 03:13:11 +00:00
|
|
|
std::copy_n(realDir, realDirSize + 1, realPath);
|
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
|
|
|
{
|
2015-10-11 22:21:00 +00:00
|
|
|
const auto p = realPath + 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;
|
|
|
|
if (realPathUsed + stdPathLen >= outSize)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-11-21 11:55:35 +00:00
|
|
|
// checks if path is already added to Searchpath. Returns 0 if yes, 1 if not.
|
2012-07-22 23:17:54 +00:00
|
|
|
int PHYSFSX_isNewPath(const char *path)
|
2010-11-21 11:55:35 +00:00
|
|
|
{
|
|
|
|
int is_new_path = 1;
|
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)
|
2010-11-21 11:55:35 +00:00
|
|
|
{
|
2015-04-26 20:15:51 +00:00
|
|
|
if (!strcmp(path, i))
|
2010-11-21 11:55:35 +00:00
|
|
|
{
|
|
|
|
is_new_path = 0;
|
2015-04-26 20:15:51 +00:00
|
|
|
break;
|
2010-11-21 11:55:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return is_new_path;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2012-11-18 18:21:50 +00:00
|
|
|
char old[PATH_MAX], n[PATH_MAX];
|
2010-08-09 14:04:22 +00:00
|
|
|
|
|
|
|
PHYSFSX_getRealPath(oldpath, old);
|
2012-11-18 18:21:50 +00:00
|
|
|
PHYSFSX_getRealPath(newpath, n);
|
|
|
|
return (rename(old, n) == 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 '.'
|
2015-05-09 17:38:57 +00:00
|
|
|
PHYSFSX_uncounted_list PHYSFSX_findFiles(const char *path, const file_extension_t *exts, uint_fast32_t count)
|
2015-01-23 03:55:05 +00:00
|
|
|
{
|
|
|
|
const auto predicate = [&](const char *i) {
|
2015-02-14 22:48:28 +00:00
|
|
|
return PHYSFSX_checkMatchingExtension(i, exts, count);
|
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.
|
2015-05-09 17:38:57 +00:00
|
|
|
PHYSFSX_uncounted_list PHYSFSX_findabsoluteFiles(const char *path, const char *realpath, const file_extension_t *exts, uint_fast32_t count)
|
2010-08-09 14:04:22 +00:00
|
|
|
{
|
2015-01-23 03:55:05 +00:00
|
|
|
const auto predicate = [&](const char *i) {
|
2015-02-14 22:48:28 +00:00
|
|
|
return PHYSFSX_checkMatchingExtension(i, exts, count) && (!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);
|
2011-06-01 07:59:55 +00:00
|
|
|
PHYSFSEXT_locateCorrectCase(filename2);
|
|
|
|
return PHYSFS_exists(filename2);
|
|
|
|
}
|
|
|
|
|
2010-08-09 14:04:22 +00:00
|
|
|
//Open a file for reading, set up a buffer
|
2015-01-17 18:31:42 +00:00
|
|
|
RAIIPHYSFS_File PHYSFSX_openReadBuffered(const char *filename)
|
2010-08-09 14:04:22 +00:00
|
|
|
{
|
|
|
|
PHYSFS_uint64 bufSize;
|
|
|
|
char filename2[PATH_MAX];
|
|
|
|
|
|
|
|
if (filename[0] == '\x01')
|
|
|
|
{
|
|
|
|
//FIXME: don't look in dir, only in hogfile
|
|
|
|
filename++;
|
|
|
|
}
|
|
|
|
|
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)
|
2015-01-17 18:31:42 +00:00
|
|
|
return nullptr;
|
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
|
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Open a file for writing, set up a buffer
|
2015-01-17 18:31:42 +00:00
|
|
|
RAIIPHYSFS_File 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)
|
2015-01-17 18:31:42 +00:00
|
|
|
return nullptr;
|
2010-08-09 14:04:22 +00:00
|
|
|
while (!PHYSFS_setBuffer(fp, bufSize) && bufSize)
|
|
|
|
bufSize /= 2;
|
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2013-12-07 00:47:27 +00:00
|
|
|
con_printf(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
|
|
|
{
|
2013-12-08 17:17:05 +00:00
|
|
|
char realfile[PATH_MAX];
|
2015-04-26 20:15:51 +00:00
|
|
|
PHYSFSX_getRealPath(i,realfile);
|
2013-12-08 17:17:05 +00:00
|
|
|
if (PHYSFS_addToSearchPath(realfile, 0))
|
2010-11-26 11:50:18 +00:00
|
|
|
{
|
2013-12-08 17:17:05 +00:00
|
|
|
con_printf(CON_DEBUG, "PHYSFS: Added %s to Search Path",realfile);
|
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
|
|
|
{
|
2013-12-08 17:18:14 +00:00
|
|
|
char demofile[PATH_MAX], realfile[PATH_MAX];
|
2015-04-26 20:15:51 +00:00
|
|
|
snprintf(demofile, sizeof(demofile), DEMO_DIR "%s", i);
|
2013-12-08 17:18:14 +00:00
|
|
|
PHYSFSX_getRealPath(demofile,realfile);
|
|
|
|
if (PHYSFS_mount(realfile, DEMO_DIR, 0))
|
2010-11-26 11:50:18 +00:00
|
|
|
{
|
2015-04-26 20:15:51 +00:00
|
|
|
con_printf(CON_DEBUG, "PHYSFS: Added %s to " DEMO_DIR, realfile);
|
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)
|
|
|
|
{
|
2013-12-07 00:47:27 +00:00
|
|
|
con_printf(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
|
|
|
{
|
2013-12-08 17:17:05 +00:00
|
|
|
char realfile[PATH_MAX];
|
2015-04-26 20:15:51 +00:00
|
|
|
PHYSFSX_getRealPath(i, realfile);
|
2013-12-08 17:17:05 +00:00
|
|
|
PHYSFS_removeFromSearchPath(realfile);
|
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
|
|
|
{
|
2013-12-08 17:18:14 +00:00
|
|
|
char demofile[PATH_MAX], realfile[PATH_MAX];
|
2015-04-26 20:15:51 +00:00
|
|
|
snprintf(demofile, sizeof(demofile), DEMO_DIR "%s", i);
|
2013-12-08 17:18:14 +00:00
|
|
|
PHYSFSX_getRealPath(demofile,realfile);
|
|
|
|
PHYSFS_removeFromSearchPath(realfile);
|
2010-08-15 06:57:51 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-13 18:00:48 +00:00
|
|
|
|
|
|
|
}
|