Skip to content

Commit

Permalink
Merge branch 'xenia-canary:canary_experimental' into Custom
Browse files Browse the repository at this point in the history
  • Loading branch information
backgamon authored Sep 22, 2024
2 parents 81176f8 + d246e3b commit 9ccac56
Show file tree
Hide file tree
Showing 11 changed files with 615 additions and 28 deletions.
153 changes: 153 additions & 0 deletions src/xenia/kernel/util/presence_string_builder.cc
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
80 changes: 80 additions & 0 deletions src/xenia/kernel/util/presence_string_builder.h
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_
130 changes: 130 additions & 0 deletions src/xenia/kernel/util/property.cc
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
Loading

0 comments on commit 9ccac56

Please sign in to comment.