summaryrefslogtreecommitdiff
path: root/StormLib/src/SFileOpenArchive.cpp
diff options
context:
space:
mode:
authorbriaguya <70942617+briaguya-ai@users.noreply.github.com>2022-11-14 05:22:34 -0500
committerGitHub <noreply@github.com>2022-11-14 11:22:34 +0100
commit3914781ebfd5cb22717cc207cb3d37d8754d0eb7 (patch)
tree2e412b87e66b1deef47bef242e7189a200cea0ff /StormLib/src/SFileOpenArchive.cpp
parent9eb29ed81cb497a6a216811255f8af7daf3f8bd8 (diff)
Import libultraship as a submodule (#1943)
Co-authored-by: briaguya <briaguya> Co-authored-by: Christopher Leggett <chris@leggett.dev> Co-authored-by: David Chavez <davi@dcvz.io>
Diffstat (limited to 'StormLib/src/SFileOpenArchive.cpp')
-rw-r--r--StormLib/src/SFileOpenArchive.cpp658
1 files changed, 0 insertions, 658 deletions
diff --git a/StormLib/src/SFileOpenArchive.cpp b/StormLib/src/SFileOpenArchive.cpp
deleted file mode 100644
index ea298500e..000000000
--- a/StormLib/src/SFileOpenArchive.cpp
+++ /dev/null
@@ -1,658 +0,0 @@
-/*****************************************************************************/
-/* SFileOpenArchive.cpp Copyright Ladislav Zezula 1999 */
-/* */
-/* Author : Ladislav Zezula */
-/* E-mail : ladik@zezula.net */
-/* WWW : www.zezula.net */
-/*---------------------------------------------------------------------------*/
-/* Implementation of archive functions */
-/*---------------------------------------------------------------------------*/
-/* Date Ver Who Comment */
-/* -------- ---- --- ------- */
-/* xx.xx.xx 1.00 Lad Created */
-/* 19.11.03 1.01 Dan Big endian handling */
-/*****************************************************************************/
-
-#define __STORMLIB_SELF__
-#include "StormLib.h"
-#include "StormCommon.h"
-
-#define HEADER_SEARCH_BUFFER_SIZE 0x1000
-
-//-----------------------------------------------------------------------------
-// Local functions
-
-static MTYPE CheckMapType(LPCTSTR szFileName, LPBYTE pbHeaderBuffer, size_t cbHeaderBuffer)
-{
- LPDWORD HeaderInt32 = (LPDWORD)pbHeaderBuffer;
- LPCTSTR szExtension;
-
- // Don't do any checks if there is not at least 16 bytes
- if(cbHeaderBuffer > 0x10)
- {
- DWORD DwordValue0 = BSWAP_INT32_UNSIGNED(HeaderInt32[0]);
- DWORD DwordValue1 = BSWAP_INT32_UNSIGNED(HeaderInt32[1]);
- DWORD DwordValue2 = BSWAP_INT32_UNSIGNED(HeaderInt32[2]);
- DWORD DwordValue3 = BSWAP_INT32_UNSIGNED(HeaderInt32[3]);
-
- // Test for AVI files (Warcraft III cinematics) - 'RIFF', 'AVI ' or 'LIST'
- if(DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C)
- return MapTypeAviFile;
-
- // Check for Starcraft II maps
- if((szExtension = _tcsrchr(szFileName, _T('.'))) != NULL)
- {
- // The "NP_Protect" protector places fake Warcraft III header
- // into the Starcraft II maps, whilst SC2 maps have no other header but MPQ v4
- if(!_tcsicmp(szExtension, _T(".s2ma")) || !_tcsicmp(szExtension, _T(".SC2Map")) || !_tcsicmp(szExtension, _T(".SC2Mod")))
- {
- return MapTypeStarcraft2;
- }
- }
-
- // Check for Warcraft III maps
- if(DwordValue0 == 0x57334D48 && DwordValue1 == 0x00000000)
- return MapTypeWarcraft3;
- }
-
- // MIX files are DLL files that contain MPQ in overlay.
- // Only Warcraft III is able to load them, so we consider them Warcraft III maps
- if(cbHeaderBuffer > 0x200 && pbHeaderBuffer[0] == 'M' && pbHeaderBuffer[1] == 'Z')
- {
- // Check the value of IMAGE_DOS_HEADER::e_lfanew at offset 0x3C
- if(0 < HeaderInt32[0x0F] && HeaderInt32[0x0F] < 0x10000)
- return MapTypeWarcraft3;
- }
-
- // No special map type recognized
- return MapTypeNotRecognized;
-}
-
-static TMPQUserData * IsValidMpqUserData(ULONGLONG ByteOffset, ULONGLONG FileSize, void * pvUserData)
-{
- TMPQUserData * pUserData;
-
- // BSWAP the source data and copy them to our buffer
- BSWAP_ARRAY32_UNSIGNED(pvUserData, sizeof(TMPQUserData));
- pUserData = (TMPQUserData *)pvUserData;
-
- // Check the sizes
- if(pUserData->cbUserDataHeader <= pUserData->cbUserDataSize && pUserData->cbUserDataSize <= pUserData->dwHeaderOffs)
- {
- // Move to the position given by the userdata
- ByteOffset += pUserData->dwHeaderOffs;
-
- // The MPQ header should be within range of the file size
- if((ByteOffset + MPQ_HEADER_SIZE_V1) < FileSize)
- {
- // Note: We should verify if there is the MPQ header.
- // However, the header could be at any position below that
- // that is multiplier of 0x200
- return (TMPQUserData *)pvUserData;
- }
- }
-
- return NULL;
-}
-
-// This function gets the right positions of the hash table and the block table.
-static DWORD VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize)
-{
- TMPQHeader * pHeader = ha->pHeader;
- ULONGLONG ByteOffset;
- //bool bMalformed = (ha->dwFlags & MPQ_FLAG_MALFORMED) ? true : false;
-
- // Check the begin of HET table
- if(pHeader->HetTablePos64)
- {
- ByteOffset = ha->MpqPos + pHeader->HetTablePos64;
- if(ByteOffset > FileSize)
- return ERROR_BAD_FORMAT;
- }
-
- // Check the begin of BET table
- if(pHeader->BetTablePos64)
- {
- ByteOffset = ha->MpqPos + pHeader->BetTablePos64;
- if(ByteOffset > FileSize)
- return ERROR_BAD_FORMAT;
- }
-
- // Check the begin of hash table
- if(pHeader->wHashTablePosHi || pHeader->dwHashTablePos)
- {
- ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos));
- if(ByteOffset > FileSize)
- return ERROR_BAD_FORMAT;
- }
-
- // Check the begin of block table
- if(pHeader->wBlockTablePosHi || pHeader->dwBlockTablePos)
- {
- ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos));
- if(ByteOffset > FileSize)
- return ERROR_BAD_FORMAT;
- }
-
- // Check the begin of hi-block table
- //if(pHeader->HiBlockTablePos64 != 0)
- //{
- // ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64;
- // if(ByteOffset > FileSize)
- // return ERROR_BAD_FORMAT;
- //}
-
- // All OK.
- return ERROR_SUCCESS;
-}
-
-//-----------------------------------------------------------------------------
-// Support for alternate markers. Call before opening an archive
-
-#define SFILE_MARKERS_MIN_SIZE (sizeof(DWORD) + sizeof(DWORD) + sizeof(const char *) + sizeof(const char *))
-
-bool WINAPI SFileSetArchiveMarkers(PSFILE_MARKERS pMarkers)
-{
- // Check structure minimum size
- if(pMarkers == NULL || pMarkers->dwSize < SFILE_MARKERS_MIN_SIZE)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return false;
- }
-
- // Make sure that the MPQ cryptography is initialized at this time
- InitializeMpqCryptography();
-
- // Remember the marker for MPQ header
- if(pMarkers->dwSignature != 0)
- g_dwMpqSignature = pMarkers->dwSignature;
-
- // Remember the encryption key for hash table
- if(pMarkers->szHashTableKey != NULL)
- g_dwHashTableKey = HashString(pMarkers->szHashTableKey, MPQ_HASH_FILE_KEY);
-
- // Remember the encryption key for block table
- if(pMarkers->szBlockTableKey != NULL)
- g_dwBlockTableKey = HashString(pMarkers->szBlockTableKey, MPQ_HASH_FILE_KEY);
-
- // Succeeded
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// SFileGetLocale and SFileSetLocale
-// Set the locale for all newly opened files
-
-LCID WINAPI SFileGetLocale()
-{
- return g_lcFileLocale;
-}
-
-LCID WINAPI SFileSetLocale(LCID lcNewLocale)
-{
- g_lcFileLocale = lcNewLocale;
- return g_lcFileLocale;
-}
-
-//-----------------------------------------------------------------------------
-// SFileOpenArchive
-//
-// szFileName - MPQ archive file name to open
-// dwPriority - When SFileOpenFileEx called, this contains the search priority for searched archives
-// dwFlags - See MPQ_OPEN_XXX in StormLib.h
-// phMpq - Pointer to store open archive handle
-
-bool WINAPI SFileOpenArchive(
- const TCHAR * szMpqName,
- DWORD dwPriority,
- DWORD dwFlags,
- HANDLE * phMpq)
-{
- TMPQUserData * pUserData;
- TFileStream * pStream = NULL; // Open file stream
- TMPQArchive * ha = NULL; // Archive handle
- TFileEntry * pFileEntry;
- ULONGLONG FileSize = 0; // Size of the file
- LPBYTE pbHeaderBuffer = NULL; // Buffer for searching MPQ header
- DWORD dwStreamFlags = (dwFlags & STREAM_FLAGS_MASK);
- MTYPE MapType = MapTypeNotChecked;
- DWORD dwErrCode = ERROR_SUCCESS;
-
- // Verify the parameters
- if(szMpqName == NULL || *szMpqName == 0 || phMpq == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return false;
- }
-
- // One time initialization of MPQ cryptography
- InitializeMpqCryptography();
- dwPriority = dwPriority;
-
- // If not forcing MPQ v 1.0, also use file bitmap
- dwStreamFlags |= (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) ? 0 : STREAM_FLAG_USE_BITMAP;
-
- // Open the MPQ archive file
- pStream = FileStream_OpenFile(szMpqName, dwStreamFlags);
- if(pStream == NULL)
- return false;
-
- // Check the file size. There must be at least 0x20 bytes
- if(dwErrCode == ERROR_SUCCESS)
- {
- FileStream_GetSize(pStream, &FileSize);
- if(FileSize < MPQ_HEADER_SIZE_V1)
- dwErrCode = ERROR_BAD_FORMAT;
- }
-
- // Allocate the MPQhandle
- if(dwErrCode == ERROR_SUCCESS)
- {
- if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL)
- dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
- }
-
- // Allocate buffer for searching MPQ header
- if(dwErrCode == ERROR_SUCCESS)
- {
- pbHeaderBuffer = STORM_ALLOC(BYTE, HEADER_SEARCH_BUFFER_SIZE);
- if(pbHeaderBuffer == NULL)
- dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
- }
-
- // Find the position of MPQ header
- if(dwErrCode == ERROR_SUCCESS)
- {
- ULONGLONG ByteOffset = 0;
- ULONGLONG EndOfSearch = FileSize;
- DWORD dwStrmFlags = 0;
- DWORD dwHeaderSize;
- DWORD dwHeaderID;
- bool bSearchComplete = false;
-
- memset(ha, 0, sizeof(TMPQArchive));
- ha->pfnHashString = HashStringSlash;
- ha->pStream = pStream;
- pStream = NULL;
-
- // Set the archive read only if the stream is read-only
- FileStream_GetFlags(ha->pStream, &dwStrmFlags);
- ha->dwFlags |= (dwStrmFlags & STREAM_FLAG_READ_ONLY) ? MPQ_FLAG_READ_ONLY : 0;
-
- // Also remember if we shall check sector CRCs when reading file
- ha->dwFlags |= (dwFlags & MPQ_OPEN_CHECK_SECTOR_CRC) ? MPQ_FLAG_CHECK_SECTOR_CRC : 0;
-
- // Also remember if this MPQ is a patch
- ha->dwFlags |= (dwFlags & MPQ_OPEN_PATCH) ? MPQ_FLAG_PATCH : 0;
-
- // Limit the header searching to about 130 MB of data
- if(EndOfSearch > 0x08000000)
- EndOfSearch = 0x08000000;
-
- // Find the offset of MPQ header within the file
- while(bSearchComplete == false && ByteOffset < EndOfSearch)
- {
- // Always read at least 0x1000 bytes for performance.
- // This is what Storm.dll (2002) does.
- DWORD dwBytesAvailable = HEADER_SEARCH_BUFFER_SIZE;
-
- // Cut the bytes available, if needed
- if((FileSize - ByteOffset) < HEADER_SEARCH_BUFFER_SIZE)
- dwBytesAvailable = (DWORD)(FileSize - ByteOffset);
-
- // Read the eventual MPQ header
- if(!FileStream_Read(ha->pStream, &ByteOffset, pbHeaderBuffer, dwBytesAvailable))
- {
- dwErrCode = GetLastError();
- break;
- }
-
- // Check whether the file is AVI file or a Warcraft III/Starcraft II map
- if(MapType == MapTypeNotChecked)
- {
- // Do nothing if the file is an AVI file
- if((MapType = CheckMapType(szMpqName, pbHeaderBuffer, dwBytesAvailable)) == MapTypeAviFile)
- {
- dwErrCode = ERROR_AVI_FILE;
- break;
- }
- }
-
- // Search the header buffer
- for(DWORD dwInBufferOffset = 0; dwInBufferOffset < dwBytesAvailable; dwInBufferOffset += 0x200)
- {
- // Copy the data from the potential header buffer to the MPQ header
- memcpy(ha->HeaderData, pbHeaderBuffer + dwInBufferOffset, sizeof(ha->HeaderData));
-
- // If there is the MPQ user data, process it
- // Note that Warcraft III does not check for user data, which is abused by many map protectors
- dwHeaderID = BSWAP_INT32_UNSIGNED(ha->HeaderData[0]);
- if(MapType != MapTypeWarcraft3 && (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0)
- {
- if(ha->pUserData == NULL && dwHeaderID == ID_MPQ_USERDATA)
- {
- // Verify if this looks like a valid user data
- pUserData = IsValidMpqUserData(ByteOffset, FileSize, ha->HeaderData);
- if(pUserData != NULL)
- {
- // Fill the user data header
- ha->UserDataPos = ByteOffset;
- ha->pUserData = &ha->UserData;
- memcpy(ha->pUserData, pUserData, sizeof(TMPQUserData));
-
- // Continue searching from that position
- ByteOffset += ha->pUserData->dwHeaderOffs;
- break;
- }
- }
- }
-
- // There must be MPQ header signature. Note that STORM.dll from Warcraft III actually
- // tests the MPQ header size. It must be at least 0x20 bytes in order to load it
- // Abused by Spazzler Map protector. Note that the size check is not present
- // in Storm.dll v 1.00, so Diablo I code would load the MPQ anyway.
- dwHeaderSize = BSWAP_INT32_UNSIGNED(ha->HeaderData[1]);
- if(dwHeaderID == g_dwMpqSignature && dwHeaderSize >= MPQ_HEADER_SIZE_V1)
- {
- // Now convert the header to version 4
- dwErrCode = ConvertMpqHeaderToFormat4(ha, ByteOffset, FileSize, dwFlags, MapType);
- if(dwErrCode != ERROR_FAKE_MPQ_HEADER)
- {
- bSearchComplete = true;
- break;
- }
- }
-
- // Check for MPK archives (Longwu Online - MPQ fork)
- if(MapType == MapTypeNotRecognized && dwHeaderID == ID_MPK)
- {
- // Now convert the MPK header to MPQ Header version 4
- dwErrCode = ConvertMpkHeaderToFormat4(ha, FileSize, dwFlags);
- bSearchComplete = true;
- break;
- }
-
- // If searching for the MPQ header is disabled, return an error
- if(dwFlags & MPQ_OPEN_NO_HEADER_SEARCH)
- {
- dwErrCode = ERROR_NOT_SUPPORTED;
- bSearchComplete = true;
- break;
- }
-
- // Move the pointers
- ByteOffset += 0x200;
- }
- }
-
- // Did we identify one of the supported headers?
- if(dwErrCode == ERROR_SUCCESS)
- {
- // Set the user data position to the MPQ header, if none
- if(ha->pUserData == NULL)
- ha->UserDataPos = ByteOffset;
-
- // Set the position of the MPQ header
- ha->pHeader = (TMPQHeader *)ha->HeaderData;
- ha->MpqPos = ByteOffset;
- ha->FileSize = FileSize;
-
- // Sector size must be nonzero.
- if(ByteOffset >= FileSize || ha->pHeader->wSectorSize == 0)
- dwErrCode = ERROR_BAD_FORMAT;
- }
- }
-
- // Fix table positions according to format
- if(dwErrCode == ERROR_SUCCESS)
- {
- // Dump the header
-// DumpMpqHeader(ha->pHeader);
-
- // W3x Map Protectors use the fact that War3's Storm.dll ignores the MPQ user data,
- // and ignores the MPQ format version as well. The trick is to
- // fake MPQ format 2, with an improper hi-word position of hash table and block table
- // We can overcome such protectors by forcing opening the archive as MPQ v 1.0
- if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1)
- {
- ha->pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1;
- ha->pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
- ha->dwFlags |= MPQ_FLAG_READ_ONLY;
- ha->pUserData = NULL;
- }
-
- // Anti-overflow. If the hash table size in the header is
- // higher than 0x10000000, it would overflow in 32-bit version
- // Observed in the malformed Warcraft III maps
- // Example map: MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x
- ha->pHeader->dwBlockTableSize = (ha->pHeader->dwBlockTableSize & BLOCK_INDEX_MASK);
- ha->pHeader->dwHashTableSize = (ha->pHeader->dwHashTableSize & BLOCK_INDEX_MASK);
-
- // Both MPQ_OPEN_NO_LISTFILE or MPQ_OPEN_NO_ATTRIBUTES trigger read only mode
- if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES))
- ha->dwFlags |= MPQ_FLAG_READ_ONLY;
-
- // Check if the caller wants to force adding listfile
- if(dwFlags & MPQ_OPEN_FORCE_LISTFILE)
- ha->dwFlags |= MPQ_FLAG_LISTFILE_FORCE;
-
- // Remember whether whis is a map for Warcraft III
- if(MapType == MapTypeWarcraft3)
- ha->dwFlags |= MPQ_FLAG_WAR3_MAP;
-
- // Set the size of file sector
- ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize);
-
- // Verify if any of the tables doesn't start beyond the end of the file
- dwErrCode = VerifyMpqTablePositions(ha, FileSize);
- }
-
- // Read the hash table. Ignore the result, as hash table is no longer required
- // Read HET table. Ignore the result, as HET table is no longer required
- if(dwErrCode == ERROR_SUCCESS)
- {
- dwErrCode = LoadAnyHashTable(ha);
- }
-
- // Now, build the file table. It will be built by combining
- // the block table, BET table, hi-block table, (attributes) and (listfile).
- if(dwErrCode == ERROR_SUCCESS)
- {
- dwErrCode = BuildFileTable(ha);
- }
-
- // Load the internal listfile and include it to the file table
- if(dwErrCode == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_LISTFILE) == 0)
- {
- // Quick check for (listfile)
- pFileEntry = GetFileEntryLocale(ha, LISTFILE_NAME, LANG_NEUTRAL);
- if(pFileEntry != NULL)
- {
- // Ignore result of the operation. (listfile) is optional.
- SFileAddListFile((HANDLE)ha, NULL);
- ha->dwFileFlags1 = pFileEntry->dwFlags;
- }
- }
-
- // Load the "(attributes)" file and merge it to the file table
- if(dwErrCode == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_ATTRIBUTES) == 0 && (ha->dwFlags & MPQ_FLAG_BLOCK_TABLE_CUT) == 0)
- {
- // Quick check for (attributes)
- pFileEntry = GetFileEntryLocale(ha, ATTRIBUTES_NAME, LANG_NEUTRAL);
- if(pFileEntry != NULL)
- {
- // Ignore result of the operation. (attributes) is optional.
- SAttrLoadAttributes(ha);
- ha->dwFileFlags2 = pFileEntry->dwFlags;
- }
- }
-
- // Remember whether the archive has weak signature. Only for MPQs format 1.0.
- if(dwErrCode == ERROR_SUCCESS)
- {
- // Quick check for (signature)
- pFileEntry = GetFileEntryLocale(ha, SIGNATURE_NAME, LANG_NEUTRAL);
- if(pFileEntry != NULL)
- {
- // Just remember that the archive is weak-signed
- assert((pFileEntry->dwFlags & MPQ_FILE_EXISTS) != 0);
- ha->dwFileFlags3 = pFileEntry->dwFlags;
- }
-
- // Finally, set the MPQ_FLAG_READ_ONLY if the MPQ was found malformed
- ha->dwFlags |= (ha->dwFlags & MPQ_FLAG_MALFORMED) ? MPQ_FLAG_READ_ONLY : 0;
- }
-
- // Cleanup and exit
- if(dwErrCode != ERROR_SUCCESS)
- {
- FileStream_Close(pStream);
- FreeArchiveHandle(ha);
- SetLastError(dwErrCode);
- ha = NULL;
- }
-
- // Free the header buffer
- if(pbHeaderBuffer != NULL)
- STORM_FREE(pbHeaderBuffer);
- if(phMpq != NULL)
- *phMpq = ha;
- return (dwErrCode == ERROR_SUCCESS);
-}
-
-//-----------------------------------------------------------------------------
-// bool WINAPI SFileSetDownloadCallback(HANDLE, SFILE_DOWNLOAD_CALLBACK, void *);
-//
-// Sets a callback that is called when content is downloaded from the master MPQ
-//
-
-bool WINAPI SFileSetDownloadCallback(HANDLE hMpq, SFILE_DOWNLOAD_CALLBACK DownloadCB, void * pvUserData)
-{
- TMPQArchive * ha = (TMPQArchive *)hMpq;
-
- // Do nothing if 'hMpq' is bad parameter
- if(!IsValidMpqHandle(hMpq))
- {
- SetLastError(ERROR_INVALID_HANDLE);
- return false;
- }
-
- return FileStream_SetCallback(ha->pStream, DownloadCB, pvUserData);
-}
-
-//-----------------------------------------------------------------------------
-// bool SFileFlushArchive(HANDLE hMpq)
-//
-// Saves all dirty data into MPQ archive.
-// Has similar effect like SFileCloseArchive, but the archive is not closed.
-// Use on clients who keep MPQ archive open even for write operations,
-// and terminating without calling SFileCloseArchive might corrupt the archive.
-//
-
-bool WINAPI SFileFlushArchive(HANDLE hMpq)
-{
- TMPQArchive * ha;
- DWORD dwResultError = ERROR_SUCCESS;
- DWORD dwErrCode;
-
- // Do nothing if 'hMpq' is bad parameter
- if((ha = IsValidMpqHandle(hMpq)) == NULL)
- {
- SetLastError(ERROR_INVALID_HANDLE);
- return false;
- }
-
- // Only if the MPQ was changed
- if(ha->dwFlags & MPQ_FLAG_CHANGED)
- {
- // Indicate that we are saving MPQ internal structures
- ha->dwFlags |= MPQ_FLAG_SAVING_TABLES;
-
- // Defragment the file table. This will allow us to put the internal files to the end
- DefragmentFileTable(ha);
-
- //
- // Create each internal file
- // Note that the (signature) file is usually before (listfile) in the file table
- //
-
- if(ha->dwFlags & MPQ_FLAG_SIGNATURE_NEW)
- {
- dwErrCode = SSignFileCreate(ha);
- if(dwErrCode != ERROR_SUCCESS)
- dwResultError = dwErrCode;
- }
-
- if(ha->dwFlags & (MPQ_FLAG_LISTFILE_NEW | MPQ_FLAG_LISTFILE_FORCE))
- {
- dwErrCode = SListFileSaveToMpq(ha);
- if(dwErrCode != ERROR_SUCCESS)
- dwResultError = dwErrCode;
- }
-
- if(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_NEW)
- {
- dwErrCode = SAttrFileSaveToMpq(ha);
- if(dwErrCode != ERROR_SUCCESS)
- dwResultError = dwErrCode;
- }
-
- // Save HET table, BET table, hash table, block table, hi-block table
- if(ha->dwFlags & MPQ_FLAG_CHANGED)
- {
- // Rebuild the HET table
- if(ha->pHetTable != NULL)
- RebuildHetTable(ha);
-
- // Save all MPQ tables first
- dwErrCode = SaveMPQTables(ha);
- if(dwErrCode != ERROR_SUCCESS)
- dwResultError = dwErrCode;
-
- // If the archive has weak signature, we need to finish it
- if(ha->dwFileFlags3 != 0)
- {
- dwErrCode = SSignFileFinish(ha);
- if(dwErrCode != ERROR_SUCCESS)
- dwResultError = dwErrCode;
- }
- }
-
- // We are no longer saving internal MPQ structures
- ha->dwFlags &= ~MPQ_FLAG_SAVING_TABLES;
- }
-
- // Return the error
- if(dwResultError != ERROR_SUCCESS)
- SetLastError(dwResultError);
- return (dwResultError == ERROR_SUCCESS);
-}
-
-//-----------------------------------------------------------------------------
-// bool SFileCloseArchive(HANDLE hMpq);
-//
-
-bool WINAPI SFileCloseArchive(HANDLE hMpq)
-{
- TMPQArchive * ha = IsValidMpqHandle(hMpq);
- bool bResult = false;
-
- // Only if the handle is valid
- if(ha == NULL)
- {
- SetLastError(ERROR_INVALID_HANDLE);
- return false;
- }
-
- // Invalidate the add file callback so it won't be called
- // when saving (listfile) and (attributes)
- ha->pfnAddFileCB = NULL;
- ha->pvAddFileUserData = NULL;
-
- // Flush all unsaved data to the storage
- bResult = SFileFlushArchive(hMpq);
-
- // Free all memory used by MPQ archive
- FreeArchiveHandle(ha);
- return bResult;
-}