aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/CascOpenFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src/CascOpenFile.cpp')
-rw-r--r--dep/CascLib/src/CascOpenFile.cpp271
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;