diff options
| author | JosJuice <josjuice@gmail.com> | 2019-05-29 09:16:03 +0200 |
|---|---|---|
| committer | JosJuice <josjuice@gmail.com> | 2019-05-29 14:53:39 +0200 |
| commit | f25367a7a274c351da568e1ce1e09b95ae0f1a60 (patch) | |
| tree | 768e9c35186ef3581b2899419c02374d9f3593ae /Source/Core | |
| parent | d4b069f4580b1cde512861cb3bfd3930c3a1e909 (diff) | |
DiscIO: Avoid copies when comparing FileSystemGCWii file names
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/DiscIO/FileSystemGCWii.cpp | 43 | ||||
| -rw-r--r-- | Source/Core/DiscIO/FileSystemGCWii.h | 1 | ||||
| -rw-r--r-- | Source/Core/DiscIO/Filesystem.h | 1 |
3 files changed, 41 insertions, 4 deletions
diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index 3954472465..c4e8d4a48e 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -6,6 +6,7 @@ #include <cinttypes> #include <cstddef> #include <cstring> +#include <locale> #include <map> #include <memory> #include <optional> @@ -119,6 +120,43 @@ std::string FileInfoGCWii::GetName() const return SHIFTJISToUTF8(reinterpret_cast<const char*>(m_fst + GetNameOffset())); } +bool FileInfoGCWii::NameCaseInsensitiveEquals(std::string_view other) const +{ + // For speed, this function avoids allocating new strings, except when we are comparing + // non-ASCII characters with non-ASCII characters, which is a rare case. + + const char* this_ptr = reinterpret_cast<const char*>(m_fst + GetNameOffset()); + const char* other_ptr = other.data(); + + for (size_t i = 0; i < other.size(); ++i, ++this_ptr, ++other_ptr) + { + if (*this_ptr == '\0') + { + // A null byte in this is always a terminator and a null byte in other is never a terminator, + // so if we reach this case, this is shorter than other + return false; + } + else if (static_cast<unsigned char>(*this_ptr) >= 0x80 && + static_cast<unsigned char>(*other_ptr) >= 0x80) + { + // other is in UTF-8 and this is in Shift-JIS, so we convert so that we can compare correctly + const std::string this_utf8 = SHIFTJISToUTF8(this_ptr); + return std::equal(this_utf8.cbegin(), this_utf8.cend(), other.cbegin() + i, other.cend(), + [](char a, char b) { + return std::tolower(a, std::locale::classic()) == + std::tolower(b, std::locale::classic()); + }); + } + else if (std::tolower(*this_ptr, std::locale::classic()) != + std::tolower(*other_ptr, std::locale::classic())) + { + return false; + } + } + + return *this_ptr == '\0'; // If we're not at a null byte, this is longer than other +} + std::string FileInfoGCWii::GetPath() const { // The root entry doesn't have a name @@ -283,11 +321,8 @@ std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(std::string_view path, for (const FileInfo& child : file_info) { - const std::string child_name = child.GetName(); - // We need case insensitive comparison since some games have OPENING.BNR instead of opening.bnr - if (child_name.size() == name.size() && - !strncasecmp(child_name.data(), name.data(), name.size())) + if (child.NameCaseInsensitiveEquals(name)) { // A match is found. The rest of the path is passed on to finish the search. std::unique_ptr<FileInfo> result = FindFileInfo(rest_of_path, child); diff --git a/Source/Core/DiscIO/FileSystemGCWii.h b/Source/Core/DiscIO/FileSystemGCWii.h index 26ff5d5444..9f7f8f2e6a 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.h +++ b/Source/Core/DiscIO/FileSystemGCWii.h @@ -45,6 +45,7 @@ public: bool IsDirectory() const override; u32 GetTotalChildren() const override; std::string GetName() const override; + bool NameCaseInsensitiveEquals(std::string_view other) const override; std::string GetPath() const override; bool IsValid(u64 fst_size, const FileInfoGCWii& parent_directory) const; diff --git a/Source/Core/DiscIO/Filesystem.h b/Source/Core/DiscIO/Filesystem.h index b46da7c29b..35b01e17b1 100644 --- a/Source/Core/DiscIO/Filesystem.h +++ b/Source/Core/DiscIO/Filesystem.h @@ -94,6 +94,7 @@ public: // Not guaranteed to return a meaningful value for files. virtual u32 GetTotalChildren() const = 0; virtual std::string GetName() const = 0; + virtual bool NameCaseInsensitiveEquals(std::string_view other) const = 0; // GetPath will find the parents of the current object and call GetName on them, // so it's slower than other functions. If you're traversing through folders // to get a file and its path, building the path while traversing is faster. |
