From 0333c376fdd15a0f8b61d7d21a158e80d85d4513 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 21 Nov 2019 19:32:41 -0800 Subject: [PATCH] Implement set_mitm --- include/stratosphere.hpp | 1 + include/stratosphere/cfg/cfg_api.hpp | 4 + include/stratosphere/cfg/cfg_locale_types.hpp | 27 +++ include/stratosphere/cfg/cfg_types.hpp | 2 +- include/stratosphere/settings.hpp | 19 ++ .../stratosphere/settings/settings_types.hpp | 175 ++++++++++++++++++ source/cfg/cfg_override.cpp | 26 +++ 7 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 include/stratosphere/cfg/cfg_locale_types.hpp create mode 100644 include/stratosphere/settings.hpp create mode 100644 include/stratosphere/settings/settings_types.hpp diff --git a/include/stratosphere.hpp b/include/stratosphere.hpp index 2e8ec8bf..0a136366 100644 --- a/include/stratosphere.hpp +++ b/include/stratosphere.hpp @@ -43,6 +43,7 @@ #include "stratosphere/reg.hpp" #include "stratosphere/rnd.hpp" #include "stratosphere/ro.hpp" +#include "stratosphere/settings.hpp" #include "stratosphere/sf.hpp" #include "stratosphere/sm.hpp" #include "stratosphere/spl.hpp" diff --git a/include/stratosphere/cfg/cfg_api.hpp b/include/stratosphere/cfg/cfg_api.hpp index 89181b82..747f7e35 100644 --- a/include/stratosphere/cfg/cfg_api.hpp +++ b/include/stratosphere/cfg/cfg_api.hpp @@ -15,6 +15,7 @@ */ #pragma once #include "cfg_types.hpp" +#include "cfg_locale_types.hpp" namespace ams::cfg { @@ -31,6 +32,9 @@ namespace ams::cfg { /* Override key utilities. */ OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id); + /* Locale utilities. */ + OverrideLocale GetOverrideLocale(ncm::ProgramId program_id); + /* Flag utilities. */ bool HasFlag(ncm::ProgramId program_id, const char *flag); bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag); diff --git a/include/stratosphere/cfg/cfg_locale_types.hpp b/include/stratosphere/cfg/cfg_locale_types.hpp new file mode 100644 index 00000000..d281c6cf --- /dev/null +++ b/include/stratosphere/cfg/cfg_locale_types.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "cfg_types.hpp" +#include "../settings/settings_types.hpp" + +namespace ams::cfg { + + struct OverrideLocale { + settings::LanguageCode language_code; + settings::RegionCode region_code; + }; + +} diff --git a/include/stratosphere/cfg/cfg_types.hpp b/include/stratosphere/cfg/cfg_types.hpp index 530e4160..71cf7e20 100644 --- a/include/stratosphere/cfg/cfg_types.hpp +++ b/include/stratosphere/cfg/cfg_types.hpp @@ -52,7 +52,7 @@ namespace ams::cfg { static_assert(std::is_pod::value, "std::is_pod::value"); constexpr inline bool operator==(const OverrideStatus &lhs, const OverrideStatus &rhs) { - return lhs.keys_held == rhs.keys_held && lhs.flags == rhs.flags; + return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0; } constexpr inline bool operator!=(const OverrideStatus &lhs, const OverrideStatus &rhs) { diff --git a/include/stratosphere/settings.hpp b/include/stratosphere/settings.hpp new file mode 100644 index 00000000..2751a061 --- /dev/null +++ b/include/stratosphere/settings.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "settings/settings_types.hpp" diff --git a/include/stratosphere/settings/settings_types.hpp b/include/stratosphere/settings/settings_types.hpp new file mode 100644 index 00000000..994a3a85 --- /dev/null +++ b/include/stratosphere/settings/settings_types.hpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::settings { + + enum Language { + Language_Japanese, + Language_AmericanEnglish, + Language_French, + Language_German, + Language_Italian, + Language_Spanish, + Language_Chinese, + Language_Korean, + Language_Dutch, + Language_Portuguese, + Language_Russian, + Language_Taiwanese, + Language_BritishEnglish, + Language_CanadianFrench, + Language_LatinAmericanSpanish, + /* 4.0.0+ */ + Language_SimplifiedChinese, + Language_TraditionalChinese, + + Language_Count, + }; + + struct LanguageCode { + static constexpr size_t MaxLength = 8; + + char name[MaxLength]; + + static constexpr LanguageCode Encode(const char *name, size_t name_size) { + LanguageCode out{}; + for (size_t i = 0; i < MaxLength && i < name_size; i++) { + out.name[i] = name[i]; + } + return out; + } + + static constexpr LanguageCode Encode(const char *name) { + return Encode(name, std::strlen(name)); + } + + template + static constexpr inline LanguageCode EncodeLanguage = [] { + if constexpr (false) { /* ... */ } + #define AMS_MATCH_LANGUAGE(lang, enc) else if constexpr (Lang == Language_##lang) { return LanguageCode::Encode(enc); } + AMS_MATCH_LANGUAGE(Japanese, "ja") + AMS_MATCH_LANGUAGE(AmericanEnglish, "en-US") + AMS_MATCH_LANGUAGE(French, "fr") + AMS_MATCH_LANGUAGE(German, "de") + AMS_MATCH_LANGUAGE(Italian, "it") + AMS_MATCH_LANGUAGE(Spanish, "es") + AMS_MATCH_LANGUAGE(Chinese, "zh-CN") + AMS_MATCH_LANGUAGE(Korean, "ko") + AMS_MATCH_LANGUAGE(Dutch, "nl") + AMS_MATCH_LANGUAGE(Portuguese, "pt") + AMS_MATCH_LANGUAGE(Russian, "ru") + AMS_MATCH_LANGUAGE(Taiwanese, "zh-TW") + AMS_MATCH_LANGUAGE(BritishEnglish, "en-GB") + AMS_MATCH_LANGUAGE(CanadianFrench, "fr-CA") + AMS_MATCH_LANGUAGE(LatinAmericanSpanish, "es-419") + /* 4.0.0+ */ + AMS_MATCH_LANGUAGE(SimplifiedChinese, "zh-Hans") + AMS_MATCH_LANGUAGE(TraditionalChinese, "zh-Hant") + #undef AMS_MATCH_LANGUAGE + else { static_assert(Lang != Language_Japanese); } + }(); + + static constexpr inline LanguageCode Encode(const Language language) { + constexpr LanguageCode EncodedLanguages[Language_Count] = { + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + /* 4.0.0+ */ + EncodeLanguage, + EncodeLanguage, + }; + return EncodedLanguages[language]; + } + + }; + + constexpr inline bool operator==(const LanguageCode &lhs, const LanguageCode &rhs) { + return std::strncmp(lhs.name, rhs.name, sizeof(lhs)) == 0; + } + + constexpr inline bool operator!=(const LanguageCode &lhs, const LanguageCode &rhs) { + return !(lhs == rhs); + } + + constexpr inline bool operator==(const LanguageCode &lhs, const Language &rhs) { + return lhs == LanguageCode::Encode(rhs); + } + + constexpr inline bool operator!=(const LanguageCode &lhs, const Language &rhs) { + return !(lhs == rhs); + } + + constexpr inline bool operator==(const Language &lhs, const LanguageCode &rhs) { + return rhs == lhs; + } + + constexpr inline bool operator!=(const Language &lhs, const LanguageCode &rhs) { + return !(lhs == rhs); + } + + namespace impl { + + template + constexpr inline bool IsValidLanguageCode(const LanguageCode &lc, std::index_sequence) { + return ((lc == LanguageCode::Encode(static_cast(Is))) || ...); + } + + } + + constexpr inline bool IsValidLanguageCodeDeprecated(const LanguageCode &lc) { + return impl::IsValidLanguageCode(lc, std::make_index_sequence{}); + } + + constexpr inline bool IsValidLanguageCode(const LanguageCode &lc) { + return impl::IsValidLanguageCode(lc, std::make_index_sequence{}); + } + + static_assert(std::is_pod::value); + static_assert(sizeof(LanguageCode) == sizeof(u64)); + + /* Not an official type, but convenient. */ + enum RegionCode : s32 { + RegionCode_Japan, + RegionCode_America, + RegionCode_Europe, + RegionCode_Australia, + RegionCode_China, + RegionCode_Korea, + RegionCode_Taiwan, + + RegionCode_Count, + }; + + constexpr inline bool IsValidRegionCode(const RegionCode rc) { + return 0 <= rc && rc < RegionCode_Count; + } + +} diff --git a/source/cfg/cfg_override.cpp b/source/cfg/cfg_override.cpp index 525c960d..7e784660 100644 --- a/source/cfg/cfg_override.cpp +++ b/source/cfg/cfg_override.cpp @@ -36,6 +36,7 @@ namespace ams::cfg { struct ContentSpecificOverrideConfig { OverrideKey override_key; OverrideKey cheat_enable_key; + OverrideLocale locale; }; /* Override globals. */ @@ -164,10 +165,29 @@ namespace ams::cfg { config->override_key = ParseOverrideKey(value); } else if (strcasecmp(name, "cheat_enable_key") == 0) { config->cheat_enable_key = ParseOverrideKey(value); + } else if (strcasecmp(name, "override_language") == 0) { + config->locale.language_code = settings::LanguageCode::Encode(value); + } else if (strcasecmp(name, "override_region") == 0) { + if (strcasecmp(value, "jpn") == 0) { + config->locale.region_code = settings::RegionCode_Japan; + } else if (strcasecmp(value, "usa") == 0) { + config->locale.region_code = settings::RegionCode_America; + } else if (strcasecmp(value, "eur") == 0) { + config->locale.region_code = settings::RegionCode_Europe; + } else if (strcasecmp(value, "aus") == 0) { + config->locale.region_code = settings::RegionCode_Australia; + } else if (strcasecmp(value, "chn") == 0) { + config->locale.region_code = settings::RegionCode_China; + } else if (strcasecmp(value, "kor") == 0) { + config->locale.region_code = settings::RegionCode_Korea; + } else if (strcasecmp(value, "twn") == 0) { + config->locale.region_code = settings::RegionCode_Taiwan; + } } } else { return 0; } + return 1; } @@ -215,6 +235,8 @@ namespace ams::cfg { .override_key = g_default_override_key, .cheat_enable_key = g_default_cheat_enable_key, }; + std::memset(&config.locale, 0xCC, sizeof(config.locale)); + ParseIniFile(ContentSpecificIniHandler, path, &config); return config; } @@ -264,6 +286,10 @@ namespace ams::cfg { return status; } + OverrideLocale GetOverrideLocale(ncm::ProgramId program_id) { + return GetContentOverrideConfig(program_id).locale; + } + /* HBL Configuration utilities. */ bool IsHblProgramId(ncm::ProgramId program_id) { return IsApplicationHblProgramId(program_id) || IsSpecificHblProgramId(program_id);