#ifndef __CASCCOMMON_H__
#define __CASCCOMMON_H__
#ifndef CASC_USE_SYSTEM_ZLIB
#include "zlib/zlib.h"
#else
#include <zlib.h>
#endif
#if defined(_DEBUG) && !defined(CASCLIB_NODEBUG)
#define CASCLIB_DEBUG
#endif
#include "CascPort.h"
#include "common/Common.h"
#include "common/Array.h"
#include "common/ArraySparse.h"
#include "common/Map.h"
#include "common/FileTree.h"
#include "common/FileStream.h"
#include "common/Directory.h"
#include "common/ListFile.h"
#include "common/Csv.h"
#include "common/Mime.h"
#include "common/Path.h"
#include "common/RootHandler.h"
#include "common/Sockets.h"
#include "hashes/md5.h"
#include "hashes/sha1.h"
#include "jenkins/lookup.h"
#include "CascStructs.h"
#if defined(CASCLIB_DEBUG) && defined(CASCLIB_DEV)
#define BREAK_ON_XKEY3(CKey, v0, v1, v2) if(CKey[0] == v0 && CKey[1] == v1 && CKey[2] == v2) { __debugbreak(); }
#define BREAKIF(condition) if(condition) { __debugbreak(); }
#else
#define BREAK_ON_XKEY3(CKey, v0, v1, v2) { }
#define BREAKIF(condition) { }
#endif
#define CASC_MAGIC_STORAGE 0x524F545343534143
#define CASC_MAGIC_FILE 0x454C494643534143
#define CASC_MAGIC_FIND 0x444E494643534143
#define CASC_MAX_ONLINE_FILE_SIZE 0x40000000
typedef enum _CBLD_TYPE
{
CascBuildNone = 0, CascBuildDb, CascBuildInfo, CascVersions } CBLD_TYPE, *PCBLD_TYPE;
typedef enum _CPATH_TYPE
{
PathTypeConfig, PathTypeData, PathTypePatch } CPATH_TYPE, *PCPATH_TYPE;
typedef enum _CSTRTG
{
CascCacheInvalid, CascCacheNothing, CascCacheLastFrame, } CSTRTG, *PCSTRTG;
typedef struct _CASC_TAG_ENTRY
{
USHORT HashType; char TagName[1]; } CASC_TAG_ENTRY, *PCASC_TAG_ENTRY;
typedef struct _CASC_BUILD_FILE
{
LPCTSTR szPlainName; CBLD_TYPE BuildFileType; TCHAR szFullPath[MAX_PATH]; } CASC_BUILD_FILE, *PCASC_BUILD_FILE;
typedef struct _CASC_INDEX
{
CASC_BLOB FileData;
LPTSTR szFileName; DWORD NewSubIndex; DWORD OldSubIndex; } CASC_INDEX, *PCASC_INDEX;
typedef struct _CASC_INDEX_HEADER
{
USHORT IndexVersion; BYTE BucketIndex; BYTE StorageOffsetLength; BYTE EncodedSizeLength; BYTE EKeyLength; BYTE FileOffsetBits; BYTE Alignment;
ULONGLONG SegmentSize; size_t HeaderLength; size_t HeaderPadding; size_t EntryLength; size_t EKeyCount;
} CASC_INDEX_HEADER, *PCASC_INDEX_HEADER;
typedef struct _CASC_ARCINDEX_FOOTER
{
BYTE TocHash[MD5_HASH_SIZE]; BYTE FooterHash[MD5_HASH_SIZE]; BYTE Version; BYTE OffsetBytes; BYTE SizeBytes; BYTE EKeyLength; BYTE FooterHashBytes; BYTE Alignment[3];
size_t ElementCount; size_t PageLength; size_t ItemLength; size_t FooterLength;
} CASC_ARCINDEX_FOOTER, *PCASC_ARCINDEX_FOOTER;
typedef struct _CASC_ENCODING_HEADER
{
USHORT Magic; USHORT Version; BYTE CKeyLength; BYTE EKeyLength; DWORD CKeyPageSize; DWORD EKeyPageSize; DWORD CKeyPageCount; DWORD EKeyPageCount; DWORD ESpecBlockSize; } CASC_ENCODING_HEADER, *PCASC_ENCODING_HEADER;
typedef struct _CASC_DOWNLOAD_HEADER
{
USHORT Magic; USHORT Version; USHORT EKeyLength; USHORT EntryHasChecksum; DWORD EntryCount;
DWORD TagCount;
USHORT FlagByteSize;
USHORT BasePriority;
size_t HeaderLength; size_t EntryLength;
} CASC_DOWNLOAD_HEADER, *PCASC_DOWNLOAD_HEADER;
typedef struct _CASC_DOWNLOAD_ENTRY
{
BYTE EKey[MD5_HASH_SIZE];
ULONGLONG EncodedSize;
DWORD Checksum;
DWORD Flags;
BYTE Priority;
} CASC_DOWNLOAD_ENTRY, *PCASC_DOWNLOAD_ENTRY;
typedef struct _CASC_TAG_ENTRY1
{
const char * szTagName; LPBYTE Bitmap; size_t BitmapLength; size_t NameLength; size_t TagLength; DWORD TagValue; } CASC_TAG_ENTRY1, *PCASC_TAG_ENTRY1;
typedef struct _CASC_TAG_ENTRY2
{
size_t NameLength; DWORD TagValue; char szTagName[0x08]; } CASC_TAG_ENTRY2, *PCASC_TAG_ENTRY2;
typedef struct _CASC_INSTALL_HEADER
{
USHORT Magic; BYTE Version; BYTE EKeyLength; DWORD EntryCount;
DWORD TagCount;
size_t HeaderLength; } CASC_INSTALL_HEADER, *PCASC_INSTALL_HEADER;
typedef struct _CASC_FILE_FRAME
{
CONTENT_KEY FrameHash; ULONGLONG StartOffset; ULONGLONG EndOffset; ULONGLONG DataFileOffset; DWORD EncodedSize; DWORD ContentSize; } CASC_FILE_FRAME, *PCASC_FILE_FRAME;
typedef struct _CASC_FILE_SPAN
{
ULONGLONG StartOffset; ULONGLONG EndOffset; PCASC_FILE_FRAME pFrames;
TFileStream * pStream; DWORD ArchiveIndex; DWORD ArchiveOffs; DWORD HeaderSize; DWORD FrameCount;
} CASC_FILE_SPAN, *PCASC_FILE_SPAN;
typedef struct _CASC_ARCHIVE_INFO
{
DWORD ArchiveIndex; DWORD ArchiveOffs; DWORD EncodedSize; BYTE ArchiveKey[MD5_HASH_SIZE];
} CASC_ARCHIVE_INFO, *PCASC_ARCHIVE_INFO;
struct TCascStorage
{
TCascStorage();
~TCascStorage();
TCascStorage * AddRef();
TCascStorage * Release();
static TCascStorage * IsValid(HANDLE hStorage)
{
TCascStorage * hs = (TCascStorage *)hStorage;
return (hs != INVALID_HANDLE_VALUE &&
hs != NULL &&
hs->ClassName == CASC_MAGIC_STORAGE) ? hs : NULL;
}
DWORD SetProductCodeName(LPCSTR szNewCodeName, size_t nLength = 0)
{
if(szCodeName == NULL && szNewCodeName != NULL)
{
if(nLength == 0)
nLength = strlen(szNewCodeName);
if((szCodeName = CASC_ALLOC<TCHAR>(nLength + 1)) == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
CascStrCopy(szCodeName, nLength + 1, szNewCodeName, nLength);
}
return ERROR_SUCCESS;
}
ULONGLONG ClassName;
PCASC_OPEN_STORAGE_ARGS pArgs; CASC_LOCK StorageLock;
LPCTSTR szIndexFormat; LPTSTR szCodeName; LPTSTR szRootPath; LPTSTR szDataPath; LPTSTR szIndexPath; LPTSTR szFilesPath; LPTSTR szConfigPath; LPTSTR szMainFile; LPTSTR szCdnHostUrl; LPTSTR szCdnServers; LPTSTR szCdnPath; LPSTR szRegion; LPSTR szBuildKey; DWORD dwDefaultLocale; DWORD dwBuildNumber; DWORD dwRefCount; DWORD dwFeatures;
CBLD_TYPE BuildFileType;
CASC_BLOB CdnConfigKey; CASC_BLOB CdnBuildKey;
CASC_BLOB ArchiveGroup; CASC_BLOB ArchivesKey; CASC_BLOB PatchArchivesKey; CASC_BLOB PatchArchivesGroup; CASC_BLOB BuildFiles;
TFileStream * DataFiles[CASC_MAX_DATA_FILES]; CASC_INDEX IndexFiles[CASC_INDEX_COUNT]; CASC_MAP IndexEKeyMap;
CASC_CKEY_ENTRY EncodingCKey; CASC_CKEY_ENTRY DownloadCKey; CASC_CKEY_ENTRY InstallCKey; CASC_CKEY_ENTRY PatchFile; CASC_CKEY_ENTRY RootFile; CASC_CKEY_ENTRY SizeFile; CASC_CKEY_ENTRY VfsRoot; CASC_ARRAY VfsRootList;
TRootHandler * pRootHandler; CASC_ARRAY IndexArray; CASC_ARRAY CKeyArray; CASC_ARRAY TagsArray; CASC_MAP IndexMap; CASC_MAP CKeyMap; CASC_MAP EKeyMap; size_t LocalFiles; size_t TotalFiles; size_t EKeyEntries; size_t EKeyLength; DWORD FileOffsetBits;
CASC_KEY_MAP KeyMap; ULONGLONG LastFailKeyName; };
struct TCascFile
{
TCascFile(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry);
~TCascFile();
DWORD OpenFileSpans(LPCTSTR szSpanList);
void InitFileSpans(PCASC_FILE_SPAN pSpans, DWORD dwSpanCount);
void InitCacheStrategy();
static TCascFile * IsValid(HANDLE hFile)
{
TCascFile * hf = (TCascFile *)hFile;
return (hf != INVALID_HANDLE_VALUE &&
hf != NULL &&
hf->ClassName == CASC_MAGIC_FILE &&
hf->pCKeyEntry != NULL) ? hf : NULL;
}
ULONGLONG ClassName;
TCascStorage * hs;
PCASC_CKEY_ENTRY pCKeyEntry; PCASC_FILE_SPAN pFileSpan; ULONGLONG ContentSize; ULONGLONG EncodedSize; ULONGLONG FilePointer; DWORD SpanCount; DWORD bVerifyIntegrity:1; DWORD bDownloadFileIf:1; DWORD bCloseFileStream:1; DWORD bOvercomeEncrypted:1; DWORD bFreeCKeyEntries:1;
ULONGLONG FileCacheStart; ULONGLONG FileCacheEnd; LPBYTE pbFileCache; CSTRTG CacheStrategy; };
struct TCascSearch
{
TCascSearch(TCascStorage * ahs, LPCTSTR aszListFile, const char * aszMask)
{
ClassName = CASC_MAGIC_FIND;
hs = (ahs != NULL) ? ahs->AddRef() : NULL;
pCache = NULL;
nFileIndex = 0;
nSearchState = 0;
bListFileUsed = false;
szListFile = CascNewStr(aszListFile);
szMask = CascNewStr((aszMask != NULL) ? aszMask : "*");
}
~TCascSearch()
{
if(hs != NULL)
hs = hs->Release();
ClassName = 0;
CASC_FREE(szMask);
CASC_FREE(szListFile);
CASC_FREE(pCache);
}
static TCascSearch * IsValid(HANDLE hFind)
{
TCascSearch * pSearch = (TCascSearch *)hFind;
return (hFind != INVALID_HANDLE_VALUE &&
hFind != NULL &&
pSearch->ClassName == CASC_MAGIC_FIND &&
pSearch->szMask != NULL) ? pSearch : NULL;
}
ULONGLONG ClassName;
TCascStorage * hs; LPTSTR szListFile; void * pCache; char * szMask;
size_t nFileIndex; DWORD nSearchState:8; DWORD bListFileUsed:1; };
inline void FreeCascBlob(PCASC_BLOB pBlob)
{
if(pBlob != NULL)
{
CASC_FREE(pBlob->pbData);
pBlob->cbData = 0;
}
}
bool InvokeProgressCallback(TCascStorage * hs, CASC_PROGRESS_MSG Message, LPCSTR szObject, DWORD CurrentValue, DWORD TotalValue);
DWORD GetFileSpanInfo(PCASC_CKEY_ENTRY pCKeyEntry, PULONGLONG PtrContentSize, PULONGLONG PtrEncodedSize = NULL);
DWORD FetchCascFile(TCascStorage * hs, CPATH_TYPE PathType, LPBYTE pbEKey, LPCTSTR szExtension, CASC_PATH<TCHAR> & LocalPath, PCASC_ARCHIVE_INFO pArchiveInfo = NULL);
DWORD CheckCascBuildFileExact(CASC_BUILD_FILE & BuildFile, LPCTSTR szLocalPath);
DWORD CheckCascBuildFileDirs(CASC_BUILD_FILE & BuildFile, LPCTSTR szLocalPath);
DWORD CheckOnlineStorage(PCASC_OPEN_STORAGE_ARGS pArgs, CASC_BUILD_FILE & BuildFile, bool bOnlineStorage);
DWORD CheckArchiveFilesDirectories(TCascStorage * hs);
DWORD CheckDataFilesDirectory(TCascStorage * hs);
DWORD LoadMainFile(TCascStorage * hs);
DWORD LoadCdnConfigFile(TCascStorage * hs);
DWORD LoadCdnBuildFile(TCascStorage * hs);
DWORD LoadInternalFileToMemory(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, CASC_BLOB & FileData);
DWORD LoadFileToMemory(LPCTSTR szFileName, CASC_BLOB & FileData);
bool OpenFileByCKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD dwOpenFlags, HANDLE * PtrFileHandle);
bool SetCacheStrategy(HANDLE hFile, CSTRTG CacheStrategy);
void * ProbeOutputBuffer(void * pvBuffer, size_t cbLength, size_t cbMinLength, size_t * pcbLengthNeeded);
PCASC_CKEY_ENTRY FindCKeyEntry_CKey(TCascStorage * hs, LPBYTE pbCKey, PDWORD PtrIndex = NULL);
PCASC_CKEY_ENTRY FindCKeyEntry_EKey(TCascStorage * hs, LPBYTE pbEKey, PDWORD PtrIndex = NULL);
size_t GetTagBitmapLength(LPBYTE pbFilePtr, LPBYTE pbFileEnd, DWORD EntryCount);
DWORD CascDecompress(LPBYTE pvOutBuffer, PDWORD pcbOutBuffer, LPBYTE pvInBuffer, DWORD cbInBuffer);
DWORD CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer);
DWORD CascLoadEncryptionKeys(TCascStorage * hs);
DWORD CascDecrypt(TCascStorage * hs, LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex);
bool CopyEKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry);
DWORD LoadIndexFiles(TCascStorage * hs);
void FreeIndexFiles(TCascStorage * hs);
DWORD RootHandler_CreateMNDX(TCascStorage * hs, CASC_BLOB & RootFile);
DWORD RootHandler_CreateTVFS(TCascStorage * hs, CASC_BLOB & RootFile);
DWORD RootHandler_CreateDiablo3(TCascStorage * hs, CASC_BLOB & RootFile);
DWORD RootHandler_CreateWoW(TCascStorage * hs, CASC_BLOB & RootFile, DWORD dwLocaleMask);
DWORD RootHandler_CreateOverwatch(TCascStorage * hs, CASC_BLOB & RootFile);
DWORD RootHandler_CreateStarcraft1(TCascStorage * hs, CASC_BLOB & RootFile);
DWORD RootHandler_CreateInstall(TCascStorage * hs, CASC_BLOB & InstallFile);
#ifdef CASCLIB_DEBUG
void CascDumpData(LPCSTR szFileName, const void * pvData, size_t cbData);
void CascDumpFile(HANDLE hFile, const char * szDumpFile = NULL);
void CascDumpStorage(HANDLE hStorage, const char * szDumpFile = NULL);
#endif
#endif