Exemple #1
0
static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry)
{
    TFileEntry * pPatchEntry = NULL;
    TFileEntry * pTempEntry;
    char szFileName[MAX_PATH];
    LCID lcLocale = pFileEntry->lcLocale;

    // Go while there are patches
    while(ha->haPatch != NULL)
    {
        // Move to the patch archive
        ha = ha->haPatch;

        // Prepare the prefix for the file name
        strcpy(szFileName, ha->szPatchPrefix);
        strcat(szFileName, pFileEntry->szFileName);

        // Try to find the file there
        pTempEntry = GetFileEntryExact(ha, szFileName, lcLocale);
        if(pTempEntry != NULL)
            pPatchEntry = pTempEntry;
    }

    // Return the found patch entry
    return pPatchEntry;
}
static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry)
{
    TFileEntry * pPatchEntry = NULL;
    TFileEntry * pTempEntry;
    char szFileName[MAX_PATH+1];

    // Go while there are patches
    while(ha->haPatch != NULL)
    {
        // Move to the patch archive
        ha = ha->haPatch;
        szFileName[0] = 0;

        // Prepare the prefix for the file name
        if(ha->pPatchPrefix != NULL)
            StringCopyA(szFileName, ha->pPatchPrefix->szPatchPrefix, MAX_PATH);
        StringCatA(szFileName, pFileEntry->szFileName, MAX_PATH);

        // Try to find the file there
        pTempEntry = GetFileEntryExact(ha, szFileName, 0, NULL);
        if(pTempEntry != NULL)
            pPatchEntry = pTempEntry;
    }

    // Return the found patch entry
    return pPatchEntry;
}
static bool IsBaseFileMissing(
    TMPQArchive * ha,
    const char * szFileName1,       // File name with prefix
    const char * szFileName2,       // File name without prefix
    LCID lcLocale)
{
    TFileEntry * pTempEntry;
    const char * szFileName;
    bool bBaseFileMissing = true;

    while(ha != NULL)
    {
        // If this patch file uses patch prefix, include it.
        // Otherwise, use non-prefixed file name
        szFileName = (ha->szPatchPrefix[0] != 0) ? szFileName1 : szFileName2;

        // Check if the file in this MPQ is patch file or not
        pTempEntry = GetFileEntryExact(ha, szFileName, lcLocale);
        if(pTempEntry != NULL)
            bBaseFileMissing = (pTempEntry->dwFlags & MPQ_FILE_PATCH_FILE) ? true : false;

        // Go one MPQ lower
        ha = ha->haBase;
    }

    // Return what we found
    return bBaseFileMissing;
}
Exemple #4
0
static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry)
{
    TFileEntry * pPatchEntry = pFileEntry;
    TFileEntry * pTempEntry;
    char szFileName[MAX_PATH+1];

    // Can't find patch entry for a file that doesn't have name
    if(pFileEntry->szFileName != NULL && pFileEntry->szFileName[0] != 0)
    {
        // Go while there are patches
        while(ha->haPatch != NULL)
        {
            // Move to the patch archive
            ha = ha->haPatch;
            szFileName[0] = 0;

            // Prepare the prefix for the file name
            if(ha->pPatchPrefix && ha->pPatchPrefix->nLength)
                StringCopy(szFileName, _countof(szFileName), ha->pPatchPrefix->szPatchPrefix);
            StringCat(szFileName, _countof(szFileName), pFileEntry->szFileName);

            // Try to find the file there
            pTempEntry = GetFileEntryExact(ha, szFileName, 0, NULL);
            if(pTempEntry != NULL)
                pPatchEntry = pTempEntry;
        }
    }

    // Return the found patch entry
    return pPatchEntry;
}
bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
{
    TMPQArchive * ha;
    TFileEntry * pFileEntry;
    TMPQFile * hf = IsValidFileHandle(hFile);

    // Invalid handle => do nothing
    if(hf == NULL)
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    // Do not allow to rename files in MPQ open for read only
    ha = hf->ha;
    if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
    {
        SetLastError(ERROR_ACCESS_DENIED);
        return false;
    }

    // Do not allow unnamed access
    if(hf->pFileEntry->szFileName == NULL)
    {
        SetLastError(ERROR_CAN_NOT_COMPLETE);
        return false;
    }

    // Do not allow to change locale of any internal file
    if(IsInternalMpqFileName(hf->pFileEntry->szFileName))
    {
        SetLastError(ERROR_INTERNAL_FILE);
        return false;
    }

    // Do not allow changing file locales if there is no hash table
    if(hf->pHashEntry == NULL)
    {
        SetLastError(ERROR_NOT_SUPPORTED);
        return false;
    }

    // We have to check if the file+locale is not already there
    pFileEntry = GetFileEntryExact(ha, hf->pFileEntry->szFileName, lcNewLocale, NULL);
    if(pFileEntry != NULL)
    {
        SetLastError(ERROR_ALREADY_EXISTS);
        return false;
    }

    // Update the locale in the hash table entry
    hf->pHashEntry->lcLocale = (USHORT)lcNewLocale;
    ha->dwFlags |= MPQ_FLAG_CHANGED;
    return true;
}
int SFileAddFile_Init(
    TMPQArchive * ha,
    const char * szFileName,
    ULONGLONG FileTime,
    DWORD dwFileSize,
    LCID lcLocale,
    DWORD dwFlags,
    TMPQFile ** phf)
{
    TFileEntry * pFileEntry = NULL;
    TMPQFile * hf = NULL;               // File structure for newly added file
    DWORD dwHashIndex = HASH_ENTRY_FREE;
    int nError = ERROR_SUCCESS;

    //
    // Note: This is an internal function so no validity checks are done.
    // It is the caller's responsibility to make sure that no invalid
    // flags get to this point
    //

    // Sestor CRC is not allowed with single unit files
    if(dwFlags & MPQ_FILE_SINGLE_UNIT)
        dwFlags &= ~MPQ_FILE_SECTOR_CRC;

    // Sector CRC is not allowed if the file is not compressed
    if(!(dwFlags & MPQ_FILE_COMPRESS_MASK))
        dwFlags &= ~MPQ_FILE_SECTOR_CRC;
    
    // Fix Key is not allowed if the file is not enrypted
    if(!(dwFlags & MPQ_FILE_ENCRYPTED))
        dwFlags &= ~MPQ_FILE_FIX_KEY;

    // If the MPQ is of version 3.0 or higher, we ignore file locale.
    // This is because HET and BET tables have no known support for it
    if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_3)
        lcLocale = 0;

    // Allocate the TMPQFile entry for newly added file
    hf = CreateWritableHandle(ha, dwFileSize);
    if(hf == NULL)
        return false;

    // Allocate file entry in the MPQ
    if(nError == ERROR_SUCCESS)
    {
        // Check if the file already exists in the archive
        pFileEntry = GetFileEntryExact(ha, szFileName, lcLocale, &dwHashIndex);
        if(pFileEntry != NULL)
        {
            if(dwFlags & MPQ_FILE_REPLACEEXISTING)
                InvalidateInternalFiles(ha);
            else
                nError = ERROR_ALREADY_EXISTS;
        }
        else
        {
            // Free all internal files - (listfile), (attributes), (signature)
            InvalidateInternalFiles(ha);
            
            // Attempt to allocate new file entry
            pFileEntry = AllocateFileEntry(ha, szFileName, lcLocale, &dwHashIndex);
            if(pFileEntry == NULL)
                nError = ERROR_DISK_FULL;   
        }

        // Set the file entry to the file structure
        hf->pFileEntry = pFileEntry;
    }

    // Prepare the pointer to hash table entry
    if(nError == ERROR_SUCCESS && ha->pHashTable != NULL && dwHashIndex < ha->pHeader->dwHashTableSize)
    {
        hf->pHashEntry = ha->pHashTable + dwHashIndex;
        hf->pHashEntry->lcLocale = (USHORT)lcLocale;
    }

    // Prepare the file key
    if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED))
    {
        hf->dwFileKey = DecryptFileKey(szFileName, hf->MpqFilePos, dwFileSize, dwFlags);
        if(hf->dwFileKey == 0)
            nError = ERROR_UNKNOWN_FILE_KEY;
    }

    // Fill the file entry and TMPQFile structure
    if(nError == ERROR_SUCCESS)
    {
        // At this point, the file name in the file entry must be set
        assert(pFileEntry->szFileName != NULL);
        assert(_stricmp(pFileEntry->szFileName, szFileName) == 0);

        nError = FillWritableHandle(ha, hf, FileTime, dwFileSize, dwFlags);
    }

    // Free the file handle if failed
    if(nError != ERROR_SUCCESS && hf != NULL)
        FreeFileHandle(hf);

    // Give the handle to the caller
    *phf = hf;
    return nError;
}
Exemple #7
0
bool OpenPatchedFile(HANDLE hMpq, const char * szFileName, DWORD dwReserved, HANDLE * phFile)
{
    TMPQArchive * haBase = NULL;
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TFileEntry * pFileEntry;
    TMPQFile * hfPatch;                     // Pointer to patch file
    TMPQFile * hfBase = NULL;               // Pointer to base open file
    TMPQFile * hf = NULL;
    HANDLE hPatchFile;
    char szPrefixBuffer[MAX_PATH];

    // Keep this flag here for future updates
    dwReserved = dwReserved;

    // First of all, find the latest archive where the file is in base version
    // (i.e. where the original, unpatched version of the file exists)
    while(ha != NULL)
    {
        // If the file is there, then we remember the archive
        pFileEntry = GetFileEntryExact(ha, GetPatchFileName(ha, szFileName, szPrefixBuffer), 0);
        if(pFileEntry != NULL && (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
            haBase = ha;

        // Move to the patch archive
        ha = ha->haPatch;
    }

    // If we couldn't find the base file in any of the patches, it doesn't exist
    if((ha = haBase) == NULL)
    {
        SetLastError(ERROR_FILE_NOT_FOUND);
        return false;
    }

    // Now open the base file
    if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szPrefixBuffer), SFILE_OPEN_BASE_FILE, (HANDLE *)&hfBase))
    {
        // The file must be a base file, i.e. without MPQ_FILE_PATCH_FILE
        assert((hfBase->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0);
        hf = hfBase;

        // Now open all patches and attach them on top of the base file
        for(ha = ha->haPatch; ha != NULL; ha = ha->haPatch)
        {
            // Prepare the file name with a correct prefix
            if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szPrefixBuffer), SFILE_OPEN_BASE_FILE, &hPatchFile))
            {
                // Remember the new version
                hfPatch = (TMPQFile *)hPatchFile;

                // We should not find patch file
                assert((hfPatch->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) != 0);

                // Attach the patch to the base file
                hf->hfPatch = hfPatch;
                hf = hfPatch;
            }
        }
    }

    // Give the updated base MPQ
    if(phFile != NULL)
        *phFile = (HANDLE)hfBase;
    return true;
}