From 136c563f76f68f83fc30984097b459f80becdef4 Mon Sep 17 00:00:00 2001
From: lat9nq <lat9nq@virginia.edu>
Date: Wed, 27 May 2020 23:12:56 -0400
Subject: [PATCH 1/3] *nix systems can read any-case patch directories

Changes many patch_manager functions to use a case-less variant of
GetSubdirectory. Fixes patches not showing up on *nix systems when
patch directories are named with odd cases, i.e. `exeFS'.
---
 src/core/file_sys/patch_manager.cpp | 35 ++++++++++++++++++++++-------
 src/core/file_sys/patch_manager.h   |  5 +++++
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index b93aa6935..3d1965abb 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -6,6 +6,7 @@
 #include <array>
 #include <cstddef>
 #include <cstring>
+#include <boost/algorithm/string/case_conv.hpp>
 
 #include "common/file_util.h"
 #include "common/hex_util.h"
@@ -48,6 +49,24 @@ std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
     return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]);
 }
 
+std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir,
+                                                       const std::string& name) {
+#ifdef _WIN32
+    return dir->GetSubdirectory(name);
+#else
+    const auto subdirs = dir->GetSubdirectories();
+    for (const auto& subdir : subdirs) {
+        std::string dir_name = subdir->GetName();
+        boost::algorithm::to_lower(dir_name);
+        if (dir_name == name) {
+            return subdir;
+        }
+    }
+
+    return nullptr;
+#endif
+}
+
 PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
 
 PatchManager::~PatchManager() = default;
@@ -104,7 +123,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
             if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
                 continue;
 
-            auto exefs_dir = subdir->GetSubdirectory("exefs");
+            auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs");
             if (exefs_dir != nullptr)
                 layers.push_back(std::move(exefs_dir));
         }
@@ -130,7 +149,7 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD
         if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend())
             continue;
 
-        auto exefs_dir = subdir->GetSubdirectory("exefs");
+        auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs");
         if (exefs_dir != nullptr) {
             for (const auto& file : exefs_dir->GetFiles()) {
                 if (file->GetExtension() == "ips") {
@@ -295,7 +314,7 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
             continue;
         }
 
-        auto cheats_dir = subdir->GetSubdirectory("cheats");
+        auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats");
         if (cheats_dir != nullptr) {
             auto res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, true);
             if (res.has_value()) {
@@ -340,11 +359,11 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
             continue;
         }
 
-        auto romfs_dir = subdir->GetSubdirectory("romfs");
+        auto romfs_dir = FindSubdirectoryCaseless(subdir, "romfs");
         if (romfs_dir != nullptr)
             layers.push_back(std::move(romfs_dir));
 
-        auto ext_dir = subdir->GetSubdirectory("romfs_ext");
+        auto ext_dir = FindSubdirectoryCaseless(subdir, "romfs_ext");
         if (ext_dir != nullptr)
             layers_ext.push_back(std::move(ext_dir));
     }
@@ -470,7 +489,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
         for (const auto& mod : mod_dir->GetSubdirectories()) {
             std::string types;
 
-            const auto exefs_dir = mod->GetSubdirectory("exefs");
+            const auto exefs_dir = FindSubdirectoryCaseless(mod, "exefs");
             if (IsDirValidAndNonEmpty(exefs_dir)) {
                 bool ips = false;
                 bool ipswitch = false;
@@ -494,9 +513,9 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
                 if (layeredfs)
                     AppendCommaIfNotEmpty(types, "LayeredExeFS");
             }
-            if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
+            if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "romfs")))
                 AppendCommaIfNotEmpty(types, "LayeredFS");
-            if (IsDirValidAndNonEmpty(mod->GetSubdirectory("cheats")))
+            if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "cheats")))
                 AppendCommaIfNotEmpty(types, "Cheats");
 
             if (types.empty())
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index ec6db524d..a1fb6694d 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -29,6 +29,11 @@ enum class TitleVersionFormat : u8 {
 std::string FormatTitleVersion(u32 version,
                                TitleVersionFormat format = TitleVersionFormat::ThreeElements);
 
+// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
+// doesn't have a directory with name.
+std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir,
+                                                       const std::string& name);
+
 // A centralized class to manage patches to games.
 class PatchManager {
 public:

From 326403518de42860778e9ac102ae04eb85ee1e85 Mon Sep 17 00:00:00 2001
From: lat9nq <lat9nq@virginia.edu>
Date: Thu, 28 May 2020 13:30:22 -0400
Subject: [PATCH 2/3] Address requested changes

---
 src/core/file_sys/patch_manager.cpp | 6 +++---
 src/core/file_sys/patch_manager.h   | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 3d1965abb..1002b688c 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -6,11 +6,11 @@
 #include <array>
 #include <cstddef>
 #include <cstring>
-#include <boost/algorithm/string/case_conv.hpp>
 
 #include "common/file_util.h"
 #include "common/hex_util.h"
 #include "common/logging/log.h"
+#include "common/string_util.h"
 #include "core/core.h"
 #include "core/file_sys/content_archive.h"
 #include "core/file_sys/control_metadata.h"
@@ -50,14 +50,14 @@ std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
 }
 
 std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir,
-                                                       const std::string& name) {
+                                                       std::string_view name) {
 #ifdef _WIN32
     return dir->GetSubdirectory(name);
 #else
     const auto subdirs = dir->GetSubdirectories();
     for (const auto& subdir : subdirs) {
         std::string dir_name = subdir->GetName();
-        boost::algorithm::to_lower(dir_name);
+        dir_name = Common::ToLower(dir_name);
         if (dir_name == name) {
             return subdir;
         }
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index a1fb6694d..f4cb918dd 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -32,7 +32,7 @@ std::string FormatTitleVersion(u32 version,
 // Returns a directory with name matching name case-insensitive. Returns nullptr if directory
 // doesn't have a directory with name.
 std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir,
-                                                       const std::string& name);
+                                                       std::string_view name);
 
 // A centralized class to manage patches to games.
 class PatchManager {

From f57cbd9f247ac43dbc9e599cc8523c9b8d93ad48 Mon Sep 17 00:00:00 2001
From: lat9nq <lat9nq@virginia.edu>
Date: Thu, 28 May 2020 13:33:50 -0400
Subject: [PATCH 3/3] Make copying directory string more concise

---
 src/core/file_sys/patch_manager.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 1002b688c..c47ff863e 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -56,8 +56,7 @@ std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<Vfs
 #else
     const auto subdirs = dir->GetSubdirectories();
     for (const auto& subdir : subdirs) {
-        std::string dir_name = subdir->GetName();
-        dir_name = Common::ToLower(dir_name);
+        std::string dir_name = Common::ToLower(subdir->GetName());
         if (dir_name == name) {
             return subdir;
         }