[Kernel] XLast: Added posibility to read:

- Title Name

- MatchmakingQuery
 - Input Parameters
 - Output
 - Filters (without operators)

- Localized Strings
This commit is contained in:
Gliniak 2024-03-22 12:32:13 +01:00
parent f54dc70d03
commit c7e97d051b
4 changed files with 144 additions and 5 deletions

View File

@ -1185,8 +1185,8 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
const uint8_t* xlast_ptr =
db.ReadXLast(compressed_size, decompressed_size);
title_xlast_ =
kernel::util::XLast(xlast_ptr, compressed_size, decompressed_size);
title_xlast_ = std::make_unique<kernel::util::XLast>(
xlast_ptr, compressed_size, decompressed_size);
auto icon_block = db.icon();
if (icon_block) {

View File

@ -299,7 +299,7 @@ class Emulator {
kernel::object_ref<kernel::XThread> main_thread_;
kernel::object_ref<kernel::XHostThread> plugin_loader_thread_;
std::optional<uint32_t> title_id_; // Currently running title ID
kernel::util::XLast title_xlast_;
std::unique_ptr<kernel::util::XLast> title_xlast_;
bool paused_;
bool restoring_;

View File

@ -11,12 +11,35 @@
#include "third_party/zlib/zlib.h"
#include "xenia/base/filesystem.h"
#include "xenia/base/logging.h"
#include "xenia/base/string_util.h"
namespace xe {
namespace kernel {
namespace util {
XLast::XLast() {}
XLastMatchmakingQuery::XLastMatchmakingQuery() {}
XLastMatchmakingQuery::XLastMatchmakingQuery(
const pugi::xpath_node query_node) {
node_ = query_node;
}
std::string XLastMatchmakingQuery::GetName() const {
return node_.node().attribute("friendlyName").value();
}
std::vector<uint32_t> XLastMatchmakingQuery::GetReturns() const {
return XLast::GetAllValuesFromNode(node_, "Returns", "id");
}
std::vector<uint32_t> XLastMatchmakingQuery::GetParameters() const {
return XLast::GetAllValuesFromNode(node_, "Parameters", "id");
}
std::vector<uint32_t> XLastMatchmakingQuery::GetFilters() const {
return XLast::GetAllValuesFromNode(node_, "Filters", "left");
}
XLast::XLast() : parsed_xlast_(nullptr) {}
XLast::XLast(const uint8_t* compressed_xml_data,
const uint32_t compressed_data_size,
@ -26,6 +49,7 @@ XLast::XLast(const uint8_t* compressed_xml_data,
return;
}
parsed_xlast_ = std::make_unique<pugi::xml_document>();
xlast_decompressed_xml_.resize(decompressed_data_size);
z_stream stream;
@ -55,17 +79,85 @@ XLast::XLast(const uint8_t* compressed_xml_data,
return;
}
inflateEnd(&stream);
parse_result_ = parsed_xlast_->load_buffer(xlast_decompressed_xml_.data(),
xlast_decompressed_xml_.size());
}
XLast::~XLast() {}
std::u16string XLast::GetTitleName() {
std::string xpath = "/XboxLiveSubmissionProject/GameConfigProject";
const pugi::xpath_node node = parsed_xlast_->select_node(xpath.c_str());
if (!node) {
return std::u16string();
}
return xe::to_utf16(node.node().attribute("titleName").value());
}
std::u16string XLast::GetLocalizedString(uint32_t string_id,
XLanguage language) {
std::string xpath = fmt::format(
"/XboxLiveSubmissionProject/GameConfigProject/LocalizedStrings/"
"LocalizedString[@id = \"{}\"]",
string_id);
const pugi::xpath_node node = parsed_xlast_->select_node(xpath.c_str());
if (!node) {
return std::u16string();
}
const std::string locale_name = GetLocaleStringFromLanguage(language);
const pugi::xml_node locale_node =
node.node().find_child_by_attribute("locale", locale_name.c_str());
if (!locale_node) {
return std::u16string();
}
return xe::to_utf16(locale_node.child_value());
}
XLastMatchmakingQuery* XLast::GetMatchmakingQuery(const uint32_t query_id) {
std::string xpath = fmt::format(
"/XboxLiveSubmissionProject/GameConfigProject/Matchmaking/Queries/"
"Query[@id = \"{}\"]",
query_id);
XLastMatchmakingQuery* query = nullptr;
pugi::xpath_node node = parsed_xlast_->select_node(xpath.c_str());
if (!node) {
return query;
}
return new XLastMatchmakingQuery(node);
}
std::vector<uint32_t> XLast::GetAllValuesFromNode(
const pugi::xpath_node node, const std::string child_name,
const std::string attirbute_name) {
std::vector<uint32_t> result{};
const auto searched_child = node.node().child(child_name.c_str());
for (pugi::xml_node_iterator itr = searched_child.begin();
itr != searched_child.end(); itr++) {
result.push_back(xe::string_util::from_string<uint32_t>(
itr->attribute(attirbute_name.c_str()).value(), true));
}
return result;
}
void XLast::Dump(std::string file_name) {
if (xlast_decompressed_xml_.empty()) {
return;
}
if (file_name.empty()) {
// TODO: Read default xlast name from it and use that one.
file_name = xe::to_utf8(GetTitleName());
}
FILE* outfile =
@ -79,6 +171,15 @@ void XLast::Dump(std::string file_name) {
fclose(outfile);
}
std::string XLast::GetLocaleStringFromLanguage(XLanguage language) {
const auto value = language_mapping.find(language);
if (value != language_mapping.cend()) {
return value->second;
}
return language_mapping.at(XLanguage::kEnglish);
}
} // namespace util
} // namespace kernel
} // namespace xe

View File

@ -10,12 +10,39 @@
#ifndef XENIA_KERNEL_UTIL_XLAST_H_
#define XENIA_KERNEL_UTIL_XLAST_H_
#include <map>
#include <string>
#include <vector>
#include "third_party/pugixml/src/pugixml.hpp"
#include "xenia/xbox.h"
namespace xe {
namespace kernel {
namespace util {
static const std::map<XLanguage, std::string> language_mapping = {
{XLanguage::kEnglish, "en-US"}, {XLanguage::kJapanese, "ja-JP"},
{XLanguage::kGerman, "de-DE"}, {XLanguage::kFrench, "fr-FR"},
{XLanguage::kSpanish, "es-ES"}, {XLanguage::kItalian, "it-IT"},
{XLanguage::kKorean, "ko-KR"}, {XLanguage::kTChinese, "zh-CHT"},
{XLanguage::kPortuguese, "pt-PT"}, {XLanguage::kPolish, "pl-PL"},
{XLanguage::kRussian, "ru-RU"}};
class XLastMatchmakingQuery {
public:
XLastMatchmakingQuery();
XLastMatchmakingQuery(const pugi::xpath_node query_node);
std::string GetName() const;
std::vector<uint32_t> GetReturns() const;
std::vector<uint32_t> GetParameters() const;
std::vector<uint32_t> GetFilters() const;
private:
pugi::xpath_node node_;
};
class XLast {
public:
XLast();
@ -23,10 +50,21 @@ class XLast {
const uint32_t decompressed_data_size);
~XLast();
std::u16string GetTitleName();
std::u16string GetLocalizedString(uint32_t string_id, XLanguage language);
XLastMatchmakingQuery* GetMatchmakingQuery(uint32_t query_id);
static std::vector<uint32_t> GetAllValuesFromNode(
const pugi::xpath_node node, const std::string child_name,
const std::string attirbute_name);
void Dump(std::string file_name);
private:
std::string GetLocaleStringFromLanguage(XLanguage language);
std::vector<uint8_t> xlast_decompressed_xml_;
std::unique_ptr<pugi::xml_document> parsed_xlast_ = nullptr;
pugi::xml_parse_result parse_result_ = {};
};
} // namespace util