mirror of
https://github.com/ladislav-zezula/StormLib.git
synced 2026-02-01 12:06:30 +01:00
+ StormLib 9.0 BETA
This commit is contained in:
@@ -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;
|
||||
|
||||
return SFileAddFile_Write(hf, szNewLine, sizeof(szNewLine), MPQ_COMPRESSION_ZLIB);
|
||||
// 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);
|
||||
|
||||
// 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++)
|
||||
// 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);
|
||||
|
||||
// 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--;
|
||||
|
||||
// If the listfile create succeeded, we write it to the MPQ
|
||||
if(pbListFile != NULL)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We expect it to be nonzero size
|
||||
assert(cbListFile != 0);
|
||||
|
||||
// Sort the table
|
||||
qsort(SortTable, nFileNodes, sizeof(char *), CompareFileNodes);
|
||||
|
||||
// Now parse the table of file names again - remove duplicates
|
||||
// and count file size.
|
||||
if(nFileNodes != 0)
|
||||
{
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user