forked from xenia-canary/xenia-canary
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'xenia-canary:canary_experimental' into Custom
- Loading branch information
Showing
11 changed files
with
615 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/** | ||
****************************************************************************** | ||
* 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/presence_string_builder.h" | ||
#include "xenia/kernel/util/shim_utils.h" | ||
|
||
namespace xe { | ||
namespace kernel { | ||
namespace util { | ||
|
||
AttributeStringFormatter::~AttributeStringFormatter() {} | ||
|
||
AttributeStringFormatter::AttributeStringFormatter( | ||
std::string_view attribute_string, XLast* title_xlast, | ||
std::map<uint32_t, uint32_t> contexts) | ||
: attribute_string_(attribute_string), attribute_to_string_mapping_() { | ||
contexts_ = contexts; | ||
title_xlast_ = title_xlast; | ||
|
||
presence_string_ = ""; | ||
|
||
if (!ParseAttributeString()) { | ||
return; | ||
} | ||
|
||
BuildPresenceString(); | ||
} | ||
|
||
bool AttributeStringFormatter::ParseAttributeString() { | ||
auto specifiers = GetPresenceFormatSpecifiers(); | ||
|
||
if (specifiers.empty()) { | ||
return true; | ||
} | ||
|
||
std::string specifier; | ||
while (!specifiers.empty()) { | ||
std::string specifier = specifiers.front(); | ||
attribute_to_string_mapping_[specifier] = GetStringFromSpecifier(specifier); | ||
specifiers.pop(); | ||
} | ||
return true; | ||
} | ||
|
||
void AttributeStringFormatter::BuildPresenceString() { | ||
presence_string_ = attribute_string_; | ||
|
||
for (const auto& entry : attribute_to_string_mapping_) { | ||
presence_string_.replace(presence_string_.find(entry.first), | ||
entry.first.length(), entry.second); | ||
} | ||
} | ||
|
||
AttributeStringFormatter::AttributeType | ||
AttributeStringFormatter::GetAttributeTypeFromSpecifier( | ||
std::string_view specifier) const { | ||
if (specifier.length() < 3) { | ||
return AttributeStringFormatter::AttributeType::Unknown; | ||
} | ||
|
||
const char presence_type = specifier.at(1); | ||
if (presence_type == 'c') { | ||
return AttributeStringFormatter::AttributeType::Context; | ||
} | ||
if (presence_type == 'p') { | ||
return AttributeStringFormatter::AttributeType::Property; | ||
} | ||
return AttributeStringFormatter::AttributeType::Unknown; | ||
} | ||
|
||
std::optional<uint32_t> AttributeStringFormatter::GetAttributeIdFromSpecifier( | ||
const std::string& specifier, | ||
const AttributeStringFormatter::AttributeType specifier_type) const { | ||
std::smatch string_match; | ||
if (std::regex_search(specifier, string_match, | ||
presence_id_extract_from_specifier)) { | ||
return std::make_optional<uint32_t>(stoi(string_match[1].str())); | ||
} | ||
|
||
return std::nullopt; | ||
} | ||
|
||
std::string AttributeStringFormatter::GetStringFromSpecifier( | ||
std::string_view specifier) const { | ||
const AttributeStringFormatter::AttributeType attribute_type = | ||
GetAttributeTypeFromSpecifier(specifier); | ||
|
||
if (attribute_type == AttributeStringFormatter::AttributeType::Unknown) { | ||
return ""; | ||
} | ||
|
||
const auto attribute_id = | ||
GetAttributeIdFromSpecifier(std::string(specifier), attribute_type); | ||
if (!attribute_id) { | ||
return ""; | ||
} | ||
|
||
if (attribute_type == AttributeStringFormatter::AttributeType::Context) { | ||
// TODO: Different handling for contexts and properties | ||
const auto itr = contexts_.find(attribute_id.value()); | ||
|
||
if (itr == contexts_.cend()) { | ||
auto attribute_placeholder = fmt::format("{{c{}}}", attribute_id.value()); | ||
|
||
return attribute_placeholder; | ||
} | ||
|
||
const auto attribute_string_id = | ||
title_xlast_->GetContextStringId(attribute_id.value(), itr->second); | ||
|
||
if (!attribute_string_id.has_value()) { | ||
return ""; | ||
} | ||
|
||
const auto attribute_string = title_xlast_->GetLocalizedString( | ||
attribute_string_id.value(), XLanguage::kEnglish); | ||
|
||
return xe::to_utf8(attribute_string); | ||
} | ||
|
||
if (attribute_type == AttributeStringFormatter::AttributeType::Property) { | ||
return ""; | ||
} | ||
|
||
return ""; | ||
} | ||
|
||
std::queue<std::string> AttributeStringFormatter::GetPresenceFormatSpecifiers() | ||
const { | ||
std::queue<std::string> format_specifiers; | ||
|
||
std::smatch match; | ||
|
||
std::string attribute_string = attribute_string_; | ||
|
||
while (std::regex_search(attribute_string, match, | ||
format_specifier_replace_fragment_regex_)) { | ||
for (const auto& presence : match) { | ||
format_specifiers.emplace(presence); | ||
} | ||
attribute_string = match.suffix().str(); | ||
} | ||
return format_specifiers; | ||
} | ||
} // namespace util | ||
} // namespace kernel | ||
} // namespace xe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/** | ||
****************************************************************************** | ||
* 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_PRESENCE_STRING_BUILDER_H_ | ||
#define XENIA_KERNEL_UTIL_PRESENCE_STRING_BUILDER_H_ | ||
|
||
#include <cstdint> | ||
#include <map> | ||
#include <optional> | ||
#include <queue> | ||
#include <regex> | ||
#include <string> | ||
#include <string_view> | ||
|
||
#include "xenia/kernel/util/xlast.h" | ||
|
||
namespace xe { | ||
namespace kernel { | ||
namespace util { | ||
|
||
class AttributeStringFormatter { | ||
public: | ||
~AttributeStringFormatter(); | ||
|
||
AttributeStringFormatter(std::string_view attribute_string, | ||
XLast* title_xlast, | ||
std::map<uint32_t, uint32_t> contexts); | ||
|
||
bool IsValid() const { return true; } | ||
std::string GetPresenceString() const { return presence_string_; } | ||
|
||
private: | ||
enum class AttributeType { Context = 0, Property = 1, Unknown = 255 }; | ||
|
||
const std::regex presence_id_extract_from_specifier = | ||
std::regex("\\{c(\\d+)\\}"); | ||
const std::regex format_specifier_replace_fragment_regex_ = | ||
std::regex(R"(\{c\d+\}|\{p0x\d+\})"); | ||
|
||
bool ParseAttributeString(); | ||
void BuildPresenceString(); | ||
|
||
std::string GetStringFromSpecifier(std::string_view specifier) const; | ||
std::queue<std::string> GetPresenceFormatSpecifiers() const; | ||
|
||
AttributeType GetAttributeTypeFromSpecifier(std::string_view specifier) const; | ||
std::optional<uint32_t> GetAttributeIdFromSpecifier( | ||
const std::string& specifier, | ||
const AttributeStringFormatter::AttributeType specifier_type) const; | ||
|
||
const std::string attribute_string_; | ||
std::map<std::string, std::string> attribute_to_string_mapping_; | ||
|
||
std::string presence_string_; | ||
|
||
std::map<uint32_t, uint32_t> contexts_; | ||
|
||
XLast* title_xlast_; | ||
|
||
// Tests | ||
// | ||
// std::map<uint32_t, std::string> contexts_ = { | ||
// {0, "Context 0"}, {1, "Context 1"}, {2, "Context 2"}}; | ||
|
||
// std::map<uint32_t, std::string> properties_ = { | ||
// {0x10000001, "Prop 0"}, {0x20000002, "Prop 2"}, {0x30000001, "Prop | ||
// 3"}}; | ||
}; | ||
|
||
} // namespace util | ||
} // namespace kernel | ||
} // namespace xe | ||
|
||
#endif XENIA_KERNEL_UTIL_PRESENCE_STRING_BUILDER_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<X_USER_DATA_TYPE>(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<X_USER_DATA_TYPE>(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<uint8_t> Property::Serialize() const { | ||
std::vector<uint8_t> 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<uint8_t*>(&property->data.s32), value_.data(), | ||
value_size_); | ||
break; | ||
case X_USER_DATA_TYPE::INT64: | ||
memcpy(reinterpret_cast<uint8_t*>(&property->data.s64), value_.data(), | ||
value_size_); | ||
break; | ||
case X_USER_DATA_TYPE::DOUBLE: | ||
memcpy(reinterpret_cast<uint8_t*>(&property->data.f64), value_.data(), | ||
value_size_); | ||
break; | ||
case X_USER_DATA_TYPE::FLOAT: | ||
memcpy(reinterpret_cast<uint8_t*>(&property->data.f32), value_.data(), | ||
value_size_); | ||
break; | ||
case X_USER_DATA_TYPE::DATETIME: | ||
memcpy(reinterpret_cast<uint8_t*>(&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<const uint32_t*>(value_.data()); | ||
case X_USER_DATA_TYPE::INT64: | ||
case X_USER_DATA_TYPE::DATETIME: | ||
return *reinterpret_cast<const uint64_t*>(value_.data()); | ||
case X_USER_DATA_TYPE::DOUBLE: | ||
return *reinterpret_cast<const double*>(value_.data()); | ||
case X_USER_DATA_TYPE::WSTRING: | ||
return std::u16string(reinterpret_cast<const char16_t*>(value_.data())); | ||
case X_USER_DATA_TYPE::FLOAT: | ||
return *reinterpret_cast<const float*>(value_.data()); | ||
default: | ||
break; | ||
} | ||
return value_; | ||
} | ||
|
||
} // namespace kernel | ||
} // namespace xe |
Oops, something went wrong.