int SFileAddFile_Finish(TMPQFile * hf) { TMPQArchive * ha = hf->ha; int nError = ERROR_SUCCESS; // Verify if the caller wrote the file properly if(hf->pBlock != NULL) { if(hf->dwFilePos != hf->pBlock->dwFSize) { nError = ERROR_CAN_NOT_COMPLETE; hf->bErrorOccured = true; } } // If all previous operations succeeded, we can update the MPQ if(!hf->bErrorOccured) { // Increment the block table size, if needed if(hf->dwBlockIndex >= ha->pHeader->dwBlockTableSize) ha->pHeader->dwBlockTableSize++; // Add the file into listfile also // Don't bother checking result, it either succeeds or not. SListFileCreateNode(ha, hf->szFileName, hf->pHash); // // Note: Don't recalculate position of MPQ tables at this point. // We merely set the flag that indicates that the MPQ tables // have been changed, and SaveMpqTables will do the work when closing the archive. // // Call the user callback, if any if(AddFileCB != NULL) AddFileCB(pvUserData, hf->pBlock->dwFSize, hf->pBlock->dwFSize, true); } else { if(hf != NULL) { // Clear the hash table entry and block table entry if(hf->pHash != NULL) memset(hf->pHash, 0xFF, sizeof(TMPQHash)); if(hf->pBlock != NULL) memset(hf->pBlock, 0, sizeof(TMPQBlock)); if(hf->pBlockEx != NULL) hf->pBlockEx->wFilePosHigh = 0; } } // Schedule to saving MPQ tables regardless of success or error ha->dwFlags |= MPQ_FLAG_CHANGED; // Clear the add file callback FreeMPQFile(hf); pvUserData = NULL; AddFileCB = NULL; return nError; }
BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality, int nFileType) { TMPQArchive * ha = (TMPQArchive *)hMPQ; HANDLE hFile = INVALID_HANDLE_VALUE; BOOL bReplaced = FALSE; // TRUE if replacing file in the archive int nError = ERROR_SUCCESS; if(nError == ERROR_SUCCESS) { // Check valid parameters if(IsValidMpqHandle(ha) == FALSE || szFileName == NULL || *szFileName == 0 || szArchivedName == NULL || *szArchivedName == 0) nError = ERROR_INVALID_PARAMETER; // Check the values of dwFlags if((dwFlags & MPQ_FILE_IMPLODE) && (dwFlags & MPQ_FILE_COMPRESS)) nError = ERROR_INVALID_PARAMETER; } // If anyone is trying to add listfile, and the archive already has a listfile, // deny the operation, but return success. if(nError == ERROR_SUCCESS) { if(ha->pListFile != NULL && !_stricmp(szFileName, LISTFILE_NAME)) return ERROR_SUCCESS; } // Open added file if(nError == ERROR_SUCCESS) { hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL); if(hFile == INVALID_HANDLE_VALUE) nError = GetLastError(); } if(nError == ERROR_SUCCESS) nError = AddFileToArchive(ha, hFile, szArchivedName, dwFlags, dwQuality, nFileType, &bReplaced); // Add the file into listfile also if(nError == ERROR_SUCCESS && bReplaced == FALSE) nError = SListFileCreateNode(ha, szArchivedName, lcLocale); // Cleanup and exit if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
// Renames the file within the archive. bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szFileName, const char * szNewFileName) { TMPQArchive * ha = (TMPQArchive *)hMpq; TMPQBlock * pBlock; TMPQHash * pOldHash = NULL; // Hash entry for the original file TMPQHash * pNewHash = NULL; // Hash entry for the renamed file TMPQFile * hf; DWORD dwOldBlockIndex = 0; LCID lcSaveLocale = 0; int nError = ERROR_SUCCESS; // Test the valid parameters if(nError == ERROR_SUCCESS) { if(!IsValidMpqHandle(ha)) nError = ERROR_INVALID_HANDLE; if(szFileName == NULL || *szFileName == 0 || szNewFileName == NULL || *szNewFileName == 0) nError = ERROR_INVALID_PARAMETER; } if(nError == ERROR_SUCCESS) { // Do not allow to rename files in MPQ open for read only if(ha->dwFlags & MPQ_FLAG_READ_ONLY) nError = ERROR_ACCESS_DENIED; // Do not allow to rename any of the internal files // Also do not allow to rename any of files to an internal file if(IsInternalMpqFileName(szFileName) || IsInternalMpqFileName(szNewFileName)) nError = ERROR_INTERNAL_FILE; } // Get the hash table entry for the original file if(nError == ERROR_SUCCESS) { if((pOldHash = GetHashEntryExact(ha, szFileName, lcFileLocale)) == NULL) nError = ERROR_FILE_NOT_FOUND; } // Test if the file already exists in the archive if(nError == ERROR_SUCCESS) { if((pNewHash = GetHashEntryExact(ha, szNewFileName, lcFileLocale)) != NULL) nError = ERROR_ALREADY_EXISTS; } // We have to know the decryption key, otherwise we cannot re-crypt // the file after renaming if(nError == ERROR_SUCCESS) { // Save block table index and remove the hash table entry dwOldBlockIndex = pOldHash->dwBlockIndex; lcSaveLocale = pOldHash->lcLocale; pBlock = ha->pBlockTable + dwOldBlockIndex; // If the file is encrypted, we have to re-crypt the file content // with the new decryption key if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED) { hf = CreateMpqFile(ha, "<renaming>"); if(hf != NULL) { hf->pHash = pOldHash; hf->pBlock = ha->pBlockTable + dwOldBlockIndex; hf->pBlockEx = ha->pExtBlockTable + dwOldBlockIndex; nError = RecryptFileData(ha, hf, szFileName, szNewFileName); FreeMPQFile(hf); } else { nError = ERROR_NOT_ENOUGH_MEMORY; } } } // Get the hash table entry for the renamed file if(nError == ERROR_SUCCESS) { SListFileRemoveNode(ha, pOldHash); pOldHash->dwName1 = 0xFFFFFFFF; pOldHash->dwName2 = 0xFFFFFFFF; pOldHash->lcLocale = 0xFFFF; pOldHash->wPlatform = 0xFFFF; pOldHash->dwBlockIndex = HASH_ENTRY_DELETED; // Note that this should always succeed; even if the hash table // was full, one entry was freed before. if((pNewHash = FindFreeHashEntry(ha, szNewFileName)) == NULL) nError = ERROR_CAN_NOT_COMPLETE; } // Save the block index and clear the hash entry if(nError == ERROR_SUCCESS) { // Copy the block table index pNewHash->dwBlockIndex = dwOldBlockIndex; pNewHash->lcLocale = (USHORT)lcSaveLocale; ha->dwFlags |= MPQ_FLAG_CHANGED; // Create new name node for the listfile nError = SListFileCreateNode(ha, szNewFileName, pNewHash); } // Resolve error and return if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
// Renames the file within the archive. BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * szNewFileName) { TMPQArchive * ha = (TMPQArchive *)hMPQ; TMPQBlock * pBlock; TMPQHash * pOldHash = NULL; // Hash entry for the original file TMPQHash * pNewHash = NULL; // Hash entry for the renamed file DWORD dwSaveBlockIndex = 0; LCID lcSaveLocale = 0; int nError = ERROR_SUCCESS; // Test the valid parameters if(nError == ERROR_SUCCESS) { if(hMPQ == NULL || szNewFileName == NULL || *szNewFileName == 0) nError = ERROR_INVALID_PARAMETER; if(szFileName == NULL || *szFileName == 0) nError = ERROR_INVALID_PARAMETER; } // Do not allow to rename listfile if(nError == ERROR_SUCCESS) { if(!_stricmp(szFileName, LISTFILE_NAME)) nError = ERROR_ACCESS_DENIED; } // Get the hash table entry for the original file if(nError == ERROR_SUCCESS) { if((pOldHash = GetHashEntryEx(ha, szFileName, lcLocale)) == NULL) nError = ERROR_FILE_NOT_FOUND; } // Test if the file already exists in the archive if(nError == ERROR_SUCCESS) { if((pNewHash = GetHashEntryEx(ha, szNewFileName, pOldHash->lcLocale)) != NULL) nError = ERROR_ALREADY_EXISTS; } // We have to know the decryption seed, otherwise we cannot re-crypt // the file after renaming if(nError == ERROR_SUCCESS) { // Save block table index and remove the hash table entry dwSaveBlockIndex = pOldHash->dwBlockIndex; lcSaveLocale = pOldHash->lcLocale; pBlock = ha->pBlockTable + dwSaveBlockIndex; // If the file is encrypted, we have to re-crypt the file content // with the new decryption seed if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED) { nError = RecryptFileData(ha, dwSaveBlockIndex, szFileName, szNewFileName); } } // Get the hash table entry for the renamed file if(nError == ERROR_SUCCESS) { SListFileRemoveNode(ha, szFileName, lcSaveLocale); pOldHash->dwName1 = 0xFFFFFFFF; pOldHash->dwName2 = 0xFFFFFFFF; pOldHash->lcLocale = 0xFFFF; pOldHash->wPlatform = 0xFFFF; pOldHash->dwBlockIndex = HASH_ENTRY_DELETED; if((pNewHash = FindFreeHashEntry(ha, szNewFileName)) == NULL) nError = ERROR_CAN_NOT_COMPLETE; } // Save the block index and clear the hash entry if(nError == ERROR_SUCCESS) { // Copy the block table index pNewHash->dwBlockIndex = dwSaveBlockIndex; pNewHash->lcLocale = (USHORT)lcSaveLocale; ha->dwFlags |= MPQ_FLAG_CHANGED; // Create new name node for the listfile nError = SListFileCreateNode(ha, szNewFileName, lcSaveLocale); } // Resolve error and return if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }