PowerUtils: implemented XDBF wrapper

This commit is contained in:
Hyper 2024-11-25 11:12:38 +00:00
parent 7dd4f91ac6
commit dd85501f11
4 changed files with 410 additions and 0 deletions

203
PowerUtils/xdbf.h Normal file
View File

@ -0,0 +1,203 @@
#pragma once
#include <xbox.h>
#define XDBF_SIGNATURE 0x58444246
#define XACH_SIGNATURE 0x58414348
struct XDBFHeader
{
be<uint32_t> Signature;
be<uint32_t> Version;
be<uint32_t> EntryTableLength;
be<uint32_t> EntryCount;
be<uint32_t> FreeSpaceTableLength;
be<uint32_t> FreeSpaceTableEntryCount;
};
enum EXDBFNamespace : uint16_t
{
XDBF_SPA_NAMESPACE_METADATA = 1,
XDBF_SPA_NAMESPACE_IMAGE = 2,
XDBF_SPA_NAMESPACE_STRING_TABLE = 3,
XDBF_GPD_NAMESPACE_ACHIEVEMENT = 1,
XDBF_GPD_NAMESPACE_IMAGE = 2,
XDBF_GPD_NAMESPACE_SETTING = 3,
XDBF_GPD_NAMESPACE_TITLE = 4,
XDBF_GPD_NAMESPACE_STRING = 5,
XDBF_GPD_NAMESPACE_ACHIEVEMENT_SECURITY_GFWL = 6,
XDBF_GPD_NAMESPACE_AVATAR_AWARD_360 = 6
};
#pragma pack(1)
struct XDBFEntry
{
be<EXDBFNamespace> NamespaceID;
be<uint64_t> ResourceID;
be<uint32_t> Offset;
be<uint32_t> Length;
};
#pragma pack()
struct XDBFFreeSpaceEntry
{
be<uint32_t> Offset;
be<uint32_t> Length;
};
enum EXDBFLanguage : uint32_t
{
XDBF_LANGUAGE_UNKNOWN = 0,
XDBF_LANGUAGE_ENGLISH = 1,
XDBF_LANGUAGE_JAPANESE = 2,
XDBF_LANGUAGE_GERMAN = 3,
XDBF_LANGUAGE_FRENCH = 4,
XDBF_LANGUAGE_SPANISH = 5,
XDBF_LANGUAGE_ITALIAN = 6,
XDBF_LANGUAGE_KOREAN = 7,
XDBF_LANGUAGE_CHINESE_TRAD = 8,
XDBF_LANGUAGE_PORTUGUESE = 9,
XDBF_LANGUAGE_CHINESE_SIMP = 10,
XDBF_LANGUAGE_POLISH = 11,
XDBF_LANGUAGE_RUSSIAN = 12,
XDBF_LANGUAGE_MAX
};
struct XSTCHeader
{
be<uint32_t> Signature;
be<uint32_t> Version;
be<uint32_t> Size;
be<EXDBFLanguage> Language;
};
#pragma pack(1)
struct XSTRHeader
{
be<uint32_t> Signature;
be<uint32_t> Version;
be<uint32_t> Size;
be<uint16_t> StringCount;
};
#pragma pack()
struct XSTREntry
{
be<uint16_t> ID;
be<uint16_t> Length;
};
#pragma pack(1)
struct XACHHeader
{
be<uint32_t> Signature;
be<uint32_t> Version;
be<uint32_t> Size;
be<uint16_t> AchievementCount;
};
#pragma pack()
enum EXACHFlags : uint32_t
{
XACH_TYPE_COMPLETION = 1U,
XACH_TYPE_LEVELING = 2U,
XACH_TYPE_UNLOCK = 3U,
XACH_TYPE_EVENT = 4U,
XACH_TYPE_TOURNAMENT = 5U,
XACH_TYPE_CHECKPOINT = 6U,
XACH_TYPE_OTHER = 7U,
XACH_TYPE_MASK = 7U,
XACH_STATUS_UNACHIEVED = (1U << 4),
XACH_STATUS_EARNED_ONLINE = (1U << 16),
XACH_STATUS_EARNED = (1U << 17),
XACH_STATUS_EDITED = (1U << 20)
};
struct XACHEntry
{
be<uint16_t> AchievementID;
be<uint16_t> NameID;
be<uint16_t> UnlockedDescID;
be<uint16_t> LockedDescID;
be<uint32_t> ImageID;
be<uint16_t> Gamerscore;
char pad0[0x02];
be<EXACHFlags> Flags;
char pad1[0x10];
};
union XDBFTitleID
{
struct
{
be<uint16_t> u16;
char u8[0x02];
};
be<uint32_t> u32;
};
struct XDBFTitleVersion
{
be<uint16_t> Major;
be<uint16_t> Minor;
be<uint16_t> Build;
be<uint16_t> Revision;
};
enum EXDBFTitleType : uint32_t
{
XDBF_TITLE_TYPE_SYSTEM = 0,
XDBF_TITLE_TYPE_FULL = 1,
XDBF_TITLE_TYPE_DEMO = 2,
XDBF_TITLE_TYPE_DOWNLOAD = 3
};
struct XTHDHeader
{
be<uint32_t> Signature;
be<uint32_t> Version;
be<uint32_t> Size;
XDBFTitleID TitleID;
be<EXDBFTitleType> Type;
XDBFTitleVersion TitleVersion;
char pad0[0x10];
};
#pragma pack(1)
struct XGAAHeader
{
be<uint32_t> Signature;
be<uint32_t> Version;
be<uint32_t> Size;
be<uint16_t> Count;
};
#pragma pack()
struct XGAAEntry
{
char pad0[0x04];
be<uint16_t> AvatarAwardID;
char pad1[0x06];
XDBFTitleID TitleID;
be<uint16_t> NameID;
be<uint16_t> UnlockedDescID;
be<uint16_t> LockedDescID;
char pad2[0x02];
be<uint32_t> ImageID;
char pad3[0x08];
};
struct XSRCHeader
{
be<uint32_t> Signature;
be<uint32_t> Version;
be<uint32_t> Size;
be<uint32_t> FileNameLength;
};
struct XSRCHeader2
{
be<uint32_t> UncompressedSize;
be<uint32_t> CompressedSize;
};

