From 0706b6243cbe2815ad38aeff9aa87b9585dbed4b Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 3 Oct 2020 19:28:57 -0300 Subject: [PATCH] Add love.filesystem.mountFullPath. --- .../xcode/liblove.xcodeproj/project.pbxproj | 8 + src/common/StringMap.h | 15 + src/common/apple.h | 50 +++ src/common/apple.mm | 76 +++++ src/common/ios.h | 15 - src/common/ios.mm | 47 +-- src/common/macos.h | 7 - src/common/macos.mm | 28 -- src/modules/filesystem/Filesystem.cpp | 47 ++- src/modules/filesystem/Filesystem.h | 35 +- src/modules/filesystem/physfs/Filesystem.cpp | 299 +++++++++++++----- src/modules/filesystem/physfs/Filesystem.h | 7 + src/modules/filesystem/wrap_Filesystem.cpp | 68 ++++ 13 files changed, 494 insertions(+), 208 deletions(-) create mode 100644 src/common/apple.h create mode 100644 src/common/apple.mm diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index ce4d481ca..dbb37e172 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -960,6 +960,8 @@ FAAA3FDA1F64B3AD00F89E99 /* lstrlib.h in Headers */ = {isa = PBXBuildFile; fileRef = FAAA3FD51F64B3AD00F89E99 /* lstrlib.h */; }; FAAA3FDB1F64B3AD00F89E99 /* lutf8lib.c in Sources */ = {isa = PBXBuildFile; fileRef = FAAA3FD61F64B3AD00F89E99 /* lutf8lib.c */; }; FAAA3FDC1F64B3AD00F89E99 /* lutf8lib.h in Headers */ = {isa = PBXBuildFile; fileRef = FAAA3FD71F64B3AD00F89E99 /* lutf8lib.h */; }; + FAAC2F79251A9D2200BCB81B /* apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAAC2F78251A9D2200BCB81B /* apple.mm */; }; + FAAC2F7A251A9D2200BCB81B /* apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAAC2F78251A9D2200BCB81B /* apple.mm */; }; FAAFF04416CB11C700CCDE45 /* OpenAL-Soft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */; }; FAB17BE61ABFAA9000F9BA27 /* lz4.c in Sources */ = {isa = PBXBuildFile; fileRef = FAB17BE41ABFAA9000F9BA27 /* lz4.c */; }; FAB17BE71ABFAA9000F9BA27 /* lz4.c in Sources */ = {isa = PBXBuildFile; fileRef = FAB17BE41ABFAA9000F9BA27 /* lz4.c */; }; @@ -1916,6 +1918,8 @@ FAAA3FD51F64B3AD00F89E99 /* lstrlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lstrlib.h; sourceTree = ""; }; FAAA3FD61F64B3AD00F89E99 /* lutf8lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lutf8lib.c; sourceTree = ""; }; FAAA3FD71F64B3AD00F89E99 /* lutf8lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lutf8lib.h; sourceTree = ""; }; + FAAC2F78251A9D2200BCB81B /* apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = apple.mm; sourceTree = ""; }; + FAAC2F7F251A9D3E00BCB81B /* apple.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = apple.h; sourceTree = ""; }; FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "OpenAL-Soft.framework"; path = "/Library/Frameworks/OpenAL-Soft.framework"; sourceTree = ""; }; FAB17BE41ABFAA9000F9BA27 /* lz4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lz4.c; sourceTree = ""; }; FAB17BE51ABFAA9000F9BA27 /* lz4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lz4.h; sourceTree = ""; }; @@ -2189,6 +2193,8 @@ children = ( FAA3A9AC1B7D465A00CED060 /* android.cpp */, FAA3A9AD1B7D465A00CED060 /* android.h */, + FAAC2F7F251A9D3E00BCB81B /* apple.h */, + FAAC2F78251A9D2200BCB81B /* apple.mm */, FA0B78F71A958E3B000E1D17 /* b64.cpp */, FA0B78F81A958E3B000E1D17 /* b64.h */, FA6BDE5B1F31725300786805 /* Color.h */, @@ -4649,6 +4655,7 @@ FA0B7E1F1A95902C000E1D17 /* Physics.cpp in Sources */, FA6A2B7B1F60B8250074C308 /* wrap_ByteData.cpp in Sources */, FA0B7E821A95902C000E1D17 /* Shape.cpp in Sources */, + FAAC2F7A251A9D2200BCB81B /* apple.mm in Sources */, FA0B7ACE1A958EA3000E1D17 /* packet.c in Sources */, FAF140891E20934C00F898D2 /* PoolAlloc.cpp in Sources */, FA27B3B41B498151008A9DCE /* wrap_Video.cpp in Sources */, @@ -5045,6 +5052,7 @@ FAF140881E20934C00F898D2 /* PoolAlloc.cpp in Sources */, FA0B7AAD1A958EA3000E1D17 /* b2WheelJoint.cpp in Sources */, FA0B7DEE1A95902C000E1D17 /* Mouse.cpp in Sources */, + FAAC2F79251A9D2200BCB81B /* apple.mm in Sources */, FAA54ACC1F91660400A8FA7B /* TheoraVideoStream.cpp in Sources */, FA1E887E1DF363CD00E808AA /* Filter.cpp in Sources */, FA0B7D281A95902C000E1D17 /* wrap_GlyphData.cpp in Sources */, diff --git a/src/common/StringMap.h b/src/common/StringMap.h index 4e6dc25de..b373e8f32 100644 --- a/src/common/StringMap.h +++ b/src/common/StringMap.h @@ -197,6 +197,21 @@ bool getConstant(const char *in, type &out) { return name##s.find(in, out); } \ bool getConstant(type in, const char *&out) { return name##s.find(in, out); } \ std::vector getConstants(type) { return name##s.getNames(); } +#define STRINGMAP_CLASS_DECLARE(type) \ +static bool getConstant(const char *in, type &out); \ +static bool getConstant(type in, const char *&out); \ +static std::vector getConstants(type); \ + +#define STRINGMAP_CLASS_BEGIN(classname, type, count, name) \ +static StringMap::Entry name##Entries[] = + +#define STRINGMAP_CLASS_END(classname, type, count, name) \ +; \ +static StringMap name##s(name##Entries, sizeof(name##Entries)); \ +bool classname::getConstant(const char *in, type &out) { return name##s.find(in, out); } \ +bool classname::getConstant(type in, const char *&out) { return name##s.find(in, out); } \ +std::vector classname::getConstants(type) { return name##s.getNames(); } + } // love #endif // LOVE_STRING_MAP_H diff --git a/src/common/apple.h b/src/common/apple.h new file mode 100644 index 000000000..a2edcda6b --- /dev/null +++ b/src/common/apple.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2006-2020 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#pragma once + +#include "config.h" + +#if defined(LOVE_IOS) || defined(LOVE_MACOS) + +#include + +namespace love +{ +namespace apple +{ + +enum UserDirectory +{ + USER_DIRECTORY_HOME, + USER_DIRECTORY_APPSUPPORT, + USER_DIRECTORY_DOCUMENTS, + USER_DIRECTORY_DESKTOP, + USER_DIRECTORY_CACHES, +}; + +std::string getUserDirectory(UserDirectory dir); + +std::string getExecutablePath(); + +} // apple +} // love + +#endif // defined(LOVE_IOS) || defined(LOVE_MACOS) diff --git a/src/common/apple.mm b/src/common/apple.mm new file mode 100644 index 000000000..9b27152dc --- /dev/null +++ b/src/common/apple.mm @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2006-2020 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "apple.h" + +#if defined(LOVE_IOS) || defined(LOVE_MACOS) + +#import + +namespace love +{ +namespace apple +{ + +std::string getUserDirectory(UserDirectory dir) +{ + std::string path; + NSSearchPathDirectory nsdir = NSTrashDirectory; + + @autoreleasepool + { + switch (dir) + { + case USER_DIRECTORY_HOME: + return NSHomeDirectory().UTF8String; + case USER_DIRECTORY_APPSUPPORT: + nsdir = NSApplicationSupportDirectory; + break; + case USER_DIRECTORY_DOCUMENTS: + nsdir = NSDocumentDirectory; + break; + case USER_DIRECTORY_DESKTOP: + nsdir = NSDesktopDirectory; + break; + case USER_DIRECTORY_CACHES: + nsdir = NSCachesDirectory; + break; + } + + NSArray *dirs = [[NSFileManager defaultManager] URLsForDirectory:nsdir inDomains:NSUserDomainMask]; + if (dirs.count > 0) + path = [dirs[0].path UTF8String]; + } + + return path; +} + +std::string getExecutablePath() +{ + @autoreleasepool + { + return std::string([NSBundle mainBundle].executablePath.UTF8String); + } +} + +} // apple +} // love + +#endif // defined(LOVE_IOS) || defined(LOVE_MACOS) diff --git a/src/common/ios.h b/src/common/ios.h index 8e436d94b..b07a05609 100644 --- a/src/common/ios.h +++ b/src/common/ios.h @@ -42,27 +42,12 @@ namespace ios **/ std::string getLoveInResources(bool &fused); -/** - * Gets the directory path where files should be stored. - **/ -std::string getAppdataDirectory(); - -/** - * Get the home directory (on iOS, this really means the app's sandbox dir.) - **/ -std::string getHomeDirectory(); - /** * Opens the specified URL with the default program associated with the URL's * scheme. **/ bool openURL(const std::string &url); -/** - * Returns the full path to the executable. - **/ -std::string getExecutablePath(); - /** * Causes devices with vibration support to vibrate for about 0.5 seconds. **/ diff --git a/src/common/ios.mm b/src/common/ios.mm index 648b56c61..bcc0bdbfc 100644 --- a/src/common/ios.mm +++ b/src/common/ios.mm @@ -19,6 +19,7 @@ **/ #include "ios.h" +#include "apple.h" #ifdef LOVE_IOS @@ -125,12 +126,6 @@ static bool deleteFileInDocuments(NSString *filename); @end -static NSString *getDocumentsDirectory() -{ - NSArray *docdirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - return docdirs[0]; -} - static NSArray *getLovesInDocuments() { NSMutableArray *paths = [NSMutableArray new]; @@ -287,38 +282,6 @@ std::string getLoveInResources(bool &fused) return path; } -static std::string getUserDirectory(NSSearchPathDirectory dir) -{ - std::string path; - - @autoreleasepool - { - NSArray *dirs = [[NSFileManager defaultManager] URLsForDirectory:dir inDomains:NSUserDomainMask]; - - if (dirs.count > 0) - path = [dirs[0].path UTF8String]; - } - - return path; -} - -std::string getAppdataDirectory() -{ - return getUserDirectory(NSApplicationSupportDirectory); -} - -std::string getHomeDirectory() -{ - std::string path; - - @autoreleasepool - { - path = [NSHomeDirectory() UTF8String]; - } - - return path; -} - bool openURL(const std::string &url) { bool success = false; @@ -335,14 +298,6 @@ bool openURL(const std::string &url) return success; } -std::string getExecutablePath() -{ - @autoreleasepool - { - return std::string([NSBundle mainBundle].executablePath.UTF8String); - } -} - void vibrate() { @autoreleasepool diff --git a/src/common/macos.h b/src/common/macos.h index a3fcbdd9d..297c8f116 100644 --- a/src/common/macos.h +++ b/src/common/macos.h @@ -31,8 +31,6 @@ namespace love namespace macos { -std::string getAppdataDirectory(); - /** * Returns the filepath of the first detected love file in the Resources folder * in the main bundle (love.app.) @@ -46,11 +44,6 @@ std::string getLoveInResources(); **/ std::string checkDropEvents(); -/** - * Returns the full path to the executable. - **/ -std::string getExecutablePath(); - /** * Bounce the dock icon, if the app isn't in the foreground. **/ diff --git a/src/common/macos.mm b/src/common/macos.mm index 1ee165a5b..06edf8a37 100644 --- a/src/common/macos.mm +++ b/src/common/macos.mm @@ -36,26 +36,6 @@ namespace love namespace macos { -static std::string getUserDirectory(NSSearchPathDirectory dir) -{ - std::string path; - - @autoreleasepool - { - NSArray *dirs = [[NSFileManager defaultManager] URLsForDirectory:dir inDomains:NSUserDomainMask]; - - if (dirs.count > 0) - path = [dirs[0].path UTF8String]; - } - - return path; -} - -std::string getAppdataDirectory() -{ - return getUserDirectory(NSApplicationSupportDirectory); -} - std::string getLoveInResources() { std::string path; @@ -94,14 +74,6 @@ std::string checkDropEvents() return dropstr; } -std::string getExecutablePath() -{ - @autoreleasepool - { - return std::string([NSBundle mainBundle].executablePath.UTF8String); - } -} - void requestAttention(bool continuous) { @autoreleasepool diff --git a/src/modules/filesystem/Filesystem.cpp b/src/modules/filesystem/Filesystem.cpp index 109b3c942..56f028ae9 100644 --- a/src/modules/filesystem/Filesystem.cpp +++ b/src/modules/filesystem/Filesystem.cpp @@ -26,10 +26,8 @@ #include #include -#if defined(LOVE_MACOS) -#include "common/macos.h" -#elif defined(LOVE_IOS) -#include "common/ios.h" +#if defined(LOVE_MACOS) || defined(LOVE_IOS) +#include "common/apple.h" #elif defined(LOVE_WINDOWS) #include #include "common/utf8.h" @@ -92,10 +90,8 @@ bool Filesystem::isRealDirectory(const std::string &path) const std::string Filesystem::getExecutablePath() const { -#if defined(LOVE_MACOS) - return love::macos::getExecutablePath(); -#elif defined(LOVE_IOS) - return love::ios::getExecutablePath(); +#if defined(LOVE_MACOS) || defined(LOVE_IOS) + return love::apple::getExecutablePath(); #elif defined(LOVE_WINDOWS) wchar_t buffer[MAX_PATH + 1] = {0}; @@ -120,30 +116,33 @@ std::string Filesystem::getExecutablePath() const #endif } -bool Filesystem::getConstant(const char *in, FileType &out) +STRINGMAP_CLASS_BEGIN(Filesystem, Filesystem::FileType, Filesystem::FILETYPE_MAX_ENUM, fileType) { - return fileTypes.find(in, out); + { "file", Filesystem::FILETYPE_FILE }, + { "directory", Filesystem::FILETYPE_DIRECTORY }, + { "symlink", Filesystem::FILETYPE_SYMLINK }, + { "other", Filesystem::FILETYPE_OTHER }, } +STRINGMAP_CLASS_END(Filesystem, Filesystem::FileType, Filesystem::FILETYPE_MAX_ENUM, fileType) -bool Filesystem::getConstant(FileType in, const char *&out) +STRINGMAP_CLASS_BEGIN(Filesystem, Filesystem::CommonPath, Filesystem::COMMONPATH_MAX_ENUM, commonPath) { - return fileTypes.find(in, out); + { "appidentity", Filesystem::COMMONPATH_APP_IDENTITY }, + { "appdocuments", Filesystem::COMMONPATH_APP_DOCUMENTS }, + { "apptemp", Filesystem::COMMONPATH_APP_TEMP }, + { "userhome", Filesystem::COMMONPATH_USER_HOME }, + { "userappdata", Filesystem::COMMONPATH_USER_APPDATA }, + { "userdesktop", Filesystem::COMMONPATH_USER_DESKTOP }, + { "userdocuments", Filesystem::COMMONPATH_USER_DOCUMENTS }, } +STRINGMAP_CLASS_END(Filesystem, Filesystem::CommonPath, Filesystem::COMMONPATH_MAX_ENUM, commonPath) -std::vector Filesystem::getConstants(FileType) +STRINGMAP_CLASS_BEGIN(Filesystem, Filesystem::MountPermissions, Filesystem::MOUNT_PERMISSIONS_MAX_ENUM, mountPermissions) { - return fileTypes.getNames(); + { "read", Filesystem::MOUNT_PERMISSIONS_READ }, + { "readwrite", Filesystem::MOUNT_PERMISSIONS_READWRITE }, } - -StringMap::Entry Filesystem::fileTypeEntries[] = -{ - { "file", FILETYPE_FILE }, - { "directory", FILETYPE_DIRECTORY }, - { "symlink", FILETYPE_SYMLINK }, - { "other", FILETYPE_OTHER }, -}; - -StringMap Filesystem::fileTypes(Filesystem::fileTypeEntries, sizeof(Filesystem::fileTypeEntries)); +STRINGMAP_CLASS_END(Filesystem, Filesystem::MountPermissions, Filesystem::MOUNT_PERMISSIONS_MAX_ENUM, mountPermissions) } // filesystem } // love diff --git a/src/modules/filesystem/Filesystem.h b/src/modules/filesystem/Filesystem.h index 715a35f80..444b18d41 100644 --- a/src/modules/filesystem/Filesystem.h +++ b/src/modules/filesystem/Filesystem.h @@ -71,6 +71,25 @@ public: FILETYPE_MAX_ENUM }; + enum CommonPath + { + COMMONPATH_APP_IDENTITY, + COMMONPATH_APP_DOCUMENTS, + COMMONPATH_APP_TEMP, + COMMONPATH_USER_HOME, + COMMONPATH_USER_APPDATA, + COMMONPATH_USER_DESKTOP, + COMMONPATH_USER_DOCUMENTS, + COMMONPATH_MAX_ENUM + }; + + enum MountPermissions + { + MOUNT_PERMISSIONS_READ, + MOUNT_PERMISSIONS_READWRITE, + MOUNT_PERMISSIONS_MAX_ENUM + }; + struct Info { // Numbers will be -1 if they cannot be determined. @@ -136,8 +155,13 @@ public: virtual bool mount(const char *archive, const char *mountpoint, bool appendToPath = false) = 0; virtual bool mount(Data *data, const char *archivename, const char *mountpoint, bool appendToPath = false) = 0; + + virtual bool mountFullPath(const char *archive, const char *mountpoint, MountPermissions permissions, bool appendToPath = false) = 0; + virtual bool mountCommonPath(CommonPath path, const char *mountpoint, MountPermissions permissions, bool appendToPath = false) = 0; + virtual bool unmount(const char *archive) = 0; virtual bool unmount(Data *data) = 0; + virtual bool unmount(CommonPath path) = 0; /** * Creates a new file. @@ -152,6 +176,8 @@ public: **/ virtual FileData *newFileData(const void *data, size_t size, const char *filename) const; + virtual std::string getFullCommonPath(CommonPath path) = 0; + /** * Gets the current working directory. **/ @@ -263,18 +289,15 @@ public: **/ virtual std::string getExecutablePath() const; - static bool getConstant(const char *in, FileType &out); - static bool getConstant(FileType in, const char *&out); - static std::vector getConstants(FileType); + STRINGMAP_CLASS_DECLARE(FileType); + STRINGMAP_CLASS_DECLARE(CommonPath); + STRINGMAP_CLASS_DECLARE(MountPermissions); private: // Should we save external or internal for Android bool useExternal; - static StringMap::Entry fileTypeEntries[]; - static StringMap fileTypes; - }; // Filesystem } // filesystem diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index 99b0d6ff5..a5f8a042a 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -45,6 +45,10 @@ # include #endif +#if defined(LOVE_IOS) || defined(LOVE_MACOS) +# include "common/apple.h" +#endif + #ifdef LOVE_IOS # include "common/ios.h" #endif @@ -60,44 +64,6 @@ #include "common/android.h" #endif -namespace -{ - size_t getDriveDelim(const std::string &input) - { - for (size_t i = 0; i < input.size(); ++i) - if (input[i] == '/' || input[i] == '\\') - return i; - // Something's horribly wrong - return 0; - } - - std::string getDriveRoot(const std::string &input) - { - return input.substr(0, getDriveDelim(input)+1); - } - - std::string skipDriveRoot(const std::string &input) - { - return input.substr(getDriveDelim(input)+1); - } - - std::string normalize(const std::string &input) - { - std::stringstream out; - bool seenSep = false, isSep = false; - for (size_t i = 0; i < input.size(); ++i) - { - isSep = (input[i] == LOVE_PATH_SEPARATOR[0]); - if (!isSep || !seenSep) - out << input[i]; - seenSep = isSep; - } - - return out.str(); - } - -} - namespace love { namespace filesystem @@ -105,6 +71,53 @@ namespace filesystem namespace physfs { +static size_t getDriveDelim(const std::string &input) +{ + for (size_t i = 0; i < input.size(); ++i) + if (input[i] == '/' || input[i] == '\\') + return i; + // Something's horribly wrong + return 0; +} + +static std::string getDriveRoot(const std::string &input) +{ + return input.substr(0, getDriveDelim(input)+1); +} + +static std::string skipDriveRoot(const std::string &input) +{ + return input.substr(getDriveDelim(input)+1); +} + +static std::string normalize(const std::string &input) +{ + std::stringstream out; + bool seenSep = false, isSep = false; + for (size_t i = 0; i < input.size(); ++i) + { + isSep = (input[i] == LOVE_PATH_SEPARATOR[0]); + if (!isSep || !seenSep) + out << input[i]; + seenSep = isSep; + } + + return out.str(); +} + +static bool isAppCommonPath(Filesystem::CommonPath path) +{ + switch (path) + { + case Filesystem::COMMONPATH_APP_IDENTITY: + case Filesystem::COMMONPATH_APP_DOCUMENTS: + case Filesystem::COMMONPATH_APP_TEMP: + return true; + default: + return false; + } +} + Filesystem::Filesystem() : fused(false) , fusedSet(false) @@ -159,15 +172,13 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath) save_identity = std::string(ident); // Generate the relative path to the game save folder. - save_path_relative = std::string(LOVE_APPDATA_PREFIX LOVE_APPDATA_FOLDER LOVE_PATH_SEPARATOR) + save_identity; + if (fused) + save_path_relative = std::string(LOVE_APPDATA_PREFIX) + save_identity; + else + save_path_relative = std::string(LOVE_APPDATA_PREFIX LOVE_APPDATA_FOLDER LOVE_PATH_SEPARATOR) + save_identity; // Generate the full path to the game save folder. - save_path_full = std::string(getAppdataDirectory()) + std::string(LOVE_PATH_SEPARATOR); - if (fused) - save_path_full += std::string(LOVE_APPDATA_PREFIX) + save_identity; - else - save_path_full += save_path_relative; - + save_path_full = std::string(getAppdataDirectory()) + std::string(LOVE_PATH_SEPARATOR) + save_path_relative; save_path_full = normalize(save_path_full); #ifdef LOVE_ANDROID @@ -370,10 +381,35 @@ bool Filesystem::mount(const char *archive, const char *mountpoint, bool appendT realPath += archive; } - if (realPath.length() == 0) + return mountFullPath(realPath.c_str(), mountpoint, MOUNT_PERMISSIONS_READ, appendToPath); +} + +bool Filesystem::mountFullPath(const char *archive, const char *mountpoint, MountPermissions permissions, bool appendToPath) +{ + if (!PHYSFS_isInit() || !archive || !mountpoint) return false; - return PHYSFS_mount(realPath.c_str(), mountpoint, appendToPath) != 0; + if (permissions == MOUNT_PERMISSIONS_READWRITE && strlen(mountpoint) == 0) + return false; + + // TODO: readwrite mount + return PHYSFS_mount(archive, mountpoint, appendToPath) != 0; +} + +bool Filesystem::mountCommonPath(CommonPath path, const char *mountpoint, MountPermissions permissions, bool appendToPath) +{ + std::string fullpath = getFullCommonPath(path); + if (fullpath.empty()) + return false; + + bool success = mountFullPath(fullpath.c_str(), mountpoint, permissions, appendToPath); + + if (!success && isAppCommonPath(path)) + { + + } + + return success; } bool Filesystem::mount(Data *data, const char *archivename, const char *mountpoint, bool appendToPath) @@ -403,42 +439,35 @@ bool Filesystem::unmount(const char *archive) return true; } - std::string realPath; - std::string sourceBase = getSourceBaseDirectory(); + if (PHYSFS_getRealDir(archive) != nullptr) + return PHYSFS_unmount(archive) != 0; - // Check whether the given archive path is in the list of allowed full paths. - auto it = std::find(allowedMountPaths.begin(), allowedMountPaths.end(), archive); + if (strlen(archive) == 0 || strstr(archive, "..") || strcmp(archive, "/") == 0) + return false; - if (it != allowedMountPaths.end()) - realPath = *it; - else if (isFused() && sourceBase.compare(archive) == 0) - { - // Special case: if the game is fused and the archive is the source's - // base directory, unmount it even though it's outside of the save dir. - realPath = sourceBase; - } - else - { - // Not allowed for safety reasons. - if (strlen(archive) == 0 || strstr(archive, "..") || strcmp(archive, "/") == 0) - return false; + const char *realDir = PHYSFS_getRealDir(archive); + if (!realDir) + return false; - const char *realDir = PHYSFS_getRealDir(archive); - if (!realDir) - return false; + std::string realPath = realDir; + realPath += LOVE_PATH_SEPARATOR; + realPath += archive; - realPath = realDir; - realPath += LOVE_PATH_SEPARATOR; - realPath += archive; - } - - const char *mountPoint = PHYSFS_getMountPoint(realPath.c_str()); - if (!mountPoint) + if (PHYSFS_getMountPoint(realPath.c_str()) == nullptr) return false; return PHYSFS_unmount(realPath.c_str()) != 0; } +bool Filesystem::unmount(CommonPath path) +{ + std::string fullpath = getFullCommonPath(path); + if (fullpath.empty()) + return false; + + return unmount(fullpath.c_str()); +} + bool Filesystem::unmount(Data *data) { for (const auto &datapair : mountedData) @@ -458,6 +487,115 @@ love::filesystem::File *Filesystem::newFile(const char *filename) const return new File(filename); } +std::string Filesystem::getFullCommonPath(CommonPath path) +{ + if (!fullCommonPaths[path].empty()) + return fullCommonPaths[path]; + + if (path == COMMONPATH_APP_IDENTITY || path == COMMONPATH_APP_DOCUMENTS || path == COMMONPATH_APP_TEMP) + { + + } + +#if defined(LOVE_MACOS) || defined(LOVE_IOS) + + switch (path) + { + case COMMONPATH_APP_IDENTITY: + case COMMONPATH_APP_DOCUMENTS: + case COMMONPATH_APP_TEMP: + // Handled above. + break; + case COMMONPATH_USER_HOME: + fullCommonPaths[path] = apple::getUserDirectory(apple::USER_DIRECTORY_HOME); + break; + case COMMONPATH_USER_APPDATA: + fullCommonPaths[path] = apple::getUserDirectory(apple::USER_DIRECTORY_APPSUPPORT); + break; + case COMMONPATH_USER_DESKTOP: + fullCommonPaths[path] = apple::getUserDirectory(apple::USER_DIRECTORY_DESKTOP); + break; + case COMMONPATH_USER_DOCUMENTS: + fullCommonPaths[path] = apple::getUserDirectory(apple::USER_DIRECTORY_DOCUMENTS); + break; + case COMMONPATH_MAX_ENUM: + break; + } + +#elif defined(LOVE_WINDOWS) + + PWSTR winpath = nullptr; + HRESULT hr = E_FAIL; + + switch (path) + { + case COMMONPATH_APP_IDENTITY: + case COMMONPATH_APP_DOCUMENTS: + case COMMONPATH_APP_TEMP: + // Handled above. + break; + case COMMONPATH_USER_HOME: + hr = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &winpath); + break; + case COMMONPATH_USER_APPDATA: + hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &winpath); + break; + case COMMONPATH_USER_DESKTOP: + hr = SHGetKnownFolderPath(FOLDERID_Desktop, 0, nullptr, &winpath); + break; + case COMMONPATH_USER_DOCUMENTS: + hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &winpath); + break; + case COMMONPATH_MAX_ENUM: + break; + } + + if (SUCCEEDED(hr)) + { + fullCommonPaths[path] = to_utf8(winpath); + CoTaskMemFree(winpath); + } + else + { + + } + +#elif defined(LOVE_ANDROID) + +#elif defined(LOVE_LINUX) + + const char *xdgdir = nullptr; + + switch (path) + { + case COMMONPATH_APP_IDENTITY: + case COMMONPATH_APP_DOCUMENTS: + case COMMONPATH_APP_TEMP: + // Handled above. + break; + case COMMONPATH_USER_HOME: + fullCommonPaths[path] = normalize(PHYSFS_getUserDir()); + break; + case COMMONPATH_USER_APPDATA: + xdgdir = getenv("XDG_DATA_HOME"); + if (!xdgdir) + fullCommonPaths[path] = normalize(std::string(getUserDirectory()) + "/.local/share/"); + else + fullCommonPaths[path] = xdgdir; + break; + case COMMONPATH_USER_DESKTOP: + break; + case COMMONPATH_USER_DOCUMENTS: + break; + case COMMONPATH_MAX_ENUM: + break; + } + +#endif + + return fullCommonPaths[path]; +} + const char *Filesystem::getWorkingDirectory() { if (cwd.empty()) @@ -474,7 +612,7 @@ const char *Filesystem::getWorkingDirectory() if (getcwd(cwd_char, LOVE_MAX_PATH)) cwd = cwd_char; // if getcwd fails, cwd_char (and thus cwd) will still be empty - delete [] cwd_char; + delete[] cwd_char; #endif } @@ -483,9 +621,9 @@ const char *Filesystem::getWorkingDirectory() std::string Filesystem::getUserDirectory() { -#ifdef LOVE_IOS +#if defined(LOVE_IOS) || defined(LOVE_MACOS) // PHYSFS_getUserDir doesn't give exactly the path we want on iOS. - static std::string userDir = normalize(love::ios::getHomeDirectory()); + static std::string userDir = normalize(apple::getUserDirectory(apple::USER_DIRECTORY_HOME)); #else static std::string userDir = normalize(PHYSFS_getUserDir()); #endif @@ -512,10 +650,8 @@ std::string Filesystem::getAppdataDirectory() appdata = to_utf8(w_appdata); } replace_char(appdata, '\\', '/'); -#elif defined(LOVE_MACOS) - appdata = normalize(love::macos::getAppdataDirectory()); -#elif defined(LOVE_IOS) - appdata = normalize(love::ios::getAppdataDirectory()); +#elif defined(LOVE_MACOS) || defined(LOVE_IOS) + appdata = normalize(apple::getUserDirectory(apple::USER_DIRECTORY_APPSUPPORT)); #elif defined(LOVE_LINUX) char *xdgdatahome = getenv("XDG_DATA_HOME"); if (!xdgdatahome) @@ -529,7 +665,6 @@ std::string Filesystem::getAppdataDirectory() return appdata; } - const char *Filesystem::getSaveDirectory() { return save_path_full.c_str(); diff --git a/src/modules/filesystem/physfs/Filesystem.h b/src/modules/filesystem/physfs/Filesystem.h index b66417f02..2ccfa9dc7 100644 --- a/src/modules/filesystem/physfs/Filesystem.h +++ b/src/modules/filesystem/physfs/Filesystem.h @@ -63,11 +63,16 @@ public: bool mount(const char *archive, const char *mountpoint, bool appendToPath = false) override; bool mount(Data *data, const char *archivename, const char *mountpoint, bool appendToPath = false) override; + bool mountFullPath(const char *archive, const char *mountpoint, MountPermissions permissions, bool appendToPath = false) override; + bool mountCommonPath(CommonPath path, const char *mountpoint, MountPermissions permissions, bool appendToPath = false) override; + bool unmount(const char *archive) override; bool unmount(Data *data) override; + bool unmount(CommonPath path) override; love::filesystem::File *newFile(const char *filename) const override; + std::string getFullCommonPath(CommonPath path) override; const char *getWorkingDirectory() override; std::string getUserDirectory() override; std::string getAppdataDirectory() override; @@ -129,6 +134,8 @@ private: std::map> mountedData; + std::string fullCommonPaths[COMMONPATH_MAX_ENUM]; + }; // Filesystem } // physfs diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 4ccb04670..59bd2ada7 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -148,6 +148,48 @@ int w_mount(lua_State *L) return 1; } +int w_mountFullPath(lua_State *L) +{ + const char *fullpath = luaL_checkstring(L, 1); + const char *mountpoint = luaL_checkstring(L, 2); + + auto permissions = Filesystem::MOUNT_PERMISSIONS_READ; + if (!lua_isnoneornil(L, 3)) + { + const char *permissionstr = luaL_checkstring(L, 3); + if (!Filesystem::getConstant(permissionstr, permissions)) + return luax_enumerror(L, "mount permissions", Filesystem::getConstants(permissions), permissionstr); + } + + bool append = luax_optboolean(L, 4, false); + + luax_pushboolean(L, instance()->mountFullPath(fullpath, mountpoint, permissions, append)); + return 1; +} + +int w_mountCommonPath(lua_State *L) +{ + const char *commonpathstr = luaL_checkstring(L, 1); + Filesystem::CommonPath commonpath; + if (!Filesystem::getConstant(commonpathstr, commonpath)) + return luax_enumerror(L, "common path", Filesystem::getConstants(commonpath), commonpathstr); + + const char *mountpoint = luaL_checkstring(L, 2); + + auto permissions = Filesystem::MOUNT_PERMISSIONS_READ; + if (!lua_isnoneornil(L, 3)) + { + const char *permissionstr = luaL_checkstring(L, 3); + if (!Filesystem::getConstant(permissionstr, permissions)) + return luax_enumerror(L, "mount permissions", Filesystem::getConstants(permissions), permissionstr); + } + + bool append = luax_optboolean(L, 4, false); + + luax_pushboolean(L, instance()->mountCommonPath(commonpath, mountpoint, permissions, append)); + return 1; +} + int w_unmount(lua_State *L) { if (luax_istype(L, 1, Data::type)) @@ -163,6 +205,17 @@ int w_unmount(lua_State *L) return 1; } +int w_unmountCommonPath(lua_State *L) +{ + const char *commonpathstr = luaL_checkstring(L, 1); + Filesystem::CommonPath commonpath; + if (!Filesystem::getConstant(commonpathstr, commonpath)) + return luax_enumerror(L, "common path", Filesystem::getConstants(commonpath), commonpathstr); + + luax_pushboolean(L, instance()->unmount(commonpath)); + return 1; +} + int w_newFile(lua_State *L) { const char *filename = luaL_checkstring(L, 1); @@ -331,6 +384,17 @@ int w_newFileData(lua_State *L) return 1; } +int w_getFullCommonPath(lua_State *L) +{ + const char *commonpathstr = luaL_checkstring(L, 1); + Filesystem::CommonPath commonpath; + if (!Filesystem::getConstant(commonpathstr, commonpath)) + return luax_enumerror(L, "common path", Filesystem::getConstants(commonpath), commonpathstr); + + luax_pushstring(L, instance()->getFullCommonPath(commonpath)); + return 1; +} + int w_getWorkingDirectory(lua_State *L) { lua_pushstring(L, instance()->getWorkingDirectory()); @@ -839,8 +903,12 @@ static const luaL_Reg functions[] = { "setSource", w_setSource }, { "getSource", w_getSource }, { "mount", w_mount }, + { "mountFullPath", w_mountFullPath }, +// { "mountCommonPath", w_mountCommonPath }, { "unmount", w_unmount }, +// { "unmountCommonPath", w_unmountCommonPath }, { "newFile", w_newFile }, +// { "getFullCommonPath", w_getFullCommonPath }, { "getWorkingDirectory", w_getWorkingDirectory }, { "getUserDirectory", w_getUserDirectory }, { "getAppdataDirectory", w_getAppdataDirectory },