aboutsummaryrefslogtreecommitdiff
path: root/src/SFileListFile.cpp
diff options
context:
space:
mode:
authorLadislav Zezula <ladislav.zezula@avg.com>2013-12-05 15:59:00 +0100
committerLadislav Zezula <ladislav.zezula@avg.com>2013-12-05 15:59:00 +0100
commitc34c37b3418f1e5ab3678ce65d46f81803dec91d (patch)
tree4a9cf4c61634691981f9dc367b53dac4070f8d0d /src/SFileListFile.cpp
parentff0c25952a28a927c48738ab5207b9bda69e588a (diff)
+ StormLib 9.0 BETA
Diffstat (limited to 'src/SFileListFile.cpp')
-rw-r--r--src/SFileListFile.cpp236
1 files changed, 131 insertions, 105 deletions
diff --git a/src/SFileListFile.cpp b/src/SFileListFile.cpp
index 2044125..f98c92b 100644
--- a/src/SFileListFile.cpp
+++ b/src/SFileListFile.cpp
@@ -35,6 +35,18 @@ struct TListFileCache
//-----------------------------------------------------------------------------
// Local functions (cache)
+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 FreeListFileCache(TListFileCache * pCache)
{
// Valid parameter check
@@ -216,19 +228,91 @@ static int CompareFileNodes(const void * p1, const void * p2)
return _stricmp(szFileName1, szFileName2);
}
-static int WriteListFileLine(
- TMPQFile * hf,
- const char * szLine)
+static LPBYTE CreateListFile(TMPQArchive * ha, DWORD * pcbListFile)
{
- char szNewLine[2] = {0x0D, 0x0A};
- size_t nLength = strlen(szLine);
- int nError;
+ 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;
- nError = SFileAddFile_Write(hf, szLine, (DWORD)nLength, MPQ_COMPRESSION_ZLIB);
- if(nError != ERROR_SUCCESS)
- return nError;
+ // 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))
+ {
+ 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);
+ }
+ }
+
+ // Free the sort table
+ STORM_FREE(SortTable);
- return SFileAddFile_Write(hf, szNewLine, sizeof(szNewLine), MPQ_COMPRESSION_ZLIB);
+ // Give away the listfile
+ if(pcbListFile != NULL)
+ *pcbListFile = (DWORD)cbListFile;
+ return (LPBYTE)szListFile;
}
//-----------------------------------------------------------------------------
@@ -252,7 +336,7 @@ static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFil
if(pFileEntry != NULL)
{
// Allocate file name for the file entry
- AllocateFileName(pFileEntry, szFileName);
+ AllocateFileName(ha, pFileEntry, szFileName);
bNameEntryCreated = true;
}
@@ -272,7 +356,7 @@ static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFil
if(pHash->dwBlockIndex < pHeader->dwBlockTableSize)
{
// Allocate file name for the file entry
- AllocateFileName(ha->pFileTable + pHash->dwBlockIndex, szFileName);
+ AllocateFileName(ha, ha->pFileTable + pHash->dwBlockIndex, szFileName);
bNameEntryCreated = true;
}
@@ -284,123 +368,65 @@ static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFil
return ERROR_CAN_NOT_COMPLETE;
}
-// Saves the whole listfile into the MPQ.
+// Saves the whole listfile to the MPQ
int SListFileSaveToMpq(TMPQArchive * ha)
{
- TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
- TFileEntry * pFileEntry;
TMPQFile * hf = NULL;
- char * szPrevItem;
- char ** SortTable = NULL;
- DWORD dwFileSize = 0;
- size_t nFileNodes = 0;
- size_t i;
+ LPBYTE pbListFile;
+ DWORD cbListFile = 0;
int nError = ERROR_SUCCESS;
- // Allocate the table for sorting listfile
- SortTable = STORM_ALLOC(char*, ha->dwFileTableSize);
- if(SortTable == NULL)
- return ERROR_NOT_ENOUGH_MEMORY;
+ // Only save (listfile) if we should do so
+ if(ha->dwFileFlags1 == 0 || ha->dwMaxFileCount == 0)
+ return ERROR_SUCCESS;
- // Construct the sort table
- // Note: in MPQs with multiple locale versions of the same file,
- // this code causes adding multiple listfile entries.
- // Since those MPQs were last time used in Starcraft,
- // we leave it as it is.
- for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
- {
- // Only take existing items
- if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->szFileName != NULL)
- {
- // Ignore pseudo-names
- if(!IsPseudoFileName(pFileEntry->szFileName, NULL) && !IsInternalMpqFileName(pFileEntry->szFileName))
- {
- SortTable[nFileNodes++] = pFileEntry->szFileName;
- }
- }
- }
+ // At this point, we expect to have at least one reserved entry in the file table
+ assert(ha->dwReservedFiles >= 1);
+
+ // 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);
- // Sort the table
- qsort(SortTable, nFileNodes, sizeof(char *), CompareFileNodes);
+ // 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--;
- // Now parse the table of file names again - remove duplicates
- // and count file size.
- if(nFileNodes != 0)
+ // If the listfile create succeeded, we write it to the MPQ
+ if(pbListFile != NULL)
{
- // Count the 0-th item
- dwFileSize += (DWORD)strlen(SortTable[0]) + 2;
- szPrevItem = SortTable[0];
-
- // Count all next items
- for(i = 1; i < nFileNodes; i++)
- {
- // If the item is different from the previous one, include its size to the file size
- if(_stricmp(SortTable[i], szPrevItem))
- {
- dwFileSize += (DWORD)strlen(SortTable[i]) + 2;
- szPrevItem = SortTable[i];
- }
- }
+ // We expect it to be nonzero size
+ assert(cbListFile != 0);
- // Determine the flags for (listfile)
- if(ha->dwFileFlags1 == 0)
- ha->dwFileFlags1 = GetDefaultSpecialFileFlags(ha, dwFileSize);
+ // Determine the real flags for (listfile)
+ if(ha->dwFileFlags1 == MPQ_FILE_EXISTS)
+ ha->dwFileFlags1 = GetDefaultSpecialFileFlags(cbListFile, ha->pHeader->wFormatVersion);
// Create the listfile in the MPQ
nError = SFileAddFile_Init(ha, LISTFILE_NAME,
0,
- dwFileSize,
+ cbListFile,
LANG_NEUTRAL,
ha->dwFileFlags1 | MPQ_FILE_REPLACEEXISTING,
&hf);
- // Add all file names
+
+ // Write the listfile raw data to it
if(nError == ERROR_SUCCESS)
{
- // Each name is followed by newline ("\x0D\x0A")
- szPrevItem = SortTable[0];
- nError = WriteListFileLine(hf, SortTable[0]);
+ // Write the content of the listfile to the MPQ
+ nError = SFileAddFile_Write(hf, pbListFile, cbListFile, MPQ_COMPRESSION_ZLIB);
+ SFileAddFile_Finish(hf);
- // Count all next items
- for(i = 1; i < nFileNodes; i++)
- {
- // If the item is the same like the last one, skip it
- if(_stricmp(SortTable[i], szPrevItem))
- {
- WriteListFileLine(hf, SortTable[i]);
- szPrevItem = SortTable[i];
- }
- }
+ // Clear the invalidate flag
+ ha->dwFlags &= ~MPQ_FLAG_LISTFILE_INVALID;
}
- }
- else
- {
- // Create the listfile in the MPQ
- dwFileSize = (DWORD)strlen(LISTFILE_NAME) + 2;
- nError = SFileAddFile_Init(ha, LISTFILE_NAME,
- 0,
- dwFileSize,
- LANG_NEUTRAL,
- MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS | MPQ_FILE_REPLACEEXISTING,
- &hf);
- // Just add "(listfile)" there
- if(nError == ERROR_SUCCESS)
- {
- WriteListFileLine(hf, LISTFILE_NAME);
- }
+ // Free the listfile buffer
+ STORM_FREE(pbListFile);
}
- // Finalize the file in the MPQ
- if(hf != NULL)
- {
- SFileAddFile_Finish(hf);
- }
-
- // Free buffers
- if(nError == ERROR_SUCCESS)
- ha->dwFlags &= ~MPQ_FLAG_LISTFILE_INVALID;
- if(SortTable != NULL)
- STORM_FREE(SortTable);
return nError;
}