152
PowerUtils/xdbf_wrapper.cpp Normal file
View File

@ -0,0 +1,152 @@
#include "xdbf_wrapper.h"
XDBFWrapper::XDBFWrapper(const uint8_t* buffer, size_t bufferSize) : pBuffer(buffer), BufferSize(bufferSize)
{
if (!buffer || bufferSize <= sizeof(XDBFHeader))
{
pBuffer = nullptr;
return;
}
auto seek = pBuffer;
pHeader = (XDBFHeader*)seek;
seek += sizeof(XDBFHeader);
if (pHeader->Signature != XDBF_SIGNATURE)
{
pBuffer = nullptr;
return;
}
pEntries = (XDBFEntry*)seek;
seek += sizeof(XDBFEntry) * pHeader->EntryCount;
pFiles = (XDBFFreeSpaceEntry*)seek;
seek += sizeof(XDBFFreeSpaceEntry) * pHeader->FreeSpaceTableLength;
pContent = seek;
}
XDBFBlock XDBFWrapper::GetResource(EXDBFNamespace ns, uint64_t id) const
{
for (int i = 0; i < pHeader->EntryCount; i++)
{
auto& entry = pEntries[i];
if (entry.NamespaceID == ns && entry.ResourceID == id)
{
XDBFBlock block{};
block.pBuffer = pContent + entry.Offset;
block.BufferSize = entry.Length;
return block;
}
}
return { nullptr };
}
std::string XDBFWrapper::GetString(EXDBFLanguage language, uint16_t id) const
{
auto languageBlock = GetResource(XDBF_SPA_NAMESPACE_STRING_TABLE, (uint64_t)language);
if (!languageBlock)
return "";
auto pHeader = (XSTRHeader*)languageBlock.pBuffer;
auto seek = languageBlock.pBuffer + sizeof(XSTRHeader);
for (int i = 0; i < pHeader->StringCount; i++)
{
auto entry = (XSTREntry*)seek;
seek += sizeof(XSTREntry);
if (entry->ID == id)
return std::string((const char*)seek, entry->Length);
seek += entry->Length;
}
return "";
}
std::vector<Achievement> XDBFWrapper::GetAchievements(EXDBFLanguage language) const
{
std::vector<Achievement> result;
auto achievementsBlock = GetResource(XDBF_SPA_NAMESPACE_METADATA, XACH_SIGNATURE);
if (!achievementsBlock)
return result;
auto pHeader = (XACHHeader*)achievementsBlock.pBuffer;
auto seek = achievementsBlock.pBuffer + sizeof(XACHHeader);
for (int i = 0; i < pHeader->AchievementCount; i++)
{
auto entry = (XACHEntry*)seek;
seek += sizeof(XACHEntry);
Achievement achievement{};
achievement.ID = entry->AchievementID;
achievement.Name = GetString(language, entry->NameID);
achievement.UnlockedDesc = GetString(language, entry->UnlockedDescID);
achievement.LockedDesc = GetString(language, entry->LockedDescID);
achievement.Score = entry->Gamerscore;
auto imageBlock = GetResource(XDBF_SPA_NAMESPACE_IMAGE, entry->ImageID);
if (imageBlock)
{
achievement.pImageBuffer = imageBlock.pBuffer;
achievement.ImageBufferSize = imageBlock.BufferSize;
}
result.push_back(achievement);
}
return result;
}
Achievement XDBFWrapper::GetAchievement(EXDBFLanguage language, uint16_t id) const
{
Achievement result{};
auto achievementsBlock = GetResource(XDBF_SPA_NAMESPACE_METADATA, 0x58414348);
if (!achievementsBlock)
return result;
auto pHeader = (XACHHeader*)achievementsBlock.pBuffer;
auto seek = achievementsBlock.pBuffer + sizeof(XACHHeader);
for (int i = 0; i < pHeader->AchievementCount; i++)
{
auto entry = (XACHEntry*)seek;
seek += sizeof(XACHEntry);
if (entry->AchievementID == id)
{
result.ID = entry->AchievementID;
result.Name = GetString(language, entry->NameID);
result.UnlockedDesc = GetString(language, entry->UnlockedDescID);
result.LockedDesc = GetString(language, entry->LockedDescID);
result.Score = entry->Gamerscore;
auto imageBlock = GetResource(XDBF_SPA_NAMESPACE_IMAGE, entry->ImageID);
if (imageBlock)
{
result.pImageBuffer = imageBlock.pBuffer;
result.ImageBufferSize = imageBlock.BufferSize;
}
return result;
}
}
return result;
}

