diff options
| author | lizzie <lizzie@eden-emu.dev> | 2026-02-23 13:39:16 +0100 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-02-23 13:39:16 +0100 |
| commit | c610b611261ae2bdb5df7bac6104f1c1e98b6354 (patch) | |
| tree | 62fb29b8fe8f9ef2775cf571f63e00d413f025ed /src/core/file_sys/control_metadata.cpp | |
| parent | 963f9981ce9846a4ed97f6b12c49d9b61db6fab9 (diff) | |
[common, hle] add new updates Polish+Thai languages (#3587)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Co-authored-by: maufeat <sahyno1996@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3587
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
Diffstat (limited to 'src/core/file_sys/control_metadata.cpp')
| -rw-r--r-- | src/core/file_sys/control_metadata.cpp | 157 |
1 files changed, 58 insertions, 99 deletions
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index 7ca7703afa..3676c1bbc8 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -12,6 +12,7 @@ #include <zlib.h> #include "common/settings.h" +#include "common/settings_enums.h" #include "common/string_util.h" #include "common/swap.h" #include "core/file_sys/control_metadata.h" @@ -19,7 +20,7 @@ namespace FileSys { -const std::array<const char*, 16> LANGUAGE_NAMES{{ +const std::array<const char*, size_t(Language::Count)> LANGUAGE_NAMES{{ "AmericanEnglish", "BritishEnglish", "Japanese", @@ -36,137 +37,95 @@ const std::array<const char*, 16> LANGUAGE_NAMES{{ "TraditionalChinese", "SimplifiedChinese", "BrazilianPortuguese", + "Polish", + "Thai", }}; -namespace { -constexpr std::size_t LEGACY_LANGUAGE_REGION_SIZE = sizeof(std::array<LanguageEntry, 16>); -constexpr std::size_t PACKED_LANGUAGE_REGION_MAX_SIZE = sizeof(LanguageEntry) * 32; +namespace +{ + constexpr std::size_t MAX_EXPANDED_LANG_SIZE = sizeof(LanguageEntry) * 32; -bool InflateRawDeflate(std::span<const u8> compressed, std::vector<u8>& out) { - if (compressed.empty() || compressed.size() > std::numeric_limits<uInt>::max()) { - return false; - } - z_stream stream{}; - stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(compressed.data())); - stream.avail_in = static_cast<uInt>(compressed.size()); - if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) { - return false; - } + bool InflateRawDeflate(std::span<const u8> compressed, std::vector<u8>& out) + { + if (compressed.empty()) return false; - std::array<u8, 0x1000> chunk{}; - int ret = Z_OK; - while (ret == Z_OK) { - stream.next_out = reinterpret_cast<Bytef*>(chunk.data()); - stream.avail_out = static_cast<uInt>(chunk.size()); - ret = inflate(&stream, Z_NO_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) { - inflateEnd(&stream); + z_stream stream{}; + stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(compressed.data())); + stream.avail_in = static_cast<uInt>(compressed.size()); + if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) { return false; } - const auto produced = chunk.size() - static_cast<std::size_t>(stream.avail_out); - if (produced != 0) { - if (out.size() + produced > PACKED_LANGUAGE_REGION_MAX_SIZE) { - inflateEnd(&stream); - return false; - } - out.insert(out.end(), chunk.begin(), - chunk.begin() + static_cast<std::ptrdiff_t>(produced)); - } - } - - inflateEnd(&stream); - return ret == Z_STREAM_END; -} + out.resize(MAX_EXPANDED_LANG_SIZE); + stream.next_out = reinterpret_cast<Bytef*>(out.data()); + stream.avail_out = static_cast<uInt>(out.size()); -void DecodePackedLanguageEntries(RawNACP& raw) { - auto* packed_region = reinterpret_cast<u8*>(raw.language_entries.data()); - u16_le compressed_size_le{}; - std::memcpy(&compressed_size_le, packed_region, sizeof(compressed_size_le)); - const auto compressed_size = static_cast<std::size_t>(compressed_size_le); + int ret = inflate(&stream, Z_FINISH); + inflateEnd(&stream); - if (compressed_size == 0 || compressed_size > LEGACY_LANGUAGE_REGION_SIZE - sizeof(u16_le)) { - return; - } - - std::vector<u8> decompressed; - if (!InflateRawDeflate( - std::span<const u8>(packed_region + sizeof(u16_le), compressed_size), decompressed)) { - return; - } + if (ret != Z_STREAM_END && ret != Z_OK) { + return false; + } - if (decompressed.size() < LEGACY_LANGUAGE_REGION_SIZE || - decompressed.size() % sizeof(LanguageEntry) != 0) { - return; + // Shrink to actual decompressed size + out.resize(stream.total_out); + return true; } - - std::memcpy(raw.language_entries.data(), decompressed.data(), LEGACY_LANGUAGE_REGION_SIZE); -} } // namespace std::string LanguageEntry::GetApplicationName() const { - return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), - application_name.size()); + return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), application_name.size()); } std::string LanguageEntry::GetDeveloperName() const { - return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), - developer_name.size()); -} - -constexpr std::array<Language, 18> language_to_codes = {{ - Language::Japanese, - Language::AmericanEnglish, - Language::French, - Language::German, - Language::Italian, - Language::Spanish, - Language::SimplifiedChinese, - Language::Korean, - Language::Dutch, - Language::Portuguese, - Language::Russian, - Language::TraditionalChinese, - Language::BritishEnglish, - Language::CanadianFrench, - Language::LatinAmericanSpanish, - Language::SimplifiedChinese, - Language::TraditionalChinese, - Language::BrazilianPortuguese, -}}; + return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), developer_name.size()); +} NACP::NACP() = default; -NACP::NACP(VirtualFile file) { +NACP::NACP(VirtualFile file) +{ file->ReadObject(&raw); - DecodePackedLanguageEntries(raw); + if (raw.titles_data_format == TitleDataFormat::Compressed) { + const u16 compressed_size = raw.language_entries.compressed_data.buffer_size; + std::span<const u8> compressed_payload{raw.language_entries.compressed_data.buffer, + compressed_size}; + + std::vector<u8> decompressed; + if (InflateRawDeflate(compressed_payload, decompressed)) { + const size_t entry_count = decompressed.size() / sizeof(LanguageEntry); + language_entries.resize(entry_count); + std::memcpy(language_entries.data(), decompressed.data(), decompressed.size()); + } + } else { + language_entries.resize(16); + std::memcpy(language_entries.data(), raw.language_entries.language_entries.data(), + sizeof(raw.language_entries.language_entries)); + } } NACP::~NACP() = default; const LanguageEntry& NACP::GetLanguageEntry() const { - Language language = - language_to_codes[static_cast<s32>(Settings::values.language_index.GetValue())]; + u32 index = static_cast<u32>(Settings::values.language_index.GetValue()); - { - const auto& language_entry = raw.language_entries.at(static_cast<u8>(language)); - if (!language_entry.GetApplicationName().empty()) - return language_entry; + if (index < language_entries.size()) { + return language_entries[index]; } - for (const auto& language_entry : raw.language_entries) { - if (!language_entry.GetApplicationName().empty()) - return language_entry; + for (const auto& entry : language_entries) { + return entry; } - return raw.language_entries.at(static_cast<u8>(Language::AmericanEnglish)); + return language_entries.at(static_cast<u8>(Language::AmericanEnglish)); } -std::array<std::string, 16> NACP::GetApplicationNames() const { - std::array<std::string, 16> names{}; - for (size_t i = 0; i < raw.language_entries.size(); ++i) { - names[i] = raw.language_entries[i].GetApplicationName(); +std::vector<std::string> NACP::GetApplicationNames() const { + std::vector<std::string> names; + names.reserve(language_entries.size()); + for (const auto& entry : language_entries) { + names.push_back(entry.GetApplicationName()); } return names; } @@ -205,7 +164,7 @@ bool NACP::GetUserAccountSwitchLock() const { } u32 NACP::GetSupportedLanguages() const { - return raw.supported_languages; + return u32(raw.supported_languages); } u64 NACP::GetDeviceSaveDataSize() const { |
