mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-20 09:17:36 +01:00
256 lines
13 KiB
C++
256 lines
13 KiB
C++
/*****************************************************************************/
|
|
/* 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 EKeyLength; // 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__
|
|
|