#ifndef __COMMON_H__
#define __COMMON_H__
#define MAKE_OFFSET64(hi, lo) (((ULONGLONG)hi << 32) | (ULONGLONG)lo)
#ifndef ALIGN_TO_SIZE
#define ALIGN_TO_SIZE(x, a) (((x) + (a)-1) & ~((a)-1))
#endif
#define CASCLIB_MIN(a, b) ((a < b) ? a : b)
#define CASCLIB_MAX(a, b) ((a > b) ? a : b)
#define CASCLIB_UNUSED(p) ((void)(p))
typedef struct _CONTENT_KEY
{
BYTE Value[MD5_HASH_SIZE];
} CONTENT_KEY, *PCONTENT_KEY, ENCODED_KEY, *PENCODED_KEY;
typedef struct _CASC_EKEY_ENTRY
{
BYTE EKey[MD5_HASH_SIZE]; ULONGLONG StorageOffset; DWORD EncodedSize; DWORD Alignment; } CASC_EKEY_ENTRY, *PCASC_EKEY_ENTRY;
#define CASC_CE_FILE_IS_LOCAL 0x0001
#define CASC_CE_HAS_CKEY 0x0002
#define CASC_CE_HAS_EKEY 0x0004
#define CASC_CE_HAS_EKEY_PARTIAL 0x0008
#define CASC_CE_IN_ENCODING 0x0010
#define CASC_CE_IN_DOWNLOAD 0x0020
#define CASC_CE_IN_BUILD 0x0040
#define CASC_CE_IN_ARCHIVE 0x0080
#define CASC_CE_FOLDER_ENTRY 0x0100
#define CASC_CE_FILE_SPAN 0x0200
#define CASC_CE_FILE_PATCH 0x0400
#define CASC_CE_PLAIN_DATA 0x0800
#define CASC_CE_OPEN_CKEY_ONCE 0x1000
struct CASC_CKEY_ENTRY
{
CASC_CKEY_ENTRY()
{
Init();
}
void Init(void)
{
memset(this, 0, sizeof(CASC_CKEY_ENTRY));
StorageOffset = CASC_INVALID_OFFS64;
EncodedSize = CASC_INVALID_SIZE;
ContentSize = CASC_INVALID_SIZE;
SpanCount = 1;
}
bool IsFile()
{
if((Flags & CASC_CE_FOLDER_ENTRY) == 0)
{
if(RefCount != 0)
return true;
if(((Flags & CASC_CE_FILE_SPAN) == 0) && (Flags & (CASC_CE_IN_ENCODING | CASC_CE_IN_DOWNLOAD | CASC_CE_IN_BUILD)))
return true;
}
return false;
}
BYTE CKey[MD5_HASH_SIZE]; BYTE EKey[MD5_HASH_SIZE]; ULONGLONG StorageOffset; ULONGLONG TagBitMask; DWORD ContentSize; DWORD EncodedSize; DWORD RefCount; USHORT Flags; BYTE SpanCount; BYTE Priority; };
typedef CASC_CKEY_ENTRY *PCASC_CKEY_ENTRY;
extern unsigned char AsciiToLowerTable_Slash[256];
extern unsigned char AsciiToUpperTable_BkSlash[256];
extern unsigned char AsciiToHexTable[128];
extern unsigned char IntToHexChar[];
template <typename T>
T * CASC_REALLOC(T * old_ptr, size_t count)
{
return (T *)realloc(old_ptr, count * sizeof(T));
}
template <typename T>
T * CASC_ALLOC(size_t nCount)
{
return (T *)malloc(nCount * sizeof(T));
}
template <typename T>
T * CASC_ALLOC_ZERO(size_t nCount)
{
T * ptr = CASC_ALLOC<T>(nCount);
if(ptr != NULL)
memset(ptr, 0, sizeof(T) * nCount);
return ptr;
}
template <typename T>
void CASC_FREE(T *& ptr)
{
if (ptr != NULL)
free(ptr);
ptr = NULL;
}
inline DWORD Rol32(DWORD dwValue, DWORD dwRolCount)
{
return (dwValue << dwRolCount) | (dwValue >> (32 - dwRolCount));
}
inline USHORT ConvertBytesToInteger_2(LPBYTE ValueAsBytes)
{
USHORT Value = 0;
Value = (Value << 0x08) | ValueAsBytes[0];
Value = (Value << 0x08) | ValueAsBytes[1];
return Value;
}
inline DWORD ConvertBytesToInteger_3(LPBYTE ValueAsBytes)
{
DWORD Value = 0;
Value = (Value << 0x08) | ValueAsBytes[0];
Value = (Value << 0x08) | ValueAsBytes[1];
Value = (Value << 0x08) | ValueAsBytes[2];
return Value;
}
inline DWORD ConvertBytesToInteger_4(LPBYTE ValueAsBytes)
{
DWORD Value = 0;
Value = (Value << 0x08) | ValueAsBytes[0];
Value = (Value << 0x08) | ValueAsBytes[1];
Value = (Value << 0x08) | ValueAsBytes[2];
Value = (Value << 0x08) | ValueAsBytes[3];
return Value;
}
inline DWORD ConvertBytesToInteger_X(LPBYTE ValueAsBytes, DWORD dwByteSize)
{
DWORD Value = 0;
if(dwByteSize > 0)
Value = (Value << 0x08) | ValueAsBytes[0];
if(dwByteSize > 1)
Value = (Value << 0x08) | ValueAsBytes[1];
if(dwByteSize > 2)
Value = (Value << 0x08) | ValueAsBytes[2];
if(dwByteSize > 3)
Value = (Value << 0x08) | ValueAsBytes[3];
return Value;
}
inline DWORD ConvertBytesToInteger_4_LE(LPBYTE ValueAsBytes)
{
DWORD Value = 0;
Value = (Value << 0x08) | ValueAsBytes[3];
Value = (Value << 0x08) | ValueAsBytes[2];
Value = (Value << 0x08) | ValueAsBytes[1];
Value = (Value << 0x08) | ValueAsBytes[0];
return Value;
}
inline ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes)
{
ULONGLONG Value = 0;
Value = (Value << 0x08) | ValueAsBytes[0];
Value = (Value << 0x08) | ValueAsBytes[1];
Value = (Value << 0x08) | ValueAsBytes[2];
Value = (Value << 0x08) | ValueAsBytes[3];
Value = (Value << 0x08) | ValueAsBytes[4];
return Value;
}
inline void ConvertIntegerToBytes_4(DWORD Value, LPBYTE ValueAsBytes)
{
ValueAsBytes[0] = (BYTE)((Value >> 0x18) & 0xFF);
ValueAsBytes[1] = (BYTE)((Value >> 0x10) & 0xFF);
ValueAsBytes[2] = (BYTE)((Value >> 0x08) & 0xFF);
ValueAsBytes[3] = (BYTE)((Value >> 0x00) & 0xFF);
}
inline void ConvertIntegerToBytes_4_LE(DWORD Value, LPBYTE ValueAsBytes)
{
ValueAsBytes[0] = (BYTE)((Value >> 0x00) & 0xFF);
ValueAsBytes[1] = (BYTE)((Value >> 0x08) & 0xFF);
ValueAsBytes[2] = (BYTE)((Value >> 0x10) & 0xFF);
ValueAsBytes[3] = (BYTE)((Value >> 0x18) & 0xFF);
}
inline void ZeroMemory16(void * Buffer)
{
PDWORD PtrBuffer = (PDWORD)Buffer;
PtrBuffer[0] = 0;
PtrBuffer[1] = 0;
PtrBuffer[2] = 0;
PtrBuffer[3] = 0;
}
inline void CopyMemory16(void * Target, void * Source)
{
PDWORD PtrTarget = (PDWORD)Target;
PDWORD PtrSource = (PDWORD)Source;
PtrTarget[0] = PtrSource[0];
PtrTarget[1] = PtrSource[1];
PtrTarget[2] = PtrSource[2];
PtrTarget[3] = PtrSource[3];
}
LPBYTE CaptureInteger16_BE(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue);
LPBYTE CaptureInteger32(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue);
LPBYTE CaptureInteger32_BE(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PDWORD PtrValue);
LPBYTE CaptureByteArray(LPBYTE pbDataPtr, LPBYTE pbDataEnd, size_t nLength, LPBYTE pbOutput);
LPBYTE CaptureContentKey(LPBYTE pbDataPtr, LPBYTE pbDataEnd, PCONTENT_KEY * PtrCKey);
LPBYTE CaptureEncodedKey(LPBYTE pbEKey, LPBYTE pbData, BYTE EKeyLength);
template <typename STRUCTURE>
LPBYTE CaptureStructure(LPBYTE pbDataPtr, LPBYTE pbDataEnd, STRUCTURE ** lpStructure)
{
if((pbDataPtr + sizeof(STRUCTURE)) <= pbDataEnd)
{
lpStructure[0] = (STRUCTURE *)(pbDataPtr);
return pbDataPtr + sizeof(STRUCTURE);
}
return NULL;
}
template <typename STRUCTURE>
LPBYTE CaptureArray(LPBYTE pbDataPtr, LPBYTE pbDataEnd, STRUCTURE ** PtrArray, size_t nCount)
{
size_t nTotalSize = nCount * sizeof(STRUCTURE);
if((pbDataPtr + nTotalSize) <= pbDataEnd)
{
PtrArray[0] = (STRUCTURE *)(pbDataPtr);
return pbDataPtr + nTotalSize;
}
return NULL;
}
template <typename STRUCTURE>
LPBYTE CaptureArrayAsByte(LPBYTE pbDataPtr, LPBYTE pbDataEnd, LPBYTE * PtrArray, size_t nCount)
{
size_t nTotalSize = nCount * sizeof(STRUCTURE);
if((pbDataPtr + nTotalSize) <= pbDataEnd)
{
PtrArray[0] = (LPBYTE)(pbDataPtr);
return pbDataPtr + nTotalSize;
}
return NULL;
}
void CascStrCopy(char * szTarget, size_t cchTarget, const char * szSource, size_t cchSource = -1);
void CascStrCopy(char * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource = -1);
void CascStrCopy(wchar_t * szTarget, size_t cchTarget, const char * szSource, size_t cchSource = -1);
void CascStrCopy(wchar_t * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource = -1);
size_t CascStrPrintfV(char * buffer, size_t nCount, const char * format, va_list argList);
size_t CascStrPrintf(char * buffer, size_t nCount, const char * format, ...);
size_t CascStrPrintfV(wchar_t * buffer, size_t nCount, const wchar_t * format, va_list argList);
size_t CascStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...);
char * CascNewStr(const char * szString, size_t nCharsToReserve = 0);
wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve = 0);
LPSTR CascNewStrT2A(LPCTSTR szString, size_t nCharsToReserve = 0);
LPTSTR CascNewStrA2T(LPCSTR szString, size_t nCharsToReserve = 0);
size_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars);
size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars);
ULONGLONG CalcNormNameHash(const char * szNormName, size_t nLength);
ULONGLONG CalcFileNameHash(const char * szFileName);
template <typename xchar>
bool IsHexadecimalDigit(xchar ch)
{
return ((ch < sizeof(AsciiToHexTable)) && (AsciiToHexTable[ch] != 0xFF));
}
template <typename xchar, typename INTXX>
DWORD ConvertStringToInt(const xchar * szString, size_t nMaxDigits, INTXX & RefValue, const xchar ** PtrStringEnd = NULL)
{
INTXX MaxValueMask = (INTXX)0x0F << ((sizeof(INTXX) * 8) - 4);
INTXX Accumulator = 0;
BYTE DigitOne;
if(nMaxDigits == 0)
nMaxDigits = sizeof(INTXX) * 2;
for(size_t i = 0; i < nMaxDigits; i++, szString++)
{
if(szString[0] > sizeof(AsciiToHexTable))
return ERROR_BAD_FORMAT;
if(szString[0] <= 0x20)
break;
DigitOne = AsciiToHexTable[szString[0]];
if(DigitOne == 0xFF)
return ERROR_BAD_FORMAT;
if(Accumulator & MaxValueMask)
return ERROR_ARITHMETIC_OVERFLOW;
Accumulator = (Accumulator << 4) | DigitOne;
}
if(PtrStringEnd != NULL)
PtrStringEnd[0] = szString;
RefValue = Accumulator;
return ERROR_SUCCESS;
}
template <typename xchar>
DWORD BinaryFromString(const xchar * szString, size_t nMaxDigits, LPBYTE pbBinary)
{
const xchar * szStringEnd = szString + nMaxDigits;
DWORD dwCounter = 0;
BYTE DigitValue;
BYTE ByteValue = 0;
while(szString < szStringEnd)
{
DigitValue = (BYTE)(AsciiToUpperTable_BkSlash[szString[0]] - '0');
if(DigitValue > 9)
DigitValue -= 'A' - '9' - 1;
if(DigitValue > 0x0F)
return ERROR_BAD_FORMAT;
ByteValue = (ByteValue << 0x04) | DigitValue;
dwCounter++;
if((dwCounter & 0x01) == 0)
*pbBinary++ = ByteValue;
szString++;
}
return ERROR_SUCCESS;
}
template <typename xchar>
xchar * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, xchar * szBuffer)
{
xchar * szSaveBuffer = szBuffer;
if(pbBinary && cbBinary)
{
for(size_t i = 0; i < cbBinary; i++)
{
*szBuffer++ = IntToHexChar[pbBinary[i] >> 0x04];
*szBuffer++ = IntToHexChar[pbBinary[i] & 0x0F];
}
}
*szBuffer = 0;
return szSaveBuffer;
}
struct CASC_BLOB
{
CASC_BLOB()
{
Reset();
}
~CASC_BLOB()
{
Free();
}
void MoveFrom(CASC_BLOB & Source)
{
Free();
pbData = Source.pbData;
cbData = Source.cbData;
Source.Reset();
}
DWORD SetData(const void * pv, size_t cb)
{
if(SetSize(cb) != ERROR_SUCCESS)
return ERROR_NOT_ENOUGH_MEMORY;
memcpy(pbData, pv, cb);
return ERROR_SUCCESS;
}
DWORD SetSize(size_t cb)
{
Free();
if((pbData = CASC_ALLOC<BYTE>(cb + 1)) == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
cbData = cb;
return ERROR_SUCCESS;
}
void Reset()
{
pbData = NULL;
cbData = 0;
}
void Free()
{
if(pbData != NULL)
CASC_FREE(pbData);
pbData = NULL;
cbData = 0;
}
LPBYTE End() const
{
return pbData + cbData;
}
bool Valid() const
{
return pbData && cbData;
}
LPBYTE pbData;
size_t cbData;
};
typedef CASC_BLOB *PCASC_BLOB;
template <typename XCHAR>
const XCHAR * GetPlainFileName(const XCHAR * szFileName)
{
const XCHAR * szPlainName = szFileName;
while(*szFileName != 0)
{
if(*szFileName == '\\' || *szFileName == '/')
szPlainName = szFileName + 1;
szFileName++;
}
return szPlainName;
}
template <typename XCHAR>
const XCHAR * GetFileExtension(const XCHAR * szFileName)
{
const XCHAR * szExtension = NULL;
szFileName = GetPlainFileName(szFileName);
while(szFileName[0] != 0)
{
if(szFileName[0] == '.')
szExtension = szFileName;
szFileName++;
}
return (XCHAR *)((szExtension != NULL) ? szExtension : szFileName);
}
bool IsFileDataIdName(const char * szFileName, DWORD & FileDataId);
bool IsFileCKeyEKeyName(const char * szFileName, LPBYTE PtrKeyBuffer);
bool CascCheckWildCard(const char * szString, const char * szWildCard);
bool CascIsValidMD5(LPBYTE pbMd5);
void CascHash_MD5(const void * pvDataBlock, size_t cbDataBlock, LPBYTE md5_hash);
void CascHash_SHA1(const void * pvDataBlock, size_t cbDataBlock, LPBYTE sha1_hash);
bool CascVerifyDataBlockHash(void * pvDataBlock, size_t cbDataBlock, LPBYTE expected_md5);
template <typename ARG, typename ARG_HOLDER>
bool ExtractVersionedArgument(const ARG_HOLDER * pHolder, size_t ArgOffset, ARG * pArg)
{
if (pHolder == NULL)
return false;
if (ArgOffset + sizeof(ARG) > pHolder->Size)
return false;
*pArg = *((ARG *)(((char*)pHolder) + ArgOffset));
return true;
}
#endif