diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index 40dda01d0d..9f93aa0331 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ namespace DiscIO { static u32 ComputeNameSize(const File::FSTEntry& parent_entry); +static std::string ASCIIToLowercase(std::string str); const size_t CVolumeDirectory::MAX_NAME_LENGTH; const size_t CVolumeDirectory::MAX_ID_LENGTH; @@ -452,10 +454,16 @@ void CVolumeDirectory::WriteDirectory(const File::FSTEntry& parent_entry, u32* f { std::vector sorted_entries = parent_entry.children; - std::sort(sorted_entries.begin(), sorted_entries.end(), - [](const File::FSTEntry& one, const File::FSTEntry& two) { - return one.virtualName < two.virtualName; - }); + // Sort for determinism + std::sort(sorted_entries.begin(), sorted_entries.end(), [](const File::FSTEntry& one, + const File::FSTEntry& two) { + // For some reason, sorting by lowest ASCII value first prevents many games from + // fully booting. We make the comparison case insensitive to solve the problem. + // (Highest ASCII value first seems to work regardless of case sensitivity.) + const std::string one_lower = ASCIIToLowercase(one.virtualName); + const std::string two_lower = ASCIIToLowercase(two.virtualName); + return one_lower == two_lower ? one.virtualName < two.virtualName : one_lower < two_lower; + }); for (const File::FSTEntry& entry : sorted_entries) { @@ -497,4 +505,11 @@ static u32 ComputeNameSize(const File::FSTEntry& parent_entry) return name_size; } +static std::string ASCIIToLowercase(std::string str) +{ + std::transform(str.begin(), str.end(), str.begin(), + [](char c) { return std::tolower(c, std::locale::classic()); }); + return str; +} + } // namespace