aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/CascStructs.h
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src/CascStructs.h')
-rw-r--r--dep/CascLib/src/CascStructs.h255
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__
+