aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src')
-rw-r--r--dep/CascLib/src/CascCommon.h12
-rw-r--r--dep/CascLib/src/CascDecrypt.cpp4
-rw-r--r--dep/CascLib/src/CascDumpData.cpp8
-rw-r--r--dep/CascLib/src/CascFiles.cpp38
-rw-r--r--dep/CascLib/src/CascFindFile.cpp2
-rw-r--r--dep/CascLib/src/CascLib.h14
-rw-r--r--dep/CascLib/src/CascOpenStorage.cpp28
-rw-r--r--dep/CascLib/src/CascPort.h4
-rw-r--r--dep/CascLib/src/CascReadFile.cpp65
-rw-r--r--dep/CascLib/src/CascRootFile_MNDX.cpp12
-rw-r--r--dep/CascLib/src/CascRootFile_TVFS.cpp21
-rw-r--r--dep/CascLib/src/CascRootFile_WoW.cpp38
-rw-r--r--dep/CascLib/src/DllMain.def1
-rw-r--r--dep/CascLib/src/common/Array.h4
-rw-r--r--dep/CascLib/src/common/ArraySparse.h2
-rw-r--r--dep/CascLib/src/common/FileTree.cpp174
-rw-r--r--dep/CascLib/src/common/FileTree.h4
-rw-r--r--dep/CascLib/src/common/ListFile.cpp8
-rw-r--r--dep/CascLib/src/common/Mime.cpp12
-rw-r--r--dep/CascLib/src/common/Mime.h4
-rw-r--r--dep/CascLib/src/common/RootHandler.cpp4
-rw-r--r--dep/CascLib/src/common/Sockets.cpp53
-rw-r--r--dep/CascLib/src/common/Sockets.h12
23 files changed, 317 insertions, 207 deletions
diff --git a/dep/CascLib/src/CascCommon.h b/dep/CascLib/src/CascCommon.h
index 19a6aa98444..b47674f1544 100644
--- a/dep/CascLib/src/CascCommon.h
+++ b/dep/CascLib/src/CascCommon.h
@@ -21,6 +21,10 @@
#include <zlib.h>
#endif
+#if defined(_DEBUG) && !defined(CASCLIB_NODEBUG)
+#define CASCLIB_DEBUG
+#endif
+
#include "CascPort.h"
#include "common/Common.h"
#include "common/Array.h"
@@ -48,7 +52,7 @@
//-----------------------------------------------------------------------------
// CascLib private defines
-#ifdef _DEBUG
+#if defined(CASCLIB_DEBUG) && defined(CASCLIB_DEV)
#define BREAK_ON_XKEY3(CKey, v0, v1, v2) if(CKey[0] == v0 && CKey[1] == v1 && CKey[2] == v2) { __debugbreak(); }
#define BREAKIF(condition) if(condition) { __debugbreak(); }
#else
@@ -60,7 +64,7 @@
#define CASC_MAGIC_FILE 0x454C494643534143 // 'CASCFILE'
#define CASC_MAGIC_FIND 0x444E494643534143 // 'CASCFIND'
-// The maximum size of an inline file
+// The maximum size of an online file
#define CASC_MAX_ONLINE_FILE_SIZE 0x40000000
//-----------------------------------------------------------------------------
@@ -456,7 +460,7 @@ DWORD GetFileSpanInfo(PCASC_CKEY_ENTRY pCKeyEntry, PULONGLONG PtrContentSize, PU
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);
DWORD CheckCascBuildFileDirs(CASC_BUILD_FILE & BuildFile, LPCTSTR szLocalPath);
-DWORD CheckOnlineStorage(PCASC_OPEN_STORAGE_ARGS pArgs, CASC_BUILD_FILE & BuildFile, DWORD dwFeatures);
+DWORD CheckOnlineStorage(PCASC_OPEN_STORAGE_ARGS pArgs, CASC_BUILD_FILE & BuildFile, bool bOnlineStorage);
DWORD CheckArchiveFilesDirectories(TCascStorage * hs);
DWORD CheckDataFilesDirectory(TCascStorage * hs);
DWORD LoadMainFile(TCascStorage * hs);
@@ -506,7 +510,7 @@ DWORD RootHandler_CreateInstall(TCascStorage * hs, CASC_BLOB & InstallFile);
//-----------------------------------------------------------------------------
// Dumpers (CascDumpData.cpp)
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
void CascDumpData(LPCSTR szFileName, const void * pvData, size_t cbData);
void CascDumpFile(HANDLE hFile, const char * szDumpFile = NULL);
void CascDumpStorage(HANDLE hStorage, const char * szDumpFile = NULL);
diff --git a/dep/CascLib/src/CascDecrypt.cpp b/dep/CascLib/src/CascDecrypt.cpp
index 2eba7a5ebff..0492a50a7c1 100644
--- a/dep/CascLib/src/CascDecrypt.cpp
+++ b/dep/CascLib/src/CascDecrypt.cpp
@@ -51,8 +51,8 @@ static CASC_ENCRYPTION_KEY StaticCascKeys[] =
// Battle.net app
{ 0x2C547F26A2613E01ULL, { 0x37, 0xC5, 0x0C, 0x10, 0x2D, 0x4C, 0x9E, 0x3A, 0x5A, 0xC0, 0x69, 0xF0, 0x72, 0xB1, 0x41, 0x7D } }, // Battle.net App Alpha 1.5.0
- // Starcraft
-// { 0xD0CAE11366CEEA83ULL, { 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x??, 0x?? } }, // 1.12.3.2609 (build 45364)
+ // StarCraft II
+ { 0xD0CAE11366CEEA83ULL, { 0x00, 0x41, 0x61, 0x07, 0x8E, 0x5A, 0x61, 0x20, 0x32, 0x1E, 0xA5, 0xFF, 0xE4, 0xDC, 0xD1, 0x26 } }, // Nova Covert Ops Expansion
// Warcraft III Reforged beta (build)
{ 0x6E4296823E7D561EULL, { 0xC0, 0xBF, 0xA2, 0x94, 0x3A, 0xC3, 0xE9, 0x22, 0x86, 0xE4, 0x44, 0x3E, 0xE3, 0x56, 0x0D, 0x65 } }, // 1.32.0.13369 Base content (Beta Week 0)
diff --git a/dep/CascLib/src/CascDumpData.cpp b/dep/CascLib/src/CascDumpData.cpp
index e29e93d093c..1c26efbeba1 100644
--- a/dep/CascLib/src/CascDumpData.cpp
+++ b/dep/CascLib/src/CascDumpData.cpp
@@ -12,7 +12,7 @@
#include "CascLib.h"
#include "CascCommon.h"
-#ifdef _DEBUG // The entire feature is only valid for debug purposes
+#ifdef CASCLIB_DEBUG // The entire feature is only valid for debug purposes
//-----------------------------------------------------------------------------
// Forward definitions
@@ -78,7 +78,7 @@ static void DumpKey(FILE * fp, const char * szInFormat, LPBYTE pbData, size_t cb
// If there will be more lines, then we clear the entire part until "%s"
if(szFormatSpec != NULL)
memset(szFormat, ' ', (szFormatSpec - szFormat));
-
+
// Move pointers
pbData += MD5_HASH_SIZE;
}
@@ -541,9 +541,9 @@ void CascDumpStorage(HANDLE hStorage, const char * szDumpFile)
}
}
-#else // _DEBUG
+#else // CASCLIB_DEBUG
// so linker won't mind this .cpp file is empty in non-DEBUG builds
void unused_symbol() { }
-#endif // _DEBUG
+#endif // CASCLIB_DEBUG
diff --git a/dep/CascLib/src/CascFiles.cpp b/dep/CascLib/src/CascFiles.cpp
index f2546e1befa..550b558f7da 100644
--- a/dep/CascLib/src/CascFiles.cpp
+++ b/dep/CascLib/src/CascFiles.cpp
@@ -1410,6 +1410,23 @@ static LPTSTR CheckForDirectory(LPCTSTR szParentFolder, LPCTSTR szSubFolder)
return szLocalPath;
}
+static LPTSTR CheckForDirectories(LPCTSTR szParentFolder, ...)
+{
+ LPCTSTR szSubDir;
+ va_list argList;
+ LPTSTR szFolder = NULL;
+
+ va_start(argList, szParentFolder);
+ while((szSubDir = va_arg(argList, LPCTSTR)) != NULL)
+ {
+ if((szFolder = CheckForDirectory(szParentFolder, szSubDir)) != NULL)
+ break;
+ }
+ va_end(argList);
+
+ return szFolder;
+}
+
//-----------------------------------------------------------------------------
// Public functions
@@ -1522,10 +1539,10 @@ DWORD CheckCascBuildFileDirs(CASC_BUILD_FILE & BuildFile, LPCTSTR szLocalPath)
return dwErrCode;
}
-DWORD CheckOnlineStorage(PCASC_OPEN_STORAGE_ARGS pArgs, CASC_BUILD_FILE & BuildFile, DWORD dwFeatures)
+DWORD CheckOnlineStorage(PCASC_OPEN_STORAGE_ARGS pArgs, CASC_BUILD_FILE & BuildFile, bool bOnlineStorage)
{
// If the online storage is required, we try to extract the product code
- if((dwFeatures & CASC_FEATURE_ONLINE) && (pArgs->szCodeName != NULL))
+ if((bOnlineStorage) && (pArgs->szCodeName != NULL))
{
CASC_PATH<TCHAR> FilePath(pArgs->szLocalPath, _T("versions"), NULL);
@@ -1554,31 +1571,22 @@ DWORD CheckArchiveFilesDirectories(TCascStorage * hs)
{
if((szDataPath = CheckForDirectory(hs->szRootPath, DataDirs[i])) != NULL)
{
- // If we found the data path, we also need to initialize the index path
-
// Check the config folder
if((szConfigPath = CheckForDirectory(szDataPath, _T("config"))) != NULL)
{
// First, check for more common "data" subdirectory
- if((szIndexPath = CheckForDirectory(szDataPath, _T("data"))) == NULL)
- {
- // Second, try the "darch" subdirectory (older builds of HOTS - Alpha)
- szIndexPath = CheckForDirectory(szDataPath, _T("darch"));
- }
-
- if(szIndexPath != NULL)
+ // Second, try the "darch" subdirectory (older builds of HOTS - Alpha)
+ if((szIndexPath = CheckForDirectories(szDataPath, _T("data"), _T("darch"), NULL)) != NULL)
{
hs->szDataPath = szDataPath;
hs->szConfigPath = szConfigPath;
hs->szIndexPath = szIndexPath;
return ERROR_SUCCESS;
}
+ CASC_FREE(szConfigPath);
}
+ CASC_FREE(szDataPath);
}
-
- CASC_FREE(szDataPath);
- CASC_FREE(szConfigPath);
- CASC_FREE(szIndexPath);
}
// One of the paths was not found
diff --git a/dep/CascLib/src/CascFindFile.cpp b/dep/CascLib/src/CascFindFile.cpp
index 76efa12ae43..6b7edbdbba4 100644
--- a/dep/CascLib/src/CascFindFile.cpp
+++ b/dep/CascLib/src/CascFindFile.cpp
@@ -38,7 +38,7 @@ static void SupplyFakeFileName(PCASC_FIND_DATA pFindData, PCASC_CKEY_ENTRY pCKey
// If there is a file data ID, create fake file name
if(pFindData->dwFileDataId != CASC_INVALID_ID)
{
- CascStrPrintf(pFindData->szFileName, _countof(pFindData->szFileName), "FILE%08X.dat", pFindData->dwFileDataId);
+ CascStrPrintf(pFindData->szFileName, _countof(pFindData->szFileName), CASC_FILEID_FORMAT, pFindData->dwFileDataId);
pFindData->NameType = CascNameDataId;
return;
}
diff --git a/dep/CascLib/src/CascLib.h b/dep/CascLib/src/CascLib.h
index b63869a49b4..01e9c314fd0 100644
--- a/dep/CascLib/src/CascLib.h
+++ b/dep/CascLib/src/CascLib.h
@@ -75,6 +75,7 @@ extern "C" {
//-----------------------------------------------------------------------------
// Defines
+// Version information
#define CASCLIB_VERSION 0x0300 // CascLib version - integral (3.0)
#define CASCLIB_VERSION_STRING "3.0" // CascLib version - string
@@ -110,11 +111,18 @@ extern "C" {
#define CASC_LOCALE_PTPT 0x00010000
// Content flags on WoW
+#define CASC_CFLAG_INSTALL 0x04
#define CASC_CFLAG_LOAD_ON_WINDOWS 0x08
#define CASC_CFLAG_LOAD_ON_MAC 0x10
+#define CASC_CFLAG_X86_32 0x20
+#define CASC_CFLAG_X86_64 0x40
#define CASC_CFLAG_LOW_VIOLENCE 0x80
#define CASC_CFLAG_DONT_LOAD 0x100
+#define CASC_CFLAG_UPDATE_PLUGIN 0x800
+#define CASC_CFLAG_ARM64 0x8000
+#define CASC_CFLAG_ENCRYPTED 0x8000000
#define CASC_CFLAG_NO_NAME_HASH 0x10000000
+#define CASC_CFLAG_UNCMN_RESOLUTION 0x20000000 // Uncommon resolution
#define CASC_CFLAG_BUNDLE 0x40000000
#define CASC_CFLAG_NO_COMPRESSION 0x80000000
@@ -153,6 +161,9 @@ extern "C" {
// Maximum length of encryption key
#define CASC_KEY_LENGTH 0x10
+// Default format string for the file ID
+#define CASC_FILEID_FORMAT "FILE%08X.dat"
+
//-----------------------------------------------------------------------------
// Structures
@@ -191,7 +202,7 @@ typedef enum _CASC_FILE_INFO_CLASS
typedef enum _CASC_NAME_TYPE
{
CascNameFull, // Fully qualified file name
- CascNameDataId, // Name created from file data id (FILE%08X.dat)
+ CascNameDataId, // Name created from file data id (CASC_FILEID_FORMAT)
CascNameCKey, // Name created as string representation of CKey
CascNameEKey // Name created as string representation of EKey
} CASC_NAME_TYPE, *PCASC_NAME_TYPE;
@@ -363,6 +374,7 @@ bool WINAPI CascCloseStorage(HANDLE hStorage);
bool WINAPI CascOpenFile(HANDLE hStorage, const void * pvFileName, DWORD dwLocaleFlags, DWORD dwOpenFlags, HANDLE * PtrFileHandle);
bool WINAPI CascOpenLocalFile(LPCTSTR szFileName, DWORD dwOpenFlags, HANDLE * PtrFileHandle);
bool WINAPI CascGetFileInfo(HANDLE hFile, CASC_FILE_INFO_CLASS InfoClass, void * pvFileInfo, size_t cbFileInfo, size_t * pcbLengthNeeded);
+bool WINAPI CascSetFileFlags(HANDLE hFile, DWORD dwOpenFlags);
bool WINAPI CascGetFileSize64(HANDLE hFile, PULONGLONG PtrFileSize);
bool WINAPI CascSetFilePointer64(HANDLE hFile, LONGLONG DistanceToMove, PULONGLONG PtrNewPos, DWORD dwMoveMethod);
bool WINAPI CascReadFile(HANDLE hFile, void * lpBuffer, DWORD dwToRead, PDWORD pdwRead);
diff --git a/dep/CascLib/src/CascOpenStorage.cpp b/dep/CascLib/src/CascOpenStorage.cpp
index 24afbc73e7b..16f0c28da48 100644
--- a/dep/CascLib/src/CascOpenStorage.cpp
+++ b/dep/CascLib/src/CascOpenStorage.cpp
@@ -29,7 +29,7 @@
#define CHECKED_KEY {0x00, 0x00, 0x0F, 0x84}
-#if defined(_DEBUG) && defined(CHECKED_KEY)
+#if defined(CASCLIB_DEBUG) && defined(CHECKED_KEY)
inline bool CheckForXKey(LPBYTE XKey)
{
@@ -117,7 +117,7 @@ TCascStorage::~TCascStorage()
// Free the blobs
FreeCascBlob(&CdnConfigKey);
FreeCascBlob(&CdnBuildKey);
-
+
FreeCascBlob(&ArchiveGroup);
FreeCascBlob(&ArchivesKey);
FreeCascBlob(&PatchArchivesKey);
@@ -423,8 +423,8 @@ static int LoadEncodingCKeyPage(TCascStorage * hs, CASC_ENCODING_HEADER & EnHead
if(pFileEntry->EKeyCount == 0)
break;
- // 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
+ // 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->CKey, 0x34, 0x82, 0x1f);
@@ -613,7 +613,7 @@ int CaptureDownloadTag(CASC_DOWNLOAD_HEADER & DlHeader, CASC_TAG_ENTRY1 & DlTag,
pbFilePtr++;
if(pbFilePtr >= pbFileEnd)
return ERROR_BAD_FORMAT;
-
+
// Save the length of the tag name
DlTag.NameLength = (pbFilePtr - pbSaveFilePtr);
pbFilePtr++;
@@ -630,7 +630,7 @@ int CaptureDownloadTag(CASC_DOWNLOAD_HEADER & DlHeader, CASC_TAG_ENTRY1 & DlTag,
// Get the bitmap length.
// If the bitmap is last in the list and it's shorter than declared, we make it shorter
DlTag.BitmapLength = GetTagBitmapLength(pbFilePtr, pbFileEnd, DlHeader.EntryCount);
-
+
// Get the entry length
DlTag.TagLength = (pbFilePtr - pbSaveFilePtr) + DlTag.BitmapLength;
return ERROR_SUCCESS;
@@ -769,7 +769,7 @@ static int LoadDownloadManifest(TCascStorage * hs)
if(dwErrCode == ERROR_SUCCESS)
{
// Parse the entire download manifest
- dwErrCode = LoadDownloadManifest(hs, DlHeader, DownloadFile.pbData, DownloadFile.pbData + DownloadFile.cbData);
+ dwErrCode = LoadDownloadManifest(hs, DlHeader, DownloadFile.pbData, DownloadFile.pbData + DownloadFile.cbData);
}
}
@@ -1122,6 +1122,7 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs, L
// Merge features
hs->dwFeatures |= (dwFeatures & (CASC_FEATURE_DATA_ARCHIVES | CASC_FEATURE_DATA_FILES | CASC_FEATURE_ONLINE));
hs->dwFeatures |= (pArgs->dwFlags & CASC_FEATURE_FORCE_DOWNLOAD);
+ hs->dwFeatures |= (BuildFileType == CascVersions) ? CASC_FEATURE_ONLINE : 0;
hs->BuildFileType = BuildFileType;
// Copy the name of the build file
@@ -1390,24 +1391,23 @@ bool WINAPI CascOpenStorageEx(LPCTSTR szParams, PCASC_OPEN_STORAGE_ARGS pArgs, b
if((hs = new TCascStorage()) != NULL)
{
CASC_BUILD_FILE BuildFile = {NULL};
- DWORD dwFeatures = bOnlineStorage ? CASC_FEATURE_ONLINE : 0;
-
+
// Check for one of the supported main files (.build.info, .build.db, versions)
if((dwErrCode = CheckCascBuildFileExact(BuildFile, pArgs->szLocalPath)) == ERROR_SUCCESS)
{
- dwErrCode = LoadCascStorage(hs, pArgs, BuildFile.szFullPath, BuildFile.BuildFileType, dwFeatures | CASC_FEATURE_DATA_ARCHIVES | CASC_FEATURE_DATA_FILES);
+ dwErrCode = LoadCascStorage(hs, pArgs, BuildFile.szFullPath, BuildFile.BuildFileType, CASC_FEATURE_DATA_ARCHIVES | CASC_FEATURE_DATA_FILES);
}
// Search the folder and upper folders for the build file
else if((dwErrCode = CheckCascBuildFileDirs(BuildFile, pArgs->szLocalPath)) == ERROR_SUCCESS)
{
- dwErrCode = LoadCascStorage(hs, pArgs, BuildFile.szFullPath, BuildFile.BuildFileType, dwFeatures | CASC_FEATURE_DATA_ARCHIVES | CASC_FEATURE_DATA_FILES);
+ dwErrCode = LoadCascStorage(hs, pArgs, BuildFile.szFullPath, BuildFile.BuildFileType, CASC_FEATURE_DATA_ARCHIVES | CASC_FEATURE_DATA_FILES);
}
// If the caller requested an online storage, we must have the code name
- else if((dwErrCode = CheckOnlineStorage(pArgs, BuildFile, dwFeatures)) == ERROR_SUCCESS)
+ else if((dwErrCode = CheckOnlineStorage(pArgs, BuildFile, bOnlineStorage)) == ERROR_SUCCESS)
{
- dwErrCode = LoadCascStorage(hs, pArgs, BuildFile.szFullPath, BuildFile.BuildFileType, dwFeatures | CASC_FEATURE_DATA_FILES);
+ dwErrCode = LoadCascStorage(hs, pArgs, BuildFile.szFullPath, BuildFile.BuildFileType, CASC_FEATURE_DATA_FILES);
}
}
}
@@ -1426,7 +1426,7 @@ bool WINAPI CascOpenStorageEx(LPCTSTR szParams, PCASC_OPEN_STORAGE_ARGS pArgs, b
}
//
-// Opens a local CASC storage
+// Opens a local CASC storage
//
// szParams: "local_path:code_name", like "C:\\Games\\World of Warcraft:wowt"
//
diff --git a/dep/CascLib/src/CascPort.h b/dep/CascLib/src/CascPort.h
index c8145a4512d..a6ee62885b4 100644
--- a/dep/CascLib/src/CascPort.h
+++ b/dep/CascLib/src/CascPort.h
@@ -13,7 +13,7 @@
#define __CASCPORT_H__
#ifndef __cplusplus
- #include <stdbool.h>
+ #include <stdbool.h>
#endif
//-----------------------------------------------------------------------------
@@ -30,6 +30,7 @@
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_NON_CONFORMING_SWPRINTFS
+ // Prevent duplicate symbols defined by Windows headers
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
@@ -46,7 +47,6 @@
#include <direct.h>
#include <malloc.h>
#include <windows.h>
- #include <ws2tcpip.h>
#include <strsafe.h>
#define CASCLIB_PLATFORM_LITTLE_ENDIAN
diff --git a/dep/CascLib/src/CascReadFile.cpp b/dep/CascLib/src/CascReadFile.cpp
index 35f91addf75..3fd173b9bde 100644
--- a/dep/CascLib/src/CascReadFile.cpp
+++ b/dep/CascLib/src/CascReadFile.cpp
@@ -116,7 +116,7 @@ static DWORD OpenDataStream(TCascFile * hf, PCASC_FILE_SPAN pFileSpan, PCASC_CKE
}
}
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
static unsigned int table_16C57A8[0x10] =
{
0x049396B8, 0x72A82A9B, 0xEE626CCA, 0x9917754F,
@@ -182,7 +182,7 @@ static DWORD ParseBlteHeader(PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEn
if(pEncodedHeader->EncodedSize != pCKeyEntry->EncodedSize)
return ERROR_BAD_FORMAT;
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
// Not really needed, it's here just for explanation of what the values mean
//assert(memcmp(pCKeyEntry->EKey, pEncodedHeader->EKey.Value, MD5_HASH_SIZE) == 0);
VerifyHeaderSpan(pEncodedHeader, HeaderOffset);
@@ -203,7 +203,7 @@ static DWORD ParseBlteHeader(PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEn
{
if(pBlteHeader->MustBe0F != 0x0F)
return ERROR_BAD_FORMAT;
-
+
// Verify the header size
FrameCount = ConvertBytesToInteger_3(pBlteHeader->FrameCount);
ExpectedHeaderSize = 0x0C + FrameCount * sizeof(BLTE_FRAME);
@@ -587,7 +587,7 @@ static DWORD DecodeFileFrame(
switch(pbEncoded[0])
{
case 'E': // Encrypted files
-
+
// The work buffer should not have been allocated by any step
assert(pbWorkBuffer == NULL && cbWorkBuffer == 0);
@@ -613,7 +613,7 @@ static DWORD DecodeFileFrame(
break;
case 'Z': // ZLIB compressed files
-
+
// If we decompressed less than expected, we simply fill the rest with zeros
// Example: INSTALL file from the TACT CASC storage
cbDecodedExpected = cbDecoded;
@@ -784,7 +784,7 @@ static DWORD ReadFile_WholeFile(TCascFile * hf, LPBYTE pbBuffer)
ULONGLONG ByteOffset = pFileSpan->ArchiveOffs + pFileSpan->HeaderSize;
DWORD EncodedSize = pCKeyEntry->EncodedSize - pFileSpan->HeaderSize;
- // Allocate the buffer for the entire encoded span
+ // Allocate the buffer for the entire encoded span
pbEncodedPtr = pbEncoded = CASC_ALLOC<BYTE>(EncodedSize);
if(pbEncoded == NULL)
{
@@ -1020,6 +1020,29 @@ bool WINAPI CascGetFileInfo(HANDLE hFile, CASC_FILE_INFO_CLASS InfoClass, void *
return (pbOutputValue != NULL);
}
+bool WINAPI CascSetFileFlags(HANDLE hFile, DWORD dwOpenFlags)
+{
+ TCascFile * hf;
+
+ // Validate the file handle
+ if((hf = TCascFile::IsValid(hFile)) == NULL)
+ {
+ SetCascError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // Currently, only CASC_OVERCOME_ENCRYPTED can be changed
+ if(dwOpenFlags & ~CASC_OVERCOME_ENCRYPTED)
+ {
+ SetCascError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Set "overcome encrypted" flag. Will apply on next CascReadFile
+ hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) != 0;
+ return true;
+}
+
//
// THE FILE SIZE PROBLEM
//
@@ -1031,7 +1054,7 @@ bool WINAPI CascGetFileInfo(HANDLE hFile, CASC_FILE_INFO_CLASS InfoClass, void *
// HotS(29049) ENCODING 0x0024BA45 - 0x0024b98a 0x0024BA45 n/a 0x0024BA45 n/a
// HotS(29049) ROOT 0x00193340 - 0x00193340 0x0010db65 0x00193340 0x0010db65 n/a
// HotS(29049) (other) 0x00001080 - 0x00001080 0x000008eb 0x00001080 0x000008eb 0x00001080
-//
+//
// WoW(18888) ENCODING 0x030d487b - 0x030dee79 0x030d487b n/a 0x030d487b n/a
// WoW(18888) ROOT 0x016a9800 - n/a 0x0131313d 0x016a9800 0x0131313d n/a
// WoW(18888) (other) 0x000007d0 - 0x000007d0 0x00000397 0x000007d0 0x00000397 n/a
@@ -1042,6 +1065,13 @@ bool WINAPI CascGetFileSize64(HANDLE hFile, PULONGLONG PtrFileSize)
TCascFile * hf;
DWORD dwErrCode;
+ // Validate the file pointer
+ if(PtrFileSize == NULL)
+ {
+ SetCascError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
// Validate the file handle
if((hf = TCascFile::IsValid(hFile)) == NULL)
{
@@ -1049,11 +1079,11 @@ bool WINAPI CascGetFileSize64(HANDLE hFile, PULONGLONG PtrFileSize)
return false;
}
- // Validate the file pointer
- if(PtrFileSize == NULL)
+ // If the content key is zeros, we treat the file as a file with size of 0
+ if(hf->ContentSize == 0)
{
- SetCascError(ERROR_INVALID_PARAMETER);
- return false;
+ PtrFileSize[0] = 0;
+ return true;
}
// ENCODING on older storages: Content size is not present in the BUILD file
@@ -1157,7 +1187,7 @@ DWORD WINAPI CascSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * PtrFilePosHi
{
ULONGLONG NewPos = 0;
LONGLONG DistanceToMove;
-
+
// Assemble the 64-bit distance to move
DistanceToMove = (PtrFilePosHigh != NULL) ? MAKE_OFFSET64(PtrFilePosHigh[0], lFilePos) : (LONGLONG)(LONG)lFilePos;
@@ -1196,6 +1226,13 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
return false;
}
+ // Check files with zero size
+ if(hf->ContentSize == 0)
+ {
+ PtrBytesRead[0] = 0;
+ return true;
+ }
+
// If we don't have file frames loaded, we need to do it now.
// Need to do it before file range check, as the file size may be unknown at this point
dwErrCode = EnsureFileSpanFramesLoaded(hf);
@@ -1242,7 +1279,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
{
// No caching at all. The entire file will be read directly to the user buffer
// Used for loading internal files, where we need to read the whole file
- case CascCacheNothing:
+ case CascCacheNothing:
dwBytesRead2 = ReadFile_NonCached(hf, pbBuffer, StartOffset, EndOffset);
break;
@@ -1268,7 +1305,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW
if(PtrBytesRead != NULL)
PtrBytesRead[0] = 0;
hf->FilePointer = SaveFilePointer;
-
+
// If 0 bytes were requested, it's actually a success
return (dwBytesToRead == 0);
}
diff --git a/dep/CascLib/src/CascRootFile_MNDX.cpp b/dep/CascLib/src/CascRootFile_MNDX.cpp
index 9b820c0d639..8075dce3a2b 100644
--- a/dep/CascLib/src/CascRootFile_MNDX.cpp
+++ b/dep/CascLib/src/CascRootFile_MNDX.cpp
@@ -660,7 +660,7 @@ class TBitEntryArray : public TGenericArray<DWORD>
#define INDEX_TO_GROUP(val) (val >> 9)
#define GROUP_TO_INDEX(grp) (grp << 9)
-// For each 0x200-th bit, this contains information about amount of "1" bits
+// For each 0x200-th bit, this contains information about amount of "1" bits
typedef struct _BASEVALS
{
DWORD BaseValue200; // Item value of every 0x200-th item
@@ -791,7 +791,7 @@ class TSparseArray
if(index & 0x20)
IntValue += GetNumberOfSetBits32(ItemBits[(index >> 0x05) - 1]);
- // 4) Count the bits in the current DWORD (masked by bit index mask)
+ // 4) Count the bits in the current DWORD (masked by bit index mask)
BitMask = (1 << (index & 0x1F)) - 1;
return IntValue + GetNumberOfSetBits32(ItemBits[index >> 0x05] & BitMask);
}
@@ -888,7 +888,7 @@ class TSparseArray
DWORD bitGroup;
DWORD edx = index;
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
//if(TotalItemCount > 0x200)
//{
// FILE * fp = fopen("e:\\Ladik\\Appdir\\CascLib\\doc\\mndx-sparse-array.txt", "wt");
@@ -1177,7 +1177,7 @@ class TSparseArray
return table_1BA1818[bitGroup + distFromBase] + itemIndex;
}
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
void Dump(FILE * fp)
{
size_t * ArrayNormal;
@@ -1868,7 +1868,7 @@ class TFileNameDatabase
// Get the hasn table item
pHashEntry = &HashTable[TableIndex & HashTableMask];
- //
+ //
if(TableIndex == pHashEntry->NextIndex)
{
// HOTS: 01957BB4
@@ -2467,7 +2467,7 @@ class TFileNameDatabase
TSparseArray CollisionTable; // Table of valid collisions, indexed by NodeIndex
TSparseArray FileNameIndexes; // Array of file name indexes
- TSparseArray CollisionHiBitsIndexes; // Table of indexes of high bits (above 8 bits) for collisions
+ TSparseArray CollisionHiBitsIndexes; // Table of indexes of high bits (above 8 bits) for collisions
// This pair of arrays serves for fast conversion from node index to FragmentOffset / FragmentChar
TGenericArray<BYTE> LoBitsTable; // Array of lower 8 bits of name fragment offset
diff --git a/dep/CascLib/src/CascRootFile_TVFS.cpp b/dep/CascLib/src/CascRootFile_TVFS.cpp
index 52408bf6660..abcac60c5c2 100644
--- a/dep/CascLib/src/CascRootFile_TVFS.cpp
+++ b/dep/CascLib/src/CascRootFile_TVFS.cpp
@@ -105,8 +105,8 @@ struct TVFS_DIRECTORY_HEADER
// In-memory layout of the path table entry
typedef struct _TVFS_PATH_TABLE_ENTRY
{
- LPBYTE pbNamePtr; // Pointer to the begin of the node name
- LPBYTE pbNameEnd; // Pointer to the end of the file name
+ char * m_pNamePtr; // Pointer to the begin of the node name
+ char * m_pNameEnd; // Pointer to the end of the file name
DWORD NodeFlags; // TVFS_PTE_XXX
DWORD NodeValue; // Node value
} TVFS_PATH_TABLE_ENTRY, *PTVFS_PATH_TABLE_ENTRY;
@@ -156,8 +156,8 @@ struct TRootHandler_TVFS : public TFileTreeRoot
PathBuffer.AppendChar('/');
// Append the name fragment, if any
- if(PathEntry.pbNameEnd > PathEntry.pbNamePtr)
- PathBuffer.AppendStringN((const char *)PathEntry.pbNamePtr, (PathEntry.pbNameEnd - PathEntry.pbNamePtr), false);
+ if(PathEntry.m_pNameEnd > PathEntry.m_pNamePtr)
+ PathBuffer.AppendStringN(PathEntry.m_pNamePtr, (PathEntry.m_pNameEnd - PathEntry.m_pNamePtr), false);
// Append the postfix separator, if needed
if(PathEntry.NodeFlags & TVFS_PTE_PATH_SEPARATOR_POST)
@@ -312,8 +312,8 @@ struct TRootHandler_TVFS : public TFileTreeRoot
LPBYTE CapturePathEntry(TVFS_PATH_TABLE_ENTRY & PathEntry, LPBYTE pbPathTablePtr, LPBYTE pbPathTableEnd)
{
// Reset the path entry structure
- PathEntry.pbNamePtr = pbPathTablePtr;
- PathEntry.pbNameEnd = pbPathTablePtr;
+ PathEntry.m_pNamePtr = (char *)(pbPathTablePtr);
+ PathEntry.m_pNameEnd = (char *)(pbPathTablePtr);
PathEntry.NodeFlags = 0;
PathEntry.NodeValue = 0;
@@ -332,8 +332,8 @@ struct TRootHandler_TVFS : public TFileTreeRoot
if((pbPathTablePtr + nLength) > pbPathTableEnd)
return NULL;
- PathEntry.pbNamePtr = pbPathTablePtr;
- PathEntry.pbNameEnd = pbPathTablePtr + nLength;
+ PathEntry.m_pNamePtr = (char *)(pbPathTablePtr);
+ PathEntry.m_pNameEnd = (char *)(pbPathTablePtr + nLength);
pbPathTablePtr += nLength;
}
@@ -536,6 +536,11 @@ struct TRootHandler_TVFS : public TFileTreeRoot
}
}
+ //BREAKIF(strcmp((const char *)PathBuffer, "Base") == 0);
+ //BREAKIF(strcmp((const char *)PathBuffer, "base") == 0);
+ //BREAKIF(strcmp((const char *)PathBuffer, "base:ComplexTypeDescriptorSizes.dat") == 0);
+ //BREAKIF(strcmp((const char *)PathBuffer, "DivideAndConquer.w3m:war3map.doo") == 0);
+
// We need to check whether this is another TVFS directory file
if(IsVfsSubDirectory(hs, DirHeader, SubHeader, SpanEntry.EKey, SpanEntry.ContentSize) == ERROR_SUCCESS)
{
diff --git a/dep/CascLib/src/CascRootFile_WoW.cpp b/dep/CascLib/src/CascRootFile_WoW.cpp
index 5b5375bcc7b..85942c432ba 100644
--- a/dep/CascLib/src/CascRootFile_WoW.cpp
+++ b/dep/CascLib/src/CascRootFile_WoW.cpp
@@ -79,6 +79,31 @@ typedef struct _FILE_ROOT_GROUP
} FILE_ROOT_GROUP, *PFILE_ROOT_GROUP;
//-----------------------------------------------------------------------------
+// Debug local stuff
+
+#if defined(_MSC_VER) && defined(CASCLIB_DEBUG)
+static FILE * fp = NULL;
+static bool bLogEntries = true;
+
+static void LogEntry(DWORD FileDataId, PCONTENT_KEY pCKey)
+{
+ if(fp && bLogEntries)
+ {
+ char szCKey[MD5_STRING_SIZE + 1];
+
+ if(FileDataId == 1260179)
+ {
+ bLogEntries = false;
+ __debugbreak();
+ }
+
+ StringFromBinary(pCKey->Value, MD5_HASH_SIZE, szCKey);
+ fprintf(fp, "File Data ID: %u, CKey = %s\n", FileDataId, szCKey);
+ }
+}
+#endif
+
+//-----------------------------------------------------------------------------
// TRootHandler_WoW interface / implementation
#define FTREE_FLAGS_WOW (FTREE_FLAG_USE_DATA_ID | FTREE_FLAG_USE_LOCALE_FLAGS | FTREE_FLAG_USE_CONTENT_FLAGS)
@@ -89,7 +114,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
TRootHandler_WoW(ROOT_FORMAT RFormat, DWORD HashlessFileCount) : TFileTreeRoot(FTREE_FLAGS_WOW)
{
- // Turn off the "we know file names" bit
+ // Turn off the "we know file names" bit
FileCounterHashless = HashlessFileCount;
FileCounter = 0;
RootFormat = RFormat;
@@ -155,7 +180,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
return pbRootPtr + (sizeof(FILE_ROOT_ENTRY) * RootGroup.Header.NumberOfFiles);
case RootFormatWoW82:
-
+
// Verify the position of array of CONTENT_KEY
if((pbRootPtr + (sizeof(CONTENT_KEY) * RootGroup.Header.NumberOfFiles)) > pbRootEnd)
return NULL;
@@ -229,7 +254,6 @@ struct TRootHandler_WoW : public TFileTreeRoot
{
// Set the file data ID
FileDataId = FileDataId + RootGroup.FileDataIds[i];
- //printf("File Data ID: %u\n", FileDataId);
// Find the item in the central storage. Insert it to the tree
if((pCKeyEntry = FindCKeyEntry_CKey(hs, pCKey->Value)) != NULL)
@@ -357,7 +381,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
*/
DWORD ParseWowRootFile_Level1(
- TCascStorage * hs,
+ TCascStorage * hs,
LPBYTE pbRootPtr,
LPBYTE pbRootEnd,
DWORD dwLocaleMask,
@@ -389,7 +413,7 @@ struct TRootHandler_WoW : public TFileTreeRoot
if(dwErrCode == ERROR_SUCCESS)
dwErrCode = ParseWowRootFile_Level1(hs, pbRootPtr, pbRootEnd, dwLocaleMask, 1);
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
// Dump the array of the file data IDs
//FileTree.DumpFileDataIds("e:\\file-data-ids.bin");
#endif
@@ -494,6 +518,8 @@ DWORD RootHandler_CreateWoW(TCascStorage * hs, CASC_BLOB & RootFile, DWORD dwLoc
pRootHandler = new TRootHandler_WoW(RootFormat, FileCounterHashless);
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, pbRootFile, pbRootEnd, dwLocaleMask);
if(dwErrCode != ERROR_SUCCESS)
@@ -501,6 +527,8 @@ DWORD RootHandler_CreateWoW(TCascStorage * hs, CASC_BLOB & RootFile, DWORD dwLoc
delete pRootHandler;
pRootHandler = NULL;
}
+
+ //fclose(fp);
}
// Assign the root directory (or NULL) and return error
diff --git a/dep/CascLib/src/DllMain.def b/dep/CascLib/src/DllMain.def
index ddda8af921b..e8b4aebd5b4 100644
--- a/dep/CascLib/src/DllMain.def
+++ b/dep/CascLib/src/DllMain.def
@@ -17,6 +17,7 @@ EXPORTS
CascOpenFile
CascOpenLocalFile
CascGetFileInfo
+ CascSetFileFlags
CascGetFileSize
CascGetFileSize64
CascSetFilePointer
diff --git a/dep/CascLib/src/common/Array.h b/dep/CascLib/src/common/Array.h
index b46f257e8a4..56cdf073a33 100644
--- a/dep/CascLib/src/common/Array.h
+++ b/dep/CascLib/src/common/Array.h
@@ -104,7 +104,7 @@ class CASC_ARRAY
// Make sure we have array large enough
if(!EnlargeArray(ItemIndex + 1, true))
return NULL;
-
+
// Get the items range
pbLastItem = m_pItemArray + (m_ItemCount * m_ItemSize);
pbNewItem = m_pItemArray + (ItemIndex * m_ItemSize);
@@ -170,7 +170,7 @@ class CASC_ARRAY
m_ItemCountMax = m_ItemCount = m_ItemSize = 0;
}
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
size_t BytesAllocated()
{
return m_ItemCountMax * m_ItemSize;
diff --git a/dep/CascLib/src/common/ArraySparse.h b/dep/CascLib/src/common/ArraySparse.h
index eb7d478cf3e..b239a0a9e93 100644
--- a/dep/CascLib/src/common/ArraySparse.h
+++ b/dep/CascLib/src/common/ArraySparse.h
@@ -229,7 +229,7 @@ class CASC_SPARSE_ARRAY
return (m_pLevel0 != NULL);
}
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
size_t BytesAllocated()
{
return m_LevelsAllocated * sizeof(CASC_ARRAY_256);
diff --git a/dep/CascLib/src/common/FileTree.cpp b/dep/CascLib/src/common/FileTree.cpp
index fa21863c5e9..453034c057d 100644
--- a/dep/CascLib/src/common/FileTree.cpp
+++ b/dep/CascLib/src/common/FileTree.cpp
@@ -13,7 +13,22 @@
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
-// Local defines
+// Local arrays
+
+static BYTE PathSeparators[256] =
+{
+/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+/* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
+
+ // Filled by zeros up to 256 bytes
+};
+
+//-----------------------------------------------------------------------------
+// Local functions
#define START_ITEM_COUNT 0x4000
@@ -31,6 +46,28 @@ inline void SET_NODE_INT32(void * node, size_t offset, DWORD value)
PtrValue[0] = value;
}
+#ifdef CASCLIB_DEV
+//static DWORD dwFileCount = 0;
+//
+//static void WatchFileNode(PCASC_FILE_NODE pFileNode, const char * szFileName, bool bNewNodeInserted)
+//{
+// const char * szSuffix = bNewNodeInserted ? "NEW" : "EXISTING";
+// const char * szFormat = "FileNode %p: CKey: %s, NameHash: %I64x (\"%s\") - %s\n";
+// char szBuffer[MD5_STRING_SIZE + 1];
+//
+// // Selected nodes only
+// if(dwFileCount < 10 && !_strnicmp(szFileName, "base", 4))
+// {
+// printf(szFormat, pFileNode,
+// StringFromBinary(pFileNode->pCKeyEntry->CKey, MD5_HASH_SIZE, szBuffer),
+// pFileNode->FileNameHash,
+// szFileName,
+// szSuffix);
+// dwFileCount++;
+// }
+//}
+#endif
+
//-----------------------------------------------------------------------------
// Protected functions
@@ -91,7 +128,7 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertNew()
}
// Insert the node to the map of FileNameHash -> CASC_FILE_NODE
-bool CASC_FILE_TREE::InsertToHashTable(PCASC_FILE_NODE pFileNode)
+bool CASC_FILE_TREE::InsertToNameMap(PCASC_FILE_NODE pFileNode)
{
bool bResult = false;
@@ -189,7 +226,7 @@ bool CASC_FILE_TREE::RebuildNameMaps()
{
// Insert it to the map "FileNameHash -> CASC_FILE_NODE"
if(pFileNode->FileNameHash != 0)
- InsertToHashTable(pFileNode);
+ InsertToNameMap(pFileNode);
// Insert it to the array "FileDataId -> CASC_FILE_NODE"
if(FileDataIds.IsInitialized())
@@ -288,13 +325,12 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertByName(PCASC_CKEY_ENTRY pCKeyEntry, const
{
PCASC_FILE_NODE pFileNode;
ULONGLONG FileNameHash;
+ //bool bNewNodeInserted = false;
// Sanity checks
assert(szFileName != NULL && szFileName[0] != 0);
assert(pCKeyEntry != NULL);
- //BREAK_ON_XKEY3(pCKeyEntry->EKey, 0x00, 0x00, 0x0F);
-
// Calculate the file name hash
FileNameHash = CalcFileNameHash(szFileName);
@@ -313,7 +349,7 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertByName(PCASC_CKEY_ENTRY pCKeyEntry, const
SetExtras(pFileNode, FileDataId, LocaleFlags, ContentFlags);
// Insert the file node to the hash map
- InsertToHashTable(pFileNode);
+ InsertToNameMap(pFileNode);
// Also make sure that it's in the file data id table, if the table is initialized
InsertToIdTable(pFileNode);
@@ -323,11 +359,16 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertByName(PCASC_CKEY_ENTRY pCKeyEntry, const
// If we created a new node, we need to increment the reference count
assert(pCKeyEntry->RefCount != 0xFFFF);
+ //bNewNodeInserted = true;
pCKeyEntry->RefCount++;
FileNodes++;
}
}
+#ifdef CASCLIB_DEV
+ //WatchFileNode(pFileNode, szFileName, bNewNodeInserted);
+#endif
+
return pFileNode;
}
@@ -349,7 +390,7 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertByHash(PCASC_CKEY_ENTRY pCKeyEntry, ULONGL
pFileNode->FileNameHash = FileNameHash;
// Insert the file node to the hash map
- InsertToHashTable(pFileNode);
+ InsertToNameMap(pFileNode);
}
return pFileNode;
@@ -543,13 +584,21 @@ bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szF
{
char chOneChar = szFileName[i];
- // Is there a path separator?
- // Note: Warcraft III paths may contain "mount points".
- // Example: "frFR-War3Local.mpq:Maps/FrozenThrone/Campaign/NightElfX06Interlude.w3x:war3map.j"
- if(chOneChar == '\\' || chOneChar == '/' || chOneChar == ':')
+ // Is there a path separator, such as '\\' or '/'?
+ // Also support TVFS "mount points", like "DivideAndConquer.w3m:war3map.doo"
+ if(PathSeparators[chOneChar])
{
+ size_t nHashLength = i;
+
+ // If there is a reparse point mark (':'), we need to include it as part of the name
+ if(PathSeparators[chOneChar] == 0x02)
+ {
+ PathBuffer.AppendChar(chOneChar);
+ nHashLength++;
+ }
+
// Calculate hash of the file name up to the end of the node name
- FileNameHash = CalcNormNameHash(PathBuffer, i);
+ FileNameHash = CalcNormNameHash(PathBuffer, nHashLength);
// If the entry is not there yet, create new one
if((pFolderNode = Find(FileNameHash)) == NULL)
@@ -559,95 +608,36 @@ bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szF
if(pFolderNode == NULL)
return false;
- // Populate the file entry
+ // Fill-in flags, name hash and parent
+ pFolderNode->Flags |= (chOneChar == ':') ? (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT) : CFN_FLAG_FOLDER;
pFolderNode->FileNameHash = FileNameHash;
pFolderNode->Parent = Parent;
- pFolderNode->Flags |= (chOneChar == ':') ? (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT) : CFN_FLAG_FOLDER;
FolderNodes++;
// Set the node sub name to the node
SetNodePlainName(pFolderNode, szNodeBegin, szFileName + i);
// Insert the entry to the name map
- InsertToHashTable(pFolderNode);
+ InsertToNameMap(pFolderNode);
}
- // Move the parent to the current node
- Parent = (DWORD)NodeTable.IndexOf(pFolderNode);
-
- // Move the begin of the node after the separator
- szNodeBegin = szFileName + i + 1;
- }
-
- // Copy the next character, even if it was slash/backslash before
- PathBuffer.AppendChar(AsciiToUpperTable_BkSlash[chOneChar]);
- }
-
- // If anything left, this is gonna be our node name
- if(szNodeBegin < szFileName + i)
- {
- // We need to reset the file node pointer, as the file node table might have changed
- pFileNode = (PCASC_FILE_NODE)NodeTable.ItemAt(nFileNode);
-
- // Write the plain file name to the node
- SetNodePlainName(pFileNode, szNodeBegin, szFileName + i);
- pFileNode->Parent = Parent;
-
- // Also insert the node to the hash table so CascOpenFile can find it
- if(pFileNode->FileNameHash == 0)
- {
- pFileNode->FileNameHash = CalcNormNameHash(PathBuffer, i);
- InsertToHashTable(pFileNode);
- }
- }
- return true;
-}
-/*
-bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szFileName)
-{
- ULONGLONG FileNameHash = 0;
- PCASC_FILE_NODE pFolderNode = NULL;
- LPCSTR szNodeBegin = szFileName;
- char szPathBuffer[MAX_PATH+1];
- size_t nFileNode = NodeTable.IndexOf(pFileNode);
- size_t i;
- DWORD Parent = 0;
-
- // Sanity checks
- assert(szFileName != NULL && szFileName[0] != 0);
-
- // Traverse the entire path. For each subfolder, we insert an appropriate fake entry
- for(i = 0; szFileName[i] != 0; i++)
- {
- char chOneChar = szFileName[i];
-
- // Is there a path separator?
- // Note: Warcraft III paths may contain "mount points".
- // Example: "frFR-War3Local.mpq:Maps/FrozenThrone/Campaign/NightElfX06Interlude.w3x:war3map.j"
- if(chOneChar == '\\' || chOneChar == '/' || chOneChar == ':')
- {
- // Calculate hash of the file name up to the end of the node name
- FileNameHash = CalcNormNameHash(szPathBuffer, i);
-
- // If the entry is not there yet, create new one
- if((pFolderNode = Find(FileNameHash)) == NULL)
+ // In case we're in the middle a mount point construction (called by CASC_FILE_TREE::InsertByName()),
+ // then we can get into situation where the call to Find() found the newly constructed item.
+ // In that case, we just set the name and bail out
+ else if(pFolderNode == pFileNode)
{
- // Insert new entry to the tree
- pFolderNode = InsertNew();
- if(pFolderNode == NULL)
- return false;
+ // The item must be a mount point, with name hash already set.
+ assert(pFolderNode->FileNameHash == FileNameHash);
+ assert(szFileName[i + 1] == 0);
- // Populate the file entry
- pFolderNode->FileNameHash = FileNameHash;
+ // Fill-in the flags and parent
+ pFolderNode->Flags |= (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT);
pFolderNode->Parent = Parent;
- pFolderNode->Flags |= (chOneChar == ':') ? (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT) : CFN_FLAG_FOLDER;
FolderNodes++;
// Set the node sub name to the node
SetNodePlainName(pFolderNode, szNodeBegin, szFileName + i);
-
- // Insert the entry to the name map
- InsertToHashTable(pFolderNode);
+ return true;
}
// Move the parent to the current node
@@ -655,10 +645,16 @@ bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szF
// Move the begin of the node after the separator
szNodeBegin = szFileName + i + 1;
+
+ // If the separator character was already appended, skip the rest of the loop
+ if(PathSeparators[chOneChar] == 0x02)
+ {
+ continue;
+ }
}
- // Copy the next character, even if it was slash/backslash before
- szPathBuffer[i] = AsciiToUpperTable_BkSlash[chOneChar];
+ // Append the character, if not appended yet
+ PathBuffer.AppendChar(AsciiToUpperTable_BkSlash[chOneChar]);
}
// If anything left, this is gonna be our node name
@@ -674,13 +670,13 @@ bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szF
// Also insert the node to the hash table so CascOpenFile can find it
if(pFileNode->FileNameHash == 0)
{
- pFileNode->FileNameHash = CalcNormNameHash(szPathBuffer, i);
- InsertToHashTable(pFileNode);
+ pFileNode->FileNameHash = CalcNormNameHash(PathBuffer, i);
+ InsertToNameMap(pFileNode);
}
}
return true;
}
-*/
+
size_t CASC_FILE_TREE::GetMaxFileIndex()
{
if(FileDataIds.IsInitialized())
diff --git a/dep/CascLib/src/common/FileTree.h b/dep/CascLib/src/common/FileTree.h
index 69a2c15c496..0e178c769bb 100644
--- a/dep/CascLib/src/common/FileTree.h
+++ b/dep/CascLib/src/common/FileTree.h
@@ -82,7 +82,7 @@ class CASC_FILE_TREE
// Retrieve the maximum FileDataId ever inserted
DWORD GetNextFileDataId();
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
void DumpFileDataIds(const char * szFileName)
{
FileDataIds.Dump(szFileName);
@@ -93,7 +93,7 @@ class CASC_FILE_TREE
PCASC_FILE_NODE InsertNew(PCASC_CKEY_ENTRY pCKeyEntry);
PCASC_FILE_NODE InsertNew();
- bool InsertToHashTable(PCASC_FILE_NODE pFileNode);
+ bool InsertToNameMap(PCASC_FILE_NODE pFileNode);
bool InsertToIdTable(PCASC_FILE_NODE pFileNode);
bool SetNodePlainName(PCASC_FILE_NODE pFileNode, const char * szPlainName, const char * szPlainNameEnd);
diff --git a/dep/CascLib/src/common/ListFile.cpp b/dep/CascLib/src/common/ListFile.cpp
index 4545ada62e9..05ac48c4cbd 100644
--- a/dep/CascLib/src/common/ListFile.cpp
+++ b/dep/CascLib/src/common/ListFile.cpp
@@ -62,14 +62,16 @@ static char * ListFile_SkipSpaces(PLISTFILE_CACHE pCache)
static void ListFile_CheckFormat(PLISTFILE_CACHE pCache)
{
- // Only if the listfile is greatger than 2 MB
- if((pCache->pEnd - pCache->pBegin) > 0x100000)
+ const size_t nSizeLimit = 0x20;
+
+ // Only if the listfile is greater than 2 MB
+ if((pCache->pEnd - pCache->pBegin) > nSizeLimit)
{
char * szPtr = pCache->pBegin;
size_t nDigitCount = 0;
// Calculate the amount of digits
- while(nDigitCount <= 20 && '0' <= szPtr[nDigitCount] && szPtr[nDigitCount] <= '9')
+ while(nDigitCount <= nSizeLimit && '0' <= szPtr[nDigitCount] && szPtr[nDigitCount] <= '9')
nDigitCount++;
// There must be a semicolon after
diff --git a/dep/CascLib/src/common/Mime.cpp b/dep/CascLib/src/common/Mime.cpp
index 5aa7401ff24..d3d975ff00e 100644
--- a/dep/CascLib/src/common/Mime.cpp
+++ b/dep/CascLib/src/common/Mime.cpp
@@ -331,7 +331,7 @@ DWORD CASC_MIME_ELEMENT::Load(char * mime_data_begin, char * mime_data_end, cons
// Otherwise, we decode the data to the end of the document
if(boundary_ptr != NULL)
{
- // Find the end of the current data by the boundary. It is 2 characters before the next boundary
+ // Find the end of the current data by the boundary. It is 2 characters before the next boundary
content.end = strstr(content.ptr, boundary_ptr);
if(content.end == NULL)
return ERROR_BAD_FORMAT;
@@ -362,7 +362,7 @@ DWORD CASC_MIME_ELEMENT::Load(char * mime_data_begin, char * mime_data_end, cons
case MimeEncodingBase64:
dwErrCode = DecodeBase64(content.ptr, content.end, data);
break;
-
+
default:
dwErrCode = ERROR_NOT_SUPPORTED;
assert(false);
@@ -379,7 +379,7 @@ DWORD CASC_MIME_ELEMENT::Load(char * mime_data_begin, char * mime_data_end, cons
return dwErrCode;
}
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
#define MAX_LEVEL 0x10
void CASC_MIME_ELEMENT::Print(size_t nLevel, size_t nIndex)
{
@@ -473,7 +473,7 @@ bool CASC_MIME_ELEMENT::ExtractBoundary(const char * line)
{
// Set begin of the boundary
begin = begin + 10;
-
+
// Is there also end?
if((end = strchr(begin, '\"')) != NULL)
{
@@ -647,7 +647,7 @@ DWORD CASC_MIME::Load(char * data, CASC_MIME_RESPONSE & MimeResponse)
return ERROR_BAD_FORMAT;
// Debug: dump the MIME data to file
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
//CascDumpData("E:\\mime_raw_data.txt", data, MimeResponse.response_length);
#endif
@@ -667,7 +667,7 @@ DWORD CASC_MIME::Load(char * data, CASC_MIME_RESPONSE & MimeResponse)
return root.Load(data, data + MimeResponse.response_length);
}
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
void CASC_MIME::Print()
{
root.Print(0, 0);
diff --git a/dep/CascLib/src/common/Mime.h b/dep/CascLib/src/common/Mime.h
index 9142c33bfd3..af204352263 100644
--- a/dep/CascLib/src/common/Mime.h
+++ b/dep/CascLib/src/common/Mime.h
@@ -92,7 +92,7 @@ class CASC_MIME_ELEMENT
CASC_MIME_ELEMENT * GetChild() { return folder.pChild; }
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
void Print(size_t nLevel, size_t nIndex);
#endif
@@ -127,7 +127,7 @@ class CASC_MIME
DWORD Load(char * data, CASC_MIME_RESPONSE & MimeResponse);
-#ifdef _DEBUG
+#ifdef CASCLIB_DEBUG
void Print();
#endif
diff --git a/dep/CascLib/src/common/RootHandler.cpp b/dep/CascLib/src/common/RootHandler.cpp
index 95fa106e1bd..227eaff6b96 100644
--- a/dep/CascLib/src/common/RootHandler.cpp
+++ b/dep/CascLib/src/common/RootHandler.cpp
@@ -83,8 +83,8 @@ PCASC_CKEY_ENTRY TFileTreeRoot::Search(TCascSearch * pSearch, PCASC_FIND_DATA pF
pFileNode = FileTree.PathAt(pFindData->szFileName, MAX_PATH, pSearch->nFileIndex++);
if(pFileNode != NULL)
{
- // Ignore folders and mount points
- if(!(pFileNode->Flags & CFN_FLAG_FOLDER))
+ // Ignore folders, but report mount points. These can and should be able to open and read
+ if((pFileNode->Flags & (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT)) != CFN_FLAG_FOLDER)
{
// Check the wildcard
if(CascCheckWildCard(pFindData->szFileName, pSearch->szMask))
diff --git a/dep/CascLib/src/common/Sockets.cpp b/dep/CascLib/src/common/Sockets.cpp
index bb490505b15..8eb9680d448 100644
--- a/dep/CascLib/src/common/Sockets.cpp
+++ b/dep/CascLib/src/common/Sockets.cpp
@@ -13,14 +13,35 @@
#include "../CascLib.h"
#include "../CascCommon.h"
+#ifdef CASCLIB_PLATFORM_WINDOWS
+#include <ws2tcpip.h>
+#endif
+
//-----------------------------------------------------------------------------
// Local variables
#define BUFFER_INITIAL_SIZE 0x8000
+#ifndef INVALID_SOCKET
+#define INVALID_SOCKET (SOCKET)(-1) // Not defined in Linux
+#endif
+
CASC_SOCKET_CACHE SocketCache;
//-----------------------------------------------------------------------------
+// Conversion functions
+
+static SOCKET inline HandleToSocket(HANDLE sock)
+{
+ return (SOCKET)(intptr_t)(sock);
+}
+
+static HANDLE inline SocketToHandle(SOCKET sock)
+{
+ return (HANDLE)(intptr_t)(sock);
+}
+
+//-----------------------------------------------------------------------------
// CASC_SOCKET functions
// Guarantees that there is zero terminator after the response
@@ -42,10 +63,10 @@ char * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, CA
// Send the request to the remote host. On Linux, this call may send signal(SIGPIPE),
// we need to prevend that by using the MSG_NOSIGNAL flag. On Windows, it fails normally.
- while(send(sock, request, (int)request_length, MSG_NOSIGNAL) == SOCKET_ERROR)
+ while(send(HandleToSocket(sock), request, (int)request_length, MSG_NOSIGNAL) == SOCKET_ERROR)
{
// If the connection was closed by the remote host, we try to reconnect
- if(ReconnectAfterShutdown(sock, remoteItem) == INVALID_SOCKET)
+ if(ReconnectAfterShutdown(sock, remoteItem) == SocketToHandle(INVALID_SOCKET))
{
SetCascError(ERROR_NETWORK_NOT_AVAILABLE);
CascUnlock(Lock);
@@ -74,7 +95,7 @@ char * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, CA
// Receive the next part of the response, up to buffer size
// Return value 0 means "connection closed", -1 means an error
- bytes_received = recv(sock, server_response + total_received, (int)(buffer_length - total_received), 0);
+ bytes_received = recv(HandleToSocket(sock), server_response + total_received, (int)(buffer_length - total_received), 0);
if(bytes_received <= 0)
{
MimeResponse.ParseResponse(server_response, total_received, true);
@@ -192,28 +213,28 @@ DWORD CASC_SOCKET::GetAddrInfoWrapper(const char * hostName, unsigned portNum, P
}
}
-SOCKET CASC_SOCKET::CreateAndConnect(addrinfo * remoteItem)
+HANDLE CASC_SOCKET::CreateAndConnect(PADDRINFO remoteItem)
{
SOCKET sock;
// Create new socket
- // On error, returns returns INVALID_SOCKET (-1) on Windows, -1 on Linux
+ // On error, returns returns INVALID_SOCKET (0 on Windows, -1 on Linux)
if((sock = socket(remoteItem->ai_family, remoteItem->ai_socktype, remoteItem->ai_protocol)) > 0)
{
// Connect to the remote host
// On error, returns SOCKET_ERROR (-1) on Windows, -1 on Linux
if(connect(sock, remoteItem->ai_addr, (int)remoteItem->ai_addrlen) == 0)
- return sock;
+ return SocketToHandle(sock);
- // Failed. Close the socket and return 0
+ // Failed. Close the socket and return INVALID_SOCKET
closesocket(sock);
sock = INVALID_SOCKET;
}
- return sock;
+ return SocketToHandle(sock);
}
-SOCKET CASC_SOCKET::ReconnectAfterShutdown(SOCKET & sock, addrinfo * remoteItem)
+HANDLE CASC_SOCKET::ReconnectAfterShutdown(HANDLE & sock, PADDRINFO remoteItem)
{
// Retrieve the error code related to previous socket operation
switch(GetSockError())
@@ -222,8 +243,8 @@ SOCKET CASC_SOCKET::ReconnectAfterShutdown(SOCKET & sock, addrinfo * remoteItem)
case WSAECONNRESET: // Windows
{
// Close the old socket
- if(sock != INVALID_SOCKET)
- closesocket(sock);
+ if(sock != SocketToHandle(INVALID_SOCKET))
+ closesocket(HandleToSocket(sock));
// Attempt to reconnect
sock = CreateAndConnect(remoteItem);
@@ -232,10 +253,10 @@ SOCKET CASC_SOCKET::ReconnectAfterShutdown(SOCKET & sock, addrinfo * remoteItem)
}
// Another problem
- return INVALID_SOCKET;
+ return SocketToHandle(INVALID_SOCKET);
}
-PCASC_SOCKET CASC_SOCKET::New(addrinfo * remoteList, addrinfo * remoteItem, const char * hostName, unsigned portNum, SOCKET sock)
+PCASC_SOCKET CASC_SOCKET::New(PADDRINFO remoteList, PADDRINFO remoteItem, const char * hostName, unsigned portNum, HANDLE sock)
{
PCASC_SOCKET pSocket;
size_t length = strlen(hostName);
@@ -268,7 +289,7 @@ PCASC_SOCKET CASC_SOCKET::Connect(const char * hostName, unsigned portNum)
addrinfo * remoteList;
addrinfo * remoteItem;
addrinfo hints = {0};
- SOCKET sock;
+ HANDLE sock;
int nErrCode;
// Retrieve the information about the remote host
@@ -293,7 +314,7 @@ PCASC_SOCKET CASC_SOCKET::Connect(const char * hostName, unsigned portNum)
}
// Close the socket
- closesocket(sock);
+ closesocket(HandleToSocket(sock));
}
}
@@ -316,7 +337,7 @@ void CASC_SOCKET::Delete()
// Close the socket, if any
if(sock != 0)
- closesocket(sock);
+ closesocket(HandleToSocket(sock));
sock = 0;
// Free the lock
diff --git a/dep/CascLib/src/common/Sockets.h b/dep/CascLib/src/common/Sockets.h
index c821748802b..917be387234 100644
--- a/dep/CascLib/src/common/Sockets.h
+++ b/dep/CascLib/src/common/Sockets.h
@@ -14,10 +14,6 @@
//-----------------------------------------------------------------------------
// Defines
-#ifndef INVALID_SOCKET
-#define INVALID_SOCKET (SOCKET)(-1)
-#endif
-
#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif
@@ -57,9 +53,9 @@ class CASC_SOCKET
// Constructor and destructor
static int GetSockError();
static DWORD GetAddrInfoWrapper(const char * hostName, unsigned portNum, PADDRINFO hints, PADDRINFO * ppResult);
- static SOCKET CreateAndConnect(addrinfo * remoteItem);
- static SOCKET ReconnectAfterShutdown(SOCKET & sock, addrinfo * remoteItem);
- static PCASC_SOCKET New(addrinfo * remoteList, addrinfo * remoteItem, const char * hostName, unsigned portNum, SOCKET sock);
+ static HANDLE CreateAndConnect(PADDRINFO remoteItem);
+ static HANDLE ReconnectAfterShutdown(HANDLE & sock, PADDRINFO remoteItem);
+ static PCASC_SOCKET New(PADDRINFO remoteList, PADDRINFO remoteItem, const char * hostName, unsigned portNum, HANDLE sock);
static PCASC_SOCKET Connect(const char * hostName, unsigned portNum);
// Frees all resources and deletes the socket
@@ -76,7 +72,7 @@ class CASC_SOCKET
PADDRINFO remoteList; // List of the remote host informations
PADDRINFO remoteItem; // The particular host picked during the last connection attempt
CASC_LOCK Lock; // Lock for single threaded access
- SOCKET sock; // Opened and connected socket
+ HANDLE sock; // Opened and connected socket
DWORD dwRefCount; // Number of references
DWORD portNum; // Port number
char hostName[1]; // Buffer for storing remote host (variable length)