diff options
Diffstat (limited to 'dep/CascLib/src/CascOpenStorage.cpp')
-rw-r--r-- | dep/CascLib/src/CascOpenStorage.cpp | 268 |
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); } |