diff options
| author | Ladislav Zezula <ladislav.zezula@avast.com> | 2021-12-17 14:51:35 +0100 | 
|---|---|---|
| committer | Ladislav Zezula <ladislav.zezula@avast.com> | 2021-12-17 14:51:35 +0100 | 
| commit | 1a94f94b50f6d829b1e8fba08a3002a5db4f00d5 (patch) | |
| tree | 86e05dc27d67a68f5b5168df451d867db0902693 | |
| parent | 5ab093b7a57b8779dff06a08fac19d46c40b3329 (diff) | |
Support for protected SCX files
| -rw-r--r-- | StormLib_vs19.vcxproj | 2 | ||||
| -rw-r--r-- | StormLib_vs19_dll.vcxproj | 8 | ||||
| -rw-r--r-- | StormLib_vs19_test.vcxproj | 8 | ||||
| -rw-r--r-- | make-msvc.bat | 16 | ||||
| -rw-r--r-- | src/SBaseCommon.cpp | 5 | ||||
| -rw-r--r-- | src/SBaseFileTable.cpp | 12 | ||||
| -rw-r--r-- | src/SFileAddFile.cpp | 2 | ||||
| -rw-r--r-- | src/SFileCreateArchive.cpp | 29 | ||||
| -rw-r--r-- | src/SFileFindFile.cpp | 4 | ||||
| -rw-r--r-- | src/SFileOpenArchive.cpp | 32 | ||||
| -rw-r--r-- | src/SFileReadFile.cpp | 10 | ||||
| -rw-r--r-- | src/StormCommon.h | 1 | ||||
| -rw-r--r-- | src/StormLib.h | 11 | ||||
| -rw-r--r-- | test/StormTest.cpp | 292 | ||||
| -rw-r--r-- | test/TLogHelper.cpp | 2 | 
15 files changed, 233 insertions, 201 deletions
diff --git a/StormLib_vs19.vcxproj b/StormLib_vs19.vcxproj index ffcf960..e0c83f9 100644 --- a/StormLib_vs19.vcxproj +++ b/StormLib_vs19.vcxproj @@ -73,7 +73,7 @@      <XPDeprecationWarning>false</XPDeprecationWarning>      <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>      <ConfigurationType>StaticLibrary</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <UseOfMfc>false</UseOfMfc>    </PropertyGroup>    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> diff --git a/StormLib_vs19_dll.vcxproj b/StormLib_vs19_dll.vcxproj index 712b427..1dbbce8 100644 --- a/StormLib_vs19_dll.vcxproj +++ b/StormLib_vs19_dll.vcxproj @@ -28,24 +28,24 @@    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">      <ConfigurationType>DynamicLibrary</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <CharacterSet>Unicode</CharacterSet>      <WholeProgramOptimization>true</WholeProgramOptimization>    </PropertyGroup>    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">      <ConfigurationType>DynamicLibrary</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <CharacterSet>Unicode</CharacterSet>    </PropertyGroup>    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">      <ConfigurationType>DynamicLibrary</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <CharacterSet>Unicode</CharacterSet>      <WholeProgramOptimization>true</WholeProgramOptimization>    </PropertyGroup>    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">      <ConfigurationType>DynamicLibrary</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <CharacterSet>Unicode</CharacterSet>    </PropertyGroup>    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> diff --git a/StormLib_vs19_test.vcxproj b/StormLib_vs19_test.vcxproj index 3bd8248..9f91ade 100644 --- a/StormLib_vs19_test.vcxproj +++ b/StormLib_vs19_test.vcxproj @@ -28,24 +28,24 @@    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">      <ConfigurationType>Application</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <CharacterSet>Unicode</CharacterSet>      <WholeProgramOptimization>true</WholeProgramOptimization>    </PropertyGroup>    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">      <ConfigurationType>Application</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <CharacterSet>Unicode</CharacterSet>    </PropertyGroup>    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">      <ConfigurationType>Application</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <CharacterSet>Unicode</CharacterSet>      <WholeProgramOptimization>true</WholeProgramOptimization>    </PropertyGroup>    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">      <ConfigurationType>Application</ConfigurationType> -    <PlatformToolset>v141</PlatformToolset> +    <PlatformToolset>v141_xp</PlatformToolset>      <CharacterSet>Unicode</CharacterSet>    </PropertyGroup>    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> diff --git a/make-msvc.bat b/make-msvc.bat index 9a2ea8e..8b9a559 100644 --- a/make-msvc.bat +++ b/make-msvc.bat @@ -42,14 +42,14 @@ goto:eof  call %1 %2  if "%2" == "x86" set SLN_TRG=Win32  if "%2" == "x64" set SLN_TRG=x64 -devenv.com %3 /project "%LIB_NAME%" /rebuild "DebugAD|%SLN_TRG%" -devenv.com %3 /project "%LIB_NAME%" /rebuild "DebugAS|%SLN_TRG%" -devenv.com %3 /project "%LIB_NAME%" /rebuild "DebugUD|%SLN_TRG%" -devenv.com %3 /project "%LIB_NAME%" /rebuild "DebugUS|%SLN_TRG%" -devenv.com %3 /project "%LIB_NAME%" /rebuild "ReleaseAD|%SLN_TRG%" -devenv.com %3 /project "%LIB_NAME%" /rebuild "ReleaseAS|%SLN_TRG%" -devenv.com %3 /project "%LIB_NAME%" /rebuild "ReleaseUD|%SLN_TRG%" -devenv.com %3 /project "%LIB_NAME%" /rebuild "ReleaseUS|%SLN_TRG%" +devenv.com %3 /project "%LIB_NAME%" /build "DebugAD|%SLN_TRG%" +devenv.com %3 /project "%LIB_NAME%" /build "DebugAS|%SLN_TRG%" +devenv.com %3 /project "%LIB_NAME%" /build "DebugUD|%SLN_TRG%" +devenv.com %3 /project "%LIB_NAME%" /build "DebugUS|%SLN_TRG%" +devenv.com %3 /project "%LIB_NAME%" /build "ReleaseAD|%SLN_TRG%" +devenv.com %3 /project "%LIB_NAME%" /build "ReleaseAS|%SLN_TRG%" +devenv.com %3 /project "%LIB_NAME%" /build "ReleaseUD|%SLN_TRG%" +devenv.com %3 /project "%LIB_NAME%" /build "ReleaseUS|%SLN_TRG%"  :: Restore environment variables to the old level  set INCLUDE=%SAVE_INCLUDE% diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index a1aa78e..98d541a 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -1334,11 +1334,12 @@ DWORD AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile)              // They are mostly empty on WoW release MPQs, but on MPQs from PTR,
              // they contain random non-zero data. Their meaning is unknown.
              //
 -            // These extra values are, however, include in the dwCmpSize in the file
 +            // These extra values are, however, included in the dwCmpSize in the file
              // table. We cannot ignore them, because compacting archive would fail
              //
 -            if(hf->SectorOffsets[0] > dwSectorOffsLen)
 +            // Clear the lower 2 bits in order to make sure that the value is aligned to 4 bytes
 +            if((hf->SectorOffsets[0] & 0xFFFFFFFC) > dwSectorOffsLen)
              {
                  // MPQ protectors put some ridiculous values there. We must limit the extra bytes
                  if(hf->SectorOffsets[0] > (dwSectorOffsLen + 0x400))
 diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index 7d52f7c..97fa3a2 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -893,15 +893,11 @@ static DWORD BuildFileTableFromBlockTable(      TMPQHash * pHash;
      LPDWORD DefragmentTable = NULL;
      DWORD dwItemCount = 0;
 -    DWORD dwFlagMask;
      // Sanity checks
      assert(ha->pFileTable != NULL);
      assert(ha->dwFileTableSize >= ha->dwMaxFileCount);
 -    // MPQs for Warcraft III doesn't know some flags, namely MPQ_FILE_SINGLE_UNIT and MPQ_FILE_PATCH_FILE
 -    dwFlagMask = (ha->dwFlags & MPQ_FLAG_WAR3_MAP) ? MPQ_FILE_VALID_FLAGS_W3X : MPQ_FILE_VALID_FLAGS;
 -
      // Defragment the hash table, if needed
      if(ha->dwFlags & MPQ_FLAG_HASH_TABLE_CUT)
      {
 @@ -976,10 +972,12 @@ static DWORD BuildFileTableFromBlockTable(              if(pFileEntry->ByteOffset == 0 && pBlock->dwFSize == 0)
                  pFileEntry->ByteOffset = ha->pHeader->dwHeaderSize;
 +            // Clear file flags that are unknown to this type of map.
 +            pFileEntry->dwFlags = pBlock->dwFlags & ha->dwValidFileFlags;
 +
              // Fill the rest of the file entry
 -            pFileEntry->dwFileSize  = pBlock->dwFSize;
 -            pFileEntry->dwCmpSize   = pBlock->dwCSize;
 -            pFileEntry->dwFlags     = pBlock->dwFlags & dwFlagMask;
 +            pFileEntry->dwFileSize = pBlock->dwFSize;
 +            pFileEntry->dwCmpSize  = pBlock->dwCSize;
          }
      }
 diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp index 7b88c12..9c7331b 100644 --- a/src/SFileAddFile.cpp +++ b/src/SFileAddFile.cpp @@ -795,7 +795,7 @@ bool WINAPI SFileCreateFile(      if(dwErrCode == ERROR_SUCCESS)
      {
          // Mask all unsupported flags out
 -        dwFlags &= (ha->dwFlags & MPQ_FLAG_WAR3_MAP) ? MPQ_FILE_VALID_FLAGS_W3X : MPQ_FILE_VALID_FLAGS;
 +        dwFlags &= ha->dwValidFileFlags;
          // Check for valid flag combinations
          if((dwFlags & (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS)) == (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS))
 diff --git a/src/SFileCreateArchive.cpp b/src/SFileCreateArchive.cpp index 742b829..4266070 100644 --- a/src/SFileCreateArchive.cpp +++ b/src/SFileCreateArchive.cpp @@ -202,20 +202,21 @@ bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCrea      if(dwErrCode == ERROR_SUCCESS)      {          memset(ha, 0, sizeof(TMPQArchive)); -        ha->pfnHashString   = HashStringSlash; -        ha->pStream         = pStream; -        ha->dwSectorSize    = pCreateInfo->dwSectorSize; -        ha->UserDataPos     = MpqPos; -        ha->MpqPos          = MpqPos; -        ha->pHeader         = pHeader = (TMPQHeader *)ha->HeaderData; -        ha->dwMaxFileCount  = dwHashTableSize; -        ha->dwFileTableSize = 0; -        ha->dwReservedFiles = dwReservedFiles; -        ha->dwFileFlags1    = pCreateInfo->dwFileFlags1; -        ha->dwFileFlags2    = pCreateInfo->dwFileFlags2; -        ha->dwFileFlags3    = pCreateInfo->dwFileFlags3 ? MPQ_FILE_EXISTS : 0; -        ha->dwAttrFlags     = pCreateInfo->dwAttrFlags; -        ha->dwFlags         = dwMpqFlags | MPQ_FLAG_CHANGED; +        ha->pfnHashString    = HashStringSlash; +        ha->pStream          = pStream; +        ha->dwSectorSize     = pCreateInfo->dwSectorSize; +        ha->UserDataPos      = MpqPos; +        ha->MpqPos           = MpqPos; +        ha->pHeader          = pHeader = (TMPQHeader *)ha->HeaderData; +        ha->dwMaxFileCount   = dwHashTableSize; +        ha->dwFileTableSize  = 0; +        ha->dwReservedFiles  = dwReservedFiles; +        ha->dwValidFileFlags = (pCreateInfo->dwMpqVersion > 1) ? MPQ_FILE_VALID_FLAGS : MPQ_FILE_VALID_FLAGS_W3X; +        ha->dwFileFlags1     = pCreateInfo->dwFileFlags1; +        ha->dwFileFlags2     = pCreateInfo->dwFileFlags2; +        ha->dwFileFlags3     = pCreateInfo->dwFileFlags3 ? MPQ_FILE_EXISTS : 0; +        ha->dwAttrFlags      = pCreateInfo->dwAttrFlags; +        ha->dwFlags          = dwMpqFlags | MPQ_FLAG_CHANGED;          pStream = NULL;          // Fill the MPQ header diff --git a/src/SFileFindFile.cpp b/src/SFileFindFile.cpp index ef8b834..223e194 100644 --- a/src/SFileFindFile.cpp +++ b/src/SFileFindFile.cpp @@ -221,7 +221,7 @@ static bool DoMPQSearch_FileEntry(      if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS)
      {
          // Ignore fake files which are not compressed but have size higher than the archive
 -        if ((pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) == 0 && (pFileEntry->dwFileSize > ha->FileSize))
 +        if((pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) == 0 && (pFileEntry->dwFileSize > ha->FileSize))
              return false;
          // Now we have to check if this file was not enumerated before
 @@ -236,8 +236,6 @@ static bool DoMPQSearch_FileEntry(              // Prepare the block index
              dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
 -            if(dwBlockIndex == 569)
 -                szNameBuff[0] = 'F';
              // Get the file name. If it's not known, we will create pseudo-name
              szFileName = pFileEntry->szFileName;
 diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index ea29850..dcc7e18 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -18,6 +18,7 @@  #include "StormCommon.h"  #define HEADER_SEARCH_BUFFER_SIZE   0x1000 +#define MINIMUM_MPQ_SIZE            0x0C  //-----------------------------------------------------------------------------  // Local functions @@ -35,21 +36,28 @@ static MTYPE CheckMapType(LPCTSTR szFileName, LPBYTE pbHeaderBuffer, size_t cbHe          DWORD DwordValue2 = BSWAP_INT32_UNSIGNED(HeaderInt32[2]);          DWORD DwordValue3 = BSWAP_INT32_UNSIGNED(HeaderInt32[3]); -        // Test for AVI files (Warcraft III cinematics) - 'RIFF', 'AVI ' or 'LIST' -        if(DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C) -            return MapTypeAviFile; - -        // Check for Starcraft II maps +        // Check maps by extension (Starcraft, Starcraft II). We must do this before +        // checking actual data, because the "NP_Protect" protector places +        // fake Warcraft III header into the Starcraft II maps          if((szExtension = _tcsrchr(szFileName, _T('.'))) != NULL)          { -            // The "NP_Protect" protector places fake Warcraft III header -            // into the Starcraft II maps, whilst SC2 maps have no other header but MPQ v4 +            // Check for Starcraft II maps by extension              if(!_tcsicmp(szExtension, _T(".s2ma")) || !_tcsicmp(szExtension, _T(".SC2Map")) || !_tcsicmp(szExtension, _T(".SC2Mod")))              {                  return MapTypeStarcraft2;              } + +            // Check for Starcraft I maps by extension +            if(!_tcsicmp(szExtension, _T(".scm")) || !_tcsicmp(szExtension, _T(".scx"))) +            { +                return MapTypeStarcraft; +            }          } +        // Test for AVI files (Warcraft III cinematics) - 'RIFF', 'AVI ' or 'LIST' +        if(DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C) +            return MapTypeAviFile; +          // Check for Warcraft III maps          if(DwordValue0 == 0x57334D48 && DwordValue1 == 0x00000000)              return MapTypeWarcraft3; @@ -271,6 +279,7 @@ bool WINAPI SFileOpenArchive(          bool bSearchComplete = false;          memset(ha, 0, sizeof(TMPQArchive)); +        ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS;          ha->pfnHashString = HashStringSlash;          ha->pStream = pStream;          pStream = NULL; @@ -288,6 +297,8 @@ bool WINAPI SFileOpenArchive(          // Limit the header searching to about 130 MB of data          if(EndOfSearch > 0x08000000)              EndOfSearch = 0x08000000; +        if(FileSize < HEADER_SEARCH_BUFFER_SIZE) +            memset(pbHeaderBuffer, 0, HEADER_SEARCH_BUFFER_SIZE);          // Find the offset of MPQ header within the file          while(bSearchComplete == false && ByteOffset < EndOfSearch) @@ -438,7 +449,14 @@ bool WINAPI SFileOpenArchive(          // Remember whether whis is a map for Warcraft III          if(MapType == MapTypeWarcraft3) +        { +            ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS_W3X;              ha->dwFlags |= MPQ_FLAG_WAR3_MAP; +        } + +        // If this is starcraft map, set the flag mask +        if(MapType == MapTypeStarcraft) +            ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS_SCX;          // Set the size of file sector          ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize); diff --git a/src/SFileReadFile.cpp b/src/SFileReadFile.cpp index 34edc06..1703748 100644 --- a/src/SFileReadFile.cpp +++ b/src/SFileReadFile.cpp @@ -663,7 +663,8 @@ static DWORD ReadMpqFileLocalFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePo  bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped)  { -    TMPQFile * hf = (TMPQFile *)hFile; +    TFileEntry * pFileEntry; +    TMPQFile * hf;      DWORD dwBytesRead = 0;                      // Number of bytes read      DWORD dwErrCode = ERROR_SUCCESS; @@ -673,7 +674,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD      lpOverlapped = lpOverlapped;      // Check valid parameters -    if(!IsValidFileHandle(hFile)) +    if((hf = IsValidFileHandle(hFile)) == NULL)      {          SetLastError(ERROR_INVALID_HANDLE);          return false; @@ -697,6 +698,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD      }      // Clear the last used compression +    pFileEntry = hf->pFileEntry;      hf->dwCompression0 = 0;      // If the file is local file, read the data directly from the stream @@ -706,7 +708,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD      }      // If the file is a patch file, we have to read it special way -    else if(hf->hfPatch != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) +    else if(hf->hfPatch != NULL && (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)      {          dwErrCode = ReadMpqFilePatchFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);      } @@ -718,7 +720,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD      }      // If the file is single unit file, redirect it to read file -    else if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) +    else if(pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT)      {          dwErrCode = ReadMpqFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead);      } diff --git a/src/StormCommon.h b/src/StormCommon.h index e9187f9..f452112 100644 --- a/src/StormCommon.h +++ b/src/StormCommon.h @@ -81,6 +81,7 @@ typedef enum _MTYPE      MapTypeNotChecked,                  // The map type was not checked yet
      MapTypeNotRecognized,               // The file does not seems to be a map
      MapTypeAviFile,                     // The file is actually an AVI file (Warcraft III cinematics)
 +    MapTypeStarcraft,                   // The file is a Starcraft map
      MapTypeWarcraft3,                   // The file is a Warcraft III map
      MapTypeStarcraft2                   // The file is a Starcraft II map
  } MTYPE, *PMTYPE;
 diff --git a/src/StormLib.h b/src/StormLib.h index f7279e6..1335f0e 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -25,7 +25,7 @@  /*                      hash table                                           */  /* 08.12.03  4.11  DCH  Fixed bug in reading file sector larger than 0x1000  */  /*                      on certain files.                                    */ -/*                      Fixed bug in AddFile with MPQ_FILE_REPLACE_EXISTING  */ +/*                      Fixed bug in AddFile with MPQ_FILE_REPLACEEXISTING   */  /*                      (Thanx Daniel Chiamarello, dchiamarello@madvawes.com)*/  /* 21.12.03  4.50  Lad  Completed port for Mac                               */  /*                      Fixed bug in compacting (if fsize is mul of 0x1000)  */ @@ -193,7 +193,7 @@ extern "C" {  #define MPQ_FLAG_CHECK_SECTOR_CRC   0x00000020  // Checking sector CRC when reading files  #define MPQ_FLAG_SAVING_TABLES      0x00000040  // If set, we are saving MPQ internal files and MPQ tables  #define MPQ_FLAG_PATCH              0x00000080  // If set, this MPQ is a patch archive -#define MPQ_FLAG_WAR3_MAP           0x00000100  // If set, this MPQ is a map for Warcraft III +#define MPQ_FLAG_WAR3_MAP           0x00000100  // If set, this MPQ is a Warcraft III map  #define MPQ_FLAG_LISTFILE_NONE      0x00000200  // Set when no (listfile) was found in InvalidateInternalFiles  #define MPQ_FLAG_LISTFILE_NEW       0x00000400  // Set when (listfile) invalidated by InvalidateInternalFiles  #define MPQ_FLAG_LISTFILE_FORCE     0x00000800  // Save updated listfile on exit @@ -250,6 +250,12 @@ extern "C" {                                    MPQ_FILE_SIGNATURE     |  \                                    MPQ_FILE_EXISTS) +#define MPQ_FILE_VALID_FLAGS_SCX (MPQ_FILE_IMPLODE       |  \ +                                  MPQ_FILE_COMPRESS      |  \ +                                  MPQ_FILE_ENCRYPTED     |  \ +                                  MPQ_FILE_FIX_KEY       |  \ +                                  MPQ_FILE_EXISTS) +  // We need to mask out the upper 4 bits of the block table index.  // This is because it gets shifted out when calculating block table offset  // BlockTableOffset = pHash->dwBlockIndex << 0x04 @@ -839,6 +845,7 @@ typedef struct _TMPQArchive      DWORD          dwFileFlags2;                // Flags for (attributes)      DWORD          dwFileFlags3;                // Flags for (signature)      DWORD          dwAttrFlags;                 // Flags for the (attributes) file, see MPQ_ATTRIBUTE_XXX +    DWORD          dwValidFileFlags;            // Valid flags for the current MPQ      DWORD          dwFlags;                     // See MPQ_FLAG_XXXXX      DWORD          dwSubType;                   // See MPQ_SUBTYPE_XXX diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 3ba9b1e..123ec43 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -35,8 +35,9 @@  //------------------------------------------------------------------------------
  // Local structures
 -#define TEST_FLAG_PROTECTED  0x01000000
 -#define TEST_FLAG_FILE_COUNT 0x00FFFFFF
 +#define TFLG_COUNT_HASH     0x01000000      // There is file count in the lower 24-bits, then hash
 +#define TFLG_COUNT_MASK     0x00FFFFFF      // Mask for file count
 +#define TEST_DATA(hash, num)   (num | TFLG_COUNT_HASH), hash
  typedef struct _TEST_INFO
  {
 @@ -80,6 +81,8 @@ static const TCHAR szListFileDir[] = { '1', '9', '9', '5', ' ', '-', ' ', 'T', '  // Global for the work MPQ
  static LPCTSTR szMpqSubDir   = _T("1995 - Test MPQs");
  static LPCTSTR szMpqPatchDir = _T("1995 - Test MPQs\\patches");
 +static LPCSTR  IntToHexChar = "0123456789abcdef";
 +
  typedef DWORD (*FIND_FILE_CALLBACK)(LPCTSTR szFullPath);
 @@ -353,23 +356,27 @@ static bool IsMpqExtension(LPCTSTR szFileName)      return false;
  }
 -static void BinaryFromString(LPCSTR szBinary, LPBYTE pbBuffer, DWORD cbBuffer)
 +// Converts binary array to string.
 +// The caller must ensure that the buffer has at least ((cbBinary * 2) + 1) characters
 +template <typename xchar>
 +xchar * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, xchar * szBuffer)
  {
 -    LPBYTE pbBufferEnd = pbBuffer + cbBuffer;
 -    char * szTemp;
 -    char szHexaDigit[4];
 +    xchar * szSaveBuffer = szBuffer;
 -    while(szBinary[0] != 0 && pbBuffer < pbBufferEnd)
 +    // Verify the binary pointer
 +    if(pbBinary && cbBinary)
      {
 -        // Get the 2-byte chunk
 -        szHexaDigit[0] = szBinary[0];
 -        szHexaDigit[1] = szBinary[1];
 -        szHexaDigit[2] = 0;
 -
 -        // Convert to integer
 -        *pbBuffer++ = (BYTE)strtoul(szHexaDigit, &szTemp, 16);
 -        szBinary += 2;
 +        // Convert the bytes to string array
 +        for(size_t i = 0; i < cbBinary; i++)
 +        {
 +            *szBuffer++ = IntToHexChar[pbBinary[i] >> 0x04];
 +            *szBuffer++ = IntToHexChar[pbBinary[i] & 0x0F];
 +        }
      }
 +
 +    // Terminate the string
 +    *szBuffer = 0;
 +    return szSaveBuffer;
  }
  static void AddStringBeforeExtension(char * szBuffer, LPCSTR szFileName, LPCSTR szExtraString)
 @@ -2452,12 +2459,12 @@ static DWORD TestArchive(      LPCTSTR szPlainName,                // Plain name of the MPQ
      LPCTSTR szListFile,                 // Listfile name (NULL if none)
      DWORD  dwFlags,                     // Flags
 -    LPCSTR szFileName1,
 -    LPCSTR szFileName2)
 +    LPCSTR szParam1,
 +    LPCSTR szParam2)
  {
 -    TFileData * pFileData1 = NULL;
 -    TFileData * pFileData2 = NULL;
 +    TFileData * FileDataList[2] = {NULL};
      TLogHelper Logger("TestMpq", szPlainName);
 +    LPCSTR FileNameList[2] = {NULL};
      LPCSTR szExpectedMD5 = NULL;
      HANDLE hMpq = NULL;
      DWORD dwFileCount = 0;
 @@ -2467,8 +2474,7 @@ static DWORD TestArchive(      DWORD dwExpectedFileCount = 0;
      DWORD dwMpqFlags = 0;
      TCHAR szFullName[MAX_PATH];
 -    BYTE ExpectedMD5[MD5_DIGEST_SIZE];
 -    BYTE OverallMD5[MD5_DIGEST_SIZE];
 +    BYTE ObtainedMD5[MD5_DIGEST_SIZE] = {0};
      bool bIgnoreOpedwErrCodes = false;
      // If the file is a partial MPQ, don't load all files
 @@ -2476,14 +2482,18 @@ static DWORD TestArchive(          dwSearchFlags |= SEARCH_FLAG_LOAD_FILES;
      // If the MPQ is a protected MPQ, do different tests
 -    if(dwFlags & TEST_FLAG_PROTECTED)
 +    if(dwFlags & TFLG_COUNT_HASH)
      {
 -        dwExpectedFileCount = (dwFlags & TEST_FLAG_FILE_COUNT);
 -        if((szExpectedMD5 = szFileName1) != NULL)
 +        if((szExpectedMD5 = szParam1) != NULL)
              dwSearchFlags |= SEARCH_FLAG_HASH_FILES;
 -        szFileName2 = szFileName1 = NULL;
 +        dwExpectedFileCount = (dwFlags & TFLG_COUNT_MASK);
 +        szParam1 = NULL;
      }
 +    // Put all file names into list
 +    FileNameList[0] = szParam1;
 +    FileNameList[1] = szParam2;
 +
      // Copy the archive so we won't fuck up the original one
      dwErrCode = OpenExistingArchiveWithCopy(&Logger, szPlainName, NULL, &hMpq);
      while(dwErrCode == ERROR_SUCCESS)
 @@ -2510,49 +2520,43 @@ static DWORD TestArchive(          if(dwErrCode != ERROR_SUCCESS)
              break;
 -        // If szFileName1 was given, load it and check its CRC
 -        if(szFileName1 && szFileName1[0])
 +        // For every file name given, load it and check its CRC
 +        for(size_t i = 0; i < _countof(FileNameList); i++)
          {
 -            // Test setting position
 -            dwErrCode = TestArchive_SetPos(hMpq, szFileName1);
 -            if(dwErrCode != ERROR_SUCCESS)
 -                break;
 +            TFileData * pFileData;
 +            LPCSTR szFileName = FileNameList[i];
 -            // Load the entire file 1
 -            pFileData1 = LoadMpqFile(&Logger, hMpq, szFileName1);
 -            if(pFileData1 == NULL)
 +            if(szFileName && szFileName[0])
              {
 -                dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName1);
 -                break;
 -            }
 +                // Test setting position
 +                dwErrCode = TestArchive_SetPos(hMpq, szFileName);
 +                if(dwErrCode != ERROR_SUCCESS)
 +                    break;
 -            // Check the CRC of file1, if available
 -            if(pFileData1->dwCrc32)
 -            {
 -                // Compare the CRC32, if available
 -                dwCrc32 = crc32(0, (Bytef *)pFileData1->FileData, (uInt)pFileData1->dwFileSize);
 -                if(dwCrc32 != pFileData1->dwCrc32)
 -                    Logger.PrintError("Warning: CRC32 error on %s", szFileName1);
 -            }
 -        }
 +                // Load the entire file 1
 +                FileDataList[i] = pFileData = LoadMpqFile(&Logger, hMpq, szFileName);
 +                if(pFileData == NULL)
 +                {
 +                    dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName);
 +                    break;
 +                }
 -        // If szFileName2 was given, load it
 -        if(szFileName2 && szFileName2[0])
 -        {
 -            // Load the entire file 2
 -            pFileData2 = LoadMpqFile(&Logger, hMpq, szFileName2);
 -            if(pFileData2 == NULL)
 -            {
 -                dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName2);
 -                break;
 +                // Check the CRC of file1, if available
 +                if(pFileData->dwCrc32)
 +                {
 +                    // Compare the CRC32, if available
 +                    dwCrc32 = crc32(0, (Bytef *)pFileData->FileData, (uInt)pFileData->dwFileSize);
 +                    if(dwCrc32 != pFileData->dwCrc32)
 +                        Logger.PrintError("Warning: CRC32 error on %s", szFileName);
 +                }
              }
          }
          // If two files were given, compare them
 -        if(pFileData1 && pFileData2)
 +        if(FileDataList[0] && FileDataList[1])
          {
              // Compare both files
 -            if(!CompareTwoFiles(&Logger, pFileData1, pFileData2))
 +            if(!CompareTwoFiles(&Logger, FileDataList[0], FileDataList[1]))
              {
                  dwErrCode = Logger.PrintError("The file has different size/content of files");
                  break;
 @@ -2560,38 +2564,38 @@ static DWORD TestArchive(          }
          // Search the archive
 -        dwErrCode = SearchArchive(&Logger, hMpq, dwSearchFlags, &dwFileCount, OverallMD5);
 +        dwErrCode = SearchArchive(&Logger, hMpq, dwSearchFlags, &dwFileCount, ObtainedMD5);
          // Shall we check the file count and overall MD5?
 -        if(dwExpectedFileCount != 0)
 +        if(dwFlags & TFLG_COUNT_HASH)
          {
              if(dwFileCount != dwExpectedFileCount)
              {
 -                Logger.PrintMessage("File count mismatch(expected: %u, found:%u)", dwExpectedFileCount, dwFileCount);
 +                Logger.PrintMessage("File count mismatch(expected: %u, found: %u)", dwExpectedFileCount, dwFileCount);
                  dwErrCode = ERROR_CAN_NOT_COMPLETE;
 -                break;
              }
          }
          // Shall we check overall MD5?
          if(szExpectedMD5 && szExpectedMD5[0])
          {
 -            BinaryFromString(szExpectedMD5, ExpectedMD5, MD5_DIGEST_SIZE);
 -            if(memcmp(ExpectedMD5, OverallMD5, MD5_DIGEST_SIZE))
 +            char szObtainedMD5[0x40];
 +
 +            StringFromBinary(ObtainedMD5, MD5_DIGEST_SIZE, szObtainedMD5);
 +            if(_stricmp(szObtainedMD5, szExpectedMD5))
              {
 -                Logger.PrintMessage("Extracted files MD5 mismatch");
 +                Logger.PrintMessage("Extracted files MD5 mismatch (expected: %s, obtained: %s)", szExpectedMD5, szObtainedMD5);
                  dwErrCode = ERROR_CAN_NOT_COMPLETE;
 -                break;
              }
          }
          break;
      }
      // Common cleanup
 -    if(pFileData2 != NULL)
 -        STORM_FREE(pFileData2);
 -    if(pFileData1 != NULL)
 -        STORM_FREE(pFileData1);
 +    if(FileDataList[1] != NULL)
 +        STORM_FREE(FileDataList[1]);
 +    if(FileDataList[0] != NULL)
 +        STORM_FREE(FileDataList[0]);
      if(hMpq != NULL)
          SFileCloseArchive(hMpq);
      return dwErrCode;
 @@ -4198,6 +4202,9 @@ static DWORD TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFil  //-----------------------------------------------------------------------------
  // Tables
 +static LPCTSTR szBliz = _T("ListFile_Blizzard.txt");
 +static LPCTSTR szWotI = _T("ListFile_WarOfTheImmortals.txt");
 +
  static const TEST_INFO TestList_StreamOps[] =
  {
      {_T("MPQ_2013_v4_alternate-original.MPQ"),         NULL, 0},
 @@ -4223,54 +4230,54 @@ static const TEST_INFO TestList_MasterMirror[] =  static const TEST_INFO Test_Mpqs[] =
  {
 -
      // Correct or damaged archives
 -    {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"),    NULL, 0, "music\\dintro.wav", "File00000023.xxx"},
 -    {_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"), NULL, 0, "waitingroombkgd.dc6"},                   // Update MPQ from Diablo II (patch 2016)
 -    {_T("MPQ_2018_v1_icon_error.w3m"),         NULL, 0, "file00000002.blp"},
 -    {_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"),   _T("ListFile_Blizzard.txt")},                      // File whose archive's (signature) file has flags = 0x90000000
 -    {_T("MPQ_2012_v2_EmptyMpq.MPQ") },                                                            // Empty archive (found in WoW cache - it's just a header)
 -    {_T("MPQ_2013_v4_EmptyMpq.MPQ") },                                                            // Empty archive (created artificially - it's just a header)
 -    {_T("MPQ_2013_v4_patch-base-16357.MPQ") },                                                    // Empty archive (found in WoW cache - it's just a header)
 -    {_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ") },                                                // Empty archive (A buggy MPQ with invalid HET entry count)
 -    {_T("MPQ_2002_v1_BlockTableCut.MPQ") },                                                       // Truncated archive
 -    {_T("MPQ_2010_v2_HasUserData.s2ma") },                                                        // MPQ that actually has user data
 -    {_T("MPQ_2014_v1_AttributesOneEntryLess.w3x") },                                              // Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries
 -    {_T("MPQ_2020_v1_AHF04patch.mix") },                                                          // MIX file
 -    {_T("MPQ_2010_v3_expansion-locale-frFR.MPQ") },                                               // MPQ archive v 3.0
 -    {_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE") },                                           // Encrypted archive from Starcraft II installer
 -    {_T("MPx_2013_v1_LongwuOnline.mpk") },                                                        // MPK archive from Longwu online
 -    {_T("MPx_2013_v1_WarOfTheImmortals.sqp"), _T("ListFile_WarOfTheImmortals.txt") },             // SQP archive from War of the Immortals
 -    {_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part") },                                // Partial MPQ with compressed hash table
 -    {_T("blk4-file://streaming/model.MPQ.0")},                                                      // Archive that is merged with multiple files
 -    {_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x")},
 -    {_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x")},
 -    {_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x")},                                                  // Warcraft III map locked by the Spazzler protector
 -    {_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x")},                                                 // Warcraft III map locked by the Spazzler protector
 -    {_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x")},                                                 // Warcraft III map locked by the Spazzler protector
 -    {_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m")},                                                      // Warcraft III map locked by the BOBA protector
 -    {_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x")},
 -    {_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x")},
 -    {_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x")},                                                     // Warcraft III map locked by Spazy protector
 -    {_T("MPQ_2015_v1_MessListFile.mpq")},
 -    {_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x")},
 -    {_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x")},
 -    {_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x")},                                                     // Something like Somj 2.0
 -    {_T("MPQ_2016_v1_WME4_4.w3x")},                                                                 // Protector from China (2016-05-27)
 -    {_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x")},
 -    {_T("MPQ_2016_v1_ProtectedMap_1.4.w3x")},
 -    {_T("MPQ_2016_v1_KoreanFile.w3m")},
 -    {_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x")},                                                       // Load map protected by PG1.11.973
 -    {_T("MPQ_2017_v1_BigDummyFiles.w3x")},
 -    {_T("MPQ_2017_v1_TildeInFileName.mpq")},
 -    {_T("MPQ_2018_v1_EWIX_v8_7.w3x"), NULL, 0, "BlueCrystal.mdx"},
 -    {_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod")},                                                      // Archive that has two fake headers before the real one
 -    {_T("MPQ_2020_v4_NP_Protect_1.s2ma")},                                                          // SC2 map that is protected by the NP_Protect
 -    {_T("MPQ_2020_v4_NP_Protect_2.s2ma")},                                                          // SC2 map that is protected by the NP_Protect
 +    {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"),                  NULL, 0, "music\\dintro.wav", "File00000023.xxx"},
 +    {_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"),               NULL, TEST_DATA("255d87a62f3c9518f72cf723a1818946", 221), "waitingroombkgd.dc6"}, // Update MPQ from Diablo II (patch 2016)
 +    {_T("MPQ_2018_v1_icon_error.w3m"),                       NULL, TEST_DATA("fcefa25fb50c391e8714f2562d1e10ff", 19),  "file00000002.blp"},
 +    {_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"),               szBliz, TEST_DATA("5ef18ef9a26b5704d8d46a344d976c89", 2)},       // File whose archive's (signature) file has flags = 0x90000000
 +    {_T("MPQ_2012_v2_EmptyMpq.MPQ"),                         NULL, TEST_DATA("00000000000000000000000000000000", 0)},       // Empty archive (found in WoW cache - it's just a header)
 +    {_T("MPQ_2013_v4_EmptyMpq.MPQ"),                         NULL, TEST_DATA("00000000000000000000000000000000", 0)},       // Empty archive (created artificially - it's just a header)
 +    {_T("MPQ_2013_v4_patch-base-16357.MPQ"),                 NULL, TEST_DATA("d41d8cd98f00b204e9800998ecf8427e", 1)},       // Empty archive (found in WoW cache - it's just a header)
 +    {_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ"),             NULL, TEST_DATA("be4b49ecc3942d1957249f9da0021659", 6)},       // Empty archive (with invalid HET entry count)
 +    {_T("MPQ_2002_v1_BlockTableCut.MPQ"),                    NULL, TEST_DATA("a9499ab74d939303d8cda7c397c36275", 287)},     // Truncated archive
 +    {_T("MPQ_2010_v2_HasUserData.s2ma"),                     NULL, TEST_DATA("feff9e2c86db716b6ff5ffc906181200", 52)},      // MPQ that actually has user data
 +    {_T("MPQ_2014_v1_AttributesOneEntryLess.w3x"),           NULL, TEST_DATA("90451b7052eb0f1d6f4bf69b2daff7f5", 116)},     // Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries
 +    {_T("MPQ_2020_v1_AHF04patch.mix"),                       NULL, TEST_DATA("d3c6aac48bc12813ef5ce4ad113e58bf", 2891)},    // MIX file
 +    {_T("MPQ_2010_v3_expansion-locale-frFR.MPQ"),            NULL, TEST_DATA("0c8fc921466f07421a281a05fad08b01", 53)},      // MPQ archive v 3.0 (the only one I know)
 +    {_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE"),        NULL, TEST_DATA("10e4dcdbe95b7ad731c563ec6b71bc16", 82)},      // Encrypted archive from Starcraft II installer
 +    {_T("MPx_2013_v1_LongwuOnline.mpk"),                     NULL, TEST_DATA("548f7db88284097f7e94c95a08c5bc24", 469)},     // MPK archive from Longwu online
 +    {_T("MPx_2013_v1_WarOfTheImmortals.sqp"),              szWotI, TEST_DATA("a048f37f7c6162a96253d8081722b6d9", 9396)},    // SQP archive from War of the Immortals
 +    {_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part"),0, TEST_DATA("d41d8cd98f00b204e9800998ecf8427e", 14263)},   // Partial MPQ with compressed hash table
 +    {_T("blk4-file://streaming/model.MPQ.0"),                NULL, TEST_DATA("e06b00efb2fc7e7469dd8b3b859ae15d", 39914)},   // Archive that is merged with multiple files
      // Protected archives
 -    {_T("MPQ_2015_v1_flem1.w3x"), NULL, TEST_FLAG_PROTECTED | 20, "1c4c13e627658c473e84d94371e31f37"},
 -    {_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, TEST_FLAG_PROTECTED | 114, "5250975ed917375fc6540d7be436d4de"},
 +    {_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x"),     NULL, TEST_DATA("b900364cc134a51ddeca21a13697c3ca", 79)},
 +    {_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x"),    NULL, TEST_DATA("db67e894da9de618a1cdf86d02d315ff", 117)},
 +    {_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x"),            NULL, TEST_DATA("72d7963aa799a7fb4117c55b7beabaf9", 470)},     // Warcraft III map locked by the Spazzler protector
 +    {_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x"),           NULL, TEST_DATA("72d7963aa799a7fb4117c55b7beabaf9", 470)},     // Warcraft III map locked by the Spazzler protector
 +    {_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x"),           NULL, TEST_DATA("e55aad2dd33cf68b372ca8e30dcb78a7", 130)},     // Warcraft III map locked by the Spazzler protector
 +    {_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m"),                NULL, TEST_DATA("7b725d87e07a2173c42fe2314b95fa6c", 17)},      // Warcraft III map locked by the BOBA protector
 +    {_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x"),          NULL, TEST_DATA("c7ca4d2d0b1e58db5c784f522506c897", 1578)},
 +    {_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x"),           NULL, TEST_DATA("b411f9a51a6e9a9a509150c8d66ba359", 92)},
 +    {_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x"),               NULL, TEST_DATA("6e491bd055511435dcb4d9c8baed0516", 4089)},    // Warcraft III map locked by Spazy protector
 +    {_T("MPQ_2015_v1_MessListFile.mpq"),                     NULL, TEST_DATA("15e25d5be124d8ad71519f967997efc2", 8)},
 +    {_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x"),   NULL, TEST_DATA("ad81b43cbd37bbfa27e4bed4c17e6a81", 176)},
 +    {_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x"),      NULL, TEST_DATA("d6e712c275a26dc51f16b3a02f6187df", 228)},
 +    {_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x"),               NULL, TEST_DATA("457cdbf97a9ca41cfe8ea130dafaa0bb", 21)},      // Something like Somj 2.0
 +    {_T("MPQ_2016_v1_WME4_4.w3x"),                           NULL, TEST_DATA("e85e1c0ccb4465a30ffd07cae3260254", 382)},     // Protector from China (2016-05-27)
 +    {_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x"),                 NULL, TEST_DATA("b6f6d56f4f8aaef04c2c4b1f08881a8b", 16)},
 +    {_T("MPQ_2016_v1_ProtectedMap_1.4.w3x"),                 NULL, TEST_DATA("3c7908b29d3feac9ec952282390a242d", 5027)},
 +    {_T("MPQ_2016_v1_KoreanFile.w3m"),                       NULL, TEST_DATA("805d1f75712472a81c6df27b2a71f946", 18)},
 +    {_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x"),                 NULL, TEST_DATA("7a7f0749b47b5f05a8b63ecba2488a3e", 16300)},   // Protected by PG1.11.973
 +    {_T("MPQ_2017_v1_BigDummyFiles.w3x"),                    NULL, TEST_DATA("f4d2ee9d85d2c4107e0b2d00ff302dd7", 9086)},
 +    {_T("MPQ_2017_v1_TildeInFileName.mpq"),                  NULL, TEST_DATA("f203e3979247a4dbf7f3828695ac810c", 5)},
 +    {_T("MPQ_2018_v1_EWIX_v8_7.w3x"),                        NULL, TEST_DATA("12c0f4e15c7361b7c13acd37a181d83b", 857), "BlueCrystal.mdx"},
 +    {_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod"),                NULL, TEST_DATA("f45392f6523250c943990a017c230b41", 24)},      // Archive that has two fake headers before the real one
 +    {_T("MPQ_2020_v4_NP_Protect_1.s2ma"),                    NULL, TEST_DATA("1a1ea40ac1165bcdb4f2e434edfc7636", 21)},      // SC2 map that is protected by the NP_Protect
 +    {_T("MPQ_2020_v4_NP_Protect_2.s2ma"),                    NULL, TEST_DATA("7d1a379da8bd966da1f4fa6e4646049b", 55)},      // SC2 map that is protected by the NP_Protect
 +    {_T("MPQ_2015_v1_flem1.w3x"),                            NULL, TEST_DATA("1c4c13e627658c473e84d94371e31f37", 20)},
 +    {_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, TEST_DATA("5250975ed917375fc6540d7be436d4de", 114)},
 +    {_T("MPQ_2021_v1_CantExtractCHK.scx"),                   NULL, TEST_DATA("c9a7ded9f93d883b9419a52bec6087f7", 28)},
  };
  //-----------------------------------------------------------------------------
 @@ -4302,50 +4309,49 @@ int _tmain(int argc, TCHAR * argv[])      // Open all files from the command line
      //
 -    TestArchive(_T("e:\\Other.sqp"), NULL, 0, "replay.game.events", NULL);
 -    for(int i = 1; i < argc; i++)
 -    {
 -        TestOpenArchive_CompactArchive(argv[i], _T("TestArchiveCopy.mpq"), false);
 -    }
 +    //for(int i = 1; i < argc; i++)
 +    //{
 +    //    TestArchive(_T("MPQ_2021_v1_CantExtractCHK.scx"), _T("Listfile_Blizzard.txt"), TEST_FLAG_FILE_COUNT, NULL, NULL);
 +    //}
      //
      // Search all testing archives and verify their SHA1 hash
      //
 -    if(dwErrCode == ERROR_SUCCESS)
 -    {
 -        dwErrCode = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir);
 -    }
 +    //if(dwErrCode == ERROR_SUCCESS)
 +    //{
 +    //    dwErrCode = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir);
 +    //}
      //
      // Test file stream operations
      //
 -    if(dwErrCode == ERROR_SUCCESS)
 -    {
 -        for(size_t i = 0; i < _countof(TestList_StreamOps); i++)
 -        {
 -            dwErrCode = TestFileStreamOperations(TestList_StreamOps[i].szMpqName1, TestList_StreamOps[i].dwFlags);
 -            if(dwErrCode != ERROR_SUCCESS)
 -                break;
 -        }
 -    }
 +    //if(dwErrCode == ERROR_SUCCESS)
 +    //{
 +    //    for(size_t i = 0; i < _countof(TestList_StreamOps); i++)
 +    //    {
 +    //        dwErrCode = TestFileStreamOperations(TestList_StreamOps[i].szMpqName1, TestList_StreamOps[i].dwFlags);
 +    //        if(dwErrCode != ERROR_SUCCESS)
 +    //            break;
 +    //    }
 +    //}
      //
      // Test master-mirror reading operations
      //
 -    if(dwErrCode == ERROR_SUCCESS)
 -    {
 -        for(size_t i = 0; i < _countof(TestList_MasterMirror); i++)
 -        {
 -            dwErrCode = TestReadFile_MasterMirror(TestList_MasterMirror[i].szMpqName1,
 -                                                  TestList_MasterMirror[i].szMpqName2,
 -                                                  TestList_MasterMirror[i].dwFlags != 0);
 -            if(dwErrCode != ERROR_SUCCESS)
 -                break;
 -        }
 -    }
 +    //if(dwErrCode == ERROR_SUCCESS)
 +    //{
 +    //    for(size_t i = 0; i < _countof(TestList_MasterMirror); i++)
 +    //    {
 +    //        dwErrCode = TestReadFile_MasterMirror(TestList_MasterMirror[i].szMpqName1,
 +    //                                              TestList_MasterMirror[i].szMpqName2,
 +    //                                              TestList_MasterMirror[i].dwFlags != 0);
 +    //        if(dwErrCode != ERROR_SUCCESS)
 +    //            break;
 +    //    }
 +    //}
      //
      // Test opening various archives - correct, damaged, protected
 diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp index cd10a3c..8a4fc41 100644 --- a/test/TLogHelper.cpp +++ b/test/TLogHelper.cpp @@ -402,7 +402,7 @@ char * TLogHelper::CopyFormatCharacter(char * szBuffer, const char *& szFormat)      // String format
      if(szFormat[0] == '%')
      {
 -        if(szFormat[1] == 's' && szFormat[2] != ')')
 +        if(szFormat[1] == 's')
          {
              strcpy(szBuffer, szStringFormat);
              szFormat += 2;
  | 
