static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch) { TFileEntry * pFileTableEnd; TFileEntry * pFileEntry; TFileEntry * pBaseEntry; const char * szPlainName; char * szLstFileName; size_t cchWorkBuffer = 0x400; size_t cchBaseName; size_t cchDirName; bool bResult = false; // Find a *-md5.lst file in the base archive pBaseEntry = FindMd5ListFile(haBase); if(pBaseEntry == NULL) return false; cchBaseName = strlen(pBaseEntry->szFileName) + 1; // Allocate working buffer for merging LST file szLstFileName = STORM_ALLOC(char, cchWorkBuffer); if(szLstFileName != NULL) { // Find that file in the patch MPQ pFileTableEnd = haPatch->pFileTable + haPatch->dwFileTableSize; for(pFileEntry = haPatch->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) { // Find the "(patch_metadata)" file within that folder // Note that the file is always relatively small and contains the patch prefix // Checking for file size greatly speeds up the search process if(pFileEntry->szFileName && !(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) && (0 < pFileEntry->dwFileSize && pFileEntry->dwFileSize < 0x40)) { // If the plain file name matches, we need to check its MD5 szPlainName = GetPlainFileName(pFileEntry->szFileName); cchDirName = (size_t)(szPlainName - pFileEntry->szFileName); // The file name must not too long and must be PATCH_METADATA_NAME if((cchDirName + cchBaseName) < cchWorkBuffer && _stricmp(szPlainName, PATCH_METADATA_NAME) == 0) { // Construct the name of the eventuall LST file memcpy(szLstFileName, pFileEntry->szFileName, cchDirName); memcpy(szLstFileName + cchDirName, pBaseEntry->szFileName, cchBaseName); // If there is the "*-md5.lst" file in that directory, we check its MD5 if(IsMatchingPatchFile(haPatch, szLstFileName, pBaseEntry->md5)) { bResult = CreatePatchPrefix(haPatch, pFileEntry->szFileName, szPlainName); break; } } } } // Free the work buffer STORM_FREE(szLstFileName); } return bResult; }
static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch) { TMPQNamePrefix * pPatchPrefix; TFileEntry * pBaseEntry; char * szLstFileName; char * szPlainName; size_t cchWorkBuffer = 0x400; bool bResult = false; // First-level patches: Find the same file within the patch archive // and verify by MD5-before-patch if(haBase->haPatch == NULL) { TFileEntry * pFileTableEnd = haPatch->pFileTable + haPatch->dwFileTableSize; TFileEntry * pFileEntry; // Allocate working buffer for merging LST file szLstFileName = STORM_ALLOC(char, cchWorkBuffer); if(szLstFileName != NULL) { // Find a *-md5.lst file in the base archive pBaseEntry = FindBaseLstFile(haBase); if(pBaseEntry == NULL) { STORM_FREE(szLstFileName); return false; } // Parse the entire file table for(pFileEntry = haPatch->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) { // Look for "patch_metadata" file if(IsPatchMetadataFile(pFileEntry)) { // Construct the name of the MD5 file strcpy(szLstFileName, pFileEntry->szFileName); szPlainName = (char *)GetPlainFileName(szLstFileName); strcpy(szPlainName, pBaseEntry->szFileName); // Check for matching MD5 file if(IsMatchingPatchFile(haPatch, szLstFileName, pBaseEntry->md5)) { bResult = CreatePatchPrefix(haPatch, szLstFileName, (size_t)(szPlainName - szLstFileName)); break; } } } // Delete the merge buffer STORM_FREE(szLstFileName); } }
static bool FindPatchPrefix(TMPQArchive * haBase, TMPQArchive * haPatch, const char * szPatchPathPrefix) { // If the patch prefix was explicitly entered, we use that one if(szPatchPathPrefix != NULL) return CreatePatchPrefix(haPatch, szPatchPathPrefix, szPatchPathPrefix + strlen(szPatchPathPrefix)); // Patches for World of Warcraft - mostly the do not use prefix. // Those who do, they have the (patch_metadata) file present in the "base" subdirectory. // All patches that use patch prefix have the "base\\(patch_metadata) file present if(GetFileEntryAny(haPatch, "base\\" PATCH_METADATA_NAME)) return FindPatchPrefix_WoW_13164_13623(haBase, haPatch); // Updates for Starcraft II // Match: LocalizedData\GameHotkeys.txt <==> Campaigns\Liberty.SC2Campaign\enGB.SC2Data\LocalizedData\GameHotkeys.txt // All Starcraft II base archives seem to have the file "StreamingBuckets.txt" present if(GetFileEntryAny(haBase, "StreamingBuckets.txt")) return FindPatchPrefix_SC2(haBase, haPatch); // Diablo III patch MPQs don't use patch prefix // Hearthstone MPQs don't use patch prefix CreatePatchPrefix(haPatch, NULL, NULL); return true; }
static bool FindPatchPrefix_WoW_13164_13623(TMPQArchive * haBase, TMPQArchive * haPatch) { const char * szPatchPrefix; char szNamePrefix[0x08]; // Try to find the language of the MPQ archive szPatchPrefix = FindArchiveLanguage(haBase, LocaleMpqs_WoW); if(szPatchPrefix == NULL) szPatchPrefix = "Base"; // Format the patch prefix szNamePrefix[0] = szPatchPrefix[0]; szNamePrefix[1] = szPatchPrefix[1]; szNamePrefix[2] = szPatchPrefix[2]; szNamePrefix[3] = szPatchPrefix[3]; szNamePrefix[4] = '\\'; szNamePrefix[5] = 0; return CreatePatchPrefix(haPatch, szNamePrefix, 5); }
static bool CheckAndCreatePatchPrefix(TMPQArchive * ha, const char * szPatchPrefix, size_t nLength) { char szTempName[MAX_SC2_PATCH_PREFIX + 0x41]; bool bResult = false; // Prepare the patch file name if(nLength > MAX_SC2_PATCH_PREFIX) return false; // Prepare the patched file name memcpy(szTempName, szPatchPrefix, nLength); memcpy(&szTempName[nLength], "\\(patch_metadata)", 18); // Verifywhether that file exists if(GetFileEntryLocale(ha, szTempName, 0) != NULL) bResult = CreatePatchPrefix(ha, szPatchPrefix, nLength); return bResult; }
static bool FindPatchPrefix_WoW_13164_13623(TMPQArchive * haBase, TMPQArchive * haPatch) { TFileEntry * pFileEntry; const char * szFilePrefix = "Base"; const char * szLanguage; char szNamePrefix[0x10]; int nLength; // Find a *-md5.lst file in the base archive pFileEntry = FindMd5ListFile(haBase); if(pFileEntry == NULL) return false; // Language-specific MPQs have the language identifier right before extension szLanguage = GetLstFileLanguage(pFileEntry->szFileName); if(szLanguage != NULL) szFilePrefix = szLanguage; // Format the name prefix nLength = sprintf(szNamePrefix, "%s\\", szFilePrefix); return CreatePatchPrefix(haPatch, szNamePrefix, &szNamePrefix[nLength]); }