diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index f82eb2baa..c582eaabb 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -37,7 +37,7 @@ namespace physfs Filesystem::Filesystem() : open_count(0) , buffer(0) - , isInited(false) + , initialized(false) , release(false) , releaseSet(false) { @@ -45,11 +45,8 @@ Filesystem::Filesystem() Filesystem::~Filesystem() { - if (isInited) - { - isInited = false; + if (initialized) PHYSFS_deinit(); - } } const char *Filesystem::getName() const @@ -61,7 +58,7 @@ void Filesystem::init(const char *arg0) { if (!PHYSFS_init(arg0)) throw Exception(PHYSFS_getLastError()); - isInited = true; + initialized = true; } void Filesystem::setRelease(bool release) @@ -79,9 +76,9 @@ bool Filesystem::isRelease() const return release; } -bool Filesystem::setIdentity(const char *ident) +bool Filesystem::setIdentity(const char *ident, SearchOrder searchorder) { - if (!isInited) + if (!initialized) return false; std::string old_save_path = save_path_full; @@ -104,15 +101,16 @@ bool Filesystem::setIdentity(const char *ident) // save_path_relative: ./LOVE/game // save_path_full: C:\Documents and Settings\user\Application Data/LOVE/game + // We don't want old read-only save paths to accumulate when we set a new + // identity. + if (!old_save_path.empty()) + PHYSFS_removeFromSearchPath(old_save_path.c_str()); + + bool append = (searchorder == SEARCH_ORDER_LAST); + // Try to add the save directory to the search path. // (No error on fail, it means that the path doesn't exist). - if (PHYSFS_addToSearchPath(save_path_full.c_str(), 0)) - { - // We don't want old read-only save paths to accumulate when we set a - // new identity. - if (old_save_path.compare(save_path_full) != 0) - PHYSFS_removeFromSearchPath(old_save_path.c_str()); - } + PHYSFS_addToSearchPath(save_path_full.c_str(), append); return true; } @@ -124,7 +122,7 @@ const char *Filesystem::getIdentity() const bool Filesystem::setSource(const char *source) { - if (!isInited) + if (!initialized) return false; // Check whether directory is already set. @@ -143,7 +141,7 @@ bool Filesystem::setSource(const char *source) bool Filesystem::setupWriteDirectory() { - if (!isInited) + if (!initialized) return false; // These must all be set. @@ -182,9 +180,9 @@ bool Filesystem::setupWriteDirectory() return true; } -bool Filesystem::mount(const char *archive, const char *mountpoint) +bool Filesystem::mount(const char *archive, const char *mountpoint, SearchOrder searchorder) { - if (!isInited || !archive) + if (!initialized || !archive) return false; // Not allowed for safety reasons. @@ -205,12 +203,14 @@ bool Filesystem::mount(const char *archive, const char *mountpoint) realPath += LOVE_PATH_SEPARATOR; realPath += archive; - return PHYSFS_mount(realPath.c_str(), mountpoint, 0); + bool append = (searchorder == SEARCH_ORDER_LAST); + + return PHYSFS_mount(realPath.c_str(), mountpoint, append); } bool Filesystem::unmount(const char *archive) { - if (!isInited || !archive) + if (!initialized || !archive) return false; // Not allowed for safety reasons. @@ -535,6 +535,24 @@ int64 Filesystem::getSize(const char *filename) const return size; } +bool Filesystem::getConstant(const char *in, Filesystem::SearchOrder &out) +{ + return orders.find(in, out); +} + +bool Filesystem::getConstant(Filesystem::SearchOrder in, const char *&out) +{ + return orders.find(in, out); +} + +StringMap::Entry Filesystem::orderEntries[] = +{ + {"first", Filesystem::SEARCH_ORDER_FIRST}, + {"last", Filesystem::SEARCH_ORDER_LAST}, +}; + +StringMap Filesystem::orders(Filesystem::orderEntries, sizeof(Filesystem::orderEntries)); + } // physfs } // filesystem } // love diff --git a/src/modules/filesystem/physfs/Filesystem.h b/src/modules/filesystem/physfs/Filesystem.h index 06d340a5a..422c857bd 100644 --- a/src/modules/filesystem/physfs/Filesystem.h +++ b/src/modules/filesystem/physfs/Filesystem.h @@ -31,6 +31,7 @@ #include "common/Module.h" #include "common/config.h" #include "common/int.h" +#include "common/StringMap.h" #include "filesystem/FileData.h" #include "File.h" @@ -71,46 +72,19 @@ namespace filesystem { namespace physfs { + class Filesystem : public Module { -private: - - // Counts open files. - int open_count; - - // Pointer used for file reads. - char *buffer; - - // Contains the current working directory (UTF8). - std::string cwd; - - // %APPDATA% on Windows. - std::string appdata; - - // This name will be used to create the folder - // in the appdata/userdata folder. - std::string save_identity; - - // Full and relative paths of the game save folder. - // (Relative to the %APPDATA% folder, meaning that the - // relative string will look something like: ./LOVE/game) - std::string save_path_relative, save_path_full; - - // The full path to the source of the game. - std::string game_source; - - // Workaround for machines without PhysFS 2.0 - bool isInited; - - // Allow saving outside of the LOVE_APPDATA_FOLDER - // for release 'builds' - bool release; - bool releaseSet; - -protected: - public: + // love.filesystem.setIdentity("foo", "last") + enum SearchOrder + { + SEARCH_ORDER_FIRST, + SEARCH_ORDER_LAST, + SEARCH_ORDER_MAX_ENUM + }; + Filesystem(); ~Filesystem(); @@ -134,7 +108,7 @@ public: * @param ident The name of the game. Will be used to * to create the folder in the LOVE data folder. **/ - bool setIdentity(const char *ident); + bool setIdentity(const char *ident, SearchOrder searchorder = SEARCH_ORDER_FIRST); const char *getIdentity() const; /** @@ -143,7 +117,8 @@ public: * @param source Path to a directory or a .love-file. **/ bool setSource(const char *source); - bool mount(const char *archive, const char *mountpoint); + + bool mount(const char *archive, const char *mountpoint, SearchOrder searchorder = SEARCH_ORDER_FIRST); bool unmount(const char *archive); /** @@ -300,6 +275,46 @@ public: **/ static int lines_i(lua_State *L); + static bool getConstant(const char *in, SearchOrder &out); + static bool getConstant(SearchOrder in, const char *&out); + +private: + + // Counts open files. + int open_count; + + // Pointer used for file reads. + char *buffer; + + // Contains the current working directory (UTF8). + std::string cwd; + + // %APPDATA% on Windows. + std::string appdata; + + // This name will be used to create the folder + // in the appdata/userdata folder. + std::string save_identity; + + // Full and relative paths of the game save folder. + // (Relative to the %APPDATA% folder, meaning that the + // relative string will look something like: ./LOVE/game) + std::string save_path_relative, save_path_full; + + // The full path to the source of the game. + std::string game_source; + + // Workaround for machines without PhysFS 2.0 + bool initialized; + + // Allow saving outside of the LOVE_APPDATA_FOLDER + // for release 'builds' + bool release; + bool releaseSet; + + static StringMap::Entry orderEntries[]; + static StringMap orders; + }; // Filesystem } // physfs diff --git a/src/modules/filesystem/physfs/wrap_Filesystem.cpp b/src/modules/filesystem/physfs/wrap_Filesystem.cpp index 7ad939492..3a55d0c95 100644 --- a/src/modules/filesystem/physfs/wrap_Filesystem.cpp +++ b/src/modules/filesystem/physfs/wrap_Filesystem.cpp @@ -77,7 +77,13 @@ int w_setIdentity(lua_State *L) { const char *arg = luaL_checkstring(L, 1); - if (!instance->setIdentity(arg)) + Filesystem::SearchOrder order = Filesystem::SEARCH_ORDER_FIRST; + const char *ostr = lua_isnoneornil(L, 2) ? 0 : lua_tostring(L, 2); + + if (ostr && !Filesystem::getConstant(ostr, order)) + return luaL_error(L, "Invalid filesystem search order: %s", ostr); + + if (!instance->setIdentity(arg, order)) return luaL_error(L, "Could not set write directory."); return 0; @@ -104,7 +110,13 @@ int w_mount(lua_State *L) const char *archive = luaL_checkstring(L, 1); const char *mountpoint = luaL_checkstring(L, 2); - luax_pushboolean(L, instance->mount(archive, mountpoint)); + Filesystem::SearchOrder order = Filesystem::SEARCH_ORDER_FIRST; + const char *ostr = lua_isnoneornil(L, 3) ? 0 : lua_tostring(L, 3); + + if (ostr && !Filesystem::getConstant(ostr, order)) + return luaL_error(L, "Invalid filesystem search order: %s", ostr); + + luax_pushboolean(L, instance->mount(archive, mountpoint, order)); return 1; } diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 8987c4d9c..253a2a6aa 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -294,6 +294,7 @@ function love.init() }, console = false, -- Only relevant for windows. identity = false, + identityorder = "first", release = false, } @@ -381,8 +382,10 @@ function love.init() if love.filesystem then love.filesystem.setRelease(c.release and is_fused_game) - if c.identity then love.filesystem.setIdentity(c.identity) end - if love.filesystem.exists("main.lua") then require("main") end + love.filesystem.setIdentity(c.identity or love.filesystem.getIdentity(), c.identityorder) + if love.filesystem.exists("main.lua") then + require("main") + end end if no_game_code then diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 74516760b..cc28056c8 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -509,6 +509,8 @@ const unsigned char boot_lua[] = 0x66, 0x6f, 0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x0a, 0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, + 0x22, 0x66, 0x69, 0x72, 0x73, 0x74, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x49, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x66, 0x69, 0x6c, 0x65, @@ -652,14 +654,17 @@ const unsigned char boot_lua[] = 0x73, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x28, 0x63, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x2e, 0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, 0x63, 0x2e, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, + 0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, 0x63, 0x2e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, + 0x29, 0x2c, 0x20, 0x63, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x75, - 0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, - 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x29, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x5f, 0x67, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,