aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2025-02-28 17:41:28 +0100
committerShauren <shauren.trinity@gmail.com>2025-02-28 17:41:28 +0100
commit464d8e39e083a2f3a73f2c33a7b20036406541c8 (patch)
tree56fc8960ebf3fa92d1029f1a80bdda3ff766d6d5 /dep/CascLib
parent438d0c3089aaf48352e493ab0a007ef6ef15a276 (diff)
Dep/CascLib: Update to ladislav-zezula/CascLib@07ab5f37ad282cc101d5c17793c550a0a6d4637f
Diffstat (limited to 'dep/CascLib')
-rw-r--r--dep/CascLib/src/CascCommon.h24
-rw-r--r--dep/CascLib/src/CascFiles.cpp76
-rw-r--r--dep/CascLib/src/CascIndexFiles.cpp8
-rw-r--r--dep/CascLib/src/CascLib.h17
-rw-r--r--dep/CascLib/src/CascOpenStorage.cpp27
-rw-r--r--dep/CascLib/src/CascPort.h5
-rw-r--r--dep/CascLib/src/CascReadFile.cpp3
-rw-r--r--dep/CascLib/src/CascRootFile_OW.cpp10
-rw-r--r--dep/CascLib/src/CascRootFile_TVFS.cpp2
-rw-r--r--dep/CascLib/src/CascRootFile_WoW.cpp152
-rw-r--r--dep/CascLib/src/CascStructs.h2
-rw-r--r--dep/CascLib/src/DllMain.def2
-rw-r--r--dep/CascLib/src/common/Common.cpp7
13 files changed, 236 insertions, 99 deletions
diff --git a/dep/CascLib/src/CascCommon.h b/dep/CascLib/src/CascCommon.h
index 97d69c97791..8e9f2ceae6c 100644
--- a/dep/CascLib/src/CascCommon.h
+++ b/dep/CascLib/src/CascCommon.h
@@ -23,6 +23,7 @@
#if defined(_DEBUG) && !defined(CASCLIB_NODEBUG)
#define CASCLIB_DEBUG
+//#define CASCLIB_WRITE_VERIFIED_FILENAMES // If defined, TRootHandler_WoW will save all files whose hashes are confirmed
#endif
#include "CascPort.h"
@@ -109,14 +110,13 @@ typedef struct _CASC_BUILD_FILE
} CASC_BUILD_FILE, *PCASC_BUILD_FILE;
// Information about index file
-struct CASC_INDEX
+typedef struct _CASC_INDEX
{
CASC_BLOB FileData;
LPTSTR szFileName; // Full name of the index file
DWORD NewSubIndex; // New subindex
DWORD OldSubIndex; // Old subindex
-};
-typedef CASC_INDEX * PCASC_INDEX;
+} CASC_INDEX, *PCASC_INDEX;
// Normalized header of the index files.
// Both version 1 and version 2 are converted to this structure
@@ -277,6 +277,22 @@ struct TCascStorage
hs->ClassName == CASC_MAGIC_STORAGE) ? hs : NULL;
}
+ DWORD SetProductCodeName(LPCSTR szNewCodeName, size_t nLength = 0)
+ {
+ if(szCodeName == NULL && szNewCodeName != NULL)
+ {
+ // Make sure we have the length
+ if(nLength == 0)
+ nLength = strlen(szNewCodeName);
+
+ // Allocate the code name buffer and copy from ANSI string
+ if((szCodeName = CASC_ALLOC<TCHAR>(nLength + 1)) == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ CascStrCopy(szCodeName, nLength + 1, szNewCodeName, nLength);
+ }
+ return ERROR_SUCCESS;
+ }
+
// Class recognizer. Has constant value of 'CASCSTOR' (CASC_MAGIC_STORAGE)
ULONGLONG ClassName;
@@ -456,7 +472,7 @@ inline void FreeCascBlob(PCASC_BLOB pBlob)
//-----------------------------------------------------------------------------
// Text file parsing (CascFiles.cpp)
-bool InvokeProgressCallback(TCascStorage * hs, LPCSTR szMessage, LPCSTR szObject, DWORD CurrentValue, DWORD TotalValue);
+bool InvokeProgressCallback(TCascStorage * hs, CASC_PROGRESS_MSG Message, LPCSTR szObject, DWORD CurrentValue, DWORD TotalValue);
DWORD GetFileSpanInfo(PCASC_CKEY_ENTRY pCKeyEntry, PULONGLONG PtrContentSize, PULONGLONG PtrEncodedSize = NULL);
DWORD FetchCascFile(TCascStorage * hs, CPATH_TYPE PathType, LPBYTE pbEKey, LPCTSTR szExtension, CASC_PATH<TCHAR> & LocalPath, PCASC_ARCHIVE_INFO pArchiveInfo = NULL);
DWORD CheckCascBuildFileExact(CASC_BUILD_FILE & BuildFile, LPCTSTR szLocalPath);
diff --git a/dep/CascLib/src/CascFiles.cpp b/dep/CascLib/src/CascFiles.cpp
index 58d239e60ad..d401be95fd9 100644
--- a/dep/CascLib/src/CascFiles.cpp
+++ b/dep/CascLib/src/CascFiles.cpp
@@ -496,16 +496,7 @@ static DWORD LoadVfsRootEntry(TCascStorage * hs, const char * szVariableName, co
static DWORD LoadBuildProductId(TCascStorage * hs, const char * /* szVariableName */, const char * szDataBegin, const char * szDataEnd, void * /* pvParam */)
{
- size_t nLength = (szDataEnd - szDataBegin);
-
- if(hs->szCodeName == NULL)
- {
- if((hs->szCodeName = CASC_ALLOC<TCHAR>(nLength + 1)) != NULL)
- {
- CascStrCopy(hs->szCodeName, nLength + 1, szDataBegin, nLength);
- }
- }
-
+ hs->SetProductCodeName(szDataBegin, (szDataEnd - szDataBegin));
return ERROR_SUCCESS;
}
@@ -559,14 +550,6 @@ static int LoadQueryKey(const CASC_CSV_COLUMN & Column, CASC_BLOB & Key)
return LoadHashArray(&Key, Column.szValue, Column.szValue + Column.nLength, 1);
}
-static void SetProductCodeName(TCascStorage * hs, LPCSTR szCodeName)
-{
- if(hs->szCodeName == NULL && szCodeName != NULL)
- {
- hs->szCodeName = CascNewStrA2T(szCodeName);
- }
-}
-
static DWORD GetDefaultCdnServers(TCascStorage * hs, const CASC_CSV_COLUMN & Column)
{
if(hs->szCdnServers == NULL && Column.nLength != 0)
@@ -661,12 +644,12 @@ static DWORD ParseFile_BuildInfo(TCascStorage * hs, CASC_CSV & Csv)
return ERROR_CANCELLED;
// We now have preferred product to open
- SetProductCodeName(hs, ProductsList[nChoiceIndex]);
+ hs->SetProductCodeName(ProductsList[nChoiceIndex]);
}
else if(nProductCount == 1)
{
// We now have preferred product to open
- SetProductCodeName(hs, ProductsList[nDefault]);
+ hs->SetProductCodeName(ProductsList[nDefault]);
}
else
{
@@ -692,7 +675,7 @@ static DWORD ParseFile_BuildInfo(TCascStorage * hs, CASC_CSV & Csv)
continue;
// Save the code name of the selected product
- SetProductCodeName(hs, Csv[i]["Product!STRING:0"].szValue);
+ hs->SetProductCodeName(Csv[i]["Product!STRING:0"].szValue);
nSelected = i;
break;
}
@@ -949,7 +932,7 @@ static DWORD LoadCsvFile(TCascStorage * hs, PARSE_REGION_LINE PfnParseRegionLine
{
// Inform the user that we are downloading something
CascStrCopy(szFileNameA, _countof(szFileNameA), szFileName);
- if(InvokeProgressCallback(hs, "Downloading the \"%s\" file", szFileNameA, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressDownloadingFile, szFileNameA, 0, 0))
return ERROR_CANCELLED;
// Download the file using Ribbit/HTTP protocol
@@ -1275,6 +1258,23 @@ static DWORD HttpDownloadFile(
return dwErrCode;
}
+DWORD SetProductCodeName(TCascStorage * hs, LPCSTR szCodeName, size_t nLength)
+{
+ if(hs->szCodeName == NULL && szCodeName != NULL)
+ {
+ // Make sure we have the length
+ if(nLength == 0)
+ {
+ nLength = strlen(szCodeName);
+ }
+
+ if((hs->szCodeName = CASC_ALLOC<TCHAR>(nLength + 1)) == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ CascStrCopy(hs->szCodeName, nLength + 1, szCodeName, nLength);
+ }
+ return ERROR_SUCCESS;
+}
+
DWORD FetchCascFile(
TCascStorage * hs,
LPCTSTR szRootPath,
@@ -1450,13 +1450,13 @@ static LPTSTR CheckForDirectories(LPCTSTR szParentFolder, ...)
//-----------------------------------------------------------------------------
// Public functions
-bool InvokeProgressCallback(TCascStorage * hs, LPCSTR szMessage, LPCSTR szObject, DWORD CurrentValue, DWORD TotalValue)
+bool InvokeProgressCallback(TCascStorage * hs, CASC_PROGRESS_MSG Message, LPCSTR szObject, DWORD CurrentValue, DWORD TotalValue)
{
PCASC_OPEN_STORAGE_ARGS pArgs = hs->pArgs;
bool bResult = false;
if(pArgs && pArgs->PfnProgressCallback)
- bResult = pArgs->PfnProgressCallback(pArgs->PtrProgressParam, szMessage, szObject, CurrentValue, TotalValue);
+ bResult = pArgs->PfnProgressCallback(pArgs->PtrProgressParam, Message, szObject, CurrentValue, TotalValue);
return bResult;
}
@@ -1522,14 +1522,14 @@ DWORD CheckCascBuildFileExact(CASC_BUILD_FILE & BuildFile, LPCTSTR szLocalPath)
}
// Unrecognized file name
- return ERROR_BAD_FORMAT;
+ return ERROR_FILE_NOT_FOUND;
}
DWORD CheckCascBuildFileDirs(CASC_BUILD_FILE & BuildFile, LPCTSTR szLocalPath)
{
CASC_PATH<TCHAR> WorkPath(szLocalPath, NULL);
- DWORD dwErrCode = ERROR_FILE_NOT_FOUND;
-
+ DWORD dwLevelCount = 0;
+
// Clear the build file structure
memset(&BuildFile, 0, sizeof(CASC_BUILD_FILE));
@@ -1547,16 +1547,15 @@ DWORD CheckCascBuildFileDirs(CASC_BUILD_FILE & BuildFile, LPCTSTR szLocalPath)
}
}
- // Try to cut off one path path
- if(!WorkPath.CutLastPart())
+ // Try to cut off one path path. Don't go indefinitely.
+ if((dwLevelCount > 5) || !WorkPath.CutLastPart())
{
- dwErrCode = ERROR_PATH_NOT_FOUND;
break;
}
}
- // Unrecognized file name
- return dwErrCode;
+ // None of the supported file names was found
+ return ERROR_FILE_NOT_FOUND;
}
DWORD CheckOnlineStorage(PCASC_OPEN_STORAGE_ARGS pArgs, CASC_BUILD_FILE & BuildFile, bool bOnlineStorage)
@@ -1616,6 +1615,7 @@ DWORD CheckArchiveFilesDirectories(TCascStorage * hs)
DWORD CheckDataFilesDirectory(TCascStorage * hs)
{
CASC_PATH<TCHAR> DataPath(hs->szRootPath, _T("data"), NULL);
+ DWORD dwErrCode;
bool bTwoDigitFolderFound = false;
// When CASC_FEATURE_ONLINE is not set, then the folder must exist
@@ -1623,17 +1623,15 @@ DWORD CheckDataFilesDirectory(TCascStorage * hs)
{
// Check if there are subfolders at all. If not, do not bother
// the file system with open requests into data files folder
- if(ScanDirectory(DataPath, CheckForTwoDigitFolder, NULL, &bTwoDigitFolderFound) != ERROR_SUCCESS)
- return ERROR_PATH_NOT_FOUND;
+ if((dwErrCode = ScanDirectory(DataPath, CheckForTwoDigitFolder, NULL, &bTwoDigitFolderFound)) != ERROR_SUCCESS)
+ return dwErrCode;
if(bTwoDigitFolderFound == false)
return ERROR_PATH_NOT_FOUND;
}
// Create the path for raw files
- if((hs->szFilesPath = DataPath.New()) == NULL)
- return ERROR_NOT_ENOUGH_MEMORY;
- return ERROR_SUCCESS;
+ return ((hs->szFilesPath = DataPath.New()) == NULL) ? ERROR_NOT_ENOUGH_MEMORY : ERROR_SUCCESS;
}
DWORD LoadBuildFile_Versions_Cdns(TCascStorage * hs)
@@ -1705,7 +1703,7 @@ DWORD LoadCdnConfigFile(TCascStorage * hs)
assert(hs->CdnConfigKey.pbData != NULL && hs->CdnConfigKey.cbData == MD5_HASH_SIZE);
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Loading CDN config file", NULL, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressLoadingFile, "CDN config", 0, 0))
return ERROR_CANCELLED;
// Load the CDN config file
@@ -1718,7 +1716,7 @@ DWORD LoadCdnBuildFile(TCascStorage * hs)
assert(hs->CdnBuildKey.pbData != NULL && hs->CdnBuildKey.cbData == MD5_HASH_SIZE);
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Loading CDN build file", NULL, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressLoadingFile, "CDN build", 0, 0))
return ERROR_CANCELLED;
// Load the CDN config file. Note that we don't
diff --git a/dep/CascLib/src/CascIndexFiles.cpp b/dep/CascLib/src/CascIndexFiles.cpp
index c26a975bada..79b197d5450 100644
--- a/dep/CascLib/src/CascIndexFiles.cpp
+++ b/dep/CascLib/src/CascIndexFiles.cpp
@@ -276,7 +276,7 @@ static DWORD LoadIndexItems(TCascStorage * hs, CASC_INDEX_HEADER & InHeader, EKE
while((pbEKeyEntry + EntryLength) <= pbEKeyEnd)
{
// ENCODING for Starcraft II Beta
- BREAK_ON_XKEY3(pbEKeyEntry, 0x8b, 0x0d, 0x9a);
+ // BREAK_ON_XKEY3(pbEKeyEntry, 0x8b, 0x0d, 0x9a);
if(!PfnEKeyEntry(hs, InHeader, pbEKeyEntry))
return ERROR_INDEX_PARSING_DONE;
@@ -487,7 +487,7 @@ static DWORD ProcessLocalIndexFiles(TCascStorage * hs, EKEY_ENTRY_CALLBACK PfnEK
CASC_INDEX & IndexFile = hs->IndexFiles[i];
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Loading index files", NULL, i, dwIndexCount))
+ if(InvokeProgressCallback(hs, CascProgressLoadingIndexes, NULL, i, dwIndexCount))
{
dwErrCode = ERROR_CANCELLED;
break;
@@ -514,7 +514,7 @@ static DWORD LoadLocalIndexFiles(TCascStorage * hs)
DWORD dwErrCode;
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Loading index files", NULL, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressLoadingIndexes, NULL, 0, 0))
return ERROR_CANCELLED;
// Perform the directory scan
@@ -749,7 +749,7 @@ static DWORD LoadArchiveIndexFiles(TCascStorage * hs)
LPBYTE pbIndexHash = hs->ArchivesKey.pbData + (i * MD5_HASH_SIZE);
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Downloading archive indexes", NULL, (DWORD)(i), (DWORD)(nArchiveCount)))
+ if(InvokeProgressCallback(hs, CascProgressDownloadingArchiveIndexes, NULL, (DWORD)(i), (DWORD)(nArchiveCount)))
{
dwErrCode = ERROR_CANCELLED;
break;
diff --git a/dep/CascLib/src/CascLib.h b/dep/CascLib/src/CascLib.h
index 6936c05a649..ba97109ac89 100644
--- a/dep/CascLib/src/CascLib.h
+++ b/dep/CascLib/src/CascLib.h
@@ -72,6 +72,12 @@ extern "C" {
#endif
#endif
+#if defined(CASCLIB_DETECT_UNICODE_MISMATCHES)
+#if defined(_UNICODE) != defined(CASCLIB_UNICODE)
+#error CascLib was not built with the same UNICODE setting as your project
+#endif
+#endif
+
//-----------------------------------------------------------------------------
// Defines
@@ -318,12 +324,21 @@ typedef struct _CASC_FILE_SPAN_INFO
//-----------------------------------------------------------------------------
// Extended version of CascOpenStorage
+typedef enum _CASC_PROGRESS_MSG
+{
+ CascProgressLoadingFile, // "Loading file: %s"
+ CascProgressLoadingManifest, // "Loading manifest: %s"
+ CascProgressDownloadingFile, // "Downloading file: %s"
+ CascProgressLoadingIndexes, // "Loading index files"
+ CascProgressDownloadingArchiveIndexes, // "Downloading archive indexes"
+} CASC_PROGRESS_MSG, *PCASC_PROGRESS_MSG;
+
// Some operations (e.g. opening an online storage) may take long time.
// This callback allows an application to be notified about loading progress
// and even cancel the storage loading process
typedef bool (WINAPI * PFNPROGRESSCALLBACK)( // Return 'true' to cancel the loading process
void * PtrUserParam, // User-specific parameter passed to the callback
- LPCSTR szWork, // Text for the current activity (example: "Loading "ENCODING" file")
+ CASC_PROGRESS_MSG ProgressMsg, // Text for the current activity. The target callback needs to translate it into language-specific message
LPCSTR szObject, // (optional) name of the object tied to the activity (example: index file name)
DWORD CurrentValue, // (optional) current object being processed
DWORD TotalValue // (optional) If non-zero, this is the total number of objects to process
diff --git a/dep/CascLib/src/CascOpenStorage.cpp b/dep/CascLib/src/CascOpenStorage.cpp
index acbd14075e7..cfe42faaf16 100644
--- a/dep/CascLib/src/CascOpenStorage.cpp
+++ b/dep/CascLib/src/CascOpenStorage.cpp
@@ -442,7 +442,7 @@ static DWORD LoadEncodingManifest(TCascStorage * hs)
DWORD dwErrCode = ERROR_SUCCESS;
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Loading ENCODING manifest", NULL, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressLoadingManifest, "ENCODING", 0, 0))
return ERROR_CANCELLED;
// Fill-in the information from the index entry and insert it to the file tree
@@ -753,7 +753,7 @@ static int LoadDownloadManifest(TCascStorage * hs)
DWORD dwErrCode = ERROR_SUCCESS;
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Loading DOWNLOAD manifest", NULL, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressLoadingManifest, "DOWNLOAD", 0, 0))
return ERROR_CANCELLED;
// Load the entire DOWNLOAD file to memory
@@ -786,7 +786,7 @@ static int LoadInstallManifest(TCascStorage * hs)
DWORD dwErrCode = ERROR_SUCCESS;
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Loading INSTALL manifest", NULL, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressLoadingManifest, "INSTALL", 0, 0))
return ERROR_CANCELLED;
// Load the entire DOWNLOAD file to memory
@@ -854,7 +854,7 @@ static int LoadBuildManifest(TCascStorage * hs, DWORD dwLocaleMask)
assert(hs->pRootHandler == NULL);
// Inform the user about what we are doing
- if(InvokeProgressCallback(hs, "Loading ROOT manifest", NULL, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressLoadingManifest, "ROOT", 0, 0))
return ERROR_CANCELLED;
// Locale: The default parameter is 0 - in that case, we load all locales
@@ -913,6 +913,10 @@ __LoadRootFile:
break;
}
}
+ else
+ {
+ dwErrCode = ERROR_BAD_FORMAT;
+ }
}
else
{
@@ -922,7 +926,7 @@ __LoadRootFile:
// Handle reparsing of the root file
if(dwErrCode == ERROR_REPARSE_ROOT && pCKeyEntry != &hs->RootFile)
{
- if(InvokeProgressCallback(hs, "Loading ROOT manifest (reparsed)", NULL, 0, 0))
+ if(InvokeProgressCallback(hs, CascProgressLoadingManifest, "ROOT (reparsed)", 0, 0))
return ERROR_CANCELLED;
// Replace the root handler
@@ -1182,6 +1186,12 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs, L
hs->dwBuildNumber = 21742 + hs->InstallCKey.ContentSize;
}
+ // Make sure we have a code name. Not a case of WoW build 22267
+ if(hs->szCodeName == NULL && hs->dwBuildNumber == 22267)
+ {
+ hs->SetProductCodeName("wow", 3);
+ }
+
// Create the array of CKey entries. Each entry represents a file in the storage
if(dwErrCode == ERROR_SUCCESS)
{
@@ -1337,6 +1347,13 @@ static DWORD ParseOpenParams(LPTSTR szParams, PCASC_OPEN_STORAGE_ARGS pArgs)
pArgs->szRegion = szParamsPtr;
}
+ // There could be region appended at the end
+ if((szParamsPtr = GetNextParam(szParamsPtr)) != NULL)
+ {
+ if(pArgs->szBuildKey && pArgs->szBuildKey[0])
+ return ERROR_INVALID_PARAMETER;
+ pArgs->szBuildKey = szParamsPtr;
+ }
return ERROR_SUCCESS;
}
diff --git a/dep/CascLib/src/CascPort.h b/dep/CascLib/src/CascPort.h
index 641c7331461..7ead36b69f3 100644
--- a/dep/CascLib/src/CascPort.h
+++ b/dep/CascLib/src/CascPort.h
@@ -100,10 +100,6 @@
#define PKEXPORT
- #ifndef __SYS_ZLIB
- #define __SYS_ZLIB
- #endif
-
#ifndef __BIG_ENDIAN__
#define CASCLIB_PLATFORM_LITTLE_ENDIAN
#endif
@@ -210,6 +206,7 @@
#define _tremove remove
#define _taccess access
#define _access access
+ #define _tfopen fopen
#define _stricmp strcasecmp
#define _strnicmp strncasecmp
diff --git a/dep/CascLib/src/CascReadFile.cpp b/dep/CascLib/src/CascReadFile.cpp
index 32efbc5b100..76b34f6415c 100644
--- a/dep/CascLib/src/CascReadFile.cpp
+++ b/dep/CascLib/src/CascReadFile.cpp
@@ -1290,6 +1290,9 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
case CascCacheLastFrame:
dwBytesRead2 = ReadFile_FrameCached(hf, pbBuffer, StartOffset, EndOffset);
break;
+
+ default:
+ break;
}
// If the second-stage-read failed, we invalidate the entire operation and return 0 bytes read
diff --git a/dep/CascLib/src/CascRootFile_OW.cpp b/dep/CascLib/src/CascRootFile_OW.cpp
index 05a33ff7a51..41fb40dbc15 100644
--- a/dep/CascLib/src/CascRootFile_OW.cpp
+++ b/dep/CascLib/src/CascRootFile_OW.cpp
@@ -34,7 +34,7 @@ typedef struct _APM_HEADER_V3
// Followed by the array of APM_ENTRY (count is in "EntryCount")
// Followed by the array of APM_PACKAGE (count is in "PackageCount")
-} APM_HEADER_V3, * PAPM_HEADER_V3;
+} APM_HEADER_V3, *PAPM_HEADER_V3;
typedef struct _APM_HEADER_V2
{
@@ -48,7 +48,7 @@ typedef struct _APM_HEADER_V2
// Followed by the array of APM_ENTRY (count is in "EntryCount")
// Followed by the array of APM_PACKAGE (count is in "PackageCount")
-} APM_HEADER_V2, * PAPM_HEADER_V2;
+} APM_HEADER_V2, *PAPM_HEADER_V2;
typedef struct _APM_HEADER_V1
{
@@ -61,7 +61,7 @@ typedef struct _APM_HEADER_V1
// Followed by the array of APM_ENTRY (count is in "EntryCount")
// Followed by the array of APM_PACKAGE (count is in "PackageCount")
-} APM_HEADER_V1, * PAPM_HEADER_V1;
+} APM_HEADER_V1, *PAPM_HEADER_V1;
// On-disk format, size = 0x0C
typedef struct _APM_ENTRY_V1
@@ -69,7 +69,7 @@ typedef struct _APM_ENTRY_V1
DWORD Index;
DWORD HashA_Lo; // Must split the hashes in order to make this structure properly aligned
DWORD HashA_Hi;
-} APM_ENTRY_V1, * PAPM_ENTRY_V1;
+} APM_ENTRY_V1, *PAPM_ENTRY_V1;
// On-disk format, size = 0x14
typedef struct _APM_ENTRY_V2
@@ -91,7 +91,7 @@ typedef struct _APM_PACKAGE_ENTRY_V1
ULONGLONG PackageGUID; // 077 file
ULONGLONG Unknown1;
DWORD Unknown2;
-} APM_PACKAGE_ENTRY_V1, * PAPM_PACKAGE_ENTRY_V1;
+} APM_PACKAGE_ENTRY_V1, *PAPM_PACKAGE_ENTRY_V1;
// On-disk format
typedef struct _APM_PACKAGE_ENTRY_V2
diff --git a/dep/CascLib/src/CascRootFile_TVFS.cpp b/dep/CascLib/src/CascRootFile_TVFS.cpp
index d6c00bf5353..c98801d0d88 100644
--- a/dep/CascLib/src/CascRootFile_TVFS.cpp
+++ b/dep/CascLib/src/CascRootFile_TVFS.cpp
@@ -712,7 +712,7 @@ struct TRootHandler_TVFS : public TFileTreeRoot
FileTree.SetKeyLength(RootHeader.EKeySize);
// Initialize the array of span entries
- dwErrCode = SpanArray.Create(sizeof(CASC_CKEY_ENTRY), 0x100);
+ dwErrCode = SpanArray.Create(sizeof(CASC_CKEY_ENTRY), 0x10000);
if(dwErrCode != ERROR_SUCCESS)
return dwErrCode;
diff --git a/dep/CascLib/src/CascRootFile_WoW.cpp b/dep/CascLib/src/CascRootFile_WoW.cpp
index b3e75fa746e..6f3521cfceb 100644
--- a/dep/CascLib/src/CascRootFile_WoW.cpp
+++ b/dep/CascLib/src/CascRootFile_WoW.cpp
@@ -35,6 +35,19 @@ typedef enum _ROOT_FORMAT
RootFormatWoW_v2, // Since build 30080 (WoW 8.2.0)
} ROOT_FORMAT, *PROOT_FORMAT;
+// The last byte of the structure causes wrong alignment with default compiler options
+#pragma pack(push, 1)
+typedef struct _FILE_ROOT_GROUP_HEADER_58221 // Since build 58221 (11.1.0.58221)
+{
+ DWORD NumberOfFiles; // Number of entries
+ DWORD LocaleFlags; // File locale mask (CASC_LOCALE_XXX)
+ DWORD ContentFlags1;
+ DWORD ContentFlags2;
+ BYTE ContentFlags3;
+
+} FILE_ROOT_GROUPHEADER_58221, *PFILE_ROOT_GROUPHEADER_58221;
+#pragma pack(pop)
+
// ROOT file header since build 50893 (10.1.7)
typedef struct _FILE_ROOT_HEADER_50893
{
@@ -43,7 +56,7 @@ typedef struct _FILE_ROOT_HEADER_50893
DWORD Version; // Must be 1
DWORD TotalFiles;
DWORD FilesWithNameHash;
-} FILE_ROOT_HEADER_50893, * PFILE_ROOT_HEADER_50893;
+} FILE_ROOT_HEADER_50893, *PFILE_ROOT_HEADER_50893;
// ROOT file header since build 30080 (8.2.0)
typedef struct _FILE_ROOT_HEADER_30080
@@ -97,14 +110,15 @@ struct TRootHandler_WoW : public TFileTreeRoot
{
public:
- typedef LPBYTE (*CAPTURE_ROOT_HEADER)(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless);
+ typedef LPBYTE (*CAPTURE_ROOT_HEADER)(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version);
- TRootHandler_WoW(ROOT_FORMAT RFormat, DWORD HashlessFileCount) : TFileTreeRoot(FTREE_FLAGS_WOW)
+ TRootHandler_WoW(ROOT_FORMAT aRootFormat, DWORD aFileCounterHashless, LPCTSTR szDumpFile = NULL) : TFileTreeRoot(FTREE_FLAGS_WOW)
{
// Turn off the "we know file names" bit
- FileCounterHashless = HashlessFileCount;
+ FileCounterHashless = aFileCounterHashless;
FileCounter = 0;
- RootFormat = RFormat;
+ RootFormat = aRootFormat;
+ fp = NULL;
// Update the flags based on format
switch(RootFormat)
@@ -117,10 +131,44 @@ struct TRootHandler_WoW : public TFileTreeRoot
dwFeatures |= CASC_FEATURE_ROOT_CKEY | CASC_FEATURE_LOCALE_FLAGS | CASC_FEATURE_CONTENT_FLAGS | CASC_FEATURE_FNAME_HASHES;
break;
}
+
+ // Create the file for dumping listfile
+ if(szDumpFile && szDumpFile[0])
+ {
+ fp = _tfopen(szDumpFile, _T("wt"));
+ }
+ }
+
+ ~TRootHandler_WoW()
+ {
+ if(fp != NULL)
+ fclose(fp);
+ fp = NULL;
}
+#ifdef CASCLIB_WRITE_VERIFIED_FILENAMES
+ void VerifyAndLogFileName(LPCSTR szFileName, ULONG FileDataId)
+ {
+ PCASC_FILE_NODE pFileNode;
+ ULONGLONG FileNameHash = CalcFileNameHash(szFileName);
+
+ if((pFileNode = FileTree.Find(FileNameHash)) != NULL)
+ {
+ if(pFileNode->FileNameHash == FileNameHash)
+ {
+ if(FileDataId != 0)
+ fprintf(fp, "%u;%s\n", FileDataId, szFileName);
+ else
+ fprintf(fp, "%s\n", szFileName);
+ }
+ }
+ }
+#else
+ #define VerifyAndLogFileName(szFileName, FileDataId) /* */
+#endif
+
// Check for the new format (World of Warcraft 10.1.7, build 50893)
- static LPBYTE CaptureRootHeader_50893(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless)
+ static LPBYTE CaptureRootHeader_50893(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version)
{
FILE_ROOT_HEADER_50893 RootHeader;
@@ -132,7 +180,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
// Verify the root file header
if(RootHeader.Signature != CASC_WOW_ROOT_SIGNATURE)
return NULL;
- if(RootHeader.Version != 1)
+ if(RootHeader.Version != 1 && RootHeader.Version != 2)
return NULL;
if(RootHeader.FilesWithNameHash > RootHeader.TotalFiles)
return NULL;
@@ -142,11 +190,12 @@ struct TRootHandler_WoW : public TFileTreeRoot
*RootFormat = RootFormatWoW_v2;
*FileCounterHashless = RootHeader.TotalFiles - RootHeader.FilesWithNameHash;
+ *Version = RootHeader.Version;
return pbRootPtr + RootHeader.SizeOfHeader;
}
// Check for the root format for build 30080+ (WoW 8.2.0)
- static LPBYTE CaptureRootHeader_30080(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless)
+ static LPBYTE CaptureRootHeader_30080(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version)
{
FILE_ROOT_HEADER_30080 RootHeader;
@@ -163,11 +212,12 @@ struct TRootHandler_WoW : public TFileTreeRoot
*RootFormat = RootFormatWoW_v2;
*FileCounterHashless = RootHeader.TotalFiles - RootHeader.FilesWithNameHash;
+ *Version = 0;
return pbRootPtr + sizeof(FILE_ROOT_HEADER_30080);
}
// Check for the root format for build 18125+ (WoW 6.0.1)
- static LPBYTE CaptureRootHeader_18125(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless)
+ static LPBYTE CaptureRootHeader_18125(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version)
{
size_t DataLength;
@@ -183,10 +233,11 @@ struct TRootHandler_WoW : public TFileTreeRoot
*RootFormat = RootFormatWoW_v1;
*FileCounterHashless = 0;
+ *Version = 0;
return pbRootPtr;
}
- static LPBYTE CaptureRootHeader(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless)
+ static LPBYTE CaptureRootHeader(LPBYTE pbRootPtr, LPBYTE pbRootEnd, PROOT_FORMAT RootFormat, PDWORD FileCounterHashless, PDWORD Version)
{
CAPTURE_ROOT_HEADER PfnCaptureRootHeader[] =
{
@@ -199,7 +250,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
{
LPBYTE pbCapturedPtr;
- if((pbCapturedPtr = PfnCaptureRootHeader[i](pbRootPtr, pbRootEnd, RootFormat, FileCounterHashless)) != NULL)
+ if((pbCapturedPtr = PfnCaptureRootHeader[i](pbRootPtr, pbRootEnd, RootFormat, FileCounterHashless, Version)) != NULL)
{
return pbCapturedPtr;
}
@@ -207,16 +258,34 @@ struct TRootHandler_WoW : public TFileTreeRoot
return NULL;
}
- LPBYTE CaptureRootGroup(FILE_ROOT_GROUP & RootGroup, LPBYTE pbRootPtr, LPBYTE pbRootEnd)
+ LPBYTE CaptureRootGroup(FILE_ROOT_GROUP & RootGroup, LPBYTE pbRootPtr, LPBYTE pbRootEnd, DWORD dwRootVersion)
{
// Reset the entire root group structure
memset(&RootGroup, 0, sizeof(FILE_ROOT_GROUP));
- // Validate the locale block header
- if((pbRootPtr + sizeof(FILE_ROOT_GROUP_HEADER)) >= pbRootEnd)
- return NULL;
- memcpy(&RootGroup.Header, pbRootPtr, sizeof(FILE_ROOT_GROUP_HEADER));
- pbRootPtr = pbRootPtr + sizeof(FILE_ROOT_GROUP_HEADER);
+ if(dwRootVersion == 0 || dwRootVersion == 1)
+ {
+ // Validate the locale block header
+ if((pbRootPtr + sizeof(FILE_ROOT_GROUP_HEADER)) >= pbRootEnd)
+ return NULL;
+ memcpy(&RootGroup.Header, pbRootPtr, sizeof(FILE_ROOT_GROUP_HEADER));
+ pbRootPtr = pbRootPtr + sizeof(FILE_ROOT_GROUP_HEADER);
+ }
+ else if(dwRootVersion == 2)
+ {
+ PFILE_ROOT_GROUPHEADER_58221 pRootGroupHeader;
+
+ // Get pointer to the root group header
+ if((pbRootPtr + sizeof(FILE_ROOT_GROUPHEADER_58221)) >= pbRootEnd)
+ return NULL;
+ pRootGroupHeader = (PFILE_ROOT_GROUPHEADER_58221)pbRootPtr;
+ pbRootPtr = pbRootPtr + sizeof(FILE_ROOT_GROUPHEADER_58221);
+
+ // Convert to old ContentFlags for now...
+ RootGroup.Header.NumberOfFiles = pRootGroupHeader->NumberOfFiles;
+ RootGroup.Header.ContentFlags = pRootGroupHeader->ContentFlags1 | pRootGroupHeader->ContentFlags2 | (DWORD)(pRootGroupHeader->ContentFlags3 << 17);
+ RootGroup.Header.LocaleFlags = pRootGroupHeader->LocaleFlags;
+ }
// Validate the array of file data IDs
if((pbRootPtr + (sizeof(DWORD) * RootGroup.Header.NumberOfFiles)) >= pbRootEnd)
@@ -345,7 +414,8 @@ struct TRootHandler_WoW : public TFileTreeRoot
LPBYTE pbRootEnd,
DWORD dwLocaleMask,
BYTE bOverrideLowViolence,
- BYTE bAudioLocale)
+ BYTE bAudioLocale,
+ DWORD dwRootVersion)
{
FILE_ROOT_GROUP RootBlock;
@@ -360,7 +430,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
//OutputDebugStringA(szMessage);
// Validate the file locale block
- pbRootPtr = CaptureRootGroup(RootBlock, pbRootPtr, pbRootEnd);
+ pbRootPtr = CaptureRootGroup(RootBlock, pbRootPtr, pbRootEnd, dwRootVersion);
if(pbRootPtr == NULL)
return ERROR_BAD_FORMAT;
@@ -446,33 +516,34 @@ struct TRootHandler_WoW : public TFileTreeRoot
LPBYTE pbRootPtr,
LPBYTE pbRootEnd,
DWORD dwLocaleMask,
- BYTE bAudioLocale)
+ BYTE bAudioLocale,
+ DWORD dwRootVersion)
{
DWORD dwErrCode;
// Load the locale as-is
- dwErrCode = ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, dwLocaleMask, false, bAudioLocale);
+ dwErrCode = ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, dwLocaleMask, false, bAudioLocale, dwRootVersion);
if(dwErrCode != ERROR_SUCCESS)
return dwErrCode;
// If we wanted enGB, we also load enUS for the missing files
if(dwLocaleMask == CASC_LOCALE_ENGB)
- ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, CASC_LOCALE_ENUS, false, bAudioLocale);
+ ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, CASC_LOCALE_ENUS, false, bAudioLocale, dwRootVersion);
if(dwLocaleMask == CASC_LOCALE_PTPT)
- ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, CASC_LOCALE_PTBR, false, bAudioLocale);
+ ParseWowRootFile_Level2(hs, pbRootPtr, pbRootEnd, CASC_LOCALE_PTBR, false, bAudioLocale, dwRootVersion);
return ERROR_SUCCESS;
}
// WoW.exe: 004146C7 (BuildManifest::Load)
- DWORD Load(TCascStorage * hs, LPBYTE pbRootPtr, LPBYTE pbRootEnd, DWORD dwLocaleMask)
+ DWORD Load(TCascStorage * hs, LPBYTE pbRootPtr, LPBYTE pbRootEnd, DWORD dwLocaleMask, DWORD dwRootVersion)
{
DWORD dwErrCode;
- dwErrCode = ParseWowRootFile_Level1(hs, pbRootPtr, pbRootEnd, dwLocaleMask, 0);
+ dwErrCode = ParseWowRootFile_Level1(hs, pbRootPtr, pbRootEnd, dwLocaleMask, 0, dwRootVersion);
if(dwErrCode == ERROR_SUCCESS)
- dwErrCode = ParseWowRootFile_Level1(hs, pbRootPtr, pbRootEnd, dwLocaleMask, 1);
+ dwErrCode = ParseWowRootFile_Level1(hs, pbRootPtr, pbRootEnd, dwLocaleMask, 1, dwRootVersion);
#ifdef CASCLIB_DEBUG
// Dump the array of the file data IDs
@@ -507,6 +578,9 @@ struct TRootHandler_WoW : public TFileTreeRoot
break;
}
+ // Try to verify the file name by hash
+ VerifyAndLogFileName(szFileName, FileDataId);
+
//
// Several files were renamed around WoW build 50893 (10.1.7). Example:
//
@@ -543,10 +617,11 @@ struct TRootHandler_WoW : public TFileTreeRoot
break;
}
- // Calculate the hash of the file name
- FileNameHash = CalcFileNameHash(szFileName);
+ // Try to verify the file name by hash
+ VerifyAndLogFileName(szFileName, 0);
- // Try to find the file node by file name hash
+ // Calculate the hash of the file name and lookup in tree
+ FileNameHash = CalcFileNameHash(szFileName);
pFileNode = FileTree.Find(FileNameHash);
if(pFileNode != NULL && pFileNode->NameLength == 0)
{
@@ -562,6 +637,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
}
ROOT_FORMAT RootFormat; // Root file format
+ FILE * fp; // Handle to the dump file
DWORD FileCounterHashless; // Number of files for which we don't have hash. Meaningless for WoW before 8.2.0
DWORD FileCounter; // Counter of loaded files. Only used during loading of ROOT file
};
@@ -573,24 +649,34 @@ DWORD RootHandler_CreateWoW(TCascStorage * hs, CASC_BLOB & RootFile, DWORD dwLoc
{
TRootHandler_WoW * pRootHandler = NULL;
ROOT_FORMAT RootFormat = RootFormatWoW_v1;
+ LPCTSTR szDumpFile = NULL;
LPBYTE pbRootFile = RootFile.pbData;
LPBYTE pbRootEnd = RootFile.End();
LPBYTE pbRootPtr;
DWORD FileCounterHashless = 0;
+ DWORD RootVersion = 0;
DWORD dwErrCode = ERROR_BAD_FORMAT;
// Verify the root header
- if((pbRootPtr = TRootHandler_WoW::CaptureRootHeader(pbRootFile, pbRootEnd, &RootFormat, &FileCounterHashless)) == NULL)
+ if((pbRootPtr = TRootHandler_WoW::CaptureRootHeader(pbRootFile, pbRootEnd, &RootFormat, &FileCounterHashless, &RootVersion)) == NULL)
return ERROR_BAD_FORMAT;
- // Create the WOW handler
- pRootHandler = new TRootHandler_WoW(RootFormat, FileCounterHashless);
+#ifdef CASCLIB_WRITE_VERIFIED_FILENAMES
+ LPCTSTR szExtension = (RootFormat == RootFormatWoW_v1) ? _T("txt") : _T("csv");
+ TCHAR szBuffer[MAX_PATH];
+
+ CascStrPrintf(szBuffer, _countof(szBuffer), _T("\\listfile_wow_%u_%s.%s"), hs->dwBuildNumber, hs->szCodeName, szExtension);
+ szDumpFile = szBuffer;
+#endif
+
+ // Create the root handler
+ pRootHandler = new TRootHandler_WoW(RootFormat, FileCounterHashless, szDumpFile);
if(pRootHandler != NULL)
{
//fp = fopen("E:\\file-data-ids2.txt", "wt");
// Load the root directory. If load failed, we free the object
- dwErrCode = pRootHandler->Load(hs, pbRootPtr, pbRootEnd, dwLocaleMask);
+ dwErrCode = pRootHandler->Load(hs, pbRootPtr, pbRootEnd, dwLocaleMask, RootVersion);
if(dwErrCode != ERROR_SUCCESS)
{
delete pRootHandler;
diff --git a/dep/CascLib/src/CascStructs.h b/dep/CascLib/src/CascStructs.h
index 42478c324f0..68caa3404b8 100644
--- a/dep/CascLib/src/CascStructs.h
+++ b/dep/CascLib/src/CascStructs.h
@@ -17,7 +17,7 @@
#define CASC_INDEX_COUNT 0x10 // Number of index files
#define CASC_CKEY_SIZE 0x10 // Size of the content key
#define CASC_EKEY_SIZE 0x09 // Size of the encoded key
-#define CASC_MAX_DATA_FILES 0x100 // Maximum number of data files
+#define CASC_MAX_DATA_FILES 0x1000 // Maximum number of data files
//-----------------------------------------------------------------------------
// The index files structures
diff --git a/dep/CascLib/src/DllMain.def b/dep/CascLib/src/DllMain.def
index e8b4aebd5b4..432eb3345ca 100644
--- a/dep/CascLib/src/DllMain.def
+++ b/dep/CascLib/src/DllMain.def
@@ -31,6 +31,8 @@ EXPORTS
CascAddEncryptionKey
CascAddStringEncryptionKey
+ CascImportKeysFromString
+ CascImportKeysFromFile
CascFindEncryptionKey
CascGetNotFoundEncryptionKey
diff --git a/dep/CascLib/src/common/Common.cpp b/dep/CascLib/src/common/Common.cpp
index 6058bf28b75..a33099b3c6b 100644
--- a/dep/CascLib/src/common/Common.cpp
+++ b/dep/CascLib/src/common/Common.cpp
@@ -77,7 +77,9 @@ unsigned char IntToHexChar[] = "0123456789abcdef";
//-----------------------------------------------------------------------------
// GetCascError/SetCascError support for non-Windows platform
-static DWORD dwLastError = ERROR_SUCCESS;
+#ifndef CASCLIB_PLATFORM_WINDOWS
+static __thread DWORD dwLastError = ERROR_SUCCESS;
+#endif
DWORD GetCascError()
{
@@ -92,8 +94,9 @@ void SetCascError(DWORD dwErrCode)
{
#ifdef CASCLIB_PLATFORM_WINDOWS
SetLastError(dwErrCode);
-#endif
+#else
dwLastError = dwErrCode;
+#endif
}
//-----------------------------------------------------------------------------