int MultiFileCurlPlugin::DownloadFile( const std::string &url, const std::string &local_file_name, const std::string &cred, long &partial_bytes ) { char partial_range[20]; FILE *file = NULL; int rval = -1; if ( !(file=OpenLocalFile(local_file_name, partial_bytes ? "a+" : "w")) ) { return rval; } struct curl_slist *header_list = NULL; try { InitializeCurlHandle( url, cred, header_list ); } catch (const std::exception &exc) { _this_file_stats->TransferSuccess = false; _this_file_stats->TransferError = exc.what(); fprintf( stderr, "Error: %s.\n", exc.what() ); return rval; } // Libcurl options that apply to all transfer protocols curl_easy_setopt( _handle, CURLOPT_WRITEDATA, file ); curl_easy_setopt( _handle, CURLOPT_HEADERDATA, _this_file_stats.get() ); if (header_list) curl_easy_setopt(_handle, CURLOPT_HTTPHEADER, header_list); // If we are attempting to resume a download, set additional flags if( partial_bytes ) { sprintf( partial_range, "%lu-", partial_bytes ); curl_easy_setopt( _handle, CURLOPT_RANGE, partial_range ); } // Update some statistics _this_file_stats->TransferType = "download"; _this_file_stats->TransferTries += 1; // Perform the curl request rval = curl_easy_perform( _handle ); if (header_list) curl_slist_free_all(header_list); // Check if the request completed partially. If so, set some // variables so we can attempt a resume on the next try. if( ( rval == CURLE_PARTIAL_FILE ) && ServerSupportsResume( url ) ) { partial_bytes = ftell( file ); } FinishCurlTransfer( rval, file ); // Error handling and cleanup if( _diagnostic && rval ) { fprintf(stderr, "curl_easy_perform returned CURLcode %d: %s\n", rval, curl_easy_strerror( ( CURLcode ) rval ) ); } fclose( file ); return rval; }
int MultiFileCurlPlugin::UploadFile( const std::string &url, const std::string &local_file_name, const std::string &cred ) { FILE *file = nullptr; int rval = -1; if( !(file=OpenLocalFile(local_file_name, "r")) ) { return rval; } struct curl_slist *header_list = NULL; try { InitializeCurlHandle( url, cred, header_list ); } catch (const std::exception &exc) { _this_file_stats->TransferSuccess = false; _this_file_stats->TransferError = exc.what(); fprintf( stderr, "Error: %s.\n", exc.what() ); return rval; } int fd = fileno(file); struct stat stat_buf; if (-1 == fstat(fd, &stat_buf)) { if ( _diagnostic ) { fprintf(stderr, "Failed to stat the local file for upload: %s (errno=%d).\n", strerror(errno), errno); } fclose( file ); return rval; } curl_easy_setopt( _handle, CURLOPT_READDATA, file ); curl_easy_setopt( _handle, CURLOPT_UPLOAD, 1L); curl_easy_setopt( _handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)stat_buf.st_size ); if (header_list) curl_easy_setopt(_handle, CURLOPT_HTTPHEADER, header_list); // Update some statistics _this_file_stats->TransferType = "upload"; _this_file_stats->TransferTries += 1; // Perform the curl request rval = curl_easy_perform( _handle ); if (header_list) curl_slist_free_all(header_list); FinishCurlTransfer( rval, file ); // Error handling and cleanup if( _diagnostic && rval ) { fprintf(stderr, "curl_easy_perform returned CURLcode %d: %s\n", rval, curl_easy_strerror( ( CURLcode ) rval ) ); } fclose( file ); return rval; }
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); }
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); }
bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * PtrFile) { TMPQArchive * ha = IsValidMpqHandle(hMpq); TFileEntry * pFileEntry = NULL; TMPQFile * hf = NULL; DWORD dwHashIndex = HASH_ENTRY_FREE; DWORD dwFileIndex = 0; bool bOpenByIndex = false; int nError = ERROR_SUCCESS; // Don't accept NULL pointer to file handle if(szFileName == NULL || *szFileName == 0) nError = ERROR_INVALID_PARAMETER; // When opening a file from MPQ, the handle must be valid if(dwSearchScope != SFILE_OPEN_LOCAL_FILE && ha == NULL) nError = ERROR_INVALID_HANDLE; // When not checking for existence, the pointer to file handle must be valid if(dwSearchScope != SFILE_OPEN_CHECK_EXISTS && PtrFile == 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: case SFILE_OPEN_CHECK_EXISTS: // Check the pseudo-file name if((bOpenByIndex = IsPseudoFileName(szFileName, &dwFileIndex)) == true) { // Get the file entry for the file if(dwFileIndex > ha->dwFileTableSize) break; pFileEntry = ha->pFileTable + dwFileIndex; } else { // If this MPQ has no patches, open the file from this MPQ directly if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE) { pFileEntry = GetFileEntryLocale2(ha, szFileName, lcFileLocale, &dwHashIndex); } // If this MPQ is a patched archive, open the file as patched else { return OpenPatchedFile(hMpq, szFileName, PtrFile); } } 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 = GetFileEntryLocale2(ha, szFileName, 0, &dwHashIndex); break; case SFILE_OPEN_LOCAL_FILE: // Open a local file return OpenLocalFile(szFileName, PtrFile); default: // Don't accept any other value nError = ERROR_INVALID_PARAMETER; break; } } // Check whether the file really exists in the MPQ if(nError == ERROR_SUCCESS) { if(pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0) nError = ERROR_FILE_NOT_FOUND; // Ignore unknown loading flags (example: MPQ_2016_v1_WME4_4.w3x) // if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS) // nError = ERROR_NOT_SUPPORTED; } // Did the caller just wanted to know if the file exists? if(nError == ERROR_SUCCESS && dwSearchScope != SFILE_OPEN_CHECK_EXISTS) { // Allocate file handle hf = CreateFileHandle(ha, pFileEntry); if(hf != NULL) { // Get the hash index for the file if(ha->pHashTable != NULL && dwHashIndex == HASH_ENTRY_FREE) dwHashIndex = FindHashIndex(ha, dwFileIndex); if(dwHashIndex != HASH_ENTRY_FREE) hf->pHashEntry = ha->pHashTable + dwHashIndex; hf->dwHashIndex = dwHashIndex; // 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(ha, 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 { nError = ERROR_NOT_ENOUGH_MEMORY; } } // Give the file entry if(PtrFile != NULL) PtrFile[0] = hf; // Return error code if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
CFile *CFileContainerArc::OpenFile(const char *filename) { const FFileInfo *FileInfo = FindFile(filename); if (!FileInfo) return NULL; return OpenLocalFile(*FileInfo); }