aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2019-10-29 19:01:39 +0100
committerShauren <shauren.trinity@gmail.com>2019-10-29 19:01:39 +0100
commitc7b41574376c21eb37ed6d45dc4f1b3bf1b528c4 (patch)
treed14503fb201a38ea913627a7b00a8fd395e3a2a9 /dep/CascLib/src
parent4328e1dfb2ba0900e6a053622f16da1cd5debc9b (diff)
Dep/CascLib: Update to ladislav-zezula/CascLib@225777494069b0b0e18bea3ffeb3773d44a70b30
Diffstat (limited to 'dep/CascLib/src')
-rw-r--r--dep/CascLib/src/CascCommon.h16
-rw-r--r--dep/CascLib/src/CascDecrypt.cpp119
-rw-r--r--dep/CascLib/src/CascFiles.cpp24
-rw-r--r--dep/CascLib/src/CascIndexFiles.cpp211
-rw-r--r--dep/CascLib/src/CascLib.def8
-rw-r--r--dep/CascLib/src/CascLib.h12
-rw-r--r--dep/CascLib/src/CascOpenStorage.cpp144
-rw-r--r--dep/CascLib/src/CascPort.h16
-rw-r--r--dep/CascLib/src/CascRootFile_TVFS.cpp72
-rw-r--r--dep/CascLib/src/DllMain.rc8
-rw-r--r--dep/CascLib/src/common/Common.h12
-rw-r--r--dep/CascLib/src/common/Directory.cpp8
-rw-r--r--dep/CascLib/src/common/Directory.h10
-rw-r--r--dep/CascLib/src/common/FileStream.cpp2
-rw-r--r--dep/CascLib/src/common/ListFile.cpp2
-rw-r--r--dep/CascLib/src/common/Map.h4
16 files changed, 433 insertions, 235 deletions
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
@@ -21,6 +21,27 @@
#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
TCascStorage::TCascStorage()
@@ -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 <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
- #include <unistd.h>
#include <fcntl.h>
- #include <stdlib.h>
#include <dirent.h>
- #include <errno.h>
+ #include <unistd.h>
#include <stddef.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <stdarg.h>
#include <string.h>
#include <ctype.h>
+ #include <wchar.h>
#include <cassert>
+ #include <errno.h>
// 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)
{