| 26 | } |
| 27 | |
| 28 | static DWORD OpenDataStream(TCascFile * hf, PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEntry, bool bDownloadFileIf) |
| 29 | { |
| 30 | TCascStorage * hs = hf->hs; |
| 31 | TFileStream * pStream = NULL; |
| 32 | TCHAR szPlainName[0x80]; |
| 33 | DWORD dwErrCode; |
| 34 | |
| 35 | // If the file is available locally, we rely on data files. |
| 36 | // If not, we download the file and open the stream |
| 37 | if(pCKeyEntry->Flags & CASC_CE_FILE_IS_LOCAL) |
| 38 | { |
| 39 | DWORD dwArchiveIndex = pFileSpan->ArchiveIndex; |
| 40 | |
| 41 | // Lock the storage to make the operation thread-safe |
| 42 | CascLock(hs->StorageLock); |
| 43 | |
| 44 | // If the data archive is not open yet, open it now. |
| 45 | if(hs->DataFiles[dwArchiveIndex] == NULL) |
| 46 | { |
| 47 | // Prepare the name of the data file |
| 48 | CascStrPrintf(szPlainName, _countof(szPlainName), _T("data.%03u"), dwArchiveIndex); |
| 49 | |
| 50 | // Create the full path of the data file |
| 51 | CASC_PATH<TCHAR> DataFile(hs->szIndexPath, szPlainName, NULL); |
| 52 | |
| 53 | // Open the data stream with read+write sharing to prevent Battle.net agent |
| 54 | // detecting a corruption and redownloading the entire package |
| 55 | pStream = FileStream_OpenFile(DataFile, STREAM_FLAG_READ_ONLY | STREAM_FLAG_WRITE_SHARE | STREAM_PROVIDER_FLAT | STREAM_FLAG_FILL_MISSING | BASE_PROVIDER_FILE); |
| 56 | hs->DataFiles[dwArchiveIndex] = pStream; |
| 57 | } |
| 58 | |
| 59 | // Unlock the storage |
| 60 | CascUnlock(hs->StorageLock); |
| 61 | |
| 62 | // Return error or success |
| 63 | pFileSpan->pStream = hs->DataFiles[dwArchiveIndex]; |
| 64 | return (pFileSpan->pStream != NULL) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND; |
| 65 | } |
| 66 | else |
| 67 | { |
| 68 | if(bDownloadFileIf) |
| 69 | { |
| 70 | CASC_ARCHIVE_INFO ArchiveInfo = {0}; |
| 71 | CASC_PATH<TCHAR> LocalPath; |
| 72 | CPATH_TYPE PathType = (pCKeyEntry->Flags & CASC_CE_FILE_PATCH) ? PathTypePatch : PathTypeData; |
| 73 | |
| 74 | // Fetch the file |
| 75 | dwErrCode = FetchCascFile(hs, PathType, pCKeyEntry->EKey, NULL, LocalPath, &ArchiveInfo); |
| 76 | if(dwErrCode == ERROR_SUCCESS) |
| 77 | { |
| 78 | pStream = FileStream_OpenFile(LocalPath, BASE_PROVIDER_FILE | STREAM_PROVIDER_FLAT); |
| 79 | if(pStream != NULL) |
| 80 | { |
| 81 | // Initialize information about the position and size of the file in archive |
| 82 | // On loose files, their position is zero and encoded size is length of the file |
| 83 | if(CascIsValidMD5(ArchiveInfo.ArchiveKey)) |
| 84 | { |
| 85 | // Archive position |
no test coverage detected