From 854b7df2bac85c8aa3d6cf88881f444df48b0aca Mon Sep 17 00:00:00 2001 From: Gliniak Date: Sun, 24 Mar 2024 18:31:11 +0100 Subject: [PATCH] [Kernel] Added Property class and storing them for user --- src/xenia/kernel/util/property.cc | 130 +++++++++++++++++++++++++++ src/xenia/kernel/util/property.h | 71 +++++++++++++++ src/xenia/kernel/util/xuserdata.h | 10 --- src/xenia/kernel/xam/apps/xgi_app.cc | 15 +++- src/xenia/kernel/xam/user_profile.cc | 24 +++++ src/xenia/kernel/xam/user_profile.h | 6 ++ 6 files changed, 243 insertions(+), 13 deletions(-) create mode 100644 src/xenia/kernel/util/property.cc create mode 100644 src/xenia/kernel/util/property.h diff --git a/src/xenia/kernel/util/property.cc b/src/xenia/kernel/util/property.cc new file mode 100644 index 000000000..83d32d70e --- /dev/null +++ b/src/xenia/kernel/util/property.cc @@ -0,0 +1,130 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2024 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/kernel/util/property.h" +#include "xenia/base/logging.h" + +namespace xe { +namespace kernel { + +Property::Property(uint32_t property_id, uint32_t value_size, + uint8_t* value_ptr) { + property_id_.value = property_id; + data_type_ = static_cast(property_id_.type); + + value_size_ = value_size; + value_.resize(value_size); + + if (value_ptr != 0) { + memcpy(value_.data(), value_ptr, value_size); + } else { + XELOGW("{} Ctor: provided value_ptr is nullptr!", __func__); + } +} + +Property::Property(const uint8_t* serialized_data, size_t data_size) { + if (data_size < 8) { + XELOGW("Property::Property lacks information. Skipping!"); + return; + } + + memcpy(&property_id_, serialized_data, sizeof(property_id_)); + data_type_ = static_cast(property_id_.type); + + memcpy(&value_size_, serialized_data + 4, sizeof(value_size_)); + + value_.resize(value_size_); + memcpy(value_.data(), serialized_data + 8, value_size_); +} + +Property::~Property() {}; + +std::vector Property::Serialize() const { + std::vector serialized_property; + serialized_property.resize(sizeof(property_id_) + sizeof(value_size_) + + value_.size()); + + size_t offset = 0; + memcpy(serialized_property.data(), &property_id_, sizeof(property_id_)); + offset += sizeof(property_id_); + + memcpy(serialized_property.data() + offset, &value_size_, + sizeof(value_size_)); + + offset += sizeof(value_size_); + + memcpy(serialized_property.data() + offset, value_.data(), value_.size()); + + return serialized_property; +} + +void Property::Write(Memory* memory, XUSER_PROPERTY* property) const { + property->property_id = property_id_.value; + property->data.type = data_type_; + + switch (data_type_) { + case X_USER_DATA_TYPE::WSTRING: + property->data.binary.size = value_size_; + break; + case X_USER_DATA_TYPE::CONTENT: + case X_USER_DATA_TYPE::BINARY: + property->data.binary.size = value_size_; + // Property pointer must be valid at this point! + memcpy(memory->TranslateVirtual(property->data.binary.ptr), value_.data(), + value_size_); + break; + case X_USER_DATA_TYPE::INT32: + memcpy(reinterpret_cast(&property->data.s32), value_.data(), + value_size_); + break; + case X_USER_DATA_TYPE::INT64: + memcpy(reinterpret_cast(&property->data.s64), value_.data(), + value_size_); + break; + case X_USER_DATA_TYPE::DOUBLE: + memcpy(reinterpret_cast(&property->data.f64), value_.data(), + value_size_); + break; + case X_USER_DATA_TYPE::FLOAT: + memcpy(reinterpret_cast(&property->data.f32), value_.data(), + value_size_); + break; + case X_USER_DATA_TYPE::DATETIME: + memcpy(reinterpret_cast(&property->data.filetime), + value_.data(), value_size_); + break; + default: + break; + } +} + +userDataVariant Property::GetValue() const { + switch (data_type_) { + case X_USER_DATA_TYPE::CONTENT: + case X_USER_DATA_TYPE::BINARY: + return value_; + case X_USER_DATA_TYPE::INT32: + return *reinterpret_cast(value_.data()); + case X_USER_DATA_TYPE::INT64: + case X_USER_DATA_TYPE::DATETIME: + return *reinterpret_cast(value_.data()); + case X_USER_DATA_TYPE::DOUBLE: + return *reinterpret_cast(value_.data()); + case X_USER_DATA_TYPE::WSTRING: + return std::u16string(reinterpret_cast(value_.data())); + case X_USER_DATA_TYPE::FLOAT: + return *reinterpret_cast(value_.data()); + default: + break; + } + return value_; +} + +} // namespace kernel +} // namespace xe \ No newline at end of file diff --git a/src/xenia/kernel/util/property.h b/src/xenia/kernel/util/property.h new file mode 100644 index 000000000..6a7119051 --- /dev/null +++ b/src/xenia/kernel/util/property.h @@ -0,0 +1,71 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2024 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_UTIL_PROPERTY_H_ +#define XENIA_KERNEL_UTIL_PROPERTY_H_ + +#include + +#include "xenia/base/byte_stream.h" +#include "xenia/kernel/util/xuserdata.h" +#include "xenia/memory.h" +#include "xenia/xbox.h" + +namespace xe { +namespace kernel { + +struct XUSER_PROPERTY { + xe::be property_id; + X_USER_DATA data; +}; + +using userDataVariant = std::variant >; + +class Property { + public: + // Ctor used while guest is creating property. + Property(uint32_t property_id, uint32_t value_size, uint8_t* value_ptr); + // Ctor used for deserialization + Property(const uint8_t* serialized_data, size_t data_size); + ~Property(); + + const AttributeKey GetPropertyId() const { return property_id_; } + + bool IsValid() const { return property_id_.value != 0; } + std::vector Serialize() const; + + // Writer back to guest structure + void Write(Memory* memory, XUSER_PROPERTY* property) const; + uint32_t GetSize() const { return value_size_; } + + bool RequiresPointer() const { + return static_cast(property_id_.type) == + X_USER_DATA_TYPE::CONTENT || + static_cast(property_id_.type) == + X_USER_DATA_TYPE::WSTRING || + static_cast(property_id_.type) == + X_USER_DATA_TYPE::BINARY; + } + + // Returns variant for specific value in LE (host) notation. + userDataVariant GetValue() const; + + private: + AttributeKey property_id_ = {}; + X_USER_DATA_TYPE data_type_ = X_USER_DATA_TYPE::UNSET; + + uint32_t value_size_ = 0; + std::vector value_; +}; + +} // namespace kernel +} // namespace xe + +#endif \ No newline at end of file diff --git a/src/xenia/kernel/util/xuserdata.h b/src/xenia/kernel/util/xuserdata.h index c2a6c502e..a601c91c5 100644 --- a/src/xenia/kernel/util/xuserdata.h +++ b/src/xenia/kernel/util/xuserdata.h @@ -74,16 +74,6 @@ class DataByteStream : public ByteStream { class UserData { public: - union Key { - uint32_t value; - struct { - uint32_t id : 14; - uint32_t unk : 2; - uint32_t size : 12; - uint32_t type : 4; - }; - }; - UserData() {}; UserData(X_USER_DATA_TYPE type) { data_.type = type; } diff --git a/src/xenia/kernel/xam/apps/xgi_app.cc b/src/xenia/kernel/xam/apps/xgi_app.cc index 1ad39c27d..0b9376b96 100644 --- a/src/xenia/kernel/xam/apps/xgi_app.cc +++ b/src/xenia/kernel/xam/apps/xgi_app.cc @@ -71,11 +71,20 @@ X_HRESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, const util::XdbfGameData title_xdbf = kernel_state_->title_xdbf(); if (title_xdbf.is_valid()) { - const auto property = title_xdbf.GetProperty(property_id); + const auto property_xdbf = title_xdbf.GetProperty(property_id); const XLanguage title_language = title_xdbf.GetExistingLanguage( static_cast(XLanguage::kEnglish)); - const std::string desc = - title_xdbf.GetStringTableEntry(title_language, property.string_id); + const std::string desc = title_xdbf.GetStringTableEntry( + title_language, property_xdbf.string_id); + + Property property = + Property(property_id, value_size, + memory_->TranslateVirtual(value_ptr)); + + auto user = kernel_state_->user_profile(user_index); + if (user) { + user->AddProperty(&property); + } XELOGD("XGIUserSetPropertyEx: Setting property: {}", desc); } diff --git a/src/xenia/kernel/xam/user_profile.cc b/src/xenia/kernel/xam/user_profile.cc index b8b0ef4c9..c086d881a 100644 --- a/src/xenia/kernel/xam/user_profile.cc +++ b/src/xenia/kernel/xam/user_profile.cc @@ -212,6 +212,30 @@ void UserProfile::SaveSetting(UserSetting* setting) { } } +bool UserProfile::AddProperty(const Property* property) { + // Find if property already exits + const Property* entry = GetProperty(property->GetPropertyId()); + if (entry) { + entry = property; + return true; + } + + properties_.push_back(*property); + return true; +} + +const Property* UserProfile::GetProperty(const AttributeKey id) const { + for (auto& entry : properties_) { + if (entry.GetPropertyId().value != id.value) { + continue; + } + + return &entry; + } + + return nullptr; +} + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam/user_profile.h b/src/xenia/kernel/xam/user_profile.h index a8d684f1b..a97ef401c 100644 --- a/src/xenia/kernel/xam/user_profile.h +++ b/src/xenia/kernel/xam/user_profile.h @@ -17,6 +17,7 @@ #include #include "xenia/base/byte_stream.h" +#include "xenia/kernel/util/property.h" #include "xenia/kernel/util/xuserdata.h" #include "xenia/xbox.h" @@ -162,6 +163,9 @@ class UserProfile { void AddSetting(std::unique_ptr setting); UserSetting* GetSetting(uint32_t setting_id); + bool AddProperty(const Property* property); + const Property* GetProperty(const AttributeKey id) const; + std::map contexts_; private: @@ -170,6 +174,8 @@ class UserProfile { std::vector> setting_list_; std::unordered_map settings_; + std::vector properties_; + void LoadSetting(UserSetting*); void SaveSetting(UserSetting*); };