summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2023-02-28 01:17:05 +0100
committerGitHub <noreply@github.com>2023-02-28 01:17:05 +0100
commit73aaa01648dba5f9d13db9e21bfb29d41b1b8f81 (patch)
tree1a5fd580e407584646c65e3ca577cc0f219342fc /Source/Core
parent7586fc8134cee5c0d428b7ca2bf0e6d1cf103cf3 (diff)
parenta0974c18cd4a445940c737bf52904db3fc56c39e (diff)
Merge pull request #11444 from AdmiralCurtiss/riivolution-linux-host-fs
RiivolutionPatcher: Use capitalization of file that exists in the host file system if possible.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/StringUtil.cpp8
-rw-r--r--Source/Core/Common/StringUtil.h1
-rw-r--r--Source/Core/DiscIO/RiivolutionPatcher.cpp44
3 files changed, 41 insertions, 12 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..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.
@@ -320,14 +348,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<FSTBuilderNode>* fst,
bool create_if_not_exists)
{
@@ -335,7 +355,7 @@ static FSTBuilderNode* FindFileNodeInFST(std::string_view path, std::vector<FSTB
const bool is_file = path_separator == std::string_view::npos;
const std::string_view name = is_file ? path : path.substr(0, path_separator);
const auto it = std::find_if(fst->begin(), fst->end(), [&](const FSTBuilderNode& node) {
- return CaseInsensitiveEquals(node.m_filename, name);
+ return Common::CaseInsensitiveEquals(node.m_filename, name);
});
if (it == fst->end())
@@ -377,7 +397,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 +418,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);