[Base] Move XdbfLocale to xbox.h as XLanguage, let STFS headers use it

Renamed to XLanguage because AFAIK locale on Xbox is a different concept involving countries, this enum only involves languages though.
This commit is contained in:
emoose 2021-04-22 01:27:12 +01:00 committed by Rick Gibbed
parent 99b7848a34
commit ce19d948f0
6 changed files with 65 additions and 43 deletions

View File

@ -714,7 +714,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
module->memory()->TranslateVirtual(resource_data), resource_size); module->memory()->TranslateVirtual(resource_data), resource_size);
if (db.is_valid()) { if (db.is_valid()) {
// TODO(gibbed): get title respective to user locale. // TODO(gibbed): get title respective to user locale.
title_name_ = db.title(kernel::util::XdbfLocale::kEnglish); title_name_ = db.title(XLanguage::kEnglish);
if (title_name_.empty()) { if (title_name_.empty()) {
// If English title is unavailable, get the title in default locale. // If English title is unavailable, get the title in default locale.
title_name_ = db.title(); title_name_ = db.title();

View File

@ -55,10 +55,10 @@ XdbfBlock XdbfWrapper::GetEntry(XdbfSection section, uint64_t id) const {
return {0}; return {0};
} }
std::string XdbfWrapper::GetStringTableEntry(XdbfLocale locale, std::string XdbfWrapper::GetStringTableEntry(XLanguage language,
uint16_t string_id) const { uint16_t string_id) const {
auto language_block = auto language_block =
GetEntry(XdbfSection::kStringTable, static_cast<uint64_t>(locale)); GetEntry(XdbfSection::kStringTable, static_cast<uint64_t>(language));
if (!language_block) { if (!language_block) {
return ""; return "";
} }
@ -88,22 +88,22 @@ XdbfBlock XdbfGameData::icon() const {
return GetEntry(XdbfSection::kImage, kXdbfIdTitle); return GetEntry(XdbfSection::kImage, kXdbfIdTitle);
} }
XdbfLocale XdbfGameData::default_language() const { XLanguage XdbfGameData::default_language() const {
auto block = GetEntry(XdbfSection::kMetadata, kXdbfIdXstc); auto block = GetEntry(XdbfSection::kMetadata, kXdbfIdXstc);
if (!block.buffer) { if (!block.buffer) {
return XdbfLocale::kEnglish; return XLanguage::kEnglish;
} }
auto xstc = reinterpret_cast<const XdbfXstc*>(block.buffer); auto xstc = reinterpret_cast<const XdbfXstc*>(block.buffer);
assert_true(xstc->magic == kXdbfMagicXstc); assert_true(xstc->magic == kXdbfMagicXstc);
return static_cast<XdbfLocale>(static_cast<uint32_t>(xstc->default_language)); return static_cast<XLanguage>(static_cast<uint32_t>(xstc->default_language));
} }
std::string XdbfGameData::title() const { std::string XdbfGameData::title() const {
return GetStringTableEntry(default_language(), kXdbfIdTitle); return GetStringTableEntry(default_language(), kXdbfIdTitle);
} }
std::string XdbfGameData::title(XdbfLocale locale) const { std::string XdbfGameData::title(XLanguage language) const {
return GetStringTableEntry(locale, kXdbfIdTitle); return GetStringTableEntry(language, kXdbfIdTitle);
} }
} // namespace util } // namespace util

View File

@ -14,6 +14,7 @@
#include <vector> #include <vector>
#include "xenia/base/memory.h" #include "xenia/base/memory.h"
#include "xenia/xbox.h"
namespace xe { namespace xe {
namespace kernel { namespace kernel {
@ -28,19 +29,6 @@ enum class XdbfSection : uint16_t {
kStringTable = 0x0003, kStringTable = 0x0003,
}; };
// Found by dumping the kSectionStringTable sections of various games:
enum class XdbfLocale : uint32_t {
kUnknown = 0,
kEnglish = 1,
kJapanese = 2,
kGerman = 3,
kFrench = 4,
kSpanish = 5,
kItalian = 6,
kKorean = 7,
kChinese = 8,
};
struct XdbfBlock { struct XdbfBlock {
const uint8_t* buffer; const uint8_t* buffer;
size_t size; size_t size;
@ -63,7 +51,7 @@ class XdbfWrapper {
// Gets a string from the string table in the given language. // Gets a string from the string table in the given language.
// Returns the empty string if the entry is not found. // Returns the empty string if the entry is not found.
std::string GetStringTableEntry(XdbfLocale locale, uint16_t string_id) const; std::string GetStringTableEntry(XLanguage language, uint16_t string_id) const;
protected: protected:
#pragma pack(push, 1) #pragma pack(push, 1)
@ -133,12 +121,12 @@ class XdbfGameData : public XdbfWrapper {
XdbfBlock icon() const; XdbfBlock icon() const;
// The game's default language. // The game's default language.
XdbfLocale default_language() const; XLanguage default_language() const;
// The game's title in its default language. // The game's title in its default language.
std::string title() const; std::string title() const;
std::string title(XdbfLocale locale) const; std::string title(XLanguage language) const;
}; };
} // namespace util } // namespace util

View File

@ -28,9 +28,6 @@ namespace xe {
namespace kernel { namespace kernel {
namespace xam { namespace xam {
constexpr uint32_t X_LANGUAGE_ENGLISH = 1;
constexpr uint32_t X_LANGUAGE_JAPANESE = 2;
dword_result_t XamFeatureEnabled(dword_t unk) { return 0; } dword_result_t XamFeatureEnabled(dword_t unk) { return 0; }
DECLARE_XAM_EXPORT1(XamFeatureEnabled, kNone, kStub); DECLARE_XAM_EXPORT1(XamFeatureEnabled, kNone, kStub);
@ -208,19 +205,19 @@ dword_result_t XGetGameRegion() { return xeXGetGameRegion(); }
DECLARE_XAM_EXPORT1(XGetGameRegion, kNone, kStub); DECLARE_XAM_EXPORT1(XGetGameRegion, kNone, kStub);
dword_result_t XGetLanguage() { dword_result_t XGetLanguage() {
uint32_t desired_language = X_LANGUAGE_ENGLISH; auto desired_language = XLanguage::kEnglish;
// Switch the language based on game region. // Switch the language based on game region.
// TODO(benvanik): pull from xex header. // TODO(benvanik): pull from xex header.
uint32_t game_region = XEX_REGION_NTSCU; uint32_t game_region = XEX_REGION_NTSCU;
if (game_region & XEX_REGION_NTSCU) { if (game_region & XEX_REGION_NTSCU) {
desired_language = X_LANGUAGE_ENGLISH; desired_language = XLanguage::kEnglish;
} else if (game_region & XEX_REGION_NTSCJ) { } else if (game_region & XEX_REGION_NTSCJ) {
desired_language = X_LANGUAGE_JAPANESE; desired_language = XLanguage::kJapanese;
} }
// Add more overrides? // Add more overrides?
return desired_language; return uint32_t(desired_language);
} }
DECLARE_XAM_EXPORT1(XGetLanguage, kNone, kImplemented); DECLARE_XAM_EXPORT1(XGetLanguage, kNone, kImplemented);

View File

@ -268,11 +268,13 @@ XEPACKEDSTRUCT(XContentMetadata, {
char16_t description_ex_chars[kNumLanguagesV2 - kNumLanguagesV1][128]; char16_t description_ex_chars[kNumLanguagesV2 - kNumLanguagesV1][128];
}; };
std::u16string display_name(uint32_t lang_id) const { std::u16string display_name(XLanguage language) const {
lang_id--; uint32_t lang_id = uint32_t(language) - 1;
if (lang_id >= kNumLanguagesV2) { if (lang_id >= kNumLanguagesV2) {
assert_always(); assert_always();
lang_id = 0; // no room for this lang, read from english slot.. // no room for this lang, read from english slot..
lang_id = uint32_t(XLanguage::kEnglish) - 1;
} }
const be<uint16_t>* str = 0; const be<uint16_t>* str = 0;
@ -284,17 +286,21 @@ XEPACKEDSTRUCT(XContentMetadata, {
} }
if (!str) { if (!str) {
// Invalid language ID?
assert_always();
return u""; return u"";
} }
return load_and_swap<std::u16string>(str); return load_and_swap<std::u16string>(str);
} }
std::u16string description(uint32_t lang_id) const { std::u16string description(XLanguage language) const {
lang_id--; uint32_t lang_id = uint32_t(language) - 1;
if (lang_id >= kNumLanguagesV2) { if (lang_id >= kNumLanguagesV2) {
assert_always(); assert_always();
lang_id = 0; // no room for this lang, read from english slot.. // no room for this lang, read from english slot..
lang_id = uint32_t(XLanguage::kEnglish) - 1;
} }
const be<uint16_t>* str = 0; const be<uint16_t>* str = 0;
@ -306,6 +312,8 @@ XEPACKEDSTRUCT(XContentMetadata, {
} }
if (!str) { if (!str) {
// Invalid language ID?
assert_always();
return u""; return u"";
} }
@ -320,11 +328,13 @@ XEPACKEDSTRUCT(XContentMetadata, {
return load_and_swap<std::u16string>(title_name_raw); return load_and_swap<std::u16string>(title_name_raw);
} }
bool set_display_name(uint32_t lang_id, const std::u16string_view value) { bool set_display_name(XLanguage language, const std::u16string_view value) {
lang_id--; uint32_t lang_id = uint32_t(language) - 1;
if (lang_id >= kNumLanguagesV2) { if (lang_id >= kNumLanguagesV2) {
assert_always(); assert_always();
lang_id = 0; // no room for this lang, store in english slot.. // no room for this lang, store in english slot..
lang_id = uint32_t(XLanguage::kEnglish) - 1;
} }
char16_t* str = 0; char16_t* str = 0;
@ -336,6 +346,8 @@ XEPACKEDSTRUCT(XContentMetadata, {
} }
if (!str) { if (!str) {
// Invalid language ID?
assert_always();
return false; return false;
} }
@ -344,11 +356,13 @@ XEPACKEDSTRUCT(XContentMetadata, {
return true; return true;
} }
bool set_description(uint32_t lang_id, const std::u16string_view value) { bool set_description(XLanguage language, const std::u16string_view value) {
lang_id--; uint32_t lang_id = uint32_t(language) - 1;
if (lang_id >= kNumLanguagesV2) { if (lang_id >= kNumLanguagesV2) {
assert_always(); assert_always();
lang_id = 0; // no room for this lang, store in english slot.. // no room for this lang, store in english slot..
lang_id = uint32_t(XLanguage::kEnglish) - 1;
} }
char16_t* str = 0; char16_t* str = 0;
@ -360,6 +374,8 @@ XEPACKEDSTRUCT(XContentMetadata, {
} }
if (!str) { if (!str) {
// Invalid language ID?
assert_always();
return false; return false;
} }

View File

@ -323,6 +323,27 @@ static_assert_size(X_EXCEPTION_RECORD, 0x50);
#pragma pack(pop) #pragma pack(pop)
// Found by dumping the kSectionStringTable sections of various games:
// and the language list at
// https://free60project.github.io/wiki/Profile_Account/
enum class XLanguage : uint32_t {
kInvalid = 0,
kEnglish = 1,
kJapanese = 2,
kGerman = 3,
kFrench = 4,
kSpanish = 5,
kItalian = 6,
kKorean = 7,
kTChinese = 8,
kPortuguese = 9,
kSChinese = 10,
kPolish = 11,
kRussian = 12,
// STFS headers can't support any more languages than these
kMaxLanguages = 13
};
} // namespace xe } // namespace xe
// clang-format on // clang-format on