aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadislav Zezula <ladislav.zezula@avg.com>2013-12-06 15:20:47 +0100
committerLadislav Zezula <ladislav.zezula@avg.com>2013-12-06 15:20:47 +0100
commitf2a388780f83cfd95afa27b01dafe3a683b0e39c (patch)
tree34137a334e713c088a41ea2bdbdba0648df5f00b
parentc34c37b3418f1e5ab3678ce65d46f81803dec91d (diff)
+ Bug fixes in SFileGetFileInfo, SAttrFileSaveToMpq, SListFileSaveToMpq
+ FileStream now handles files over 2GB properly + Test under Linux
-rw-r--r--Publish.bat30
-rw-r--r--Publish_beta.bat30
-rw-r--r--src/FileStream.cpp18
-rw-r--r--src/SFileAttributes.cpp33
-rw-r--r--src/SFileGetFileInfo.cpp195
-rw-r--r--src/SFileListFile.cpp8
-rw-r--r--src/StormLib.h2
-rw-r--r--test/TLogHelper.cpp107
-rw-r--r--test/Test.cpp51
9 files changed, 306 insertions, 168 deletions
diff --git a/Publish.bat b/Publish.bat
index 9c9a639..b5c71fc 100644
--- a/Publish.bat
+++ b/Publish.bat
@@ -2,21 +2,23 @@
rem This BAT file updates the ZIP file that is to be uploaded to web
rem Only use when both 32-bit and 64-bit are properly compiled
-echo Creating stormlib.zip ...
+set STORMLIB_NAME=stormlib-9.00
+
+echo Creating %STORMLIB_NAME%.zip ...
cd \Ladik\Appdir
-zip.exe -ur9 ..\WWW\web\download\stormlib.zip StormLib\doc\*
-zip.exe -ur9 ..\WWW\web\download\stormlib.zip StormLib\src\*
-zip.exe -ur9 ..\WWW\web\download\stormlib.zip StormLib\storm_dll\*
-zip.exe -ur9 ..\WWW\web\download\stormlib.zip StormLib\StormLib.xcodeproj\*
-zip.exe -ur9 ..\WWW\web\download\stormlib.zip StormLib\stormlib_dll\*
-zip.exe -ur9 ..\WWW\web\download\stormlib.zip StormLib\test\*
-zip.exe -u9 ..\WWW\web\download\stormlib.zip StormLib\CMakeLists.txt
-zip.exe -u9 ..\WWW\web\download\stormlib.zip StormLib\makefile.*
-zip.exe -u9 ..\WWW\web\download\stormlib.zip StormLib\Info.plist
-zip.exe -u9 ..\WWW\web\download\stormlib.zip StormLib\*.bat
-zip.exe -u9 ..\WWW\web\download\stormlib.zip StormLib\*.sln
-zip.exe -u9 ..\WWW\web\download\stormlib.zip StormLib\*.vcproj
-zip.exe -u9 ..\WWW\web\download\stormlib.zip StormLib\*.vcxproj
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\doc\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\src\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\storm_dll\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\StormLib.xcodeproj\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\stormlib_dll\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\test\*
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\CMakeLists.txt
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\makefile.*
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\Info.plist
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\*.bat
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\*.sln
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\*.vcproj
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%.zip StormLib\*.vcxproj
echo.
echo Press any key to exit ...
diff --git a/Publish_beta.bat b/Publish_beta.bat
index a13ea56..77dc215 100644
--- a/Publish_beta.bat
+++ b/Publish_beta.bat
@@ -2,21 +2,23 @@
rem This BAT file updates the ZIP file that is to be uploaded to web
rem Only use when both 32-bit and 64-bit are properly compiled
-echo Creating stormlib_beta.zip ...
+set STORMLIB_NAME=stormlib-9.00
+
+echo Creating %STORMLIB_NAME%-beta.zip ...
cd \Ladik\Appdir
-zip.exe -ur9 ..\WWW\web\download\stormlib_beta.zip StormLib\doc\*
-zip.exe -ur9 ..\WWW\web\download\stormlib_beta.zip StormLib\src\*
-zip.exe -ur9 ..\WWW\web\download\stormlib_beta.zip StormLib\storm_dll\*
-zip.exe -ur9 ..\WWW\web\download\stormlib_beta.zip StormLib\StormLib.xcodeproj\*
-zip.exe -ur9 ..\WWW\web\download\stormlib_beta.zip StormLib\stormlib_dll\*
-zip.exe -ur9 ..\WWW\web\download\stormlib_beta.zip StormLib\test\*
-zip.exe -u9 ..\WWW\web\download\stormlib_beta.zip StormLib\CMakeLists.txt
-zip.exe -u9 ..\WWW\web\download\stormlib_beta.zip StormLib\makefile.*
-zip.exe -u9 ..\WWW\web\download\stormlib_beta.zip StormLib\Info.plist
-zip.exe -u9 ..\WWW\web\download\stormlib_beta.zip StormLib\*.bat
-zip.exe -u9 ..\WWW\web\download\stormlib_beta.zip StormLib\*.sln
-zip.exe -u9 ..\WWW\web\download\stormlib_beta.zip StormLib\*.vcproj
-zip.exe -u9 ..\WWW\web\download\stormlib_beta.zip StormLib\*.vcxproj
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\doc\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\src\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\storm_dll\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\StormLib.xcodeproj\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\stormlib_dll\*
+zip.exe -ur9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\test\*
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\CMakeLists.txt
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\makefile.*
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\Info.plist
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\*.bat
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\*.sln
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\*.vcproj
+zip.exe -u9 ..\WWW\web\download\%STORMLIB_NAME%-beta.zip StormLib\*.vcxproj
echo.
echo Press any key to exit ...
diff --git a/src/FileStream.cpp b/src/FileStream.cpp
index 81933fd..03a8fea 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)
{
- lseek((intptr_t)pStream->Base.File.hFile, (off_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)
{
- lseek((intptr_t)pStream->Base.File.hFile, (off_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(ftruncate((intptr_t)pStream->Base.File.hFile, (off_t)NewFileSize) == -1)
+ if(ftruncate64((intptr_t)pStream->Base.File.hFile, (__off64_t)NewFileSize) == -1)
{
nLastError = errno;
return false;
@@ -429,7 +429,7 @@ static bool BaseFile_Create(
{
intptr_t handle;
- handle = open(szFileName, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ handle = open(szFileName, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if(handle == -1)
{
nLastError = errno;
@@ -489,12 +489,12 @@ static bool BaseFile_Open(
#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
{
- struct stat fileinfo;
+ struct stat64 fileinfo;
int oflag = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? O_RDONLY : O_RDWR;
intptr_t handle;
// Open the file
- handle = open(szFileName, oflag);
+ handle = open(szFileName, oflag | O_LARGEFILE);
if(handle == -1)
{
nLastError = errno;
@@ -502,7 +502,7 @@ static bool BaseFile_Open(
}
// Get the file size
- if(fstat(handle, &fileinfo) == -1)
+ if(fstat64(handle, &fileinfo) == -1)
{
nLastError = errno;
return false;
@@ -650,7 +650,7 @@ static bool BaseMap_Open(
#endif
#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
- struct stat fileinfo;
+ struct stat64 fileinfo;
intptr_t handle;
bool bResult = false;
@@ -659,7 +659,7 @@ static bool BaseMap_Open(
if(handle != -1)
{
// Get the file size
- if(fstat(handle, &fileinfo) != -1)
+ if(fstat64(handle, &fileinfo) != -1)
{
pStream->Base.Map.pbFile = (LPBYTE)mmap(NULL, (size_t)fileinfo.st_size, PROT_READ, MAP_PRIVATE, handle, 0);
if(pStream->Base.Map.pbFile != NULL)
diff --git a/src/SFileAttributes.cpp b/src/SFileAttributes.cpp
index bca1f66..7f12028 100644
--- a/src/SFileAttributes.cpp
+++ b/src/SFileAttributes.cpp
@@ -41,8 +41,10 @@ static DWORD GetSizeOfAttributesFile(DWORD dwAttrFlags, DWORD dwFileTableSize)
if(dwAttrFlags & MPQ_ATTRIBUTE_MD5)
cbAttrFile += dwFileTableSize * MD5_DIGEST_SIZE;
- // Weird: When there's 1 extra bit in the patch bit array, it's ignored
- // wow-update-13164.MPQ: BlockTableSize = 0x62E1, but there's only 0xC5C bytes
+ // The bit array has been create without the last bit belonging to (attributes)
+ // When the number of files is a multiplier of 8 plus one, then the size of (attributes)
+ // if 1 byte less than expected.
+ // Example: wow-update-13164.MPQ: BlockTableSize = 0x62E1, but there's only 0xC5C bytes
if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
cbAttrFile += (dwFileTableSize + 6) / 8;
@@ -165,7 +167,7 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
LPBYTE pbAttrFile;
LPBYTE pbAttrPtr;
size_t cbAttrFile;
- DWORD dwFinalEntries = ha->dwFileTableSize + ha->dwReservedFiles;
+ DWORD dwFinalEntries = ha->dwFileTableSize + ha->dwReservedFiles + 1;
// Check if we need patch bits in the (attributes) file
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
@@ -202,7 +204,7 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
*pArrayCRC32++ = BSWAP_INT32_UNSIGNED(pFileEntry->dwCrc32);
// Skip the reserved entries
- pbAttrPtr = (LPBYTE)(pArrayCRC32 + ha->dwReservedFiles);
+ pbAttrPtr = (LPBYTE)(pArrayCRC32 + ha->dwReservedFiles + 1);
}
// Write the array of file time
@@ -215,7 +217,7 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
*pArrayFileTime++ = BSWAP_INT64_UNSIGNED(pFileEntry->FileTime);
// Skip the reserved entries
- pbAttrPtr = (LPBYTE)(pArrayFileTime + ha->dwReservedFiles);
+ pbAttrPtr = (LPBYTE)(pArrayFileTime + ha->dwReservedFiles + 1);
}
// Write the array of MD5s
@@ -231,16 +233,15 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
}
// Skip the reserved items
- pbAttrPtr = pbArrayMD5 + (ha->dwReservedFiles * MD5_DIGEST_SIZE);
+ pbAttrPtr = pbArrayMD5 + ((ha->dwReservedFiles + 1) * MD5_DIGEST_SIZE);
}
// Write the array of patch bits
if(ha->dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
{
LPBYTE pbBitArray = pbAttrPtr;
- DWORD dwByteSize = (dwFinalEntries + 7) / 8;
DWORD dwByteIndex = 0;
- DWORD dwBitMask = 0x80;
+ BYTE dwBitMask = 0x80;
// Copy from file table
for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
@@ -254,14 +255,18 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile)
dwBitMask = (dwBitMask << 0x07) | (dwBitMask >> 0x01);
}
+ // Note: Do not increment the array by the last bit that belongs to (attributes).
+ // This might create the array one byte less (if the number of files a multiplier of 8).
+ // Blizzard MPQs have the same feature.
+
// Move past the bit array
- pbAttrPtr = (pbBitArray + dwByteSize);
+ pbAttrPtr = (pbBitArray + dwByteIndex) + ((dwBitMask & 0x7F) ? 1 : 0);
}
// Now we expect that current position matches the estimated size
// Note that if there is 1 extra bit above the byte size,
// the table is actually 1 byte shorted in Blizzard MPQs. See GetSizeOfAttributesFile
- assert((size_t)(pbAttrPtr - pbAttrFile) == cbAttrFile + ((dwFinalEntries & 0x07) == 1) ? 1 : 0);
+ assert((size_t)(pbAttrPtr - pbAttrFile) == cbAttrFile);
}
// Give away the attributes file
@@ -329,18 +334,12 @@ int SAttrFileSaveToMpq(TMPQArchive * ha)
// We expect at least one reserved entry to be there
assert(ha->dwReservedFiles >= 1);
+ ha->dwReservedFiles--;
// Create the raw data that is to be written to (attributes)
// Note: Blizzard MPQs have entries for (listfile) and (attributes),
// but they are filled empty
pbAttrFile = CreateAttributesFile(ha, &cbAttrFile);
-
- // Now we decrement the number of reserved files.
- // This frees one slot in the file table, so the subsequent file create operation should succeed
- // This must happen even if CreateAttributesFile failed
- ha->dwReservedFiles--;
-
- // If we created something, write the attributes to the MPQ
if(pbAttrFile != NULL)
{
// We expect it to be nonzero size
diff --git a/src/SFileGetFileInfo.cpp b/src/SFileGetFileInfo.cpp
index 06c8d6a..a8083dc 100644
--- a/src/SFileGetFileInfo.cpp
+++ b/src/SFileGetFileInfo.cpp
@@ -16,12 +16,13 @@
// Local defines
// Information types for SFileGetFileInfo
-#define SFILE_INFO_TYPE_UNKNOWN 0
-#define SFILE_INFO_TYPE_DIRECT_POINTER 1
-#define SFILE_INFO_TYPE_ALLOCATED 2
-#define SFILE_INFO_TYPE_READ_FROM_FILE 3
-#define SFILE_INFO_TYPE_TABLE_POINTER 4
-#define SFILE_INFO_TYPE_FILE_ENTRY 5
+#define SFILE_INFO_TYPE_INVALID_HANDLE 0
+#define SFILE_INFO_TYPE_NOT_FOUND 1
+#define SFILE_INFO_TYPE_DIRECT_POINTER 2
+#define SFILE_INFO_TYPE_ALLOCATED 3
+#define SFILE_INFO_TYPE_READ_FROM_FILE 4
+#define SFILE_INFO_TYPE_TABLE_POINTER 5
+#define SFILE_INFO_TYPE_FILE_ENTRY 6
//-----------------------------------------------------------------------------
// Local functions
@@ -146,8 +147,8 @@ bool WINAPI SFileGetFileInfo(
void * pvSrcFileInfo = NULL;
DWORD cbSrcFileInfo = 0;
DWORD dwInt32Value = 0;
- int nInfoType = SFILE_INFO_TYPE_UNKNOWN;
- int nError = ERROR_INVALID_PARAMETER;
+ int nInfoType = SFILE_INFO_TYPE_INVALID_HANDLE;
+ int nError = ERROR_SUCCESS;
switch(InfoClass)
{
@@ -163,31 +164,43 @@ bool WINAPI SFileGetFileInfo(
case SFileMpqUserDataOffset:
ha = IsValidMpqHandle(hMpqOrFile);
- if(ha != NULL && ha->pUserData != NULL)
+ if(ha != NULL)
{
- pvSrcFileInfo = &ha->UserDataPos;
- cbSrcFileInfo = sizeof(ULONGLONG);
- nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pUserData != NULL)
+ {
+ pvSrcFileInfo = &ha->UserDataPos;
+ cbSrcFileInfo = sizeof(ULONGLONG);
+ nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ }
}
break;
case SFileMpqUserDataHeader:
ha = IsValidMpqHandle(hMpqOrFile);
- if(ha != NULL && ha->pUserData != NULL)
+ if(ha != NULL)
{
- ByteOffset = ha->UserDataPos;
- cbSrcFileInfo = sizeof(TMPQUserData);
- nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pUserData != NULL)
+ {
+ ByteOffset = ha->UserDataPos;
+ cbSrcFileInfo = sizeof(TMPQUserData);
+ nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE;
+ }
}
break;
case SFileMpqUserData:
ha = IsValidMpqHandle(hMpqOrFile);
- if(ha != NULL && ha->pUserData != NULL)
+ if(ha != NULL)
{
- ByteOffset = ha->UserDataPos + sizeof(TMPQUserData);
- cbSrcFileInfo = ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData);
- nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pUserData != NULL)
+ {
+ ByteOffset = ha->UserDataPos + sizeof(TMPQUserData);
+ cbSrcFileInfo = ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData);
+ nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE;
+ }
}
break;
@@ -245,9 +258,13 @@ bool WINAPI SFileGetFileInfo(
ha = IsValidMpqHandle(hMpqOrFile);
if(ha != NULL)
{
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->HetTablePos64, (size_t)ha->pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE);
- cbSrcFileInfo = sizeof(TMPQHetHeader);
- nInfoType = SFILE_INFO_TYPE_ALLOCATED;
+ if(pvSrcFileInfo != NULL)
+ {
+ cbSrcFileInfo = sizeof(TMPQHetHeader);
+ nInfoType = SFILE_INFO_TYPE_ALLOCATED;
+ }
}
break;
@@ -255,9 +272,13 @@ bool WINAPI SFileGetFileInfo(
ha = IsValidMpqHandle(hMpqOrFile);
if(ha != NULL)
{
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
pvSrcFileInfo = LoadHetTable(ha);
- cbSrcFileInfo = sizeof(void *);
- nInfoType = SFILE_INFO_TYPE_TABLE_POINTER;
+ if(pvSrcFileInfo != NULL)
+ {
+ cbSrcFileInfo = sizeof(void *);
+ nInfoType = SFILE_INFO_TYPE_TABLE_POINTER;
+ }
}
break;
@@ -285,6 +306,7 @@ bool WINAPI SFileGetFileInfo(
ha = IsValidMpqHandle(hMpqOrFile);
if(ha != NULL)
{
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->BetTablePos64, (size_t)ha->pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE);
if(pvSrcFileInfo != NULL)
{
@@ -301,9 +323,13 @@ bool WINAPI SFileGetFileInfo(
ha = IsValidMpqHandle(hMpqOrFile);
if(ha != NULL)
{
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
pvSrcFileInfo = LoadBetTable(ha);
- cbSrcFileInfo = sizeof(void *);
- nInfoType = SFILE_INFO_TYPE_TABLE_POINTER;
+ if(pvSrcFileInfo != NULL)
+ {
+ cbSrcFileInfo = sizeof(void *);
+ nInfoType = SFILE_INFO_TYPE_TABLE_POINTER;
+ }
}
break;
@@ -342,9 +368,13 @@ bool WINAPI SFileGetFileInfo(
ha = IsValidMpqHandle(hMpqOrFile);
if(ha != NULL)
{
- cbSrcFileInfo = ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
- pvSrcFileInfo = ha->pHashTable;
- nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pHashTable != NULL)
+ {
+ pvSrcFileInfo = ha->pHashTable;
+ cbSrcFileInfo = ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
+ nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ }
}
break;
@@ -383,10 +413,14 @@ bool WINAPI SFileGetFileInfo(
ha = IsValidMpqHandle(hMpqOrFile);
if(ha != NULL)
{
- cbSrcFileInfo = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
- if(cbFileInfo >= cbSrcFileInfo)
- pvSrcFileInfo = LoadBlockTable(ha, true);
- nInfoType = SFILE_INFO_TYPE_ALLOCATED;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos) != 0)
+ {
+ cbSrcFileInfo = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
+ if(cbFileInfo >= cbSrcFileInfo)
+ pvSrcFileInfo = LoadBlockTable(ha, true);
+ nInfoType = SFILE_INFO_TYPE_ALLOCATED;
+ }
}
break;
@@ -411,7 +445,15 @@ bool WINAPI SFileGetFileInfo(
break;
case SFileMpqHiBlockTable:
- assert(false);
+ ha = IsValidMpqHandle(hMpqOrFile);
+ if(ha != NULL)
+ {
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pHeader->HiBlockTablePos64 && ha->pHeader->HiBlockTableSize64)
+ {
+ assert(false);
+ }
+ }
break;
case SFileMpqSignatures:
@@ -426,10 +468,10 @@ bool WINAPI SFileGetFileInfo(
case SFileMpqStrongSignatureOffset:
ha = IsValidMpqHandle(hMpqOrFile);
- if(ha != NULL && QueryMpqSignatureInfo(ha, &SignatureInfo))
+ if(ha != NULL)
{
- // Is a strong signature present?
- if(SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG))
{
pvSrcFileInfo = &SignatureInfo.EndMpqData;
cbSrcFileInfo = sizeof(ULONGLONG);
@@ -440,10 +482,10 @@ bool WINAPI SFileGetFileInfo(
case SFileMpqStrongSignatureSize:
ha = IsValidMpqHandle(hMpqOrFile);
- if(ha != NULL && QueryMpqSignatureInfo(ha, &SignatureInfo))
+ if(ha != NULL)
{
- // Is a strong signature present?
- if(SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG))
{
dwInt32Value = MPQ_STRONG_SIGNATURE_SIZE + 4;
pvSrcFileInfo = &dwInt32Value;
@@ -455,10 +497,10 @@ bool WINAPI SFileGetFileInfo(
case SFileMpqStrongSignature:
ha = IsValidMpqHandle(hMpqOrFile);
- if(ha != NULL && QueryMpqSignatureInfo(ha, &SignatureInfo))
+ if(ha != NULL)
{
- // Is a strong signature present?
- if(SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG))
{
pvSrcFileInfo = SignatureInfo.Signature;
cbSrcFileInfo = MPQ_STRONG_SIGNATURE_SIZE + 4;
@@ -469,22 +511,30 @@ bool WINAPI SFileGetFileInfo(
case SFileMpqBitmapOffset:
ha = IsValidMpqHandle(hMpqOrFile);
- if(ha != NULL && ha->pBitmap != NULL)
+ if(ha != NULL)
{
- Int64Value = MAKE_OFFSET64(ha->pBitmap->dwMapOffsetHi, ha->pBitmap->dwMapOffsetLo);
- pvSrcFileInfo = &Int64Value;
- cbSrcFileInfo = sizeof(ULONGLONG);
- nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pBitmap != NULL)
+ {
+ Int64Value = MAKE_OFFSET64(ha->pBitmap->dwMapOffsetHi, ha->pBitmap->dwMapOffsetLo);
+ pvSrcFileInfo = &Int64Value;
+ cbSrcFileInfo = sizeof(ULONGLONG);
+ nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ }
}
break;
case SFileMpqBitmapSize:
ha = IsValidMpqHandle(hMpqOrFile);
- if(ha != NULL && ha->pBitmap != NULL)
+ if(ha != NULL)
{
- pvSrcFileInfo = &ha->dwBitmapSize;
- cbSrcFileInfo = sizeof(DWORD);
- nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pBitmap != NULL)
+ {
+ pvSrcFileInfo = &ha->dwBitmapSize;
+ cbSrcFileInfo = sizeof(DWORD);
+ nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ }
}
break;
@@ -492,9 +542,13 @@ bool WINAPI SFileGetFileInfo(
ha = IsValidMpqHandle(hMpqOrFile);
if(ha != NULL)
{
- pvSrcFileInfo = ha->pBitmap;
- cbSrcFileInfo = ha->dwBitmapSize;
- nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pBitmap != NULL)
+ {
+ pvSrcFileInfo = ha->pBitmap;
+ cbSrcFileInfo = ha->dwBitmapSize;
+ nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ }
}
break;
@@ -563,9 +617,13 @@ bool WINAPI SFileGetFileInfo(
ha = IsValidMpqHandle(hMpqOrFile);
if(ha != NULL)
{
- pvSrcFileInfo = &ha->pHeader->dwRawChunkSize;
- cbSrcFileInfo = sizeof(DWORD);
- nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ nInfoType = SFILE_INFO_TYPE_NOT_FOUND;
+ if(ha->pHeader->dwRawChunkSize != 0)
+ {
+ pvSrcFileInfo = &ha->pHeader->dwRawChunkSize;
+ cbSrcFileInfo = sizeof(DWORD);
+ nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ }
}
break;
@@ -760,7 +818,7 @@ bool WINAPI SFileGetFileInfo(
}
// If we validated the handle and info class, give as much info as possible
- if(nInfoType != SFILE_INFO_TYPE_UNKNOWN)
+ if(nInfoType >= SFILE_INFO_TYPE_DIRECT_POINTER)
{
// Give the length needed, if wanted
if(pcbLengthNeeded != NULL)
@@ -777,24 +835,21 @@ bool WINAPI SFileGetFileInfo(
case SFILE_INFO_TYPE_DIRECT_POINTER:
case SFILE_INFO_TYPE_ALLOCATED:
memcpy(pvFileInfo, pvSrcFileInfo, cbSrcFileInfo);
- nError = ERROR_SUCCESS;
break;
case SFILE_INFO_TYPE_READ_FROM_FILE:
- if(FileStream_Read(ha->pStream, &ByteOffset, pvFileInfo, cbSrcFileInfo))
- nError = ERROR_SUCCESS;
+ if(!FileStream_Read(ha->pStream, &ByteOffset, pvFileInfo, cbSrcFileInfo))
+ nError = GetLastError();
break;
case SFILE_INFO_TYPE_TABLE_POINTER:
*(void **)pvFileInfo = pvSrcFileInfo;
pvSrcFileInfo = NULL;
- nError = ERROR_SUCCESS;
break;
case SFILE_INFO_TYPE_FILE_ENTRY:
assert(pFileEntry != NULL);
ConvertFileEntryToSelfRelative((TFileEntry *)pvFileInfo, pFileEntry);
- nError = ERROR_SUCCESS;
break;
}
}
@@ -803,10 +858,6 @@ bool WINAPI SFileGetFileInfo(
nError = ERROR_INSUFFICIENT_BUFFER;
}
}
- else
- {
- nError = ERROR_SUCCESS;
- }
// Free the file info if needed
if(nInfoType == SFILE_INFO_TYPE_ALLOCATED && pvSrcFileInfo != NULL)
@@ -814,6 +865,14 @@ bool WINAPI SFileGetFileInfo(
if(nInfoType == SFILE_INFO_TYPE_TABLE_POINTER && pvSrcFileInfo != NULL)
SFileFreeFileInfo(pvSrcFileInfo, InfoClass);
}
+ else
+ {
+ // Handle error cases
+ if(nInfoType == SFILE_INFO_TYPE_INVALID_HANDLE)
+ nError = ERROR_INVALID_HANDLE;
+ if(nInfoType == SFILE_INFO_TYPE_NOT_FOUND)
+ nError = ERROR_FILE_NOT_FOUND;
+ }
// Set the last error value, if needed
if(nError != ERROR_SUCCESS)
diff --git a/src/SFileListFile.cpp b/src/SFileListFile.cpp
index f98c92b..896b341 100644
--- a/src/SFileListFile.cpp
+++ b/src/SFileListFile.cpp
@@ -382,19 +382,13 @@ int SListFileSaveToMpq(TMPQArchive * ha)
// At this point, we expect to have at least one reserved entry in the file table
assert(ha->dwReservedFiles >= 1);
+ ha->dwReservedFiles--;
// Create the raw data that is to be written to (listfile)
// Note: Creating the raw data before the (listfile) has been created in the MPQ
// causes that the name of the listfile will not be included in the listfile itself.
// That is OK, because (listfile) in Blizzard MPQs does not contain it either.
pbListFile = CreateListFile(ha, &cbListFile);
-
- // Now we decrement the number of reserved files.
- // This frees one slot in the file table, so the subsequent file create operation should succeed
- // This must happen even if the listfile cannot be created
- ha->dwReservedFiles--;
-
- // If the listfile create succeeded, we write it to the MPQ
if(pbListFile != NULL)
{
// We expect it to be nonzero size
diff --git a/src/StormLib.h b/src/StormLib.h
index ce65f7f..3659c23 100644
--- a/src/StormLib.h
+++ b/src/StormLib.h
@@ -413,7 +413,7 @@ typedef enum _SFileInfoClass
SFileInfoNameHash2, // The second name hash in the hash table (DWORD)
SFileInfoNameHash3, // 64-bit file name hash for the HET/BET tables (ULONGLONG)
SFileInfoLocale, // File locale (DWORD)
- SFileInfoFileIndex, // Block index (DWORD)
+ SFileInfoFileIndex, // Block index (DWORD)
SFileInfoByteOffset, // File position in the archive (ULONGLONG)
SFileInfoFileTime, // File time (ULONGLONG)
SFileInfoFileSize, // Size of the file (DWORD)
diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp
index bd1bd56..127ce77 100644
--- a/test/TLogHelper.cpp
+++ b/test/TLogHelper.cpp
@@ -41,6 +41,10 @@ class TLogHelper
protected:
+#if defined(UNICODE) || defined(UNICODE)
+ TCHAR * CopyFormatCharacter(TCHAR * szBuffer, const TCHAR *& szFormat);
+#endif
+ char * CopyFormatCharacter(char * szBuffer, const char *& szFormat);
int GetConsoleWidth();
const char * szMainTitle; // Title of the text (usually name)
@@ -50,6 +54,17 @@ class TLogHelper
};
//-----------------------------------------------------------------------------
+// String replacements for format strings
+
+#ifdef _MSC_VER
+#define I64u_t _T("%I64u");
+#define I64u_a "%I64u";
+#else
+#define I64u_t "%llu";
+#define I64u_a "%llu";
+#endif
+
+//-----------------------------------------------------------------------------
// Constructor and destructor
TLogHelper::TLogHelper(const char * szNewTestTitle, const char * szNewSubTitle)
@@ -124,21 +139,8 @@ int TLogHelper::PrintWithClreol(const TCHAR * szFormat, va_list argList, bool bP
// Copy the message format itself. Replace %s with "%s", unless it's (%s)
if(szFormat != NULL)
{
- while(szFormat[0] != 0)
- {
- if(szFormat[0] == '%' && szFormat[1] == 's' && szFormat[2] != ')')
- {
- *szBuffer++ = '\"';
- *szBuffer++ = '%';
- *szBuffer++ = 's';
- *szBuffer++ = '\"';
- szFormat += 2;
- }
- else
- {
- *szBuffer++ = *szFormat++;
- }
- }
+ szBuffer = CopyFormatCharacter(szBuffer, szFormat);
+ szFormat += nLength;
}
// Append the last error
@@ -235,18 +237,7 @@ int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPr
{
while(szFormat[0] != 0)
{
- if(szFormat[0] == '%' && szFormat[1] == 's' && szFormat[2] != ')')
- {
- *szBuffer++ = '\"';
- *szBuffer++ = '%';
- *szBuffer++ = 's';
- *szBuffer++ = '\"';
- szFormat += 2;
- }
- else
- {
- *szBuffer++ = *szFormat++;
- }
+ szBuffer = CopyFormatCharacter(szBuffer, szFormat);
}
}
@@ -324,6 +315,66 @@ int TLogHelper::PrintError(const char * szFormat, const char * szFileName)
//-----------------------------------------------------------------------------
// Protected functions
+#ifdef _UNICODE
+TCHAR * TLogHelper::CopyFormatCharacter(TCHAR * szBuffer, const TCHAR *& szFormat)
+{
+ static const TCHAR * szStringFormat = _T("\"%s\"");
+ static const TCHAR * szUint64Format = I64u_t;
+
+ // String format
+ if(szFormat[0] == '%')
+ {
+ if(szFormat[1] == 's' && szFormat[2] != ')')
+ {
+ _tcscpy(szBuffer, szStringFormat);
+ szFormat += 2;
+ return szBuffer + _tcslen(szStringFormat);
+ }
+
+ // Replace %I64u with the proper platform-dependent suffix
+ if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u')
+ {
+ _tcscpy(szBuffer, szUint64Format);
+ szFormat += 5;
+ return szBuffer + _tcslen(szUint64Format);
+ }
+ }
+
+ // Copy the character as-is
+ *szBuffer++ = *szFormat++;
+ return szBuffer;
+}
+#endif
+
+char * TLogHelper::CopyFormatCharacter(char * szBuffer, const char *& szFormat)
+{
+ static const char * szStringFormat = "\"%s\"";
+ static const char * szUint64Format = I64u_a;
+
+ // String format
+ if(szFormat[0] == '%')
+ {
+ if(szFormat[1] == 's' && szFormat[2] != ')')
+ {
+ strcpy(szBuffer, szStringFormat);
+ szFormat += 2;
+ return szBuffer + strlen(szStringFormat);
+ }
+
+ // Replace %I64u with the proper platform-dependent suffix
+ if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u')
+ {
+ strcpy(szBuffer, szUint64Format);
+ szFormat += 5;
+ return szBuffer + strlen(szUint64Format);
+ }
+ }
+
+ // Copy the character as-is
+ *szBuffer++ = *szFormat++;
+ return szBuffer;
+}
+
int TLogHelper::GetConsoleWidth()
{
#ifdef PLATFORM_WINDOWS
@@ -336,7 +387,7 @@ int TLogHelper::GetConsoleWidth()
// On non-Windows platforms, we assume that width of the console line
// is 80 characters
- return 80;
+ return 120;
#endif
}
diff --git a/test/Test.cpp b/test/Test.cpp
index 41a310b..bb5fc38 100644
--- a/test/Test.cpp
+++ b/test/Test.cpp
@@ -219,7 +219,7 @@ static void CreateFullPathName(TCHAR * szBuffer, const char * szSubDir, const ch
// Append the subdirectory, if any
if(szSubDir != NULL && (nLength = strlen(szSubDir)) != 0)
{
- // No leading or trailing separator must be there
+ // No leading or trailing separators allowed
assert(szSubDir[0] != '/' && szSubDir[0] != '\\');
assert(szSubDir[nLength - 1] != '/' && szSubDir[nLength - 1] != '\\');
@@ -228,6 +228,12 @@ static void CreateFullPathName(TCHAR * szBuffer, const char * szSubDir, const ch
// Copy the subdirectory
mbstowcs(szBuffer, szSubDir, nLength);
+
+ // Fix the path separators
+ for(size_t i = 0; i < nLength; i++)
+ szBuffer[i] = (szBuffer[i] != '\\' && szBuffer[i] != '/') ? szBuffer[i] : PATH_SEPARATOR;
+
+ // Move the buffer pointer
szBuffer += nLength;
}
@@ -241,7 +247,7 @@ static void CreateFullPathName(TCHAR * szBuffer, const char * szSubDir, const ch
// Append file path separator
*szBuffer++ = PATH_SEPARATOR;
- // Copy the subdirectory
+ // Copy the file name
mbstowcs(szBuffer, szFileName, nLength);
szBuffer += nLength;
}
@@ -309,6 +315,12 @@ static void CreateFullPathName(char * szBuffer, const char * szSubDir, const cha
// Copy the subdirectory
memcpy(szBuffer, szSubDir, nLength);
+
+ // Fix the path separators
+ for(size_t i = 0; i < nLength; i++)
+ szBuffer[i] = (szBuffer[i] != '\\' && szBuffer[i] != '/') ? szBuffer[i] : PATH_SEPARATOR;
+
+ // Move the buffer pointer
szBuffer += nLength;
}
@@ -322,7 +334,7 @@ static void CreateFullPathName(char * szBuffer, const char * szSubDir, const cha
// Append file path separator
*szBuffer++ = PATH_SEPARATOR;
- // Copy the subdirectory
+ // Copy file name
memcpy(szBuffer, szFileName, nLength);
szBuffer += nLength;
}
@@ -1045,7 +1057,7 @@ static int OpenExistingArchive(TLogHelper * pLogger, const char * szFileName, co
TCHAR szMpqName[MAX_PATH];
HANDLE hMpq = NULL;
DWORD dwFlags = 0;
- int nError;
+ int nError = ERROR_SUCCESS;
// We expect MPQ directory to be already prepared by InitializeMpqDirectory
assert(szMpqDirectory[0] != 0);
@@ -1088,7 +1100,7 @@ static int OpenExistingArchive(TLogHelper * pLogger, const char * szFileName, co
SFileCloseArchive(hMpq);
else
*phMpq = hMpq;
- return ERROR_SUCCESS;
+ return nError;
}
static int OpenPatchedArchive(TLogHelper * pLogger, HANDLE * phMpq, const char * PatchList[])
@@ -1126,7 +1138,7 @@ static int OpenPatchedArchive(TLogHelper * pLogger, HANDLE * phMpq, const char *
SFileCloseArchive(hMpq);
else
*phMpq = hMpq;
- return ERROR_SUCCESS;
+ return nError;
}
static int AddFileToMpq(
@@ -1648,6 +1660,7 @@ static int TestOpenArchive_ReadOnly(const char * szPlainName, bool bReadOnly)
static int TestOpenArchive_GetFileInfo(const char * szPlainName1, const char * szPlainName4)
{
TLogHelper Logger("GetFileInfoTest");
+ HANDLE hFile;
HANDLE hMpq4;
HANDLE hMpq1;
DWORD cbLength;
@@ -1660,12 +1673,18 @@ static int TestOpenArchive_GetFileInfo(const char * szPlainName1, const char * s
nError4 = OpenExistingArchive(&Logger, szPlainName4, NULL, &hMpq4);
if(nError1 == ERROR_SUCCESS && nError4 == ERROR_SUCCESS)
{
- // Invalid handle - expected (false, ERROR_INVALID_PARAMETER)
- TestGetFileInfo(&Logger, NULL, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_INVALID_PARAMETER);
+ // Invalid handle - expected (false, ERROR_INVALID_HANDLE)
+ TestGetFileInfo(&Logger, NULL, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_INVALID_HANDLE);
+
+ // Valid handle but invalid value of file info class (false, ERROR_INVALID_PARAMETER)
+ TestGetFileInfo(&Logger, NULL, (SFileInfoClass)0xFFF, NULL, 0, NULL, false, ERROR_INVALID_PARAMETER);
+
+ // Valid archive handle but file info class is for file (false, ERROR_INVALID_HANDLE)
+ TestGetFileInfo(&Logger, NULL, SFileInfoNameHash1, NULL, 0, NULL, false, ERROR_INVALID_HANDLE);
// Valid handle and all parameters NULL
// Returns (true, ERROR_SUCCESS), if BET table is present, otherwise (false, ERROR_CAN_NOT_COMPLETE)
- TestGetFileInfo(&Logger, hMpq1, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_INVALID_PARAMETER);
+ TestGetFileInfo(&Logger, hMpq1, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_FILE_NOT_FOUND);
TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, NULL, true, ERROR_SUCCESS);
// Now try to retrieve the required size of the BET table header
@@ -1685,7 +1704,7 @@ static int TestOpenArchive_GetFileInfo(const char * szPlainName1, const char * s
// Try to retrieve strong signature from the MPQ
TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, NULL, true, ERROR_SUCCESS);
- TestGetFileInfo(&Logger, hMpq4, SFileMpqStrongSignature, NULL, 0, NULL, false, ERROR_INVALID_PARAMETER);
+ TestGetFileInfo(&Logger, hMpq4, SFileMpqStrongSignature, NULL, 0, NULL, false, ERROR_FILE_NOT_FOUND);
// Strong signature is returned including the signature ID
TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, &cbLength, true, ERROR_SUCCESS);
@@ -1694,6 +1713,18 @@ static int TestOpenArchive_GetFileInfo(const char * szPlainName1, const char * s
// Retrieve the signature
TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, DataBuff, sizeof(DataBuff), &cbLength, true, ERROR_SUCCESS);
assert(memcmp(DataBuff, "NGIS", 4) == 0);
+
+ // Check SFileGetFileInfo on
+ if(SFileOpenFileEx(hMpq4, LISTFILE_NAME, 0, &hFile))
+ {
+ // Valid parameters but the handle should be file handle
+ TestGetFileInfo(&Logger, hMpq4, SFileInfoFileTime, DataBuff, sizeof(DataBuff), &cbLength, false, ERROR_INVALID_HANDLE);
+
+ // Valid parameters
+ TestGetFileInfo(&Logger, hFile, SFileInfoFileTime, DataBuff, sizeof(DataBuff), &cbLength, true, ERROR_SUCCESS);
+
+ SFileCloseFile(hFile);
+ }
}
if(hMpq4 != NULL)