From bdb19085c47cdfeb2051020cb5564c6ecd9605c5 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Tue, 31 May 2022 02:06:42 +0200 Subject: [PATCH 1/2] Common: Add utility function for case-insensitive string comparison. --- Source/Core/Common/StringUtil.cpp | 8 ++++++++ Source/Core/Common/StringUtil.h | 1 + Source/Core/DiscIO/RiivolutionPatcher.cpp | 14 +++----------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Source/Core/Common/StringUtil.cpp b/Source/Core/Common/StringUtil.cpp index 1277a18f72..113d7b781a 100644 --- a/Source/Core/Common/StringUtil.cpp +++ b/Source/Core/Common/StringUtil.cpp @@ -704,4 +704,12 @@ void ToUpper(std::string* str) { std::transform(str->begin(), str->end(), str->begin(), [](char c) { return Common::ToUpper(c); }); } + +bool CaseInsensitiveEquals(std::string_view a, std::string_view b) +{ + if (a.size() != b.size()) + return false; + return std::equal(a.begin(), a.end(), b.begin(), + [](char ca, char cb) { return Common::ToLower(ca) == Common::ToLower(cb); }); +} } // namespace Common diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index 3ae97e5562..ed08e758dd 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -264,4 +264,5 @@ inline char ToUpper(char ch) } void ToLower(std::string* str); void ToUpper(std::string* str); +bool CaseInsensitiveEquals(std::string_view a, std::string_view b); } // namespace Common diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index 4b265599d8..f12664710d 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -320,14 +320,6 @@ static void ApplyPatchToFile(const Patch& patch, const File& file_patch, file_patch.m_fileoffset, file_patch.m_length, file_patch.m_resize); } -static bool CaseInsensitiveEquals(std::string_view a, std::string_view b) -{ - if (a.size() != b.size()) - return false; - return std::equal(a.begin(), a.end(), b.begin(), - [](char ca, char cb) { return Common::ToLower(ca) == Common::ToLower(cb); }); -} - static FSTBuilderNode* FindFileNodeInFST(std::string_view path, std::vector* fst, bool create_if_not_exists) { @@ -335,7 +327,7 @@ static FSTBuilderNode* FindFileNodeInFST(std::string_view path, std::vectorbegin(), fst->end(), [&](const FSTBuilderNode& node) { - return CaseInsensitiveEquals(node.m_filename, name); + return Common::CaseInsensitiveEquals(node.m_filename, name); }); if (it == fst->end()) @@ -377,7 +369,7 @@ static DiscIO::FSTBuilderNode* FindFilenameNodeInFST(std::string_view filename, if (result) return result; } - else if (CaseInsensitiveEquals(node.m_filename, filename)) + else if (Common::CaseInsensitiveEquals(node.m_filename, filename)) { return &node; } @@ -398,7 +390,7 @@ static void ApplyFilePatchToFST(const Patch& patch, const File& file, if (node) ApplyPatchToFile(patch, file, node); } - else if (dol_node && CaseInsensitiveEquals(file.m_disc, "main.dol")) + else if (dol_node && Common::CaseInsensitiveEquals(file.m_disc, "main.dol")) { // Special case: If the filename is "main.dol", we want to patch the main executable. ApplyPatchToFile(patch, file, dol_node); From a0974c18cd4a445940c737bf52904db3fc56c39e Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 15 Jan 2023 05:39:03 +0100 Subject: [PATCH 2/2] RiivolutionPatcher: Use capitalization of file that exists in the host file system if possible. Fixes https://bugs.dolphin-emu.org/issues/13138 --- Source/Core/DiscIO/RiivolutionPatcher.cpp | 30 ++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index f12664710d..0f9bbec3ca 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -64,7 +64,8 @@ FileDataLoaderHostFS::MakeAbsoluteFromRelative(std::string_view external_relativ return std::nullopt; #endif - std::string result = external_relative_path.starts_with('/') ? m_sd_root : m_patch_root; + const std::string& root = external_relative_path.starts_with('/') ? m_sd_root : m_patch_root; + std::string result = root; std::string_view work = external_relative_path; // Strip away all leading and trailing path separators. @@ -116,6 +117,33 @@ FileDataLoaderHostFS::MakeAbsoluteFromRelative(std::string_view external_relativ // Append path element to result string. result += '/'; result += element; + + // Riivolution assumes a case-insensitive file system, which means it's possible that an XML + // file references a 'file.bin' but the actual file is named 'File.bin' or 'FILE.BIN'. To + // preserve this behavior, we modify the file path to match any existing file in the file + // system, if one exists. + if (!::File::Exists(result)) + { + // Drop path element again so we can search in the directory. + result.erase(result.size() - element.size(), element.size()); + + // Re-attach an element that actually matches the capitalization in the host filesystem. + auto possible_files = ::File::ScanDirectoryTree(result, false); + bool found = false; + for (auto& f : possible_files.children) + { + if (Common::CaseInsensitiveEquals(element, f.virtualName)) + { + result += f.virtualName; + found = true; + break; + } + } + + // If there isn't any file that matches just use the given element. + if (!found) + result += element; + } } // If this was the last path element, we're done.