예제 #1
0
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;
}
예제 #2
0
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);
        }
    }
예제 #3
0
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;
}
예제 #4
0
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);
}
예제 #5
0
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;
}
예제 #6
0
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]);
}