diff options
author | Shauren <shauren.trinity@gmail.com> | 2019-08-10 19:01:24 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-08-10 19:01:24 +0200 |
commit | cd720efbfa60f434f420ab66e220eca742c48e45 (patch) | |
tree | 3c960ac5249d0711b71fbfdc62f6c0b665ed85ee /dep/CascLib/src/CascOpenFile.cpp | |
parent | 0d6320dfd3932865edb69c8528327b767bd476ef (diff) |
Dep/CascLib: Update to ladislav-zezula/CascLib@b91f87c770c78340dcd96df970e55b5c0469e884
Diffstat (limited to 'dep/CascLib/src/CascOpenFile.cpp')
-rw-r--r-- | dep/CascLib/src/CascOpenFile.cpp | 271 |
1 files changed, 263 insertions, 8 deletions
diff --git a/dep/CascLib/src/CascOpenFile.cpp b/dep/CascLib/src/CascOpenFile.cpp index 45d10bc18f1..8ff9739d6e3 100644 --- a/dep/CascLib/src/CascOpenFile.cpp +++ b/dep/CascLib/src/CascOpenFile.cpp @@ -13,8 +13,171 @@ #include "CascCommon.h" //----------------------------------------------------------------------------- +// TCascFile class functions + +TCascFile::TCascFile(TCascStorage * ahs, PCASC_CKEY_ENTRY apCKeyEntry) +{ + // Reference the storage handle + if((hs = ahs) != NULL) + hs->AddRef(); + ClassName = CASC_MAGIC_FILE; + + FilePointer = 0; + pCKeyEntry = apCKeyEntry; + SpanCount = (pCKeyEntry->SpanCount != 0) ? pCKeyEntry->SpanCount : 1; + bVerifyIntegrity = false; + bDownloadFileIf = false; + bCloseFileStream = false; + bFreeCKeyEntries = false; + + // Allocate the array of file spans + if((pFileSpan = CASC_ALLOC_ZERO<CASC_FILE_SPAN>(SpanCount)) != NULL) + { + InitFileSpans(pFileSpan, SpanCount); + InitCacheStrategy(); + } +} + +TCascFile::~TCascFile() +{ + // Free all stuff related to file spans + if (pFileSpan != NULL) + { + PCASC_FILE_SPAN pSpanPtr = pFileSpan; + + for(DWORD i = 0; i < SpanCount; i++, pSpanPtr++) + { + // Close the span file stream if this is a local file + if(bCloseFileStream) + FileStream_Close(pSpanPtr->pStream); + pSpanPtr->pStream = NULL; + + // Free the span frames + CASC_FREE(pSpanPtr->pFrames); + } + + CASC_FREE(pFileSpan); + } + + // Free the CKey entries, if needed + if(pCKeyEntry && bFreeCKeyEntries) + delete [] pCKeyEntry; + pCKeyEntry = NULL; + + // Free the file cache + CASC_FREE(pbFileCache); + + // Close (dereference) the archive handle + if(hs != NULL) + hs = hs->Release(); + ClassName = 0; +} + +DWORD TCascFile::OpenFileSpans(LPCTSTR szSpanList) +{ + TFileStream * pStream; + ULONGLONG FileSize = 0; + DWORD dwErrCode = ERROR_SUCCESS; + + for(DWORD i = 0; i < SpanCount; i++) + { + // Open the file span + pFileSpan[i].pStream = pStream = FileStream_OpenFile(szSpanList, BASE_PROVIDER_FILE | STREAM_PROVIDER_FLAT); + if(pFileSpan[i].pStream == NULL) + { + dwErrCode = GetLastError(); + break; + } + + // If succeeded, we assign the span to the + FileStream_GetSize(pStream, &FileSize); + if((FileSize >> 0x1E) != 0) + { + dwErrCode = ERROR_NOT_SUPPORTED; + break; + } + + pCKeyEntry[i].EncodedSize = (DWORD)FileSize; + } + + // Free the so-far-opened files + if(dwErrCode != ERROR_SUCCESS) + { + for(DWORD i = 0; i < SpanCount; i++) + { + if(pFileSpan[i].pStream != NULL) + FileStream_Close(pFileSpan[i].pStream); + pFileSpan[i].pStream = NULL; + } + } + + return dwErrCode; +} + +void TCascFile::InitFileSpans(PCASC_FILE_SPAN pSpans, DWORD dwSpanCount) +{ + ULONGLONG FileOffsetBits = 30; + ULONGLONG FileOffsetMask = 0; + ULONGLONG FileOffset = 0; + + // Initialize the file sizes. Note that if any of the spans has invalid size, + // the entire file size will be set to CASC_INVALID_SIZE64. + GetFileSpanInfo(pCKeyEntry, &ContentSize, &EncodedSize); + + // Resolve the file offset bits and file offset mask + if(hs != NULL) + FileOffsetBits = hs->FileOffsetBits; + FileOffsetMask = ((ULONGLONG)1 << FileOffsetBits) - 1; + + // Add all span sizes + for(DWORD i = 0; i < dwSpanCount; i++, pSpans++) + { + // Put the archive index and archive offset + pSpans->ArchiveIndex = (DWORD)(pCKeyEntry[i].StorageOffset >> FileOffsetBits); + pSpans->ArchiveOffs = (DWORD)(pCKeyEntry[i].StorageOffset & FileOffsetMask); + + // Add to the total encoded size + if(ContentSize != CASC_INVALID_SIZE64) + { + pSpans->StartOffset = FileOffset; + FileOffset = FileOffset + pCKeyEntry[i].ContentSize; + pSpans->EndOffset = FileOffset; + } + } +} + +void TCascFile::InitCacheStrategy() +{ + CacheStrategy = CascCacheLastFrame; + FileCacheStart = FileCacheEnd = 0; + pbFileCache = NULL; +} + +//----------------------------------------------------------------------------- // Local functions +static size_t GetSpanFileCount(LPTSTR szSpanList) +{ + LPTSTR szSpanPtr = szSpanList; + size_t nSpanCount = 1; + + while(szSpanPtr[0] != 0) + { + // End of a file? + if(szSpanPtr[0] == ';' && szSpanPtr[1] != 0) + { + szSpanPtr[0] = 0; + nSpanCount++; + } + + szSpanPtr++; + } + + // Place an additional zero to make the list terminated by double EOS + szSpanPtr[1] = 0; + return nSpanCount; +} + PCASC_CKEY_ENTRY FindCKeyEntry_CKey(TCascStorage * hs, LPBYTE pbCKey, PDWORD PtrIndex) { return (PCASC_CKEY_ENTRY)hs->CKeyMap.FindObject(pbCKey, PtrIndex); @@ -28,7 +191,7 @@ PCASC_CKEY_ENTRY FindCKeyEntry_EKey(TCascStorage * hs, LPBYTE pbEKey, PDWORD Ptr bool OpenFileByCKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD dwOpenFlags, HANDLE * PtrFileHandle) { TCascFile * hf = NULL; - int nError = ERROR_FILE_NOT_FOUND; + DWORD dwErrCode = ERROR_FILE_NOT_FOUND; // If the CKey entry is NULL, we consider the file non-existant if(pCKeyEntry != NULL) @@ -39,11 +202,11 @@ bool OpenFileByCKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD d hf->bVerifyIntegrity = (dwOpenFlags & CASC_STRICT_DATA_CHECK) ? true : false; hf->bDownloadFileIf = (hs->dwFeatures & CASC_FEATURE_ONLINE) ? true : false; hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) ? true : false; - nError = ERROR_SUCCESS; + dwErrCode = ERROR_SUCCESS; } else { - nError = ERROR_NOT_ENOUGH_MEMORY; + dwErrCode = ERROR_NOT_ENOUGH_MEMORY; } } @@ -51,9 +214,89 @@ bool OpenFileByCKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD d PtrFileHandle[0] = (HANDLE)hf; // Handle last error - if(nError != ERROR_SUCCESS) - SetLastError(nError); - return (nError == ERROR_SUCCESS); + if(dwErrCode != ERROR_SUCCESS) + SetLastError(dwErrCode); + return (dwErrCode == ERROR_SUCCESS); +} + +bool OpenLocalFile(LPCTSTR szFileName, DWORD dwOpenFlags, HANDLE * PtrFileHandle) +{ + PCASC_CKEY_ENTRY pCKeyEntry; + TCascFile * hf = NULL; + LPTSTR szSpanList; + size_t nSpanCount; + DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY; + + // Create a copy of the file name. It is actually a file name list, + // separated by comma (for supporting multi-span files) + if((szSpanList = CascNewStr(szFileName, 1)) != NULL) + { + // Calculate the span count + if((nSpanCount = GetSpanFileCount(szSpanList)) != 0 || nSpanCount > 0xFF) + { + // Allocate CKey array for the file. Each entry describes one file span + if((pCKeyEntry = new CASC_CKEY_ENTRY[nSpanCount]) != NULL) + { + // Prepare the span count to the first item + pCKeyEntry->SpanCount = (BYTE)nSpanCount; + + // Prepare the archive offset in each CKey entry + for(size_t i = 0; i < nSpanCount; i++) + pCKeyEntry[i].StorageOffset = 0; + + // Create an instance of the TCascFile + if((hf = new TCascFile(NULL, pCKeyEntry)) != NULL) + { + // Prepare the structure + hf->bVerifyIntegrity = (dwOpenFlags & CASC_STRICT_DATA_CHECK) ? true : false; + hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) ? true : false; + hf->bCloseFileStream = true; + + // Open all local file spans + dwErrCode = hf->OpenFileSpans(szSpanList); + if(dwErrCode != ERROR_SUCCESS) + { + delete hf; + hf = NULL; + } + } + } + } + else + { + dwErrCode = ERROR_INVALID_PARAMETER; + } + + delete [] szSpanList; + } + + // Give the output parameter, no matter what + PtrFileHandle[0] = (HANDLE)hf; + + // Handle last error + if(dwErrCode != ERROR_SUCCESS) + SetLastError(dwErrCode); + return (dwErrCode == ERROR_SUCCESS); +} + +bool SetCacheStrategy(HANDLE hFile, CSTRTG CacheStrategy) +{ + TCascFile * hf; + + // Validate the file handle + if((hf = TCascFile::IsValid(hFile)) != NULL) + { + // The cache must not be initialized yet + if(hf->pbFileCache == NULL) + { + hf->CacheStrategy = CacheStrategy; + return true; + } + } + + // Failed. This should never happen + assert(false); + return false; } //----------------------------------------------------------------------------- @@ -66,7 +309,7 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const void * pvFileName, DWORD dwLocal const char * szFileName; DWORD FileDataId = CASC_INVALID_ID; BYTE CKeyEKeyBuffer[MD5_HASH_SIZE]; - int nError = ERROR_SUCCESS; + DWORD dwErrCode = ERROR_SUCCESS; // This parameter is not used CASCLIB_UNUSED(dwLocaleFlags); @@ -162,7 +405,7 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const void * pvFileName, DWORD dwLocal default: // Unknown open mode - nError = ERROR_INVALID_PARAMETER; + dwErrCode = ERROR_INVALID_PARAMETER; break; } @@ -170,6 +413,18 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const void * pvFileName, DWORD dwLocal return OpenFileByCKeyEntry(hs, pCKeyEntry, dwOpenFlags, PtrFileHandle); } +bool WINAPI CascOpenLocalFile(LPCTSTR szFileName, DWORD dwOpenFlags, HANDLE * PtrFileHandle) +{ + // Verify parameters + if(szFileName == NULL || szFileName[0] == 0 || PtrFileHandle == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + return OpenLocalFile(szFileName, dwOpenFlags, PtrFileHandle); +} + bool WINAPI CascCloseFile(HANDLE hFile) { TCascFile * hf; |