66#include < filesystem>
77#include < regex>
88#include < stdexcept>
9+ #include < string>
10+ #include < algorithm>
11+ #include < cctype>
12+ #include < chrono>
13+ #include < ctime>
14+ #include < cstdio>
15+ #include < vector>
16+ #include < curl/curl.h>
917
1018#include " launcher/isaac_installation.h"
1119#include " launcher/repentogon_installation.h"
2028#include " launcher/standalone_rgon_folder.h"
2129#include " steam_api.h"
2230
23-
24- #include < io.h>
25- #include < fstream>
26- #include < filesystem>
27- #include < string>
28- #include < stdexcept>
29- #include < curl/curl.h>
30- #include < algorithm>
31- #include < cctype>
32- #include < chrono>
33- #include < ctime>
34- #include < string>
35- #include < cstdio>
36- #include < vector>
37- #include < curl/curl.h>
38-
3931static constexpr const char * __versionNeedle = " Binding of Isaac: Repentance+ v" ;
4032static constexpr const char * __launcherDataFolder = " launcher-data" ;
4133static constexpr const char * __patchFolder = " launcher-data/patch" ;
@@ -358,27 +350,37 @@ static size_t patchwriteresponse(void* contents, size_t size, size_t nmemb, void
358350 return fwrite (contents, size, nmemb, fp);
359351}
360352
361- static void RemoveOldPatchFolder ()
353+ static bool RemoveOldPatchFolder ()
362354{
363- namespace fs = std::filesystem;
364- if (fs::exists (__patchFolder))
365- fs::remove_all (__patchFolder);
355+ int attempts = 0 ;
356+ while (fs::exists (__patchFolder) && attempts++ <= 5 ) {
357+ try {
358+ fs::remove_all (__patchFolder);
359+ } catch (std::filesystem::filesystem_error& err) {
360+ Logger::Error (" Failed to delete patch folder: %s (attempt #%d)" , err.what (), attempts);
361+ std::this_thread::sleep_for (std::chrono::milliseconds (200 ));
362+ }
363+ }
364+ return !fs::exists (__patchFolder);
366365}
367366
368- bool CheckIfAvailableOnlineNGet (const std::string& currexehash,
369- const std::string& targetversion)
367+ bool CheckIfAvailableOnlineNGet (const std::string& currexehash, const std::string& targetversion)
370368{
371369 const std::string url =
372370 " https://gitlab.com/repentogon/versiontracker/-/raw/main/Patches/_" +
373371 currexehash + " _-_" + targetversion + " _.zip?inline=false" ;
374372
375373 CURL * curl = curl_easy_init ();
376374 if (!curl)
375+ {
376+ Logger::Error (" Failed to initialize curl!!!\n " );
377377 return false ;
378+ }
378379
379380 FILE * fp = fopen (__patchZip, " wb" );
380381 if (!fp)
381382 {
383+ Logger::Error (" Failed to fopen %s (%d)\n " , __patchZip, errno);
382384 curl_easy_cleanup (curl);
383385 return false ;
384386 }
@@ -402,24 +404,41 @@ bool CheckIfAvailableOnlineNGet(const std::string& currexehash,
402404 curl_slist_free_all (headers);
403405 curl_easy_cleanup (curl);
404406
405- if (res != CURLE_OK || http_code < 200 || http_code >= 300 )
407+ bool patchAvailable = false ;
408+
409+ if (res != CURLE_OK )
406410 {
407- return false ;
411+ Logger::Error (" Curl error: %d\n " , res);
412+ }
413+ else if (http_code < 200 || http_code >= 300 )
414+ {
415+ Logger::Info (" Curl HTTP code: %d\n " , http_code);
416+ }
417+ else if (!RemoveOldPatchFolder ())
418+ {
419+ Logger::Error (" Failed to remove existing patch folder!\n " );
408420 }
409- RemoveOldPatchFolder ();
410- if (!Zip::ExtractAllToFolder (__patchZip, __launcherDataFolder))
421+ else if (!Zip::ExtractAllToFolder (__patchZip, __launcherDataFolder))
411422 {
423+ Logger::Error (" Failed to extract downloaded patch!\n " );
424+ }
425+ else
426+ {
427+ // Patch successfully found, downloaded and extracted.
428+ patchAvailable = true ;
429+ }
430+
431+ try {
412432 std::filesystem::remove (__patchZip);
413- return false ;
433+ } catch (std::filesystem::filesystem_error& err) {
434+ Logger::Error (" Failed to delete patch zip: %s" , err.what ());
414435 }
415- std::filesystem::remove (__patchZip);
416- return true ;
436+ return patchAvailable;
417437}
418438
419439
420440
421441bool InstallationData::PatchIsAvailable (const bool skipOnlineCheck) {
422- namespace fs = std::filesystem;
423442 if (_vanillaexeispatchable > 0 ) {
424443 return _vanillaexeispatchable == 1 ; // so it doesnt do the whole check and we can call this a shitton of times without worrying, the vanilla exe shouldnt change while the launcher is open anyway, since the launcher doesnt update it and...if it does, just fucking restart the launcher, dude
425444 }
@@ -430,33 +449,11 @@ bool InstallationData::PatchIsAvailable(const bool skipOnlineCheck) {
430449 fs::path fullPath = fs::current_path () / __patchFolder / " exehash.txt" ;
431450 std::string s = fullPath.string ();
432451 if (fs::exists (fullPath)) {
433- ScopedFile file (fopen (s.c_str (), " r" ));
434- if (!file) {
435- Logger::Error (" InstallationData::PatchIsAvailable: failed to open patch file %s\n " , s.c_str ());
436- return false ;
437- }
438-
439- long begin = ftell (file);
440- fseek (file, 0 , SEEK_END );
441-
442- if (ferror (file)) {
443- Logger::Error (" InstallationData::PatchIsAvailable: failed to fseek\n " );
444- return false ;
445- }
446-
447- long end = ftell (file);
448- rewind (file);
449-
450- std::unique_ptr<char []> content = std::make_unique<char []>(end - begin + 1 );
451- if (!content) {
452- Logger::Error (" InstallationData::PatchIsAvailable: unable to allocate memory\n " );
453- return false ;
454- }
455-
456- fread (content.get (), end - begin, 1 , file);
457- content.get ()[end - begin] = ' \0 ' ;
452+ // Read the exe hash and compare it.
453+ std::stringstream buffer;
454+ buffer << std::ifstream (fullPath).rdbuf ();
455+ std::string currexehash = buffer.str ();
458456
459- std::string currexehash = content.get ();
460457 std::transform (currexehash.begin (), currexehash.end (), currexehash.begin (),
461458 [](unsigned char c) { return std::tolower (c); });
462459
0 commit comments