From 7235058f0990540562551036160589736224a892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Wed, 5 Jul 2023 21:31:52 -0300 Subject: [PATCH] scan secondary library folders on windows --- src/win32/i_steam.cpp | 128 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 5 deletions(-) diff --git a/src/win32/i_steam.cpp b/src/win32/i_steam.cpp index 056b59364b..5b62ae4354 100644 --- a/src/win32/i_steam.cpp +++ b/src/win32/i_steam.cpp @@ -80,6 +80,112 @@ #include "cmdlib.h" #include "i_interface.h" + +//TODO maybe move this code to a separate cpp file, so that there isn't code duplication between the win32 and posix backends +static void PSR_FindEndBlock(FScanner &sc) +{ + int depth = 1; + do + { + if(sc.CheckToken('}')) + --depth; + else if(sc.CheckToken('{')) + ++depth; + else + sc.MustGetAnyToken(); + } + while(depth); +} +static void PSR_SkipBlock(FScanner &sc) +{ + sc.MustGetToken('{'); + PSR_FindEndBlock(sc); +} +static bool PSR_FindAndEnterBlock(FScanner &sc, const char* keyword) +{ + // Finds a block with a given keyword and then enter it (opening brace) + // Should be closed with PSR_FindEndBlock + while(sc.GetToken()) + { + if(sc.TokenType == '}') + { + sc.UnGet(); + return false; + } + + sc.TokenMustBe(TK_StringConst); + if(!sc.Compare(keyword)) + { + if(!sc.CheckToken(TK_StringConst)) + PSR_SkipBlock(sc); + } + else + { + sc.MustGetToken('{'); + return true; + } + } + return false; +} +static TArray PSR_ReadBaseInstalls(FScanner &sc) +{ + TArray result; + + // Get a list of possible install directories. + while(sc.GetToken()) + { + if(sc.TokenType == '}') + break; + + sc.TokenMustBe(TK_StringConst); + FString key(sc.String); + if(key.Left(18).CompareNoCase("BaseInstallFolder_") == 0) + { + sc.MustGetToken(TK_StringConst); + result.Push(FString(sc.String) + "/steamapps/common"); + } + else + { + if(sc.CheckToken('{')) + PSR_FindEndBlock(sc); + else + sc.MustGetToken(TK_StringConst); + } + } + + return result; +} +static TArray ParseSteamRegistry(const char* path) +{ + TArray dirs; + + // Read registry data + FScanner sc; + if (sc.OpenFile(path)) + { + sc.SetCMode(true); + + // Find the SteamApps listing + if (PSR_FindAndEnterBlock(sc, "InstallConfigStore")) + { + if (PSR_FindAndEnterBlock(sc, "Software")) + { + if (PSR_FindAndEnterBlock(sc, "Valve")) + { + if (PSR_FindAndEnterBlock(sc, "Steam")) + { + dirs = PSR_ReadBaseInstalls(sc); + } + PSR_FindEndBlock(sc); + } + PSR_FindEndBlock(sc); + } + PSR_FindEndBlock(sc); + } + } + return dirs; +} + //========================================================================== // // QueryPathKey @@ -240,18 +346,30 @@ TArray I_GetSteamPath() "Doom 2/finaldoombase" }; - FString path; + FString steamPath; - if (!QueryPathKey(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", L"SteamPath", path)) + if (!QueryPathKey(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", L"SteamPath", steamPath)) { - if (!QueryPathKey(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", L"InstallPath", path)) + if (!QueryPathKey(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", L"InstallPath", steamPath)) return result; } - path += "/SteamApps/common/"; + + TArray paths = ParseSteamRegistry(steamPath + "/config/config.vdf"); + + for(FString &path : paths) + { + path.ReplaceChars('\\','/'); + path+="/"; + } + + paths.Push(steamPath + "/steamapps/common/"); for(unsigned int i = 0; i < countof(steam_dirs); ++i) { - result.Push(path + steam_dirs[i]); + for(const FString &path : paths) + { + result.Push(path + steam_dirs[i]); + } } return result;