|
| 1 | +/** |
| 2 | + ****************************************************************************** |
| 3 | + * Xenia : Xbox 360 Emulator Research Project * |
| 4 | + ****************************************************************************** |
| 5 | + * Copyright 2024 Ben Vanik. All rights reserved. * |
| 6 | + * Released under the BSD license - see LICENSE in the root for more details. * |
| 7 | + ****************************************************************************** |
| 8 | + */ |
| 9 | + |
| 10 | +#ifndef XENIA_KERNEL_UTIL_XUSERDATA_H_ |
| 11 | +#define XENIA_KERNEL_UTIL_XUSERDATA_H_ |
| 12 | + |
| 13 | +#include "xenia/base/byte_stream.h" |
| 14 | +#include "xenia/xbox.h" |
| 15 | + |
| 16 | +namespace xe { |
| 17 | +namespace kernel { |
| 18 | + |
| 19 | +enum class X_USER_DATA_TYPE : uint8_t { |
| 20 | + CONTENT = 0, |
| 21 | + INT32 = 1, |
| 22 | + INT64 = 2, |
| 23 | + DOUBLE = 3, |
| 24 | + WSTRING = 4, |
| 25 | + FLOAT = 5, |
| 26 | + BINARY = 6, |
| 27 | + DATETIME = 7, |
| 28 | + UNSET = 0xFF, |
| 29 | +}; |
| 30 | + |
| 31 | +struct X_USER_DATA { |
| 32 | + X_USER_DATA_TYPE type; |
| 33 | + |
| 34 | + union { |
| 35 | + be<int32_t> s32; |
| 36 | + be<int64_t> s64; |
| 37 | + be<uint32_t> u32; |
| 38 | + be<double> f64; |
| 39 | + struct { |
| 40 | + be<uint32_t> size; |
| 41 | + be<uint32_t> ptr; |
| 42 | + } unicode; |
| 43 | + be<float> f32; |
| 44 | + struct { |
| 45 | + be<uint32_t> size; |
| 46 | + be<uint32_t> ptr; |
| 47 | + } binary; |
| 48 | + be<uint64_t> filetime; |
| 49 | + }; |
| 50 | +}; |
| 51 | +static_assert_size(X_USER_DATA, 16); |
| 52 | + |
| 53 | +class DataByteStream : public ByteStream { |
| 54 | + public: |
| 55 | + DataByteStream(uint32_t ptr, uint8_t* data, size_t data_length, |
| 56 | + size_t offset = 0) |
| 57 | + : ByteStream(data, data_length, offset), ptr_(ptr) {} |
| 58 | + |
| 59 | + uint32_t ptr() const { return static_cast<uint32_t>(ptr_ + offset()); } |
| 60 | + |
| 61 | + private: |
| 62 | + uint32_t ptr_; |
| 63 | +}; |
| 64 | + |
| 65 | +class UserData { |
| 66 | + public: |
| 67 | + union Key { |
| 68 | + uint32_t value; |
| 69 | + struct { |
| 70 | + uint32_t id : 14; |
| 71 | + uint32_t unk : 2; |
| 72 | + uint32_t size : 12; |
| 73 | + uint32_t type : 4; |
| 74 | + }; |
| 75 | + }; |
| 76 | + |
| 77 | + UserData(){}; |
| 78 | + UserData(X_USER_DATA_TYPE type) { data_.type = type; } |
| 79 | + |
| 80 | + virtual void Append(X_USER_DATA* data, DataByteStream* stream) { |
| 81 | + data->type = data_.type; |
| 82 | + } |
| 83 | + |
| 84 | + virtual std::vector<uint8_t> Serialize() const { |
| 85 | + return std::vector<uint8_t>(); |
| 86 | + } |
| 87 | + virtual void Deserialize(std::vector<uint8_t>) {} |
| 88 | + |
| 89 | + private: |
| 90 | + X_USER_DATA data_ = {}; |
| 91 | +}; |
| 92 | + |
| 93 | +class Int32UserData : public UserData { |
| 94 | + public: |
| 95 | + Int32UserData(int32_t value) |
| 96 | + : UserData(X_USER_DATA_TYPE::INT32), value_(value) {} |
| 97 | + void Append(X_USER_DATA* data, DataByteStream* stream) override { |
| 98 | + UserData::Append(data, stream); |
| 99 | + data->s32 = value_; |
| 100 | + } |
| 101 | + |
| 102 | + private: |
| 103 | + int32_t value_; |
| 104 | +}; |
| 105 | + |
| 106 | +class Uint32UserData : public UserData { |
| 107 | + public: |
| 108 | + Uint32UserData(uint32_t value) |
| 109 | + : UserData(X_USER_DATA_TYPE::INT32), value_(value) {} |
| 110 | + void Append(X_USER_DATA* data, DataByteStream* stream) override { |
| 111 | + UserData::Append(data, stream); |
| 112 | + data->u32 = value_; |
| 113 | + } |
| 114 | + |
| 115 | + private: |
| 116 | + uint32_t value_; |
| 117 | +}; |
| 118 | + |
| 119 | +class Int64UserData : public UserData { |
| 120 | + public: |
| 121 | + Int64UserData(int64_t value) |
| 122 | + : UserData(X_USER_DATA_TYPE::INT64), value_(value) {} |
| 123 | + void Append(X_USER_DATA* data, DataByteStream* stream) override { |
| 124 | + UserData::Append(data, stream); |
| 125 | + data->s64 = value_; |
| 126 | + } |
| 127 | + |
| 128 | + private: |
| 129 | + int64_t value_; |
| 130 | +}; |
| 131 | + |
| 132 | +class FloatUserData : public UserData { |
| 133 | + public: |
| 134 | + FloatUserData(float value) |
| 135 | + : UserData(X_USER_DATA_TYPE::FLOAT), value_(value) {} |
| 136 | + |
| 137 | + void Append(X_USER_DATA* data, DataByteStream* stream) override { |
| 138 | + UserData::Append(data, stream); |
| 139 | + data->f32 = value_; |
| 140 | + } |
| 141 | + |
| 142 | + private: |
| 143 | + float value_; |
| 144 | +}; |
| 145 | + |
| 146 | +class DoubleUserData : public UserData { |
| 147 | + public: |
| 148 | + DoubleUserData(double value) |
| 149 | + : UserData(X_USER_DATA_TYPE::DOUBLE), value_(value) {} |
| 150 | + void Append(X_USER_DATA* data, DataByteStream* stream) override { |
| 151 | + UserData::Append(data, stream); |
| 152 | + data->f64 = value_; |
| 153 | + } |
| 154 | + |
| 155 | + private: |
| 156 | + double value_; |
| 157 | +}; |
| 158 | + |
| 159 | +class UnicodeUserData : public UserData { |
| 160 | + public: |
| 161 | + UnicodeUserData(const std::u16string& value) |
| 162 | + : UserData(X_USER_DATA_TYPE::WSTRING), value_(value) {} |
| 163 | + void Append(X_USER_DATA* data, DataByteStream* stream) override { |
| 164 | + UserData::Append(data, stream); |
| 165 | + |
| 166 | + if (value_.empty()) { |
| 167 | + data->unicode.size = 0; |
| 168 | + data->unicode.ptr = 0; |
| 169 | + return; |
| 170 | + } |
| 171 | + |
| 172 | + size_t count = value_.size() + 1; |
| 173 | + size_t size = 2 * count; |
| 174 | + assert_true(size <= std::numeric_limits<uint32_t>::max()); |
| 175 | + data->unicode.size = static_cast<uint32_t>(size); |
| 176 | + data->unicode.ptr = stream->ptr(); |
| 177 | + auto buffer = |
| 178 | + reinterpret_cast<uint16_t*>(&stream->data()[stream->offset()]); |
| 179 | + stream->Advance(size); |
| 180 | + copy_and_swap(buffer, (uint16_t*)value_.data(), count); |
| 181 | + } |
| 182 | + |
| 183 | + private: |
| 184 | + std::u16string value_; |
| 185 | +}; |
| 186 | + |
| 187 | +class BinaryUserData : public UserData { |
| 188 | + public: |
| 189 | + BinaryUserData(const std::vector<uint8_t>& value) |
| 190 | + : UserData(X_USER_DATA_TYPE::BINARY), value_(value) {} |
| 191 | + void Append(X_USER_DATA* data, DataByteStream* stream) override { |
| 192 | + UserData::Append(data, stream); |
| 193 | + |
| 194 | + if (value_.empty()) { |
| 195 | + data->binary.size = 0; |
| 196 | + data->binary.ptr = 0; |
| 197 | + return; |
| 198 | + } |
| 199 | + |
| 200 | + size_t size = value_.size(); |
| 201 | + assert_true(size <= std::numeric_limits<uint32_t>::max()); |
| 202 | + data->binary.size = static_cast<uint32_t>(size); |
| 203 | + data->binary.ptr = stream->ptr(); |
| 204 | + stream->Write(value_.data(), size); |
| 205 | + } |
| 206 | + |
| 207 | + std::vector<uint8_t> Serialize() const override { |
| 208 | + return std::vector<uint8_t>(value_.data(), value_.data() + value_.size()); |
| 209 | + } |
| 210 | + |
| 211 | + void Deserialize(std::vector<uint8_t> data) override { value_ = data; } |
| 212 | + |
| 213 | + private: |
| 214 | + std::vector<uint8_t> value_; |
| 215 | +}; |
| 216 | + |
| 217 | +class DateTimeUserData : public UserData { |
| 218 | + public: |
| 219 | + DateTimeUserData(int64_t value) |
| 220 | + : UserData(X_USER_DATA_TYPE::DATETIME), value_(value) {} |
| 221 | + |
| 222 | + void Append(X_USER_DATA* data, DataByteStream* stream) override { |
| 223 | + UserData::Append(data, stream); |
| 224 | + data->filetime = value_; |
| 225 | + } |
| 226 | + |
| 227 | + private: |
| 228 | + int64_t value_; |
| 229 | +}; |
| 230 | + |
| 231 | +} // namespace kernel |
| 232 | +} // namespace xe |
| 233 | + |
| 234 | +#endif |
0 commit comments