From c7b41574376c21eb37ed6d45dc4f1b3bf1b528c4 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 29 Oct 2019 19:01:39 +0100 Subject: Dep/CascLib: Update to ladislav-zezula/CascLib@225777494069b0b0e18bea3ffeb3773d44a70b30 --- dep/CascLib/src/CascCommon.h | 16 +++ dep/CascLib/src/CascDecrypt.cpp | 119 ++++++++++++------- dep/CascLib/src/CascFiles.cpp | 24 +++- dep/CascLib/src/CascIndexFiles.cpp | 211 +++++++++++++++++++++------------- dep/CascLib/src/CascLib.def | 8 +- dep/CascLib/src/CascLib.h | 12 +- dep/CascLib/src/CascOpenStorage.cpp | 144 +++++++++++++++-------- dep/CascLib/src/CascPort.h | 16 ++- dep/CascLib/src/CascRootFile_TVFS.cpp | 72 +++++++++--- dep/CascLib/src/DllMain.rc | 8 +- dep/CascLib/src/common/Common.h | 12 +- dep/CascLib/src/common/Directory.cpp | 8 +- dep/CascLib/src/common/Directory.h | 10 +- dep/CascLib/src/common/FileStream.cpp | 2 +- dep/CascLib/src/common/ListFile.cpp | 2 +- dep/CascLib/src/common/Map.h | 4 +- 16 files changed, 433 insertions(+), 235 deletions(-) (limited to 'dep/CascLib/src') diff --git a/dep/CascLib/src/CascCommon.h b/dep/CascLib/src/CascCommon.h index a0caa5d85eb..7700c782cbf 100644 --- a/dep/CascLib/src/CascCommon.h +++ b/dep/CascLib/src/CascCommon.h @@ -86,6 +86,16 @@ typedef struct _CASC_TAG_ENTRY char TagName[1]; // Tag name. Variable length. } CASC_TAG_ENTRY, *PCASC_TAG_ENTRY; +// Information about index file +typedef struct _CASC_INDEX +{ + LPTSTR szFileName; // Full name of the index file + LPBYTE pbFileData; // Loaded content of the index file + size_t cbFileData; // Size of the index file + DWORD NewSubIndex; // New subindex + DWORD OldSubIndex; // Old subindex +} CASC_INDEX, *PCASC_INDEX; + // Normalized header of the index files. // Both version 1 and version 2 are converted to this structure typedef struct _CASC_INDEX_HEADER @@ -292,6 +302,8 @@ struct TCascStorage QUERY_KEY BuildFiles; // List of supported build files TFileStream * DataFiles[CASC_MAX_DATA_FILES]; // Array of open data files + CASC_INDEX IndexFiles[CASC_INDEX_COUNT]; // Array of found index files + CASC_MAP IndexEKeyMap; CASC_CKEY_ENTRY EncodingCKey; // Information about ENCODING file CASC_CKEY_ENTRY DownloadCKey; // Information about DOWNLOAD file @@ -317,6 +329,7 @@ struct TCascStorage CASC_ARRAY ExtraKeysList; // List additional encryption keys CASC_MAP EncryptionKeys; // Map of encryption keys + ULONGLONG LastFailKeyName; // The value of the encryption key that recently was NOT found. }; @@ -465,7 +478,10 @@ DWORD CascDecrypt(TCascStorage * hs, LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LP //----------------------------------------------------------------------------- // Support for index files +bool CopyEKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry); + DWORD LoadIndexFiles(TCascStorage * hs); +void FreeIndexFiles(TCascStorage * hs); //----------------------------------------------------------------------------- // Support for ROOT file diff --git a/dep/CascLib/src/CascDecrypt.cpp b/dep/CascLib/src/CascDecrypt.cpp index 1e07342d9c5..308be6cab46 100644 --- a/dep/CascLib/src/CascDecrypt.cpp +++ b/dep/CascLib/src/CascDecrypt.cpp @@ -16,7 +16,6 @@ // Local structures #define CASC_EXTRA_KEYS 0x80 -#define CASC_KEY_LENGTH 0x10 typedef struct _CASC_ENCRYPTION_KEY { @@ -48,6 +47,10 @@ static CASC_ENCRYPTION_KEY CascKeys[] = // Starcraft // { 0xD0CAE11366CEEA83ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? }}, // 1.12.3.2609 (build 45364) + // Warcraft III Reforged beta (build) + { 0x6E4296823E7D561EULL, { 0xC0, 0xBF, 0xA2, 0x94, 0x3A, 0xC3, 0xE9, 0x22, 0x86, 0xE4, 0x44, 0x3E, 0xE3, 0x56, 0x0D, 0x65 }}, // Build 13369 + { 0xE04D60E31DDEBF63ULL, { 0x26, 0x3D, 0xB5, 0xC4, 0x02, 0xDA, 0x8D, 0x4D, 0x68, 0x63, 0x09, 0xCB, 0x2E, 0x32, 0x54, 0xD0 }}, // Build 13445 + // Overwatch { 0xFB680CB6A8BF81F3ULL, { 0x62, 0xD9, 0x0E, 0xFA, 0x7F, 0x36, 0xD7, 0x1C, 0x39, 0x8A, 0xE2, 0xF1, 0xFE, 0x37, 0xBD, 0xB9 } }, // 0.8.0.24919_retailx64 (hardcoded) { 0x402CD9D8D6BFED98ULL, { 0xAE, 0xB0, 0xEA, 0xDE, 0xA4, 0x76, 0x12, 0xFE, 0x6C, 0x04, 0x1A, 0x03, 0x95, 0x8D, 0xF2, 0x41 } }, // 0.8.0.24919_retailx64 (hardcoded) @@ -208,7 +211,7 @@ static CASC_ENCRYPTION_KEY CascKeys[] = { 0x0C9ABD5081C06411ULL, { 0x25, 0xA7, 0x7C, 0xD8, 0x00, 0x19, 0x7E, 0xE6, 0xA3, 0x2D, 0xD6, 0x3F, 0x04, 0xE1, 0x15, 0xFA } }, // 230 WOW-26871patch8.0.1_Beta zcf cinematic { 0x3C6243057F3D9B24ULL, { 0x58, 0xAE, 0x3E, 0x06, 0x42, 0x10, 0xE3, 0xED, 0xF9, 0xC1, 0x25, 0x9C, 0xDE, 0x91, 0x4C, 0x5D } }, // 231 WOW-26871patch8.0.1_Beta ktf cinematic { 0x7827FBE24427E27DULL, { 0x34, 0xA4, 0x32, 0x04, 0x20, 0x73, 0xCD, 0x0B, 0x51, 0x62, 0x70, 0x68, 0xD2, 0xE0, 0xBD, 0x3E } }, // 232 WOW-26871patch8.0.1_Beta rot cinematic - { 0xFAF9237E1186CF66ULL, { 0xAE, 0x78, 0x78, 0x40, 0x04, 0x1E, 0x9B, 0x41, 0x98, 0xF4, 0x79, 0x71, 0x4D, 0xAD, 0x56, 0x2C } }, // 233 WOW-28048patch8.1.0_PTR encrypted db2 sections (battle pet?) + { 0xFAF9237E1186CF66ULL, { 0xAE, 0x78, 0x78, 0x40, 0x04, 0x1E, 0x9B, 0x41, 0x98, 0xF4, 0x79, 0x71, 0x4D, 0xAD, 0x56, 0x2C } }, // 233 WOW-28048patch8.1.0_PTR DB2 partial encryption test battle pet // { 0x5DD92EE32BBF9ABDULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 234 WOW-27004patch8.0.1_Subm filedataid 2238294 { 0x0B68A7AF5F85F7EEULL, { 0x27, 0xAA, 0x01, 0x10, 0x82, 0xF5, 0xE8, 0xBB, 0xBD, 0x71, 0xD1, 0xBA, 0x04, 0xF6, 0xAB, 0xA4 } }, // 236 WOW-28151patch8.1.0_PTR encrypted06 Flying pig mount // { 0x01531713C83FCC39ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 237 WOW-28151patch8.1.0_PTR fdid 2460009, 2460732 @@ -218,31 +221,37 @@ static CASC_ENCRYPTION_KEY CascKeys[] = { 0xE2F6BD41298A2AB9ULL, { 0xC5, 0xDC, 0x1B, 0xB4, 0x3B, 0x8C, 0xF3, 0xF0, 0x85, 0xD6, 0x98, 0x68, 0x26, 0xB9, 0x28, 0xEC } }, // 241 WOW-28151patch8.1.0_PTR Horde fireworks { 0x14C4257E557B49A1ULL, { 0x06, 0x4A, 0x97, 0x09, 0xF4, 0x2D, 0x50, 0xCB, 0x5F, 0x8B, 0x94, 0xBC, 0x1A, 0xCF, 0xDD, 0x5D } }, // 242 WOW-28440patch8.1.0_PTR dor cinematic { 0x1254E65319C6EEFFULL, { 0x79, 0xD2, 0xB3, 0xD1, 0xCC, 0xB0, 0x15, 0x47, 0x4E, 0x71, 0x58, 0x81, 0x38, 0x64, 0xB8, 0xE6 } }, // 243 WOW-28440patch8.1.0_PTR akt cinematic - { 0xC8753773ADF1174CULL, { 0x1E, 0x0E, 0x37, 0xD4, 0x2E, 0xE5, 0xCE, 0x5E, 0x80, 0x67, 0xF0, 0x39, 0x4B, 0x09, 0x05, 0xF2 } }, // 244 WOW-28938patch8.1.5_PTR starts at fdid 2615771, total of 15 fdids + { 0xC8753773ADF1174CULL, { 0x1E, 0x0E, 0x37, 0xD4, 0x2E, 0xE5, 0xCE, 0x5E, 0x80, 0x67, 0xF0, 0x39, 0x4B, 0x09, 0x05, 0xF2 } }, // 244 WOW-28938patch8.1.5_PTR Obsidian Worldbreaker mount & Lil' Nefarian pet // { 0x2170BCAA9FA96E22ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 245 WOW-28938patch8.1.5_PTR alpaca mount // { 0x75485627AA225F4DULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 246 WOW-28938patch8.1.5_PTR fdid 2741546, 2741548, 2741549 { 0x08717B15BF3C7955ULL, { 0x4B, 0x06, 0xBF, 0x9D, 0x17, 0x66, 0x3C, 0xEB, 0x33, 0x12, 0xEA, 0x3C, 0x69, 0xFB, 0xC5, 0xDD } }, // 248 WOW-29220patch8.1.5_PTR inv_encrypted20.blp (fdid 2823166) -// { 0xD19DCF7ACA8D96D6ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 249 WOW-30080patch8.2.0_PTR starts at fdid 2843110, total of 10 fdids +// { 0xD19DCF7ACA8D96D6ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 249 WOW-30080patch8.2.0_PTR starts at fdid 2843110, 10 files { 0x9FD609902B4B2E07ULL, { 0xAB, 0xE0, 0xC5, 0xF9, 0xC1, 0x23, 0xE6, 0xE2, 0x4E, 0x7B, 0xEA, 0x43, 0xC2, 0xBF, 0x00, 0xAC } }, // 250 WOW-29418patch8.1.5_PTR Derek Proudmoore cinematic (dpr, 5 files) // { 0xCB26B441FAE4C8CDULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 251 WOW-30080patch8.2.0_PTR fdid 2888623, 2892270, 2892271, 2892272, 2892274, 2892275 -// { 0xA98C7594F55C02F0ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 252 WOW-30080patch8.2.0_PTR starts at fdid 2921871, total of 24 fdids - { 0x259EE68CD9E76DBAULL, { 0x46, 0x5D, 0x78, 0x4F, 0x10, 0x19, 0x66, 0x1C, 0xCF, 0x41, 0x7F, 0xE4, 0x66, 0x80, 0x12, 0x83 } }, // 253 WOW-30080patch8.2.0_PTR starts at fdid 2957406, total of 30 fdids -// { 0x6A026290FBDB3754ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 255 WOW-30080patch8.2.0_PTR starts at fdid 2976294, total of 201 fdids + { 0xA98C7594F55C02F0ULL, { 0xEE, 0xDB, 0x77, 0x47, 0x3B, 0x72, 0x1D, 0xED, 0x62, 0x04, 0xA9, 0x76, 0xC9, 0xA6, 0x61, 0xE7 } }, // 252 WOW-30080patch8.2.0_PTR BlizzCon 2019 - Murloc pets + { 0x259EE68CD9E76DBAULL, { 0x46, 0x5D, 0x78, 0x4F, 0x10, 0x19, 0x66, 0x1C, 0xCF, 0x41, 0x7F, 0xE4, 0x66, 0x80, 0x12, 0x83 } }, // 253 WOW-30080patch8.2.0_PTR Alabaster mounts (30 files) + { 0x6A026290FBDB3754ULL, { 0x3D, 0x2D, 0x62, 0x08, 0x50, 0xA6, 0x76, 0x5D, 0xD5, 0x91, 0x22, 0x4F, 0x60, 0x5B, 0x94, 0x9A } }, // 255 WOW-30080patch8.2.0_PTR BlizzCon 2019 - Wendigo transmog set { 0xCF72FD04608D36EDULL, { 0xA0, 0xA8, 0x89, 0x97, 0x6D, 0x02, 0xFA, 0x8D, 0x00, 0xF7, 0xAF, 0x00, 0x17, 0xAD, 0x72, 0x1F } }, // 257 WOW-30262patch8.2.0_PTR Azshara Warbringer cinematic (5 files) - { 0x17F07C2E3A45DB3DULL, { 0x6D, 0x38, 0x86, 0xBD, 0xB9, 0x1E, 0x71, 0x5A, 0xE7, 0x18, 0x2D, 0x9F, 0x3A, 0x08, 0xF2, 0xC9 } }, // 258 WOW-30262patch8.2.0_PTR Solesa Naksu Nazjatar phase (17 files) -// { 0xDFAB5841B87802B5ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 259 WOW-31337patch8.2.5_PTR starts at fdid 3016206, total of 8 fdids + { 0x17F07C2E3A45DB3DULL, { 0x6D, 0x38, 0x86, 0xBD, 0xB9, 0x1E, 0x71, 0x5A, 0xE7, 0x18, 0x2D, 0x9F, 0x3A, 0x08, 0xF2, 0xC9 } }, // 258 WOW-30262patch8.2.0_PTR Solesa Naksu Nazjatar phase (34 files) +// { 0xDFAB5841B87802B5ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 259 WOW-31337patch8.2.5_PTR starts at fdid 3016206, 8 files, 3016206 is a creature { 0xC050FA06BB0538F6ULL, { 0xC5, 0x52, 0xF5, 0xD0, 0xB7, 0x22, 0x31, 0x50, 0x2D, 0x25, 0x47, 0x31, 0x4E, 0x60, 0x15, 0xF7 } }, // 260 WOW-30495patch8.2.0_PTR Crossroads cinematic (5 files) { 0xAB5CDD3FC321831FULL, { 0xE1, 0x38, 0x4F, 0x5B, 0x06, 0xEB, 0xBC, 0xD3, 0x33, 0x69, 0x5A, 0xA6, 0xFF, 0xC6, 0x83, 0x18 } }, // 261 WOW-30495patch8.2.0_PTR Azshara kill cinematic (5 files) { 0xA7B7D1F12395040EULL, { 0x36, 0xAD, 0x3B, 0x31, 0x27, 0x3F, 0x1E, 0xBC, 0xEE, 0x85, 0x20, 0xAA, 0xA7, 0x4B, 0x12, 0xF2 } }, // 262 WOW-30495patch8.2.0_PTR Nazjatar intro cinematics (9 files) -// { 0x83A2AB72DD8AE992ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 263 WOW-31337patch8.2.5_PTR starts at fdid 801707, total of 372 fdids -// { 0xBEAF567CC45362F0ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 264 WOW-31337patch8.2.5_PTR starts at fdid 1002186, total of 71 fdids -// { 0x7BB3A77FD8D14783ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 265 WOW-31337patch8.2.5_PTR fdid 1251882, 1251883 -// { 0x8F4098E2470FE0C8ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 266 WOW-31337patch8.2.5_PTR starts at fdid 841604, total of 58 fdids -// { 0x6AC5C837A2027A6BULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 267 WOW-31337patch8.2.5_PTR starts at fdid 3037834, total of 263 fdids -// { 0x302AAD8B1F441D95ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 271 WOW-31337patch8.2.5_PTR starts at fdid 1376212, total of 300 fdids -// { 0x5C909F00088734B9ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 272 WOW-31337patch8.2.5_PTR -// { 0xF785977C76DE9C77ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 273 WOW-31337patch8.2.5_PTR starts at fdid 3071600, total of 295 fdids -// { 0x1CDAF3931871BEC3ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 275 WOW-31337patch8.2.5_PTR fdid 988200, 1140079, 1263818, 1347275 + { 0x83A2AB72DD8AE992ULL, { 0x02, 0x3C, 0xFF, 0x06, 0x2B, 0x19, 0xA5, 0x29, 0xB9, 0xF1, 0x4F, 0x9B, 0x7A, 0xAA, 0xC5, 0xBB } }, // 263 WOW-31337patch8.2.5_PTR 8.2.5 War Campaign scenario/models + { 0xBEAF567CC45362F0ULL, { 0x8B, 0xD3, 0xED, 0x79, 0x24, 0x05, 0xD9, 0xEE, 0x74, 0x2B, 0xF6, 0xAF, 0xA9, 0x44, 0x57, 0x8A } }, // 264 WOW-31337patch8.2.5_PTR 8.2.5 War Campaign quests/vo + { 0x7BB3A77FD8D14783ULL, { 0x4C, 0x94, 0xE3, 0x60, 0x9C, 0xFE, 0x0A, 0x82, 0x00, 0x0A, 0x0B, 0xD4, 0x60, 0x69, 0xAC, 0x6F } }, // 265 WOW-31337patch8.2.5_PTR 8.2.5 War Campaign epilogue quests + { 0x8F4098E2470FE0C8ULL, { 0xAA, 0x71, 0x8D, 0x1F, 0x1A, 0x23, 0x07, 0x8D, 0x49, 0xAD, 0x0C, 0x60, 0x6A, 0x72, 0xF3, 0xD5 } }, // 266 WOW-31337patch8.2.5_PTR 8.2.5 War Campaign epilogue in-game cinematic +// { 0x6AC5C837A2027A6BULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 267 WOW-31337patch8.2.5_PTR starts at fdid 3037834, 263 files, 3037834 & 3040716 are creatures + { 0x302AAD8B1F441D95ULL, { 0x24, 0xB8, 0x64, 0x38, 0xCF, 0x02, 0x53, 0x86, 0x49, 0xE5, 0xBA, 0x67, 0x2F, 0xD5, 0x99, 0x3A } }, // 271 WOW-31337patch8.2.5_PTR RaF mounts & armor +// { 0x5C909F00088734B9ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 272 WOW-31337patch8.2.5_PTR Unused in 8.2.5 +// { 0xF785977C76DE9C77ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 273 WOW-31337patch8.2.5_PTR starts at fdid 3071600, 313 files, Winter Veil? +// { 0x1CDAF3931871BEC3ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 275 WOW-31337patch8.2.5_PTR unknown toy/achievement, 28 files + { 0x814E1AB43F3F9345ULL, { 0xB6, 0x5E, 0x2A, 0x63, 0xA1, 0x16, 0xAA, 0x25, 0x1F, 0xA5, 0xD7, 0xB0, 0xBA, 0xAB, 0xF7, 0x78 } }, // 276 WOW-31599patch8.2.5_PTR The Negotiation cinematic (5 files) + { 0x1FBE97A317FFBEFAULL, { 0xBD, 0x71, 0xF7, 0x8D, 0x43, 0x11, 0x7C, 0x68, 0x72, 0x4B, 0xB6, 0xE0, 0xD9, 0x57, 0x7E, 0x08 } }, // 277 WOW-31599patch8.2.5_PTR Reckoning cinematic (5 files) +// { 0x4287F49A5BB366DAULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 279 WOW-31599patch8.2.5_PTR Unused in 8.2.5 +// { 0x01C82EE0725EDA3AULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 281 WOW-31812patch8.2.5_PTR Unused in 8.2.5 +// { 0x04C0C50B5BE0CC78ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 282 WOW-31812patch8.2.5_PTR Unused in 8.2.5 +// { 0xA26FD104489B3DE5ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 283 WOW-31812patch8.2.5_PTR Unused in 8.2.5 }; //----------------------------------------------------------------------------- @@ -458,7 +467,10 @@ DWORD CascDecrypt(TCascStorage * hs, LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LP // Check if we know the key pbKey = CascFindKey(hs, KeyName); if(pbKey == NULL) + { + hs->LastFailKeyName = KeyName; return ERROR_FILE_ENCRYPTED; + } // Shuffle the Vector with the block index // Note that there's no point to go beyond 32 bits, unless the file has @@ -537,39 +549,39 @@ bool WINAPI CascAddEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPBYTE Key) pEncKey->KeyName = KeyName; // Also insert the key to the map - if (!hs->EncryptionKeys.InsertObject(pEncKey, &pEncKey->KeyName)) - { - SetLastError(ERROR_ALREADY_EXISTS); - return false; - } + if (!hs->EncryptionKeys.InsertObject(pEncKey, &pEncKey->KeyName)) + { + SetLastError(ERROR_ALREADY_EXISTS); + return false; + } - return true; + return true; } bool WINAPI CascAddStringEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPCSTR szKey) { - BYTE Key[CASC_KEY_LENGTH]; - - // Check the length of the string key - if(strlen(szKey) != CASC_KEY_LENGTH * 2) - { - SetLastError(ERROR_INVALID_PARAMETER); - return false; - } - - // Convert the string key to the binary array - if(ConvertStringToBinary(szKey, CASC_KEY_LENGTH * 2, Key) != ERROR_SUCCESS) - { - SetLastError(ERROR_INVALID_PARAMETER); - return false; - } - - return CascAddEncryptionKey(hStorage, KeyName, Key); + BYTE Key[CASC_KEY_LENGTH]; + + // Check the length of the string key + if(strlen(szKey) != CASC_KEY_LENGTH * 2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // Convert the string key to the binary array + if(ConvertStringToBinary(szKey, CASC_KEY_LENGTH * 2, Key) != ERROR_SUCCESS) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + return CascAddEncryptionKey(hStorage, KeyName, Key); } LPBYTE WINAPI CascFindEncryptionKey(HANDLE hStorage, ULONGLONG KeyName) { - TCascStorage* hs; + TCascStorage * hs; // Validate the storage handle hs = TCascStorage::IsValid(hStorage); @@ -581,3 +593,26 @@ LPBYTE WINAPI CascFindEncryptionKey(HANDLE hStorage, ULONGLONG KeyName) return CascFindKey(hs, KeyName); } + +bool WINAPI CascGetNotFoundEncryptionKey(HANDLE hStorage, ULONGLONG * KeyName) +{ + TCascStorage * hs; + + // Validate the storage handle + if ((hs = TCascStorage::IsValid(hStorage)) == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // If there was no decryption key error, just return false with ERROR_SUCCESS + if(hs->LastFailKeyName == 0) + { + SetLastError(ERROR_SUCCESS); + return false; + } + + // Give the name of the key that failed most recently + KeyName[0] = hs->LastFailKeyName; + return true; +} diff --git a/dep/CascLib/src/CascFiles.cpp b/dep/CascLib/src/CascFiles.cpp index 8d90df23000..f47b8316693 100644 --- a/dep/CascLib/src/CascFiles.cpp +++ b/dep/CascLib/src/CascFiles.cpp @@ -503,7 +503,20 @@ static void SetProductCodeName(TCascStorage * hs, LPCSTR szCodeName) } } -static int GetDefaultLocaleMask(TCascStorage * hs, const CASC_CSV_COLUMN & Column) +static DWORD GetDefaultCdnPath(TCascStorage * hs, const CASC_CSV_COLUMN & Column) +{ + TCHAR szCdnPath[MAX_PATH]; + + if(hs->szCdnPath == NULL && Column.nLength != 0) + { + CascStrCopy(szCdnPath, _countof(szCdnPath), Column.szValue); + hs->szCdnPath = CascNewStr(szCdnPath); + } + + return ERROR_SUCCESS; +} + +static DWORD GetDefaultLocaleMask(TCascStorage * hs, const CASC_CSV_COLUMN & Column) { LPCSTR szTagEnd = Column.szValue + Column.nLength - 4; LPCSTR szTagPtr = Column.szValue; @@ -662,6 +675,9 @@ static DWORD ParseFile_BuildInfo(TCascStorage * hs, CASC_CSV & Csv) if (dwErrCode != ERROR_SUCCESS) return dwErrCode; + // Get the CDN path + GetDefaultCdnPath(hs, Csv[nSelected]["CDN Path!STRING:0"]); + // If we found tags, we can extract language build from it GetDefaultLocaleMask(hs, Csv[nSelected]["Tags!STRING:0"]); @@ -1228,7 +1244,9 @@ DWORD GetFileSpanInfo(PCASC_CKEY_ENTRY pCKeyEntry, PULONGLONG PtrContentSize, PU // Sanity check assert(pCKeyEntry->SpanCount != 0); - // Sum all span size + // Sum the file size over all file spans + // Note: The first file span, if referenced by the ROOT folder, gets the same size + // like the entire file (example: zone\base.xpak, zone\base.xpak_1) for(DWORD i = 0; i < dwSpanCount; i++, pCKeyEntry++) { if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE) @@ -1433,7 +1451,7 @@ LPBYTE LoadInternalFileToMemory(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, cbFileData = pCKeyEntry->ContentSize; } - // Retrieve the size of the ENCODING file + // Load the entire file to memory if(dwErrCode == ERROR_SUCCESS) { // Allocate space for the ENCODING file diff --git a/dep/CascLib/src/CascIndexFiles.cpp b/dep/CascLib/src/CascIndexFiles.cpp index 9cab9c6a901..eddbdb67b0d 100644 --- a/dep/CascLib/src/CascIndexFiles.cpp +++ b/dep/CascLib/src/CascIndexFiles.cpp @@ -15,13 +15,15 @@ //----------------------------------------------------------------------------- // Local variables -static const TCHAR * szAllowedHexChars = _T("0123456789aAbBcCdDeEfF"); -static const TCHAR * szIndexFormat_V1 = _T("data.i%x%x"); -static const TCHAR * szIndexFormat_V2 = _T("%02x%08x.idx"); +static LPCTSTR szAllowedHexChars = _T("0123456789aAbBcCdDeEfF"); +static LPCTSTR szIndexFormat_V1 = _T("data.i%x%x"); +static LPCTSTR szIndexFormat_V2 = _T("%02x%08x.idx"); // Limit for "orphaned" items - those that are in index files, but are not in ENCODING manifest #define CASC_MAX_ORPHANED_ITEMS 0x100 +typedef bool (*EKEY_ENTRY_CALLBACK)(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, LPBYTE pbEKeyEntry); + //----------------------------------------------------------------------------- // Local functions @@ -43,12 +45,11 @@ static bool IsIndexFileName_V2(const TCHAR * szFileName) } static bool IndexDirectory_OnFileFound( - const TCHAR * szFileName, - PDWORD IndexArray, - PDWORD OldIndexArray, + LPCTSTR szFileName, void * pvContext) { TCascStorage * hs = (TCascStorage *)pvContext; + PCASC_INDEX pIndexFile; DWORD IndexValue = 0; DWORD IndexVersion = 0; @@ -97,17 +98,17 @@ static bool IndexDirectory_OnFileFound( // The index value must not be greater than 0x0F if(IndexValue >= CASC_INDEX_COUNT) return false; + pIndexFile = &hs->IndexFiles[IndexValue]; - // If the new subindex is greater than the previous one, - // use this one instead - if(IndexVersion > IndexArray[IndexValue]) + // If the new subindex is greater than the previous one, use this one instead + if(IndexVersion > pIndexFile->NewSubIndex) { - OldIndexArray[IndexValue] = IndexArray[IndexValue]; - IndexArray[IndexValue] = IndexVersion; + pIndexFile->OldSubIndex = pIndexFile->NewSubIndex; + pIndexFile->NewSubIndex = IndexVersion; } - else if(IndexVersion > OldIndexArray[IndexValue]) + else if(IndexVersion > pIndexFile->OldSubIndex) { - OldIndexArray[IndexValue] = IndexVersion; + pIndexFile->OldSubIndex = IndexVersion; } // Note: WoW6 only keeps last two index files @@ -216,7 +217,7 @@ static LPBYTE CaptureGuardedBlock3(LPBYTE pbFileData, LPBYTE pbFileEnd, size_t E // Give the output return (LPBYTE)(PtrEntryHash + 1); } - +/* static bool CaptureIndexEntry(CASC_INDEX_HEADER & InHeader, PCASC_EKEY_ENTRY pEKeyEntry, LPBYTE pbEKeyEntry) { // Copy the EKey of the variable length @@ -278,24 +279,17 @@ static void InsertCKeyEntry(TCascStorage * hs, CASC_EKEY_ENTRY & EKeyEntry, DWOR // Add the extra flag pCKeyEntry->Flags |= Flags; } - -static DWORD LoadIndexItems(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, LPBYTE pbEKeyEntry, LPBYTE pbEKeyEnd) +*/ +static DWORD LoadIndexItems(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, EKEY_ENTRY_CALLBACK PfnEKeyEntry, LPBYTE pbEKeyEntry, LPBYTE pbEKeyEnd) { size_t EntryLength = InHeader.EntryLength; while((pbEKeyEntry + EntryLength) <= pbEKeyEnd) { - CASC_EKEY_ENTRY EKeyEntry; - - // Capture the index entry and verify it. - if(CaptureIndexEntry(InHeader, &EKeyEntry, pbEKeyEntry)) - { - // DOWNLOAD in HOTS - //BREAK_ON_XKEY3(EKeyEntry.EKey, 0x09, 0xF3, 0xCD); - - // Insert the index entry to the central table - InsertCKeyEntry(hs, EKeyEntry, CASC_CE_FILE_IS_LOCAL); - } + // DOWNLOAD in HOTS + //BREAK_ON_XKEY3(EKeyEntry.EKey, 0x09, 0xF3, 0xCD); + if(!PfnEKeyEntry(hs, InHeader, pbEKeyEntry)) + return ERROR_INDEX_PARSING_DONE; pbEKeyEntry += EntryLength; } @@ -303,7 +297,7 @@ static DWORD LoadIndexItems(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, LPB return ERROR_SUCCESS; } -static DWORD CaptureIndexHeader_V1(CASC_INDEX_HEADER & InHeader, LPBYTE pbFileData, DWORD cbFileData, DWORD BucketIndex) +static DWORD CaptureIndexHeader_V1(CASC_INDEX_HEADER & InHeader, LPBYTE pbFileData, size_t cbFileData, DWORD BucketIndex) { PFILE_INDEX_HEADER_V1 pIndexHeader = (PFILE_INDEX_HEADER_V1)pbFileData; LPBYTE pbKeyEntries; @@ -363,7 +357,7 @@ static DWORD CaptureIndexHeader_V1(CASC_INDEX_HEADER & InHeader, LPBYTE pbFileDa return ERROR_SUCCESS; } -static DWORD CaptureIndexHeader_V2(CASC_INDEX_HEADER & InHeader, LPBYTE pbFileData, DWORD cbFileData, DWORD BucketIndex) +static DWORD CaptureIndexHeader_V2(CASC_INDEX_HEADER & InHeader, LPBYTE pbFileData, size_t cbFileData, DWORD BucketIndex) { PFILE_INDEX_HEADER_V2 pIndexHeader; LPBYTE pbFileEnd = pbFileData + cbFileData; @@ -397,7 +391,7 @@ static DWORD CaptureIndexHeader_V2(CASC_INDEX_HEADER & InHeader, LPBYTE pbFileDa return ERROR_SUCCESS; } -static DWORD LoadIndexFile_V1(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, LPBYTE pbFileData, DWORD cbFileData) +static DWORD LoadIndexFile_V1(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, EKEY_ENTRY_CALLBACK PfnEKeyEntry, LPBYTE pbFileData, size_t cbFileData) { LPBYTE pbEKeyEntries = pbFileData + InHeader.HeaderLength + InHeader.HeaderPadding; @@ -405,10 +399,10 @@ static DWORD LoadIndexFile_V1(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, L SaveFileOffsetBitsAndEKeyLength(hs, InHeader.FileOffsetBits, InHeader.EKeyLength); // Load the entries from a continuous array - return LoadIndexItems(hs, InHeader, pbEKeyEntries, pbFileData + cbFileData); + return LoadIndexItems(hs, InHeader, PfnEKeyEntry, pbEKeyEntries, pbFileData + cbFileData); } -static DWORD LoadIndexFile_V2(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, LPBYTE pbFileData, DWORD cbFileData) +static DWORD LoadIndexFile_V2(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, EKEY_ENTRY_CALLBACK PfnEKeyEntry, LPBYTE pbFileData, size_t cbFileData) { LPBYTE pbEKeyEntry; LPBYTE pbFileEnd = pbFileData + cbFileData; @@ -427,7 +421,7 @@ static DWORD LoadIndexFile_V2(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, L InHeader.HeaderPadding += sizeof(FILE_INDEX_GUARDED_BLOCK); // Load the continuous array of EKeys - return LoadIndexItems(hs, InHeader, pbEKeyEntry, pbEKeyEntry + BlockSize); + return LoadIndexItems(hs, InHeader, PfnEKeyEntry, pbEKeyEntry, pbEKeyEntry + BlockSize); } // Get the pointer to the second block of EKey entries. @@ -446,8 +440,6 @@ static DWORD LoadIndexFile_V2(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, L while(pbEKeyEntry < pbEndPage) { - CASC_EKEY_ENTRY EKeyEntry; - // Check the EKey entry protected by 32-bit hash if((pbEKeyEntry = CaptureGuardedBlock3(pbEKeyEntry, pbEndPage, InHeader.EntryLength)) == NULL) break; @@ -455,13 +447,10 @@ static DWORD LoadIndexFile_V2(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, L // CASC\\0001: Encoding //BREAK_ON_XKEY3(pbEKeyEntry, 0xbc, 0xe8, 0x23); - // Capture the index entry and verify it. - if(CaptureIndexEntry(InHeader, &EKeyEntry, pbEKeyEntry)) - { - InsertCKeyEntry(hs, EKeyEntry, CASC_CE_FILE_IS_LOCAL); - } + // Call the EKey entry callback + if(!PfnEKeyEntry(hs, InHeader, pbEKeyEntry)) + return ERROR_INDEX_PARSING_DONE; - // Move to the next entry pbEKeyEntry += AlignedLength; } @@ -474,80 +463,95 @@ static DWORD LoadIndexFile_V2(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, L return dwErrCode; } -static DWORD LoadIndexFile(TCascStorage * hs, LPBYTE pbFileData, DWORD cbFileData, DWORD BucketIndex) +static DWORD LoadIndexFile(TCascStorage * hs, EKEY_ENTRY_CALLBACK PfnEKeyEntry, LPBYTE pbFileData, size_t cbFileData, DWORD BucketIndex) { CASC_INDEX_HEADER InHeader; // Check for CASC version 2 if(CaptureIndexHeader_V2(InHeader, pbFileData, cbFileData, BucketIndex) == ERROR_SUCCESS) - return LoadIndexFile_V2(hs, InHeader, pbFileData, cbFileData); + return LoadIndexFile_V2(hs, InHeader, PfnEKeyEntry, pbFileData, cbFileData); // Check for CASC index version 1 if(CaptureIndexHeader_V1(InHeader, pbFileData, cbFileData, BucketIndex) == ERROR_SUCCESS) - return LoadIndexFile_V1(hs, InHeader, pbFileData, cbFileData); + return LoadIndexFile_V1(hs, InHeader, PfnEKeyEntry, pbFileData, cbFileData); // Should never happen assert(false); return ERROR_BAD_FORMAT; } -static DWORD LoadIndexFile(TCascStorage * hs, const TCHAR * szFileName, DWORD BucketIndex) +// Checks the EKey entry for EKey of the ENCODING manifest +static bool InsertEncodingEKeyToMap(TCascStorage * hs, CASC_INDEX_HEADER &, LPBYTE pbEKeyEntry) +{ + hs->IndexEKeyMap.InsertObject(pbEKeyEntry, pbEKeyEntry); + return true; +} + +static DWORD ProcessLocalIndexFiles(TCascStorage * hs, EKEY_ENTRY_CALLBACK PfnEKeyEntry) { - LPBYTE pbFileData; - DWORD cbFileData; DWORD dwErrCode = ERROR_SUCCESS; - // WoW6 actually reads THE ENTIRE file to memory. Verified on Mac build (x64). - pbFileData = LoadFileToMemory(szFileName, &cbFileData); - if(pbFileData && cbFileData) - { - // Parse and load the index file - dwErrCode = LoadIndexFile(hs, pbFileData, cbFileData, BucketIndex); - CASC_FREE(pbFileData); - } - else + // Load each index file + for(DWORD i = 0; i < CASC_INDEX_COUNT; i++) { - dwErrCode = GetLastError(); + CASC_INDEX & IndexFile = hs->IndexFiles[i]; + + // Inform the user about what we are doing + if(InvokeProgressCallback(hs, "Loading index files", NULL, i, CASC_INDEX_COUNT)) + { + dwErrCode = ERROR_CANCELLED; + break; + } + + // Load the index file + if((dwErrCode = LoadIndexFile(hs, PfnEKeyEntry, IndexFile.pbFileData, IndexFile.cbFileData, i)) != ERROR_SUCCESS) + break; } + // Swallow the "done parsing" error + if(dwErrCode == ERROR_INDEX_PARSING_DONE) + dwErrCode = ERROR_SUCCESS; + + // Remember the number of files that are present locally + hs->LocalFiles = hs->CKeyArray.ItemCount(); return dwErrCode; } static DWORD LoadLocalIndexFiles(TCascStorage * hs) { - TCHAR * szFileName; - DWORD OldIndexArray[CASC_INDEX_COUNT]; - DWORD IndexArray[CASC_INDEX_COUNT]; + ULONGLONG TotalSize = 0; DWORD dwErrCode; - // Scan all index files and load contained EKEY entries - memset(OldIndexArray, 0, sizeof(OldIndexArray)); - memset(IndexArray, 0, sizeof(IndexArray)); - dwErrCode = ScanIndexDirectory(hs->szIndexPath, IndexDirectory_OnFileFound, IndexArray, OldIndexArray, hs); - if(dwErrCode == ERROR_SUCCESS) + // Inform the user about what we are doing + if(InvokeProgressCallback(hs, "Loading index files", NULL, 0, 0)) + return ERROR_CANCELLED; + + // Perform the directory scan + if((dwErrCode = ScanIndexDirectory(hs->szIndexPath, IndexDirectory_OnFileFound, hs)) == ERROR_SUCCESS) { // Load each index file for(DWORD i = 0; i < CASC_INDEX_COUNT; i++) { - // Create the name of the index file - if((szFileName = CreateIndexFileName(hs, i, IndexArray[i])) != NULL) - { - // Inform the user about what we are doing - if(InvokeProgressCallback(hs, "Loading index files", NULL, i, CASC_INDEX_COUNT)) - { - dwErrCode = ERROR_CANCELLED; - break; - } + CASC_INDEX & IndexFile = hs->IndexFiles[i]; + DWORD cbFileData = 0; - // Load the index file - if((dwErrCode = LoadIndexFile(hs, szFileName, i)) != ERROR_SUCCESS) - break; - CASC_FREE(szFileName); - } + // Create the file name + if((IndexFile.szFileName = CreateIndexFileName(hs, i, IndexFile.NewSubIndex)) == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // WoW6 actually reads THE ENTIRE file to memory. Verified on Mac build (x64). + if((IndexFile.pbFileData = LoadFileToMemory(IndexFile.szFileName, &cbFileData)) == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + IndexFile.cbFileData = cbFileData; + TotalSize += cbFileData; } - // Remember the number of files that are present locally - hs->LocalFiles = hs->CKeyArray.ItemCount(); + // Build the map of EKey -> IndexEKeyEntry + dwErrCode = hs->IndexEKeyMap.Create((size_t)(TotalSize / sizeof(FILE_EKEY_ENTRY)), CASC_EKEY_SIZE, 0); + if(dwErrCode == ERROR_SUCCESS) + { + dwErrCode = ProcessLocalIndexFiles(hs, InsertEncodingEKeyToMap); + } } return dwErrCode; @@ -785,9 +789,31 @@ static DWORD LoadArchiveIndexFiles(TCascStorage * hs) //----------------------------------------------------------------------------- // Public functions +bool CopyEKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry) +{ + LPBYTE pbEKeyEntry = (LPBYTE)hs->IndexEKeyMap.FindObject(pCKeyEntry->EKey); + + // Don't do this on online storages + if(!(hs->dwFeatures & CASC_FEATURE_ONLINE)) + { + // If the file was found, then copy the content to the CKey entry + pbEKeyEntry = (LPBYTE)hs->IndexEKeyMap.FindObject(pCKeyEntry->EKey); + if(pbEKeyEntry == NULL) + return false; + + pCKeyEntry->StorageOffset = ConvertBytesToInteger_5(pbEKeyEntry + hs->EKeyLength); + pCKeyEntry->EncodedSize = ConvertBytesToInteger_4_LE(pbEKeyEntry + hs->EKeyLength + 5); + pCKeyEntry->Flags |= CASC_CE_FILE_IS_LOCAL; + } + + return true; +} + DWORD LoadIndexFiles(TCascStorage * hs) { - if (hs->dwFeatures & CASC_FEATURE_ONLINE) + // For local storages, load the index files from the disk + // For online storages, load the index files from the cache / internet + if(hs->dwFeatures & CASC_FEATURE_ONLINE) { return LoadArchiveIndexFiles(hs); } @@ -795,4 +821,23 @@ DWORD LoadIndexFiles(TCascStorage * hs) { return LoadLocalIndexFiles(hs); } -} \ No newline at end of file +} + +void FreeIndexFiles(TCascStorage * hs) +{ + // Free the map of EKey -> Index Ekey item + hs->IndexEKeyMap.Free(); + + // Free all loaded index files + for(size_t i = 0; i < CASC_INDEX_COUNT; i++) + { + CASC_INDEX & IndexFile = hs->IndexFiles[i]; + + // Free the file data + CASC_FREE(IndexFile.pbFileData); + IndexFile.cbFileData = 0; + + // Free the file name + CASC_FREE(IndexFile.szFileName); + } +} diff --git a/dep/CascLib/src/CascLib.def b/dep/CascLib/src/CascLib.def index 0359dfa3a2e..9442184946f 100644 --- a/dep/CascLib/src/CascLib.def +++ b/dep/CascLib/src/CascLib.def @@ -12,9 +12,6 @@ EXPORTS CascOpenStorageEx CascOpenOnlineStorage CascGetStorageInfo - CascAddEncryptionKey - CascAddStringEncryptionKey - CascFindEncryptionKey CascCloseStorage CascOpenFile @@ -31,5 +28,10 @@ EXPORTS CascFindNextFile CascFindClose + CascAddEncryptionKey + CascAddStringEncryptionKey + CascFindEncryptionKey + CascGetNotFoundEncryptionKey + GetLastError=Kernel32.GetLastError SetLastError=Kernel32.SetLastError diff --git a/dep/CascLib/src/CascLib.h b/dep/CascLib/src/CascLib.h index 90be65a00b2..8bf515abca9 100644 --- a/dep/CascLib/src/CascLib.h +++ b/dep/CascLib/src/CascLib.h @@ -86,6 +86,7 @@ extern "C" { #define CASC_OVERCOME_ENCRYPTED 0x00000020 // When CascReadFile encounters a block encrypted with a key that is missing, the block is filled with zeros and returned as success #define CASC_LOCALE_ALL 0xFFFFFFFF +#define CASC_LOCALE_ALL_WOW 0x0001F3F6 // All except enCN and enTW #define CASC_LOCALE_NONE 0x00000000 #define CASC_LOCALE_UNKNOWN1 0x00000001 #define CASC_LOCALE_ENUS 0x00000002 @@ -142,6 +143,9 @@ extern "C" { #define CASC_FILE_DATA_ID(FileDataId) ((LPCSTR)(size_t)FileDataId) #define CASC_FILE_DATA_ID_FROM_STRING(szFileName) ((DWORD)(size_t)szFileName) +// Maximum length of encryption key +#define CASC_KEY_LENGTH 0x10 + //----------------------------------------------------------------------------- // Structures @@ -342,9 +346,6 @@ bool WINAPI CascOpenStorageEx(LPCTSTR szParams, PCASC_OPEN_STORAGE_ARGS pArgs, bool WINAPI CascOpenStorage(LPCTSTR szParams, DWORD dwLocaleMask, HANDLE * phStorage); bool WINAPI CascOpenOnlineStorage(LPCTSTR szParams, DWORD dwLocaleMask, HANDLE * phStorage); bool WINAPI CascGetStorageInfo(HANDLE hStorage, CASC_STORAGE_INFO_CLASS InfoClass, void * pvStorageInfo, size_t cbStorageInfo, size_t * pcbLengthNeeded); -bool WINAPI CascAddEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPBYTE Key); -bool WINAPI CascAddStringEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPCSTR szKey); -LPBYTE WINAPI CascFindEncryptionKey(HANDLE hStorage, ULONGLONG KeyName); bool WINAPI CascCloseStorage(HANDLE hStorage); bool WINAPI CascOpenFile(HANDLE hStorage, const void * pvFileName, DWORD dwLocaleFlags, DWORD dwOpenFlags, HANDLE * PtrFileHandle); @@ -362,6 +363,11 @@ HANDLE WINAPI CascFindFirstFile(HANDLE hStorage, LPCSTR szMask, PCASC_FIND_DATA bool WINAPI CascFindNextFile(HANDLE hFind, PCASC_FIND_DATA pFindData); bool WINAPI CascFindClose(HANDLE hFind); +bool WINAPI CascAddEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPBYTE Key); +bool WINAPI CascAddStringEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPCSTR szKey); +LPBYTE WINAPI CascFindEncryptionKey(HANDLE hStorage, ULONGLONG KeyName); +bool WINAPI CascGetNotFoundEncryptionKey(HANDLE hStorage, ULONGLONG * KeyName); + //----------------------------------------------------------------------------- // GetLastError/SetLastError support for non-Windows platform diff --git a/dep/CascLib/src/CascOpenStorage.cpp b/dep/CascLib/src/CascOpenStorage.cpp index abc17e1e9ce..aab10d2c88a 100644 --- a/dep/CascLib/src/CascOpenStorage.cpp +++ b/dep/CascLib/src/CascOpenStorage.cpp @@ -20,6 +20,27 @@ // Limit for "additional" items in CKey table #define CASC_MAX_EXTRA_ITEMS 0x40 +//----------------------------------------------------------------------------- +// DEBUG functions + +//#define CHECKED_KEY "2a378c" + +#if defined(_DEBUG) && defined(CHECKED_KEY) + +inline bool CheckForXKey(LPBYTE XKey) +{ + BYTE CheckedKey[4]; + ConvertStringToBinary(CHECKED_KEY, 6, CheckedKey); + return (XKey[0] == CheckedKey[0] && XKey[1] == CheckedKey[1] && XKey[2] == CheckedKey[2]); +} +#define BREAK_ON_WATCHED(XKey) if(CheckForXKey((LPBYTE)XKey)) { __debugbreak(); } + +#else + +#define BREAK_ON_WATCHED(XKey) { /* NOTHING */ } + +#endif + //----------------------------------------------------------------------------- // TCascStorage class functions @@ -35,6 +56,7 @@ TCascStorage::TCascStorage() szRegion = NULL; memset(DataFiles, 0, sizeof(DataFiles)); + memset(IndexFiles, 0, sizeof(IndexFiles)); dwBuildNumber = 0; dwFeatures = 0; BuildFileType = CascBuildNone; @@ -56,6 +78,9 @@ TCascStorage::~TCascStorage() DataFiles[i] = NULL; } + // Cleanup space occupied by index files + FreeIndexFiles(this); + // Free the file paths CASC_FREE(szDataPath); CASC_FREE(szRootPath); @@ -113,9 +138,9 @@ void * ProbeOutputBuffer(void * pvBuffer, size_t cbLength, size_t cbMinLength, s return pvBuffer; } -static TCHAR * CheckForIndexDirectory(TCascStorage * hs, const TCHAR * szSubDir) +static LPTSTR CheckForIndexDirectory(TCascStorage * hs, LPCTSTR szSubDir) { - TCHAR * szIndexPath; + LPTSTR szIndexPath; // Combine the index path szIndexPath = CombinePath(hs->szDataPath, szSubDir); @@ -132,6 +157,9 @@ static PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, CASC_CKEY_ENTRY & CKe { PCASC_CKEY_ENTRY pCKeyEntry = NULL; + // Stop on file-of-interest + BREAK_ON_WATCHED(CKeyEntry.EKey); + // Skip entries without any key if(CKeyEntry.Flags & (CASC_CE_HAS_CKEY | CASC_CE_HAS_EKEY)) { @@ -171,14 +199,14 @@ static PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, PFILE_CKEY_ENTRY pFil { PCASC_CKEY_ENTRY pCKeyEntry; - // Check whether the entry is already there - if((pCKeyEntry = FindCKeyEntry_EKey(hs, pFileEntry->EKey)) == NULL) - { - // Insert a new entry to the array. DO NOT ALLOW enlarge array here - pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false); - if(pCKeyEntry == NULL) - return NULL; + // Stop on file-of-interest + BREAK_ON_WATCHED(pFileEntry->EKey); + // Insert a new entry to the array. DO NOT ALLOW enlarge array here + pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false); + if(pCKeyEntry != NULL) + { + // Initialize the entry CopyMemory16(pCKeyEntry->CKey, pFileEntry->CKey); CopyMemory16(pCKeyEntry->EKey, pFileEntry->EKey); pCKeyEntry->StorageOffset = CASC_INVALID_OFFS64; @@ -190,24 +218,16 @@ static PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, PFILE_CKEY_ENTRY pFil pCKeyEntry->SpanCount = 1; pCKeyEntry->Priority = 0; + // Copy the information from index files to the CKey entry + CopyEKeyEntry(hs, pCKeyEntry); + // Insert the item into both maps hs->CKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->CKey); hs->EKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->EKey); } else { - // Supply both CKey and EKey. Rewrite EKey regardless, because ENCODING manifest contains a full one - CopyMemory16(pCKeyEntry->CKey, pFileEntry->CKey); - CopyMemory16(pCKeyEntry->EKey, pFileEntry->EKey); - - // Supply the content size - if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE) - pCKeyEntry->ContentSize = ConvertBytesToInteger_4(pFileEntry->ContentSize); - pCKeyEntry->Flags |= CASC_CE_HAS_CKEY | CASC_CE_HAS_EKEY | CASC_CE_IN_ENCODING; - pCKeyEntry->Flags &= ~CASC_CE_HAS_EKEY_PARTIAL; - - // Insert the item into CKey map - hs->CKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->CKey); + assert(false); } return pCKeyEntry; @@ -218,13 +238,19 @@ static PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, CASC_DOWNLOAD_ENTRY & { PCASC_CKEY_ENTRY pCKeyEntry; + // Stop on file-of-interest + BREAK_ON_WATCHED(DlEntry.EKey); + // Check whether the entry is already there if((pCKeyEntry = FindCKeyEntry_EKey(hs, DlEntry.EKey)) == NULL) { // Insert dummy CKey entry to the array. DO NOT allow to enlarge the array pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false); if(pCKeyEntry == NULL) + { + assert(false); return NULL; + } // Copy the entry ZeroMemory16(pCKeyEntry->CKey); @@ -237,6 +263,9 @@ static PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, CASC_DOWNLOAD_ENTRY & pCKeyEntry->RefCount = 0; pCKeyEntry->SpanCount = 1; + // Copy the information from index files to the CKey entry + CopyEKeyEntry(hs, pCKeyEntry); + // Insert the entry to the map. Only insert it to the EKey map, as there is no CKey present hs->EKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->EKey); } @@ -278,25 +307,34 @@ static DWORD CopyBuildFileItemsToCKeyArray(TCascStorage * hs) return ERROR_SUCCESS; } -// Estimate the total number of files, so we won't have to re-allocate the array +// Estimate the total number of files, so we won't have to re-allocate arrays and maps +// and thus speed-up storage loading. In theory, we could guess the file count by +// measuring size of ENCODING or DOWNLOAD manifests. static size_t GetEstimatedNumberOfFiles(TCascStorage * hs) { + size_t nNumberOfFiles1 = 0; + size_t nNumberOfFiles2 = 0; + // If we know the size of DOWNLOAD at this point, we estimate number of files from it. - // Size of one entry in DOWNLOAD is at least 26 bytes. This is the most reliable method. + // Size of one entry in DOWNLOAD is at least 22 bytes. This is the most reliable method. // However, for some online storages ("agent"), this is a very small value if(hs->DownloadCKey.ContentSize != CASC_INVALID_SIZE) - return (hs->DownloadCKey.ContentSize / 26) + CASC_MAX_EXTRA_ITEMS; + nNumberOfFiles1 = (hs->DownloadCKey.ContentSize / sizeof(FILE_DOWNLOAD_ENTRY)) + CASC_MAX_EXTRA_ITEMS; // If we know the size of ENCODING at this point, we estimate number of files from it. // Size of one entry in ENCODING is at least 38 bytes. This method fails on storages // with TVFS file system, as ENCODING only contains a small subset of file. // Fortunately, all known TVFS-based storages have "download-size" present if(hs->EncodingCKey.ContentSize != CASC_INVALID_SIZE) - return (hs->EncodingCKey.ContentSize / 26) + CASC_MAX_EXTRA_ITEMS; + nNumberOfFiles2 = (hs->EncodingCKey.ContentSize / sizeof(FILE_CKEY_ENTRY)) + CASC_MAX_EXTRA_ITEMS; + + // Do we know any of them? + if(nNumberOfFiles1 || nNumberOfFiles2) + return CASCLIB_MAX(nNumberOfFiles1, nNumberOfFiles2); - // By default, it's gonna be half a million, which is the maximum observed number of files - // for all older storages (HOTS before 39445, WoW before 19116) - return 500000; + // Older storages (HOTS before 39445, WoW before 19116) don't state sizes of ENCODING + // and DOWNLOAD in the Build Config files. Solution: Assume there is max 1M of files + return 1000000; } static DWORD InitCKeyArray(TCascStorage * hs) @@ -373,7 +411,7 @@ static int LoadEncodingCKeyPage(TCascStorage * hs, CASC_ENCODING_HEADER & EnHead // Example of a file entry with multiple EKeys: // Overwatch build 24919, CKey: 0e 90 94 fa d2 cb 85 ac d0 7c ea 09 f9 c5 ba 00 // BREAKIF(pFileEntry->EKeyCount > 1); -// BREAK_ON_XKEY3(pFileEntry->EKey, 0x09, 0xF3, 0xCD); +// BREAK_ON_XKEY3(pFileEntry->CKey, 0x34, 0x82, 0x1f); // Insert the entry to the central CKey table InsertCKeyEntry(hs, pFileEntry); @@ -386,7 +424,7 @@ static int LoadEncodingCKeyPage(TCascStorage * hs, CASC_ENCODING_HEADER & EnHead static int LoadEncodingManifest(TCascStorage * hs) { - PCASC_CKEY_ENTRY pCKeyEntry = FindCKeyEntry_CKey(hs, hs->EncodingCKey.CKey); + CASC_CKEY_ENTRY & CKeyEntry = hs->EncodingCKey; LPBYTE pbEncodingFile; DWORD cbEncodingFile = 0; DWORD dwErrCode = ERROR_SUCCESS; @@ -395,8 +433,12 @@ static int LoadEncodingManifest(TCascStorage * hs) if(InvokeProgressCallback(hs, "Loading ENCODING manifest", NULL, 0, 0)) return ERROR_CANCELLED; + // Fill-in the information from the index entry + if(!CopyEKeyEntry(hs, &CKeyEntry)) + return ERROR_FILE_NOT_FOUND; + // Load the entire encoding file to memory - pbEncodingFile = LoadInternalFileToMemory(hs, pCKeyEntry, &cbEncodingFile); + pbEncodingFile = LoadInternalFileToMemory(hs, &hs->EncodingCKey, &cbEncodingFile); if(pbEncodingFile != NULL && cbEncodingFile != 0) { CASC_ENCODING_HEADER EnHeader; @@ -451,12 +493,6 @@ static int LoadEncodingManifest(TCascStorage * hs) dwErrCode = CopyBuildFileItemsToCKeyArray(hs); } - // Now supply all the entries from the index files - //if(dwErrCode == ERROR_SUCCESS) - //{ - // dwErrCode = CopyIndexItemsToCKeyArray(hs); - //} - // Free the loaded ENCODING file CASC_FREE(pbEncodingFile); } @@ -807,6 +843,10 @@ static int LoadBuildManifest(TCascStorage * hs, DWORD dwLocaleMask) assert(hs->CKeyMap.IsInitialized() == true); assert(hs->pRootHandler == NULL); + // Inform the user about what we are doing + if(InvokeProgressCallback(hs, "Loading ROOT manifest", NULL, 0, 0)) + return ERROR_CANCELLED; + // Locale: The default parameter is 0 - in that case, we load all locales dwLocaleMask = (dwLocaleMask != 0) ? dwLocaleMask : 0xFFFFFFFF; @@ -814,10 +854,6 @@ static int LoadBuildManifest(TCascStorage * hs, DWORD dwLocaleMask) pCKeyEntry = (hs->VfsRoot.ContentSize != CASC_INVALID_SIZE) ? &hs->VfsRoot : &hs->RootFile; pCKeyEntry = FindCKeyEntry_CKey(hs, pCKeyEntry->CKey); - // Inform the user about what we are doing - if(InvokeProgressCallback(hs, "Loading ROOT manifest", NULL, 0, 0)) - return ERROR_CANCELLED; - // Load the entire ROOT file to memory pbRootFile = LoadInternalFileToMemory(hs, pCKeyEntry, &cbRootFile); if(pbRootFile != NULL) @@ -1020,7 +1056,7 @@ static bool GetStoragePathProduct(TCascStorage * hs, void * pvStorageInfo, size_ static DWORD InitializeLocalDirectories(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs) { - TCHAR * szWorkPath; + LPTSTR szWorkPath; DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY; // Find the root directory of the storage. The root directory @@ -1135,13 +1171,13 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs) dwErrCode = LoadCdnBuildFile(hs); } - // Create the central file array + // Create the array of CKey entries. Each entry represents a file in the storage if(dwErrCode == ERROR_SUCCESS) { dwErrCode = InitCKeyArray(hs); } - // Load the index files. Store information from the index files to the CKeyArray. + // Pre-load the local index files if(dwErrCode == ERROR_SUCCESS) { dwErrCode = LoadIndexFiles(hs); @@ -1153,8 +1189,7 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs) dwErrCode = LoadEncodingManifest(hs); } - // We need to load the DOWNLOAD manifest. This will give us the information about - // how many physical files are in the storage, so we can start building file tables + // We need to load the DOWNLOAD manifest if(dwErrCode == ERROR_SUCCESS) { dwErrCode = LoadDownloadManifest(hs); @@ -1163,10 +1198,20 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs) // Load the build manifest ("ROOT" file) if(dwErrCode == ERROR_SUCCESS) { - // If we fail to load the ROOT file, we take the file names from the INSTALL manifest + // For WoW storages, multiple files are present in the storage (same name, same file data ID, different locale). + // Failing to select storage on them will lead to the first-in-order file in the list being loaded. + // Example: WoW build 32144, file: DBFilesClient\Achievement.db2, file data ID: 1260179 + // Locales: koKR frFR deDE zhCN esES zhTW enUS&enGB esMX ruRU itIT ptBT&ptPT (in order of appearance in the build manifest) + if(dwLocaleMask == 0) + { + dwLocaleMask = hs->dwDefaultLocale; + } + + // Continue loading the manifest dwErrCode = LoadBuildManifest(hs, dwLocaleMask); if (dwErrCode != ERROR_SUCCESS) { + // If we fail to load the ROOT file, we take the file names from the INSTALL manifest dwErrCode = LoadInstallManifest(hs); } } @@ -1192,8 +1237,9 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs) dwErrCode = CascLoadEncryptionKeys(hs); } - // Clear the arg structure - hs->pArgs = pArgs; + // Cleanup and exit + FreeIndexFiles(hs); + hs->pArgs = NULL; return dwErrCode; } diff --git a/dep/CascLib/src/CascPort.h b/dep/CascLib/src/CascPort.h index 21cd991a09c..9f401f80b2e 100644 --- a/dep/CascLib/src/CascPort.h +++ b/dep/CascLib/src/CascPort.h @@ -80,15 +80,19 @@ #include #include #include - #include #include - #include #include - #include + #include #include + #include + #include + #include + #include #include #include + #include #include + #include // Support for PowerPC on Max OS X #if (__ppc__ == 1) || (__POWERPC__ == 1) || (_ARCH_PPC == 1) @@ -261,6 +265,10 @@ #define ERROR_CANCELLED 1009 #endif +#ifndef ERROR_INDEX_PARSING_DONE +#define ERROR_INDEX_PARSING_DONE 1010 +#endif + #ifndef _countof #define _countof(x) (sizeof(x) / sizeof(x[0])) #endif @@ -321,7 +329,7 @@ inline DWORD CascInterlockedIncrement(PDWORD PtrValue) inline DWORD CascInterlockedDecrement(PDWORD PtrValue) { #ifdef PLATFORM_WINDOWS - return (DWORD)InterlockedIncrement((LONG *)(PtrValue)); + return (DWORD)InterlockedDecrement((LONG *)(PtrValue)); #else return --PtrValue[0]; #endif diff --git a/dep/CascLib/src/CascRootFile_TVFS.cpp b/dep/CascLib/src/CascRootFile_TVFS.cpp index 25ccf450397..dbd681758ba 100644 --- a/dep/CascLib/src/CascRootFile_TVFS.cpp +++ b/dep/CascLib/src/CascRootFile_TVFS.cpp @@ -397,6 +397,32 @@ struct TRootHandler_TVFS : public TFileTreeRoot return dwErrCode; } + PCASC_CKEY_ENTRY InsertUnknownCKeyEntry(TCascStorage * hs, LPBYTE pbEKey, size_t cbEKey, DWORD ContentSize) + { + PCASC_CKEY_ENTRY pCKeyEntry; + + // Insert a new entry to the array. DO NOT ALLOW enlarge array here + pCKeyEntry = (PCASC_CKEY_ENTRY)hs->CKeyArray.Insert(1, false); + if(pCKeyEntry != NULL) + { + memset(pCKeyEntry, 0, sizeof(CASC_CKEY_ENTRY)); + memcpy(pCKeyEntry->EKey, pbEKey, cbEKey); + pCKeyEntry->StorageOffset = CASC_INVALID_OFFS64; + pCKeyEntry->ContentSize = ContentSize; + pCKeyEntry->EncodedSize = CASC_INVALID_SIZE; + pCKeyEntry->Flags = CASC_CE_HAS_EKEY | CASC_CE_HAS_EKEY_PARTIAL; + pCKeyEntry->SpanCount = 1; + + // Copy the information from index files to the CKey entry + CopyEKeyEntry(hs, pCKeyEntry); + + // Insert the item into EKey map + hs->EKeyMap.InsertObject(pCKeyEntry, pCKeyEntry->EKey); + } + + return pCKeyEntry; + } + void InsertRootVfsEntry(TCascStorage * hs, LPBYTE pbCKey, const char * szFormat, size_t nIndex) { PCASC_CKEY_ENTRY pCKeyEntry; @@ -474,29 +500,37 @@ struct TRootHandler_TVFS : public TFileTreeRoot // Find the CKey entry pCKeyEntry = FindCKeyEntry_EKey(hs, SpanEntry.EKey); - if(pCKeyEntry != NULL) + if(pCKeyEntry == NULL) { - // We need to check whether this is another TVFS directory file - if (IsVfsSubDirectory(hs, DirHeader, SubHeader, SpanEntry.EKey, SpanEntry.ContentSize) == ERROR_SUCCESS) + // Some files are in the ROOT manifest even if they are not in ENCODING and DOWNLOAD. + // Example: "2018 - New CASC\00001", file "DivideAndConquer.w3m:war3mapMap.blp" + pCKeyEntry = InsertUnknownCKeyEntry(hs, SpanEntry.EKey, DirHeader.EKeySize, SpanEntry.ContentSize); + if(pCKeyEntry == NULL) { - // Add colon (':') - PathBuffer.AppendChar(':'); + return ERROR_NOT_ENOUGH_MEMORY; + } + } - // The file content size should already be there - assert(pCKeyEntry->ContentSize == SpanEntry.ContentSize); - FileTree.InsertByName(pCKeyEntry, PathBuffer); + // We need to check whether this is another TVFS directory file + if (IsVfsSubDirectory(hs, DirHeader, SubHeader, SpanEntry.EKey, SpanEntry.ContentSize) == ERROR_SUCCESS) + { + // Add colon (':') + PathBuffer.AppendChar(':'); - // Parse the subdir - ParseDirectoryData(hs, SubHeader, PathBuffer); - CASC_FREE(SubHeader.pbDirectoryData); - } - else - { - // If the content content size is not there, supply it now - if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE) - pCKeyEntry->ContentSize = SpanEntry.ContentSize; - FileTree.InsertByName(pCKeyEntry, PathBuffer); - } + // The file content size should already be there + assert(pCKeyEntry->ContentSize == SpanEntry.ContentSize); + FileTree.InsertByName(pCKeyEntry, PathBuffer); + + // Parse the subdir + ParseDirectoryData(hs, SubHeader, PathBuffer); + CASC_FREE(SubHeader.pbDirectoryData); + } + else + { + // If the content content size is not there, supply it now + if(pCKeyEntry->ContentSize == CASC_INVALID_SIZE) + pCKeyEntry->ContentSize = SpanEntry.ContentSize; + FileTree.InsertByName(pCKeyEntry, PathBuffer); } } else diff --git a/dep/CascLib/src/DllMain.rc b/dep/CascLib/src/DllMain.rc index 7cb068f5ada..a6243d2540b 100644 --- a/dep/CascLib/src/DllMain.rc +++ b/dep/CascLib/src/DllMain.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,50,0,158 - PRODUCTVERSION 1,50,0,158 + FILEVERSION 1,50,0,181 + PRODUCTVERSION 1,50,0,181 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -42,12 +42,12 @@ BEGIN BLOCK "040504b0" BEGIN VALUE "FileDescription", "CascLib library for reading Blizzard CASC storages" - VALUE "FileVersion", "1, 50, 0, 158\0" + VALUE "FileVersion", "1, 50, 0, 181\0" VALUE "InternalName", "CascLib" VALUE "LegalCopyright", "Copyright (c) 2014 - 2019 Ladislav Zezula" VALUE "OriginalFilename", "CascLib.dll" VALUE "ProductName", "CascLib" - VALUE "ProductVersion", "1, 50, 0, 158\0" + VALUE "ProductVersion", "1, 50, 0, 181\0" END END BLOCK "VarFileInfo" diff --git a/dep/CascLib/src/common/Common.h b/dep/CascLib/src/common/Common.h index d32202413ba..ddf8e136c9b 100644 --- a/dep/CascLib/src/common/Common.h +++ b/dep/CascLib/src/common/Common.h @@ -438,17 +438,11 @@ bool CascVerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expec //----------------------------------------------------------------------------- // Scanning a directory -typedef bool (*INDEX_FILE_FOUND)(const TCHAR * szFileName, PDWORD IndexArray, PDWORD OldIndexArray, void * pvContext); +typedef bool (*INDEX_FILE_FOUND)(LPCTSTR szFileName, void * pvContext); -bool DirectoryExists(const TCHAR * szDirectory); +bool DirectoryExists(LPCTSTR szDirectory); -int ScanIndexDirectory( - const TCHAR * szIndexPath, - INDEX_FILE_FOUND pfnOnFileFound, - PDWORD IndexArray, - PDWORD OldIndexArray, - void * pvContext - ); +int ScanIndexDirectory(LPCTSTR szIndexPath, INDEX_FILE_FOUND pfnOnFileFound, void * pvContext); //----------------------------------------------------------------------------- // Argument structure versioning diff --git a/dep/CascLib/src/common/Directory.cpp b/dep/CascLib/src/common/Directory.cpp index 463881f3f9c..387ca3a8ea4 100644 --- a/dep/CascLib/src/common/Directory.cpp +++ b/dep/CascLib/src/common/Directory.cpp @@ -53,10 +53,8 @@ bool MakeDirectory(const TCHAR * szDirectory) } int ScanIndexDirectory( - const TCHAR * szIndexPath, + LPCTSTR szIndexPath, INDEX_FILE_FOUND pfnOnFileFound, - PDWORD MainIndexes, - PDWORD OldIndexArray, void * pvContext) { #ifdef PLATFORM_WINDOWS @@ -81,7 +79,7 @@ int ScanIndexDirectory( if(!(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { // Let the callback scan the file name - pfnOnFileFound(wf.cFileName, MainIndexes, OldIndexArray, pvContext); + pfnOnFileFound(wf.cFileName, pvContext); } } @@ -103,7 +101,7 @@ int ScanIndexDirectory( { if(dir_entry->d_type != DT_DIR) { - pfnOnFileFound(dir_entry->d_name, MainIndexes, OldIndexArray, pvContext); + pfnOnFileFound(dir_entry->d_name, pvContext); } } diff --git a/dep/CascLib/src/common/Directory.h b/dep/CascLib/src/common/Directory.h index 739f0612e54..30c7e384284 100644 --- a/dep/CascLib/src/common/Directory.h +++ b/dep/CascLib/src/common/Directory.h @@ -14,17 +14,13 @@ //----------------------------------------------------------------------------- // Scanning a directory -typedef bool (*INDEX_FILE_FOUND)(const TCHAR * szFileName, PDWORD IndexArray, PDWORD OldIndexArray, void * pvContext); +bool DirectoryExists(LPCTSTR szDirectory); -bool DirectoryExists(const TCHAR * szDirectory); - -bool MakeDirectory(const TCHAR * szDirectory); +bool MakeDirectory(LPCTSTR szDirectory); int ScanIndexDirectory( - const TCHAR * szIndexPath, + LPCTSTR szIndexPath, INDEX_FILE_FOUND pfnOnFileFound, - PDWORD IndexArray, - PDWORD OldIndexArray, void * pvContext ); diff --git a/dep/CascLib/src/common/FileStream.cpp b/dep/CascLib/src/common/FileStream.cpp index cd3300a46a7..ab591a2e3f1 100644 --- a/dep/CascLib/src/common/FileStream.cpp +++ b/dep/CascLib/src/common/FileStream.cpp @@ -680,7 +680,7 @@ static bool BaseHttp_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, szStatusCode, &dwDataSize, &dwIndex)) dwStatusCode = _tcstoul(szStatusCode, &szEndPtr, 10); - // Copare the statuc code + // Compare the status code if (dwStatusCode == 200) { // Check if the archive has Last Modified field diff --git a/dep/CascLib/src/common/ListFile.cpp b/dep/CascLib/src/common/ListFile.cpp index a2239e18fa3..bcca8b7177a 100644 --- a/dep/CascLib/src/common/ListFile.cpp +++ b/dep/CascLib/src/common/ListFile.cpp @@ -199,7 +199,7 @@ size_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const { // If we have found a newline, stop loading // Note: the 0x85 char came from Overwatch build 24919 - if(pCache->pPos[0] == 0x0A || pCache->pPos[0] == 0x0D || pCache->pPos[0] == 0x85) + if(pCache->pPos[0] == '\x0A' || pCache->pPos[0] == '\x0D' || pCache->pPos[0] == '\x85') break; // Blizzard listfiles can also contain information about patch: diff --git a/dep/CascLib/src/common/Map.h b/dep/CascLib/src/common/Map.h index a6eface844d..4b277cb73a8 100644 --- a/dep/CascLib/src/common/Map.h +++ b/dep/CascLib/src/common/Map.h @@ -94,7 +94,7 @@ class CASC_MAP Free(); } - int Create(size_t MaxItems, size_t KeyLength, size_t KeyOffset, KEY_TYPE KeyType = KeyIsHash) + DWORD Create(size_t MaxItems, size_t KeyLength, size_t KeyOffset, KEY_TYPE KeyType = KeyIsHash) { // Set the class variables m_KeyLength = CASCLIB_MAX(KeyLength, 8); @@ -331,7 +331,7 @@ class CASC_MAP size_t PowerOfTwo; // Round the hash table size up to the nearest power of two - for(PowerOfTwo = MIN_HASH_TABLE_SIZE; PowerOfTwo < MAX_HASH_TABLE_SIZE; PowerOfTwo <<= 1) + for(PowerOfTwo = MIN_HASH_TABLE_SIZE; PowerOfTwo <= MAX_HASH_TABLE_SIZE; PowerOfTwo <<= 1) { if(PowerOfTwo > MaxItems) { -- cgit v1.2.3