diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index b9e3955888..991f63ec35 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -57,7 +57,7 @@ int fmt::CmpNoCase(const std::string& a, const std::string& b) return std::equal(a.begin(), a.end(), b.begin(), - [](const char& a, const char& b){return tolower(a) == tolower(b); }) + [](const char& a, const char& b){return ::tolower(a) == ::tolower(b); }) ? 0 : -1; } } @@ -133,4 +133,35 @@ std::vector fmt::split(const std::string& source, std::initializer_ } return std::move(result); +} + +std::string fmt::merge(std::vector source, const std::string& separator) +{ + std::string result; + + for (auto &s : source) + { + result += s + separator; + } + + return result; +} + +std::string fmt::merge(std::initializer_list> sources, const std::string& separator) +{ + std::string result; + + for (auto &v : sources) + { + result += fmt::merge(v, separator); + } + + return result; +} + +std::string fmt::tolower(std::string source) +{ + std::transform(source.begin(), source.end(), source.begin(), ::tolower); + + return source; } \ No newline at end of file diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 20a5fdcfc2..963bb8b1b8 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -194,4 +194,7 @@ namespace fmt{ std::vector rSplit(const std::string& source, const std::string& delim); std::vector split(const std::string& source, std::initializer_list separators, bool is_skip_empty = true); + std::string merge(std::vector source, const std::string& separator); + std::string merge(std::initializer_list> sources, const std::string& separator); + std::string tolower(std::string source); } diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp index 82e188ada3..f36c39c045 100644 --- a/rpcs3/Emu/FS/VFS.cpp +++ b/rpcs3/Emu/FS/VFS.cpp @@ -8,23 +8,9 @@ #undef CreateFile -int sort_devices(const void* _a, const void* _b) -{ - const vfsDevice& a = **(const vfsDevice**)_a; - const vfsDevice& b = **(const vfsDevice**)_b; - - if (a.GetPs3Path().length() > b.GetPs3Path().length()) return 1; - if (a.GetPs3Path().length() < b.GetPs3Path().length()) return -1; - - return 0; -} - std::vector simplify_path_blocks(const std::string& path) { - std::string lower_path = path; - std::transform(lower_path.begin(), lower_path.end(), lower_path.begin(), ::tolower); - - std::vector path_blocks = std::move(fmt::split(lower_path, { "/", "\\" })); + std::vector path_blocks = std::move(fmt::split(fmt::tolower(path), { "/", "\\" })); for (size_t i = 0; i < path_blocks.size(); ++i) { @@ -53,19 +39,11 @@ std::string simplify_path(const std::string& path, bool is_dir) if (is_dir) { - for (auto &dir : path_blocks) - { - result += dir + "/"; - } + result = fmt::merge(path_blocks, "/"); } else { - for (size_t i = 0; i < path_blocks.size() - 1; ++i) - { - result += path_blocks[i] + "/"; - } - - result += path_blocks[path_blocks.size() - 1]; + result = fmt::merge(std::vector(path_blocks.begin(), path_blocks.end() - 1), "/") + path_blocks[path_blocks.size() - 1]; } return result; @@ -76,12 +54,6 @@ VFS::~VFS() UnMountAll(); } -std::string VFS::FindEntry(const std::string &path) -{ - return path; - return cwd + "/" + path; -} - void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device) { std::string simpl_ps3_path = simplify_path(ps3_path, true); @@ -93,10 +65,43 @@ void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsD if (m_devices.size() > 1) { - //std::qsort(m_devices.GetPtr(), m_devices.GetCount(), sizeof(vfsDevice*), sort_devices); + std::sort(m_devices.begin(), m_devices.end(), [](vfsDevice *a, vfsDevice *b) { return b->GetPs3Path().length() < a->GetPs3Path().length(); }); } } +void VFS::Link(const std::string& mount_point, const std::string& ps3_path) +{ + links[simplify_path_blocks(mount_point)] = simplify_path_blocks(ps3_path); +} + +std::string VFS::GetLinked(std::string ps3_path) const +{ + ps3_path = fmt::tolower(ps3_path); + auto path_blocks = fmt::split(ps3_path, { "/", "\\" }); + + for (auto link : links) + { + if (path_blocks.size() < link.first.size()) + continue; + + bool is_ok = true; + + for (size_t i = 0; i < link.first.size(); ++i) + { + if (link.first[i] != path_blocks[i]) + { + is_ok = false; + break; + } + } + + if (is_ok) + return fmt::merge({ link.second, std::vector(path_blocks.begin() + link.first.size(), path_blocks.end()) }, "/"); + } + + return ps3_path; +} + void VFS::UnMount(const std::string& ps3_path) { std::string simpl_ps3_path = simplify_path(ps3_path, true); @@ -285,8 +290,9 @@ bool VFS::RenameDir(const std::string& ps3_path_from, const std::string& ps3_pat vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const { - auto try_get_device = [this, &path](const std::vector& ps3_path_blocks) -> vfsDevice* + auto try_get_device = [this, &path](const std::string& ps3_path) -> vfsDevice* { + std::vector ps3_path_blocks = simplify_path_blocks(ps3_path); size_t max_eq = 0; int max_i = -1; @@ -328,10 +334,10 @@ vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const return m_devices[max_i]; }; - if (auto res = try_get_device(simplify_path_blocks(ps3_path))) + if (auto res = try_get_device(GetLinked(ps3_path))) return res; - if (auto res = try_get_device(simplify_path_blocks(cwd + ps3_path))) + if (auto res = try_get_device(GetLinked(cwd + ps3_path))) return res; return nullptr; @@ -415,6 +421,8 @@ void VFS::Init(const std::string& path) fmt::Replace(mpath, "$(GameDir)", cwd); Mount(entry.mount, mpath, dev); } + + Link("/app_home/", cwd); } void VFS::SaveLoadDevices(std::vector& res, bool is_load) @@ -434,7 +442,6 @@ void VFS::SaveLoadDevices(std::vector& res, bool is_load) res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/"); - res.emplace_back(vfsDevice_LocalFile, "$(GameDir)", "/app_home/"); res.emplace_back(vfsDevice_LocalFile, "$(GameDir)/../", "/dev_bdvd/"); res.emplace_back(vfsDevice_LocalFile, "", "/host_root/"); diff --git a/rpcs3/Emu/FS/VFS.h b/rpcs3/Emu/FS/VFS.h index acaccf17ec..aad5121211 100644 --- a/rpcs3/Emu/FS/VFS.h +++ b/rpcs3/Emu/FS/VFS.h @@ -1,4 +1,5 @@ #pragma once +#include class vfsDevice; struct vfsFileBase; @@ -51,18 +52,30 @@ struct VFS std::string cwd; - std::string FindEntry(const std::string &path); - //TODO: find out where these are supposed to be deleted or just make it shared_ptr //and also make GetDevice and GetDeviceLocal return shared_ptr then. // A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed. // This will cause problems if other code stores the pointer returned by GetDevice/GetDeviceLocal // and tries to use it after the device is unmounted. std::vector m_devices; + + struct links_sorter + { + bool operator()(const std::vector& a, const std::vector& b) + { + return b.size() < a.size(); + } + }; + + std::map, std::vector, links_sorter> links; + void Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device); + void Link(const std::string& mount_point, const std::string& ps3_path); void UnMount(const std::string& ps3_path); void UnMountAll(); + std::string GetLinked(std::string ps3_path) const; + vfsFileBase* OpenFile(const std::string& ps3_path, vfsOpenMode mode) const; vfsDirBase* OpenDir(const std::string& ps3_path) const; bool CreateFile(const std::string& ps3_path) const; diff --git a/rpcs3/Emu/FS/vfsDir.cpp b/rpcs3/Emu/FS/vfsDir.cpp index 7d483d8b3d..a6e2cc565f 100644 --- a/rpcs3/Emu/FS/vfsDir.cpp +++ b/rpcs3/Emu/FS/vfsDir.cpp @@ -29,7 +29,7 @@ bool vfsDir::Open(const std::string& path) DirEntryInfo info; - m_cwd = simplify_path(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path, true); + m_cwd = simplify_path(Emu.GetVFS().GetLinked(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path), true); auto blocks = simplify_path_blocks(GetPath());