From f438d59c5c10c9d2308ac1bfaff8da54bdbb8c4f Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 26 Aug 2020 10:17:05 +0200 Subject: * Removed sprintf as source of incompatibilities * Fixed bug --- src/FileStream.cpp | 28 ++++++++++++++++++++++------ src/SBaseCommon.cpp | 28 ++++++++++++++++++++++++++-- src/SFileFindFile.cpp | 2 +- src/SFileGetFileInfo.cpp | 5 ++--- src/StormCommon.h | 40 +++++++++++++++++++++++++++++++++++++++- test/StormTest.cpp | 13 ++++++++----- 6 files changed, 98 insertions(+), 18 deletions(-) diff --git a/src/FileStream.cpp b/src/FileStream.cpp index a492e66..a462690 100644 --- a/src/FileStream.cpp +++ b/src/FileStream.cpp @@ -53,13 +53,29 @@ static DWORD StringToInt(const char * szString) while('0' <= szString[0] && szString[0] <= '9') { - dwValue = (dwValue * 10) + (szString[0] - '9'); + dwValue = (dwValue * 10) + (szString[0] - '0'); szString++; } return dwValue; } +static void CreateNameWithSuffix(LPTSTR szBuffer, size_t cchMaxChars, LPCTSTR szName, unsigned int nValue) +{ + LPTSTR szBufferEnd = szBuffer + cchMaxChars - 1; + + // Copy the name + while(szBuffer < szBufferEnd && szName[0] != 0) + *szBuffer++ = *szName++; + + // Append "." + if(szBuffer < szBufferEnd) + *szBuffer++ = '.'; + + // Append the number + IntToString(szBuffer, szBufferEnd - szBuffer + 1, nValue); +} + //----------------------------------------------------------------------------- // Dummy init function @@ -800,7 +816,7 @@ static bool BaseHttp_Read( { // Add range request to the HTTP headers // http://www.clevercomponents.com/articles/article015/resuming.asp - _stprintf(szRangeRequest, _T("Range: bytes=%u-%u"), (unsigned int)dwStartOffset, (unsigned int)dwEndOffset); + wsprintf(szRangeRequest, _T("Range: bytes=%u-%u"), (unsigned int)dwStartOffset, (unsigned int)dwEndOffset); HttpAddRequestHeaders(hRequest, szRangeRequest, 0xFFFFFFFF, HTTP_ADDREQ_FLAG_ADD_IF_NEW); // Send the request to the server @@ -1738,7 +1754,7 @@ static void PartStream_Close(TBlockStream * pStream) // Make sure that the header is properly BSWAPed BSWAP_ARRAY32_UNSIGNED(&PartHeader, sizeof(PART_FILE_HEADER)); - sprintf(PartHeader.GameBuildNumber, "%u", (unsigned int)pStream->BuildNumber); + IntToString(PartHeader.GameBuildNumber, _countof(PartHeader.GameBuildNumber), pStream->BuildNumber); // Write the part header pStream->BaseWrite(pStream, &ByteOffset, &PartHeader, sizeof(PART_FILE_HEADER)); @@ -2323,7 +2339,7 @@ static TFileStream * Block4Stream_Open(const TCHAR * szFileName, DWORD dwStreamF for(int nSuffix = 0; nSuffix < 30; nSuffix++) { // Open the n-th file - _stprintf(szNameBuff, _T("%s.%u"), pStream->szFileName, nSuffix); + CreateNameWithSuffix(szNameBuff, nNameLength + 4, pStream->szFileName, nSuffix); if(!pStream->BaseOpen(pStream, szNameBuff, dwBaseFlags)) break; @@ -2887,10 +2903,10 @@ void FileStream_Close(TFileStream * pStream) FileStream_Close(pStream->pMaster); pStream->pMaster = NULL; - // Close the stream provider ... + // Close the stream provider if(pStream->StreamClose != NULL) pStream->StreamClose(pStream); - + // ... or close base stream, if any else if(pStream->BaseClose != NULL) pStream->BaseClose(pStream); diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index 61e7bdb..fc80dee 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -95,11 +95,13 @@ unsigned char AsciiToUpperTable_Slash[256] = //----------------------------------------------------------------------------- // Safe string functions (for ANSI builds) -void StringCopy(char * szTarget, size_t cchTarget, const char * szSource) +char * StringCopy(char * szTarget, size_t cchTarget, const char * szSource) { + size_t cchSource = 0; + if(cchTarget > 0) { - size_t cchSource = strlen(szSource); + cchSource = strlen(szSource); if(cchSource >= cchTarget) cchSource = cchTarget - 1; @@ -107,6 +109,8 @@ void StringCopy(char * szTarget, size_t cchTarget, const char * szSource) memcpy(szTarget, szSource, cchSource); szTarget[cchSource] = 0; } + + return szTarget + cchSource; } void StringCat(char * szTarget, size_t cchTargetMax, const char * szSource) @@ -121,6 +125,26 @@ void StringCat(char * szTarget, size_t cchTargetMax, const char * szSource) } } +void StringCreatePseudoFileName(char * szBuffer, size_t cchMaxChars, unsigned int nIndex, const char * szExtension) +{ + char * szBufferEnd = szBuffer + cchMaxChars; + + // "File" + szBuffer = StringCopy(szBuffer, (szBufferEnd - szBuffer), "File"); + + // Number + szBuffer = IntToString(szBuffer, szBufferEnd - szBuffer + 1, nIndex, 8); + + // Dot + if(szBuffer < szBufferEnd) + *szBuffer++ = '.'; + + // Extension + while(szExtension[0] == '.') + szExtension++; + StringCopy(szBuffer, (szBufferEnd - szBuffer), szExtension); +} + //----------------------------------------------------------------------------- // Utility functions (UNICODE) only exist in the ANSI version of the library // In ANSI builds, TCHAR = char, so we don't need these functions implemented diff --git a/src/SFileFindFile.cpp b/src/SFileFindFile.cpp index 30be19a..7e8502b 100644 --- a/src/SFileFindFile.cpp +++ b/src/SFileFindFile.cpp @@ -244,7 +244,7 @@ static bool DoMPQSearch_FileEntry( if(szFileName == NULL) { // Open the file by its pseudo-name. - sprintf(szNameBuff, "File%08u.xxx", (unsigned int)dwBlockIndex); + StringCreatePseudoFileName(szNameBuff, _countof(szNameBuff), dwBlockIndex, "xxx"); if(SFileOpenFileEx((HANDLE)hs->ha, szNameBuff, SFILE_OPEN_BASE_FILE, &hFile)) { SFileGetFileName(hFile, szNameBuff); diff --git a/src/SFileGetFileInfo.cpp b/src/SFileGetFileInfo.cpp index 8d57f7a..c57b3b7 100644 --- a/src/SFileGetFileInfo.cpp +++ b/src/SFileGetFileInfo.cpp @@ -926,6 +926,7 @@ static int CreatePseudoFileName(HANDLE hFile, TFileEntry * pFileEntry, char * sz DWORD FirstBytes[2] = {0, 0}; // The first 4 bytes of the file DWORD dwBytesRead = 0; DWORD dwFilePos; // Saved file position + char szPseudoName[20]; // Read the first 2 DWORDs bytes from the file dwFilePos = SFileSetFilePointer(hFile, 0, NULL, FILE_CURRENT); @@ -944,10 +945,8 @@ static int CreatePseudoFileName(HANDLE hFile, TFileEntry * pFileEntry, char * sz if((FirstBytes[0] & data2ext[i].dwOffset00Mask) == data2ext[i].dwOffset00Data && (FirstBytes[1] & data2ext[i].dwOffset04Mask) == data2ext[i].dwOffset04Data) { - char szPseudoName[20] = ""; - // Format the pseudo-name - sprintf(szPseudoName, "File%08u.%s", (unsigned int)(pFileEntry - hf->ha->pFileTable), data2ext[i].szExt); + StringCreatePseudoFileName(szPseudoName, _countof(szPseudoName), (unsigned int)(pFileEntry - hf->ha->pFileTable), data2ext[i].szExt); // Save the pseudo-name in the file entry as well AllocateFileName(hf->ha, pFileEntry, szPseudoName); diff --git a/src/StormCommon.h b/src/StormCommon.h index de88357..f622e02 100644 --- a/src/StormCommon.h +++ b/src/StormCommon.h @@ -133,8 +133,46 @@ extern unsigned char AsciiToUpperTable[256]; //----------------------------------------------------------------------------- // Safe string functions -void StringCopy(char * szTarget, size_t cchTarget, const char * szSource); +template +XCHAR * IntToString(XCHAR * szBuffer, size_t cchMaxChars, XINT nValue, size_t nDigitCount = 0) +{ + XCHAR * szBufferEnd = szBuffer + cchMaxChars - 1; + XCHAR szNumberRev[0x20]; + size_t nLength = 0; + + // Always put the first digit + szNumberRev[nLength++] = (nValue % 10) + '0'; + nValue /= 10; + + // Continue as long as we have non-zero + while(nValue != 0) + { + szNumberRev[nLength++] = (nValue % 10) + '0'; + nValue /= 10; + } + + // Fill zeros, if needed + while(szBuffer < szBufferEnd && nLength < nDigitCount) + { + *szBuffer++ = '0'; + nDigitCount--; + } + + // Fill the buffer + while(szBuffer < szBufferEnd && nLength > 0) + { + nLength--; + *szBuffer++ = szNumberRev[nLength]; + } + + // Terminate the number with zeros + szBuffer[0] = 0; + return szBuffer; +} + +char * StringCopy(char * szTarget, size_t cchTarget, const char * szSource); void StringCat(char * szTarget, size_t cchTargetMax, const char * szSource); +void StringCreatePseudoFileName(char * szBuffer, size_t cchMaxChars, unsigned int nIndex, const char * szExtension); #ifdef _UNICODE void StringCopy(TCHAR * szTarget, size_t cchTarget, const char * szSource); diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 9766fd0..6732ed0 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -1559,8 +1559,8 @@ static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileN pLogger->PrintProgress("Loading file %s ...", GetShortPlainName(szFileName)); #if defined(_MSC_VER) && defined(_DEBUG) - if(!_stricmp(szFileName, "File00000733.wav")) - __debugbreak(); +// if(!_stricmp(szFileName, "File00000733.wav")) +// __debugbreak(); #endif // Make sure that we open the proper locale file @@ -4409,6 +4409,9 @@ int _tmain(int argc, TCHAR * argv[]) printf("==== Test Suite for StormLib version %s ====\n", STORMLIB_VERSION_STRING); nError = InitializeMpqDirectory(argv, argc); + HANDLE hMpq = NULL; + SFileOpenArchive(_T("e:\\Multimedia\\MPQs\\2010 - Starcraft II\\25092\\Updates\\enGB\\s2-update-enGB-24540.MPQ"), 0, 0, &hMpq); + // Not a test, but rather a tool for creating links to duplicated files // if(nError == ERROR_SUCCESS) // nError = FindFilePairs(ForEachFile_CreateArchiveLink, "2004 - WoW\\06080", "2004 - WoW\\06299"); @@ -4656,8 +4659,8 @@ int _tmain(int argc, TCHAR * argv[]) */ // Test on an archive that has two fake headers before the real one if (nError == ERROR_SUCCESS) - nError = TestOpenArchive_Corrupt(_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod")); -/* + nError = TestOpenArchive(_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod")); + // Open a patched archive if(nError == ERROR_SUCCESS) nError = TestOpenArchive_Patched(PatchList_StarCraft, "music\\terran1.wav", 0); @@ -4852,7 +4855,7 @@ int _tmain(int argc, TCHAR * argv[]) // Test replacing a file with zero size file if(nError == ERROR_SUCCESS) nError = TestModifyArchive_ReplaceFile(_T("MPQ_2014_v4_Base.StormReplay"), _T("AddFile-replay.message.events")); -*/ + #ifdef _MSC_VER _CrtDumpMemoryLeaks(); #endif // _MSC_VER -- cgit v1.2.3