Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. /*
  8.  *
  9.  * Some simple physfs extensions
  10.  *
  11.  */
  12.  
  13. #include <cstdlib>
  14. #if !defined(macintosh) && !defined(_MSC_VER)
  15. #include <sys/param.h>
  16. #endif
  17. #if defined(__APPLE__) && defined(__MACH__)
  18. #include <sys/mount.h>
  19. #include <unistd.h>     // for chdir hack
  20. #include <ApplicationServices/ApplicationServices.h>
  21. #endif
  22. #include <unistd.h> // Pierre-Marie Baty -- for getuid()
  23. #include <pwd.h> // Pierre-Marie Baty -- for getpwuid()
  24.  
  25. #include "args.h"
  26. #include "newdemo.h"
  27. #include "console.h"
  28. #include "strutil.h"
  29. #include "ignorecase.h"
  30. #include "physfs_list.h"
  31.  
  32. #include "compiler-range_for.h"
  33. #include "compiler-poison.h"
  34. #include "partial_range.h"
  35.  
  36. namespace dcx {
  37.  
  38. const std::array<file_extension_t, 1> archive_exts{{"dxa"}};
  39.  
  40. char *PHYSFSX_fgets_t::get(char *const buf, std::size_t n, PHYSFS_File *const fp)
  41. {
  42.         PHYSFS_sint64 r = PHYSFS_read(fp, buf, sizeof(*buf), n - 1);
  43.         if (r <= 0)
  44.                 return DXX_POISON_MEMORY(buf, buf + n, 0xcc), nullptr;
  45.         char *p = buf;
  46.         const auto cleanup = [&]{
  47.                 return *p = 0, DXX_POISON_MEMORY(p + 1, buf + n, 0xcc), p;
  48.         };
  49.         char *const e = &buf[r];
  50.         for (;;)
  51.         {
  52.                 if (p == e)
  53.                 {
  54.                         return cleanup();
  55.                 }
  56.                 char c = *p;
  57.                 if (c == 0)
  58.                         break;
  59.                 if (c == '\n')
  60.                 {
  61.                         break;
  62.                 }
  63.                 else if (c == '\r')
  64.                 {
  65.                         *p = 0;
  66.                         if (++p != e && *p != '\n')
  67.                                 --p;
  68.                         break;
  69.                 }
  70.                 ++p;
  71.         }
  72.         PHYSFS_seek(fp, PHYSFS_tell(fp) + p - e + 1);
  73.         return cleanup();
  74. }
  75.  
  76. int PHYSFSX_checkMatchingExtension(const char *filename, const partial_range_t<const file_extension_t *> range)
  77. {
  78.         const char *ext = strrchr(filename, '.');
  79.         if (!ext)
  80.                 return 0;
  81.         ++ext;
  82.         // see if the file is of a type we want
  83.         range_for (auto &k, range)
  84.         {
  85.                 if (!d_stricmp(ext, k))
  86.                         return 1;
  87.         }
  88.         return 0;
  89. }
  90.  
  91. }
  92.  
  93. namespace dsx {
  94.  
  95. // Initialise PhysicsFS, set up basic search paths and add arguments from .ini file.
  96. // The .ini file can be in either the user directory or the same directory as the program.
  97. // The user directory is searched first.
  98. bool PHYSFSX_init(int argc, char *argv[])
  99. {
  100. #if defined(__unix__) || defined(__APPLE__) || defined(__MACH__)
  101.         char fullPath[PATH_MAX + 5];
  102. #endif
  103. #ifdef macintosh        // Mac OS 9
  104.         char base_dir[PATH_MAX];
  105.         int bundle = 0;
  106. #else
  107. #define base_dir PHYSFS_getBaseDir()
  108. #endif
  109.        
  110.         if (!PHYSFS_init(argv[0]))
  111.                 Error("Failed to init PhysFS: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); // Pierre-Marie Baty -- work around PHYSFS_getLastError() deprecation
  112.         PHYSFS_permitSymbolicLinks(1);
  113.        
  114. #ifdef macintosh
  115.         strcpy(base_dir, PHYSFS_getBaseDir());
  116.         if (strstr(base_dir, ".app:Contents:MacOSClassic"))     // the Mac OS 9 program is still in the .app bundle
  117.         {
  118.                 char *p;
  119.                
  120.                 bundle = 1;
  121.                 if (base_dir[strlen(base_dir) - 1] == ':')
  122.                         base_dir[strlen(base_dir) - 1] = '\0';
  123.                 p = strrchr(base_dir, ':'); *p = '\0';  // path to 'Contents'
  124.                 p = strrchr(base_dir, ':'); *p = '\0';  // path to bundle
  125.                 p = strrchr(base_dir, ':'); *p = '\0';  // path to directory containing bundle
  126.         }
  127. #endif
  128.        
  129. #if (defined(__APPLE__) && defined(__MACH__))   // others?
  130.         chdir(base_dir);        // make sure relative hogdir paths work
  131. #endif
  132.        
  133.         const char *writedir;
  134. #if defined(__unix__)
  135. #if defined(DXX_BUILD_DESCENT_I)
  136. #define DESCENT_PATH_NUMBER     "1"
  137. #elif defined(DXX_BUILD_DESCENT_II)
  138. #define DESCENT_PATH_NUMBER     "2"
  139. #endif
  140. //      const auto &home_environ_var = "D" DESCENT_PATH_NUMBER "X_REBIRTH_HOME";
  141.                 const char *path;// = getenv(home_environ_var);
  142. //      if (!path)
  143. //      {
  144. //              path = getenv(&home_environ_var[4]);
  145. //              if (!path)
  146. # if !(defined(__APPLE__) && defined(__MACH__))
  147.         path = "~/.d" DESCENT_PATH_NUMBER "x-rebirth/";
  148. # else
  149.         path = "~/Library/Preferences/Descent" DESCENT_PATH_NUMBER "/";
  150. # endif
  151. //      }
  152.        
  153.         if (path[0] == '~') // yes, this tilde can be put before non-unix paths.
  154.         {
  155.                 const char *home = /*PHYSFS_getUserDir()*/getpwuid(getuid())->pw_dir; // Pierre-Marie Baty -- work around PHYSFS_getUserDir() deprecation
  156.                 path++;
  157.                 // prepend home to the path
  158.                 //if (*path == *PHYSFS_getDirSeparator())
  159.                 //      path++;
  160.                 snprintf(fullPath, sizeof(fullPath), "%s%s", home, path);
  161.         }
  162.         else
  163.         {
  164.                 fullPath[sizeof(fullPath) - 1] = 0;
  165.                 strncpy(fullPath, path, sizeof(fullPath) - 1);
  166.         }
  167.  
  168.         PHYSFS_setWriteDir(fullPath);
  169.         if (!(writedir = PHYSFS_getWriteDir()))
  170.         {                                               // need to make it
  171.                 char *p;
  172.                 char ancestor[PATH_MAX + 5];    // the directory which actually exists
  173.                 char child[PATH_MAX + 5];               // the directory relative to the above we're trying to make
  174.                
  175.                 strcpy(ancestor, fullPath);
  176.                 const auto separator = *PHYSFS_getDirSeparator();
  177.                 while (!PHYSFS_getWriteDir() && (p = strrchr(ancestor, separator)))
  178.                 {
  179.                         if (p[1] == 0)
  180.                         {                                       // separator at the end (intended here, for safety)
  181.                                 *p = 0;                 // kill this separator
  182.                                 if (!(p = strrchr(ancestor, separator)))
  183.                                         break;          // give up, this is (usually) the root directory
  184.                         }
  185.                        
  186.                         p[1] = 0;                       // go to parent
  187.                         PHYSFS_setWriteDir(ancestor);
  188.                 }
  189.                
  190.                 strcpy(child, fullPath + strlen(ancestor));
  191.                 if (separator != '/')
  192.                         for (p = child; (p = strchr(p, separator)); p++)
  193.                                 *p = '/';
  194.                 PHYSFS_mkdir(child);
  195.                 PHYSFS_setWriteDir(fullPath);
  196.                 writedir = PHYSFS_getWriteDir();
  197.         }
  198.         con_printf(CON_DEBUG, "PHYSFS: append write directory \"%s\" to search path", writedir);
  199. printf("PHYSFS: append write directory \"%s\" to search path: %s", writedir, fullPath);
  200.         PHYSFS_mount(writedir, NULL, 1); // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  201. #endif
  202.         con_printf(CON_DEBUG, "PHYSFS: temporarily append base directory \"%s\" to search path", base_dir);
  203.         PHYSFS_mount(base_dir, NULL, 1); // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  204.         if (!InitArgs( argc,argv ))
  205.                 return false;
  206.         PHYSFS_unmount(base_dir); // Pierre-Marie Baty -- work around PHYSFS_removeFromSearchPath() deprecation
  207.        
  208.         if (!PHYSFS_getWriteDir())
  209.         {
  210.                 PHYSFS_setWriteDir(base_dir);
  211.                 if (!(writedir = PHYSFS_getWriteDir()))
  212.                         Error("can't set write dir: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); // Pierre-Marie Baty -- work around PHYSFS_getLastError() deprecation
  213.                 PHYSFS_mount(writedir, NULL, 0); // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  214.         }
  215.        
  216.         //tell PHYSFS where hogdir is
  217.         if (!CGameArg.SysHogDir.empty())
  218.         {
  219.                 const auto p = CGameArg.SysHogDir.c_str();
  220.                 con_printf(CON_DEBUG, "PHYSFS: append argument hog directory \"%s\" to search path", p);
  221.                 PHYSFS_mount(p, NULL, 1); // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  222.         }
  223. #if DXX_USE_SHAREPATH
  224.         else if (!GameArg.SysNoHogDir)
  225.         {
  226.                 con_puts(CON_DEBUG, "PHYSFS: append sharepath directory \"" DXX_SHAREPATH "\" to search path");
  227.                 PHYSFS_mount(DXX_SHAREPATH, NULL, 1); // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  228.         }
  229.         else
  230.         {
  231.                 con_puts(CON_DEBUG, "PHYSFS: skipping built-in sharepath \"" DXX_SHAREPATH "\"");
  232.         }
  233. #else
  234.         else
  235.         {
  236.                 con_puts(CON_DEBUG, "PHYSFS: no built-in sharepath");
  237.         }
  238. #endif
  239.        
  240.         PHYSFSX_addRelToSearchPath("data", 1);  // 'Data' subdirectory
  241.        
  242.         // For Macintosh, add the 'Resources' directory in the .app bundle to the searchpaths
  243. #if defined(__APPLE__) && defined(__MACH__)
  244.         {
  245.                 CFBundleRef mainBundle = CFBundleGetMainBundle();
  246.                 if (mainBundle)
  247.                 {
  248.                         CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
  249.                         if (resourcesURL)
  250.                         {
  251.                                 if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, reinterpret_cast<uint8_t *>(fullPath), sizeof(fullPath)))
  252.                                 {
  253.                                         con_printf(CON_DEBUG, "PHYSFS: append resources directory \"%s\" to search path", fullPath);
  254.                                         PHYSFS_mount(fullPath, NULL, 1); // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  255.                                 }
  256.                        
  257.                                 CFRelease(resourcesURL);
  258.                         }
  259.                 }
  260.         }
  261. #elif defined(macintosh)
  262.         if (bundle)
  263.         {
  264.                 base_dir[strlen(base_dir)] = ':';       // go back in the bundle
  265.                 base_dir[strlen(base_dir)] = ':';       // go back in 'Contents'
  266.                 strncat(base_dir, ":Resources:", PATH_MAX - 1 - strlen(base_dir));
  267.                 base_dir[PATH_MAX - 1] = '\0';
  268.                 con_printf(CON_DEBUG, "PHYSFS: append bundle directory \"%s\" to search path", base_dir);
  269.                 PHYSFS_mount(base_dir, NULL, 1); // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  270.         }
  271. #endif
  272.         return true;
  273. }
  274.  
  275. }
  276.  
  277. namespace dcx {
  278.  
  279. // Add a searchpath, but that searchpath is relative to an existing searchpath
  280. // It will add the first one it finds and return 1, if it doesn't find any it returns 0
  281. int PHYSFSX_addRelToSearchPath(const char *relname, int add_to_end)
  282. {
  283.         char relname2[PATH_MAX];
  284.  
  285.         snprintf(relname2, sizeof(relname2), "%s", relname);
  286.         PHYSFSEXT_locateCorrectCase(relname2);
  287.  
  288.         std::array<char, PATH_MAX> pathname;
  289.         if (!PHYSFSX_getRealPath(relname2, pathname))
  290.         {
  291.                 con_printf(CON_DEBUG, "PHYSFS: ignoring map request: no canonical path for relative name \"%s\"", relname2);
  292.                 return 0;
  293.         }
  294.  
  295.         auto r = PHYSFS_mount(pathname.data(), NULL, add_to_end); // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  296.         const auto action = add_to_end ? "append" : "insert";
  297.         if (r)
  298.                 con_printf(CON_DEBUG, "PHYSFS: %s canonical directory \"%s\" to search path from relative name \"%s\"", action, pathname.data(), relname);
  299.         else
  300.                 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(PHYSFS_getLastErrorCode())); // Pierre-Marie Baty -- work around PHYSFS_getLastError() deprecation
  301.         return r;
  302. }
  303.  
  304. int PHYSFSX_removeRelFromSearchPath(const char *relname)
  305. {
  306.         char relname2[PATH_MAX];
  307.  
  308.         snprintf(relname2, sizeof(relname2), "%s", relname);
  309.         PHYSFSEXT_locateCorrectCase(relname2);
  310.  
  311.         std::array<char, PATH_MAX> pathname;
  312.         if (!PHYSFSX_getRealPath(relname2, pathname))
  313.         {
  314.                 con_printf(CON_DEBUG, "PHYSFS: ignoring unmap request: no canonical path for relative name \"%s\"", relname2);
  315.                 return 0;
  316.         }
  317.         auto r = PHYSFS_unmount(pathname.data()); // Pierre-Marie Baty -- work around PHYSFS_removeFromSearchPath() deprecation
  318.         if (r)
  319.                 con_printf(CON_DEBUG, "PHYSFS: unmap canonical directory \"%s\" (relative name \"%s\")", pathname.data(), relname);
  320.         else
  321.                 con_printf(CON_VERBOSE, "PHYSFS: failed to unmap canonical directory \"%s\" (relative name \"%s\"): \"%s\"", pathname.data(), relname, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); // Pierre-Marie Baty -- work around PHYSFS_getLastError() deprecation
  322.         return r;
  323. }
  324.  
  325. int PHYSFSX_fsize(const char *hogname)
  326. {
  327.         char hogname2[PATH_MAX];
  328.  
  329.         snprintf(hogname2, sizeof(hogname2), "%s", hogname);
  330.         PHYSFSEXT_locateCorrectCase(hogname2);
  331.  
  332.         if (RAIIPHYSFS_File fp{PHYSFS_openRead(hogname2)})
  333.                 return PHYSFS_fileLength(fp);
  334.         return -1;
  335. }
  336.  
  337. void PHYSFSX_listSearchPathContent()
  338. {
  339.         con_puts(CON_DEBUG, "PHYSFS: Listing contents of Search Path.");
  340.         PHYSFSX_uncounted_list list{PHYSFS_getSearchPath()};
  341.         range_for (const auto i, list)
  342.                 con_printf(CON_DEBUG, "PHYSFS: [%s] is in the Search Path.", i);
  343.         list.reset();
  344.         list.reset(PHYSFS_enumerateFiles(""));
  345.         range_for (const auto i, list)
  346.                 con_printf(CON_DEBUG, "PHYSFS: * We've got [%s].", i);
  347. }
  348.  
  349. }
  350.  
  351. namespace dsx {
  352.  
  353. // checks which archives are supported by PhysFS. Return 0 if some essential (HOG) is not supported
  354. int PHYSFSX_checkSupportedArchiveTypes()
  355. {
  356.         int hog_sup = 0;
  357. #ifdef DXX_BUILD_DESCENT_II
  358.         int mvl_sup = 0;
  359. #endif
  360.  
  361.         con_puts(CON_DEBUG, "PHYSFS: Checking supported archive types.");
  362.         range_for (const auto i, make_null_sentinel_array(PHYSFS_supportedArchiveTypes()))
  363.         {
  364.                 const auto iextension = i->extension;
  365.                 con_printf(CON_DEBUG, "PHYSFS: Supported archive: [%s], which is [%s].", iextension, i->description);
  366.                 if (!d_stricmp(iextension, "HOG"))
  367.                         hog_sup = 1;
  368. #ifdef DXX_BUILD_DESCENT_II
  369.                 else if (!d_stricmp(iextension, "MVL"))
  370.                         mvl_sup = 1;
  371. #endif
  372.         }
  373.  
  374.         if (!hog_sup)
  375.                 con_puts(CON_CRITICAL, "PHYSFS: HOG not supported. The game will not work without!");
  376. #ifdef DXX_BUILD_DESCENT_II
  377.         if (!mvl_sup)
  378.                 con_puts(CON_URGENT, "PHYSFS: MVL not supported. Won't be able to play movies!");
  379. #endif
  380.  
  381.         return hog_sup;
  382. }
  383.  
  384. }
  385.  
  386. namespace dcx {
  387.  
  388. int PHYSFSX_getRealPath(const char *stdPath, char *realPath, const std::size_t outSize)
  389. {
  390.         DXX_POISON_MEMORY(realPath, outSize, 0xdd);
  391.         const char *realDir = PHYSFS_getRealDir(stdPath);
  392.         if (!realDir)
  393.         {
  394.                 realDir = PHYSFS_getWriteDir();
  395.                 if (!realDir)
  396.                         return 0;
  397.         }
  398.         const auto realDirSize = strlen(realDir);
  399.         if (realDirSize >= outSize)
  400.                 return 0;
  401.         auto mountpoint = PHYSFS_getMountPoint(realDir);
  402.         if (!mountpoint)
  403.                 return 0;
  404.         std::copy_n(realDir, realDirSize + 1, realPath);
  405. #ifdef _unix__
  406.         auto &sep = "/";
  407.         assert(!strcmp(PHYSFS_getDirSeparator(), sep));
  408. #else
  409.         const auto sep = PHYSFS_getDirSeparator();
  410. #endif
  411.         const auto sepSize = strlen(sep);
  412.         auto realPathUsed = realDirSize;
  413.         if (realDirSize >= sepSize)
  414.         {
  415.                 const auto p = realPath + realDirSize - sepSize;
  416.                 if (strcmp(p, sep)) // no sep at end of realPath
  417.                 {
  418.                         realPathUsed += sepSize;
  419.                         std::copy_n(sep, sepSize, &realPath[realDirSize]);
  420.                 }
  421.         }
  422.         if (*mountpoint == '/')
  423.                 ++mountpoint;
  424.         if (*stdPath == '/')
  425.                 ++stdPath;
  426.         const auto ml = strlen(mountpoint);
  427.         if (!strncmp(mountpoint, stdPath, ml))
  428.                 stdPath += ml;
  429.         else
  430.         {
  431.                 /* Virtual path is not under the virtual mount point that
  432.                  * provides the path.
  433.                  */
  434.                 assert(false);
  435.         }
  436.         const auto stdPathLen = strlen(stdPath) + 1;
  437.         if (realPathUsed + stdPathLen >= outSize)
  438.                 return 0;
  439. #ifdef __unix__
  440.         /* Separator is "/" and physfs internal separator is "/".  Copy
  441.          * through.
  442.          */
  443.         std::copy_n(stdPath, stdPathLen, &realPath[realPathUsed]);
  444. #else
  445.         /* Separator might be / on non-unix, but the fallback path works
  446.          * regardless of whether separator is "/".
  447.          */
  448.         const auto csep = *sep;
  449.         const auto a = [csep](char c) {
  450.                 return c == '/' ? csep : c;
  451.         };
  452.         std::transform(stdPath, &stdPath[stdPathLen], &realPath[realPathUsed], a);
  453. #endif
  454.         return 1;
  455. }
  456.  
  457. // checks if path is already added to Searchpath. Returns 0 if yes, 1 if not.
  458. int PHYSFSX_isNewPath(const char *path)
  459. {
  460.         int is_new_path = 1;
  461.         PHYSFSX_uncounted_list list{PHYSFS_getSearchPath()};
  462.         range_for (const auto i, list)
  463.         {
  464.                 if (!strcmp(path, i))
  465.                 {
  466.                         is_new_path = 0;
  467.                         break;
  468.                 }
  469.         }
  470.         return is_new_path;
  471. }
  472.  
  473. int PHYSFSX_rename(const char *oldpath, const char *newpath)
  474. {
  475.         std::array<char, PATH_MAX> old, n;
  476.         PHYSFSX_getRealPath(oldpath, old);
  477.         PHYSFSX_getRealPath(newpath, n);
  478.         return (rename(old.data(), n.data()) == 0);
  479. }
  480.  
  481. template <typename F>
  482. static inline PHYSFSX_uncounted_list PHYSFSX_findPredicateFiles(const char *path, F f)
  483. {
  484.         PHYSFSX_uncounted_list list{PHYSFS_enumerateFiles(path)};
  485.         if (!list)
  486.                 return nullptr; // out of memory: not so good
  487.         char **j = list.get();
  488.         range_for (const auto i, list)
  489.         {
  490.                 if (f(i))
  491.                         *j++ = i;
  492.                 else
  493.                         free(i);
  494.         }
  495.         *j = NULL;
  496.         char **r = reinterpret_cast<char **>(realloc(list.get(), (j - list.get() + 1)*sizeof(char *))); // save a bit of memory (or a lot?)
  497.         if (r)
  498.         {
  499.                 list.release();
  500.                 list.reset(r);
  501.         }
  502.         return list;
  503. }
  504.  
  505. // Find files at path that have an extension listed in exts
  506. // The extension list exts must be NULL-terminated, with each ext beginning with a '.'
  507. PHYSFSX_uncounted_list PHYSFSX_findFiles(const char *path, const partial_range_t<const file_extension_t *> exts)
  508. {
  509.         const auto predicate = [&](const char *i) {
  510.                 return PHYSFSX_checkMatchingExtension(i, exts);
  511.         };
  512.         return PHYSFSX_findPredicateFiles(path, predicate);
  513. }
  514.  
  515. // Same function as above but takes a real directory as second argument, only adding files originating from this directory.
  516. // This can be used to further seperate files in search path but it must be made sure realpath is properly formatted.
  517. PHYSFSX_uncounted_list PHYSFSX_findabsoluteFiles(const char *path, const char *realpath, const partial_range_t<const file_extension_t *> exts)
  518. {
  519.         const auto predicate = [&](const char *i) {
  520.                 return PHYSFSX_checkMatchingExtension(i, exts) && (!strcmp(PHYSFS_getRealDir(i), realpath));
  521.         };
  522.         return PHYSFSX_findPredicateFiles(path, predicate);
  523. }
  524.  
  525. int PHYSFSX_exists_ignorecase(const char *filename)
  526. {
  527.         char filename2[PATH_MAX];
  528.         snprintf(filename2, sizeof(filename2), "%s", filename);
  529.         return !PHYSFSEXT_locateCorrectCase(filename2);
  530. }
  531.  
  532. //Open a file for reading, set up a buffer
  533. RAIIPHYSFS_File PHYSFSX_openReadBuffered(const char *filename)
  534. {
  535.         PHYSFS_uint64 bufSize;
  536.         char filename2[PATH_MAX];
  537. #if 0
  538.         if (filename[0] == '\x01')
  539.         {
  540.                 //FIXME: don't look in dir, only in hogfile
  541.                 filename++;
  542.         }
  543. #endif
  544.         snprintf(filename2, sizeof(filename2), "%s", filename);
  545.         PHYSFSEXT_locateCorrectCase(filename2);
  546.        
  547.         RAIIPHYSFS_File fp{PHYSFS_openRead(filename2)};
  548.         if (!fp)
  549.                 return nullptr;
  550.        
  551.         bufSize = PHYSFS_fileLength(fp);
  552.         while (!PHYSFS_setBuffer(fp, bufSize) && bufSize)
  553.                 bufSize /= 2;   // even if the error isn't memory full, for a 20MB file it'll only do this 8 times
  554.         return fp;
  555. }
  556.  
  557. //Open a file for writing, set up a buffer
  558. RAIIPHYSFS_File PHYSFSX_openWriteBuffered(const char *filename)
  559. {
  560.         PHYSFS_uint64 bufSize = 1024*1024;      // hmm, seems like an OK size.
  561.        
  562.         RAIIPHYSFS_File fp{PHYSFS_openWrite(filename)};
  563.         if (!fp)
  564.                 return nullptr;
  565.         while (!PHYSFS_setBuffer(fp, bufSize) && bufSize)
  566.                 bufSize /= 2;
  567.         return fp;
  568. }
  569.  
  570. /*
  571.  * Add archives to the game.
  572.  * 1) archives from Sharepath/Data to extend/replace builtin game content
  573.  * 2) archived demos
  574.  */
  575. void PHYSFSX_addArchiveContent()
  576. {
  577.         int content_updated = 0;
  578.  
  579.         con_puts(CON_DEBUG, "PHYSFS: Adding archives to the game.");
  580.         // find files in Searchpath ...
  581.         auto list = PHYSFSX_findFiles("", archive_exts);
  582.         // if found, add them...
  583.         range_for (const auto i, list)
  584.         {
  585.                 std::array<char, PATH_MAX> realfile;
  586.                 PHYSFSX_getRealPath(i,realfile);
  587.                 if (PHYSFS_mount(realfile.data(), NULL, 0)) // Pierre-Marie Baty -- work around PHYSFS_addToSearchPath() deprecation
  588.                 {
  589.                         con_printf(CON_DEBUG, "PHYSFS: Added %s to Search Path",realfile.data());
  590.                         content_updated = 1;
  591.                 }
  592.         }
  593. #if PHYSFS_VER_MAJOR >= 2
  594.         list.reset();
  595.         // find files in DEMO_DIR ...
  596.         list = PHYSFSX_findFiles(DEMO_DIR, archive_exts);
  597.         // if found, add them...
  598.         range_for (const auto i, list)
  599.         {
  600.                 char demofile[PATH_MAX];
  601.                 snprintf(demofile, sizeof(demofile), DEMO_DIR "%s", i);
  602.                 std::array<char, PATH_MAX> realfile;
  603.                 PHYSFSX_getRealPath(demofile,realfile);
  604.                 if (PHYSFS_mount(realfile.data(), DEMO_DIR, 0))
  605.                 {
  606.                         con_printf(CON_DEBUG, "PHYSFS: Added %s to " DEMO_DIR, realfile.data());
  607.                         content_updated = 1;
  608.                 }
  609.         }
  610. #endif
  611.         list.reset();
  612.  
  613.         if (content_updated)
  614.         {
  615.                 con_puts(CON_DEBUG, "Game content updated!");
  616.                 PHYSFSX_listSearchPathContent();
  617.         }
  618. }
  619.  
  620. // Removes content added above when quitting game
  621. void PHYSFSX_removeArchiveContent()
  622. {
  623.         // find files in Searchpath ...
  624.         auto list = PHYSFSX_findFiles("", archive_exts);
  625.         // if found, remove them...
  626.         range_for (const auto i, list)
  627.         {
  628.                 std::array<char, PATH_MAX> realfile;
  629.                 PHYSFSX_getRealPath(i, realfile);
  630.                 PHYSFS_unmount(realfile.data()); // Pierre-Marie Baty -- work around PHYSFS_removeFromSearchPath() deprecation
  631.         }
  632.         list.reset();
  633.         // find files in DEMO_DIR ...
  634.         list = PHYSFSX_findFiles(DEMO_DIR, archive_exts);
  635.         // if found, remove them...
  636.         range_for (const auto i, list)
  637.         {
  638.                 char demofile[PATH_MAX];
  639.                 snprintf(demofile, sizeof(demofile), DEMO_DIR "%s", i);
  640.                 std::array<char, PATH_MAX> realfile;
  641.                 PHYSFSX_getRealPath(demofile,realfile);
  642.                 PHYSFS_unmount(realfile.data()); // Pierre-Marie Baty -- work around PHYSFS_removeFromSearchPath() deprecation
  643.         }
  644. }
  645.  
  646. void PHYSFSX_read_helper_report_error(const char *const filename, const unsigned line, const char *const func, PHYSFS_File *const file)
  647. {
  648.         (Error)(filename, line, func, "reading at %lu", static_cast<unsigned long>((PHYSFS_tell)(file)));
  649. }
  650.  
  651. }
  652.