From fcafa791b308114d5f9cc5d0a9a231ea0f8a32f5 Mon Sep 17 00:00:00 2001 From: James Benton Date: Sun, 7 May 2017 01:38:01 +0100 Subject: [PATCH] Add libgfd. --- src/libgfd/CMakeLists.txt | 7 + src/libgfd/include/libgfd.h | 204 +++++++++ src/libgfd/src/libgfd.c | 858 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1069 insertions(+) create mode 100644 src/libgfd/CMakeLists.txt create mode 100644 src/libgfd/include/libgfd.h create mode 100644 src/libgfd/src/libgfd.c diff --git a/src/libgfd/CMakeLists.txt b/src/libgfd/CMakeLists.txt new file mode 100644 index 0000000..3cfdd01 --- /dev/null +++ b/src/libgfd/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.2) +project(libgfd) + +add_library(gfd src/libgfd.c) +target_include_directories(gfd PRIVATE "../../include") +target_include_directories(gfd PUBLIC "include") +install(TARGETS gfd ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") diff --git a/src/libgfd/include/libgfd.h b/src/libgfd/include/libgfd.h new file mode 100644 index 0000000..b77c4b4 --- /dev/null +++ b/src/libgfd/include/libgfd.h @@ -0,0 +1,204 @@ +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GFDHeader GFDHeader; +typedef struct GFDBlockHeader GFDBlockHeader; +typedef struct GFDRelocationHeader GFDRelocationHeader; + +#define GFD_HEADER_MAGIC (0x47667832) +#define GFD_BLOCK_HEADER_MAGIC (0x424C4B7B) +#define GFD_RELOCATION_HEADER_MAGIC (0x7D424C4B) + +#define GFD_FILE_VERSION_MAJOR (7) +#define GFD_FILE_VERSION_MINOR (1) +#define GFD_BLOCK_VERSION_MAJOR (1) + +#define GFD_PATCH_MASK (0xFFF00000) +#define GFD_PATCH_DATA (0xD0600000) +#define GFD_PATCH_TEXT (0xCA700000) + +typedef enum GFDBlockType +{ + GFD_BLOCK_END_OF_FILE = 1, + GFD_BLOCK_PADDING = 2, + GFD_BLOCK_VERTEX_SHADER_HEADER = 3, + GFD_BLOCK_VERTEX_SHADER_PROGRAM = 5, + GFD_BLOCK_PIXEL_SHADER_HEADER = 6, + GFD_BLOCK_PIXEL_SHADER_PROGRAM = 7, + GFD_BLOCK_GEOMETRY_SHADER_HEADER = 8, + GFD_BLOCK_GEOMETRY_SHADER_PROGRAM = 9, + GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM = 10, + GFD_BLOCK_TEXTURE_HEADER = 11, + GFD_BLOCK_TEXTURE_IMAGE = 12, + GFD_BLOCK_TEXTURE_MIPMAP = 13, + GFD_BLOCK_COMPUTE_SHADER_HEADER = 14, + GFD_BLOCK_COMPUTE_SHADER_PROGRAM = 15, +} GFDBlockType; + +struct GFDHeader +{ + uint32_t magic; + uint32_t headerSize; + uint32_t majorVersion; + uint32_t minorVersion; + uint32_t gpuVersion; + uint32_t align; + uint32_t unk1; + uint32_t unk2; +}; +CHECK_OFFSET(GFDHeader, 0x00, magic); +CHECK_OFFSET(GFDHeader, 0x04, headerSize); +CHECK_OFFSET(GFDHeader, 0x08, majorVersion); +CHECK_OFFSET(GFDHeader, 0x0C, minorVersion); +CHECK_OFFSET(GFDHeader, 0x10, gpuVersion); +CHECK_OFFSET(GFDHeader, 0x14, align); +CHECK_OFFSET(GFDHeader, 0x18, unk1); +CHECK_OFFSET(GFDHeader, 0x1C, unk2); +CHECK_SIZE(GFDHeader, 0x20); + +struct GFDBlockHeader +{ + uint32_t magic; + uint32_t headerSize; + uint32_t majorVersion; + uint32_t minorVersion; + GFDBlockType type; + uint32_t dataSize; + uint32_t id; + uint32_t index; +}; +CHECK_OFFSET(GFDBlockHeader, 0x00, magic); +CHECK_OFFSET(GFDBlockHeader, 0x04, headerSize); +CHECK_OFFSET(GFDBlockHeader, 0x08, majorVersion); +CHECK_OFFSET(GFDBlockHeader, 0x0C, minorVersion); +CHECK_OFFSET(GFDBlockHeader, 0x10, type); +CHECK_OFFSET(GFDBlockHeader, 0x14, dataSize); +CHECK_OFFSET(GFDBlockHeader, 0x18, id); +CHECK_OFFSET(GFDBlockHeader, 0x1C, index); +CHECK_SIZE(GFDHeader, 0x20); + +struct GFDRelocationHeader +{ + uint32_t magic; + uint32_t headerSize; + uint32_t unk1; + uint32_t dataSize; + uint32_t dataOffset; + uint32_t textSize; + uint32_t textOffset; + uint32_t patchBase; + uint32_t patchCount; + uint32_t patchOffset; +}; +CHECK_OFFSET(GFDRelocationHeader, 0x00, magic); +CHECK_OFFSET(GFDRelocationHeader, 0x04, headerSize); +CHECK_OFFSET(GFDRelocationHeader, 0x08, unk1); +CHECK_OFFSET(GFDRelocationHeader, 0x0C, dataSize); +CHECK_OFFSET(GFDRelocationHeader, 0x10, dataOffset); +CHECK_OFFSET(GFDRelocationHeader, 0x14, textSize); +CHECK_OFFSET(GFDRelocationHeader, 0x18, textOffset); +CHECK_OFFSET(GFDRelocationHeader, 0x1C, patchBase); +CHECK_OFFSET(GFDRelocationHeader, 0x20, patchCount); +CHECK_OFFSET(GFDRelocationHeader, 0x24, patchOffset); +CHECK_SIZE(GFDRelocationHeader, 0x28); + +uint32_t +GFDGetGeometryShaderCount(const void *file); + +uint32_t +GFDGetGeometryShaderHeaderSize(uint32_t index, + const void *file); + +uint32_t +GFDGetGeometryShaderProgramSize(uint32_t index, + const void *file); + +uint32_t +GFDGetGeometryShaderCopyProgramSize(uint32_t index, + const void *file); + +BOOL +GFDGetGeometryShader(GX2GeometryShader *shader, + void *program, + void *copyProgram, + uint32_t index, + const void *file); + +uint32_t +GFDGetPixelShaderCount(const void *file); + +uint32_t +GFDGetPixelShaderHeaderSize(uint32_t index, + const void *file); + +uint32_t +GFDGetPixelShaderProgramSize(uint32_t index, + const void *file); + +BOOL +GFDGetPixelShader(GX2PixelShader *shader, + void *program, + uint32_t index, + const void *file); + +uint32_t +GFDGetVertexShaderCount(const void *file); + +uint32_t +GFDGetVertexShaderHeaderSize(uint32_t index, + const void *file); + +uint32_t +GFDGetVertexShaderProgramSize(uint32_t index, + const void *file); + +BOOL +GFDGetVertexShader(GX2VertexShader *shader, + void *program, + uint32_t index, + const void *file); + +uint32_t +GFDGetTextureCount(const void *file); + +uint32_t +GFDGetTextureHeaderSize(uint32_t index, + const void *file); + +uint32_t +GFDGetTextureImageSize(uint32_t index, + const void *file); + +uint32_t +GFDGetTextureMipImageSize(uint32_t index, + const void *file); + +uint32_t +GFDGetTextureAlignmentSize(uint32_t index, + const void *file); + +BOOL +GFDGetTexture(GX2Texture *texture, + void *image, + void *mipmap, + uint32_t index, + const void *file); + +BOOL +GFDGetGX2RTexture(GX2Texture *texture, + uint32_t index, + const void *file); + +const GX2Texture * +GFDGetTexturePointer(uint32_t index, + const void *file); + +#ifdef __cplusplus +} +#endif diff --git a/src/libgfd/src/libgfd.c b/src/libgfd/src/libgfd.c new file mode 100644 index 0000000..90567fb --- /dev/null +++ b/src/libgfd/src/libgfd.c @@ -0,0 +1,858 @@ +#include "libgfd.h" + +#include +#include +#include + +static uint32_t _GFDCleanTag(uint32_t tag); +static BOOL _GFDCheckTagDAT(uint32_t tag); +static BOOL _GFDCheckTagSTR(uint32_t tag); +static BOOL _GFDRelocateBlock(const GFDBlockHeader *blockHeader, void *dst); +static BOOL _GFDRelocateBlockEx(const GFDRelocationHeader *relocationHeader, const uint32_t *patchTable, uint8_t *dst); +static uint32_t _GFDGetBlockDataSize(GFDBlockType type, uint32_t index, const void *file); +static uint32_t _GFDGetBlockCount(GFDBlockType type, const void *file); +static BOOL _GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader *header); +static BOOL _GFDCheckHeaderVersions(const void *file); +static BOOL _GFDGetHeaderVersions(uint32_t *majorVersion, uint32_t *minorVersion, uint32_t *gpuVersion, const void *file); +static BOOL _GFDGetBlockPointer(GFDBlockType type, uint32_t index, void *file, GFDBlockHeader **blockHeaderOut, void **blockDataOut); +static BOOL _GFDGetBlockPointerConst(GFDBlockType type, uint32_t index, const void *file, const GFDBlockHeader **blockHeaderOut, const void **blockDataOut); + +static BOOL +_GFDGetHeaderVersions(uint32_t *majorVersion, + uint32_t *minorVersion, + uint32_t *gpuVersion, + const void *file) +{ + GFDHeader *header = (GFDHeader *)file; + *majorVersion = 0; + *minorVersion = 0; + *gpuVersion = 0; + + if (header->magic != GFD_HEADER_MAGIC) { + return FALSE; + } + + *majorVersion = header->majorVersion; + *minorVersion = header->minorVersion; + *gpuVersion = header->gpuVersion; + return TRUE; +} + +static BOOL +_GFDCheckHeaderVersions(const void *file) +{ + uint32_t majorVersion, minorVersion, gpuVersion; + + if (!_GFDGetHeaderVersions(&majorVersion, &minorVersion, &gpuVersion, file)) { + return FALSE; + } + + if (majorVersion != GFD_FILE_VERSION_MAJOR) { + return FALSE; + } + + if (minorVersion != GFD_FILE_VERSION_MINOR) { + return FALSE; + } + + if (gpuVersion != GX2TempGetGPUVersion()) { + return FALSE; + } + + return TRUE; +} + +static BOOL +_GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader *header) +{ + if (header->magic != GFD_BLOCK_HEADER_MAGIC) { + return FALSE; + } + + if (header->majorVersion != GFD_BLOCK_VERSION_MAJOR) { + return FALSE; + } + + return TRUE; +} + +static uint32_t +_GFDGetBlockCount(GFDBlockType type, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t count = 0; + + if (!file) { + return 0; + } + + if (!_GFDCheckHeaderVersions(file)) { + return 0; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + if (blockHeader->type == type) { + count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->headerSize + blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return count; +} + +static uint32_t +_GFDGetBlockDataSize(GFDBlockType type, + uint32_t index, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t count = 0; + + if (!file) { + return 0; + } + + if (!_GFDCheckHeaderVersions(file)) { + return 0; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + if (blockHeader->type == type) { + if (count == index) { + return blockHeader->dataSize; + } + + count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->headerSize + blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return 0; +} + +static BOOL +_GFDGetBlockPointerConst(GFDBlockType type, + uint32_t index, + const void *file, + const GFDBlockHeader **blockHeaderOut, + const void **blockDataOut) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t count = 0; + + if (!file) { + return FALSE; + } + + if (!_GFDCheckHeaderVersions(file)) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + if (blockHeader->type == type) { + if (count == index) { + *blockHeaderOut = blockHeader; + *blockDataOut = ptr + blockHeader->headerSize; + return TRUE; + } + + count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->headerSize + blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return FALSE; +} + +static BOOL +_GFDGetBlockPointer(GFDBlockType type, + uint32_t index, + void *file, + GFDBlockHeader **blockHeaderOut, + void **blockDataOut) +{ + uint8_t *ptr = (uint8_t *)file; + GFDHeader *fileHeader = (GFDHeader *)file; + GFDBlockHeader *blockHeader; + uint32_t count = 0; + + if (!file) { + return FALSE; + } + + if (!_GFDCheckHeaderVersions(file)) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + if (blockHeader->type == type) { + if (count == index) { + *blockHeaderOut = blockHeader; + *blockDataOut = ptr + blockHeader->headerSize; + + if (type == GFD_BLOCK_VERTEX_SHADER_HEADER + || type == GFD_BLOCK_PIXEL_SHADER_HEADER + || type == GFD_BLOCK_GEOMETRY_SHADER_HEADER + || type == GFD_BLOCK_COMPUTE_SHADER_HEADER) { + _GFDRelocateBlock(blockHeader, blockHeader); + } + + return TRUE; + } + + count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->headerSize + blockHeader->dataSize; + blockHeader = (GFDBlockHeader *)ptr; + } + + return FALSE; +} + +static uint32_t +_GFDCleanTag(uint32_t tag) +{ + return tag & ~GFD_PATCH_MASK; +} + +static BOOL +_GFDCheckTagDAT(uint32_t tag) +{ + return (tag & GFD_PATCH_MASK) == GFD_PATCH_DATA; +} + +static BOOL +_GFDCheckTagSTR(uint32_t tag) +{ + return (tag & GFD_PATCH_MASK) == GFD_PATCH_TEXT; +} + +// This method differs from the official because they made poor design decisions. +static BOOL +_GFDRelocateBlockEx(const GFDRelocationHeader *relocationHeader, + const uint32_t *patchTable, + uint8_t *dst) +{ + uint32_t patchOffset = _GFDCleanTag(relocationHeader->patchOffset); + uint32_t i; + + for (i = 0; i < relocationHeader->patchCount; ++i) { + uint32_t *target; + uint32_t offset = patchTable[i]; + + if (offset == 0) { + continue; + } + + if (!_GFDCheckTagDAT(offset) && !_GFDCheckTagSTR(offset)) { + return FALSE; + } + + target = (uint32_t *)(dst + _GFDCleanTag(offset)); + + if (!_GFDCheckTagDAT(*target) && !_GFDCheckTagSTR(*target)) { + return FALSE; + } + + *target = (uintptr_t)(dst + _GFDCleanTag(*target)); + } + + return TRUE; +} + +static BOOL +_GFDRelocateBlock(const GFDBlockHeader *blockHeader, + void *dst) +{ + const uint8_t *blockData = ((const uint8_t *)blockHeader) + blockHeader->headerSize; + const GFDRelocationHeader *relocationHeader; + const uint32_t *patchTable; + + if (!blockHeader || !dst) { + return FALSE; + } + + + relocationHeader = (const GFDRelocationHeader *)(blockData + + blockHeader->dataSize + - sizeof(GFDRelocationHeader)); + + if (relocationHeader->magic != GFD_RELOCATION_HEADER_MAGIC) { + return FALSE; + } + + if (!_GFDCheckTagDAT(relocationHeader->patchOffset)) { + return FALSE; + } + + patchTable = (const uint32_t *)(blockData + relocationHeader->patchOffset); + + return _GFDRelocateBlockEx(relocationHeader, patchTable, (uint8_t *)dst); +} + +static BOOL +_GFDCheckShaderAlign(void *program) +{ + return (((uintptr_t)program) & (GX2_SHADER_PROGRAM_ALIGNMENT - 1)) == 0; +} + +static BOOL +_GFDGetGenericBlock(GFDBlockType blockTypeHeader, + void *header, + uint32_t headerSize, + GFDBlockType blockTypeProgram1, + void **outProgramPtr1, + void *program1, + GFDBlockType blockTypeProgram2, + void **outProgramPtr2, + void *program2, + uint32_t index, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t headerCount = 0; + uint32_t program1Count = 0; + uint32_t program2Count = 0; + BOOL result = FALSE; + + if (!header || !file) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + ptr += blockHeader->headerSize; + + if (blockHeader->type == blockTypeHeader) { + if (headerCount == index) { + if (blockHeader->dataSize < headerSize) { + return FALSE; + } + + memcpy(header, ptr, headerSize); + + // Process relocations for all headers except a texture header. + if (blockTypeHeader != GFD_BLOCK_TEXTURE_HEADER) { + if (!_GFDRelocateBlock(blockHeader, header)) { + return FALSE; + } + } + } + + headerCount++; + } else if (blockHeader->type == blockTypeProgram1) { + if (program1Count == index) { + *outProgramPtr1 = program1; + memcpy(program1, ptr, blockHeader->dataSize); + } + + program1Count++; + } else if (program2 && blockHeader->type == blockTypeProgram2) { + if (program2Count == index) { + *outProgramPtr2 = program2; + memcpy(program2, ptr, blockHeader->dataSize); + } + + program2Count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + if (headerCount > index && program1Count > index) { + if (!program2 || program2Count > index) { + result = TRUE; + break; + } + } + + ptr += blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return result; +} +/* +BOOL +GFDGetVertexShader(GX2VertexShader *shader, + void *program, + uint32_t index, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t headerCount = 0; + uint32_t programCount = 0; + BOOL result = FALSE; + + if (!shader || !program || !file) { + return FALSE; + } + + if ((uintptr_t)program & (GX2_SHADER_PROGRAM_ALIGNMENT - 1)) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + ptr += blockHeader->headerSize; + + if (blockHeader->type == GFD_BLOCK_VERTEX_SHADER_HEADER) { + if (headerCount == index) { + if (blockHeader->dataSize < sizeof(GX2VertexShader)) { + return FALSE; + } + + memcpy(shader, ptr, sizeof(GX2VertexShader)); + + if (!_GFDRelocateBlock(blockHeader, shader)) { + return FALSE; + } + } + + headerCount++; + } else if (blockHeader->type == GFD_BLOCK_VERTEX_SHADER_PROGRAM) { + if (programCount == index) { + shader->program = program; + memcpy(program, ptr, blockHeader->dataSize); + } + + programCount++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + if (headerCount > index && programCount > index) { + result = TRUE; + break; + } + + ptr += blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return result; +} +*/ + +uint32_t +GFDGetComputeShaderCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_COMPUTE_SHADER_HEADER, + file); +} + +uint32_t +GFDGetComputeShaderHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_COMPUTE_SHADER_HEADER, + index, + file); +} + +uint32_t +GFDGetComputeShaderProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_COMPUTE_SHADER_PROGRAM, + index, + file); +} + +/* +BOOL +GFDGetComputeShader(GX2ComputeShader *shader, + void *program, + uint32_t index, + const void *file) +{ + return _GFDGetGenericBlock(GFD_BLOCK_COMPUTE_SHADER_HEADER, + shader, + sizeof(GX2ComputeShader), + GFD_BLOCK_COMPUTE_SHADER_PROGRAM, + &shader->program, + program, + 0, + NULL, + NULL, + index, + file); +} +*/ + +uint32_t +GFDGetGeometryShaderCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_GEOMETRY_SHADER_HEADER, + file); +} + +uint32_t +GFDGetGeometryShaderHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_HEADER, + index, + file); +} + +uint32_t +GFDGetGeometryShaderProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_PROGRAM, + index, + file); +} + +uint32_t +GFDGetGeometryShaderCopyProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM, + index, + file); +} + +BOOL +GFDGetGeometryShader(GX2GeometryShader *shader, + void *program, + void *copyProgram, + uint32_t index, + const void *file) +{ + if (!_GFDCheckShaderAlign(program) || !_GFDCheckShaderAlign(copyProgram)) { + return FALSE; + } + + return _GFDGetGenericBlock(GFD_BLOCK_GEOMETRY_SHADER_HEADER, + shader, + sizeof(GX2GeometryShader), + GFD_BLOCK_GEOMETRY_SHADER_PROGRAM, + &shader->program, + program, + GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM, + &shader->vertexProgram, + copyProgram, + index, + file); +} + +uint32_t +GFDGetPixelShaderCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_PIXEL_SHADER_HEADER, + file); +} + +uint32_t +GFDGetPixelShaderHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_PIXEL_SHADER_HEADER, + index, + file); +} + +uint32_t +GFDGetPixelShaderProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_PIXEL_SHADER_PROGRAM, + index, + file); +} + +BOOL +GFDGetPixelShader(GX2PixelShader *shader, + void *program, + uint32_t index, + const void *file) +{ + if (!_GFDCheckShaderAlign(program)) { + return FALSE; + } + + return _GFDGetGenericBlock(GFD_BLOCK_PIXEL_SHADER_HEADER, + shader, + sizeof(GX2PixelShader), + GFD_BLOCK_PIXEL_SHADER_PROGRAM, + &shader->program, + program, + 0, + NULL, + NULL, + index, + file); +} + +uint32_t +GFDGetVertexShaderCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_VERTEX_SHADER_HEADER, + file); +} + +uint32_t +GFDGetVertexShaderHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_VERTEX_SHADER_HEADER, + index, + file); +} + +uint32_t +GFDGetVertexShaderProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_VERTEX_SHADER_PROGRAM, + index, + file); +} + +BOOL +GFDGetVertexShader(GX2VertexShader *shader, + void *program, + uint32_t index, + const void *file) +{ + return _GFDGetGenericBlock(GFD_BLOCK_VERTEX_SHADER_HEADER, + shader, + sizeof(GX2VertexShader), + GFD_BLOCK_VERTEX_SHADER_PROGRAM, + &shader->program, + program, + 0, + NULL, + NULL, + index, + file); +} + +uint32_t +GFDGetTextureCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_TEXTURE_HEADER, + file); +} + +uint32_t +GFDGetTextureHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_HEADER, + index, + file); +} + +uint32_t +GFDGetTextureImageSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_IMAGE, + index, + file); +} + +uint32_t +GFDGetTextureMipImageSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_MIPMAP, + index, + file); +} + +uint32_t +GFDGetTextureAlignmentSize(uint32_t index, + const void *file) +{ + const GFDBlockHeader *blockHeader; + const GX2Texture *texture; + + if (!_GFDGetBlockPointerConst(GFD_BLOCK_TEXTURE_HEADER, + index, + file, + &blockHeader, + (const void **)&texture)) { + return 0; + } + + return texture->surface.alignment; +} + +BOOL +GFDGetTexture(GX2Texture *texture, + void *image, + void *mipmap, + uint32_t index, + const void *file) +{ + return _GFDGetGenericBlock(GFD_BLOCK_TEXTURE_HEADER, + texture, + sizeof(GX2Texture), + GFD_BLOCK_TEXTURE_IMAGE, + &texture->surface.image, + image, + GFD_BLOCK_TEXTURE_MIPMAP, + &texture->surface.mipmaps, + mipmap, + index, + file); +} + +BOOL +GFDGetGX2RTexture(GX2Texture *texture, + uint32_t index, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t headerCount = 0; + BOOL created = FALSE; + + if (!texture || !file) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + ptr += blockHeader->headerSize; + + if (blockHeader->type == GFD_BLOCK_TEXTURE_HEADER) { + if (headerCount == index) { + if (blockHeader->dataSize < sizeof(GX2Texture)) { + goto error; + } + + memcpy(texture, ptr, sizeof(GX2Texture)); + + texture->surface.image = NULL; + texture->surface.mipmaps = NULL; + + GX2RCreateSurface(&texture->surface, + GX2R_RESOURCE_BIND_TEXTURE + | GX2R_RESOURCE_USAGE_CPU_WRITE + | GX2R_RESOURCE_USAGE_GPU_READ); + + created = TRUE; + } else if (created) { + break; + } + + headerCount++; + } else if (blockHeader->type == GFD_BLOCK_TEXTURE_IMAGE) { + if (created) { + void *image = GX2RLockSurfaceEx(&texture->surface, 0, 0); + if (!image) { + goto error; + } + + memcpy(image, ptr, blockHeader->dataSize); + GX2RUnlockSurfaceEx(&texture->surface, 0, + GX2R_RESOURCE_DISABLE_CPU_INVALIDATE + | GX2R_RESOURCE_DISABLE_GPU_INVALIDATE); + } + } else if (blockHeader->type == GFD_BLOCK_TEXTURE_MIPMAP) { + if (created) { + void *mipmap = GX2RLockSurfaceEx(&texture->surface, -1, 0); + if (!mipmap) { + goto error; + } + + memcpy(mipmap, ptr, blockHeader->dataSize); + GX2RUnlockSurfaceEx(&texture->surface, -1, + GX2R_RESOURCE_DISABLE_CPU_INVALIDATE + | GX2R_RESOURCE_DISABLE_GPU_INVALIDATE); + } + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + if (created && (texture->surface.image || texture->surface.mipmaps)) { + if (texture->surface.image) { + GX2RInvalidateSurface(&texture->surface, 0, 0); + } + + if (texture->surface.mipmaps) { + GX2RInvalidateSurface(&texture->surface, -1, 0); + } + + return TRUE; + } + +error: + GX2RDestroySurface(&texture->surface); + return FALSE; +} + +const GX2Texture * +GFDGetTexturePointer(uint32_t index, + const void *file) +{ + const GFDBlockHeader *blockHeader; + const GX2Texture *texture; + + if (!_GFDGetBlockPointerConst(GFD_BLOCK_TEXTURE_HEADER, + index, + file, + &blockHeader, + (const void **)&texture)) { + return NULL; + } + + if (blockHeader->dataSize < sizeof(GX2Texture)) { + return NULL; + } + + return texture; +}