示例#1
0
// Verifies the archive against the signature
DWORD WINAPI SFileVerifyArchive(HANDLE hMpq)
{
    MPQ_SIGNATURE_INFO si;
    TMPQArchive * ha = (TMPQArchive *)hMpq;

    // Verify input parameters
    if(!IsValidMpqHandle(hMpq))
        return ERROR_VERIFY_FAILED;

    // If the archive was modified, we need to flush it
    if(ha->dwFlags & MPQ_FLAG_CHANGED)
        SFileFlushArchive(hMpq);

    // Get the MPQ signature and signature type
    memset(&si, 0, sizeof(MPQ_SIGNATURE_INFO));
    if(!QueryMpqSignatureInfo(ha, &si))
        return ERROR_VERIFY_FAILED;

    // If there is no signature
    if(si.SignatureTypes == 0)
        return ERROR_NO_SIGNATURE;

    // We haven't seen a MPQ with both signatures
    assert(si.SignatureTypes == SIGNATURE_TYPE_WEAK || si.SignatureTypes == SIGNATURE_TYPE_STRONG);

    // Verify the strong signature, if present
    if(si.SignatureTypes & SIGNATURE_TYPE_STRONG)
        return VerifyStrongSignature(ha, &si);

    // Verify the weak signature, if present
    if(si.SignatureTypes & SIGNATURE_TYPE_WEAK)
        return VerifyWeakSignature(ha, &si);

    return ERROR_NO_SIGNATURE;
}
示例#2
0
// Verifies the archive against the signature
DWORD WINAPI SFileVerifyArchive(HANDLE hMpq)
{
    MPQ_SIGNATURE_INFO si;
    TMPQArchive * ha = (TMPQArchive *)hMpq;

    // Verify input parameters
    if(!IsValidMpqHandle(ha))
        return ERROR_VERIFY_FAILED;

    // Get the MPQ signature and signature type
    memset(&si, 0, sizeof(MPQ_SIGNATURE_INFO));
    if(!QueryMpqSignatureInfo(ha, &si))
        return ERROR_VERIFY_FAILED;

    // Verify the signature
    switch(si.nSignatureType)
    {
        case SIGNATURE_TYPE_NONE:
            return ERROR_NO_SIGNATURE;

        case SIGNATURE_TYPE_WEAK:
            return VerifyWeakSignature(ha, &si);

        case SIGNATURE_TYPE_STRONG:
            return VerifyStrongSignature(ha, &si);
    }

    return ERROR_VERIFY_FAILED;
}
示例#3
0
bool WINAPI SFileFlushArchive(HANDLE hMpq)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    int nResultError = ERROR_SUCCESS;
    int nError;

    // Do nothing if 'hMpq' is bad parameter
    if (!IsValidMpqHandle(ha))
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    // If the archive has been changed, update the changes on the disk drive.
    // Save listfile (if created), attributes (if created) and also save MPQ tables.
    if (ha->dwFlags & MPQ_FLAG_CHANGED)
    {
        nError = SListFileSaveToMpq(ha);
        if (nError != ERROR_SUCCESS)
            nResultError = nError;

        nError = SAttrFileSaveToMpq(ha);
        if (nError != ERROR_SUCCESS)
            nResultError = nError;

        nError = SaveMPQTables(ha);
        if (nError != ERROR_SUCCESS)
            nResultError = nError;
    }

    // Return the error
    if (nResultError != ERROR_SUCCESS)
        SetLastError(nResultError);
    return (nResultError == ERROR_SUCCESS);
}
示例#4
0
static bool IsValidSearchHandle(TMPQSearch * hs)
{
    if(hs == NULL)
        return false;

    return IsValidMpqHandle(hs->ha);
}
bool WINAPI SFileSetHashTableSize(HANDLE hMpq, DWORD dwNewTableSize)
{
    SFILE_FIND_DATA sf;
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TFileNode ** pListFileToFree = NULL;
    TFileNode ** pNewListFile = NULL;
    TMPQHash * pOldHashTable = NULL;
    TMPQHash * pNewHashTable = NULL;
    TMPQHash * pTableToFree = NULL;
    TMPQHash * pNewHash = NULL;
    HANDLE hFind;
    DWORD dwOldTableSize = ha->pHeader->dwHashTableSize;
    DWORD dwIndex;
    bool bFoundSomething = true;
    int nError = ERROR_SUCCESS;

    // Test the valid parameters
    if(!IsValidMpqHandle(ha))
        nError = ERROR_INVALID_HANDLE;
    if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
        nError = ERROR_ACCESS_DENIED;

    // New hash table size must be a power of two
    if(dwNewTableSize & (dwNewTableSize - 1))
        nError = ERROR_INVALID_PARAMETER;

    // Allocate buffers for copy of the old hash table and new hash table
    if(nError == ERROR_SUCCESS)
    {
        pOldHashTable = ALLOCMEM(TMPQHash, dwOldTableSize);
        pNewHashTable = ALLOCMEM(TMPQHash, dwNewTableSize);
        pNewListFile = ALLOCMEM(TFileNode *, dwNewTableSize);
        if(pOldHashTable == NULL || pNewHashTable == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
    }
示例#6
0
bool WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope)
{
    TMPQArchive * ha = IsValidMpqHandle(hMpq);
    TMPQFile * hf = NULL;
    int nError = ERROR_SUCCESS;

    // Keep compiler happy
    dwSearchScope = dwSearchScope;

    // Check the parameters
    if(ha == NULL)
        nError = ERROR_INVALID_HANDLE;
    if(szFileName == NULL || *szFileName == 0)
        nError = ERROR_INVALID_PARAMETER;
    if(IsInternalMpqFileName(szFileName))
        nError = ERROR_INTERNAL_FILE;

    // Do not allow to remove files from read-only or patched MPQs
    if(nError == ERROR_SUCCESS)
    {
        if((ha->dwFlags & MPQ_FLAG_READ_ONLY) || (ha->haPatch != NULL))
            nError = ERROR_ACCESS_DENIED;
    }

    // If all checks have passed, we can delete the file from the MPQ
    if(nError == ERROR_SUCCESS)
    {
        // Open the file from the MPQ
        if(SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_BASE_FILE, (HANDLE *)&hf))
        {
            // Delete the file entry
            nError = DeleteFileEntry(ha, hf);
            FreeFileHandle(hf);
        }
        else
            nError = GetLastError();
    }

    // If the file has been deleted, we need to invalidate
    // the internal files and recreate HET table
    if(nError == ERROR_SUCCESS)
    {
        // Invalidate the entries for internal files
        // After we are done with MPQ changes, we need to re-create them anyway
        InvalidateInternalFiles(ha);

        //
        // Don't rebuild HET table now; the file's flags indicate
        // that it's been deleted, which is enough
        //
    }

    // Resolve error and exit
    if(nError != ERROR_SUCCESS)
        SetLastError(nError);
    return (nError == ERROR_SUCCESS);
}
示例#7
0
static TMPQSearch * IsValidSearchHandle(HANDLE hFind)
{
    TMPQSearch * hs = (TMPQSearch *)hFind;

    if(hs != NULL && IsValidMpqHandle(hs->ha))
        return hs;

    return NULL;
}
bool WINAPI SFileIsPatchedArchive(HANDLE hMpq)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;

    // Verify input parameters
    if(!IsValidMpqHandle(ha))
        return false;

    return (ha->haPatch != NULL);
}
示例#9
0
bool WINAPI SFileCreateFile(
    HANDLE hMpq,
    const char * szArchivedName,
    ULONGLONG FileTime,
    DWORD dwFileSize,
    LCID lcLocale,
    DWORD dwFlags,
    HANDLE * phFile)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    int nError = ERROR_SUCCESS;

    // Check valid parameters
    if(!IsValidMpqHandle(hMpq))
        nError = ERROR_INVALID_HANDLE;
    if(szArchivedName == NULL || *szArchivedName == 0)
        nError = ERROR_INVALID_PARAMETER;
    if(phFile == NULL)
        nError = ERROR_INVALID_PARAMETER;
    
    // Don't allow to add file if the MPQ is open for read only
    if(nError == ERROR_SUCCESS)
    {
        if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
            nError = ERROR_ACCESS_DENIED;

        // Don't allow to add a file under pseudo-file name
        if(IsPseudoFileName(szArchivedName, NULL))
            nError = ERROR_INVALID_PARAMETER;

        // Don't allow to add any of the internal files
        if(IsInternalMpqFileName(szArchivedName))
            nError = ERROR_INTERNAL_FILE;
    }

    // Perform validity check of the MPQ flags
    if(nError == ERROR_SUCCESS)
    {
        // Mask all unsupported flags out
        dwFlags &= MPQ_FILE_VALID_FLAGS;

        // Check for valid flag combinations
        if((dwFlags & (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS)) == (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS))
            nError = ERROR_INVALID_PARAMETER;
    }

    // Initiate the add file operation
    if(nError == ERROR_SUCCESS)
        nError = SFileAddFile_Init(ha, szArchivedName, FileTime, dwFileSize, lcLocale, dwFlags, (TMPQFile **)phFile);

    // Deal with the errors
    if(nError != ERROR_SUCCESS)
        SetLastError(nError);
    return (nError == ERROR_SUCCESS);
}
示例#10
0
bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TFileEntry * pFileEntry;
    DWORD dwFlagsToCheck = MPQ_FILE_EXISTS;
    DWORD dwFileIndex = 0;
    char szPatchFileName[MAX_PATH];
    bool bIsPseudoName;
    int nError = ERROR_SUCCESS;

    if(!IsValidMpqHandle(ha))
        nError = ERROR_INVALID_HANDLE;
    if(szFileName == NULL || *szFileName == 0)
        nError = ERROR_INVALID_PARAMETER;

    // Prepare the file opening
    if(nError == ERROR_SUCCESS)
    {
        // Different processing for pseudo-names
        bIsPseudoName = IsPseudoFileName(szFileName, &dwFileIndex);

        // Walk through the MPQ and all patches
        while(ha != NULL)
        {
            // Verify presence of the file
            pFileEntry = (bIsPseudoName == false) ? GetFileEntryLocale(ha, szFileName, lcFileLocale)
                                                  : GetFileEntryByIndex(ha, dwFileIndex);
            // Verify the file flags
            if(pFileEntry != NULL && (pFileEntry->dwFlags & dwFlagsToCheck) == MPQ_FILE_EXISTS)
                return true;

            // If this is patched archive, go to the patch
            dwFlagsToCheck = MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE;
            ha = ha->haPatch;

            // Prepare the patched file name
            if(ha != NULL)
            {
                strcpy(szPatchFileName, ha->szPatchPrefix);
                strcat(szPatchFileName, szFileName);
                szFileName = szPatchFileName;
            }
        }

        // Not found, sorry
        nError = ERROR_FILE_NOT_FOUND;
    }

    // Cleanup
    SetLastError(nError);
    return false;
}
示例#11
0
bool WINAPI SFileSetDownloadCallback(HANDLE hMpq, SFILE_DOWNLOAD_CALLBACK DownloadCB, void * pvUserData)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;

    // Do nothing if 'hMpq' is bad parameter
    if(!IsValidMpqHandle(hMpq))
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    return FileStream_SetCallback(ha->pStream, DownloadCB, pvUserData);
}
示例#12
0
bool WINAPI SFileSetAddFileCallback(HANDLE hMpq, SFILE_ADDFILE_CALLBACK AddFileCB, void * pvUserData)
{
    TMPQArchive * ha = (TMPQArchive *) hMpq;

    if(!IsValidMpqHandle(hMpq))
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    ha->pvAddFileUserData = pvUserData;
    ha->pfnAddFileCB = AddFileCB;
    return true;
}
int EXPORT_SYMBOL SFileSetCompactCallback(void * hMpq, SFILE_COMPACT_CALLBACK pfnCompactCB, void * pvUserData)
{
    TMPQArchive * ha = (TMPQArchive *) hMpq;

    if (!IsValidMpqHandle(hMpq))
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return 0;
    }

    ha->pfnCompactCB = pfnCompactCB;
    ha->pvCompactUserData = pvUserData;
    return 1;
}
示例#14
0
bool WINAPI SFileSetCompactCallback(HANDLE hMpq, SFILE_COMPACT_CALLBACK pfnCompactCB, void * pvUserData)
{
    TMPQArchive * ha = (TMPQArchive *) hMpq;

    if (!IsValidMpqHandle(hMpq))
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    ha->pfnCompactCB = pfnCompactCB;
    ha->pvCompactUserData = pvUserData;
    return true;
}
示例#15
0
BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality, int nFileType)
{
    TMPQArchive * ha = (TMPQArchive *)hMPQ;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    BOOL   bReplaced = FALSE;          // TRUE if replacing file in the archive
    int    nError = ERROR_SUCCESS;

    if(nError == ERROR_SUCCESS)
    {
        // Check valid parameters
        if(IsValidMpqHandle(ha) == FALSE || szFileName == NULL || *szFileName == 0 || szArchivedName == NULL || *szArchivedName == 0)
            nError = ERROR_INVALID_PARAMETER;

        // Check the values of dwFlags
        if((dwFlags & MPQ_FILE_IMPLODE) && (dwFlags & MPQ_FILE_COMPRESS))
            nError = ERROR_INVALID_PARAMETER;
    }

    // If anyone is trying to add listfile, and the archive already has a listfile,
    // deny the operation, but return success.
    if(nError == ERROR_SUCCESS)
    {
        if(ha->pListFile != NULL && !_stricmp(szFileName, LISTFILE_NAME))
            return ERROR_SUCCESS;
    }

    // Open added file
    if(nError == ERROR_SUCCESS)
    {
        hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
        if(hFile == INVALID_HANDLE_VALUE)
            nError = GetLastError();
    }

    if(nError == ERROR_SUCCESS)
        nError = AddFileToArchive(ha, hFile, szArchivedName, dwFlags, dwQuality, nFileType, &bReplaced);

    // Add the file into listfile also
    if(nError == ERROR_SUCCESS && bReplaced == FALSE)
        nError = SListFileCreateNode(ha, szArchivedName, lcLocale);

    // Cleanup and exit
    if(hFile != INVALID_HANDLE_VALUE)
        CloseHandle(hFile);
    if(nError != ERROR_SUCCESS)
        SetLastError(nError);
    return (nError == ERROR_SUCCESS);
}
示例#16
0
bool WINAPI SFileFlushArchive(HANDLE hMpq)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    int nResultError = ERROR_SUCCESS;
    int nError;

    // Do nothing if 'hMpq' is bad parameter
    if(!IsValidMpqHandle(hMpq))
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    // Indicate that we are saving MPQ internal structures
    ha->dwFlags |= MPQ_FLAG_SAVING_TABLES;

    // If the (listfile) has been invalidated, save it
    if(ha->dwFlags & MPQ_FLAG_LISTFILE_INVALID)
    {
        nError = SListFileSaveToMpq(ha);
        if(nError != ERROR_SUCCESS)
            nResultError = nError;
    }

    // If the (attributes) has been invalidated, save it
    if(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_INVALID)
    {
        nError = SAttrFileSaveToMpq(ha);
        if(nError != ERROR_SUCCESS)
            nResultError = nError;
    }

    // Save HET table, BET table, hash table, block table, hi-block table
    if(ha->dwFlags & MPQ_FLAG_CHANGED)
    {
        nError = SaveMPQTables(ha);
        if(nError != ERROR_SUCCESS)
            nResultError = nError;
    }

    // We are no longer saving internal MPQ structures
    ha->dwFlags &= ~MPQ_FLAG_SAVING_TABLES;

    // Return the error
    if(nResultError != ERROR_SUCCESS)
        SetLastError(nResultError);
    return (nResultError == ERROR_SUCCESS);
}
示例#17
0
bool WINAPI SFileSetMaxFileCount(HANDLE hMpq, DWORD dwMaxFileCount)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    DWORD dwNewHashTableSize = 0;
    int nError = ERROR_SUCCESS;

    // Test the valid parameters
    if(!IsValidMpqHandle(hMpq))
        nError = ERROR_INVALID_HANDLE;
    if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
        nError = ERROR_ACCESS_DENIED;
    if(dwMaxFileCount < ha->dwFileTableSize)
        nError = ERROR_DISK_FULL;

    // ALL file names must be known in order to be able
    // to rebuild hash table
    if(nError == ERROR_SUCCESS)
    {
        nError = CheckIfAllFilesKnown(ha, NULL, NULL);
    }

    // If the MPQ has a hash table, then we relocate the hash table
    if(nError == ERROR_SUCCESS)
    {
        // Calculate the hash table size for the new file limit
        dwNewHashTableSize = GetHashTableSizeForFileCount(dwMaxFileCount);

        // Rebuild both file tables
        nError = RebuildFileTable(ha, dwNewHashTableSize, dwMaxFileCount);
    }

    // We always have to rebuild the (attributes) file due to file table change
    if(nError == ERROR_SUCCESS)
    {
        // Invalidate (listfile) and (attributes)
        InvalidateInternalFiles(ha);

        // Rebuild the HET table, if we have any
        if(ha->pHetTable != NULL)
            nError = RebuildHetTable(ha);
    }

    // Return the error
    if(nError != ERROR_SUCCESS)
        SetLastError(nError);
    return (nError == ERROR_SUCCESS);
}
示例#18
0
int WINAPI SFileEnumLocales(
    HANDLE hMpq,
    const char * szFileName,
    LCID * PtrLocales,
    LPDWORD PtrMaxLocales,
    DWORD dwSearchScope)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TMPQHash * pFirstHash;
    TMPQHash * pHash;
    DWORD dwFileIndex = 0;
    DWORD dwMaxLocales;
    DWORD dwLocales = 0;

    // Test the parameters
    if(!IsValidMpqHandle(hMpq))
        return ERROR_INVALID_HANDLE;
    if(szFileName == NULL || *szFileName == 0)
        return ERROR_INVALID_PARAMETER;
    if(ha->pHashTable == NULL)
        return ERROR_NOT_SUPPORTED;
    if(PtrMaxLocales == NULL)
        return ERROR_INVALID_PARAMETER;
    if(IsPseudoFileName(szFileName, &dwFileIndex))
        return ERROR_INVALID_PARAMETER;
    
    // Keep compiler happy
    dwMaxLocales = PtrMaxLocales[0];
    dwSearchScope = dwSearchScope;

    // Parse all files with that name
    pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
    while(pHash != NULL)
    {
        // Put the locales to the buffer
        if(PtrLocales != NULL && dwLocales < dwMaxLocales)
            *PtrLocales++ = pHash->lcLocale;
        dwLocales++;

        // Get the next locale
        pHash = GetNextHashEntry(ha, pFirstHash, pHash);
    }

    // Give the caller the number of locales and return
    PtrMaxLocales[0] = dwLocales;
    return (dwLocales <= dwMaxLocales) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
}
示例#19
0
// TODO: Test for archives > 4GB
BOOL WINAPI SFileCloseArchive(HANDLE hMPQ)
{
    TMPQArchive * ha = (TMPQArchive *)hMPQ;
    
    if(!IsValidMpqHandle(ha))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    if(ha->dwFlags & MPQ_FLAG_CHANGED)
    {
        SListFileSaveToMpq(ha);
        SaveMPQTables(ha);
    }
    FreeMPQArchive(ha);
    return TRUE;
}
int EXPORT_SYMBOL SFileSetMaxFileCount(void * hMpq, uint32_t dwMaxFileCount)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    uint32_t dwNewHashTableSize = 0;
    int nError = ERROR_SUCCESS;

    /* Test the valid parameters */
    if(!IsValidMpqHandle(hMpq))
        nError = ERROR_INVALID_HANDLE;
    if(ha->dwFlags & MPQ_FLAG_READ_ONLY)
        nError = ERROR_ACCESS_DENIED;
    if(dwMaxFileCount < ha->dwFileTableSize)
        nError = ERROR_DISK_FULL;

    /* ALL file names must be known in order to be able to rebuild hash table */
    if(nError == ERROR_SUCCESS && ha->pHashTable != NULL)
    {
        nError = CheckIfAllFilesKnown(ha);
        if(nError == ERROR_SUCCESS)
        {
            /* Calculate the hash table size for the new file limit */
            dwNewHashTableSize = GetHashTableSizeForFileCount(dwMaxFileCount);

            /* Rebuild both file tables */
            nError = RebuildFileTable(ha, dwNewHashTableSize);
        }
    }

    /* We always have to rebuild the (attributes) file due to file table change */
    if(nError == ERROR_SUCCESS)
    {
        /* Invalidate (listfile) and (attributes) */
        InvalidateInternalFiles(ha);

        /* Rebuild the HET table, if we have any */
        if(ha->pHetTable != NULL)
            nError = RebuildHetTable(ha);
    }

    /* Return the error */
    if(nError != ERROR_SUCCESS)
        SetLastError(nError);
    return (nError == ERROR_SUCCESS);
}
示例#21
0
BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
{
    TMPQFile * hf = (TMPQFile *)hFile;

    // Invalid handle => do nothing
    if(IsValidFileHandle(hf) == FALSE || IsValidMpqHandle(hf->ha) == FALSE)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    // If the file has not been open for writing, do nothing.
    if(hf->ha->pListFile == NULL)
        return ERROR_ACCESS_DENIED;

    hf->pHash->lcLocale = (USHORT)lcNewLocale;
    hf->ha->dwFlags |= MPQ_FLAG_CHANGED;
    return TRUE;
}
示例#22
0
bool WINAPI SFileFlushArchive(HANDLE hMpq)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    int nResultError = ERROR_SUCCESS;
    int nError;

    // Do nothing if 'hMpq' is bad parameter
    if(!IsValidMpqHandle(ha))
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    // If the (listfile) has been invalidated, save it
    if(ha->dwFlags & MPQ_FLAG_INV_LISTFILE)
    {
        nError = SListFileSaveToMpq(ha);
        if(nError != ERROR_SUCCESS)
            nResultError = nError;
    }

    // If the (attributes) has been invalidated, save it
    if(ha->dwFlags & MPQ_FLAG_INV_ATTRIBUTES)
    {
        nError = SAttrFileSaveToMpq(ha);
        if(nError != ERROR_SUCCESS)
            nResultError = nError;
    }

    // Save HET table, BET table, hash table, block table, hi-block table
    if(ha->dwFlags & MPQ_FLAG_CHANGED)
    {
        nError = SaveMPQTables(ha);
        if(nError != ERROR_SUCCESS)
            nResultError = nError;
    }

    // Return the error
    if(nResultError != ERROR_SUCCESS)
        SetLastError(nResultError);
    return (nResultError == ERROR_SUCCESS);
}
示例#23
0
// Verifies the archive against the signature
bool WINAPI SFileSignArchive(HANDLE hMpq, DWORD dwSignatureType)
{
    TMPQArchive * ha;

    // Verify the archive handle
    ha = IsValidMpqHandle(hMpq);
    if(ha == NULL)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return false;
    }

    // We only support weak signature, and only for MPQs version 1.0
    if(dwSignatureType != SIGNATURE_TYPE_WEAK)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return false;
    }

    // The archive must not be malformed and must not be read-only
    if(ha->dwFlags & (MPQ_FLAG_READ_ONLY | MPQ_FLAG_MALFORMED))
    {
        SetLastError(ERROR_ACCESS_DENIED);
        return false;
    }

    // If the signature is not there yet
    if(ha->dwFileFlags3 == 0)
    {
        // Turn the signature on. The signature will
        // be applied when the archive is closed
        ha->dwFlags |= MPQ_FLAG_SIGNATURE_NEW | MPQ_FLAG_CHANGED;
        ha->dwFileFlags3 = MPQ_FILE_EXISTS;
        ha->dwReservedFiles++;
    }

    return true;
}
示例#24
0
bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    int nError = ERROR_SUCCESS;

    if (!IsValidMpqHandle(ha))
        nError = ERROR_INVALID_HANDLE;
    if (*szFileName == 0)
        nError = ERROR_INVALID_PARAMETER;

    // Prepare the file opening
    if (nError == ERROR_SUCCESS)
    {
        if (GetFileEntryLocale(ha, szFileName, lcFileLocale) == NULL)
        {
            nError = ERROR_FILE_NOT_FOUND;
        }
    }

    // Cleanup
    if (nError != ERROR_SUCCESS)
        SetLastError(nError);
    return (nError == ERROR_SUCCESS);
}
示例#25
0
bool WINAPI SFileCloseArchive(HANDLE hMpq)
{
    TMPQArchive * ha = IsValidMpqHandle(hMpq);
    bool bResult = false;

    // Only if the handle is valid
    if(ha == NULL)
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return false;
    }

    // Invalidate the add file callback so it won't be called
    // when saving (listfile) and (attributes)
    ha->pfnAddFileCB = NULL;
    ha->pvAddFileUserData = NULL;

    // Flush all unsaved data to the storage
    bResult = SFileFlushArchive(hMpq);

    // Free all memory used by MPQ archive
    FreeArchiveHandle(ha);
    return bResult;
}
bool WINAPI SFileOpenPatchArchive(
    HANDLE hMpq,
    const char * szPatchMpqName,
    const char * szPatchPathPrefix,
    DWORD dwFlags)
{
    TMPQArchive * haPatch;
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    HANDLE hPatchMpq = NULL;
    size_t nLength = 0;
    int nError = ERROR_SUCCESS;

    // Keep compiler happy
    dwFlags = dwFlags;

    // Verify input parameters
    if(!IsValidMpqHandle(ha))
        nError = ERROR_INVALID_HANDLE;
    if(szPatchMpqName == NULL || *szPatchMpqName == 0)
        nError = ERROR_INVALID_PARAMETER;

    // Check the path prefix for patches
    if(szPatchPathPrefix != NULL)
    {
        nLength = strlen(szPatchPathPrefix);
        if(nLength > MPQ_PATCH_PREFIX_LEN - 2)
            nError = ERROR_INVALID_PARAMETER;
    }

    //
    // We don't allow adding patches to archives that have been open for write
    //
    // Error scenario:
    //
    // 1) Open archive for writing
    // 2) Modify or replace a file
    // 3) Add patch archive to the opened MPQ
    // 4) Read patched file
    // 5) Now what ?
    //

    if(nError == ERROR_SUCCESS)
    {
        if((ha->pStream->StreamFlags & STREAM_FLAG_READ_ONLY) == 0)
		{
			printf("omg");
            nError = ERROR_ACCESS_DENIED;
		}
    }

    // Open the archive like it is normal archive
    if(nError == ERROR_SUCCESS)
    {
        if(!SFileOpenArchive(szPatchMpqName, 0, MPQ_OPEN_READ_ONLY, &hPatchMpq))
            return false;
        haPatch = (TMPQArchive *)hPatchMpq;

        // Save the prefix for patch file names.
        // Make sure that there is backslash after it
        if(nLength > 0)
        {
            strcpy(haPatch->szPatchPrefix, szPatchPathPrefix);
            if(haPatch->szPatchPrefix[nLength - 1] != '\\')
            {
                haPatch->szPatchPrefix[nLength++] = '\\';
                haPatch->szPatchPrefix[nLength] = 0;
            }
        }

        // Now add the patch archive to the list of patches to the original MPQ
        while(ha != NULL)
        {
            if(ha->haPatch == NULL)
            {
                ha->haPatch = haPatch;
                return true;
            }

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

        // Should never happen
        nError = ERROR_CAN_NOT_COMPLETE;
    }

    SetLastError(nError);
    return false;
}
示例#27
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);
}
示例#28
0
int WINAPI SFileEnumLocales(
    HANDLE hMpq,
    const char * szFileName,
    LCID * plcLocales,
    LPDWORD pdwMaxLocales,
    DWORD dwSearchScope)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TMPQHash * pFirstHash;
    TMPQHash * pHash;
    DWORD dwLocales = 0;

    // Test the parameters
    if (!IsValidMpqHandle(ha))
        return ERROR_INVALID_HANDLE;
    if (pdwMaxLocales == NULL)
        return ERROR_INVALID_PARAMETER;
    if (dwSearchScope == SFILE_OPEN_BY_INDEX && (DWORD_PTR)szFileName > ha->pHeader->dwBlockTableSize)
        return ERROR_INVALID_PARAMETER;
    if (dwSearchScope != SFILE_OPEN_BY_INDEX && *szFileName == 0)
        return ERROR_INVALID_PARAMETER;

    // Parse hash table entries for all locales
    if (dwSearchScope == SFILE_OPEN_FROM_MPQ)
    {
        pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
        while(pHash != NULL)
        {
            dwLocales++;
            pHash = GetNextHashEntry(ha, pFirstHash, pHash);
        }
    }
    else
    {
        // For nameless access, always return 1 locale
//      pHash = GetFileEntryByIndex(ha, (DWORD)(DWORD_PTR)szFileName);
//      if (pHash != NULL)
//          dwLocales++;
    }

    // Test if there is enough space to copy the locales
    if (*pdwMaxLocales < dwLocales)
    {
        *pdwMaxLocales = dwLocales;
        return ERROR_INSUFFICIENT_BUFFER;
    }

    // Now find all locales
    if (dwSearchScope == SFILE_OPEN_FROM_MPQ)
    {
        pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);
        while(pHash != NULL)
        {
            *plcLocales++ = pHash->lcLocale;
            pHash = GetNextHashEntry(ha, pFirstHash, pHash);
        }
    }
    else
    {
        // For nameless access, always return 1 locale
//      pHash = GetFileEntryByIndex(ha, (DWORD)(DWORD_PTR)szFileName);
//      if (pHash != NULL)
//          *plcLocales++ = pHash->lcLocale;
    }

    // Give the caller the total number of found locales
    *pdwMaxLocales = dwLocales;
    return ERROR_SUCCESS;
}
示例#29
0
void LoadMapMPQFiles()
{
    char filename[512];

    //Locale-xxXX.MPQ
    sprintf(filename,"%s/Data/world.MPQ", input_path);
    printf("Loading %s\n", filename);
    if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &WorldMPQ))
    {
        printf("%i\n", GetLastError());
        assert(false && "\nLoad of MPQ failed");
    }

    for(int i = 0; i < PATCH_REV_COUNT; ++i)
    {
        char ext[7] = "";
        sprintf(ext, "-%i", patchRev[i]);

        sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext);
        printf("    -%i\n", patchRev[i]);
        if (!SFileOpenPatchArchive(WorldMPQ, filename, "base", MPQ_OPEN_READ_ONLY))
        {
            printf("%i\n", GetLastError());
            assert(false && "Load of MPQ patch failed");
        }
    }
    if (!SFileIsPatchedArchive(WorldMPQ))
        assert(false && "An error occured");

    for(int j = 0; j < 3; j++)
    {
        sprintf(filename, "%s/Data/expansion%u.MPQ", input_path, j+1);
        printf("Loading %s\n", filename);
        if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &ExpansionsMPQ[j]))
        {
            printf("%i\n", GetLastError());
            assert(false && "\nLoad of MPQ failed");
        }

        if (!IsValidMpqHandle((TMPQArchive*)ExpansionsMPQ[j]))
        {
            printf("Load of Expansion%u.MPQ Failed!\n", j+1);
            printf("\nPlease verify you downloaded all the MPQs. You should replace\n'SET accountType \"xx\"'\nin your WTF/config.wtf and WTF/launcher.wtf by\n'SET accountType \"CT\"'\nand then restart your launcher\n");
            exit(1);
        }

        for(int i = 0; i < PATCH_REV_COUNT; ++i)
        {
            char ext[7] = "";
            sprintf(ext, "-%i", patchRev[i]);

            sprintf(filename,"%s/Data/wow-update%s.MPQ", input_path, ext);
            printf("    -%i\n", patchRev[i]);
            if (!SFileOpenPatchArchive(ExpansionsMPQ[j], filename, "base", MPQ_OPEN_READ_ONLY))
            {
                printf("%i\n", GetLastError());
                assert(false && "Load of MPQ patch failed");
            }
        }
    }
}
示例#30
0
bool WINAPI SFileSetHashTableSize(HANDLE hMpq, DWORD dwNewTableSize)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
    TFileEntry * pFileEntry;
    TMPQHash * pOldHashTable = NULL;
    TMPQHash * pNewHashTable = NULL;
    TMPQHash * pTableToFree = NULL;
    TMPQHash * pHash = NULL;
    DWORD dwOldHashTableSize = 0;
    int nError = ERROR_SUCCESS;

    // Test the valid parameters
    if (!IsValidMpqHandle(ha))
        nError = ERROR_INVALID_HANDLE;
    if (ha->dwFlags & MPQ_FLAG_READ_ONLY)
        nError = ERROR_ACCESS_DENIED;
    if (ha->pHetTable != NULL || ha->pHetTable != NULL)
        nError = ERROR_ACCESS_DENIED;

    // New hash table size must be a power of two
    if (dwNewTableSize & (dwNewTableSize - 1))
        nError = ERROR_INVALID_PARAMETER;

    // ALL file names must be known in order to be able
    // to rebuild hash table size
    if (nError == ERROR_SUCCESS)
        nError = CheckIfAllFilesKnown(ha, NULL, NULL);

    // Allocate buffer fo new hash table
    if (nError == ERROR_SUCCESS)
    {
        dwOldHashTableSize = ha->pHeader->dwHashTableSize;
        pOldHashTable = ha->pHashTable;

        pNewHashTable = ALLOCMEM(TMPQHash, dwNewTableSize);
        if (pOldHashTable == NULL || pNewHashTable == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
    }

    // Now build the new hash table
    // we have to reallocate block table, and also all tables in the (attributes)
    if (nError == ERROR_SUCCESS)
    {
        // Set new hash table
        memset(pNewHashTable, 0xFF, dwNewTableSize * sizeof(TMPQHash));
        ha->pHashTable = pNewHashTable;
        ha->pHeader->dwHashTableSize = dwNewTableSize;

        // Make new hash table entry for each file
        for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++)
        {
            if (pFileEntry->dwFlags & MPQ_FILE_EXISTS)
            {
                // The file name must be known
                assert(pFileEntry->szFileName != NULL);

                // Create new hashtable entry
                pHash = AllocateHashEntry(ha, pFileEntry->szFileName, pFileEntry->lcLocale);
                if (pHash == NULL)
                {
                    nError = ERROR_CAN_NOT_COMPLETE;
                    break;
                }

                // Fill the hash table entry
                pHash->wPlatform = pFileEntry->wPlatform;
                pHash->dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);

                // Fix the hash table index
                pFileEntry->dwHashIndex = (DWORD)(pHash - pNewHashTable);
            }
        }

        // If something failed, we have to revert hash table
        if (nError == ERROR_SUCCESS)
        {
            pTableToFree = pOldHashTable;
            ha->dwFlags |= MPQ_FLAG_CHANGED;
        }
        else
        {
            ha->pHeader->dwHashTableSize = dwOldHashTableSize;
            ha->pHashTable = pOldHashTable;
            pTableToFree = pNewHashTable;
        }
    }

    // Free buffers
    if (pTableToFree != NULL)
        FREEMEM(pTableToFree);

    // Return the result
    if (nError != ERROR_SUCCESS)
        SetLastError(nError);
    return (nError == ERROR_SUCCESS);
}