From 729a1af0d52baac18c3a4249c8a794f6f10be4c8 Mon Sep 17 00:00:00 2001 From: x1nixmzeng Date: Thu, 7 Jan 2016 00:51:27 +0000 Subject: [PATCH] Added XDBF utility library Utility library to support the XDBF file format for XEX module resources --- premake5.lua | 1 + src/xenia/app/premake5.lua | 1 + src/xenia/xdbf/premake5.lua | 17 +++++ src/xenia/xdbf/xdbf_utils.cc | 141 +++++++++++++++++++++++++++++++++++ src/xenia/xdbf/xdbf_utils.h | 122 ++++++++++++++++++++++++++++++ 5 files changed, 282 insertions(+) create mode 100644 src/xenia/xdbf/premake5.lua create mode 100644 src/xenia/xdbf/xdbf_utils.cc create mode 100644 src/xenia/xdbf/xdbf_utils.h diff --git a/premake5.lua b/premake5.lua index 3431b60da..c559c7361 100644 --- a/premake5.lua +++ b/premake5.lua @@ -190,6 +190,7 @@ solution("xenia") include("src/xenia/ui/gl") include("src/xenia/ui/spirv") include("src/xenia/vfs") + include("src/xenia/xdbf") if os.is("windows") then include("src/xenia/apu/xaudio2") diff --git a/src/xenia/app/premake5.lua b/src/xenia/app/premake5.lua index d72059e22..245e90d69 100644 --- a/src/xenia/app/premake5.lua +++ b/src/xenia/app/premake5.lua @@ -25,6 +25,7 @@ project("xenia-app") "xenia-ui", "xenia-ui-gl", "xenia-vfs", + "xenia-xdbf", }) flags({ "WinMain", -- Use WinMain instead of main. diff --git a/src/xenia/xdbf/premake5.lua b/src/xenia/xdbf/premake5.lua new file mode 100644 index 000000000..44e9e6a64 --- /dev/null +++ b/src/xenia/xdbf/premake5.lua @@ -0,0 +1,17 @@ +project_root = "../../.." +include(project_root.."/tools/build") + +group("src") +project("xenia-xdbf") + uuid("a95b5fce-1083-4bff-a022-ffdd0bab3db0") + kind("StaticLib") + language("C++") + links({ + "xenia-base", + }) + defines({ + }) + includedirs({ + project_root.."third_party/gflags/src", + }) + recursive_platform_files() diff --git a/src/xenia/xdbf/xdbf_utils.cc b/src/xenia/xdbf/xdbf_utils.cc new file mode 100644 index 000000000..993f88b44 --- /dev/null +++ b/src/xenia/xdbf/xdbf_utils.cc @@ -0,0 +1,141 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +#include "xenia/xdbf/xdbf_utils.h" + +namespace xe { +namespace xdbf { + + XdbfWrapper::XdbfWrapper() = default; + + XBDF_HEADER& XdbfWrapper::get_header() const + { + return *state_.header; + } + + XBDF_ENTRY& XdbfWrapper::get_entry(uint32_t n) const + { + return state_.entries[n]; + } + + XBDF_FILE_LOC& XdbfWrapper::get_file(uint32_t n) const + { + return state_.files[n]; + } + + bool XdbfWrapper::initialize(uint8_t* buffer, size_t length) + { + if (length <= sizeof(XBDF_HEADER)) { + return false; + } + + XdbfState state; + + state.data = buffer; + state.size = length; + + uint8_t* ptr = state.data; + + state.header = reinterpret_cast(ptr); + ptr += sizeof(XBDF_HEADER); + + state.entries = reinterpret_cast(ptr); + ptr += (sizeof(XBDF_ENTRY) * state.header->entry_max); + + state.files = reinterpret_cast(ptr); + ptr += (sizeof(XBDF_FILE_LOC) * state.header->free_max); + + state.offset = ptr; + + if (state.header->magic == 'XDBF') { + state_ = state; + return true; + } + + return false; + } + + XdbfBlock XdbfWrapper::get_entry(XdbfSection section, uint64_t id) const { + + XdbfBlock block = { nullptr,0 }; + uint32_t x = 0; + + while( x < get_header().entry_current ) { + auto &entry = get_entry(x); + + if (entry.section == section && entry.id == id) { + block.buffer = state_.offset + entry.offset; + block.size = entry.size; + break; + } + + ++x; + } + + return block; + } + + std::vector get_icon(XdbfWrapper& ref) + { + std::vector icon; + + XdbfBlock block = ref.get_entry(kSectionImage, 0x8000); + + if (block.buffer != nullptr) { + icon.resize(block.size); + std::copy(block.buffer, block.buffer + block.size, icon.data()); + } + + return icon; + } + + std::string get_title(XdbfWrapper& ref) + { + std::string title_str; + + XdbfBlock block = ref.get_entry(kSectionMetadata, 0x58535443); + if (block.buffer != nullptr) { + XDBF_XSTC* xstc = reinterpret_cast(block.buffer); + + assert_true(xstc->magic == 'XSTC'); + uint32_t def_language = xstc->default_language; + + XdbfBlock lang_block = ref.get_entry(kSectionStringTable, static_cast(def_language)); + + if (lang_block.buffer != nullptr) { + XDBF_XSTR_HEADER* xstr_head = reinterpret_cast(lang_block.buffer); + + assert_true(xstr_head->magic == 'XSTR'); + assert_true(xstr_head->version == 1); + + uint16_t str_count = xstr_head->string_count; + uint8_t *currentAddress = lang_block.buffer + sizeof(XDBF_XSTR_HEADER); + + uint16_t s = 0; + while( s < str_count && title_str.empty() ) { + XDBF_STRINGTABLE_ENTRY* entry = reinterpret_cast(currentAddress); + currentAddress += sizeof(XDBF_STRINGTABLE_ENTRY); + uint16_t len = entry->string_length; + + if (entry->id == 0x00008000) { + title_str.resize(static_cast(len)); + std::copy(currentAddress, currentAddress + len, title_str.begin()); + } + + currentAddress += len; + } + } + } + + return title_str; + } + + +} // namespace xdbf +} // namespace xe diff --git a/src/xenia/xdbf/xdbf_utils.h b/src/xenia/xdbf/xdbf_utils.h new file mode 100644 index 000000000..f8b80c1af --- /dev/null +++ b/src/xenia/xdbf/xdbf_utils.h @@ -0,0 +1,122 @@ +/** + ****************************************************************************** + * 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_XDBF_XDBF_UTILS_H_ +#define XENIA_XDBF_XDBF_UTILS_H_ + +#include +#include + +#include "xenia/base/memory.h" + +namespace xe { +namespace xdbf { + + // http://freestyledash.googlecode.com/svn/trunk/Freestyle/Tools/XEX/SPA.h + // http://freestyledash.googlecode.com/svn/trunk/Freestyle/Tools/XEX/SPA.cpp + + enum XdbfSection : uint16_t { + kSectionMetadata = 0x0001, + kSectionImage = 0x0002, + kSectionStringTable = 0x0003, + }; + + enum XdbfLocale : uint32_t { + kLocaleDefault = 0, + kLocaleEnglish = 1, + kLocaleJapanese = 2, + }; + + struct XBDF_HEADER { + xe::be magic; + xe::be version; + xe::be entry_max; + xe::be entry_current; + xe::be free_max; + xe::be free_current; + }; + static_assert_size(XBDF_HEADER, 24); + +#pragma pack(push, 1) + struct XBDF_ENTRY { + xe::be section; + xe::be id; + xe::be offset; + xe::be size; + }; + static_assert_size(XBDF_ENTRY, 18); +#pragma pack(pop) + + struct XBDF_FILE_LOC { + xe::be offset; + xe::be size; + }; + static_assert_size(XBDF_FILE_LOC, 8); + + struct XDBF_XSTC { + xe::be magic; + xe::be version; + xe::be size; + xe::be default_language; + }; + static_assert_size(XDBF_XSTC, 16); + +#pragma pack(push, 1) + struct XDBF_XSTR_HEADER { + xe::be magic; + xe::be version; + xe::be size; + xe::be string_count; + }; + static_assert_size(XDBF_XSTR_HEADER, 14); +#pragma pack(pop) + + struct XDBF_STRINGTABLE_ENTRY { + xe::be id; + xe::be string_length; + }; + static_assert_size(XDBF_STRINGTABLE_ENTRY, 4); + + struct XdbfState { + XBDF_HEADER* header; + XBDF_ENTRY* entries; + XBDF_FILE_LOC* files; + uint8_t* offset; + uint8_t* data; + size_t size; + }; + + struct XdbfBlock { + uint8_t* buffer; + size_t size; + }; + + class XdbfWrapper { + public: + XdbfWrapper(); + + bool initialize(uint8_t* buffer, size_t length); + XdbfBlock get_entry(XdbfSection section, uint64_t id) const; + + private: + XBDF_HEADER& get_header() const; + XBDF_ENTRY& get_entry(uint32_t n) const; + XBDF_FILE_LOC& get_file(uint32_t n) const; + + XdbfState state_; + }; + + std::vector get_icon(XdbfWrapper& ref); + std::string get_title(XdbfWrapper& ref); + + +} // namespace xdbf +} // namespace xe + +#endif // XENIA_XDBF_XDBF_UTILS_H_