From 99101b4c52c61f04b98d6f5b5312dc74d5cea221 Mon Sep 17 00:00:00 2001 From: Sestain Date: Mon, 16 Mar 2026 10:20:48 +0200 Subject: [PATCH] Added support for Big-Endian DLCs --- Minecraft.Client/Common/DLC/DLCManager.cpp | 85 +++++++++++++++++++--- Minecraft.Client/Common/DLC/DLCManager.h | 25 +++++++ 2 files changed, 101 insertions(+), 9 deletions(-) diff --git a/Minecraft.Client/Common/DLC/DLCManager.cpp b/Minecraft.Client/Common/DLC/DLCManager.cpp index 931b0e1d9..8eb672908 100644 --- a/Minecraft.Client/Common/DLC/DLCManager.cpp +++ b/Minecraft.Client/Common/DLC/DLCManager.cpp @@ -387,22 +387,35 @@ bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD // // unsigned long, p = number of parameters // // p * DLC_FILE_PARAM describing each parameter for this file // // ulFileSize bytes of data blob of the file added - unsigned int uiVersion=*(unsigned int *)pbData; + unsigned int uiVersion=readUInt32(pbData, false); uiCurrentByte+=sizeof(int); - if(uiVersion < CURRENT_DLC_VERSION_NUM) - { - if(pbData!=nullptr) delete [] pbData; - app.DebugPrintf("DLC version of %d is too old to be read\n", uiVersion); + bool bSwapEndian = false; + unsigned int uiVersionSwapped = SwapInt32(uiVersion); + if (uiVersion >= 0 && uiVersion <= CURRENT_DLC_VERSION_NUM) { + bSwapEndian = false; + } else if (uiVersionSwapped >= 0 && uiVersionSwapped <= CURRENT_DLC_VERSION_NUM) { + bSwapEndian = true; + } else { + if(pbData!=nullptr) delete [] pbData; + app.DebugPrintf("Unknown DLC version of %d\n", uiVersion); return false; } pack->SetDataPointer(pbData); - unsigned int uiParameterCount=*(unsigned int *)&pbData[uiCurrentByte]; + unsigned int uiParameterCount=readUInt32(&pbData[uiCurrentByte], bSwapEndian); uiCurrentByte+=sizeof(int); C4JStorage::DLC_FILE_PARAM *pParams = (C4JStorage::DLC_FILE_PARAM *)&pbData[uiCurrentByte]; //DWORD dwwchCount=0; + bool hasXMLVersion = false; for(unsigned int i=0;idwType = bSwapEndian ? SwapInt32(pParams->dwType) : pParams->dwType; + pParams->dwWchCount = bSwapEndian ? SwapInt32(pParams->dwWchCount) : pParams->dwWchCount; + char16_t* wchData = reinterpret_cast(pParams->wchData); + if (bSwapEndian) { + SwapUTF16Bytes(wchData, pParams->dwWchCount); + } + // Map DLC strings to application strings, then store the DLC index mapping to application index wstring parameterName(static_cast(pParams->wchData)); EDLCParameterType type = getParameterType(parameterName); @@ -414,14 +427,14 @@ bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD pParams = (C4JStorage::DLC_FILE_PARAM *)&pbData[uiCurrentByte]; } //ulCurrentByte+=ulParameterCount * sizeof(C4JStorage::DLC_FILE_PARAM); - - unsigned int uiFileCount=*(unsigned int *)&pbData[uiCurrentByte]; + unsigned int uiFileCount=readUInt32(&pbData[uiCurrentByte], bSwapEndian); uiCurrentByte+=sizeof(int); C4JStorage::DLC_FILE_DETAILS *pFile = (C4JStorage::DLC_FILE_DETAILS *)&pbData[uiCurrentByte]; DWORD dwTemp=uiCurrentByte; for(unsigned int i=0;idwWchCount = bSwapEndian ? SwapInt32(pFile->dwWchCount) : pFile->dwWchCount; dwTemp+=sizeof(C4JStorage::DLC_FILE_DETAILS)+pFile->dwWchCount*sizeof(WCHAR); pFile = (C4JStorage::DLC_FILE_DETAILS *)&pbData[dwTemp]; } @@ -430,27 +443,45 @@ bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD for(unsigned int i=0;idwType = bSwapEndian ? SwapInt32(pFile->dwType) : pFile->dwType; + pFile->uiFileSize = bSwapEndian ? SwapInt32(pFile->uiFileSize) : pFile->uiFileSize; + char16_t* wchFile = reinterpret_cast(pFile->wchFile); + if (bSwapEndian) { + SwapUTF16Bytes(wchFile, pFile->dwWchCount); + } + EDLCType type = static_cast(pFile->dwType); DLCFile *dlcFile = nullptr; DLCPack *dlcTexturePack = nullptr; + DLCPack *dlcSkinPack = nullptr; if(type == e_DLCType_TexturePack) { dlcTexturePack = new DLCPack(pack->getName(), pack->getLicenseMask()); } + else if(type == e_DLCType_SkinData) + { + dlcSkinPack = new DLCPack(pack->getName(), pack->getLicenseMask()); + } else if(type != e_DLCType_PackConfig) { dlcFile = pack->addFile(type,(WCHAR *)pFile->wchFile); } // Params - uiParameterCount=*(unsigned int *)pbTemp; + uiParameterCount=readUInt32(pbTemp, bSwapEndian); pbTemp+=sizeof(int); pParams = (C4JStorage::DLC_FILE_PARAM *)pbTemp; for(unsigned int j=0;jdwType = bSwapEndian ? SwapInt32(pParams->dwType) : pParams->dwType; + pParams->dwWchCount = bSwapEndian ? SwapInt32(pParams->dwWchCount) : pParams->dwWchCount; + char16_t* wchData = reinterpret_cast(pParams->wchData); + if (bSwapEndian) { + SwapUTF16Bytes(wchData, pParams->dwWchCount); + } auto it = parameterMapping.find(pParams->dwType); @@ -492,6 +523,42 @@ bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD } ++dwFilesProcessed; } + else if(dlcSkinPack != nullptr) + { + DWORD skinFilesProcessed = 0; + bool validPack = processDLCDataFile(skinFilesProcessed, pbTemp, pFile->uiFileSize, dlcSkinPack); + if(!validPack || skinFilesProcessed == 0) + { + delete dlcSkinPack; + dlcSkinPack = nullptr; + } + else + { + for(DWORD i = 0; i < dlcSkinPack->getSkinCount(); ++i) + { + DLCSkinFile* skinFile = dlcSkinPack->getSkinFile(i); + if(skinFile) + { + DLCFile* newFile = pack->addFile(DLCManager::e_DLCType_Skin, skinFile->getPath()); + + for(int param = 0; param < DLCManager::e_DLCParamType_Max; ++param) + { + auto value = skinFile->getParameterAsString(static_cast(param)); + if(!value.empty()) + { + newFile->addParameter(static_cast(param), value); + } + } + + app.vSkinNames.push_back(skinFile->getPath()); + } + } + + pack->addChildPack(dlcSkinPack); + } + + ++dwFilesProcessed; + } else if(dlcFile != nullptr) { // Data diff --git a/Minecraft.Client/Common/DLC/DLCManager.h b/Minecraft.Client/Common/DLC/DLCManager.h index d4dd2508e..596fc66a4 100644 --- a/Minecraft.Client/Common/DLC/DLCManager.h +++ b/Minecraft.Client/Common/DLC/DLCManager.h @@ -20,6 +20,7 @@ public: e_DLCType_Audio, e_DLCType_ColourTable, e_DLCType_GameRulesHeader, + e_DLCType_SkinData, e_DLCType_Max, e_DLCType_All, @@ -94,6 +95,30 @@ public: bool readDLCDataFile(DWORD &dwFilesProcessed, const string &path, DLCPack *pack, bool fromArchive = false); DWORD retrievePackIDFromDLCDataFile(const string &path, DLCPack *pack); + static unsigned short SwapInt16(unsigned short value) { + return (value >> 8) | (value << 8); + } + + static unsigned int SwapInt32(unsigned int value) { + return ((value & 0xFF) << 24) | + ((value & 0xFF00) << 8) | + ((value & 0xFF0000) >> 8) | + ((value & 0xFF000000) >> 24); + } + + static void SwapUTF16Bytes(char16_t* buffer, size_t count) { + for (size_t i = 0; i < count; ++i) { + char16_t& c = buffer[i]; + c = (c >> 8) | (c << 8); + } + } + + static unsigned int readUInt32(unsigned char* ptr, bool endian) { + unsigned int val = *(unsigned int*)ptr; + if (endian) val = SwapInt32(val); + return val; + } + private: bool processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD dwLength, DLCPack *pack);