diff options
author | Shauren <shauren.trinity@gmail.com> | 2025-02-28 17:41:28 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2025-02-28 17:41:28 +0100 |
commit | 464d8e39e083a2f3a73f2c33a7b20036406541c8 (patch) | |
tree | 56fc8960ebf3fa92d1029f1a80bdda3ff766d6d5 /dep | |
parent | 438d0c3089aaf48352e493ab0a007ef6ef15a276 (diff) |
Dep/CascLib: Update to ladislav-zezula/CascLib@07ab5f37ad282cc101d5c17793c550a0a6d4637f
Diffstat (limited to 'dep')
-rw-r--r-- | dep/CascLib/src/CascCommon.h | 24 | ||||
-rw-r--r-- | dep/CascLib/src/CascFiles.cpp | 76 | ||||
-rw-r--r-- | dep/CascLib/src/CascIndexFiles.cpp | 8 | ||||
-rw-r--r-- | dep/CascLib/src/CascLib.h | 17 | ||||
-rw-r--r-- | dep/CascLib/src/CascOpenStorage.cpp | 27 | ||||
-rw-r--r-- | dep/CascLib/src/CascPort.h | 5 | ||||
-rw-r--r-- | dep/CascLib/src/CascReadFile.cpp | 3 | ||||
-rw-r--r-- | dep/CascLib/src/CascRootFile_OW.cpp | 10 | ||||
-rw-r--r-- | dep/CascLib/src/CascRootFile_TVFS.cpp | 2 | ||||
-rw-r--r-- | dep/CascLib/src/CascRootFile_WoW.cpp | 152 | ||||
-rw-r--r-- | dep/CascLib/src/CascStructs.h | 2 | ||||
-rw-r--r-- | dep/CascLib/src/DllMain.def | 2 | ||||
-rw-r--r-- | dep/CascLib/src/common/Common.cpp | 7 | ||||
-rw-r--r-- | dep/PackageList.txt | 2 |
14 files changed, 237 insertions, 100 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 } //----------------------------------------------------------------------------- diff --git a/dep/PackageList.txt b/dep/PackageList.txt index ecb19b5b6f8..1f0ee92d392 100644 --- a/dep/PackageList.txt +++ b/dep/PackageList.txt @@ -63,7 +63,7 @@ catch2 CascLib (An open-source implementation of library for reading CASC storage from Blizzard games since 2014) https://github.com/ladislav-zezula/CascLib - Version: 5c60050770767f2e606f6fec0c35beb8b9b00c60 + Version: 07ab5f37ad282cc101d5c17793c550a0a6d4637f rapidjson (A fast JSON parser/generator for C++ with both SAX/DOM style API http://rapidjson.org/) https://github.com/Tencent/rapidjson |