static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry) { TFileEntry * pPatchEntry = NULL; TFileEntry * pTempEntry; char szFileName[MAX_PATH]; LCID lcLocale = pFileEntry->lcLocale; // Go while there are patches while(ha->haPatch != NULL) { // Move to the patch archive ha = ha->haPatch; // Prepare the prefix for the file name strcpy(szFileName, ha->szPatchPrefix); strcat(szFileName, pFileEntry->szFileName); // Try to find the file there pTempEntry = GetFileEntryExact(ha, szFileName, lcLocale); if(pTempEntry != NULL) pPatchEntry = pTempEntry; } // Return the found patch entry return pPatchEntry; }
static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry) { TFileEntry * pPatchEntry = NULL; TFileEntry * pTempEntry; char szFileName[MAX_PATH+1]; // Go while there are patches while(ha->haPatch != NULL) { // Move to the patch archive ha = ha->haPatch; szFileName[0] = 0; // Prepare the prefix for the file name if(ha->pPatchPrefix != NULL) StringCopyA(szFileName, ha->pPatchPrefix->szPatchPrefix, MAX_PATH); StringCatA(szFileName, pFileEntry->szFileName, MAX_PATH); // Try to find the file there pTempEntry = GetFileEntryExact(ha, szFileName, 0, NULL); if(pTempEntry != NULL) pPatchEntry = pTempEntry; } // Return the found patch entry return pPatchEntry; }
static bool IsBaseFileMissing( TMPQArchive * ha, const char * szFileName1, // File name with prefix const char * szFileName2, // File name without prefix LCID lcLocale) { TFileEntry * pTempEntry; const char * szFileName; bool bBaseFileMissing = true; while(ha != NULL) { // If this patch file uses patch prefix, include it. // Otherwise, use non-prefixed file name szFileName = (ha->szPatchPrefix[0] != 0) ? szFileName1 : szFileName2; // Check if the file in this MPQ is patch file or not pTempEntry = GetFileEntryExact(ha, szFileName, lcLocale); if(pTempEntry != NULL) bBaseFileMissing = (pTempEntry->dwFlags & MPQ_FILE_PATCH_FILE) ? true : false; // Go one MPQ lower ha = ha->haBase; } // Return what we found return bBaseFileMissing; }
static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry) { TFileEntry * pPatchEntry = pFileEntry; TFileEntry * pTempEntry; char szFileName[MAX_PATH+1]; // Can't find patch entry for a file that doesn't have name if(pFileEntry->szFileName != NULL && pFileEntry->szFileName[0] != 0) { // Go while there are patches while(ha->haPatch != NULL) { // Move to the patch archive ha = ha->haPatch; szFileName[0] = 0; // Prepare the prefix for the file name if(ha->pPatchPrefix && ha->pPatchPrefix->nLength) StringCopy(szFileName, _countof(szFileName), ha->pPatchPrefix->szPatchPrefix); StringCat(szFileName, _countof(szFileName), pFileEntry->szFileName); // Try to find the file there pTempEntry = GetFileEntryExact(ha, szFileName, 0, NULL); if(pTempEntry != NULL) pPatchEntry = pTempEntry; } } // Return the found patch entry return pPatchEntry; }
bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale) { TMPQArchive * ha; TFileEntry * pFileEntry; TMPQFile * hf = IsValidFileHandle(hFile); // Invalid handle => do nothing if(hf == NULL) { SetLastError(ERROR_INVALID_HANDLE); return false; } // Do not allow to rename files in MPQ open for read only ha = hf->ha; if(ha->dwFlags & MPQ_FLAG_READ_ONLY) { SetLastError(ERROR_ACCESS_DENIED); return false; } // Do not allow unnamed access if(hf->pFileEntry->szFileName == NULL) { SetLastError(ERROR_CAN_NOT_COMPLETE); return false; } // Do not allow to change locale of any internal file if(IsInternalMpqFileName(hf->pFileEntry->szFileName)) { SetLastError(ERROR_INTERNAL_FILE); return false; } // Do not allow changing file locales if there is no hash table if(hf->pHashEntry == NULL) { SetLastError(ERROR_NOT_SUPPORTED); return false; } // We have to check if the file+locale is not already there pFileEntry = GetFileEntryExact(ha, hf->pFileEntry->szFileName, lcNewLocale, NULL); if(pFileEntry != NULL) { SetLastError(ERROR_ALREADY_EXISTS); return false; } // Update the locale in the hash table entry hf->pHashEntry->lcLocale = (USHORT)lcNewLocale; ha->dwFlags |= MPQ_FLAG_CHANGED; return true; }
int SFileAddFile_Init( TMPQArchive * ha, const char * szFileName, ULONGLONG FileTime, DWORD dwFileSize, LCID lcLocale, DWORD dwFlags, TMPQFile ** phf) { TFileEntry * pFileEntry = NULL; TMPQFile * hf = NULL; // File structure for newly added file DWORD dwHashIndex = HASH_ENTRY_FREE; int nError = ERROR_SUCCESS; // // Note: This is an internal function so no validity checks are done. // It is the caller's responsibility to make sure that no invalid // flags get to this point // // Sestor CRC is not allowed with single unit files if(dwFlags & MPQ_FILE_SINGLE_UNIT) dwFlags &= ~MPQ_FILE_SECTOR_CRC; // Sector CRC is not allowed if the file is not compressed if(!(dwFlags & MPQ_FILE_COMPRESS_MASK)) dwFlags &= ~MPQ_FILE_SECTOR_CRC; // Fix Key is not allowed if the file is not enrypted if(!(dwFlags & MPQ_FILE_ENCRYPTED)) dwFlags &= ~MPQ_FILE_FIX_KEY; // If the MPQ is of version 3.0 or higher, we ignore file locale. // This is because HET and BET tables have no known support for it if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_3) lcLocale = 0; // Allocate the TMPQFile entry for newly added file hf = CreateWritableHandle(ha, dwFileSize); if(hf == NULL) return false; // Allocate file entry in the MPQ if(nError == ERROR_SUCCESS) { // Check if the file already exists in the archive pFileEntry = GetFileEntryExact(ha, szFileName, lcLocale, &dwHashIndex); if(pFileEntry != NULL) { if(dwFlags & MPQ_FILE_REPLACEEXISTING) InvalidateInternalFiles(ha); else nError = ERROR_ALREADY_EXISTS; } else { // Free all internal files - (listfile), (attributes), (signature) InvalidateInternalFiles(ha); // Attempt to allocate new file entry pFileEntry = AllocateFileEntry(ha, szFileName, lcLocale, &dwHashIndex); if(pFileEntry == NULL) nError = ERROR_DISK_FULL; } // Set the file entry to the file structure hf->pFileEntry = pFileEntry; } // Prepare the pointer to hash table entry if(nError == ERROR_SUCCESS && ha->pHashTable != NULL && dwHashIndex < ha->pHeader->dwHashTableSize) { hf->pHashEntry = ha->pHashTable + dwHashIndex; hf->pHashEntry->lcLocale = (USHORT)lcLocale; } // Prepare the file key if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED)) { hf->dwFileKey = DecryptFileKey(szFileName, hf->MpqFilePos, dwFileSize, dwFlags); if(hf->dwFileKey == 0) nError = ERROR_UNKNOWN_FILE_KEY; } // Fill the file entry and TMPQFile structure if(nError == ERROR_SUCCESS) { // At this point, the file name in the file entry must be set assert(pFileEntry->szFileName != NULL); assert(_stricmp(pFileEntry->szFileName, szFileName) == 0); nError = FillWritableHandle(ha, hf, FileTime, dwFileSize, dwFlags); } // Free the file handle if failed if(nError != ERROR_SUCCESS && hf != NULL) FreeFileHandle(hf); // Give the handle to the caller *phf = hf; return nError; }
bool OpenPatchedFile(HANDLE hMpq, const char * szFileName, DWORD dwReserved, HANDLE * phFile) { TMPQArchive * haBase = NULL; TMPQArchive * ha = (TMPQArchive *)hMpq; TFileEntry * pFileEntry; TMPQFile * hfPatch; // Pointer to patch file TMPQFile * hfBase = NULL; // Pointer to base open file TMPQFile * hf = NULL; HANDLE hPatchFile; char szPrefixBuffer[MAX_PATH]; // Keep this flag here for future updates dwReserved = dwReserved; // First of all, find the latest archive where the file is in base version // (i.e. where the original, unpatched version of the file exists) while(ha != NULL) { // If the file is there, then we remember the archive pFileEntry = GetFileEntryExact(ha, GetPatchFileName(ha, szFileName, szPrefixBuffer), 0); if(pFileEntry != NULL && (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) haBase = ha; // Move to the patch archive ha = ha->haPatch; } // If we couldn't find the base file in any of the patches, it doesn't exist if((ha = haBase) == NULL) { SetLastError(ERROR_FILE_NOT_FOUND); return false; } // Now open the base file if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szPrefixBuffer), SFILE_OPEN_BASE_FILE, (HANDLE *)&hfBase)) { // The file must be a base file, i.e. without MPQ_FILE_PATCH_FILE assert((hfBase->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0); hf = hfBase; // Now open all patches and attach them on top of the base file for(ha = ha->haPatch; ha != NULL; ha = ha->haPatch) { // Prepare the file name with a correct prefix if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szPrefixBuffer), SFILE_OPEN_BASE_FILE, &hPatchFile)) { // Remember the new version hfPatch = (TMPQFile *)hPatchFile; // We should not find patch file assert((hfPatch->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) != 0); // Attach the patch to the base file hf->hfPatch = hfPatch; hf = hfPatch; } } } // Give the updated base MPQ if(phFile != NULL) *phFile = (HANDLE)hfBase; return true; }