summaryrefslogtreecommitdiff
path: root/StormLib/src/SFileListFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'StormLib/src/SFileListFile.cpp')
-rw-r--r--StormLib/src/SFileListFile.cpp687
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);
-}
-