summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadislav <Zezula>2013-12-15 10:29:50 +0100
committerLadislav <Zezula>2013-12-15 10:29:50 +0100
commitfe51da468be9ca0963192c5f3a1705562bc957ba (patch)
tree767edeed5f8cd2b4561317724efdb2d1b2547d7b
parent6961cd51b65e8df7f807e25ab6ffc4da8c205449 (diff)
+ static analysis issues fixed
-rw-r--r--StormLib.xcodeproj/project.pbxproj2
-rw-r--r--src/FileStream.cpp10
-rw-r--r--src/SBaseCommon.cpp5
-rw-r--r--src/SBaseFileTable.cpp9
-rw-r--r--src/SFileAddFile.cpp2
-rw-r--r--src/SFileCompactArchive.cpp5
-rw-r--r--src/SFileGetFileInfo.cpp9
-rw-r--r--src/SFileListFile.cpp20
-rw-r--r--src/SFilePatchArchives.cpp1
-rw-r--r--src/SFileReadFile.cpp2
-rw-r--r--src/StormPort.h1
-rw-r--r--test/TLogHelper.cpp20
-rw-r--r--test/Test.cpp614
13 files changed, 463 insertions, 237 deletions
diff --git a/StormLib.xcodeproj/project.pbxproj b/StormLib.xcodeproj/project.pbxproj
index 7ee4f29..2cf44e7 100644
--- a/StormLib.xcodeproj/project.pbxproj
+++ b/StormLib.xcodeproj/project.pbxproj
@@ -1855,7 +1855,6 @@
MACOSX_DEPLOYMENT_TARGET = 10.6;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
- SKIP_INSTALL = YES;
STRIP_INSTALLED_PRODUCT = NO;
};
name = Debug;
@@ -1875,7 +1874,6 @@
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.6;
SDKROOT = macosx;
- SKIP_INSTALL = YES;
STRIP_INSTALLED_PRODUCT = YES;
};
name = Release;
diff --git a/src/FileStream.cpp b/src/FileStream.cpp
index a081bd7..eaf85de 100644
--- a/src/FileStream.cpp
+++ b/src/FileStream.cpp
@@ -182,7 +182,7 @@ static bool BaseFile_Read(
// we have to update the file position
if(ByteOffset != pStream->Base.File.FilePos)
{
- lseek64((intptr_t)pStream->Base.File.hFile, (__off64_t)(ByteOffset), SEEK_SET);
+ lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET);
pStream->Base.File.FilePos = ByteOffset;
}
@@ -271,7 +271,7 @@ static bool BaseFile_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const
// we have to update the file position
if(ByteOffset != pStream->Base.File.FilePos)
{
- lseek64((intptr_t)pStream->Base.File.hFile, (__off64_t)(ByteOffset), SEEK_SET);
+ lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET);
pStream->Base.File.FilePos = ByteOffset;
}
@@ -346,7 +346,7 @@ static bool BaseFile_SetSize(TFileStream * pStream, ULONGLONG NewFileSize)
#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
{
- if(ftruncate64((intptr_t)pStream->Base.File.hFile, (__off64_t)NewFileSize) == -1)
+ if(ftruncate64((intptr_t)pStream->Base.File.hFile, (off64_t)NewFileSize) == -1)
{
nLastError = errno;
return false;
@@ -1134,7 +1134,6 @@ static bool PartialStream_Read(
DWORD dwPartIndex;
DWORD dwBytesRead = 0;
DWORD dwBlockSize = pStream->BlockSize;
- bool bResult = false;
int nFailReason = ERROR_HANDLE_EOF; // Why it failed if not enough bytes was read
// If the byte offset is not entered, use the current position
@@ -1172,7 +1171,6 @@ static bool PartialStream_Read(
if((PartMap->Flags & 3) == 0)
{
nFailReason = ERROR_FILE_CORRUPT;
- bResult = false;
break;
}
@@ -1188,7 +1186,6 @@ static bool PartialStream_Read(
if(RawByteOffset == 0)
{
nFailReason = ERROR_FILE_CORRUPT;
- bResult = false;
break;
}
@@ -1201,7 +1198,6 @@ static bool PartialStream_Read(
if(!pStream->BaseRead(pStream, &RawByteOffset, pbBuffer, dwBytesInPart))
{
nFailReason = ERROR_FILE_CORRUPT;
- bResult = false;
break;
}
diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp
index a0e789b..bb580b5 100644
--- a/src/SBaseCommon.cpp
+++ b/src/SBaseCommon.cpp
@@ -371,6 +371,7 @@ DWORD DetectFileKeyByKnownContent(void * pvFileContent, DWORD nDwords, ...)
// We need at least two DWORDS to detect the file key
if(nDwords < 0x02 || nDwords > 0x10)
return 0;
+ memset(dwDecrypted, 0, sizeof(dwDecrypted));
va_start(argList, nDwords);
for(i = 0; i < nDwords; i++)
@@ -639,7 +640,7 @@ ULONGLONG FindFreeMpqSpace(TMPQArchive * ha)
{
TMPQHeader * pHeader = ha->pHeader;
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
- TFileEntry * pFileEntry = ha->pFileTable;
+ TFileEntry * pFileEntry;
ULONGLONG FreeSpacePos = ha->pHeader->dwHeaderSize;
DWORD dwChunkCount;
@@ -952,7 +953,7 @@ int AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile)
__LoadSectorOffsets:
// Allocate the sector offset table
- hf->SectorOffsets = (DWORD *)STORM_ALLOC(BYTE, dwSectorOffsLen);
+ hf->SectorOffsets = STORM_ALLOC(DWORD, (dwSectorOffsLen / sizeof(DWORD)));
if(hf->SectorOffsets == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index d4155bd..d88c5f9 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -499,7 +499,7 @@ int ConvertMpqHeaderToFormat4(
if(pHeader->HetTablePos64)
{
pHeader->HetTableSize64 = ByteOffset - pHeader->HetTablePos64;
- ByteOffset = pHeader->HetTablePos64;
+// ByteOffset = pHeader->HetTablePos64;
}
break;
@@ -1479,7 +1479,7 @@ static TMPQBetTable * TranslateBetTable(
LengthInBytes = (pBetTable->pNameHashes->NumberOfBits + 7) / 8;
if(pBetTable->pNameHashes != NULL)
memcpy(pBetTable->pNameHashes->Elements, pbSrcData, LengthInBytes);
- pbSrcData += pBetHeader->dwNameHashArraySize;
+// pbSrcData += pBetHeader->dwNameHashArraySize;
// Dump both tables
// DumpHetAndBetTable(ha->pHetTable, pBetTable);
@@ -1592,7 +1592,7 @@ TMPQExtHeader * TranslateBetTable(
// Write the array of BET hashes
LengthInBytes = (pBitArray->NumberOfBits + 7) / 8;
memcpy(pbTrgData, pBitArray->Elements, LengthInBytes);
- pbTrgData += LengthInBytes;
+// pbTrgData += LengthInBytes;
// Free the bit array
STORM_FREE(pBitArray);
@@ -2726,6 +2726,7 @@ int RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize, DWORD dwNewMaxF
// Set the new tables to the MPQ archive
ha->pFileTable = pFileTable;
ha->pHashTable = pHashTable;
+ pFileTable = NULL;
// Set the new limits to the MPQ archive
ha->pHeader->dwHashTableSize = dwNewHashTableSize;
@@ -2763,6 +2764,8 @@ int RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize, DWORD dwNewMaxF
STORM_FREE(pOldFileTable);
if(pOldHashTable != NULL)
STORM_FREE(pOldHashTable);
+ if(pFileTable != NULL)
+ STORM_FREE(pFileTable);
return nError;
}
diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp
index bb8f4f1..5246f89 100644
--- a/src/SFileAddFile.cpp
+++ b/src/SFileAddFile.cpp
@@ -276,7 +276,7 @@ static int RecryptFileData(
if(hf->SectorOffsets != NULL)
{
// Allocate secondary buffer for sectors copy
- DWORD * SectorOffsetsCopy = (DWORD *)STORM_ALLOC(BYTE, hf->SectorOffsets[0]);
+ DWORD * SectorOffsetsCopy = STORM_ALLOC(DWORD, hf->SectorOffsets[0] / sizeof(DWORD));
DWORD dwSectorOffsLen = hf->SectorOffsets[0];
if(SectorOffsetsCopy == NULL)
diff --git a/src/SFileCompactArchive.cpp b/src/SFileCompactArchive.cpp
index ad9801b..5ca4065 100644
--- a/src/SFileCompactArchive.cpp
+++ b/src/SFileCompactArchive.cpp
@@ -118,7 +118,7 @@ static int CopyNonMpqData(
DataSize -= dwToRead;
}
- return ERROR_SUCCESS;
+ return nError;
}
// Copies all file sectors into another archive.
@@ -167,7 +167,7 @@ static int CopyMpqFileSectors(
// If we have to save sector offset table, do it.
if(nError == ERROR_SUCCESS && hf->SectorOffsets != NULL)
{
- DWORD * SectorOffsetsCopy = (DWORD *)STORM_ALLOC(BYTE, hf->SectorOffsets[0]);
+ DWORD * SectorOffsetsCopy = STORM_ALLOC(DWORD, hf->SectorOffsets[0] / sizeof(DWORD));
DWORD dwSectorOffsLen = hf->SectorOffsets[0];
assert((pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) == 0);
@@ -311,7 +311,6 @@ static int CopyMpqFileSectors(
// Include these extra data in the compressed size
dwCmpSize += dwBytesToCopy;
- dwBytesToCopy = 0;
STORM_FREE(pbExtraData);
}
else
diff --git a/src/SFileGetFileInfo.cpp b/src/SFileGetFileInfo.cpp
index 07b7722..da47fc9 100644
--- a/src/SFileGetFileInfo.cpp
+++ b/src/SFileGetFileInfo.cpp
@@ -143,6 +143,7 @@ bool WINAPI SFileGetFileInfo(
TFileEntry * pFileEntry = NULL;
ULONGLONG Int64Value = 0;
ULONGLONG ByteOffset = 0;
+ TMPQHash * pHash;
TMPQFile * hf = NULL;
void * pvSrcFileInfo = NULL;
DWORD cbSrcFileInfo = 0;
@@ -691,7 +692,8 @@ bool WINAPI SFileGetFileInfo(
hf = IsValidFileHandle(hMpqOrFile);
if(hf != NULL && hf->ha != NULL && hf->ha->pHashTable != NULL)
{
- pvSrcFileInfo = &ha->pHashTable[hf->pFileEntry->dwHashIndex].dwName1;
+ pHash = hf->ha->pHashTable + hf->pFileEntry->dwHashIndex;
+ pvSrcFileInfo = &pHash->dwName1;
cbSrcFileInfo = sizeof(DWORD);
nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
}
@@ -701,7 +703,8 @@ bool WINAPI SFileGetFileInfo(
hf = IsValidFileHandle(hMpqOrFile);
if(hf != NULL && hf->ha != NULL && hf->ha->pHashTable != NULL)
{
- pvSrcFileInfo = &ha->pHashTable[hf->pFileEntry->dwHashIndex].dwName2;
+ pHash = hf->ha->pHashTable + hf->pFileEntry->dwHashIndex;
+ pvSrcFileInfo = &pHash->dwName2;
cbSrcFileInfo = sizeof(DWORD);
nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
}
@@ -825,7 +828,7 @@ bool WINAPI SFileGetFileInfo(
pcbLengthNeeded[0] = cbSrcFileInfo;
// If the caller entered an output buffer, the output size must also be entered
- if(pvFileInfo != NULL && cbFileInfo != 0)
+ if(pvSrcFileInfo != NULL && pvFileInfo != NULL && cbFileInfo != 0)
{
// Check if there is enough space in the output buffer
if(cbSrcFileInfo <= cbFileInfo)
diff --git a/src/SFileListFile.cpp b/src/SFileListFile.cpp
index 896b341..c1197c9 100644
--- a/src/SFileListFile.cpp
+++ b/src/SFileListFile.cpp
@@ -138,7 +138,7 @@ static DWORD ReloadListFileCache(TListFileCache * pCache)
// Load the next data chunk to the cache
SFileSetFilePointer(pCache->hFile, pCache->dwFilePos, NULL, FILE_BEGIN);
- SFileReadFile(pCache->hFile, pCache->Buffer, CACHE_BUFFER_SIZE, &dwBytesRead, NULL);
+ SFileReadFile(pCache->hFile, pCache->Buffer, dwBytesToRead, &dwBytesRead, NULL);
// If we didn't read anything, it might mean that the block
// of the file is not available (in case of partial MPQs).
@@ -327,7 +327,6 @@ static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFil
TFileEntry * pFileEntry;
TMPQHash * pFirstHash;
TMPQHash * pHash;
- bool bNameEntryCreated = false;
// If we have HET table, use that one
if(ha->pHetTable != NULL)
@@ -337,14 +336,13 @@ static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFil
{
// Allocate file name for the file entry
AllocateFileName(ha, pFileEntry, szFileName);
- bNameEntryCreated = true;
}
return ERROR_SUCCESS;
}
// If we have hash table, we use it
- if(bNameEntryCreated == false && ha->pHashTable != NULL)
+ if(ha->pHashTable != NULL)
{
// Look for the first hash table entry for the file
pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
@@ -357,7 +355,6 @@ static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFil
{
// Allocate file name for the file entry
AllocateFileName(ha, ha->pFileTable + pHash->dwBlockIndex, szFileName);
- bNameEntryCreated = true;
}
// Now find the next language version of the file
@@ -599,17 +596,20 @@ HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const
}
}
+ // Close the listfile
+ if(hListFile != NULL)
+ SFileCloseFile(hListFile);
+
// Cleanup & exit
if(nError != ERROR_SUCCESS)
{
+ if(pCache != NULL)
+ FreeListFileCache(pCache);
+ pCache = NULL;
+
memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA));
SetLastError(nError);
}
-
- if(pCache != NULL)
- FreeListFileCache(pCache);
- if(hListFile != NULL)
- SFileCloseFile(hListFile);
return (HANDLE)pCache;
}
diff --git a/src/SFilePatchArchives.cpp b/src/SFilePatchArchives.cpp
index 7f67749..cc10726 100644
--- a/src/SFilePatchArchives.cpp
+++ b/src/SFilePatchArchives.cpp
@@ -65,7 +65,6 @@ static void Decompress_RLE(LPBYTE pbDecompressed, DWORD cbDecompressed, LPBYTE p
// Cut the initial DWORD from the compressed chunk
pbCompressed += sizeof(DWORD);
- cbCompressed -= sizeof(DWORD);
// Pre-fill decompressed buffer with zeros
memset(pbDecompressed, 0, cbDecompressed);
diff --git a/src/SFileReadFile.cpp b/src/SFileReadFile.cpp
index ff4783c..1e1ae56 100644
--- a/src/SFileReadFile.cpp
+++ b/src/SFileReadFile.cpp
@@ -301,7 +301,7 @@ static int ReadMpqFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos
}
else
{
- if(pbRawData != hf->pbFileSector)
+ if(hf->pbFileSector != NULL && pbRawData != hf->pbFileSector)
memcpy(hf->pbFileSector, pbRawData, hf->dwDataSize);
}
diff --git a/src/StormPort.h b/src/StormPort.h
index 83d8624..38726ab 100644
--- a/src/StormPort.h
+++ b/src/StormPort.h
@@ -186,6 +186,7 @@
#define stat64 stat
#define fstat64 fstat
#define lseek64 lseek
+ #define ftruncate64 ftruncate
#define off64_t off_t
#define O_LARGEFILE 0
#endif
diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp
index 8bfb5fd..229f9fb 100644
--- a/test/TLogHelper.cpp
+++ b/test/TLogHelper.cpp
@@ -38,6 +38,7 @@ class TLogHelper
const char * UserString;
unsigned int UserCount;
unsigned int UserTotal;
+ bool bDontPrintResult;
protected:
@@ -78,14 +79,15 @@ TLogHelper::TLogHelper(const char * szNewTestTitle, const char * szNewSubTitle)
szSubTitle = szNewSubTitle;
nTextLength = 0;
bMessagePrinted = false;
+ bDontPrintResult = false;
// Print the initial information
if(szMainTitle != NULL)
{
if(szSubTitle != NULL)
- printf("Running test %s (%s) ...", szMainTitle, szSubTitle);
+ printf("Running %s (%s) ...", szMainTitle, szSubTitle);
else
- printf("Running test %s ...", szMainTitle);
+ printf("Running %s ...", szMainTitle);
}
}
@@ -101,10 +103,18 @@ TLogHelper::~TLogHelper()
// Print the final information
if(szSaveMainTitle != NULL && bMessagePrinted == false)
{
- if(szSaveSubTitle != NULL)
- PrintMessage("The test %s (%s) succeeded.", szSaveMainTitle, szSaveSubTitle);
+ if(bDontPrintResult == false)
+ {
+ if(szSaveSubTitle != NULL)
+ PrintMessage("%s (%s) succeeded.", szSaveMainTitle, szSaveSubTitle);
+ else
+ PrintMessage("%s succeeded.", szSaveMainTitle);
+ }
else
- PrintMessage("The test %s succeeded.", szSaveMainTitle);
+ {
+ PrintProgress(" ");
+ printf("\r");
+ }
}
}
diff --git a/test/Test.cpp b/test/Test.cpp
index 061d432..7566fbe 100644
--- a/test/Test.cpp
+++ b/test/Test.cpp
@@ -44,10 +44,11 @@
#endif
// Global for the work MPQ
-static const char * szMpqSubDir = "1996 - Test MPQs";
-static const char * szMpqPatchDir = "1996 - Test MPQs\\patches";
+static const char * szMpqSubDir = "1995 - Test MPQs";
+static const char * szMpqPatchDir = "1995 - Test MPQs\\patches";
-typedef int (*ARCHIVE_TEST)(const char * szMpqName);
+typedef int (*FIND_FILE_CALLBACK)(const char * szFullPath);
+typedef int (*FIND_PAIR_CALLBACK)(const char * szFullPath1, const char * szFullPath2);
//-----------------------------------------------------------------------------
// Testing data
@@ -195,20 +196,13 @@ static bool IsMpqExtension(const char * szFileName)
return true;
if(!_stricmp(szExtension, ".SC2Map"))
return true;
+ if(!_stricmp(szExtension, ".link"))
+ return true;
}
return false;
}
-static bool IsUnicodeNameConvertableToAnsi(const TCHAR * szFileNameT, const char * szFileNameA)
-{
- TCHAR szUnicodeName[MAX_PATH];
-
- // Convert the ANSI to UNICODE and compare them
- CopyFileName(szUnicodeName, szFileNameA, strlen(szFileNameA));
- return (_tcsicmp(szUnicodeName, szFileNameT) == 0);
-}
-
static size_t ConvertSha1ToText(const unsigned char * sha1_digest, char * szSha1Text)
{
const char * szTable = "0123456789abcdef";
@@ -224,25 +218,119 @@ static size_t ConvertSha1ToText(const unsigned char * sha1_digest, char * szSha1
return (SHA1_DIGEST_SIZE * 2);
}
-static const char * GetShortPlainName(const char * szFileName)
+static int GetPathSeparatorCount(const char * szPath)
{
- const char * szPlainName = szFileName;
- const char * szPlainEnd = szFileName + strlen(szFileName);
+ int nSeparatorCount = 0;
- // If there is terminating slash or backslash, move to it
- while(szFileName < szPlainEnd)
+ while(szPath[0] != 0)
{
- if(szFileName[0] == '\\' || szFileName[0] == '/')
- szPlainName = szFileName + 1;
- szFileName++;
+ if(szPath[0] == '\\' || szPath[0] == '/')
+ nSeparatorCount++;
+ szPath++;
}
+ return nSeparatorCount;
+}
+
+static const char * FindNextPathPart(const char * szPath, size_t nPartCount)
+{
+ const char * szPathPart = szPath;
+
+ while(szPath[0] != 0 && nPartCount > 0)
+ {
+ // Is there path separator?
+ if(szPath[0] == '\\' || szPath[0] == '/')
+ {
+ szPathPart = szPath + 1;
+ nPartCount--;
+ }
+
+ // Move to the next letter
+ szPath++;
+ }
+
+ return szPathPart;
+}
+
+static const char * GetShortPlainName(const char * szFileName)
+{
+ const char * szPlainName = FindNextPathPart(szFileName, 1000);
+ const char * szPlainEnd = szFileName + strlen(szFileName);
+
// If the name is still too long, cut it
if((szPlainEnd - szPlainName) > 50)
szPlainName = szPlainEnd - 50;
return szPlainName;
}
+static void CopyPathPart(char * szBuffer, const char * szPath)
+{
+ while(szPath[0] != 0)
+ {
+ szBuffer[0] = (szPath[0] == '\\' || szPath[0] == '/') ? '/' : szPath[0];
+ szBuffer++;
+ szPath++;
+ }
+
+ *szBuffer = 0;
+}
+
+static void CalculateRelativePath(const char * szFullPath1, const char * szFullPath2, char * szBuffer)
+{
+ const char * szPathPart1 = szFullPath1;
+ const char * szPathPart2 = szFullPath2;
+ const char * szNextPart1;
+ const char * szNextPart2;
+ int nEqualParts = 0;
+ int nStepsUp = 0;
+
+ // Parse both paths and find all path parts that are equal
+ for(;;)
+ {
+ // Find the next part of the first path
+ szNextPart1 = FindNextPathPart(szPathPart1, 1);
+ if(szNextPart1 == szPathPart1)
+ break;
+
+ szNextPart2 = FindNextPathPart(szPathPart2, 1);
+ if(szNextPart2 == szPathPart2)
+ break;
+
+ // Are these equal?
+ if((szNextPart2 - szPathPart2) != (szNextPart1 - szPathPart1))
+ break;
+ if(_strnicmp(szPathPart1, szPathPart2, (szNextPart1 - szPathPart1 - 1)))
+ break;
+
+ // Increment the number of path parts that are equal
+ szPathPart1 = szNextPart1;
+ szPathPart2 = szNextPart2;
+ nEqualParts++;
+ }
+
+ // If we found at least one equal part, we can create relative path
+ if(nEqualParts != 0)
+ {
+ // Calculate how many steps up we need to go
+ nStepsUp = GetPathSeparatorCount(szPathPart2);
+
+ // Append "../" nStepsUp-times
+ for(int i = 0; i < nStepsUp; i++)
+ {
+ *szBuffer++ = '.';
+ *szBuffer++ = '.';
+ *szBuffer++ = '/';
+ }
+
+ // Append the rest of the path. Also change DOS backslashes to slashes
+ CopyPathPart(szBuffer, szPathPart1);
+ return;
+ }
+
+ // Failed. Just copy the source path as it is
+ strcpy(szBuffer, szFullPath1);
+}
+
static void CreateFullPathName(char * szBuffer, const char * szSubDir, const char * szNamePart1, const char * szNamePart2 = NULL)
{
size_t nLength;
@@ -299,6 +387,133 @@ static void CreateFullPathName(char * szBuffer, const char * szSubDir, const cha
*szBuffer = 0;
}
+static int FindFilesInternal(FIND_FILE_CALLBACK pfnTest, char * szDirectory)
+{
+ char * szPlainName;
+ int nError = ERROR_SUCCESS;
+
+ // Setup the search masks
+ strcat(szDirectory, "\\*");
+ szPlainName = strrchr(szDirectory, '*');
+
+ if(szDirectory != NULL && szPlainName != NULL)
+ {
+#ifdef PLATFORM_WINDOWS
+ WIN32_FIND_DATAA wf;
+ HANDLE hFind;
+
+ // Initiate search. Use ANSI function only
+ hFind = FindFirstFileA(szDirectory, &wf);
+ if(hFind != INVALID_HANDLE_VALUE)
+ {
+ // Skip the first entry, since it's always "." or ".."
+ while(FindNextFileA(hFind, &wf) && nError == ERROR_SUCCESS)
+ {
+ // Found a directory?
+ if(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if(wf.cFileName[0] != '.')
+ {
+ strcpy(szPlainName, wf.cFileName);
+ nError = FindFilesInternal(pfnTest, szDirectory);
+ }
+ }
+ else
+ {
+ if(pfnTest != NULL)
+ {
+ strcpy(szPlainName, wf.cFileName);
+ nError = pfnTest(szDirectory);
+ }
+ }
+ }
+
+ FindClose(hFind);
+ }
+#endif
+ }
+
+ // Free the path buffer, if any
+ return nError;
+}
+
+static int FindFiles(FIND_FILE_CALLBACK pfnFindFile, const char * szSubDirectory)
+{
+ char szWorkBuff[MAX_PATH];
+
+ CreateFullPathName(szWorkBuff, szSubDirectory, NULL);
+ return FindFilesInternal(pfnFindFile, szWorkBuff);
+}
+
+static int FindFilePairsInternal(
+ FIND_PAIR_CALLBACK pfnFilePair,
+ char * szSource,
+ char * szTarget)
+{
+ char * szPlainName1;
+ char * szPlainName2;
+ int nError = ERROR_SUCCESS;
+
+ // Setup the search masks
+ strcat(szSource, "\\*");
+ szPlainName1 = strrchr(szSource, '*');
+ strcat(szTarget, "\\*");
+ szPlainName2 = strrchr(szTarget, '*');
+
+ // If both paths are OK, perform the search
+ if(szPlainName1 != NULL && szPlainName2 != NULL)
+ {
+#ifdef PLATFORM_WINDOWS
+ WIN32_FIND_DATAA wf;
+ HANDLE hFind;
+
+ // Search the second directory
+ hFind = FindFirstFileA(szTarget, &wf);
+ if(hFind != INVALID_HANDLE_VALUE)
+ {
+ // Skip the first entry, since it's always "." or ".."
+ while(FindNextFileA(hFind, &wf) && nError == ERROR_SUCCESS)
+ {
+ // Found a directory?
+ if(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if(wf.cFileName[0] != '.')
+ {
+ strcpy(szPlainName1, wf.cFileName);
+ strcpy(szPlainName2, wf.cFileName);
+ nError = FindFilePairsInternal(pfnFilePair, szSource, szTarget);
+ }
+ }
+ else
+ {
+ if(pfnFilePair != NULL)
+ {
+ strcpy(szPlainName1, wf.cFileName);
+ strcpy(szPlainName2, wf.cFileName);
+ nError = pfnFilePair(szSource, szTarget);
+ }
+ }
+ }
+
+ FindClose(hFind);
+ }
+#endif
+ }
+
+ return nError;
+}
+
+static int FindFilePairs(FIND_PAIR_CALLBACK pfnFindPair, const char * szSourceSubDir, const char * szTargetSubDir)
+{
+ char szSource[MAX_PATH];
+ char szTarget[MAX_PATH];
+
+ // Create the source search mask
+ CreateFullPathName(szSource, szSourceSubDir, NULL);
+ CreateFullPathName(szTarget, szTargetSubDir, NULL);
+ return FindFilePairsInternal(pfnFindPair, szSource, szTarget);
+}
+
TFileStream * OpenLocalFile(const char * szFileName, DWORD dwStreamFlags)
{
TCHAR szFileNameT[MAX_PATH];
@@ -315,6 +530,76 @@ TFileStream * CreateLocalFile(const char * szFileName, DWORD dwStreamFlags)
return FileStream_CreateFile(szFileNameT, dwStreamFlags);
}
+static int CalculateFileSha1(TLogHelper * pLogger, const char * szFullPath, char * szFileSha1)
+{
+ TFileStream * pStream;
+ unsigned char sha1_digest[SHA1_DIGEST_SIZE];
+ const char * szShortPlainName = GetShortPlainName(szFullPath);
+ hash_state sha1_state;
+ ULONGLONG ByteOffset = 0;
+ ULONGLONG FileSize = 0;
+ BYTE * pbFileBlock;
+ DWORD cbBytesToRead;
+ DWORD cbFileBlock = 0x100000;
+ int nError = ERROR_SUCCESS;
+
+ // Notify the user
+ pLogger->PrintProgress("Hashing file %s", szShortPlainName);
+ szFileSha1[0] = 0;
+
+ // Open the file to be verified
+ pStream = OpenLocalFile(szFullPath, STREAM_FLAG_READ_ONLY);
+ if(pStream != NULL)
+ {
+ // Retrieve the size of the file
+ FileStream_GetSize(pStream, &FileSize);
+
+ // Allocate the buffer for loading file parts
+ pbFileBlock = STORM_ALLOC(BYTE, cbFileBlock);
+ if(pbFileBlock != NULL)
+ {
+ // Initialize SHA1 calculation
+ sha1_init(&sha1_state);
+
+ // Calculate the SHA1 of the file
+ while(ByteOffset < FileSize)
+ {
+ // Notify the user
+ pLogger->PrintProgress("Hashing file %s (%I64u of %I64u)", szShortPlainName, ByteOffset, FileSize);
+
+ // Load the file block
+ cbBytesToRead = ((FileSize - ByteOffset) > cbFileBlock) ? cbFileBlock : (DWORD)(FileSize - ByteOffset);
+ if(!FileStream_Read(pStream, &ByteOffset, pbFileBlock, cbBytesToRead))
+ {
+ nError = GetLastError();
+ break;
+ }
+
+ // Add to SHA1
+ sha1_process(&sha1_state, pbFileBlock, cbBytesToRead);
+ ByteOffset += cbBytesToRead;
+ }
+
+ // Notify the user
+ pLogger->PrintProgress("Hashing file %s (%I64u of %I64u)", szShortPlainName, ByteOffset, FileSize);
+
+ // Finalize SHA1
+ sha1_done(&sha1_state, sha1_digest);
+
+ // Convert the SHA1 to ANSI text
+ ConvertSha1ToText(sha1_digest, szFileSha1);
+ STORM_FREE(pbFileBlock);
+ }
+
+ FileStream_Close(pStream);
+ }
+
+ // If we calculated something, return OK
+ if(nError == ERROR_SUCCESS && szFileSha1[0] == 0)
+ nError = ERROR_CAN_NOT_COMPLETE;
+ return nError;
+}
+
static int InitializeMpqDirectory(char * argv[], int argc)
{
TLogHelper Logger("InitWorkDir");
@@ -714,7 +999,7 @@ static void WINAPI CompactCallback(void * pvUserData, DWORD dwWork, ULONGLONG By
if(pLogger != NULL)
pLogger->PrintProgress("%s (%I64u of %I64u) ...", szWork, BytesDone, TotalBytes);
else
- printf("%s (" I64u_a " of " I64u_a ") ... \r", szWork, (DWORD)BytesDone, (DWORD)TotalBytes);
+ printf("%s (" I64u_a " of " I64u_a ") ... \r", szWork, BytesDone, TotalBytes);
}
}
@@ -1307,104 +1592,6 @@ static void TestGetFileInfo(
pLogger->PrintMessage("Different error from SFileGetFileInfo (expected %u, returned %u)", nExpectedError, nError);
}
-static int TestVerifyFileChecksum(const char * szFullPath)
-{
- const char * szShortPlainName = GetShortPlainName(szFullPath);
- unsigned char sha1_digest[SHA1_DIGEST_SIZE];
- TFileStream * pStream;
- TFileData * pFileData;
- hash_state sha1_state;
- ULONGLONG ByteOffset = 0;
- ULONGLONG FileSize = 0;
- char * szExtension;
- LPBYTE pbFileBlock;
- char szShaFileName[MAX_PATH];
- char Sha1Text[0x40];
- DWORD cbBytesToRead;
- DWORD cbFileBlock = 0x10000;
- size_t nLength;
- int nError = ERROR_SUCCESS;
-
- // Try to load the file with the SHA extension
- strcpy(szShaFileName, szFullPath);
- szExtension = strrchr(szShaFileName, '.');
- if(szExtension == NULL)
- return ERROR_SUCCESS;
-
- // Skip .SHA and .TXT files
- if(!_stricmp(szExtension, ".sha") || !_stricmp(szExtension, ".txt"))
- return ERROR_SUCCESS;
-
- // Load the local file to memory
- strcpy(szExtension, ".sha");
- pFileData = LoadLocalFile(NULL, szShaFileName, false);
- if(pFileData != NULL)
- {
- TLogHelper Logger("VerifyFileHash", szShortPlainName);
-
- // Open the file to be verified
- pStream = OpenLocalFile(szFullPath, STREAM_FLAG_READ_ONLY);
- if(pStream != NULL)
- {
- // Notify the user
- Logger.PrintProgress("Verifying file %s", szShortPlainName);
-
- // Retrieve the size of the file
- FileStream_GetSize(pStream, &FileSize);
-
- // Allocate the buffer for loading file parts
- pbFileBlock = STORM_ALLOC(BYTE, cbFileBlock);
- if(pbFileBlock != NULL)
- {
- // Initialize SHA1 calculation
- sha1_init(&sha1_state);
-
- // Calculate the SHA1 of the file
- while(ByteOffset < FileSize)
- {
- // Notify the user
- Logger.PrintProgress("Verifying file %s (%I64u of %I64u)", szShortPlainName, ByteOffset, FileSize);
-
- // Load the file block
- cbBytesToRead = ((FileSize - ByteOffset) > cbFileBlock) ? cbFileBlock : (DWORD)(FileSize - ByteOffset);
- if(!FileStream_Read(pStream, &ByteOffset, pbFileBlock, cbBytesToRead))
- {
- nError = GetLastError();
- break;
- }
-
- // Add to SHA1
- sha1_process(&sha1_state, pbFileBlock, cbBytesToRead);
- ByteOffset += cbBytesToRead;
- }
-
- // Finalize SHA1
- sha1_done(&sha1_state, sha1_digest);
- STORM_FREE(pbFileBlock);
-
- // Compare with what we loaded from the file
- if(pFileData->dwFileSize >= (SHA1_DIGEST_SIZE * 2))
- {
- // Compare the Sha1
- nLength = ConvertSha1ToText(sha1_digest, Sha1Text);
- if(_strnicmp(Sha1Text, (char *)pFileData->FileData, nLength))
- {
- Logger.PrintError("File CRC check failed: %s", szFullPath);
- nError = ERROR_FILE_CORRUPT;
- }
- }
- }
-
- // Close the file
- FileStream_Close(pStream);
- }
-
- STORM_FREE(pFileData);
- }
-
- return nError;
-}
-
// StormLib is able to open local files (as well as the original Storm.dll)
// I want to keep this for occasional use
static int TestOpenLocalFile(const char * szPlainName)
@@ -1630,7 +1817,7 @@ static int TestOpenArchive_ReadOnly(const char * szPlainName, bool bReadOnly)
{
const char * szCopyName;
TLogHelper Logger("ReadOnlyTest", szPlainName);
- HANDLE hMpq;
+ HANDLE hMpq = NULL;
char szFullPathName[MAX_PATH];
DWORD dwFlags = bReadOnly ? MPQ_OPEN_READ_ONLY : 0;;
bool bMustSucceed;
@@ -1872,9 +2059,56 @@ static int TestOpenArchive_CraftedUserData(const char * szPlainName, const char
return nError;
}
+static int ForEachFile_VerifyFileChecksum(const char * szFullPath)
+{
+ const char * szShortPlainName = GetShortPlainName(szFullPath);
+ TFileData * pFileData;
+ char * szExtension;
+ char szShaFileName[MAX_PATH];
+ char szSha1Text[0x40];
+ int nError = ERROR_SUCCESS;
+
+ // Try to load the file with the SHA extension
+ strcpy(szShaFileName, szFullPath);
+ szExtension = strrchr(szShaFileName, '.');
+ if(szExtension == NULL)
+ return ERROR_SUCCESS;
+
+ // Skip .SHA and .TXT files
+ if(!_stricmp(szExtension, ".sha") || !_stricmp(szExtension, ".txt"))
+ return ERROR_SUCCESS;
+
+ // Load the local file to memory
+ strcpy(szExtension, ".sha");
+ pFileData = LoadLocalFile(NULL, szShaFileName, false);
+ if(pFileData != NULL)
+ {
+ TLogHelper Logger("VerifyFileHash", szShortPlainName);
+
+ // Calculate SHA1 of the entire file
+ nError = CalculateFileSha1(&Logger, szFullPath, szSha1Text);
+ if(nError == ERROR_SUCCESS)
+ {
+ // Compare with what we loaded from the file
+ if(pFileData->dwFileSize >= (SHA1_DIGEST_SIZE * 2))
+ {
+ // Compare the SHA1
+ if(_strnicmp(szSha1Text, (char *)pFileData->FileData, (SHA1_DIGEST_SIZE * 2)))
+ {
+ Logger.PrintError("File CRC check failed: %s", szFullPath);
+ nError = ERROR_FILE_CORRUPT;
+ }
+ }
+ }
+
+ STORM_FREE(pFileData);
+ }
-// Searches a direcroty
-static int TestOpenEachArchive_EachFile(const char * szFullPath)
+ return nError;
+}
+
+// Opens a found archive
+static int ForEachFile_OpenArchive(const char * szFullPath)
{
HANDLE hMpq = NULL;
DWORD dwFileCount = 0;
@@ -2342,7 +2576,8 @@ static int TestCreateArchive_FileFlagTest(const char * szPlainName)
hMpq = NULL;
// Try to reopen the archive
- nError = OpenExistingArchive(&Logger, szFullPath, 0, NULL);
+ if(nError == ERROR_SUCCESS)
+ nError = OpenExistingArchive(&Logger, szFullPath, 0, NULL);
return nError;
}
@@ -2547,90 +2782,67 @@ static int TestCreateArchive_BigArchive(const char * szPlainName)
return nError;
}
-static int TestForEachArchive(ARCHIVE_TEST pfnTest, TCHAR * szSearchMask, TCHAR * szPlainName)
+//-----------------------------------------------------------------------------
+// Comparing two directories, creating links
+
+#define LINK_COMPARE_BLOCK_SIZE 0x200
+
+static int CreateArchiveLinkFile(const char * szFullPath1, const char * szFullPath2, const char * szFileHash)
{
- TCHAR szPathBuffT[MAX_PATH];
- char szPathBuffA[MAX_PATH];
- char szFullPath[MAX_PATH];
- int nError = ERROR_SUCCESS;
+ TFileStream * pStream;
+ char szLinkData[MAX_PATH + 0x80];
+ char szLinkFile[MAX_PATH];
+ char szLinkPath[MAX_PATH];
+ int nLength;
- // If the name was not entered, construct new one
- if(szSearchMask == NULL)
- {
- CreateFullPathName(szPathBuffA, szMpqSubDir, "*");
- CopyFileName(szPathBuffT, szPathBuffA, strlen(szPathBuffA));
- szSearchMask = szPathBuffT;
- }
+ // Construct the link file name
+ CalculateRelativePath(szFullPath1, szFullPath2, szLinkPath);
+ sprintf(szLinkFile, "%s.link", szFullPath2);
- // Get the position of the plain name
- if(szPlainName == NULL)
- {
- szPlainName = _tcsrchr(szSearchMask, _T('*'));
- if(szPlainName == NULL)
- return ERROR_SUCCESS;
- }
+ // Format the content of the link file
+ nLength = sprintf(szLinkData, "LINK:%s\x0D\x0ASHA1:%s", szLinkPath, szFileHash);
- // At this point, both pointers must be valid
- assert(szSearchMask != NULL && szPlainName != NULL);
+ // Create the link file
+ pStream = CreateLocalFile(szLinkFile, 0);
+ if(pStream == NULL)
+ return GetLastError();
- // Now both must be entered
- if(szSearchMask != NULL && szPlainName != NULL)
- {
-#ifdef PLATFORM_WINDOWS
- WIN32_FIND_DATA wf;
- HANDLE hFind;
+ // Write the content of the link file
+ FileStream_Write(pStream, NULL, szLinkData, (DWORD)nLength);
+ FileStream_Close(pStream);
+ return ERROR_SUCCESS;
+}
- // Initiate search. Use ANSI function only
- hFind = FindFirstFile(szSearchMask, &wf);
- if(hFind != INVALID_HANDLE_VALUE)
+static int ForEachFile_CreateArchiveLink(const char * szFullPath1, const char * szFullPath2)
+{
+ TLogHelper Logger("CreateMpqLink", GetShortPlainName(szFullPath2));
+ char szFileHash1[0x40];
+ char szFileHash2[0x40];
+ int nError;
+
+ // Prevent logger from witing any result messages
+ Logger.bDontPrintResult = true;
+
+ // Create SHA1 of both files
+ nError = CalculateFileSha1(&Logger, szFullPath1, szFileHash1);
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = CalculateFileSha1(&Logger, szFullPath2, szFileHash2);
+ if(nError == ERROR_SUCCESS)
{
- // Skip the first entry, since it's always "." or ".."
- while(FindNextFile(hFind, &wf) && nError == ERROR_SUCCESS)
+ // If the hashes are identical, we can create link
+ if(!strcmp(szFileHash1, szFileHash2))
{
- // Found a directory?
- if(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ nError = CreateArchiveLinkFile(szFullPath1, szFullPath2, szFileHash1);
+ if(nError == ERROR_SUCCESS)
{
- if(wf.cFileName[0] != '.')
- {
- _stprintf(szPlainName, _T("%s\\*"), wf.cFileName);
- nError = TestForEachArchive(pfnTest, szSearchMask, NULL);
- }
- }
- else
- {
- if(pfnTest != NULL)
- {
- // Create the full path as TCHAR
- _tcscpy(szPlainName, wf.cFileName);
- CopyFileName(szFullPath, szSearchMask, _tcslen(szSearchMask));
-
- // Check for UNICODE names
- if(IsUnicodeNameConvertableToAnsi(szSearchMask, szFullPath))
- nError = pfnTest(szFullPath);
- }
+ Logger.PrintMessage("Created link to %s", szFullPath2);
}
}
-
- FindClose(hFind);
}
-#endif
}
- // Free the path buffer, if any
- return nError;
-}
-
-static int TestOpenArchive_EachArchive()
-{
- TCHAR szSearchMaskT[MAX_PATH];
- char szSearchMaskA[MAX_PATH];
-
- // Create the TCHAR name of search mask
- CreateFullPathName(szSearchMaskA, NULL, "*");
- CopyFileName(szSearchMaskT, szSearchMaskA, strlen(szSearchMaskA));
-
- // Invoke the searching function
- return TestForEachArchive(TestOpenEachArchive_EachFile, szSearchMaskT, NULL);
+ return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------
@@ -2648,10 +2860,14 @@ int main(int argc, char * argv[])
printf("==== Test Suite for StormLib version %s ====\n", STORMLIB_VERSION_STRING);
nError = InitializeMpqDirectory(argv, argc);
- // Search all testing archives and verify their SHA1 hash
+ // Not a test, but rather a tool for creating links to duplicated files
if(nError == ERROR_SUCCESS)
- nError = TestForEachArchive(TestVerifyFileChecksum, NULL, NULL);
+ nError = FindFilePairs(ForEachFile_CreateArchiveLink, "2004 - WoW\\16965", "2004 - WoW\\17658");
+ // Search all testing archives and verify their SHA1 hash
+ if(nError == ERROR_SUCCESS)
+ nError = FindFiles(ForEachFile_VerifyFileChecksum, szMpqDirectory);
+
// Test opening local file with SFileOpenFileEx
if(nError == ERROR_SUCCESS)
nError = TestOpenLocalFile("ListFile_Blizzard.txt");
@@ -2720,6 +2936,10 @@ int main(int argc, char * argv[])
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2010_v2_HashTableCompressed.MPQ.part");
+ // Open every MPQ that we have in the storage
+ if(nError == ERROR_SUCCESS)
+ nError = FindFiles(ForEachFile_OpenArchive, szMpqDirectory);
+
// Open a patched archive
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive_Patched(PatchList_WoW_OldWorld13286, "OldWorld\\World\\Model.blob", 2);
@@ -2764,10 +2984,6 @@ int main(int argc, char * argv[])
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive_CraftedUserData("MPQ_2013_v4_expansion1.MPQ", "StormLibTest_CraftedMpq3_v4.mpq");
- // Open every MPQ that we have in the storage
- if(nError == ERROR_SUCCESS)
- nError = TestOpenArchive_EachArchive();
-
// Test modifying file with no (listfile) and no (attributes)
if(nError == ERROR_SUCCESS)
nError = TestAddFile_ListFileTest("MPQ_1997_v1_Diablo1_DIABDAT.MPQ", false, false);