static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD * pFileSeeds) { TMPQHash * pHashTableCopy = NULL; // Copy of the hash table TMPQHash * pHash; TMPQHash * pHashEnd = NULL; // End of the hash table DWORD dwFileCount = 0; int nError = ERROR_SUCCESS; // First of all, create a copy of hash table if(nError == ERROR_SUCCESS) { if((pHashTableCopy = CopyHashTable(ha)) == NULL) nError = ERROR_NOT_ENOUGH_MEMORY; pHashEnd = pHashTableCopy + ha->pHeader->dwHashTableSize; // Notify the user if(CompactCB != NULL) CompactCB(lpUserData, CCB_CHECKING_FILES, 0, ha->pHeader->dwBlockTableSize); } // Now check all the files from the filelist if(nError == ERROR_SUCCESS) { SFILE_FIND_DATA wf; HANDLE hFind = SFileFindFirstFile((HANDLE)ha, "*", &wf, szListFile); BOOL bResult = TRUE; // Do while some files have been found while(hFind != NULL && bResult) { TMPQHash * pHash = GetHashEntry(ha, wf.cFileName); // If the hash table entry has been found, find it's position // in the hash table copy if(pHash != NULL) { pHash = pHashTableCopy + (pHash - ha->pHashTable); if(pHash->dwName1 != (DWORD)-1 && pHash->dwName2 != (DWORD)-1) { TMPQBlock * pBlock = ha->pBlockTable + pHash->dwBlockIndex; DWORD dwSeed = 0; // Resolve the file seed. Use plain file name for it if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED) { char * szFileName = strrchr(wf.cFileName, '\\'); if(szFileName == NULL) szFileName = wf.cFileName; else szFileName++; dwSeed = DecryptFileSeed(szFileName); if(pBlock->dwFlags & MPQ_FILE_FIXSEED) dwSeed = (dwSeed + pBlock->dwFilePos) ^ pBlock->dwFSize; } pFileSeeds[pHash->dwBlockIndex] = dwSeed; pHash->dwName1 = 0xFFFFFFFF; pHash->dwName2 = 0xFFFFFFFF; pHash->lcLocale = 0xFFFF; pHash->wPlatform = 0xFFFF; pHash->dwBlockIndex = 0xFFFFFFFF; } } // Notify the user if(CompactCB != NULL) CompactCB(lpUserData, CCB_CHECKING_FILES, ++dwFileCount, ha->pHeader->dwBlockTableSize); // Find the next file in the archive bResult = SFileFindNextFile(hFind, &wf); } if(hFind != NULL) SFileFindClose(hFind); } // When the filelist checking is complete, parse the hash table copy and find the if(nError == ERROR_SUCCESS) { // Notify the user about checking hash table dwFileCount = 0; if(CompactCB != NULL) CompactCB(lpUserData, CCB_CHECKING_HASH_TABLE, dwFileCount, ha->pHeader->dwBlockTableSize); for(pHash = pHashTableCopy; pHash < pHashEnd; pHash++) { // If there is an unresolved entry, try to detect its seed. If it fails, // we cannot complete the work if(pHash->dwName1 != (DWORD)-1 && pHash->dwName2 != (DWORD)-1) { HANDLE hFile = NULL; DWORD dwFlags = 0; DWORD dwSeed = 0; if(SFileOpenFileEx((HANDLE)ha, (char *)(DWORD_PTR)pHash->dwBlockIndex, SFILE_OPEN_BY_INDEX, &hFile)) { TMPQFile * hf = (TMPQFile *)hFile; dwFlags = hf->pBlock->dwFlags; dwSeed = hf->dwSeed1; SFileCloseFile(hFile); } // If the file is encrypted, we have to check // If we can apply the file decryption seed if(dwFlags & MPQ_FILE_ENCRYPTED && dwSeed == 0) { nError = ERROR_CAN_NOT_COMPLETE; break; } // Remember the seed pFileSeeds[pHash->dwBlockIndex] = dwSeed; // Notify the user if(CompactCB != NULL) CompactCB(lpUserData, CCB_CHECKING_HASH_TABLE, ++dwFileCount, ha->pHeader->dwBlockTableSize); } } } // Delete the copy of hash table if(pHashTableCopy != NULL) FREEMEM(pHashTableCopy); return nError; }
static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD * pFileKeys) { TMPQHash * pHashTableCopy = NULL; // Copy of the hash table TMPQHash * pHash; TMPQHash * pHashEnd = NULL; // End of the hash table DWORD dwFileCount = 0; int nError = ERROR_SUCCESS; // First of all, create a copy of hash table if(nError == ERROR_SUCCESS) { if((pHashTableCopy = CopyHashTable(ha)) == NULL) nError = ERROR_NOT_ENOUGH_MEMORY; pHashEnd = pHashTableCopy + ha->pHeader->dwHashTableSize; // Notify the user if(CompactCB != NULL) CompactCB(pvUserData, CCB_CHECKING_FILES, &CompactBytesProcessed, &CompactTotalBytes); } // Now check all the files from the listfile if(nError == ERROR_SUCCESS) { SFILE_FIND_DATA wf; HANDLE hFind = SFileFindFirstFile((HANDLE)ha, "*", &wf, szListFile); bool bResult = true; // Do while something has been found while(hFind != NULL && bResult) { TMPQHash * pHash = ha->pHashTable + wf.dwHashIndex; // Find the entry in the hash table copy pHash = pHashTableCopy + (pHash - ha->pHashTable); if(pHash->dwBlockIndex != HASH_ENTRY_FREE) { TMPQBlock * pBlock = ha->pBlockTable + pHash->dwBlockIndex; DWORD dwFileKey = 0; // Resolve the file key. Use plain file name for it if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED) { const char * szPlainName = GetPlainMpqFileName(wf.cFileName); dwFileKey = DecryptFileKey(szPlainName); if(pBlock->dwFlags & MPQ_FILE_FIX_KEY) dwFileKey = (dwFileKey + pBlock->dwFilePos) ^ pBlock->dwFSize; } // Give the key to the caller pFileKeys[pHash->dwBlockIndex] = dwFileKey; pHash->dwName1 = 0xFFFFFFFF; pHash->dwName2 = 0xFFFFFFFF; pHash->lcLocale = 0xFFFF; pHash->wPlatform = 0xFFFF; pHash->dwBlockIndex = HASH_ENTRY_FREE; } // Find the next file in the archive bResult = SFileFindNextFile(hFind, &wf); } if(hFind != NULL) SFileFindClose(hFind); } // When the filelist checking is complete, parse the hash table copy and find the if(nError == ERROR_SUCCESS) { // Notify the user about checking hash table dwFileCount = 0; if(CompactCB != NULL) CompactCB(pvUserData, CCB_CHECKING_HASH_TABLE, &CompactBytesProcessed, &CompactTotalBytes); for(pHash = pHashTableCopy; pHash < pHashEnd; pHash++) { // If there is an unresolved entry, try to detect its key. If it fails, // we cannot complete the work if(pHash->dwBlockIndex < ha->pHeader->dwBlockTableSize) { HANDLE hFile = NULL; DWORD dwFlags = 0; DWORD dwFileKey = 0; if(SFileOpenFileEx((HANDLE)ha, (char *)(DWORD_PTR)pHash->dwBlockIndex, SFILE_OPEN_BY_INDEX, &hFile)) { TMPQFile * hf = (TMPQFile *)hFile; dwFlags = hf->pBlock->dwFlags; dwFileKey = hf->dwFileKey; SFileCloseFile(hFile); } // If the file is encrypted, we have to check // If we can apply the file decryption key if((dwFlags & MPQ_FILE_ENCRYPTED) && dwFileKey == 0) { nError = ERROR_CAN_NOT_COMPLETE; break; } // Give the key to the caller pFileKeys[pHash->dwBlockIndex] = dwFileKey; } } } // Delete the copy of hash table if(pHashTableCopy != NULL) FREEMEM(pHashTableCopy); return nError; }