[XAM] Implemented XamGetLanguageLocaleFallbackString and XamGetLanguageTypeface
- Added stub XamGetLanguageTypefacePatch - Moved locale related calls to xam_locale from xam_info
This commit is contained in:
committed by
Radosław Gliński
parent
dc4db67f9c
commit
4c396fe611
@@ -44,8 +44,6 @@ DEFINE_int32(avpack, 8,
|
|||||||
" 7 = TV PAL-60\n"
|
" 7 = TV PAL-60\n"
|
||||||
" 8 = HDMI (default)",
|
" 8 = HDMI (default)",
|
||||||
"Video");
|
"Video");
|
||||||
DECLARE_int32(user_country);
|
|
||||||
DECLARE_int32(user_language);
|
|
||||||
DECLARE_uint32(audio_flag);
|
DECLARE_uint32(audio_flag);
|
||||||
|
|
||||||
DEFINE_bool(staging_mode, 0,
|
DEFINE_bool(staging_mode, 0,
|
||||||
@@ -90,40 +88,6 @@ dword_result_t XamGetOnlineSchema_entry() {
|
|||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamGetOnlineSchema, kNone, kImplemented);
|
DECLARE_XAM_EXPORT1(XamGetOnlineSchema, kNone, kImplemented);
|
||||||
|
|
||||||
void XamFormatDateString_entry(dword_t locale_format, qword_t filetime,
|
|
||||||
lpvoid_t output_buffer, dword_t output_count) {
|
|
||||||
output_buffer.Zero(output_count * sizeof(char16_t));
|
|
||||||
|
|
||||||
auto tp = xe::chrono::WinSystemClock::to_sys(
|
|
||||||
xe::chrono::WinSystemClock::from_file_time(filetime));
|
|
||||||
auto dp = date::floor<date::days>(tp);
|
|
||||||
auto year_month_day = date::year_month_day{dp};
|
|
||||||
|
|
||||||
auto str = fmt::format(u"{:02d}/{:02d}/{}",
|
|
||||||
static_cast<unsigned>(year_month_day.month()),
|
|
||||||
static_cast<unsigned>(year_month_day.day()),
|
|
||||||
static_cast<int>(year_month_day.year()));
|
|
||||||
xe::string_util::copy_and_swap_truncating(output_buffer.as<char16_t*>(), str,
|
|
||||||
output_count);
|
|
||||||
}
|
|
||||||
DECLARE_XAM_EXPORT1(XamFormatDateString, kNone, kImplemented);
|
|
||||||
|
|
||||||
void XamFormatTimeString_entry(dword_t user_index, qword_t filetime,
|
|
||||||
lpvoid_t output_buffer, dword_t output_count) {
|
|
||||||
output_buffer.Zero(output_count * sizeof(char16_t));
|
|
||||||
|
|
||||||
auto tp = xe::chrono::WinSystemClock::to_sys(
|
|
||||||
xe::chrono::WinSystemClock::from_file_time(filetime));
|
|
||||||
auto dp = date::floor<date::days>(tp);
|
|
||||||
auto time = date::hh_mm_ss{date::floor<std::chrono::milliseconds>(tp - dp)};
|
|
||||||
|
|
||||||
auto str = fmt::format(u"{:02d}:{:02d}", time.hours().count(),
|
|
||||||
time.minutes().count());
|
|
||||||
xe::string_util::copy_and_swap_truncating(output_buffer.as<char16_t*>(), str,
|
|
||||||
output_count);
|
|
||||||
}
|
|
||||||
DECLARE_XAM_EXPORT1(XamFormatTimeString, kNone, kImplemented);
|
|
||||||
|
|
||||||
dword_result_t keXamBuildResourceLocator(uint64_t module,
|
dword_result_t keXamBuildResourceLocator(uint64_t module,
|
||||||
const std::u16string& container,
|
const std::u16string& container,
|
||||||
const std::u16string& resource,
|
const std::u16string& resource,
|
||||||
@@ -253,61 +217,6 @@ dword_result_t XGetAVPack_entry() {
|
|||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XGetAVPack, kNone, kStub);
|
DECLARE_XAM_EXPORT1(XGetAVPack, kNone, kStub);
|
||||||
|
|
||||||
uint32_t xeXGetGameRegion() {
|
|
||||||
static uint32_t constexpr table[] = {
|
|
||||||
0xFFFFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x02FEu, 0x0201u, 0x03FFu,
|
|
||||||
0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu,
|
|
||||||
0x00FFu, 0xFFFFu, 0x02FEu, 0x03FFu, 0x0102u, 0x03FFu, 0x03FFu, 0x02FEu,
|
|
||||||
0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu,
|
|
||||||
0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu,
|
|
||||||
0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu,
|
|
||||||
0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x0101u, 0x03FFu, 0x03FFu,
|
|
||||||
0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu,
|
|
||||||
0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x0102u, 0x03FFu, 0x00FFu,
|
|
||||||
0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x0201u, 0x03FFu, 0x03FFu, 0x03FFu,
|
|
||||||
0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu, 0x03FFu, 0x03FFu, 0x02FEu,
|
|
||||||
0x02FEu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu, 0x02FEu, 0xFFFFu, 0x03FFu,
|
|
||||||
0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x03FFu, 0x02FEu, 0x00FFu,
|
|
||||||
0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu};
|
|
||||||
auto country = static_cast<uint8_t>(cvars::user_country);
|
|
||||||
return country < xe::countof(table) ? table[country] : 0xFFFFu;
|
|
||||||
}
|
|
||||||
|
|
||||||
dword_result_t XGetGameRegion_entry() { return xeXGetGameRegion(); }
|
|
||||||
DECLARE_XAM_EXPORT1(XGetGameRegion, kNone, kStub);
|
|
||||||
|
|
||||||
XLanguage xeGetLanguage(bool extended_languages_support) {
|
|
||||||
auto desired_language = static_cast<XLanguage>(cvars::user_language);
|
|
||||||
uint32_t region = xeXGetGameRegion();
|
|
||||||
auto max_languages = extended_languages_support ? XLanguage::kMaxLanguages
|
|
||||||
: XLanguage::kSChinese;
|
|
||||||
if (desired_language < max_languages) {
|
|
||||||
return desired_language;
|
|
||||||
}
|
|
||||||
if ((region & 0xff00) != 0x100) {
|
|
||||||
return XLanguage::kEnglish;
|
|
||||||
}
|
|
||||||
switch (region) {
|
|
||||||
case 0x101: // NTSC-J (Japan)
|
|
||||||
return XLanguage::kJapanese;
|
|
||||||
case 0x102: // NTSC-J (China)
|
|
||||||
return extended_languages_support ? XLanguage::kSChinese
|
|
||||||
: XLanguage::kEnglish;
|
|
||||||
default:
|
|
||||||
return XLanguage::kKorean;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dword_result_t XGetLanguage_entry() {
|
|
||||||
return static_cast<uint32_t>(xeGetLanguage(false));
|
|
||||||
}
|
|
||||||
DECLARE_XAM_EXPORT1(XGetLanguage, kNone, kImplemented);
|
|
||||||
|
|
||||||
dword_result_t XamGetLanguage_entry() {
|
|
||||||
return static_cast<uint32_t>(xeGetLanguage(true));
|
|
||||||
}
|
|
||||||
DECLARE_XAM_EXPORT1(XamGetLanguage, kNone, kImplemented);
|
|
||||||
|
|
||||||
dword_result_t XamGetCurrentTitleId_entry() {
|
dword_result_t XamGetCurrentTitleId_entry() {
|
||||||
return kernel_state()->emulator()->title_id();
|
return kernel_state()->emulator()->title_id();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,11 @@
|
|||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
DECLARE_int32(user_country);
|
#include "third_party/fmt/include/fmt/format.h"
|
||||||
|
#include "third_party/fmt/include/fmt/xchar.h"
|
||||||
|
|
||||||
|
DECLARE_int32(user_country);
|
||||||
|
DECLARE_int32(user_language);
|
||||||
// TODO(gibbed): put these forward decls in a header somewhere.
|
// TODO(gibbed): put these forward decls in a header somewhere.
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
@@ -453,6 +456,126 @@ dword_result_t XamGetLocaleDateFormat_entry(dword_t locale) {
|
|||||||
|
|
||||||
DECLARE_XAM_EXPORT1(XamGetLocaleDateFormat, kLocale, kImplemented);
|
DECLARE_XAM_EXPORT1(XamGetLocaleDateFormat, kLocale, kImplemented);
|
||||||
|
|
||||||
|
void XamFormatDateString_entry(dword_t locale_format, qword_t filetime,
|
||||||
|
lpvoid_t output_buffer, dword_t output_count) {
|
||||||
|
output_buffer.Zero(output_count * sizeof(char16_t));
|
||||||
|
|
||||||
|
auto tp = xe::chrono::WinSystemClock::to_sys(
|
||||||
|
xe::chrono::WinSystemClock::from_file_time(filetime));
|
||||||
|
auto dp = date::floor<date::days>(tp);
|
||||||
|
auto year_month_day = date::year_month_day{dp};
|
||||||
|
|
||||||
|
auto str = fmt::format(u"{:02d}/{:02d}/{}",
|
||||||
|
static_cast<unsigned>(year_month_day.month()),
|
||||||
|
static_cast<unsigned>(year_month_day.day()),
|
||||||
|
static_cast<int>(year_month_day.year()));
|
||||||
|
xe::string_util::copy_and_swap_truncating(output_buffer.as<char16_t*>(), str,
|
||||||
|
output_count);
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XamFormatDateString, kNone, kImplemented);
|
||||||
|
|
||||||
|
void XamFormatTimeString_entry(dword_t user_index, qword_t filetime,
|
||||||
|
lpvoid_t output_buffer, dword_t output_count) {
|
||||||
|
output_buffer.Zero(output_count * sizeof(char16_t));
|
||||||
|
|
||||||
|
auto tp = xe::chrono::WinSystemClock::to_sys(
|
||||||
|
xe::chrono::WinSystemClock::from_file_time(filetime));
|
||||||
|
auto dp = date::floor<date::days>(tp);
|
||||||
|
auto time = date::hh_mm_ss{date::floor<std::chrono::milliseconds>(tp - dp)};
|
||||||
|
|
||||||
|
auto str = fmt::format(u"{:02d}:{:02d}", time.hours().count(),
|
||||||
|
time.minutes().count());
|
||||||
|
xe::string_util::copy_and_swap_truncating(output_buffer.as<char16_t*>(), str,
|
||||||
|
output_count);
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XamFormatTimeString, kNone, kImplemented);
|
||||||
|
|
||||||
|
uint32_t xeXGetGameRegion() {
|
||||||
|
static uint32_t constexpr table[] = {
|
||||||
|
0xFFFFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x02FEu, 0x0201u, 0x03FFu,
|
||||||
|
0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu,
|
||||||
|
0x00FFu, 0xFFFFu, 0x02FEu, 0x03FFu, 0x0102u, 0x03FFu, 0x03FFu, 0x02FEu,
|
||||||
|
0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu,
|
||||||
|
0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu,
|
||||||
|
0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu,
|
||||||
|
0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x03FFu, 0x0101u, 0x03FFu, 0x03FFu,
|
||||||
|
0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x02FEu, 0x02FEu,
|
||||||
|
0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x03FFu, 0x0102u, 0x03FFu, 0x00FFu,
|
||||||
|
0x03FFu, 0x03FFu, 0x02FEu, 0x02FEu, 0x0201u, 0x03FFu, 0x03FFu, 0x03FFu,
|
||||||
|
0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu, 0x03FFu, 0x03FFu, 0x02FEu,
|
||||||
|
0x02FEu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu, 0x02FEu, 0xFFFFu, 0x03FFu,
|
||||||
|
0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x03FFu, 0x02FEu, 0x00FFu,
|
||||||
|
0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu};
|
||||||
|
auto country = static_cast<uint8_t>(cvars::user_country);
|
||||||
|
return country < xe::countof(table) ? table[country] : 0xFFFFu;
|
||||||
|
}
|
||||||
|
|
||||||
|
dword_result_t XGetGameRegion_entry() { return xeXGetGameRegion(); }
|
||||||
|
DECLARE_XAM_EXPORT1(XGetGameRegion, kNone, kStub);
|
||||||
|
|
||||||
|
XLanguage xeGetLanguage(bool extended_languages_support) {
|
||||||
|
auto desired_language = static_cast<XLanguage>(cvars::user_language);
|
||||||
|
uint32_t region = xeXGetGameRegion();
|
||||||
|
auto max_languages = extended_languages_support ? XLanguage::kMaxLanguages
|
||||||
|
: XLanguage::kSChinese;
|
||||||
|
if (desired_language < max_languages) {
|
||||||
|
return desired_language;
|
||||||
|
}
|
||||||
|
if ((region & 0xff00) != 0x100) {
|
||||||
|
return XLanguage::kEnglish;
|
||||||
|
}
|
||||||
|
switch (region) {
|
||||||
|
case 0x101: // NTSC-J (Japan)
|
||||||
|
return XLanguage::kJapanese;
|
||||||
|
case 0x102: // NTSC-J (China)
|
||||||
|
return extended_languages_support ? XLanguage::kSChinese
|
||||||
|
: XLanguage::kEnglish;
|
||||||
|
default:
|
||||||
|
return XLanguage::kKorean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dword_result_t XGetLanguage_entry() {
|
||||||
|
return static_cast<uint32_t>(xeGetLanguage(false));
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XGetLanguage, kNone, kImplemented);
|
||||||
|
|
||||||
|
dword_result_t XamGetLanguage_entry() {
|
||||||
|
return static_cast<uint32_t>(xeGetLanguage(true));
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XamGetLanguage, kNone, kImplemented);
|
||||||
|
|
||||||
|
pointer_result_t XamGetLanguageLocaleFallbackString_entry(dword_t language) {
|
||||||
|
assert_false(language > 17);
|
||||||
|
return kernel_state()->xam_state()->GetLanguageFallbackAddress(language);
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XamGetLanguageLocaleFallbackString, kNone, kImplemented);
|
||||||
|
|
||||||
|
dword_result_t XamGetLanguageTypeface_entry(dword_t language,
|
||||||
|
dword_t buffer_size,
|
||||||
|
dword_t buffer) {
|
||||||
|
std::u16string path{};
|
||||||
|
|
||||||
|
if (language == 0x11) {
|
||||||
|
path = u"file://media:/XenonSCLatin.xtt";
|
||||||
|
} else if (language == 8) {
|
||||||
|
path = u"file://media:/XenonCLatin.xtt";
|
||||||
|
} else {
|
||||||
|
path = u"file://media:/XenonJKLatin.xtt";
|
||||||
|
}
|
||||||
|
xe::string_util::copy_and_swap_truncating(
|
||||||
|
kernel_state()->memory()->TranslateVirtual<char16_t*>(buffer), path,
|
||||||
|
path.size() + 1);
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XamGetLanguageTypeface, kNone, kImplemented);
|
||||||
|
|
||||||
|
pointer_result_t XamGetLanguageTypefacePatch_entry(dword_t language) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XamGetLanguageTypefacePatch, kNone, kStub);
|
||||||
|
|
||||||
} // namespace xam
|
} // namespace xam
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|||||||
@@ -30,9 +30,36 @@ XamState::XamState(Emulator* emulator, KernelState* kernel_state)
|
|||||||
std::make_unique<ProfileManager>(kernel_state, user_tracker_.get());
|
std::make_unique<ProfileManager>(kernel_state, user_tracker_.get());
|
||||||
achievement_manager_ = std::make_unique<AchievementManager>();
|
achievement_manager_ = std::make_unique<AchievementManager>();
|
||||||
|
|
||||||
|
LoadLanguageLocaleFallback();
|
||||||
|
|
||||||
AppManager::RegisterApps(kernel_state, app_manager_.get());
|
AppManager::RegisterApps(kernel_state, app_manager_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XamState::LoadLanguageLocaleFallback() {
|
||||||
|
const std::array<std::u16string, 18> locale_data = {
|
||||||
|
u"", u"", u"ja-JP", u"de-DE", u"fr-FR", u"es-ES",
|
||||||
|
u"it-IT", u"ko-KR", u"zh-TW", u"pt-BR", u"zh-CHS", u"pl-PL",
|
||||||
|
u"ru-RU", u"sv-SE", u"tr-TR", u"nb-NO", u"nl-NL", u"zh-CHS"};
|
||||||
|
|
||||||
|
constexpr uint32_t array_start = 0x80D00000;
|
||||||
|
|
||||||
|
if (kernel_state_->memory()
|
||||||
|
->LookupHeap(0x80000000)
|
||||||
|
->AllocFixed(array_start, 0xC8, 0x1000, kMemoryAllocationCommit,
|
||||||
|
kMemoryProtectRead | kMemoryProtectWrite)) {
|
||||||
|
char16_t* ptr =
|
||||||
|
kernel_state_->memory()->TranslateVirtual<char16_t*>(array_start);
|
||||||
|
|
||||||
|
for (size_t i = 1; i < locale_data.size(); i++) {
|
||||||
|
language_fallback_address_[i] =
|
||||||
|
kernel_state_->memory()->HostToGuestVirtual(ptr);
|
||||||
|
ptr += xe::string_util::copy_and_swap_truncating(
|
||||||
|
ptr, locale_data.at(i), locale_data.at(i).size() + 1) +
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UserProfile* XamState::GetUserProfile(uint32_t user_index) const {
|
UserProfile* XamState::GetUserProfile(uint32_t user_index) const {
|
||||||
if (user_index >= XUserMaxUserCount && user_index < XUserIndexLatest) {
|
if (user_index >= XUserMaxUserCount && user_index < XUserIndexLatest) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ class XamState {
|
|||||||
return xam_dialogs_shown_ > 0 || xam_nui_dialogs_shown_ > 0;
|
return xam_dialogs_shown_ > 0 || xam_nui_dialogs_shown_ > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t GetLanguageFallbackAddress(uint32_t index) const {
|
||||||
|
return language_fallback_address_[index];
|
||||||
|
}
|
||||||
|
|
||||||
X_DASH_APP_INFO dash_app_info_ = {};
|
X_DASH_APP_INFO dash_app_info_ = {};
|
||||||
uint32_t dash_backstack_nodes_count_ = 0;
|
uint32_t dash_backstack_nodes_count_ = 0;
|
||||||
X_DASH_BACKSTACK_DATA dash_backstack_data_[2] = {};
|
X_DASH_BACKSTACK_DATA dash_backstack_data_[2] = {};
|
||||||
@@ -71,6 +75,8 @@ class XamState {
|
|||||||
std::atomic<int32_t> xam_nui_dialogs_shown_ = {0};
|
std::atomic<int32_t> xam_nui_dialogs_shown_ = {0};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void LoadLanguageLocaleFallback();
|
||||||
|
|
||||||
KernelState* kernel_state_;
|
KernelState* kernel_state_;
|
||||||
|
|
||||||
std::unique_ptr<AppManager> app_manager_;
|
std::unique_ptr<AppManager> app_manager_;
|
||||||
@@ -80,6 +86,9 @@ class XamState {
|
|||||||
std::unique_ptr<ProfileManager> profile_manager_;
|
std::unique_ptr<ProfileManager> profile_manager_;
|
||||||
|
|
||||||
std::unique_ptr<SpaInfo> spa_info_;
|
std::unique_ptr<SpaInfo> spa_info_;
|
||||||
|
|
||||||
|
// Custom XAM stuff
|
||||||
|
std::array<uint32_t, 0x12> language_fallback_address_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xam
|
} // namespace xam
|
||||||
|
|||||||
Reference in New Issue
Block a user