[file_sys] Avoid crash on empty NACP language entries (#4062)

This fixes an Android game library scan crash when reading XCI title metadata with empty or incomplete NACP language entries.

Previously, NACP::GetLanguageEntry() could fall back to:

language_entries.at(static_cast<u8>(Language::AmericanEnglish))

When language_entries was empty, this threw std::out_of_range and aborted the Android scan thread.

The new fallback preserves the existing lookup order:
1. preferred language entry with non-empty application name
2. any entry with non-empty application name
3. first available entry
4. static empty LanguageEntry if no entries exist

Tested locally with a Mainline RelWithDebInfo APK on Odin3 Android 15 using a large external TF-card ROM directory. The previous build crashed during fresh ROM scan; the patched build completes scanning normally.

Related my issue:
https://github.com/eden-emulator/Issue-Reports/issues/500

Co-authored-by: bdm110 <bdm110@prontmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4062
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
bdm110 2026-06-05 17:20:24 +02:00 committed by crueter
parent 48219f348c
commit fb6330645a
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6

View file

@ -128,25 +128,32 @@ const LanguageEntry& NACP::GetLanguageEntry() const {
case Settings::Language::Russian: return Language::Russian; case Settings::Language::Russian: return Language::Russian;
case Settings::Language::Spanish: return Language::Spanish; case Settings::Language::Spanish: return Language::Spanish;
case Settings::Language::SpanishLatin: return Language::LatinAmericanSpanish; case Settings::Language::SpanishLatin: return Language::LatinAmericanSpanish;
case Settings::Language::Taiwanese: return Language::SimplifiedChinese; case Settings::Language::Taiwanese: return Language::TraditionalChinese;
case Settings::Language::Thai: return Language::Thai; case Settings::Language::Thai: return Language::Thai;
case Settings::Language::Polish: return Language::Polish; case Settings::Language::Polish: return Language::Polish;
default: return Language::AmericanEnglish; default: return Language::AmericanEnglish;
} }
}(); }();
u32 index = u32(language); const auto index = static_cast<size_t>(language);
if (index < language_entries.size() && !language_entries[index].GetApplicationName().empty()) { if (index < language_entries.size() &&
!language_entries[index].GetApplicationName().empty()) {
return language_entries[index]; return language_entries[index];
} }
for (const auto& entry : language_entries) { for (const auto& entry : language_entries) {
if (!entry.GetApplicationName().empty()) if (!entry.GetApplicationName().empty()) {
return entry; return entry;
} }
}
return language_entries.at(static_cast<u8>(Language::AmericanEnglish)); if (!language_entries.empty()) {
return language_entries.front();
}
static const LanguageEntry empty_entry{};
return empty_entry;
} }
std::vector<std::string> NACP::GetApplicationNames() const { std::vector<std::string> NACP::GetApplicationNames() const {