diff options
| author | Connor McLaughlin <stenzek@gmail.com> | 2019-06-08 20:52:34 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-08 20:52:34 +1000 |
| commit | ab66e91766f66110e8c4f4d0ba7ddac969e21fe7 (patch) | |
| tree | 95455982e61999710b548586b148d24d04027631 /Source/Core/DiscIO/FileSystemGCWii.cpp | |
| parent | bed2d66bedca7e9537d67d3e7a5506aee8717c8f (diff) | |
| parent | f25367a7a274c351da568e1ce1e09b95ae0f1a60 (diff) | |
Merge pull request #8134 from JosJuice/filesystem-string-view
DiscIO: Use std::string_view in FileSystem::FindFileInfo
Diffstat (limited to 'Source/Core/DiscIO/FileSystemGCWii.cpp')
| -rw-r--r-- | Source/Core/DiscIO/FileSystemGCWii.cpp | 51 |
1 files changed, 46 insertions, 5 deletions
diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index a7826c9ab1..c4e8d4a48e 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -6,10 +6,12 @@ #include <cinttypes> #include <cstddef> #include <cstring> +#include <locale> #include <map> #include <memory> #include <optional> #include <string> +#include <string_view> #include <vector> #include "Common/CommonFuncs.h" @@ -118,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 @@ -257,7 +296,7 @@ const FileInfo& FileSystemGCWii::GetRoot() const return m_root; } -std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(const std::string& path) const +std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(std::string_view path) const { if (!IsValid()) return nullptr; @@ -265,7 +304,7 @@ std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(const std::string& path) return FindFileInfo(path, m_root); } -std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(const std::string& path, +std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(std::string_view path, const FileInfo& file_info) const { // Given a path like "directory1/directory2/fileA.bin", this function will @@ -276,12 +315,14 @@ std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(const std::string& path, return file_info.clone(); // We're done const size_t name_end = path.find('/', name_start); - const std::string name = path.substr(name_start, name_end - name_start); - const std::string rest_of_path = (name_end != std::string::npos) ? path.substr(name_end + 1) : ""; + const std::string_view name = path.substr(name_start, name_end - name_start); + const std::string_view rest_of_path = + (name_end != std::string::npos) ? path.substr(name_end + 1) : ""; for (const FileInfo& child : file_info) { - if (!strcasecmp(child.GetName().c_str(), name.c_str())) + // We need case insensitive comparison since some games have OPENING.BNR instead of opening.bnr + 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); |
