fix: mario world localization crash

This commit is contained in:
Fireblade
2026-07-08 15:40:09 -04:00
parent 1f6c4886c5
commit adaff9e992
8 changed files with 168 additions and 71 deletions
+168 -71
View File
@@ -71,6 +71,11 @@ static bool hasPckFolderFallback(const wstring &path, wstring &folderPath)
return true;
}
static bool isValidDLCRange(const PBYTE pbData, DWORD dwLength, unsigned int offset, size_t size)
{
return offset <= dwLength && size <= static_cast<size_t>(dwLength) - offset;
}
static DLCManager::EDLCType getFolderFileType(const wstring &path)
{
wstring lowerPath = toLower(path);
@@ -568,8 +573,14 @@ bool DLCManager::readDLCDataFolder(DWORD &dwFilesProcessed, const wstring &path,
bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD dwLength, DLCPack *pack)
{
if(pbData == nullptr || pack == nullptr || dwLength < sizeof(unsigned int) * 2)
{
return false;
}
const PBYTE pbEnd = pbData + dwLength;
unordered_map<int, EDLCParameterType> parameterMapping;
unsigned int uiCurrentByte=0;
unsigned int uiCurrentByte = 0;
// File format defined in the DLC_Creator
// File format: Version 2
@@ -582,78 +593,146 @@ 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=readUInt32(pbData, false);
uiCurrentByte+=sizeof(int);
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, sizeof(unsigned int)))
{
return false;
}
unsigned int uiVersion = readUInt32(pbData, false);
uiCurrentByte += sizeof(unsigned int);
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);
if(uiVersion <= CURRENT_DLC_VERSION_NUM)
{
bSwapEndian = false;
}
else if(uiVersionSwapped <= CURRENT_DLC_VERSION_NUM)
{
bSwapEndian = true;
}
else
{
app.DebugPrintf("Unknown DLC version of %u\n", uiVersion);
return false;
}
pack->SetDataPointer(pbData);
unsigned int uiParameterCount=readUInt32(&pbData[uiCurrentByte], bSwapEndian);
uiCurrentByte+=sizeof(int);
C4JStorage::DLC_FILE_PARAM *pParams = (C4JStorage::DLC_FILE_PARAM *)&pbData[uiCurrentByte];
bool bXMLVersion = false;
//DWORD dwwchCount=0;
for(unsigned int i=0;i<uiParameterCount;i++)
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, sizeof(unsigned int)))
{
pParams->dwType = bSwapEndian ? SwapInt32(pParams->dwType) : pParams->dwType;
pParams->dwWchCount = bSwapEndian ? SwapInt32(pParams->dwWchCount) : pParams->dwWchCount;
char16_t* wchData = reinterpret_cast<char16_t*>(pParams->wchData);
if (bSwapEndian) {
SwapUTF16Bytes(wchData, pParams->dwWchCount);
return false;
}
unsigned int uiParameterCount = readUInt32(&pbData[uiCurrentByte], bSwapEndian);
uiCurrentByte += sizeof(unsigned int);
bool bXMLVersion = false;
for(unsigned int i = 0; i < uiParameterCount; ++i)
{
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, sizeof(C4JStorage::DLC_FILE_PARAM)))
{
return false;
}
// Map DLC strings to application strings, then store the DLC index mapping to application index
wstring parameterName(static_cast<WCHAR *>(pParams->wchData));
C4JStorage::DLC_FILE_PARAM *pParams = reinterpret_cast<C4JStorage::DLC_FILE_PARAM *>(&pbData[uiCurrentByte]);
unsigned int dwWchCount = bSwapEndian ? SwapInt32(pParams->dwWchCount) : pParams->dwWchCount;
size_t paramSize = sizeof(C4JStorage::DLC_FILE_PARAM) + (dwWchCount * sizeof(WCHAR));
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, paramSize))
{
return false;
}
pParams->dwType = bSwapEndian ? SwapInt32(pParams->dwType) : pParams->dwType;
pParams->dwWchCount = dwWchCount;
char16_t* wchData = reinterpret_cast<char16_t*>(pParams->wchData);
if (bSwapEndian)
{
SwapUTF16Bytes(wchData, dwWchCount);
}
wstring parameterName(reinterpret_cast<WCHAR *>(pParams->wchData), pParams->dwWchCount);
EDLCParameterType type = getParameterType(parameterName);
if( type != e_DLCParamType_Invalid )
if(type != e_DLCParamType_Invalid)
{
parameterMapping[pParams->dwType] = type;
if (type == e_DLCParamType_XMLVersion)
if(type == e_DLCParamType_XMLVersion)
{
bXMLVersion = true;
}
}
uiCurrentByte+= sizeof(C4JStorage::DLC_FILE_PARAM)+(pParams->dwWchCount*sizeof(WCHAR));
pParams = (C4JStorage::DLC_FILE_PARAM *)&pbData[uiCurrentByte];
uiCurrentByte += static_cast<unsigned int>(paramSize);
}
//ulCurrentByte+=ulParameterCount * sizeof(C4JStorage::DLC_FILE_PARAM);
if (bXMLVersion)
{
uiCurrentByte += sizeof(int);
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, sizeof(unsigned int)))
{
return false;
}
uiCurrentByte += sizeof(unsigned int);
}
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;i<uiFileCount;i++)
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, sizeof(unsigned int)))
{
pFile->dwWchCount = bSwapEndian ? SwapInt32(pFile->dwWchCount) : pFile->dwWchCount;
dwTemp+=sizeof(C4JStorage::DLC_FILE_DETAILS)+pFile->dwWchCount*sizeof(WCHAR);
pFile = (C4JStorage::DLC_FILE_DETAILS *)&pbData[dwTemp];
return false;
}
PBYTE pbTemp=((PBYTE )pFile);//+ sizeof(C4JStorage::DLC_FILE_DETAILS)*ulFileCount;
pFile = (C4JStorage::DLC_FILE_DETAILS *)&pbData[uiCurrentByte];
unsigned int uiFileCount = readUInt32(&pbData[uiCurrentByte], bSwapEndian);
uiCurrentByte += sizeof(unsigned int);
for(unsigned int i=0;i<uiFileCount;i++)
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, sizeof(C4JStorage::DLC_FILE_DETAILS)))
{
return false;
}
C4JStorage::DLC_FILE_DETAILS *pFile = reinterpret_cast<C4JStorage::DLC_FILE_DETAILS *>(&pbData[uiCurrentByte]);
DWORD dwTemp = uiCurrentByte;
for(unsigned int i = 0; i < uiFileCount; ++i)
{
if(!isValidDLCRange(pbData, dwLength, dwTemp, sizeof(C4JStorage::DLC_FILE_DETAILS)))
{
return false;
}
pFile = reinterpret_cast<C4JStorage::DLC_FILE_DETAILS *>(&pbData[dwTemp]);
unsigned int dwWchCount = bSwapEndian ? SwapInt32(pFile->dwWchCount) : pFile->dwWchCount;
size_t fileDetailsSize = sizeof(C4JStorage::DLC_FILE_DETAILS) + (dwWchCount * sizeof(WCHAR));
if(!isValidDLCRange(pbData, dwLength, dwTemp, fileDetailsSize))
{
return false;
}
dwTemp += static_cast<DWORD>(fileDetailsSize);
}
if(!isValidDLCRange(pbData, dwLength, dwTemp, 0))
{
return false;
}
PBYTE pbTemp = pbData + dwTemp;
pFile = reinterpret_cast<C4JStorage::DLC_FILE_DETAILS *>(&pbData[uiCurrentByte]);
for(unsigned int i = 0; i < uiFileCount; ++i)
{
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, sizeof(C4JStorage::DLC_FILE_DETAILS)))
{
return false;
}
pFile = reinterpret_cast<C4JStorage::DLC_FILE_DETAILS *>(&pbData[uiCurrentByte]);
unsigned int dwWchCount = bSwapEndian ? SwapInt32(pFile->dwWchCount) : pFile->dwWchCount;
unsigned int uiFileSize = bSwapEndian ? SwapInt32(pFile->uiFileSize) : pFile->uiFileSize;
size_t fileHeaderSize = sizeof(C4JStorage::DLC_FILE_DETAILS) + (dwWchCount * sizeof(WCHAR));
if(!isValidDLCRange(pbData, dwLength, uiCurrentByte, fileHeaderSize))
{
return false;
}
pFile->dwType = bSwapEndian ? SwapInt32(pFile->dwType) : pFile->dwType;
pFile->uiFileSize = bSwapEndian ? SwapInt32(pFile->uiFileSize) : pFile->uiFileSize;
pFile->uiFileSize = uiFileSize;
char16_t* wchFile = reinterpret_cast<char16_t*>(pFile->wchFile);
if (bSwapEndian) {
SwapUTF16Bytes(wchFile, pFile->dwWchCount);
if (bSwapEndian)
{
SwapUTF16Bytes(wchFile, dwWchCount);
}
EDLCType type = static_cast<EDLCType>(pFile->dwType);
@@ -670,43 +749,65 @@ bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD
dlcFile = pack->addFile(type,(WCHAR *)pFile->wchFile);
}
// Params
uiParameterCount=readUInt32(pbTemp, bSwapEndian);
pbTemp+=sizeof(int);
pParams = (C4JStorage::DLC_FILE_PARAM *)pbTemp;
for(unsigned int j=0;j<uiParameterCount;j++)
if(!isValidDLCRange(pbData, dwLength, static_cast<unsigned int>(pbTemp - pbData), sizeof(unsigned int)))
{
//DLCManager::EDLCParameterType paramType = DLCManager::e_DLCParamType_Invalid;
return false;
}
uiParameterCount = readUInt32(pbTemp, bSwapEndian);
pbTemp += sizeof(unsigned int);
C4JStorage::DLC_FILE_PARAM *pParams = reinterpret_cast<C4JStorage::DLC_FILE_PARAM *>(pbTemp);
for(unsigned int j = 0; j < uiParameterCount; ++j)
{
if(!isValidDLCRange(pbData, dwLength, static_cast<unsigned int>(pbTemp - pbData), sizeof(C4JStorage::DLC_FILE_PARAM)))
{
return false;
}
pParams = reinterpret_cast<C4JStorage::DLC_FILE_PARAM *>(pbTemp);
unsigned int dwParamWchCount = bSwapEndian ? SwapInt32(pParams->dwWchCount) : pParams->dwWchCount;
size_t paramSize = sizeof(C4JStorage::DLC_FILE_PARAM) + (dwParamWchCount * sizeof(WCHAR));
if(!isValidDLCRange(pbData, dwLength, static_cast<unsigned int>(pbTemp - pbData), paramSize))
{
return false;
}
pParams->dwType = bSwapEndian ? SwapInt32(pParams->dwType) : pParams->dwType;
pParams->dwWchCount = bSwapEndian ? SwapInt32(pParams->dwWchCount) : pParams->dwWchCount;
pParams->dwWchCount = dwParamWchCount;
char16_t* wchData = reinterpret_cast<char16_t*>(pParams->wchData);
if (bSwapEndian) {
SwapUTF16Bytes(wchData, pParams->dwWchCount);
if (bSwapEndian)
{
SwapUTF16Bytes(wchData, dwParamWchCount);
}
auto it = parameterMapping.find(pParams->dwType);
if(it != parameterMapping.end() )
if(it != parameterMapping.end())
{
if(type == e_DLCType_PackConfig)
{
pack->addParameter(it->second,(WCHAR *)pParams->wchData);
}
else
else if(dlcFile != nullptr)
{
if(dlcFile != nullptr) dlcFile->addParameter(it->second,(WCHAR *)pParams->wchData);
else if(dlcTexturePack != nullptr) dlcTexturePack->addParameter(it->second, (WCHAR *)pParams->wchData);
dlcFile->addParameter(it->second,(WCHAR *)pParams->wchData);
}
else if(dlcTexturePack != nullptr)
{
dlcTexturePack->addParameter(it->second, (WCHAR *)pParams->wchData);
}
}
pbTemp+=sizeof(C4JStorage::DLC_FILE_PARAM)+(sizeof(WCHAR)*pParams->dwWchCount);
pParams = (C4JStorage::DLC_FILE_PARAM *)pbTemp;
pbTemp += static_cast<unsigned int>(paramSize);
}
if(!isValidDLCRange(pbData, dwLength, static_cast<unsigned int>(pbTemp - pbData), uiFileSize))
{
return false;
}
//pbTemp+=ulParameterCount * sizeof(C4JStorage::DLC_FILE_PARAM);
if(dlcTexturePack != nullptr)
{
DWORD texturePackFilesProcessed = 0;
bool validPack = processDLCDataFile(texturePackFilesProcessed,pbTemp,pFile->uiFileSize,dlcTexturePack);
bool validPack = processDLCDataFile(texturePackFilesProcessed, pbTemp, uiFileSize, dlcTexturePack);
pack->SetDataPointer(nullptr); // If it's a child pack, it doesn't own the data
if(!validPack || texturePackFilesProcessed == 0)
{
@@ -726,8 +827,7 @@ bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD
}
else if(dlcFile != nullptr)
{
// Data
dlcFile->addData(pbTemp,pFile->uiFileSize);
dlcFile->addData(pbTemp, uiFileSize);
// TODO - 4J Stu Remove the need for this vSkinNames vector, or manage it differently
switch(pFile->dwType)
@@ -740,14 +840,11 @@ bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD
++dwFilesProcessed;
}
// Move the pointer to the start of the next files data;
pbTemp+=pFile->uiFileSize;
uiCurrentByte+=sizeof(C4JStorage::DLC_FILE_DETAILS)+pFile->dwWchCount*sizeof(WCHAR);
pFile=(C4JStorage::DLC_FILE_DETAILS *)&pbData[uiCurrentByte];
pbTemp += uiFileSize;
uiCurrentByte += static_cast<unsigned int>(fileHeaderSize);
}
if( pack->getDLCItemsCount(e_DLCType_GameRules) > 0
if(pack->getDLCItemsCount(e_DLCType_GameRules) > 0
|| pack->getDLCItemsCount(e_DLCType_GameRulesHeader) > 0)
{
app.m_gameRules.loadGameRules(pack);