diff --git a/PowerUtils/xdbf.h b/PowerUtils/xdbf.h new file mode 100644 index 0000000..f3fa1a3 --- /dev/null +++ b/PowerUtils/xdbf.h @@ -0,0 +1,203 @@ +#pragma once + +#include + +#define XDBF_SIGNATURE 0x58444246 +#define XACH_SIGNATURE 0x58414348 + +struct XDBFHeader +{ + be Signature; + be Version; + be EntryTableLength; + be EntryCount; + be FreeSpaceTableLength; + be 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 NamespaceID; + be ResourceID; + be Offset; + be Length; +}; +#pragma pack() + +struct XDBFFreeSpaceEntry +{ + be Offset; + be 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 Signature; + be Version; + be Size; + be Language; +}; + +#pragma pack(1) +struct XSTRHeader +{ + be Signature; + be Version; + be Size; + be StringCount; +}; +#pragma pack() + +struct XSTREntry +{ + be ID; + be Length; +}; + +#pragma pack(1) +struct XACHHeader +{ + be Signature; + be Version; + be Size; + be 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 AchievementID; + be NameID; + be UnlockedDescID; + be LockedDescID; + be ImageID; + be Gamerscore; + char pad0[0x02]; + be Flags; + char pad1[0x10]; +}; + +union XDBFTitleID +{ + struct + { + be u16; + char u8[0x02]; + }; + + be u32; +}; + +struct XDBFTitleVersion +{ + be Major; + be Minor; + be Build; + be 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 Signature; + be Version; + be Size; + XDBFTitleID TitleID; + be Type; + XDBFTitleVersion TitleVersion; + char pad0[0x10]; +}; + +#pragma pack(1) +struct XGAAHeader +{ + be Signature; + be Version; + be Size; + be Count; +}; +#pragma pack() + +struct XGAAEntry +{ + char pad0[0x04]; + be AvatarAwardID; + char pad1[0x06]; + XDBFTitleID TitleID; + be NameID; + be UnlockedDescID; + be LockedDescID; + char pad2[0x02]; + be ImageID; + char pad3[0x08]; +}; + +struct XSRCHeader +{ + be Signature; + be Version; + be Size; + be FileNameLength; +}; + +struct XSRCHeader2 +{ + be UncompressedSize; + be CompressedSize; +}; diff --git a/PowerUtils/xdbf_wrapper.cpp b/PowerUtils/xdbf_wrapper.cpp new file mode 100644 index 0000000..9f6b2cd --- /dev/null +++ b/PowerUtils/xdbf_wrapper.cpp @@ -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 XDBFWrapper::GetAchievements(EXDBFLanguage language) const +{ + std::vector 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; +} diff --git a/PowerUtils/xdbf_wrapper.h b/PowerUtils/xdbf_wrapper.h new file mode 100644 index 0000000..c39aa0a --- /dev/null +++ b/PowerUtils/xdbf_wrapper.h @@ -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 GetAchievements(EXDBFLanguage language) const; + Achievement GetAchievement(EXDBFLanguage language, uint16_t id) const; +}; + +extern XDBFWrapper g_xdbf; diff --git a/PowerUtils/xex.h b/PowerUtils/xex.h index eb0d34e..d00417f 100644 --- a/PowerUtils/xex.h +++ b/PowerUtils/xex.h @@ -54,6 +54,14 @@ typedef struct _XEX_FILE_FORMAT_INFO be CompressionType; } XEX_FILE_FORMAT_INFO; +typedef struct _XEX_RESOURCE_INFO +{ + be SizeOfHeader; + uint8_t ResourceID[8]; + be Offset; + be SizeOfData; +} XEX_RESOURCE_INFO; + typedef struct _XEX_BASIC_FILE_COMPRESSION_INFO { be SizeOfData;