diff options
-rw-r--r-- | Publish.bat | 30 | ||||
-rw-r--r-- | Publish_beta.bat | 30 | ||||
-rw-r--r-- | src/FileStream.cpp | 18 | ||||
-rw-r--r-- | src/SFileAttributes.cpp | 33 | ||||
-rw-r--r-- | src/SFileGetFileInfo.cpp | 195 | ||||
-rw-r--r-- | src/SFileListFile.cpp | 8 | ||||
-rw-r--r-- | src/StormLib.h | 2 | ||||
-rw-r--r-- | test/TLogHelper.cpp | 107 | ||||
-rw-r--r-- | test/Test.cpp | 51 |
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) |