// 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; }
// 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; }
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); }
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; }
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); }
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); }
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); }
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; }
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); }
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; }
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; }
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); }
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); }
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); }
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; }
// 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); }
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; }
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); }
// 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; }
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); }
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; }
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); }
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; }
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"); } } } }
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); }