#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
#include "overwatch.h"
template <typename APM_ENTRY>
static bool IsContinuousArray(APM_ENTRY * pEntry, size_t nCount)
{
if(nCount-- >= 5)
{
for(size_t i = 0; i < nCount; i++, pEntry++)
{
if(pEntry[1].Index > pEntry[0].Index + 10)
{
return false;
}
}
return true;
}
return false;
}
static LPBYTE CaptureApmHeader(TCascStorage * hs, LPBYTE pbDataPtr, LPBYTE pbDataEnd, CASC_APM_HEADER & ApmHeader)
{
PCASC_APM_HEADER_V2 pHeader_V3 = NULL;
if(CaptureStructure<CASC_APM_HEADER_V2>(pbDataPtr, pbDataEnd, &pHeader_V3) != NULL)
{
if(pHeader_V3->BuildNumber == hs->dwBuildNumber &&
pHeader_V3->ZeroValue1 == 0 &&
pHeader_V3->ZeroValue2 == 0 &&
pHeader_V3->ZeroValue3 == 0)
{
ApmHeader.BuildNumber = pHeader_V3->BuildNumber;
ApmHeader.PackageCount = pHeader_V3->PackageCount;
ApmHeader.PackageCount = pHeader_V3->PackageCount;
ApmHeader.EntryCount = pHeader_V3->EntryCount;
ApmHeader.HeaderMagic = pHeader_V3->HeaderMagic;
return pbDataPtr + sizeof(CASC_APM_HEADER_V2);
}
}
PCASC_APM_HEADER_V1 pHeader_V1 = NULL;
if(CaptureStructure<CASC_APM_HEADER_V1>(pbDataPtr, pbDataEnd, &pHeader_V1) != NULL)
{
if((pHeader_V1->HeaderMagic & 0x00FFFFFF) == CASC_APM_HEADER_MAGIC)
{
ApmHeader.BuildNumber = pHeader_V1->BuildNumber;
ApmHeader.PackageCount = pHeader_V1->PackageCount;
ApmHeader.PackageCount = pHeader_V1->PackageCount;
ApmHeader.EntryCount = pHeader_V1->EntryCount;
ApmHeader.HeaderMagic = pHeader_V1->HeaderMagic;
return pbDataPtr + sizeof(CASC_APM_HEADER_V1);
}
}
return NULL;
}
static LPBYTE SkipApmEntries(TCascStorage * hs, LPBYTE pbDataPtr, LPBYTE pbDataEnd, size_t nCount)
{
PCASC_APM_ENTRY_V2 pApmEntries_V2 = NULL;
PCASC_APM_ENTRY_V1 pApmEntries_V1 = NULL;
LPBYTE pbSavePtr = pbDataPtr;
CASCLIB_UNUSED(hs);
if((pbDataPtr = CaptureArray(pbSavePtr, pbDataEnd, &pApmEntries_V2, nCount)) != NULL)
{
if(IsContinuousArray(pApmEntries_V2, nCount))
{
return pbDataPtr;
}
}
if((pbDataPtr = CaptureArray(pbSavePtr, pbDataEnd, &pApmEntries_V1, nCount)) != NULL)
{
if(IsContinuousArray(pApmEntries_V1, nCount))
{
return pbDataPtr;
}
}
return NULL;
}
DWORD LoadApplicationPackageManifestFile(TCascStorage * hs, CASC_FILE_TREE & FileTree, PCASC_CKEY_ENTRY pCKeyEntry, const char * szApmFileName)
{
CASC_BLOB ApmFile;
const char * szApmPlainName = GetPlainFileName(szApmFileName);
DWORD dwErrCode;
if((dwErrCode = LoadInternalFileToMemory(hs, pCKeyEntry, ApmFile)) == ERROR_SUCCESS)
{
PCASC_APM_PACKAGE_ENTRY_V1 pEntries;
CASC_APM_HEADER ApmHeader = {0};
LPBYTE pbDataEnd = ApmFile.pbData + ApmFile.cbData;
LPBYTE pbDataPtr = ApmFile.pbData;
size_t nPlainName;
char szFileName[MAX_PATH];
if((pbDataPtr = CaptureApmHeader(hs, pbDataPtr, pbDataEnd, ApmHeader)) == NULL)
return ERROR_BAD_FORMAT;
if((pbDataPtr = SkipApmEntries(hs, pbDataPtr, pbDataEnd, ApmHeader.EntryCount)) == NULL)
return ERROR_BAD_FORMAT;
if((pbDataPtr = CaptureArray(pbDataPtr, pbDataEnd, &pEntries, ApmHeader.PackageCount)) != NULL)
{
if(pbDataPtr == pbDataEnd && ApmHeader.PackageCount > 1)
{
if(FindCKeyEntry_CKey(hs, pEntries[0].CKey) != NULL && FindCKeyEntry_CKey(hs, pEntries[1].CKey) != NULL)
{
nPlainName = BuildAssetFileNameTemplate(szFileName,
_countof(szFileName),
"AppPackageManifests",
szApmPlainName);
dwErrCode = InsertAssetFiles(hs, FileTree, szFileName, nPlainName, pEntries, ApmHeader.PackageCount);
}
}
}
}
return dwErrCode;
}