aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/CascOpenStorage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src/CascOpenStorage.cpp')
-rw-r--r--dep/CascLib/src/CascOpenStorage.cpp268
1 files changed, 112 insertions, 156 deletions
diff --git a/dep/CascLib/src/CascOpenStorage.cpp b/dep/CascLib/src/CascOpenStorage.cpp
index 1231ef58bfe..24afbc73e7b 100644
--- a/dep/CascLib/src/CascOpenStorage.cpp
+++ b/dep/CascLib/src/CascOpenStorage.cpp
@@ -61,7 +61,8 @@ TCascStorage::TCascStorage()
pRootHandler = NULL;
dwRefCount = 1;
- szRootPath = szDataPath = szIndexPath = szBuildFile = szCdnServers = szCdnPath = szCdnHostUrl = szCodeName = NULL;
+ szRootPath = szDataPath = szIndexPath = szFilesPath = szConfigPath = szMainFile = NULL;
+ szCdnHostUrl = szCdnServers = szCdnPath = szCodeName = NULL;
szIndexFormat = NULL;
szRegion = NULL;
szBuildKey = NULL;
@@ -100,14 +101,16 @@ TCascStorage::~TCascStorage()
CascFreeLock(StorageLock);
// Free the file paths
- CASC_FREE(szDataPath);
CASC_FREE(szRootPath);
- CASC_FREE(szBuildFile);
+ CASC_FREE(szDataPath);
CASC_FREE(szIndexPath);
+ CASC_FREE(szFilesPath);
+ CASC_FREE(szConfigPath);
+ CASC_FREE(szMainFile);
+ CASC_FREE(szCdnHostUrl);
CASC_FREE(szCdnServers);
CASC_FREE(szCdnPath);
CASC_FREE(szCodeName);
- CASC_FREE(szCdnHostUrl);
CASC_FREE(szRegion);
CASC_FREE(szBuildKey);
@@ -166,20 +169,6 @@ void * ProbeOutputBuffer(void * pvBuffer, size_t cbLength, size_t cbMinLength, s
return pvBuffer;
}
-static LPTSTR CheckForIndexDirectory(TCascStorage * hs, LPCTSTR szSubDir)
-{
- TCHAR szIndexPath[MAX_PATH];
-
- // Combine the index path
- CombinePath(szIndexPath, _countof(szIndexPath), hs->szDataPath, szSubDir, NULL);
-
- // Check whether the path exists
- if(!DirectoryExists(szIndexPath))
- return NULL;
-
- return CascNewStr(szIndexPath);
-}
-
// Inserts an entry from the text build file
static PCASC_CKEY_ENTRY InsertCKeyEntry(TCascStorage * hs, CASC_CKEY_ENTRY & CKeyEntry)
{
@@ -451,8 +440,7 @@ static int LoadEncodingCKeyPage(TCascStorage * hs, CASC_ENCODING_HEADER & EnHead
static int LoadEncodingManifest(TCascStorage * hs)
{
CASC_CKEY_ENTRY & CKeyEntry = hs->EncodingCKey;
- LPBYTE pbEncodingFile;
- DWORD cbEncodingFile = 0;
+ CASC_BLOB EncodingFile;
DWORD dwErrCode = ERROR_SUCCESS;
// Inform the user about what we are doing
@@ -465,24 +453,25 @@ static int LoadEncodingManifest(TCascStorage * hs)
InsertCKeyEntry(hs, CKeyEntry);
// Load the entire encoding file to memory
- pbEncodingFile = LoadInternalFileToMemory(hs, &hs->EncodingCKey, &cbEncodingFile);
- if(pbEncodingFile != NULL && cbEncodingFile != 0)
+ dwErrCode = LoadInternalFileToMemory(hs, &hs->EncodingCKey, EncodingFile);
+ if(dwErrCode == ERROR_SUCCESS && EncodingFile.cbData != 0)
{
CASC_ENCODING_HEADER EnHeader;
// Capture the header of the ENCODING file
- dwErrCode = CaptureEncodingHeader(EnHeader, pbEncodingFile, cbEncodingFile);
+ dwErrCode = CaptureEncodingHeader(EnHeader, EncodingFile.pbData, EncodingFile.cbData);
if(dwErrCode == ERROR_SUCCESS)
{
// Get the CKey page header and the first page
- PFILE_CKEY_PAGE pPageHeader = (PFILE_CKEY_PAGE)(pbEncodingFile + sizeof(FILE_ENCODING_HEADER) + EnHeader.ESpecBlockSize);
+ PFILE_CKEY_PAGE pPageHeader = (PFILE_CKEY_PAGE)(EncodingFile.pbData + sizeof(FILE_ENCODING_HEADER) + EnHeader.ESpecBlockSize);
+ LPBYTE pbEncodingEnd = EncodingFile.pbData + EncodingFile.cbData;
LPBYTE pbCKeyPage = (LPBYTE)(pPageHeader + EnHeader.CKeyPageCount);
// Go through all CKey pages and verify them
for(DWORD i = 0; i < EnHeader.CKeyPageCount; i++)
{
// Check if there is enough space in the buffer
- if((pbCKeyPage + EnHeader.CKeyPageSize) > (pbEncodingFile + cbEncodingFile))
+ if((pbCKeyPage + EnHeader.CKeyPageSize) > pbEncodingEnd)
{
dwErrCode = ERROR_FILE_CORRUPT;
break;
@@ -519,9 +508,6 @@ static int LoadEncodingManifest(TCascStorage * hs)
{
dwErrCode = CopyBuildFileItemsToCKeyArray(hs);
}
-
- // Free the loaded ENCODING file
- CASC_FREE(pbEncodingFile);
}
else
{
@@ -735,15 +721,18 @@ static int LoadDownloadManifest(TCascStorage * hs, CASC_DOWNLOAD_HEADER & DlHead
// Insert the entry to the central CKey table
if((pCKeyEntry = InsertCKeyEntry(hs, DlEntry)) != NULL)
{
- // Supply the tag bits
- for(size_t j = 0; j < TagItemCount; j++)
+ if(TagArray != NULL)
{
- // Set the bit in the entry, if the tag for it is present
- if((BitMaskOffset < TagArray[j].BitmapLength) && (TagArray[j].Bitmap[BitMaskOffset] & BitMaskBit))
- pCKeyEntry->TagBitMask |= TagBit;
+ // Supply the tag bits
+ for(size_t j = 0; j < TagItemCount; j++)
+ {
+ // Set the bit in the entry, if the tag for it is present
+ if((BitMaskOffset < TagArray[j].BitmapLength) && (TagArray[j].Bitmap[BitMaskOffset] & BitMaskBit))
+ pCKeyEntry->TagBitMask |= TagBit;
- // Move to the next bit
- TagBit <<= 1;
+ // Move to the next bit
+ TagBit <<= 1;
+ }
}
}
@@ -762,8 +751,7 @@ static int LoadDownloadManifest(TCascStorage * hs, CASC_DOWNLOAD_HEADER & DlHead
static int LoadDownloadManifest(TCascStorage * hs)
{
PCASC_CKEY_ENTRY pCKeyEntry = FindCKeyEntry_CKey(hs, hs->DownloadCKey.CKey);
- LPBYTE pbDownloadFile = NULL;
- DWORD cbDownloadFile = 0;
+ CASC_BLOB DownloadFile;
DWORD dwErrCode = ERROR_SUCCESS;
// Inform the user about what we are doing
@@ -771,21 +759,18 @@ static int LoadDownloadManifest(TCascStorage * hs)
return ERROR_CANCELLED;
// Load the entire DOWNLOAD file to memory
- pbDownloadFile = LoadInternalFileToMemory(hs, pCKeyEntry, &cbDownloadFile);
- if(pbDownloadFile != NULL && cbDownloadFile != 0)
+ dwErrCode = LoadInternalFileToMemory(hs, pCKeyEntry, DownloadFile);
+ if(dwErrCode == ERROR_SUCCESS && DownloadFile.cbData != 0)
{
CASC_DOWNLOAD_HEADER DlHeader;
// Capture the header of the DOWNLOAD file
- dwErrCode = CaptureDownloadHeader(DlHeader, pbDownloadFile, cbDownloadFile);
+ dwErrCode = CaptureDownloadHeader(DlHeader, DownloadFile.pbData, DownloadFile.cbData);
if(dwErrCode == ERROR_SUCCESS)
{
// Parse the entire download manifest
- dwErrCode = LoadDownloadManifest(hs, DlHeader, pbDownloadFile, pbDownloadFile + cbDownloadFile);
+ dwErrCode = LoadDownloadManifest(hs, DlHeader, DownloadFile.pbData, DownloadFile.pbData + DownloadFile.cbData);
}
-
- // Free the loaded manifest
- CASC_FREE(pbDownloadFile);
}
// If the DOWNLOAD manifest is not present, we won't abort the downloading process.
@@ -799,8 +784,7 @@ static int LoadDownloadManifest(TCascStorage * hs)
static int LoadInstallManifest(TCascStorage * hs)
{
PCASC_CKEY_ENTRY pCKeyEntry = FindCKeyEntry_CKey(hs, hs->InstallCKey.CKey);
- LPBYTE pbInstallFile = NULL;
- DWORD cbInstallFile = 0;
+ CASC_BLOB InstallFile;
DWORD dwErrCode = ERROR_SUCCESS;
// Inform the user about what we are doing
@@ -808,11 +792,10 @@ static int LoadInstallManifest(TCascStorage * hs)
return ERROR_CANCELLED;
// Load the entire DOWNLOAD file to memory
- pbInstallFile = LoadInternalFileToMemory(hs, pCKeyEntry, &cbInstallFile);
- if(pbInstallFile != NULL && cbInstallFile != 0)
+ dwErrCode = LoadInternalFileToMemory(hs, pCKeyEntry, InstallFile);
+ if(dwErrCode == ERROR_SUCCESS && InstallFile.cbData != 0)
{
- dwErrCode = RootHandler_CreateInstall(hs, pbInstallFile, cbInstallFile);
- CASC_FREE(pbInstallFile);
+ dwErrCode = RootHandler_CreateInstall(hs, InstallFile);
}
else
{
@@ -864,9 +847,8 @@ static int LoadBuildManifest(TCascStorage * hs, DWORD dwLocaleMask)
{
PCASC_CKEY_ENTRY pCKeyEntry = &hs->RootFile;
TRootHandler * pOldRootHandler = NULL;
+ CASC_BLOB RootFile;
PDWORD FileSignature;
- LPBYTE pbRootFile = NULL;
- DWORD cbRootFile = 0;
DWORD dwErrCode = ERROR_BAD_FORMAT;
// Sanity checks
@@ -888,30 +870,30 @@ __LoadRootFile:
// Load the entire ROOT file to memory
pCKeyEntry = FindCKeyEntry_CKey(hs, pCKeyEntry->CKey);
- pbRootFile = LoadInternalFileToMemory(hs, pCKeyEntry, &cbRootFile);
- if(pbRootFile != NULL)
+ dwErrCode = LoadInternalFileToMemory(hs, pCKeyEntry, RootFile);
+ if(dwErrCode == ERROR_SUCCESS)
{
// Ignore ROOT files that contain just a MD5 hash
- if(cbRootFile > MD5_STRING_SIZE)
+ if(RootFile.cbData > MD5_STRING_SIZE)
{
// Check the type of the ROOT file
- FileSignature = (PDWORD)pbRootFile;
+ FileSignature = (PDWORD)(RootFile.pbData);
switch(FileSignature[0])
{
case CASC_MNDX_ROOT_SIGNATURE:
- dwErrCode = RootHandler_CreateMNDX(hs, pbRootFile, cbRootFile);
+ dwErrCode = RootHandler_CreateMNDX(hs, RootFile);
break;
case CASC_DIABLO3_ROOT_SIGNATURE:
- dwErrCode = RootHandler_CreateDiablo3(hs, pbRootFile, cbRootFile);
+ dwErrCode = RootHandler_CreateDiablo3(hs, RootFile);
break;
case CASC_TVFS_ROOT_SIGNATURE:
- dwErrCode = RootHandler_CreateTVFS(hs, pbRootFile, cbRootFile);
+ dwErrCode = RootHandler_CreateTVFS(hs, RootFile);
break;
case CASC_WOW82_ROOT_SIGNATURE:
- dwErrCode = RootHandler_CreateWoW(hs, pbRootFile, cbRootFile, dwLocaleMask);
+ dwErrCode = RootHandler_CreateWoW(hs, RootFile, dwLocaleMask);
break;
default:
@@ -921,21 +903,18 @@ __LoadRootFile:
// If the format was not recognized, they need to return ERROR_BAD_FORMAT
//
- dwErrCode = RootHandler_CreateOverwatch(hs, pbRootFile, cbRootFile);
+ dwErrCode = RootHandler_CreateOverwatch(hs, RootFile);
if(dwErrCode == ERROR_BAD_FORMAT)
{
- dwErrCode = RootHandler_CreateStarcraft1(hs, pbRootFile, cbRootFile);
+ dwErrCode = RootHandler_CreateStarcraft1(hs, RootFile);
if(dwErrCode == ERROR_BAD_FORMAT)
{
- dwErrCode = RootHandler_CreateWoW(hs, pbRootFile, cbRootFile, dwLocaleMask);
+ dwErrCode = RootHandler_CreateWoW(hs, RootFile, dwLocaleMask);
}
}
break;
}
}
-
- // Free the root file
- CASC_FREE(pbRootFile);
}
else
{
@@ -1109,73 +1088,7 @@ static bool GetStoragePathProduct(TCascStorage * hs, void * pvStorageInfo, size_
return (szBuffer != NULL);
}
-static DWORD InitializeLocalDirectories(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs)
-{
- LPTSTR szWorkPath;
- DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
-
- // Find the root directory of the storage. The root directory
- // is the one with ".build.info" or ".build.db".
- szWorkPath = CascNewStr(pArgs->szLocalPath);
- if(szWorkPath != NULL)
- {
- // Get the length and go up until we find the ".build.info" or ".build.db"
- for(;;)
- {
- // Is this a game directory?
- dwErrCode = CheckGameDirectory(hs, szWorkPath);
- if(dwErrCode == ERROR_SUCCESS)
- {
- dwErrCode = ERROR_SUCCESS;
- break;
- }
-
- // Cut one path part
- if(!CutLastPathPart(szWorkPath))
- {
- dwErrCode = ERROR_FILE_NOT_FOUND;
- break;
- }
- }
-
- // Find the index directory
- if(dwErrCode == ERROR_SUCCESS)
- {
- // First, check for more common "data" subdirectory
- if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("data"))) != NULL)
- dwErrCode = ERROR_SUCCESS;
-
- // Second, try the "darch" subdirectory (older builds of HOTS - Alpha)
- else if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("darch"))) != NULL)
- dwErrCode = ERROR_SUCCESS;
-
- else
- dwErrCode = ERROR_FILE_NOT_FOUND;
- }
-
- // Free the work path buffer
- CASC_FREE(szWorkPath);
- }
-
- return dwErrCode;
-}
-
-static DWORD InitializeOnlineDirectories(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs)
-{
- // Create the root path
- hs->szRootPath = CascNewStr(pArgs->szLocalPath);
- if(hs->szRootPath != NULL)
- {
- hs->BuildFileType = CascVersionsDb;
- hs->dwFeatures |= CASC_FEATURE_ONLINE;
- hs->dwFeatures |= (pArgs->dwFlags & (CASC_FEATURE_LOCAL_CDNS | CASC_FEATURE_LOCAL_VERSIONS));
- return ERROR_SUCCESS;
- }
-
- return ERROR_NOT_ENOUGH_MEMORY;
-}
-
-static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs)
+static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs, LPCTSTR szMainFile, CBLD_TYPE BuildFileType, DWORD dwFeatures)
{
LPCTSTR szCdnHostUrl = NULL;
LPCTSTR szCodeName = NULL;
@@ -1206,21 +1119,48 @@ static DWORD LoadCascStorage(TCascStorage * hs, PCASC_OPEN_STORAGE_ARGS pArgs)
if(ExtractVersionedArgument(pArgs, FIELD_OFFSET(CASC_OPEN_STORAGE_ARGS, szBuildKey), &szBuildKey) && szBuildKey != NULL)
hs->szBuildKey = CascNewStrT2A(szBuildKey);
- // Special handling to online storages
- if(hs->dwFeatures & CASC_FEATURE_ONLINE)
- {
- // Enable caching of the sockets. This will add references
- // to all existing and all future sockets
- sockets_set_caching(true);
+ // 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->BuildFileType = BuildFileType;
+
+ // Copy the name of the build file
+ hs->szMainFile = CascNewStr(szMainFile);
- // For online storages, we need to load CDN servers
- dwErrCode = LoadCdnsFile(hs);
+ // Construct the root path from the name of the build file
+ CASC_PATH<TCHAR> RootPath(szMainFile, NULL);
+ hs->szRootPath = RootPath.New(true);
+
+ // If either of the root path or build file is known, it's an error
+ if(hs->szRootPath == NULL || hs->szMainFile == NULL)
+ {
+ dwErrCode = ERROR_NOT_ENOUGH_MEMORY;
}
- // Now, load the main storage file ".build.info" (or ".build.db" in old storages)
+ // Initialize variables for local CASC storages
if(dwErrCode == ERROR_SUCCESS)
{
- dwErrCode = LoadBuildInfo(hs);
+ // For local (game) storages, we need the data and indices subdirectory
+ if(hs->dwFeatures & CASC_FEATURE_DATA_ARCHIVES)
+ {
+ if(CheckArchiveFilesDirectories(hs) != ERROR_SUCCESS)
+ hs->dwFeatures &= ~CASC_FEATURE_DATA_ARCHIVES;
+ }
+
+ // For data files storage, we need that folder
+ if(hs->dwFeatures & CASC_FEATURE_DATA_FILES)
+ {
+ if(CheckDataFilesDirectory(hs) != ERROR_SUCCESS)
+ hs->dwFeatures &= ~CASC_FEATURE_DATA_FILES;
+ }
+
+ // Enable caching of the sockets. This will add references
+ // to all existing and all future sockets
+ if(hs->dwFeatures & CASC_FEATURE_ONLINE)
+ sockets_set_caching(true);
+
+ // Now, load the main storage file (".build.info", ".build.db" or "versions")
+ dwErrCode = LoadMainFile(hs);
}
// Proceed with loading the CDN config file
@@ -1439,33 +1379,49 @@ bool WINAPI CascOpenStorageEx(LPCTSTR szParams, PCASC_OPEN_STORAGE_ARGS pArgs, b
}
}
- // Allocate the storage structure
+ // Now we need to get the CASC main file, which is either
+ // [*] .build.info - for current local storages
+ // [*] .build.db - for older local storages
+ // [*] versions - for cached online storages
+ // If there is none of these and `bOnlineStorage` is specified,
+ // CascLib will download it, as long as the product code was specified
if(dwErrCode == ERROR_SUCCESS)
{
if((hs = new TCascStorage()) != NULL)
{
- // Setup the directories
- dwErrCode = (bOnlineStorage) ? InitializeOnlineDirectories(hs, pArgs) : InitializeLocalDirectories(hs, pArgs);
- if(dwErrCode == ERROR_SUCCESS)
+ 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);
+ }
+
+ // Search the folder and upper folders for the build file
+ else if((dwErrCode = CheckCascBuildFileDirs(BuildFile, pArgs->szLocalPath)) == ERROR_SUCCESS)
{
- // Perform the entire storage loading
- dwErrCode = LoadCascStorage(hs, pArgs);
+ dwErrCode = LoadCascStorage(hs, pArgs, BuildFile.szFullPath, BuildFile.BuildFileType, dwFeatures | 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)
+ {
+ dwErrCode = LoadCascStorage(hs, pArgs, BuildFile.szFullPath, BuildFile.BuildFileType, dwFeatures | CASC_FEATURE_DATA_FILES);
}
}
}
- // Handle errors
+ // Delete the storage on error
if(dwErrCode != ERROR_SUCCESS)
- {
- SetCascError(dwErrCode);
hs = hs->Release();
- }
-
- // Free the copy of the parameters
CASC_FREE(szParamsCopy);
// Give the output parameter to the caller
- *phStorage = (HANDLE)hs;
+ if(phStorage != NULL)
+ phStorage[0] = (HANDLE)hs;
+ if(dwErrCode != ERROR_SUCCESS)
+ SetCascError(dwErrCode);
return (dwErrCode == ERROR_SUCCESS);
}