diff options
| author | unknown <C:\Ladik\Mail> | 2015-08-03 17:41:31 +0200 | 
|---|---|---|
| committer | unknown <C:\Ladik\Mail> | 2015-08-03 17:41:31 +0200 | 
| commit | 922d3a82b897f3cbe45b45d4e072361c681a8959 (patch) | |
| tree | 196d2fc5034c68bbd8d4d5b660b40a127dc6ef25 /src | |
| parent | 607e4458e775e17de450f550e7d412ef41013138 (diff) | |
+ Fixed patch archives
+ Empty MPQs are no longer marked as malformed
Diffstat (limited to 'src')
| -rw-r--r-- | src/SBaseFileTable.cpp | 11 | ||||
| -rw-r--r-- | src/SFilePatchArchives.cpp | 138 | ||||
| -rw-r--r-- | src/StormLib.h | 1 | 
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  | 
