diff options
| author | briaguya <70942617+briaguya-ai@users.noreply.github.com> | 2022-11-14 05:22:34 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-14 11:22:34 +0100 |
| commit | 3914781ebfd5cb22717cc207cb3d37d8754d0eb7 (patch) | |
| tree | 2e412b87e66b1deef47bef242e7189a200cea0ff /StormLib/src/SFileListFile.cpp | |
| parent | 9eb29ed81cb497a6a216811255f8af7daf3f8bd8 (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/SFileListFile.cpp')
| -rw-r--r-- | StormLib/src/SFileListFile.cpp | 687 |
1 files changed, 0 insertions, 687 deletions
diff --git a/StormLib/src/SFileListFile.cpp b/StormLib/src/SFileListFile.cpp deleted file mode 100644 index 0a53e4b1a..000000000 --- a/StormLib/src/SFileListFile.cpp +++ /dev/null @@ -1,687 +0,0 @@ -/*****************************************************************************/ -/* SListFile.cpp Copyright (c) Ladislav Zezula 2004 */ -/*---------------------------------------------------------------------------*/ -/* Description: */ -/*---------------------------------------------------------------------------*/ -/* Date Ver Who Comment */ -/* -------- ---- --- ------- */ -/* 12.06.04 1.00 Lad The first version of SListFile.cpp */ -/*****************************************************************************/ - -#define __STORMLIB_SELF__ -#include "StormLib.h" -#include "StormCommon.h" -#include <assert.h> - -//----------------------------------------------------------------------------- -// Listfile entry structure - -#define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer -#define MAX_LISTFILE_SIZE 0x8000000 // Maximum accepted listfile size is 128 MB - -union TListFileHandle -{ - TFileStream * pStream; // Opened local file - HANDLE hFile; // Opened MPQ file -}; - -struct TListFileCache -{ - char * szWildCard; // Self-relative pointer to file mask - LPBYTE pBegin; // The begin of the listfile cache - LPBYTE pPos; // Current position in the cache - LPBYTE pEnd; // The last character in the file cache - DWORD dwFlags; // Flags from TMPQArchive - -// char szWildCard[wildcard_length]; // Followed by the name mask (if any) -// char szListFile[listfile_length]; // Followed by the listfile (if any) -}; - -typedef bool (*LOAD_LISTFILE)(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead); - -//----------------------------------------------------------------------------- -// Local functions (cache) - -// In SFileFindFile.cll -bool SFileCheckWildCard(const char * szString, const char * szWildCard); - -static char * CopyListLine(char * szListLine, const char * szFileName) -{ - // Copy the string - while (szFileName[0] != 0) - { - *szListLine++ = *szFileName++; - } - // Append the end-of-line - *szListLine++ = 0x0D; - *szListLine++ = 0x0A; - return szListLine; -} - -static bool LoadListFile_Stream(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead) -{ - ULONGLONG ByteOffset = 0; - bool bResult; - - bResult = FileStream_Read(pHandle->pStream, &ByteOffset, pvBuffer, cbBuffer); - if(bResult) - *pdwBytesRead = cbBuffer; - return bResult; -} - -static bool LoadListFile_MPQ(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead) -{ - return SFileReadFile(pHandle->hFile, pvBuffer, cbBuffer, pdwBytesRead, NULL); -} - -static bool FreeListFileCache(TListFileCache * pCache) -{ - // Valid parameter check - if(pCache != NULL) - STORM_FREE(pCache); - return true; -} - -static TListFileCache * CreateListFileCache( - LOAD_LISTFILE PfnLoadFile, - TListFileHandle * pHandle, - const char * szWildCard, - DWORD dwFileSize, - DWORD dwMaxSize, - DWORD dwFlags) -{ - TListFileCache * pCache = NULL; - size_t cchWildCardAligned = 0; - size_t cchWildCard = 0; - DWORD dwBytesRead = 0; - - // Get the amount of bytes that need to be allocated - if(dwFileSize == 0 || dwFileSize > dwMaxSize) - return NULL; - - // Append buffer for name mask, if any - if(szWildCard != NULL) - { - cchWildCard = strlen(szWildCard) + 1; - cchWildCardAligned = (cchWildCard + 3) & 0xFFFFFFFC; - } - - // Allocate cache for one file block - pCache = (TListFileCache *)STORM_ALLOC(BYTE, sizeof(TListFileCache) + cchWildCardAligned + dwFileSize + 1); - if(pCache != NULL) - { - // Clear the entire structure - memset(pCache, 0, sizeof(TListFileCache) + cchWildCard); - pCache->dwFlags = dwFlags; - - // Shall we copy the mask? - if(cchWildCard != 0) - { - pCache->szWildCard = (char *)(pCache + 1); - memcpy(pCache->szWildCard, szWildCard, cchWildCard); - } - - // Fill-in the rest of the cache pointers - pCache->pBegin = (LPBYTE)(pCache + 1) + cchWildCardAligned; - - // Load the entire listfile to the cache - PfnLoadFile(pHandle, pCache->pBegin, dwFileSize, &dwBytesRead); - if(dwBytesRead != 0) - { - // Allocate pointers - pCache->pPos = pCache->pBegin; - pCache->pEnd = pCache->pBegin + dwBytesRead; - } - else - { - FreeListFileCache(pCache); - pCache = NULL; - } - } - - // Return the cache - return pCache; -} - -static TListFileCache * CreateListFileCache( - HANDLE hMpq, - const TCHAR * szListFile, - const char * szWildCard, - DWORD dwMaxSize, - DWORD dwFlags) -{ - TListFileCache * pCache = NULL; - TListFileHandle ListHandle = {NULL}; - - // Put default value to dwMaxSize - if(dwMaxSize == 0) - dwMaxSize = MAX_LISTFILE_SIZE; - - // Internal listfile: hMPQ must be non NULL and szListFile must be NULL. - // We load the MPQ::(listfile) file - if(hMpq != NULL && szListFile == NULL) - { - DWORD dwFileSize = 0; - - // Open the file from the MPQ - if(SFileOpenFileEx(hMpq, LISTFILE_NAME, 0, &ListHandle.hFile)) - { - // Get the file size and create the listfile cache - dwFileSize = SFileGetFileSize(ListHandle.hFile, NULL); - pCache = CreateListFileCache(LoadListFile_MPQ, &ListHandle, szWildCard, dwFileSize, dwMaxSize, dwFlags); - - // Close the MPQ file - SFileCloseFile(ListHandle.hFile); - } - - // Return the loaded cache - return pCache; - } - - // External listfile: hMpq must be NULL and szListFile must be non-NULL. - // We load the file using TFileStream - if(hMpq == NULL && szListFile != NULL) - { - ULONGLONG FileSize = 0; - - // Open the local file - ListHandle.pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY); - if(ListHandle.pStream != NULL) - { - // Verify the file size - FileStream_GetSize(ListHandle.pStream, &FileSize); - if(0 < FileSize && FileSize < dwMaxSize) - { - pCache = CreateListFileCache(LoadListFile_Stream, &ListHandle, szWildCard, (DWORD)FileSize, dwMaxSize, dwFlags); - } - - // Close the stream - FileStream_Close(ListHandle.pStream); - } - - // Return the loaded cache - return pCache; - } - - // This combination should never happen - SetLastError(ERROR_INVALID_PARAMETER); - assert(false); - return NULL; -} - -#ifdef _DEBUG -/* -TMPQNameCache * CreateNameCache(HANDLE hListFile, const char * szSearchMask) -{ - TMPQNameCache * pNameCache; - char * szCachePointer; - size_t cbToAllocate; - size_t nMaskLength = 1; - DWORD dwBytesRead = 0; - DWORD dwFileSize; - - // Get the size of the listfile. Ignore zero or too long ones - dwFileSize = SFileGetFileSize(hListFile, NULL); - if(dwFileSize == 0 || dwFileSize > MAX_LISTFILE_SIZE) - return NULL; - - // Get the length of the search mask - if(szSearchMask == NULL) - szSearchMask = "*"; - nMaskLength = strlen(szSearchMask) + 1; - - // Allocate the name cache - cbToAllocate = sizeof(TMPQNameCache) + nMaskLength + dwFileSize + 1; - pNameCache = (TMPQNameCache *)STORM_ALLOC(BYTE, cbToAllocate); - if(pNameCache != NULL) - { - // Initialize the name cache - memset(pNameCache, 0, sizeof(TMPQNameCache)); - pNameCache->TotalCacheSize = (DWORD)(nMaskLength + dwFileSize + 1); - szCachePointer = (char *)(pNameCache + 1); - - // Copy the search mask, if any - memcpy(szCachePointer, szSearchMask, nMaskLength); - pNameCache->FirstNameOffset = (DWORD)nMaskLength; - pNameCache->FreeSpaceOffset = (DWORD)nMaskLength; - - // Read the listfile itself - SFileSetFilePointer(hListFile, 0, NULL, FILE_BEGIN); - SFileReadFile(hListFile, szCachePointer + nMaskLength, dwFileSize, &dwBytesRead, NULL); - - // If nothing has been read from the listfile, clear the cache - if(dwBytesRead == 0) - { - STORM_FREE(pNameCache); - return NULL; - } - - // Move the free space offset - pNameCache->FreeSpaceOffset = pNameCache->FirstNameOffset + dwBytesRead + 1; - szCachePointer[nMaskLength + dwBytesRead] = 0; - } - - return pNameCache; -} - -static void FreeNameCache(TMPQNameCache * pNameCache) -{ - if(pNameCache != NULL) - STORM_FREE(pNameCache); - pNameCache = NULL; -} -*/ -#endif // _DEBUG - -static char * ReadListFileLine(TListFileCache * pCache, size_t * PtrLength) -{ - LPBYTE pbLineBegin; - LPBYTE pbLineEnd; - - // Skip newlines. Keep spaces and tabs, as they can be a legal part of the file name - while(pCache->pPos < pCache->pEnd && (pCache->pPos[0] == 0x0A || pCache->pPos[0] == 0x0D)) - pCache->pPos++; - - // Set the line begin and end - if(pCache->pPos >= pCache->pEnd) - return NULL; - pbLineBegin = pbLineEnd = pCache->pPos; - - // Find the end of the line - while(pCache->pPos < pCache->pEnd && pCache->pPos[0] != 0x0A && pCache->pPos[0] != 0x0D) - pCache->pPos++; - - // Remember the end of the line - pbLineEnd = pCache->pPos++; - pbLineEnd[0] = 0; - - // Give the line to the caller - if(PtrLength != NULL) - PtrLength[0] = (size_t)(pbLineEnd - pbLineBegin); - return (char *)pbLineBegin; -} - -static int STORMLIB_CDECL CompareFileNodes(const void * p1, const void * p2) -{ - char * szFileName1 = *(char **)p1; - char * szFileName2 = *(char **)p2; - - return _stricmp(szFileName1, szFileName2); -} - -static LPBYTE CreateListFile(TMPQArchive * ha, DWORD * pcbListFile) -{ - TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; - TFileEntry * pFileEntry; - char ** SortTable = NULL; - char * szListFile = NULL; - char * szListLine; - size_t nFileNodes = 0; - size_t cbListFile = 0; - size_t nIndex0; - size_t nIndex1; - - // Allocate the table for sorting listfile - SortTable = STORM_ALLOC(char*, ha->dwFileTableSize); - if(SortTable == NULL) - return NULL; - - // Construct the sort table - // Note: in MPQs with multiple locale versions of the same file, - // this code causes adding multiple listfile entries. - // They will get removed after the listfile sorting - for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) - { - // Only take existing items - if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->szFileName != NULL) - { - // Ignore pseudo-names and internal names - if(!IsPseudoFileName(pFileEntry->szFileName, NULL) && !IsInternalMpqFileName(pFileEntry->szFileName)) - { - for (int i = 0; i < strlen(pFileEntry->szFileName); i++) - { - // OTRTODO - //if (pFileEntry->szFileName[i] == '/') - //pFileEntry->szFileName[i] = '\\'; - } - - SortTable[nFileNodes++] = pFileEntry->szFileName; - } - } - } - - // Remove duplicities - if(nFileNodes > 0) - { - // Sort the table - qsort(SortTable, nFileNodes, sizeof(char *), CompareFileNodes); - - // Count the 0-th item - cbListFile += strlen(SortTable[0]) + 2; - - // Walk through the items and only use the ones that are not duplicated - for(nIndex0 = 0, nIndex1 = 1; nIndex1 < nFileNodes; nIndex1++) - { - // If the next file node is different, we will include it to the result listfile - if(_stricmp(SortTable[nIndex1], SortTable[nIndex0]) != 0) - { - cbListFile += strlen(SortTable[nIndex1]) + 2; - nIndex0 = nIndex1; - } - } - - // Now allocate buffer for the entire listfile - szListFile = szListLine = STORM_ALLOC(char, cbListFile + 1); - if(szListFile != NULL) - { - // Copy the 0-th item - szListLine = CopyListLine(szListLine, SortTable[0]); - - // Walk through the items and only use the ones that are not duplicated - for(nIndex0 = 0, nIndex1 = 1; nIndex1 < nFileNodes; nIndex1++) - { - // If the next file node is different, we will include it to the result listfile - if(_stricmp(SortTable[nIndex1], SortTable[nIndex0]) != 0) - { - // Copy the listfile line - szListLine = CopyListLine(szListLine, SortTable[nIndex1]); - nIndex0 = nIndex1; - } - } - - // Sanity check - does the size match? - assert((size_t)(szListLine - szListFile) == cbListFile); - } - } - else - { - szListFile = STORM_ALLOC(char, 1); - cbListFile = 0; - } - - // Free the sort table - STORM_FREE(SortTable); - - // Give away the listfile - if(pcbListFile != NULL) - *pcbListFile = (DWORD)cbListFile; - return (LPBYTE)szListFile; -} - -//----------------------------------------------------------------------------- -// Local functions (listfile nodes) - -// Adds a name into the list of all names. For each locale in the MPQ, -// one entry will be created -// If the file name is already there, does nothing. -static DWORD SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFileName) -{ - TFileEntry * pFileEntry; - TMPQHash * pFirstHash; - TMPQHash * pHash; - - // If we have HET table, use that one - if(ha->pHetTable != NULL) - { - pFileEntry = GetFileEntryLocale(ha, szFileName, 0); - if(pFileEntry != NULL) - { - // Allocate file name for the file entry - AllocateFileName(ha, pFileEntry, szFileName); - } - - return ERROR_SUCCESS; - } - - // If we have hash table, we use it - if(ha->pHashTable != NULL) - { - // Go while we found something - pFirstHash = pHash = GetFirstHashEntry(ha, szFileName); - while(pHash != NULL) - { - // Allocate file name for the file entry - AllocateFileName(ha, ha->pFileTable + MPQ_BLOCK_INDEX(pHash), szFileName); - - // Now find the next language version of the file - pHash = GetNextHashEntry(ha, pFirstHash, pHash); - } - - return ERROR_SUCCESS; - } - - return ERROR_CAN_NOT_COMPLETE; -} - -// Saves the whole listfile to the MPQ -DWORD SListFileSaveToMpq(TMPQArchive * ha) -{ - TMPQFile * hf = NULL; - LPBYTE pbListFile; - DWORD cbListFile = 0; - DWORD dwErrCode = ERROR_SUCCESS; - - // Only save the listfile if we should do so - if(ha->dwFileFlags1 != 0) - { - // At this point, we expect to have at least one reserved entry in the file table - assert(ha->dwFlags & MPQ_FLAG_LISTFILE_NEW); - assert(ha->dwReservedFiles > 0); - - // 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); - if(pbListFile != NULL) - { - // Determine the real flags for (listfile) - if(ha->dwFileFlags1 == MPQ_FILE_DEFAULT_INTERNAL) - ha->dwFileFlags1 = GetDefaultSpecialFileFlags(cbListFile, ha->pHeader->wFormatVersion); - - // Create the listfile in the MPQ - dwErrCode = SFileAddFile_Init(ha, LISTFILE_NAME, - 0, - cbListFile, - LANG_NEUTRAL, - ha->dwFileFlags1 | MPQ_FILE_REPLACEEXISTING, - &hf); - - // Write the listfile raw data to it - if(dwErrCode == ERROR_SUCCESS) - { - // Write the content of the listfile to the MPQ - dwErrCode = SFileAddFile_Write(hf, pbListFile, cbListFile, MPQ_COMPRESSION_ZLIB); - SFileAddFile_Finish(hf); - } - - // Clear the listfile flags - ha->dwFlags &= ~(MPQ_FLAG_LISTFILE_NEW | MPQ_FLAG_LISTFILE_NONE); - ha->dwReservedFiles--; - - // Free the listfile buffer - STORM_FREE(pbListFile); - } - else - { - // If the (listfile) file would be empty, its OK - dwErrCode = (cbListFile == 0) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; - } - } - - return dwErrCode; -} - -static DWORD SFileAddArbitraryListFile( - TMPQArchive * ha, - HANDLE hMpq, - const TCHAR * szListFile, - DWORD dwMaxSize) -{ - TListFileCache * pCache = NULL; - - // Create the listfile cache for that file - pCache = CreateListFileCache(hMpq, szListFile, NULL, dwMaxSize, ha->dwFlags); - if(pCache != NULL) - { - char * szFileName; - size_t nLength = 0; - - // Get the next line - while((szFileName = ReadListFileLine(pCache, &nLength)) != NULL) - { - // Add the line to the MPQ - if(nLength != 0) - SListFileCreateNodeForAllLocales(ha, szFileName); - } - - // Delete the cache - FreeListFileCache(pCache); - } - - return (pCache != NULL) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; -} - -static DWORD SFileAddInternalListFile( - TMPQArchive * ha, - HANDLE hMpq) -{ - TMPQHash * pFirstHash; - TMPQHash * pHash; - LCID lcSaveLocale = g_lcFileLocale; - DWORD dwMaxSize = MAX_LISTFILE_SIZE; - DWORD dwErrCode = ERROR_SUCCESS; - - // If there is hash table, we need to support multiple listfiles - // with different locales (BrooDat.mpq) - if(ha->pHashTable != NULL) - { - // If the archive is a malformed map, ignore too large listfiles - if(ha->dwFlags & MPQ_FLAG_MALFORMED) - dwMaxSize = 0x40000; - - pFirstHash = pHash = GetFirstHashEntry(ha, LISTFILE_NAME); - while(dwErrCode == ERROR_SUCCESS && pHash != NULL) - { - // Set the prefered locale to that from list file - SFileSetLocale(pHash->lcLocale); - - // Add that listfile - dwErrCode = SFileAddArbitraryListFile(ha, hMpq, NULL, dwMaxSize); - - // Move to the next hash - pHash = GetNextHashEntry(ha, pFirstHash, pHash); - } - - // Restore the original locale - SFileSetLocale(lcSaveLocale); - } - else - { - // Add the single listfile - dwErrCode = SFileAddArbitraryListFile(ha, hMpq, NULL, dwMaxSize); - } - - // Return the result of the operation - return dwErrCode; -} - -static bool DoListFileSearch(TListFileCache * pCache, SFILE_FIND_DATA * lpFindFileData) -{ - // Check for the valid search handle - if(pCache != NULL) - { - char * szFileName; - size_t nLength = 0; - - // Get the next line - while((szFileName = ReadListFileLine(pCache, &nLength)) != NULL) - { - // Check search mask - if(nLength != 0 && SFileCheckWildCard(szFileName, pCache->szWildCard)) - { - if(nLength >= sizeof(lpFindFileData->cFileName)) - nLength = sizeof(lpFindFileData->cFileName) - 1; - - memcpy(lpFindFileData->cFileName, szFileName, nLength); - lpFindFileData->cFileName[nLength] = 0; - return true; - } - } - } - - // No more files - memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); - SetLastError(ERROR_NO_MORE_FILES); - return false; -} - -//----------------------------------------------------------------------------- -// File functions - -// Adds a listfile into the MPQ archive. -DWORD WINAPI SFileAddListFile(HANDLE hMpq, const TCHAR * szListFile) -{ - TMPQArchive * ha = (TMPQArchive *)hMpq; - DWORD dwErrCode = ERROR_SUCCESS; - - // Add the listfile for each MPQ in the patch chain - while(ha != NULL) - { - if(szListFile != NULL) - dwErrCode = SFileAddArbitraryListFile(ha, NULL, szListFile, MAX_LISTFILE_SIZE); - else - dwErrCode = SFileAddInternalListFile(ha, hMpq); - - // Also, add three special files to the listfile: - // (listfile) itself, (attributes) and (signature) - SListFileCreateNodeForAllLocales(ha, LISTFILE_NAME); - SListFileCreateNodeForAllLocales(ha, SIGNATURE_NAME); - SListFileCreateNodeForAllLocales(ha, ATTRIBUTES_NAME); - - // Move to the next archive in the chain - ha = ha->haPatch; - } - - return dwErrCode; -} - -//----------------------------------------------------------------------------- -// Enumerating files in listfile - -HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const TCHAR * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData) -{ - TListFileCache * pCache = NULL; - - // Initialize the structure with zeros - memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); - - // Open the local/internal listfile - pCache = CreateListFileCache(hMpq, szListFile, szMask, 0, 0); - if(pCache != NULL) - { - if(!DoListFileSearch(pCache, lpFindFileData)) - { - memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); - SetLastError(ERROR_NO_MORE_FILES); - FreeListFileCache(pCache); - pCache = NULL; - } - } - - // Return the listfile cache as handle - return (HANDLE)pCache; -} - -bool WINAPI SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) -{ - return DoListFileSearch((TListFileCache *)hFind, lpFindFileData); -} - -bool WINAPI SListFileFindClose(HANDLE hFind) -{ - TListFileCache * pCache = (TListFileCache *)hFind; - - return FreeListFileCache(pCache); -} - |
