diff options
Diffstat (limited to 'dep/CascLib/src/CascFiles.cpp')
-rw-r--r-- | dep/CascLib/src/CascFiles.cpp | 299 |
1 files changed, 210 insertions, 89 deletions
diff --git a/dep/CascLib/src/CascFiles.cpp b/dep/CascLib/src/CascFiles.cpp index 695d7d4af6a..b18b8847a3d 100644 --- a/dep/CascLib/src/CascFiles.cpp +++ b/dep/CascLib/src/CascFiles.cpp @@ -60,7 +60,7 @@ static LPCTSTR DataDirs[] = NULL, }; -static LPCTSTR bnet_region = _T("us"); +static const LPCTSTR szDefaultCDN = _T("ribbit://us.version.battle.net/v1/products"); //----------------------------------------------------------------------------- // Local functions @@ -454,6 +454,7 @@ static DWORD LoadBuildProductId(TCascStorage * hs, const char * /* szVariableNam // "B29049" // "WOW-18125patch6.0.1" +// "WOW-45779patch10.0.2_Beta" // "30013_Win32_2_2_0_Ptr_ptr" // "prometheus-0_8_0_0-24919" static DWORD LoadBuildNumber(TCascStorage * hs, const char * /* szVariableName */, const char * szDataBegin, const char * szDataEnd, void * /* pvParam */) @@ -914,6 +915,93 @@ static DWORD LoadCsvFile(TCascStorage * hs, LPCTSTR szFileName, PARSECSVFILE Pfn return dwErrCode; } +static DWORD ForcePathExist(LPCTSTR szFileName, bool bIsFileName) +{ + LPTSTR szLocalPath; + size_t nIndex; + bool bFirstSeparator = false; + DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY; + + // Sanity checks + if(szFileName && szFileName[0]) + { + szLocalPath = CascNewStr(szFileName); + if(szLocalPath != NULL) + { + // Get the end of search + if(bIsFileName) + CutLastPathPart(szLocalPath); + + // Check the entire path + if(_taccess(szLocalPath, 0) != 0) + { + // Searth the entire path + for(nIndex = 0; szLocalPath[nIndex] != 0; nIndex++) + { + if(szLocalPath[nIndex] == '\\' || szLocalPath[nIndex] == '/') + { + // Cut the path and verify whether the folder/file exists + szLocalPath[nIndex] = 0; + + // Skip the very first separator + if(bFirstSeparator == true) + { + // Is it there? + if(DirectoryExists(szLocalPath) == false && MakeDirectory(szLocalPath) == false) + { + dwErrCode = ERROR_PATH_NOT_FOUND; + break; + } + } + + // Restore the character + szLocalPath[nIndex] = PATH_SEP_CHAR; + bFirstSeparator = true; + dwErrCode = ERROR_SUCCESS; + } + } + + // Now check the final path + if(DirectoryExists(szLocalPath) || MakeDirectory(szLocalPath)) + { + dwErrCode = ERROR_SUCCESS; + } + } + else + { + dwErrCode = ERROR_SUCCESS; + } + + CASC_FREE(szLocalPath); + } + } + + return dwErrCode; +} + +static DWORD SaveLocalFile(LPCTSTR szLocalName, LPBYTE pbFileData, size_t cbFileData) +{ + TFileStream * pLocStream; + DWORD dwErrCode = ERROR_DISK_FULL; + + // Make sure that the path exists + ForcePathExist(szLocalName, true); + + // Create local file + pLocStream = FileStream_CreateFile(szLocalName, BASE_PROVIDER_FILE | STREAM_PROVIDER_FLAT); + if(pLocStream != NULL) + { + if(FileStream_Write(pLocStream, NULL, pbFileData, (DWORD)(cbFileData))) + dwErrCode = ERROR_SUCCESS; + + FileStream_Close(pLocStream); + } + else + dwErrCode = GetCascError(); + + return dwErrCode; +} + static LPCTSTR ExtractCdnServerName(LPTSTR szServerName, size_t cchServerName, LPCTSTR szCdnServers) { LPCTSTR szSeparator; @@ -997,70 +1085,6 @@ static void CreateRemoteAndLocalPath(TCascStorage * hs, CASC_CDN_DOWNLOAD & Cdns LocalPath.AppendString(CdnsInfo.szExtension, false); } -static DWORD ForcePathExist(LPCTSTR szFileName, bool bIsFileName) -{ - LPTSTR szLocalPath; - size_t nIndex; - bool bFirstSeparator = false; - DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY; - - // Sanity checks - if(szFileName && szFileName[0]) - { - szLocalPath = CascNewStr(szFileName); - if(szLocalPath != NULL) - { - // Get the end of search - if(bIsFileName) - CutLastPathPart(szLocalPath); - - // Check the entire path - if(_taccess(szLocalPath, 0) != 0) - { - // Searth the entire path - for(nIndex = 0; szLocalPath[nIndex] != 0; nIndex++) - { - if(szLocalPath[nIndex] == '\\' || szLocalPath[nIndex] == '/') - { - // Cut the path and verify whether the folder/file exists - szLocalPath[nIndex] = 0; - - // Skip the very first separator - if(bFirstSeparator == true) - { - // Is it there? - if(DirectoryExists(szLocalPath) == false && MakeDirectory(szLocalPath) == false) - { - dwErrCode = ERROR_PATH_NOT_FOUND; - break; - } - } - - // Restore the character - szLocalPath[nIndex] = PATH_SEP_CHAR; - bFirstSeparator = true; - dwErrCode = ERROR_SUCCESS; - } - } - - // Now check the final path - if(DirectoryExists(szLocalPath) || MakeDirectory(szLocalPath)) - { - dwErrCode = ERROR_SUCCESS; - } - } - else - { - dwErrCode = ERROR_SUCCESS; - } - - CASC_FREE(szLocalPath); - } - } - - return dwErrCode; -} - static bool FileAlreadyExists(LPCTSTR szFileName) { TFileStream * pStream; @@ -1084,7 +1108,6 @@ static DWORD DownloadFile( DWORD dwPortFlags) { TFileStream * pRemStream; - TFileStream * pLocStream; LPBYTE pbFileData; DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY; @@ -1098,28 +1121,31 @@ static DWORD DownloadFile( ULONGLONG FileSize = 0; // Retrieve the file size, but not longer than 1 GB - if(FileStream_GetSize(pRemStream, &FileSize) && 0 < FileSize && FileSize < 0x40000000) + if(FileStream_GetSize(pRemStream, &FileSize)) { - // Cut the file size down to 32 bits - cbReadSize = (DWORD)FileSize; + // Verify valid size + if(0 < FileSize && FileSize < CASC_MAX_ONLINE_FILE_SIZE) + { + cbReadSize = (DWORD)FileSize; + dwErrCode = ERROR_SUCCESS; + } + else + { + dwErrCode = ERROR_BAD_FORMAT; + } + } + else + { + dwErrCode = GetCascError(); } } // Shall we read something? - if((cbReadSize != 0) && (pbFileData = CASC_ALLOC<BYTE>(cbReadSize)) != NULL) + if((dwErrCode == ERROR_SUCCESS) && (cbReadSize != 0) && (pbFileData = CASC_ALLOC<BYTE>(cbReadSize)) != NULL) { // Read all required data from the remote file if(FileStream_Read(pRemStream, PtrByteOffset, pbFileData, cbReadSize)) - { - pLocStream = FileStream_CreateFile(szLocalName, BASE_PROVIDER_FILE | STREAM_PROVIDER_FLAT); - if(pLocStream != NULL) - { - if(FileStream_Write(pLocStream, NULL, pbFileData, cbReadSize)) - dwErrCode = ERROR_SUCCESS; - - FileStream_Close(pLocStream); - } - } + dwErrCode = SaveLocalFile(szLocalName, pbFileData, cbReadSize); // Free the data buffer CASC_FREE(pbFileData); @@ -1136,16 +1162,38 @@ static DWORD DownloadFile( return dwErrCode; } -static DWORD RibbitDownloadFile(LPCTSTR szProduct, LPCTSTR szFileName, QUERY_KEY & FileData) +static DWORD RibbitDownloadFile(LPCTSTR szCdnHostUrl, LPCTSTR szProduct, LPCTSTR szFileName, CASC_PATH<TCHAR> & LocalPath, QUERY_KEY & FileData) { + CASC_PATH<TCHAR> LocalFile; TFileStream * pStream; ULONGLONG FileSize = 0; TCHAR szRemoteUrl[256]; DWORD dwErrCode = ERROR_CAN_NOT_COMPLETE; + // If required, try to load the local name first + if(LocalPath.Length() && LocalPath.LocalCaching()) + { + LPBYTE pbFileData; + DWORD cbFileData = 0; + + // Load the local file into memory + pbFileData = LoadFileToMemory(LocalPath, &cbFileData); + if(pbFileData && cbFileData) + { + // Pass the file data to the caller + FileData.pbData = pbFileData; + FileData.cbData = cbFileData; + return ERROR_SUCCESS; + } + } + + // Supply the default CDN URL, if not present + if(szCdnHostUrl == NULL || szCdnHostUrl[0] == 0) + szCdnHostUrl = szDefaultCDN; + // Construct the full URL (https://wowdev.wiki/Ribbit) // Old (HTTP) download: wget http://us.patch.battle.net:1119/wow_classic/cdns - CascStrPrintf(szRemoteUrl, _countof(szRemoteUrl), _T("ribbit://%s.version.battle.net/v1/products/%s/%s"), bnet_region, szProduct, szFileName); + CascStrPrintf(szRemoteUrl, _countof(szRemoteUrl), _T("%s/%s/%s"), szCdnHostUrl, szProduct, szFileName); // Open the file stream if((pStream = FileStream_OpenFile(szRemoteUrl, 0)) != NULL) @@ -1186,6 +1234,9 @@ static DWORD RibbitDownloadFile(LPCTSTR szProduct, LPCTSTR szFileName, QUERY_KEY dwErrCode = GetCascError(); } + // Save the file to the local cache + if(LocalPath.Length() && FileData.pbData && FileData.cbData && dwErrCode == ERROR_SUCCESS) + SaveLocalFile(LocalPath, FileData.pbData, FileData.cbData); return dwErrCode; } @@ -1228,13 +1279,24 @@ DWORD DownloadFileFromCDN(TCascStorage * hs, CASC_CDN_DOWNLOAD & CdnsInfo) // from the storage's configuration if(CdnsInfo.szCdnsHost == NULL) { + // Supply the CDN host + CdnsInfo.szCdnsHost = szCdnHost; + // Try all download servers while((szCdnServers = ExtractCdnServerName(szCdnHost, _countof(szCdnHost), szCdnServers)) != NULL) { - CdnsInfo.szCdnsHost = szCdnHost; - if((dwErrCode = DownloadFileFromCDN2(hs, CdnsInfo)) == ERROR_SUCCESS) - return ERROR_SUCCESS; + // Attempt to download the file from the remote server + dwErrCode = DownloadFileFromCDN2(hs, CdnsInfo); + + // If the download succeeded, exit immediately. + // Also exit when there is a low memory condition, + // as it will most likely end up with low memory on next download + if(dwErrCode == ERROR_SUCCESS || dwErrCode == ERROR_NOT_ENOUGH_MEMORY) + break; } + + // Don't give the local buffer pointer to the caller + CdnsInfo.szCdnsHost = NULL; } else { @@ -1411,14 +1473,21 @@ DWORD LoadBuildInfo(TCascStorage * hs) // If the storage is online storage, we need to download "versions" if(hs->dwFeatures & CASC_FEATURE_ONLINE) { + CASC_PATH<TCHAR> LocalPath; QUERY_KEY FileData; + LPCTSTR szVersionsName = _T("versions"); // Inform the user about loading the build.info/build.db/versions if(InvokeProgressCallback(hs, "Downloading the \"versions\" file", NULL, 0, 0)) return ERROR_CANCELLED; - // Download the file using Ribbit protocol - dwErrCode = RibbitDownloadFile(hs->szCodeName, _T("versions"), FileData); + // Shall we prefer the locally cached file? + LocalPath.SetPathRoot(hs->szRootPath); + LocalPath.AppendString(szVersionsName, true); + LocalPath.SetLocalCaching(hs->dwFeatures & CASC_FEATURE_LOCAL_VERSIONS); + + // Download the file using Ribbit/HTTP protocol + dwErrCode = RibbitDownloadFile(hs->szCdnHostUrl, hs->szCodeName, szVersionsName, LocalPath, FileData); if(dwErrCode == ERROR_SUCCESS) { // Parse the downloaded file @@ -1436,7 +1505,9 @@ DWORD LoadBuildInfo(TCascStorage * hs) DWORD LoadCdnsFile(TCascStorage * hs) { + CASC_PATH<TCHAR> LocalPath; QUERY_KEY FileData; + LPCTSTR szCdnsName = _T("cdns"); DWORD dwErrCode = ERROR_SUCCESS; // Sanity checks @@ -1446,8 +1517,13 @@ DWORD LoadCdnsFile(TCascStorage * hs) if(InvokeProgressCallback(hs, "Downloading the \"cdns\" file", NULL, 0, 0)) return ERROR_CANCELLED; + // Construct the local path of the file + LocalPath.SetPathRoot(hs->szRootPath); + LocalPath.AppendString(szCdnsName, true); + LocalPath.SetLocalCaching(hs->dwFeatures & CASC_FEATURE_LOCAL_CDNS); + // Download the file using Ribbit protocol - dwErrCode = RibbitDownloadFile(hs->szCodeName, _T("cdns"), FileData); + dwErrCode = RibbitDownloadFile(hs->szCdnHostUrl, hs->szCodeName, szCdnsName, LocalPath, FileData); if(dwErrCode == ERROR_SUCCESS) { // Parse the downloaded file @@ -1603,7 +1679,6 @@ LPBYTE LoadFileToMemory(LPCTSTR szFileName, DWORD * pcbFileData) { SetCascError(ERROR_BAD_FORMAT); cbFileData = 0; - assert(false); } // Close the file stream @@ -1616,3 +1691,49 @@ LPBYTE LoadFileToMemory(LPCTSTR szFileName, DWORD * pcbFileData) return pbFileData; } +//----------------------------------------------------------------------------- +// Public CDN functions + +LPCTSTR WINAPI CascCdnGetDefault() +{ + return szDefaultCDN; +} + +LPBYTE WINAPI CascCdnDownload(LPCTSTR szCdnHostUrl, LPCTSTR szProduct, LPCTSTR szFileName, DWORD * PtrSize) +{ + CASC_PATH<TCHAR> LocalPath; + QUERY_KEY FileData; + LPBYTE pbFileData = NULL; + size_t cbFileData = 0; + DWORD dwErrCode; + + // Download the file + dwErrCode = RibbitDownloadFile(szCdnHostUrl, szProduct, szFileName, LocalPath, FileData); + if(dwErrCode == ERROR_SUCCESS) + { + // Create copy of the buffer + if((pbFileData = CASC_ALLOC<BYTE>(FileData.cbData + 1)) != NULL) + { + memcpy(pbFileData, FileData.pbData, FileData.cbData); + pbFileData[FileData.cbData] = 0; + cbFileData = FileData.cbData; + } + else + { + dwErrCode = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Give the results + if(dwErrCode != ERROR_SUCCESS) + SetCascError(dwErrCode); + if(PtrSize != NULL) + PtrSize[0] = (DWORD)cbFileData; + return pbFileData; +} + +void WINAPI CascCdnFree(void * buffer) +{ + CASC_FREE(buffer); +} + |