Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
bool WINAPI SFileCloseFile(HANDLE hFile)
{
    TMPQFile * hf = (TMPQFile *)hFile;

    if (!IsValidFileHandle(hf))
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    // Free the structure
    FreeMPQFile(hf);
    return true;
}
Exemplo n.º 3
0
bool OpenPatchedFile(HANDLE hMpq, const char * szFileName, DWORD dwReserved, HANDLE * phFile)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TMPQFile * hfPatch;                     // Pointer to patch file
    TMPQFile * hfBase = NULL;               // Pointer to base open file
    TMPQFile * hfLast;                      // The highest file in the chain that is not patch file
    TMPQFile * hf;
    HANDLE hPatchFile;
    char szPatchFileName[MAX_PATH];

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

    // First of all, try to open the original version of the file in any of the patch chain
    while(ha != NULL)
    {
        // Construct the name of the patch file
        strcpy(szPatchFileName, ha->szPatchPrefix);
        strcat(szPatchFileName, szFileName);
        if (SFileOpenFileEx((HANDLE)ha, szPatchFileName, SFILE_OPEN_FROM_MPQ, phFile))
        {
            hfBase = (TMPQFile *)(*phFile);
            break;
        }

        // Move to the next file in the patch chain
        ha = ha->haPatch;
    }

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

    // At this point, we require that the open file is not a patch
    if (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
    {
        FreeMPQFile(hf);
        SetLastError(ERROR_FILE_NOT_FOUND);
        return false;
    }

    // Move to the patch MPQ
    ha = ha->haPatch;

    // Now keep going in the patch chain and open every patch file that is there
    while(ha != NULL)
    {
        // Construct patch file name
        strcpy(szPatchFileName, ha->szPatchPrefix);
        strcat(szPatchFileName, szFileName);
        if (SFileOpenFileEx((HANDLE)ha, szPatchFileName, SFILE_OPEN_FROM_MPQ, &hPatchFile))
        {
            // Remember the new version
            hfPatch = (TMPQFile *)hPatchFile;

            // If we encountered a full replacement of the file,
            // we have to remember the highest full file
            if ((hfPatch->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
                hfLast = hfPatch;

            // Set current patch tobase file and move on
            hf->hfPatchFile = hfPatch;
            hf = hfPatch;
        }

        // Move to the next patch in the chain
        ha = ha->haPatch;
    }

    // Now we need to free all files that are below the highest unpatched version
    while(hfBase != hfLast)
    {
        TMPQFile * hfNext = hfBase->hfPatchFile;

        // Free the file below
        hfBase->hfPatchFile = NULL;
        FreeMPQFile(hfBase);

        // Move the base to the next file
        hfBase = hfNext;
    }

    // Give the updated base MPQ
    if (phFile != NULL)
        *phFile = (HANDLE)hfBase;
    return true;
}
Exemplo n.º 4
0
bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TFileEntry  * pFileEntry = NULL;
    TMPQFile    * hf = NULL;
    DWORD dwBlockIndex = 0;             // Found table index
    int nError = ERROR_SUCCESS;

    // Don't accept NULL pointer to file handle
    if (phFile == NULL)
        nError = ERROR_INVALID_PARAMETER;

    // Prepare the file opening
    if (nError == ERROR_SUCCESS)
    {
        switch(dwSearchScope)
        {
            case SFILE_OPEN_PATCHED_FILE:

                // We want to open the updated version of the file
                return OpenPatchedFile(hMpq, szFileName, 0, phFile);

            case SFILE_OPEN_FROM_MPQ:

                if (!IsValidMpqHandle(ha))
                {
                    nError = ERROR_INVALID_HANDLE;
                    break;
                }

                if (szFileName == NULL || *szFileName == 0)
                {
                    nError = ERROR_INVALID_PARAMETER;
                    break;
                }

                // First of all, check the name as-is
                pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale);
                if (pFileEntry != NULL)
                    break;

                // If the file doesn't exist in the MPQ, check file pseudo-name ("FileXXXXXXXX.ext")
                if (!IsPseudoFileName(szFileName, &dwBlockIndex))
                {
                    nError = ERROR_FILE_NOT_FOUND;
                    break;
                }

                // Set the file name to the file index and fall through
                szFileName = (const char *)(DWORD_PTR)dwBlockIndex;
                dwSearchScope = SFILE_OPEN_BY_INDEX;
                // No break here, fall through.

            case SFILE_OPEN_BY_INDEX:

                if (!IsValidMpqHandle(ha))
                {
                    nError = ERROR_INVALID_HANDLE;
                    break;
                }

                // Set handle size to be sizeof(TMPQFile) + length of FileXXXXXXXX.xxx
                pFileEntry = GetFileEntryByIndex(ha, (DWORD)(DWORD_PTR)szFileName);
                if (pFileEntry == NULL)
                    nError = ERROR_FILE_NOT_FOUND;
                break;

            case SFILE_OPEN_ANY_LOCALE:

                // This open option is reserved for opening MPQ internal listfile.
                // No argument validation. Tries to open file with neutral locale first,
                // then any other available.
                dwSearchScope = SFILE_OPEN_FROM_MPQ;
                pFileEntry = GetFileEntryAny(ha, szFileName);
                if (pFileEntry == NULL)
                    nError = ERROR_FILE_NOT_FOUND;
                break;

            case SFILE_OPEN_LOCAL_FILE:

                if (szFileName == NULL || *szFileName == 0)
                {
                    nError = ERROR_INVALID_PARAMETER;
                    break;
                }

                return OpenLocalFile(szFileName, phFile);

            default:

                // Don't accept any other value
                nError = ERROR_INVALID_PARAMETER;
                break;
        }

        // Quick return if something failed
        if (nError != ERROR_SUCCESS)
        {
            SetLastError(nError);
            return false;
        }
    }

    // Test if the file was not already deleted.
    if (nError == ERROR_SUCCESS)
    {
        if ((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
            nError = ERROR_FILE_NOT_FOUND;
        if (pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS)
            nError = ERROR_NOT_SUPPORTED;
    }

    // Allocate file handle
    if (nError == ERROR_SUCCESS)
    {
        if ((hf = ALLOCMEM(TMPQFile, 1)) == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
    }

    // Initialize file handle
    if (nError == ERROR_SUCCESS)
    {
        memset(hf, 0, sizeof(TMPQFile));
        hf->pFileEntry = pFileEntry;
        hf->dwMagic = ID_MPQ_FILE;
        hf->ha = ha;

        hf->MpqFilePos   = pFileEntry->ByteOffset;
        hf->RawFilePos   = ha->MpqPos + hf->MpqFilePos;

        hf->dwDataSize   = pFileEntry->dwFileSize;
        hf->dwHashIndex  = pFileEntry->dwHashIndex;
        hf->dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);

        // If the MPQ has sector CRC enabled, enable if for the file
        if (ha->dwFlags & MPQ_FLAG_CHECK_SECTOR_CRC)
            hf->bCheckSectorCRCs = true;

        // Decrypt file key. Cannot be used if the file is given by index
        if (dwSearchScope == SFILE_OPEN_FROM_MPQ)
        {
            if (pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
            {
                hf->dwFileKey = DecryptFileKey(szFileName,
                                               pFileEntry->ByteOffset,
                                               pFileEntry->dwFileSize,
                                               pFileEntry->dwFlags);
            }
        }
        else
        {
            // If the file is encrypted and not compressed, we cannot detect the file key
            if (!SFileGetFileName(hf, NULL))
                nError = GetLastError();
        }
    }

    // If the file is actually a patch file, we have to load the patch file header
    if (nError == ERROR_SUCCESS && pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
    {
        assert(hf->PatchInfo == NULL);
        nError = AllocatePatchInfo(hf, true);
    }

    // Cleanup
    if (nError != ERROR_SUCCESS)
    {
        SetLastError(nError);
        FreeMPQFile(hf);
    }

    *phFile = hf;
    return (nError == ERROR_SUCCESS);
}
Exemplo n.º 5
0
static int CopyMpqFiles(TMPQArchive * ha, LPDWORD pFileKeys, TFileStream * pNewStream)
{
    TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
    TFileEntry * pFileEntry;
    TMPQFile * hf = NULL;
    int nError = ERROR_SUCCESS;

    // Walk through all files and write them to the destination MPQ archive
    for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
    {
        // Copy all the file sectors
        // Only do that when the file has nonzero size
        if ((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->dwFileSize != 0)
        {
            // Allocate structure for the MPQ file
            hf = CreateMpqFile(ha);
            if (hf == NULL)
                return ERROR_NOT_ENOUGH_MEMORY;

            // Store file entry
            hf->pFileEntry = pFileEntry;

            // Set the raw file position
            hf->MpqFilePos = pFileEntry->ByteOffset;
            hf->RawFilePos = ha->MpqPos + hf->MpqFilePos;

            // Set the file decryption key
            hf->dwFileKey = pFileKeys[pFileEntry - ha->pFileTable];
            hf->dwDataSize = pFileEntry->dwFileSize;

            // If the file is a patch file, load the patch header
            if (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
            {
                nError = AllocatePatchInfo(hf, true);
                if (nError != ERROR_SUCCESS)
                    break;
            }

            // Allocate buffers for file sector and sector offset table
            nError = AllocateSectorBuffer(hf);
            if (nError != ERROR_SUCCESS)
                break;

            // Also allocate sector offset table and sector checksum table
            nError = AllocateSectorOffsets(hf, true);
            if (nError != ERROR_SUCCESS)
                break;

            // Also load sector checksums, if any
            if (pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC)
            {
                nError = AllocateSectorChecksums(hf, false);
                if (nError != ERROR_SUCCESS)
                    break;
            }

            // Copy all file sectors
            nError = CopyMpqFileSectors(ha, hf, pNewStream);
            if (nError != ERROR_SUCCESS)
                break;

            // Free buffers. This also sets "hf" to NULL.
            FreeMPQFile(hf);
        }
    }

    // Cleanup and exit
    if (hf != NULL)
        FreeMPQFile(hf);
    return nError;
}
Exemplo n.º 6
0
bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TFileEntry  * pFileEntry = NULL;
    TMPQFile    * hf = NULL;
    DWORD dwFileIndex = 0;
    bool bOpenByIndex = false;
    int nError = ERROR_SUCCESS;

    // Don't accept NULL pointer to file handle
    if(phFile == NULL)
        nError = ERROR_INVALID_PARAMETER;

    // Prepare the file opening
    if(nError == ERROR_SUCCESS)
    {
        switch(dwSearchScope)
        {
            case SFILE_OPEN_FROM_MPQ:
            case SFILE_OPEN_BASE_FILE:
                
                if(!IsValidMpqHandle(ha))
                {
                    nError = ERROR_INVALID_HANDLE;
                    break;
                }

                if(szFileName == NULL || *szFileName == 0)
                {
                    nError = ERROR_INVALID_PARAMETER;
                    break;
                }

                // Check the pseudo-file name
                if(IsPseudoFileName(szFileName, &dwFileIndex))
                {
                    pFileEntry = GetFileEntryByIndex(ha, dwFileIndex);
                    bOpenByIndex = true;
                    if(pFileEntry == NULL)
                        nError = ERROR_FILE_NOT_FOUND;
                }
                else
                {
                    // If this MPQ is a patched archive, open the file as patched
                    if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE)
                    {
                        // Otherwise, open the file from *this* MPQ
                        pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale);
                        if(pFileEntry == NULL)
                            nError = ERROR_FILE_NOT_FOUND;
                    }
                    else
                    {
                        return OpenPatchedFile(hMpq, szFileName, 0, phFile);
                    }
                }
                break;

            case SFILE_OPEN_ANY_LOCALE:

                // This open option is reserved for opening MPQ internal listfile.
                // No argument validation. Tries to open file with neutral locale first,
                // then any other available.
                pFileEntry = GetFileEntryAny(ha, szFileName);
                if(pFileEntry == NULL)
                    nError = ERROR_FILE_NOT_FOUND;
                break;

            case SFILE_OPEN_LOCAL_FILE:

                if(szFileName == NULL || *szFileName == 0)
                {
                    nError = ERROR_INVALID_PARAMETER;
                    break;
                }

                return OpenLocalFile(szFileName, phFile); 

            default:

                // Don't accept any other value
                nError = ERROR_INVALID_PARAMETER;
                break;
        }

        // Quick return if something failed
        if(nError != ERROR_SUCCESS)
        {
            SetLastError(nError);
            return false;
        }
    }

    // Test if the file was not already deleted.
    if(nError == ERROR_SUCCESS)
    {
        if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
            nError = ERROR_FILE_NOT_FOUND;
        if(pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS)
            nError = ERROR_NOT_SUPPORTED;
    }

    // Allocate file handle
    if(nError == ERROR_SUCCESS)
    {
        if((hf = STORM_ALLOC(TMPQFile, 1)) == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
    }

    // Initialize file handle
    if(nError == ERROR_SUCCESS)
    {
        memset(hf, 0, sizeof(TMPQFile));
        hf->pFileEntry = pFileEntry;
        hf->dwMagic = ID_MPQ_FILE;
        hf->ha = ha;

        hf->MpqFilePos   = pFileEntry->ByteOffset;
        hf->RawFilePos   = ha->MpqPos + hf->MpqFilePos;
        hf->dwDataSize   = pFileEntry->dwFileSize;

        // If the MPQ has sector CRC enabled, enable if for the file
        if(ha->dwFlags & MPQ_FLAG_CHECK_SECTOR_CRC)
            hf->bCheckSectorCRCs = true;

        // If we know the real file name, copy it to the file entry
        if(bOpenByIndex == false)
        {
            // If there is no file name yet, allocate it
            AllocateFileName(pFileEntry, szFileName);

            // If the file is encrypted, we should detect the file key
            if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
            {
                hf->dwFileKey = DecryptFileKey(szFileName,
                                               pFileEntry->ByteOffset,
                                               pFileEntry->dwFileSize,
                                               pFileEntry->dwFlags);
            }
        }
        else
        {
            // Try to auto-detect the file name
            if(!SFileGetFileName(hf, NULL))
                nError = GetLastError();
        }
    }

    // If the file is actually a patch file, we have to load the patch file header
    if(nError == ERROR_SUCCESS && pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
    {
        assert(hf->pPatchInfo == NULL);
        nError = AllocatePatchInfo(hf, true);
    }

    // Cleanup
    if(nError != ERROR_SUCCESS)
    {
        SetLastError(nError);
        FreeMPQFile(hf);
    }

    *phFile = hf;
    return (nError == ERROR_SUCCESS);
}
Exemplo n.º 7
0
// 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);
}
Exemplo n.º 8
0
bool OpenPatchedFile(HANDLE hMpq, const char * szFileName, DWORD dwReserved, HANDLE * phFile)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TMPQFile * hfPatch;                     // Pointer to patch file
    TMPQFile * hfBase = NULL;               // Pointer to base open file
    TMPQFile * hfLast = NULL;               // The highest file in the chain that is not patch file
    TMPQFile * hf = NULL;
    HANDLE hPatchFile;
    char szPrefixBuffer[MAX_PATH];

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

    // First of all, try to open the original version of the file in any of the patch chain
    while(ha != NULL)
    {
        // Prepare the file name with a correct prefix
        if(SFileOpenFileEx((HANDLE)ha, GetPrefixedName(ha, szFileName, szPrefixBuffer), SFILE_OPEN_BASE_FILE, (HANDLE *)&hfBase))
        {
            // The file must be a base file, i.e. without MPQ_FILE_PATCH_FILE
            if((hfBase->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
            {
                hf = hfLast = hfBase;
                break;
            }

            SFileCloseFile((HANDLE)hfBase);
        }

        // Move to the next file in the patch chain
        ha = ha->haPatch;
    }

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

    // Now keep going in the patch chain and open every patch file that is there
    for(ha = ha->haPatch; ha != NULL; ha = ha->haPatch)
    {
        // Prepare the file name with a correct prefix
        if(SFileOpenFileEx((HANDLE)ha, GetPrefixedName(ha, szFileName, szPrefixBuffer), SFILE_OPEN_BASE_FILE, &hPatchFile))
        {
            // Remember the new version
            hfPatch = (TMPQFile *)hPatchFile;

            // If we encountered a full replacement of the file, 
            // we have to remember the highest full file
            if((hfPatch->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0)
                hfLast = hfPatch;

            // Set current patch to base file and move on
            hf->hfPatchFile = hfPatch;
            hf = hfPatch;
        }
    }

    // Now we need to free all files that are below the highest unpatched version
    while(hfBase != hfLast)
    {
        TMPQFile * hfNext = hfBase->hfPatchFile;

        // Free the file below
        hfBase->hfPatchFile = NULL;
        FreeMPQFile(hfBase);

        // Move the base to the next file
        hfBase = hfNext;
    }

    // Give the updated base MPQ
    if(phFile != NULL)
        *phFile = (HANDLE)hfBase;
    return true;
}
Exemplo n.º 9
0
static int CopyMpqFiles(TMPQArchive * ha, DWORD * pFileKeys, TFileStream * pNewStream)
{
    TMPQBlockEx * pBlockEx = ha->pExtBlockTable;
    TMPQBlock * pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize;
    TMPQBlock * pBlock;
    TMPQFile * hf = NULL;
    int nError = ERROR_SUCCESS;

    // Walk through all files and write them to the destination MPQ archive
    for(pBlock = ha->pBlockTable; pBlock < pBlockEnd; pBlock++, pBlockEx++)
    {
        // Copy all the file sectors
        // Only do that when the file has nonzero size
        if((pBlock->dwFlags & MPQ_FILE_EXISTS) && pBlock->dwFSize != 0)
        {
            // Allocate structure for the MPQ file
            hf = CreateMpqFile(ha, "<compacting>");
            if(hf == NULL)
                return ERROR_NOT_ENOUGH_MEMORY;

            // Store block positions
            hf->pBlockEx = pBlockEx;
            hf->pBlock = pBlock;

            // Set the raw file position
            hf->MpqFilePos.HighPart = hf->pBlockEx->wFilePosHigh;
            hf->MpqFilePos.LowPart  = hf->pBlock->dwFilePos;
            hf->RawFilePos.QuadPart = ha->MpqPos.QuadPart + hf->MpqFilePos.LowPart;

            // Set the file decryption key
            hf->dwFileKey = pFileKeys[pBlock - ha->pBlockTable];

            // Allocate buffers for file sector and sector offset table
            nError = AllocateSectorBuffer(hf);
            if(nError != ERROR_SUCCESS)
                break;

            // Also allocate sector offset table and sector checksum table
            nError = AllocateSectorOffsets(hf, true);
            if(nError != ERROR_SUCCESS)
                break;

            if(pBlock->dwFlags & MPQ_FILE_SECTOR_CRC)
            {
                nError = AllocateSectorChecksums(hf, false);
                if(nError != ERROR_SUCCESS)
                    break;
            }

            // Copy all file sectors
            nError = CopyMpqFileSectors(ha, hf, pNewStream);
            if(nError != ERROR_SUCCESS)
                break;

            // Free buffers. This also sets "hf" to NULL.
            FreeMPQFile(hf);
        }
    }

    // Cleanup and exit
    if(hf != NULL)
        FreeMPQFile(hf);
    return nError;
}