Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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
}