Guard macOS filename normalization behind __APPLE__

This commit is contained in:
Rodrigo Iglesias 2026-04-29 22:05:00 +02:00
parent 4ac3eb45c0
commit d936d3fe3c
4 changed files with 14 additions and 12 deletions

View file

@ -170,12 +170,12 @@ std::u16string UTF8ToUTF16(std::string_view input) {
return boost::locale::conv::utf_to_utf<char16_t>(input.data(), input.data() + input.size());
}
#if defined(__APPLE__)
// macOS filesystems may expose decomposed Unicode names through directory listings.
// Normalize to NFC before passing names to guest APIs that expect stable text.
std::string NormalizeUTF8ToNFC(std::string_view input) {
std::string NormalizeNFDToNFC(std::string_view input) {
const std::string fallback(input);
#if defined(__APPLE__)
//Core Foundation string
CFStringRef source = CFStringCreateWithBytes(
kCFAllocatorDefault,
@ -221,10 +221,8 @@ std::string NormalizeUTF8ToNFC(std::string_view input) {
output.resize(std::strlen(output.c_str()));
return output;
#else
return fallback;
#endif
}
#endif
#ifdef _WIN32
static std::wstring CPToUTF16(u32 code_page, const std::string& input) {

View file

@ -50,7 +50,9 @@ void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _P
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
// Returns UTF-8 normalized to NFC on platforms that need explicit Unicode normalization.
[[nodiscard]] std::string NormalizeUTF8ToNFC(std::string_view input);
#if defined(__APPLE__)
[[nodiscard]] std::string NormalizeNFDToNFC(std::string_view input);
#endif
#ifdef _WIN32
[[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);

View file

@ -66,7 +66,11 @@ u32 DiskDirectory::Read(const u32 count, Entry* entries) {
const FileUtil::FSTEntry& file = *children_iterator;
// Directory entries are exposed to the guest as UTF-16. Normalize host UTF-8 names first
// so host Unicode normalization differences do not leak into guest-visible SDMC paths.
const std::string filename = Common::NormalizeUTF8ToNFC(file.virtualName);
#if defined(__APPLE__)
const std::string filename = Common::NormalizeNFDToNFC(file.virtualName);
#else
const std::string& filename = file.virtualName;
#endif
const std::u16string filename_utf16 = Common::UTF8ToUTF16(filename);
Entry& entry = entries[entries_read];
@ -97,6 +101,4 @@ u32 DiskDirectory::Read(const u32 count, Entry* entries) {
}
return entries_read;
}
} // namespace FileSys

View file

@ -25,13 +25,13 @@ TEST_CASE("SplitFilename83 Sanity", "[common]") {
REQUIRE(std::memcmp(extension.data(), expected_extension.data(), extension.size()) == 0);
}
TEST_CASE("NormalizeUTF8ToNFC Sanity", "[common]") {
TEST_CASE("NormalizeNFDToNFC Sanity", "[common]") {
const std::string decomposed = "i\xCC\x81";
const std::string composed = "\xC3\xAD";
#if defined(__APPLE__)
REQUIRE(Common::NormalizeUTF8ToNFC(decomposed) == composed);
REQUIRE(Common::NormalizeNFDToNFC(decomposed) == composed);
#else
REQUIRE(Common::NormalizeUTF8ToNFC(decomposed) == decomposed);
REQUIRE(Common::NormalizeNFDToNFC(decomposed) == decomposed);
#endif
}