#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
TCascFile::TCascFile(TCascStorage * ahs, PCASC_CKEY_ENTRY apCKeyEntry)
{
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;
if((pFileSpan = CASC_ALLOC_ZERO<CASC_FILE_SPAN>(SpanCount)) != NULL)
{
InitFileSpans(pFileSpan, SpanCount);
InitCacheStrategy();
}
}
TCascFile::~TCascFile()
{
if(pFileSpan != NULL)
{
PCASC_FILE_SPAN pSpanPtr = pFileSpan;
for(DWORD i = 0; i < SpanCount; i++, pSpanPtr++)
{
if(bCloseFileStream)
FileStream_Close(pSpanPtr->pStream);
pSpanPtr->pStream = NULL;
CASC_FREE(pSpanPtr->pFrames);
}
CASC_FREE(pFileSpan);
}
if(pCKeyEntry && bFreeCKeyEntries)
delete [] pCKeyEntry;
pCKeyEntry = NULL;
CASC_FREE(pbFileCache);
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++)
{
pFileSpan[i].pStream = pStream = FileStream_OpenFile(szSpanList, BASE_PROVIDER_FILE | STREAM_PROVIDER_FLAT);
if(pFileSpan[i].pStream == NULL)
{
dwErrCode = GetCascError();
break;
}
FileStream_GetSize(pStream, &FileSize);
if((FileSize >> 0x1E) != 0)
{
dwErrCode = ERROR_NOT_SUPPORTED;
break;
}
pCKeyEntry[i].EncodedSize = (DWORD)FileSize;
}
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;
GetFileSpanInfo(pCKeyEntry, &ContentSize, &EncodedSize);
if(hs != NULL)
FileOffsetBits = hs->FileOffsetBits;
FileOffsetMask = ((ULONGLONG)1 << FileOffsetBits) - 1;
for(DWORD i = 0; i < dwSpanCount; i++, pSpans++)
{
pSpans->ArchiveIndex = (DWORD)(pCKeyEntry[i].StorageOffset >> FileOffsetBits);
pSpans->ArchiveOffs = (DWORD)(pCKeyEntry[i].StorageOffset & FileOffsetMask);
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;
}
static size_t GetSpanFileCount(LPTSTR szSpanList)
{
LPTSTR szSpanPtr = szSpanList;
size_t nSpanCount = 1;
while(szSpanPtr[0] != 0)
{
if(szSpanPtr[0] == ';' && szSpanPtr[1] != 0)
{
szSpanPtr[0] = 0;
nSpanCount++;
}
szSpanPtr++;
}
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);
}
PCASC_CKEY_ENTRY FindCKeyEntry_EKey(TCascStorage * hs, LPBYTE pbEKey, PDWORD PtrIndex)
{
return (PCASC_CKEY_ENTRY)hs->EKeyMap.FindObject(pbEKey, PtrIndex);
}
bool OpenFileByCKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD dwOpenFlags, HANDLE * PtrFileHandle)
{
TCascFile * hf = NULL;
DWORD dwErrCode = ERROR_FILE_NOT_FOUND;
if(pCKeyEntry != NULL)
{
if((hf = new TCascFile(hs, pCKeyEntry)) != NULL)
{
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;
dwErrCode = ERROR_SUCCESS;
}
else
{
dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
}
PtrFileHandle[0] = (HANDLE)hf;
if(dwErrCode != ERROR_SUCCESS)
SetCascError(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;
if((szSpanList = CascNewStr(szFileName, 1)) != NULL)
{
if((nSpanCount = GetSpanFileCount(szSpanList)) != 0 || nSpanCount > 0xFF)
{
if((pCKeyEntry = new CASC_CKEY_ENTRY[nSpanCount]) != NULL)
{
pCKeyEntry->SpanCount = (BYTE)nSpanCount;
for(size_t i = 0; i < nSpanCount; i++)
pCKeyEntry[i].StorageOffset = 0;
if((hf = new TCascFile(NULL, pCKeyEntry)) != NULL)
{
hf->bVerifyIntegrity = (dwOpenFlags & CASC_STRICT_DATA_CHECK) ? true : false;
hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) ? true : false;
hf->bCloseFileStream = true;
dwErrCode = hf->OpenFileSpans(szSpanList);
if(dwErrCode != ERROR_SUCCESS)
{
delete hf;
hf = NULL;
}
}
}
}
else
{
dwErrCode = ERROR_INVALID_PARAMETER;
}
delete [] szSpanList;
}
PtrFileHandle[0] = (HANDLE)hf;
if(dwErrCode != ERROR_SUCCESS)
SetCascError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}
bool SetCacheStrategy(HANDLE hFile, CSTRTG CacheStrategy)
{
TCascFile * hf;
if((hf = TCascFile::IsValid(hFile)) != NULL)
{
if(hf->pbFileCache == NULL)
{
hf->CacheStrategy = CacheStrategy;
return true;
}
}
assert(false);
return false;
}
bool WINAPI CascOpenFile(HANDLE hStorage, const void * pvFileName, DWORD dwLocaleFlags, DWORD dwOpenFlags, HANDLE * PtrFileHandle)
{
PCASC_CKEY_ENTRY pCKeyEntry = NULL;
TCascStorage * hs;
const char * szFileName;
DWORD FileDataId = CASC_INVALID_ID;
BYTE CKeyEKeyBuffer[MD5_HASH_SIZE];
DWORD dwErrCode = ERROR_SUCCESS;
CASCLIB_UNUSED(dwLocaleFlags);
hs = TCascStorage::IsValid(hStorage);
if(hs == NULL)
{
SetCascError(ERROR_INVALID_HANDLE);
return false;
}
if(PtrFileHandle == NULL)
{
SetCascError(ERROR_INVALID_PARAMETER);
return false;
}
switch(dwOpenFlags & CASC_OPEN_TYPE_MASK)
{
case CASC_OPEN_BY_NAME:
szFileName = (const char *)pvFileName;
if(szFileName == NULL || szFileName[0] == 0)
{
SetCascError(ERROR_INVALID_PARAMETER);
return false;
}
pCKeyEntry = hs->pRootHandler->GetFile(hs, szFileName);
if(pCKeyEntry != NULL)
break;
if(IsFileDataIdName(szFileName, FileDataId))
{
pCKeyEntry = hs->pRootHandler->GetFile(hs, FileDataId);
if(pCKeyEntry != NULL)
break;
}
if(IsFileCKeyEKeyName(szFileName, CKeyEKeyBuffer))
{
pCKeyEntry = FindCKeyEntry_CKey(hs, CKeyEKeyBuffer);
if(pCKeyEntry != NULL)
break;
pCKeyEntry = FindCKeyEntry_EKey(hs, CKeyEKeyBuffer);
if(pCKeyEntry != NULL)
break;
}
SetCascError(ERROR_FILE_NOT_FOUND);
return false;
case CASC_OPEN_BY_CKEY:
if(pvFileName == NULL)
{
SetCascError(ERROR_INVALID_PARAMETER);
return false;
}
pCKeyEntry = FindCKeyEntry_CKey(hs, (LPBYTE)pvFileName);
break;
case CASC_OPEN_BY_EKEY:
if(pvFileName == NULL)
{
SetCascError(ERROR_INVALID_PARAMETER);
return false;
}
pCKeyEntry = FindCKeyEntry_EKey(hs, (LPBYTE)pvFileName);
break;
case CASC_OPEN_BY_FILEID:
pCKeyEntry = hs->pRootHandler->GetFile(hs, CASC_FILE_DATA_ID_FROM_STRING(pvFileName));
break;
default:
dwErrCode = ERROR_INVALID_PARAMETER;
break;
}
if(dwOpenFlags & CASC_OPEN_CKEY_ONCE)
{
if(pCKeyEntry->Flags & CASC_CE_OPEN_CKEY_ONCE)
{
SetCascError(ERROR_CKEY_ALREADY_OPENED);
return false;
}
else
{
pCKeyEntry->Flags |= CASC_CE_OPEN_CKEY_ONCE;
}
}
return OpenFileByCKeyEntry(hs, pCKeyEntry, dwOpenFlags, PtrFileHandle);
}
bool WINAPI CascOpenLocalFile(LPCTSTR szFileName, DWORD dwOpenFlags, HANDLE * PtrFileHandle)
{
if(szFileName == NULL || szFileName[0] == 0 || PtrFileHandle == NULL)
{
SetCascError(ERROR_INVALID_PARAMETER);
return false;
}
return OpenLocalFile(szFileName, dwOpenFlags, PtrFileHandle);
}
bool WINAPI CascCloseFile(HANDLE hFile)
{
TCascFile * hf;
hf = TCascFile::IsValid(hFile);
if(hf != NULL)
{
delete hf;
return true;
}
SetCascError(ERROR_INVALID_HANDLE);
return false;
}