Dep/CascLib: Update to ladislav-zezula/CascLib@a27d2b3b9c
Closes #29102 Closes #29132
This commit is contained in:
@@ -296,7 +296,7 @@ struct TCascStorage
|
||||
LPTSTR szCdnPath; // Remote CDN sub path for the product
|
||||
LPSTR szRegion; // Product region. Only when "versions" is used as storage root file
|
||||
LPSTR szBuildKey; // Product build key, aka MD5 of the build file
|
||||
DWORD dwDefaultLocale; // Default locale, read from ".build.info"
|
||||
DWORD dwDefaultLocale; // Mask of installed localles
|
||||
DWORD dwBuildNumber; // Product build number
|
||||
DWORD dwRefCount; // Number of references
|
||||
DWORD dwFeatures; // List of CASC features. See CASC_FEATURE_XXX
|
||||
|
||||
@@ -274,9 +274,8 @@ static DWORD GetLocaleValue(LPCSTR szTag)
|
||||
case 0x64654445: return CASC_LOCALE_DEDE;
|
||||
case 0x72755255: return CASC_LOCALE_RURU;
|
||||
case 0x69744954: return CASC_LOCALE_ITIT;
|
||||
default: return CASC_LOCALE_NONE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool CheckConfigFileVariable(
|
||||
@@ -579,29 +578,41 @@ static DWORD GetDefaultCdnPath(TCascStorage * hs, const CASC_CSV_COLUMN & Column
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static DWORD GetDefaultLocaleMask(TCascStorage * hs, const CASC_CSV_COLUMN & Column)
|
||||
static DWORD GetDefaultLocaleByRegion(LPCSTR szRegion)
|
||||
{
|
||||
#define CASC_REGION_INT(hi, lo) (((DWORD)(hi) << 0x08) | lo)
|
||||
|
||||
// Setup the default locale
|
||||
switch(CASC_REGION_INT(szRegion[0], szRegion[1]))
|
||||
{
|
||||
case CASC_REGION_INT('u', 's'): return CASC_LOCALE_ENUS;
|
||||
case CASC_REGION_INT('e', 'u'): return CASC_LOCALE_ENGB;
|
||||
case CASC_REGION_INT('c', 'n'): return CASC_LOCALE_ZHCN;
|
||||
case CASC_REGION_INT('k', 'r'): return CASC_LOCALE_KOKR;
|
||||
case CASC_REGION_INT('t', 'w'): return CASC_LOCALE_ZHTW;
|
||||
// case CASC_REGION_INT('s', 'g'): return CASC_LOCALE_????;
|
||||
default: return CASC_LOCALE_ENUS;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD GetDefaultLocaleMask(const CASC_CSV_COLUMN & Column)
|
||||
{
|
||||
LPCSTR szTagEnd = Column.szValue + Column.nLength - 4;
|
||||
LPCSTR szTagPtr = Column.szValue;
|
||||
LPCSTR szTagPtr;
|
||||
DWORD dwLocaleValue;
|
||||
DWORD dwLocaleMask = 0;
|
||||
|
||||
while(szTagPtr < szTagEnd)
|
||||
// Go through the whole tag string
|
||||
for(szTagPtr = Column.szValue; szTagPtr <= szTagEnd; szTagPtr++)
|
||||
{
|
||||
DWORD dwLocaleValue = GetLocaleValue(szTagPtr);
|
||||
|
||||
if(dwLocaleValue != 0)
|
||||
// Try to recognize the 4-char locale code
|
||||
if((dwLocaleValue = GetLocaleValue(szTagPtr)) != CASC_LOCALE_NONE)
|
||||
{
|
||||
dwLocaleMask = dwLocaleMask | GetLocaleValue(szTagPtr);
|
||||
szTagPtr += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
szTagPtr++;
|
||||
dwLocaleMask |= dwLocaleValue;
|
||||
szTagPtr += 3; // Will be moved by 1 more at the end of the loop
|
||||
}
|
||||
}
|
||||
|
||||
hs->dwDefaultLocale = dwLocaleMask;
|
||||
return ERROR_SUCCESS;
|
||||
return dwLocaleMask;
|
||||
}
|
||||
|
||||
static DWORD ParseFile_BuildInfo(TCascStorage * hs, CASC_CSV & Csv)
|
||||
@@ -703,7 +714,7 @@ static DWORD ParseFile_BuildInfo(TCascStorage * hs, CASC_CSV & Csv)
|
||||
return dwErrCode;
|
||||
|
||||
// If we found tags, we can extract language build from it
|
||||
GetDefaultLocaleMask(hs, Csv[nSelected]["Tags!STRING:0"]);
|
||||
hs->dwDefaultLocale = GetDefaultLocaleMask(Csv[nSelected]["Tags!STRING:0"]);
|
||||
|
||||
// Get the CDN servers and hosts
|
||||
if(hs->dwFeatures & CASC_FEATURE_ONLINE)
|
||||
@@ -734,6 +745,9 @@ static DWORD ParseRegionLine_Versions(TCascStorage * hs, CASC_CSV & Csv, size_t
|
||||
if(hs->szRegion == NULL)
|
||||
hs->szRegion = CascNewStr(Csv[nLine]["Region!STRING:0"].szValue);
|
||||
|
||||
// Get the default locale mask based on the region
|
||||
hs->dwDefaultLocale = GetDefaultLocaleByRegion(hs->szRegion);
|
||||
|
||||
// Extract the CDN build key
|
||||
dwErrCode = LoadQueryKey(Csv[nLine]["BuildConfig!HEX:16"], hs->CdnBuildKey);
|
||||
if(dwErrCode != ERROR_SUCCESS)
|
||||
@@ -783,6 +797,9 @@ static DWORD ParseFile_BuildDb(TCascStorage * hs, CASC_CSV & Csv)
|
||||
if(dwErrCode != ERROR_SUCCESS)
|
||||
return dwErrCode;
|
||||
|
||||
// Extract tags
|
||||
hs->dwDefaultLocale = GetDefaultLocaleMask(Csv[CSV_ZERO][2]);
|
||||
|
||||
// Verify all variables
|
||||
return (hs->CdnBuildKey.pbData != NULL && hs->CdnConfigKey.pbData != NULL) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;
|
||||
}
|
||||
|
||||
@@ -164,6 +164,9 @@ extern "C" {
|
||||
// Default format string for the file ID
|
||||
#define CASC_FILEID_FORMAT "FILE%08X.dat"
|
||||
|
||||
// Separator char for path-product delimiter
|
||||
#define CASC_PARAM_SEPARATOR '*'
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Structures
|
||||
|
||||
|
||||
@@ -1072,7 +1072,7 @@ static bool GetStoragePathProduct(TCascStorage * hs, void * pvStorageInfo, size_
|
||||
// Append the product code name, if any
|
||||
if(hs->szCodeName != NULL)
|
||||
{
|
||||
*szBuffer++ = _T(':');
|
||||
*szBuffer++ = _T(CASC_PARAM_SEPARATOR);
|
||||
CascStrCopy(szBuffer, (szBufferEnd - szBuffer), hs->szCodeName);
|
||||
szBuffer += _tcslen(hs->szCodeName);
|
||||
}
|
||||
@@ -1080,7 +1080,7 @@ static bool GetStoragePathProduct(TCascStorage * hs, void * pvStorageInfo, size_
|
||||
// Append the product region, if any
|
||||
if(hs->szRegion != NULL)
|
||||
{
|
||||
*szBuffer++ = _T(':');
|
||||
*szBuffer++ = _T(CASC_PARAM_SEPARATOR);
|
||||
CascStrCopy(szBuffer, (szBufferEnd - szBuffer), hs->szRegion);
|
||||
}
|
||||
}
|
||||
@@ -1209,10 +1209,7 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs, L
|
||||
// Failing to select storage on them will lead to the first-in-order file in the list being loaded.
|
||||
// Example: WoW build 32144, file: DBFilesClient\Achievement.db2, file data ID: 1260179
|
||||
// Locales: koKR frFR deDE zhCN esES zhTW enUS&enGB esMX ruRU itIT ptBT&ptPT (in order of appearance in the build manifest)
|
||||
if(dwLocaleMask == 0)
|
||||
{
|
||||
dwLocaleMask = hs->dwDefaultLocale;
|
||||
}
|
||||
dwLocaleMask = (dwLocaleMask != 0) ? dwLocaleMask : hs->dwDefaultLocale;
|
||||
|
||||
// Continue loading the manifest
|
||||
dwErrCode = LoadBuildManifest(hs, dwLocaleMask);
|
||||
@@ -1250,10 +1247,10 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs, L
|
||||
return dwErrCode;
|
||||
}
|
||||
|
||||
// Check for URL pattern. Note that the string may be terminated by ':' instead of '\0'
|
||||
// Check for URL pattern. Note that the string may be terminated by CASC_PARAM_SEPARATOR instead of '\0'
|
||||
static bool IsUrl(LPCTSTR szString)
|
||||
{
|
||||
while(szString[0] != 0 && szString[0] != '*')
|
||||
while(szString[0] != 0 && szString[0] != CASC_PARAM_SEPARATOR)
|
||||
{
|
||||
// Check for "://"
|
||||
if(!_tcsncmp(szString, _T("://"), 3))
|
||||
@@ -1276,7 +1273,7 @@ static LPTSTR GetNextParam(LPTSTR szParamsPtr, bool bMustBeUrl = false)
|
||||
if(szParamsPtr != NULL)
|
||||
{
|
||||
// Find the separator ("*") or end of string
|
||||
if((szSeparator = _tcschr(szParamsPtr, _T('*'))) != NULL)
|
||||
if((szSeparator = _tcschr(szParamsPtr, _T(CASC_PARAM_SEPARATOR))) != NULL)
|
||||
{
|
||||
// Check for URL pattern, if needed
|
||||
if(bMustBeUrl && IsUrl(szSeparator + 1) == false)
|
||||
|
||||
@@ -173,13 +173,16 @@ static DWORD ParseBlteHeader(PCASC_FILE_SPAN pFileSpan, PCASC_CKEY_ENTRY pCKeyEn
|
||||
CASCLIB_UNUSED(HeaderOffset);
|
||||
|
||||
// On files within storage segments ("data.###"), there is BLTE_ENCODED_HEADER
|
||||
// On local files, there is just PBLTE_HEADER
|
||||
// On local files, there is just BLTE_HEADER
|
||||
if(ConvertBytesToInteger_4_LE(pBlteHeader->Signature) != BLTE_HEADER_SIGNATURE)
|
||||
{
|
||||
// There must be at least some bytes
|
||||
if(cbEncodedBuffer < FIELD_OFFSET(BLTE_ENCODED_HEADER, MustBe0F))
|
||||
return ERROR_BAD_FORMAT;
|
||||
if(pEncodedHeader->EncodedSize != pCKeyEntry->EncodedSize)
|
||||
|
||||
// Note that some newer WoW builds have the entire encoded part zeroed
|
||||
// Tested on WoW retail 50401, file DBFilesClient\\LoreTextPublic.db2
|
||||
if(pEncodedHeader->EncodedSize != 0 && pEncodedHeader->EncodedSize != pCKeyEntry->EncodedSize)
|
||||
return ERROR_BAD_FORMAT;
|
||||
|
||||
#ifdef CASCLIB_DEBUG
|
||||
@@ -1039,7 +1042,7 @@ bool WINAPI CascSetFileFlags(HANDLE hFile, DWORD dwOpenFlags)
|
||||
}
|
||||
|
||||
// Set "overcome encrypted" flag. Will apply on next CascReadFile
|
||||
hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) != 0;
|
||||
hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) ? true : false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,31 +78,6 @@ 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
|
||||
|
||||
@@ -123,11 +98,11 @@ struct TRootHandler_WoW : public TFileTreeRoot
|
||||
switch(RootFormat)
|
||||
{
|
||||
case RootFormatWoW6x:
|
||||
dwFeatures |= CASC_FEATURE_ROOT_CKEY | CASC_FEATURE_FNAME_HASHES | CASC_FEATURE_FILE_DATA_IDS | CASC_FEATURE_LOCALE_FLAGS | CASC_FEATURE_CONTENT_FLAGS;
|
||||
dwFeatures |= CASC_FEATURE_ROOT_CKEY | CASC_FEATURE_LOCALE_FLAGS | CASC_FEATURE_CONTENT_FLAGS | CASC_FEATURE_FNAME_HASHES;
|
||||
break;
|
||||
|
||||
case RootFormatWoW82:
|
||||
dwFeatures |= CASC_FEATURE_ROOT_CKEY | CASC_FEATURE_FNAME_HASHES_OPTIONAL | CASC_FEATURE_FILE_DATA_IDS | CASC_FEATURE_LOCALE_FLAGS | CASC_FEATURE_CONTENT_FLAGS;
|
||||
dwFeatures |= CASC_FEATURE_ROOT_CKEY | CASC_FEATURE_LOCALE_FLAGS | CASC_FEATURE_CONTENT_FLAGS | CASC_FEATURE_FILE_DATA_IDS | CASC_FEATURE_FNAME_HASHES_OPTIONAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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: ebd79e8fd43279343c543a27fce620f6b1b53cb9
|
||||
Version: a27d2b3b9ccb326768e57b4cc7c49d15a0da9e0c
|
||||
|
||||
rapidjson (A fast JSON parser/generator for C++ with both SAX/DOM style API http://rapidjson.org/)
|
||||
https://github.com/Tencent/rapidjson
|
||||
|
||||
Reference in New Issue
Block a user