aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorunknown <C:\Ladik\Mail>2015-08-03 17:41:31 +0200
committerunknown <C:\Ladik\Mail>2015-08-03 17:41:31 +0200
commit922d3a82b897f3cbe45b45d4e072361c681a8959 (patch)
tree196d2fc5034c68bbd8d4d5b660b40a127dc6ef25 /src
parent607e4458e775e17de450f550e7d412ef41013138 (diff)
+ Fixed patch archives
+ Empty MPQs are no longer marked as malformed
Diffstat (limited to 'src')
-rw-r--r--src/SBaseFileTable.cpp11
-rw-r--r--src/SFilePatchArchives.cpp138
-rw-r--r--src/StormLib.h1
3 files changed, 71 insertions, 79 deletions
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index b293574..ed0748d 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -374,10 +374,13 @@ int ConvertMpqHeaderToFormat4(
//
Label_ArchiveVersion1:
- if(pHeader->dwHashTablePos <= pHeader->dwHeaderSize || (pHeader->dwHashTablePos & 0x80000000))
- ha->dwFlags |= MPQ_FLAG_MALFORMED;
- if(pHeader->dwBlockTablePos <= pHeader->dwHeaderSize || (pHeader->dwBlockTablePos & 0x80000000))
- ha->dwFlags |= MPQ_FLAG_MALFORMED;
+ if(pHeader->dwBlockTableSize > 1) // Prevent empty MPQs being marked as malformed
+ {
+ if(pHeader->dwHashTablePos <= pHeader->dwHeaderSize || (pHeader->dwHashTablePos & 0x80000000))
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
+ if(pHeader->dwBlockTablePos <= pHeader->dwHeaderSize || (pHeader->dwBlockTablePos & 0x80000000))
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
+ }
// Only low byte of sector size is really used
if(pHeader->wSectorSize & 0xFF00)
diff --git a/src/SFilePatchArchives.cpp b/src/SFilePatchArchives.cpp
index 7c6515e..d01aaf2 100644
--- a/src/SFilePatchArchives.cpp
+++ b/src/SFilePatchArchives.cpp
@@ -437,24 +437,37 @@ static bool CreatePatchPrefix(TMPQArchive * ha, const char * szFileName, size_t
static bool IsMatchingPatchFile(
TMPQArchive * ha,
const char * szFileName,
- LPBYTE pbFileMd5)
+ LPBYTE pbBaseFileMd5)
{
MPQ_PATCH_HEADER PatchHeader = {0};
HANDLE hFile = NULL;
DWORD dwTransferred = 0;
+ DWORD dwFlags = 0;
bool bResult = false;
// Open the file and load the patch header
if(SFileOpenFileEx((HANDLE)ha, szFileName, SFILE_OPEN_BASE_FILE, &hFile))
{
- // Load the patch header
- SFileReadFile(hFile, &PatchHeader, sizeof(MPQ_PATCH_HEADER), &dwTransferred, NULL);
- BSWAP_ARRAY32_UNSIGNED(pPatchHeader, sizeof(DWORD) * 6);
-
- // If the file contains an incremental patch,
- // compare the "MD5 before patching" with the base file MD5
- if(dwTransferred == sizeof(MPQ_PATCH_HEADER) && PatchHeader.dwSignature == PATCH_SIGNATURE_HEADER)
- bResult = (!memcmp(PatchHeader.md5_before_patch, pbFileMd5, MD5_DIGEST_SIZE));
+ // Retrieve the flags. We need to know whether the file is a patch or not
+ SFileGetFileInfo(hFile, SFileInfoFlags, &dwFlags, sizeof(DWORD), &dwTransferred);
+ if(dwFlags & MPQ_FILE_PATCH_FILE)
+ {
+ // Load the patch header
+ SFileReadFile(hFile, &PatchHeader, sizeof(MPQ_PATCH_HEADER), &dwTransferred, NULL);
+ BSWAP_ARRAY32_UNSIGNED(pPatchHeader, sizeof(DWORD) * 6);
+
+ // If the file contains an incremental patch,
+ // compare the "MD5 before patching" with the base file MD5
+ if(dwTransferred == sizeof(MPQ_PATCH_HEADER) && PatchHeader.dwSignature == PATCH_SIGNATURE_HEADER)
+ bResult = (!memcmp(PatchHeader.md5_before_patch, pbBaseFileMd5, MD5_DIGEST_SIZE));
+ }
+ else
+ {
+ // TODO: How to match it if it's not an incremental patch?
+ // Example: StarCraft II\Updates\enGB\s2-update-enGB-23258.MPQ:
+ // Mods\Core.SC2Mod\enGB.SC2Assets\StreamingBuckets.txt"
+ bResult = false;
+ }
// Close the file
SFileCloseFile(hFile);
@@ -499,33 +512,6 @@ static const char * FindArchiveLanguage(TMPQArchive * ha, PLOCALIZED_MPQ_INFO pM
return NULL;
}
-static TFileEntry * FindBaseLstFile(TMPQArchive * ha)
-{
- TFileEntry * pFileEntry;
- const char * szLanguage;
- char szFileName[0x40];
-
- // Prepare the file name tenplate
- memcpy(szFileName, "####-md5.lst", 13);
-
- // Try all languages
- for(szLanguage = LanguageList; szLanguage[0] != 0; szLanguage++)
- {
- // Copy the language name
- szFileName[0] = szLanguage[0];
- szFileName[1] = szLanguage[1];
- szFileName[2] = szLanguage[2];
- szFileName[3] = szLanguage[3];
-
- // Check whether this file exists
- pFileEntry = GetFileEntryLocale(ha, szFileName, 0);
- if(pFileEntry != NULL)
- return pFileEntry;
- }
-
- return NULL;
-}
-
static bool FindPatchPrefix_WoW_13164_13623(TMPQArchive * haBase, TMPQArchive * haPatch)
{
const char * szPatchPrefix;
@@ -565,12 +551,11 @@ static bool FindPatchPrefix_WoW_13164_13623(TMPQArchive * haBase, TMPQArchive *
// We need to match the file by its MD5
//
-
-static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch)
+// Note: pBaseEntry is the file entry of the base version of "StreamingBuckets.txt"
+static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch, TFileEntry * pBaseEntry)
{
TMPQNamePrefix * pPatchPrefix;
- TFileEntry * pBaseEntry;
- char * szLstFileName;
+ char * szPatchFileName;
char * szPlainName;
size_t cchWorkBuffer = 0x400;
bool bResult = false;
@@ -583,17 +568,9 @@ static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch)
TFileEntry * pFileEntry;
// Allocate working buffer for merging LST file
- szLstFileName = STORM_ALLOC(char, cchWorkBuffer);
- if(szLstFileName != NULL)
+ szPatchFileName = STORM_ALLOC(char, cchWorkBuffer);
+ if(szPatchFileName != NULL)
{
- // Find a *-md5.lst file in the base archive
- pBaseEntry = FindBaseLstFile(haBase);
- if(pBaseEntry == NULL)
- {
- STORM_FREE(szLstFileName);
- return false;
- }
-
// Parse the entire file table
for(pFileEntry = haPatch->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
{
@@ -601,21 +578,21 @@ static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch)
if(IsPatchMetadataFile(pFileEntry))
{
// Construct the name of the MD5 file
- strcpy(szLstFileName, pFileEntry->szFileName);
- szPlainName = (char *)GetPlainFileName(szLstFileName);
+ strcpy(szPatchFileName, pFileEntry->szFileName);
+ szPlainName = (char *)GetPlainFileName(szPatchFileName);
strcpy(szPlainName, pBaseEntry->szFileName);
// Check for matching MD5 file
- if(IsMatchingPatchFile(haPatch, szLstFileName, pBaseEntry->md5))
+ if(IsMatchingPatchFile(haPatch, szPatchFileName, pBaseEntry->md5))
{
- bResult = CreatePatchPrefix(haPatch, szLstFileName, (size_t)(szPlainName - szLstFileName));
+ bResult = CreatePatchPrefix(haPatch, szPatchFileName, (size_t)(szPlainName - szPatchFileName));
break;
}
}
}
// Delete the merge buffer
- STORM_FREE(szLstFileName);
+ STORM_FREE(szPatchFileName);
}
}
@@ -637,6 +614,8 @@ static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch)
static bool FindPatchPrefix(TMPQArchive * haBase, TMPQArchive * haPatch, const char * szPatchPathPrefix)
{
+ TFileEntry * pFileEntry;
+
// If the patch prefix was explicitly entered, we use that one
if(szPatchPathPrefix != NULL)
return CreatePatchPrefix(haPatch, szPatchPathPrefix, 0);
@@ -649,8 +628,9 @@ static bool FindPatchPrefix(TMPQArchive * haBase, TMPQArchive * haPatch, const c
// Updates for Starcraft II
// Match: LocalizedData\GameHotkeys.txt <==> Campaigns\Liberty.SC2Campaign\enGB.SC2Data\LocalizedData\GameHotkeys.txt
// All Starcraft II base archives seem to have the file "StreamingBuckets.txt" present
- if(GetFileEntryLocale(haBase, "StreamingBuckets.txt", 0))
- return FindPatchPrefix_SC2(haBase, haPatch);
+ pFileEntry = GetFileEntryLocale(haBase, "StreamingBuckets.txt", 0);
+ if(pFileEntry != NULL)
+ return FindPatchPrefix_SC2(haBase, haPatch, pFileEntry);
// Diablo III patch MPQs don't use patch prefix
// Hearthstone MPQs don't use patch prefix
@@ -896,29 +876,37 @@ bool WINAPI SFileOpenPatchArchive(
// Open the archive like it is normal archive
if(nError == ERROR_SUCCESS)
{
- if(!SFileOpenArchive(szPatchMpqName, 0, MPQ_OPEN_READ_ONLY | MPQ_OPEN_PATCH, &hPatchMpq))
- return false;
- haPatch = (TMPQArchive *)hPatchMpq;
-
- // We need to remember the proper patch prefix to match names of patched files
- FindPatchPrefix(ha, (TMPQArchive *)hPatchMpq, szPatchPathPrefix);
-
- // Now add the patch archive to the list of patches to the original MPQ
- while(ha != NULL)
+ if(SFileOpenArchive(szPatchMpqName, 0, MPQ_OPEN_READ_ONLY | MPQ_OPEN_PATCH, &hPatchMpq))
{
- if(ha->haPatch == NULL)
+ // Cast the archive handle to structure pointer
+ haPatch = (TMPQArchive *)hPatchMpq;
+
+ // We need to remember the proper patch prefix to match names of patched files
+ if(FindPatchPrefix(ha, (TMPQArchive *)hPatchMpq, szPatchPathPrefix))
{
- haPatch->haBase = ha;
- ha->haPatch = haPatch;
- return true;
+ // Now add the patch archive to the list of patches to the original MPQ
+ while(ha != NULL)
+ {
+ if(ha->haPatch == NULL)
+ {
+ haPatch->haBase = ha;
+ ha->haPatch = haPatch;
+ return true;
+ }
+
+ // Move to the next archive
+ ha = ha->haPatch;
+ }
}
- // Move to the next archive
- ha = ha->haPatch;
+ // Close the archive
+ SFileCloseArchive(hPatchMpq);
+ nError = ERROR_CANT_FIND_PATCH_PREFIX;
+ }
+ else
+ {
+ nError = GetLastError();
}
-
- // Should never happen
- nError = ERROR_CAN_NOT_COMPLETE;
}
SetLastError(nError);
diff --git a/src/StormLib.h b/src/StormLib.h
index b6cb0c9..fb32b8b 100644
--- a/src/StormLib.h
+++ b/src/StormLib.h
@@ -149,6 +149,7 @@ extern "C" {
#define ERROR_MARKED_FOR_DELETE 10005 // The file was marked as "deleted" in the MPQ
#define ERROR_FILE_INCOMPLETE 10006 // The required file part is missing
#define ERROR_UNKNOWN_FILE_NAMES 10007 // A name of at least one file is unknown
+#define ERROR_CANT_FIND_PATCH_PREFIX 10008 // StormLib was unable to find patch prefix for the patches
// Values for SFileCreateArchive
#define HASH_TABLE_SIZE_MIN 0x00000004 // Verified: If there is 1 file, hash table size is 4