47
PowerUtils/xdbf_wrapper.h Normal file
View File

@ -0,0 +1,47 @@
#pragma once
#include "xdbf.h"
struct Achievement
{
uint16_t ID;
std::string Name;
std::string UnlockedDesc;
std::string LockedDesc;
const uint8_t* pImageBuffer;
size_t ImageBufferSize;
uint16_t Score;
};
struct XDBFBlock
{
const uint8_t* pBuffer;
size_t BufferSize;
operator bool() const
{
return pBuffer;
}
};
class XDBFWrapper
{
public:
const uint8_t* pBuffer;
size_t BufferSize;
const uint8_t* pContent;
const XDBFHeader* pHeader;
const XDBFEntry* pEntries;
const XDBFFreeSpaceEntry* pFiles;
XDBFWrapper() {}
XDBFWrapper(const uint8_t* pBuffer, size_t bufferSize);
XDBFBlock GetResource(EXDBFNamespace ns, uint64_t id) const;
std::string GetString(EXDBFLanguage language, uint16_t id) const;
std::vector<Achievement> GetAchievements(EXDBFLanguage language) const;
Achievement GetAchievement(EXDBFLanguage language, uint16_t id) const;
};
extern XDBFWrapper g_xdbf;

View File

@ -54,6 +54,14 @@ typedef struct _XEX_FILE_FORMAT_INFO
be<uint16_t> CompressionType;
} XEX_FILE_FORMAT_INFO;
typedef struct _XEX_RESOURCE_INFO
{
be<uint32_t> SizeOfHeader;
uint8_t ResourceID[8];
be<uint32_t> Offset;
be<uint32_t> SizeOfData;
} XEX_RESOURCE_INFO;
typedef struct _XEX_BASIC_FILE_COMPRESSION_INFO
{
be<uint32_t> SizeOfData;