mirror of
				https://github.com/hedge-dev/XenonRecomp.git
				synced 2025-11-04 06:47:09 +00:00 
			
		
		
		
	Added handling of normal compression for patching xex files (#126)
* Added handling of normal compression for patching xex files * Added normal compression handling to XenonAnalyse * Swap calloc for unique_ptr, tidied up code layout
This commit is contained in:
		@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <aes.hpp>
 | 
					#include <aes.hpp>
 | 
				
			||||||
 | 
					#include <TinySHA1.hpp>
 | 
				
			||||||
 | 
					#include <xex_patcher.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STRINGIFY(X) #X
 | 
					#define STRINGIFY(X) #X
 | 
				
			||||||
#define XE_EXPORT(MODULE, ORDINAL, NAME, TYPE) { (ORDINAL), "__imp__" STRINGIFY(NAME) }
 | 
					#define XE_EXPORT(MODULE, ORDINAL, NAME, TYPE) { (ORDINAL), "__imp__" STRINGIFY(NAME) }
 | 
				
			||||||
@@ -135,7 +137,7 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize)
 | 
				
			|||||||
    // Decompress image
 | 
					    // Decompress image
 | 
				
			||||||
    if (fileFormatInfo != nullptr)
 | 
					    if (fileFormatInfo != nullptr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        assert(fileFormatInfo->compressionType <= XEX_COMPRESSION_BASIC);
 | 
					        assert(fileFormatInfo->compressionType <= XEX_COMPRESSION_NORMAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::unique_ptr<uint8_t[]> decryptedData;
 | 
					        std::unique_ptr<uint8_t[]> decryptedData;
 | 
				
			||||||
        const uint8_t* srcData = nullptr;
 | 
					        const uint8_t* srcData = nullptr;
 | 
				
			||||||
@@ -192,6 +194,67 @@ Image Xex2LoadImage(const uint8_t* data, size_t dataSize)
 | 
				
			|||||||
                destData += blocks[i].zeroSize;
 | 
					                destData += blocks[i].zeroSize;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            result = std::make_unique<uint8_t[]>(imageSize);
 | 
				
			||||||
 | 
					            auto* destData = result.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const Xex2CompressedBlockInfo* blocks = &((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->firstBlock;
 | 
				
			||||||
 | 
					            const uint32_t headerSize = header->headerSize.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const uint32_t exeLength = dataSize - headerSize;
 | 
				
			||||||
 | 
					            const uint8_t* exeBuffer = srcData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto compressBuffer = std::make_unique<uint8_t[]>(exeLength);
 | 
				
			||||||
 | 
					            const uint8_t* p = NULL;
 | 
				
			||||||
 | 
					            uint8_t* d = NULL;
 | 
				
			||||||
 | 
					            sha1::SHA1 s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            p = exeBuffer;
 | 
				
			||||||
 | 
					            d = compressBuffer.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint8_t blockCalcedDigest[0x14];
 | 
				
			||||||
 | 
					            while (blocks->blockSize) 
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                const uint8_t* pNext = p + blocks->blockSize;
 | 
				
			||||||
 | 
					                const auto* nextBlock = (const Xex2CompressedBlockInfo*)p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                s.reset();
 | 
				
			||||||
 | 
					                s.processBytes(p, blocks->blockSize);
 | 
				
			||||||
 | 
					                s.finalize(blockCalcedDigest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (memcmp(blockCalcedDigest, blocks->blockHash, 0x14) != 0)
 | 
				
			||||||
 | 
					                    return {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                p += 4;
 | 
				
			||||||
 | 
					                p += 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                while (true) 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    const size_t chunkSize = (p[0] << 8) | p[1];
 | 
				
			||||||
 | 
					                    p += 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (!chunkSize)
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    memcpy(d, p, chunkSize);
 | 
				
			||||||
 | 
					                    p += chunkSize;
 | 
				
			||||||
 | 
					                    d += chunkSize;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                p = pNext;
 | 
				
			||||||
 | 
					                blocks = nextBlock;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            int resultCode = 0;
 | 
				
			||||||
 | 
					            uint32_t uncompressedSize = security->imageSize;
 | 
				
			||||||
 | 
					            uint8_t* buffer = destData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            resultCode = lzxDecompress(compressBuffer.get(), d - compressBuffer.get(), buffer, uncompressedSize, ((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->windowSize, nullptr, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (resultCode)
 | 
				
			||||||
 | 
					                return {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    image.data = std::move(result);
 | 
					    image.data = std::move(result);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -403,7 +403,63 @@ XexPatcher::Result XexPatcher::apply(const uint8_t* xexBytes, size_t xexBytesSiz
 | 
				
			|||||||
            memmove(outDataCursor, srcDataCursor, blocks[i].dataSize);
 | 
					            memmove(outDataCursor, srcDataCursor, blocks[i].dataSize);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL || fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA)
 | 
					    else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const Xex2CompressedBlockInfo* blocks = &((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->firstBlock;
 | 
				
			||||||
 | 
					        const uint32_t exeLength = xexBytesSize - xexHeader->headerSize.get();
 | 
				
			||||||
 | 
					        const uint8_t* exeBuffer = &outBytes[headerTargetSize];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto compressBuffer = std::make_unique<uint8_t[]>(exeLength);
 | 
				
			||||||
 | 
					        const uint8_t* p = NULL;
 | 
				
			||||||
 | 
					        uint8_t* d = NULL;
 | 
				
			||||||
 | 
					        sha1::SHA1 s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        p = exeBuffer;
 | 
				
			||||||
 | 
					        d = compressBuffer.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t blockCalcedDigest[0x14];
 | 
				
			||||||
 | 
					        while (blocks->blockSize) 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            const uint8_t* pNext = p + blocks->blockSize;
 | 
				
			||||||
 | 
					            const auto* nextBlock = (const Xex2CompressedBlockInfo*)p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            s.reset();
 | 
				
			||||||
 | 
					            s.processBytes(p, blocks->blockSize);
 | 
				
			||||||
 | 
					            s.finalize(blockCalcedDigest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (memcmp(blockCalcedDigest, blocks->blockHash, 0x14) != 0)
 | 
				
			||||||
 | 
					                return Result::PatchFailed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            p += 4;
 | 
				
			||||||
 | 
					            p += 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while (true) 
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                const size_t chunkSize = (p[0] << 8) | p[1];
 | 
				
			||||||
 | 
					                p += 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!chunkSize)
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                memcpy(d, p, chunkSize);
 | 
				
			||||||
 | 
					                p += chunkSize;
 | 
				
			||||||
 | 
					                d += chunkSize;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            p = pNext;
 | 
				
			||||||
 | 
					            blocks = nextBlock;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int resultCode = 0;
 | 
				
			||||||
 | 
					        uint32_t uncompressedSize = originalSecurityInfo->imageSize;
 | 
				
			||||||
 | 
					        uint8_t* buffer = outBytes.data() + newXexHeaderSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        resultCode = lzxDecompress(compressBuffer.get(), d - compressBuffer.get(), buffer, uncompressedSize, ((const Xex2FileNormalCompressionInfo*)(fileFormatInfo + 1))->windowSize, nullptr, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (resultCode)
 | 
				
			||||||
 | 
					            return Result::PatchFailed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return Result::XexFileUnsupported;
 | 
					        return Result::XexFileUnsupported;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,8 @@
 | 
				
			|||||||
#include <span>
 | 
					#include <span>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int lzxDecompress(const void* lzxData, size_t lzxLength, void* dst, size_t dstLength, uint32_t windowSize, void* windowData, size_t windowDataLength);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct XexPatcher
 | 
					struct XexPatcher
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    enum class Result {
 | 
					    enum class Result {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user