diff options
Diffstat (limited to 'dep/CascLib/src/CascStructs.h')
-rw-r--r-- | dep/CascLib/src/CascStructs.h | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/dep/CascLib/src/CascStructs.h b/dep/CascLib/src/CascStructs.h new file mode 100644 index 00000000000..f67da810c9e --- /dev/null +++ b/dep/CascLib/src/CascStructs.h @@ -0,0 +1,255 @@ +/*****************************************************************************/ +/* CascStructs.h Copyright (c) Ladislav Zezula 2019 */ +/*---------------------------------------------------------------------------*/ +/* On-disk structures for CASC storages */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 28.04.19 1.00 Lad The first version of CascStructs.h */ +/*****************************************************************************/ + +#ifndef __CASC_STRUCTS_H__ +#define __CASC_STRUCTS_H__ + +//----------------------------------------------------------------------------- +// Common definitions + +#define CASC_INDEX_COUNT 0x10 // Number of index files +#define CASC_CKEY_SIZE 0x10 // Size of the content key +#define CASC_EKEY_SIZE 0x09 // Size of the encoded key +#define CASC_MAX_DATA_FILES 0x100 // Maximum number of data files + +//----------------------------------------------------------------------------- +// The index files structures + +#define FILE_INDEX_PAGE_SIZE 0x200 // Number of bytes in one page of EKey items + +// Structure describing the 32-bit block size and 32-bit Jenkins hash of the block +typedef struct _BLOCK_SIZE_AND_HASH +{ + DWORD cbBlockSize; + DWORD dwBlockHash; + +} BLOCK_SIZE_AND_HASH, *PBLOCK_SIZE_AND_HASH; + +// Checksum describing a block in the index file (v2) +typedef struct _FILE_INDEX_GUARDED_BLOCK +{ + DWORD BlockSize; + DWORD BlockHash; + +} FILE_INDEX_GUARDED_BLOCK, *PFILE_INDEX_GUARDED_BLOCK; + +// Structure of the header of the index files version 1 +typedef struct _FILE_INDEX_HEADER_V1 +{ + USHORT IndexVersion; // Must be 0x05 + BYTE BucketIndex; // The bucket index of this file; should be the same as the first byte of the hex filename. + BYTE align_3; + DWORD field_4; + ULONGLONG field_8; + ULONGLONG SegmentSize; // Size of one data segment (aka data.### file) + BYTE EncodedSizeLength; // Length, in bytes, of the EncodedSize in the EKey entry + BYTE StorageOffsetLength; // Length, in bytes, of the StorageOffset field in the EKey entry + BYTE EKeyLength; // Length of the encoded key (bytes) + BYTE FileOffsetBits; // Number of bits of the archive file offset in StorageOffset field. Rest is data segment index + DWORD EKeyCount1; + DWORD EKeyCount2; + DWORD KeysHash1; + DWORD KeysHash2; + DWORD HeaderHash; +} FILE_INDEX_HEADER_V1, *PFILE_INDEX_HEADER_V1; + +typedef struct _FILE_INDEX_HEADER_V2 +{ + USHORT IndexVersion; // Must be 0x07 + BYTE BucketIndex; // The bucket index of this file; should be the same as the first byte of the hex filename. + BYTE ExtraBytes; // Unknown; must be 0 + BYTE EncodedSizeLength; // Length, in bytes, of the EncodedSize in the EKey entry + BYTE StorageOffsetLength; // Length, in bytes, of the StorageOffset field in the EKey entry + BYTE EKeyLength; // Length of the encoded key (bytes) + BYTE FileOffsetBits; // Number of bits of the archive file offset in StorageOffset field. Rest is data segment index + ULONGLONG SegmentSize; // Size of one data segment (aka data.### file) + +} FILE_INDEX_HEADER_V2, *PFILE_INDEX_HEADER_V2; + +// The EKey entry from the ".idx" files. Note that the lengths are optional and controlled by the FILE_INDEX_HEADER_Vx +typedef struct _FILE_EKEY_ENTRY +{ + BYTE EKey[CASC_EKEY_SIZE]; // The first 9 bytes of the encoded key + BYTE FileOffsetBE[5]; // Index of data file and offset within (big endian). + BYTE EncodedSize[4]; // Encoded size (big endian). This is the size of encoded header, all file frame headers and all file frames +} FILE_EKEY_ENTRY, *PFILE_EKEY_ENTRY; + +//----------------------------------------------------------------------------- +// The archive index (md5.index) files structures +// https://wowdev.wiki/TACT#CDN_File_Organization + +template <int CHKSUM_LENGTH> +struct FILE_INDEX_FOOTER +{ + BYTE TocHash[MD5_HASH_SIZE]; // Client tries to read with 0x10, then backs off in size when smaller + BYTE Version; // Version of the index header + BYTE Reserved[2]; // Length, in bytes, of the file offset field + BYTE PageSizeKB; // Length, in kilobytes, of the index page + BYTE OffsetBytes; // Normally 4 for archive indices, 6 for group indices, and 0 for loose file indices + BYTE SizeBytes; // Normally 4 + BYTE EKeySizeBytes; // Normally 16 + BYTE FooterHashBytes; // Normally 8, <= 0x10 + BYTE ElementCount[4]; // BigEndian in _old_ versions (e.g. 18179) + BYTE FooterHash[CHKSUM_LENGTH]; +}; + +//----------------------------------------------------------------------------- +// The ENCODING manifest structures +// +// The ENCODING file is in the form of: +// * File header. Fixed length. +// * Encoding Specification (ESpec) in the string form. Length is stored in FILE_ENCODING_HEADER::ESpecBlockSize +// https://wowdev.wiki/CASC#Encoding +// https://wowdev.wiki/TACT#Encoding_table +// + +#define FILE_MAGIC_ENCODING 0x4E45 // 'EN' + +// File header of the ENCODING manifest +typedef struct _FILE_ENCODING_HEADER +{ + USHORT Magic; // FILE_MAGIC_ENCODING ('EN') + BYTE Version; // Expected to be 1 by CascLib + BYTE CKeyLength; // The content key length in ENCODING file. Usually 0x10 + BYTE EKeyLength; // The encoded key length in ENCODING file. Usually 0x10 + BYTE CKeyPageSize[2]; // Size of the CKey page, in KB (big-endian) + BYTE EKeyPageSize[2]; // Size of the EKey page, in KB (big-endian) + BYTE CKeyPageCount[4]; // Number of CKey pages in the table (big endian) + BYTE EKeyPageCount[4]; // Number of EKey pages in the table (big endian) + BYTE field_11; // Asserted to be zero by the agent + BYTE ESpecBlockSize[4]; // Size of the ESpec string block + +} FILE_ENCODING_HEADER, *PFILE_ENCODING_HEADER; + +// Page header of the ENCODING manifest +typedef struct _FILE_CKEY_PAGE +{ + BYTE FirstKey[MD5_HASH_SIZE]; // The first CKey/EKey in the segment + BYTE SegmentHash[MD5_HASH_SIZE]; // MD5 hash of the entire segment + +} FILE_CKEY_PAGE, *PFILE_CKEY_PAGE; + +// Single entry in the page +typedef struct _FILE_CKEY_ENTRY +{ + USHORT EKeyCount; // Number of EKeys + BYTE ContentSize[4]; // Content file size (big endian) + BYTE CKey[CASC_CKEY_SIZE]; // Content key. This is MD5 of the file content + BYTE EKey[CASC_CKEY_SIZE]; // Encoded key. This is (trimmed) MD5 hash of the file header, containing MD5 hashes of all the logical blocks of the file + +} FILE_CKEY_ENTRY, *PFILE_CKEY_ENTRY; + +typedef struct _FILE_ESPEC_ENTRY +{ + BYTE ESpecKey[MD5_HASH_SIZE]; // The ESpec key of the file + BYTE ESpecIndexBE[4]; // Index of ESPEC entry, assuming zero-terminated strings (big endian) + BYTE FileSizeBE[5]; // Size of the encoded version of the file (big endian) + +} FILE_ESPEC_ENTRY, *PFILE_ESPEC_ENTRY; + +//----------------------------------------------------------------------------- +// The DOWNLOAD manifest structures +// +// See https://wowdev.wiki/TACT#Download_manifest +// + +#define FILE_MAGIC_DOWNLOAD 0x4C44 // 'DL' + +// File header of the DOWNLOAD manifest +typedef struct _FILE_DOWNLOAD_HEADER +{ + USHORT Magic; // FILE_MAGIC_DOWNLOAD ('DL') + BYTE Version; // Expected to be 1 by CascLib + BYTE EKeyLength; // The content key length in DOWNLOAD file. Expected to be 0x10 + BYTE EntryHasChecksum; // If nonzero, then the entry has checksum. + BYTE EntryCount[4]; // Number of entries (big-endian) + BYTE TagCount[2]; // Number of tag entries (big endian) + + // Version 2 or newer + BYTE FlagByteSize; // Number of flag bytes + + // Verion 3 or newer + BYTE BasePriority; + BYTE Unknown2[3]; + +} FILE_DOWNLOAD_HEADER, *PFILE_DOWNLOAD_HEADER; + +typedef struct _FILE_DOWNLOAD_ENTRY +{ + BYTE EKey[MD5_HASH_SIZE]; // Encoding key (variable length) + BYTE FileSize[5]; // File size + BYTE Priority; + + // DWORD Checksum [optional] + // BYTE Flags; + +} FILE_DOWNLOAD_ENTRY, *PFILE_DOWNLOAD_ENTRY; + +//----------------------------------------------------------------------------- +// The INSTALL manifest structures +// +// See https://wowdev.wiki/TACT#Install_manifest +// + +#define FILE_MAGIC_INSTALL 0x4E49 // 'IN' + +// File header of the INSTALL manifest +typedef struct _FILE_INSTALL_HEADER +{ + USHORT Magic; // FILE_MAGIC_INSTALL ('DL') + BYTE Version; // Expected to be 1 by CascLib + BYTE EKeyLength; // The content key length in INSTALL file. Expected to be 0x10 + BYTE TagCount[2]; // Number of tag entries (big endian) + BYTE EntryCount[4]; // Number of entries (big-endian) + +} FILE_INSTALL_HEADER, *PFILE_INSTALL_HEADER; + +//----------------------------------------------------------------------------- +// Data file structures + +#define BLTE_HEADER_SIGNATURE 0x45544C42 // 'BLTE' header in the data files +#define BLTE_HEADER_DELTA 0x1E // Distance of BLTE header from begin of the header area +#define MAX_ENCODED_HEADER 0x1000 // Starting size for the frame headers + +typedef struct _BLTE_HEADER +{ + BYTE Signature[4]; // Must be "BLTE" + BYTE HeaderSize[4]; // Header size in bytes (big endian) + BYTE MustBe0F; // Must be 0x0F. Optional, only if HeaderSize != 0 + BYTE FrameCount[3]; // Frame count (big endian). Optional, only if HeaderSize != 0 +} BLTE_HEADER, *PBLTE_HEADER; + +typedef struct _BLTE_ENCODED_HEADER +{ + // Header span. + ENCODED_KEY EKey; // Encoded key of the data beginning with "BLTE" (byte-reversed) + DWORD EncodedSize; // Encoded size of the data data beginning with "BLTE" (little endian) + BYTE field_14; // Seems to be 1 if the header span has no data + BYTE field_15; // Hardcoded to zero (Agent.exe 2.15.0.6296: 01370000->0148E2AA) + BYTE JenkinsHash[4]; // Jenkins hash (hashlittle2) of the preceding fields (EKey + EncodedSize + field_14 + field_15) (little endian) + BYTE Checksum[4]; // Checksum of the previous part. See "VerifyHeaderSpan()" for more information. + + // BLTE header. Always present. + BYTE Signature[4]; // Must be "BLTE" + BYTE HeaderSize[4]; // Header size in bytes (big endian) + BYTE MustBe0F; // Must be 0x0F. Optional, only if HeaderSize != 0 + BYTE FrameCount[3]; // Frame count (big endian). Optional, only if HeaderSize != 0 +} BLTE_ENCODED_HEADER, *PBLTE_ENCODED_HEADER; + +typedef struct _BLTE_FRAME +{ + BYTE EncodedSize[4]; // Encoded frame size (big endian) + BYTE ContentSize[4]; // Content frame size (big endian) + CONTENT_KEY FrameHash; // Hash of the encoded frame + +} BLTE_FRAME, *PBLTE_FRAME; + +#endif // __CASC_STRUCTS_H__ + |