diff options
author | Ladislav Zezula <ladislav.zezula@avg.com> | 2013-12-05 15:59:00 +0100 |
---|---|---|
committer | Ladislav Zezula <ladislav.zezula@avg.com> | 2013-12-05 15:59:00 +0100 |
commit | c34c37b3418f1e5ab3678ce65d46f81803dec91d (patch) | |
tree | 4a9cf4c61634691981f9dc367b53dac4070f8d0d /src/SFileListFile.cpp | |
parent | ff0c25952a28a927c48738ab5207b9bda69e588a (diff) |
+ StormLib 9.0 BETA
Diffstat (limited to 'src/SFileListFile.cpp')
-rw-r--r-- | src/SFileListFile.cpp | 236 |
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; } |