Added XDBF utility library
Utility library to support the XDBF file format for XEX module resources
This commit is contained in:
parent
16c97189dd
commit
729a1af0d5
|
@ -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")
|
||||
|
|
|
@ -25,6 +25,7 @@ project("xenia-app")
|
|||
"xenia-ui",
|
||||
"xenia-ui-gl",
|
||||
"xenia-vfs",
|
||||
"xenia-xdbf",
|
||||
})
|
||||
flags({
|
||||
"WinMain", -- Use WinMain instead of main.
|
||||
|
|
|
@ -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()
|
|
@ -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<XBDF_HEADER*>(ptr);
|
||||
ptr += sizeof(XBDF_HEADER);
|
||||
|
||||
state.entries = reinterpret_cast<XBDF_ENTRY*>(ptr);
|
||||
ptr += (sizeof(XBDF_ENTRY) * state.header->entry_max);
|
||||
|
||||
state.files = reinterpret_cast<XBDF_FILE_LOC*>(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<uint8_t> get_icon(XdbfWrapper& ref)
|
||||
{
|
||||
std::vector<uint8_t> 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<XDBF_XSTC*>(block.buffer);
|
||||
|
||||
assert_true(xstc->magic == 'XSTC');
|
||||
uint32_t def_language = xstc->default_language;
|
||||
|
||||
XdbfBlock lang_block = ref.get_entry(kSectionStringTable, static_cast<uint64_t>(def_language));
|
||||
|
||||
if (lang_block.buffer != nullptr) {
|
||||
XDBF_XSTR_HEADER* xstr_head = reinterpret_cast<XDBF_XSTR_HEADER*>(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<XDBF_STRINGTABLE_ENTRY*>(currentAddress);
|
||||
currentAddress += sizeof(XDBF_STRINGTABLE_ENTRY);
|
||||
uint16_t len = entry->string_length;
|
||||
|
||||
if (entry->id == 0x00008000) {
|
||||
title_str.resize(static_cast<size_t>(len));
|
||||
std::copy(currentAddress, currentAddress + len, title_str.begin());
|
||||
}
|
||||
|
||||
currentAddress += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return title_str;
|
||||
}
|
||||
|
||||
|
||||
} // namespace xdbf
|
||||
} // namespace xe
|
|
@ -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 <vector>
|
||||
#include <string>
|
||||
|
||||
#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<uint32_t> magic;
|
||||
xe::be<uint32_t> version;
|
||||
xe::be<uint32_t> entry_max;
|
||||
xe::be<uint32_t> entry_current;
|
||||
xe::be<uint32_t> free_max;
|
||||
xe::be<uint32_t> free_current;
|
||||
};
|
||||
static_assert_size(XBDF_HEADER, 24);
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct XBDF_ENTRY {
|
||||
xe::be<uint16_t> section;
|
||||
xe::be<uint64_t> id;
|
||||
xe::be<uint32_t> offset;
|
||||
xe::be<uint32_t> size;
|
||||
};
|
||||
static_assert_size(XBDF_ENTRY, 18);
|
||||
#pragma pack(pop)
|
||||
|
||||
struct XBDF_FILE_LOC {
|
||||
xe::be<uint32_t> offset;
|
||||
xe::be<uint32_t> size;
|
||||
};
|
||||
static_assert_size(XBDF_FILE_LOC, 8);
|
||||
|
||||
struct XDBF_XSTC {
|
||||
xe::be<uint32_t> magic;
|
||||
xe::be<uint32_t> version;
|
||||
xe::be<uint32_t> size;
|
||||
xe::be<uint32_t> default_language;
|
||||
};
|
||||
static_assert_size(XDBF_XSTC, 16);
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct XDBF_XSTR_HEADER {
|
||||
xe::be<uint32_t> magic;
|
||||
xe::be<uint32_t> version;
|
||||
xe::be<uint32_t> size;
|
||||
xe::be<uint16_t> string_count;
|
||||
};
|
||||
static_assert_size(XDBF_XSTR_HEADER, 14);
|
||||
#pragma pack(pop)
|
||||
|
||||
struct XDBF_STRINGTABLE_ENTRY {
|
||||
xe::be<uint16_t> id;
|
||||
xe::be<uint16_t> 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<uint8_t> get_icon(XdbfWrapper& ref);
|
||||
std::string get_title(XdbfWrapper& ref);
|
||||
|
||||
|
||||
} // namespace xdbf
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_XDBF_XDBF_UTILS_H_
|
Loading…
Reference in New Issue