/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2016 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_KERNEL_UTIL_XDBF_UTILS_H_ #define XENIA_KERNEL_UTIL_XDBF_UTILS_H_ #include #include #include "xenia/base/memory.h" #include "xenia/xbox.h" namespace xe { namespace kernel { namespace util { // https://github.com/oukiar/freestyledash/blob/master/Freestyle/Tools/XEX/SPA.h // https://github.com/oukiar/freestyledash/blob/master/Freestyle/Tools/XEX/SPA.cpp enum class XdbfSection : uint16_t { kMetadata = 0x0001, kImage = 0x0002, kStringTable = 0x0003, }; #pragma pack(push, 1) struct XbdfHeader { xe::be magic; xe::be version; xe::be entry_count; xe::be entry_used; xe::be free_count; xe::be free_used; }; static_assert_size(XbdfHeader, 24); struct XbdfEntry { xe::be section; xe::be id; xe::be offset; xe::be size; }; static_assert_size(XbdfEntry, 18); struct XbdfFileLoc { xe::be offset; xe::be size; }; static_assert_size(XbdfFileLoc, 8); struct XdbfXstc { xe::be magic; xe::be version; xe::be size; xe::be default_language; }; static_assert_size(XdbfXstc, 16); struct XdbfSectionHeader { xe::be magic; xe::be version; xe::be size; }; static_assert_size(XdbfSectionHeader, 12); struct XdbfStringTableEntry { xe::be id; xe::be string_length; }; static_assert_size(XdbfStringTableEntry, 4); struct XdbfContextTableEntry { xe::be id; xe::be unk1; xe::be string_id; xe::be max_value; xe::be default_value; }; static_assert_size(XdbfContextTableEntry, 16); struct XdbfPropertyTableEntry { xe::be id; xe::be string_id; xe::be data_size; }; static_assert_size(XdbfPropertyTableEntry, 8); struct XdbfAchievementTableEntry { xe::be id; xe::be label_id; xe::be description_id; xe::be unachieved_id; xe::be image_id; xe::be gamerscore; xe::be unkE; xe::be flags; xe::be unk14; xe::be unk18; xe::be unk1C; xe::be unk20; }; static_assert_size(XdbfAchievementTableEntry, 0x24); struct XdbfStatsViewTableEntry { xe::be id; xe::be flags; xe::be shared_index; xe::be string_id; xe::be unused; }; static_assert_size(XdbfStatsViewTableEntry, 0x10); struct XdbfViewFieldEntry { xe::be size; xe::be property_id; xe::be flags; xe::be attribute_id; xe::be string_id; xe::be aggregation_type; xe::be ordinal; xe::be field_type; xe::be format_type; xe::be unused_1; xe::be unused_2; }; static_assert_size(XdbfViewFieldEntry, 0x20); struct XdbfSharedViewMetaTableEntry { xe::be column_count; xe::be row_count; xe::be unused_1; xe::be unused_2; }; static_assert_size(XdbfSharedViewMetaTableEntry, 0xC); #pragma pack(pop) struct XdbfPropertyBag { std::vector> contexts; std::vector> properties; }; struct XdbfSharedView { std::vector column_entries; std::vector row_entries; XdbfPropertyBag property_bag; }; struct XdbfViewTable { XdbfStatsViewTableEntry view_entry; XdbfSharedView shared_view; }; struct XdbfBlock { const uint8_t* buffer; size_t size; operator bool() const { return buffer != nullptr; } }; // Wraps an XBDF (XboxDataBaseFormat) in-memory database. // https://free60project.github.io/wiki/XDBF.html class XdbfWrapper { public: XdbfWrapper(const uint8_t* data, size_t data_size); // True if the target memory contains a valid XDBF instance. bool is_valid() const { return data_ != nullptr; } // Gets an entry in the given section. // If the entry is not found the returned block will be nullptr. XdbfBlock GetEntry(XdbfSection section, uint64_t id) const; // Gets a string from the string table in the given language. // Returns the empty string if the entry is not found. std::string GetStringTableEntry(XLanguage language, uint16_t string_id) const; std::vector GetAchievements() const; std::vector GetProperties() const; std::vector GetContexts() const; XdbfAchievementTableEntry GetAchievement(const uint32_t id) const; XdbfPropertyTableEntry GetProperty(const uint32_t id) const; XdbfContextTableEntry GetContext(const uint32_t id) const; std::vector GetStatsView() const; XdbfSharedView GetSharedView(const uint8_t* ptr, uint32_t& byte_count) const; void GetPropertyBagMetadata(const uint8_t* ptr, uint32_t& byte_count, std::vector>& contexts, std::vector>& properties) const; XdbfPropertyBag GetMatchCollection() const; const uint8_t* ReadXLast(uint32_t& compressed_size, uint32_t& decompressed_size) const; private: const uint8_t* data_ = nullptr; size_t data_size_ = 0; const uint8_t* content_offset_ = nullptr; const XbdfHeader* header_ = nullptr; const XbdfEntry* entries_ = nullptr; const XbdfFileLoc* files_ = nullptr; }; class XdbfGameData : public XdbfWrapper { public: XdbfGameData(const uint8_t* data, size_t data_size) : XdbfWrapper(data, data_size) {} // Checks if provided language exist, if not returns default title language. XLanguage GetExistingLanguage(XLanguage language_to_check) const; // The game icon image, if found. XdbfBlock icon() const; // The game's default language. XLanguage default_language() const; // The game's title in its default language. std::string title() const; std::string title(XLanguage language) const; }; } // namespace util } // namespace kernel } // namespace xe #endif // XENIA_KERNEL_UTIL_XDBF_UTILS_H_