mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-22 11:23:27 -04:00
Merge branch 'registry' into 'master'
Detect Steam installations on Windows and Linux See merge request OpenMW/openmw!4885
This commit is contained in:
commit
04e566ce92
@ -71,11 +71,9 @@ Wizard::MainWizard::MainWizard(Files::ConfigurationManager&& cfgMgr, QWidget* pa
|
||||
setupInstallations();
|
||||
setupPages();
|
||||
|
||||
const std::filesystem::path& installationPath = mCfgMgr.getInstallPath();
|
||||
if (!installationPath.empty())
|
||||
for (std::filesystem::path installationPath : mCfgMgr.getInstallPaths())
|
||||
{
|
||||
const std::filesystem::path& dataPath = installationPath / "Data Files";
|
||||
addInstallation(Files::pathToQString(dataPath));
|
||||
addInstallation(Files::pathToQString(installationPath / "Data Files"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,9 +66,9 @@ namespace Files
|
||||
return std::filesystem::path(g_path_user);
|
||||
}
|
||||
|
||||
std::filesystem::path AndroidPath::getInstallPath() const
|
||||
std::vector<std::filesystem::path> AndroidPath::getInstallPaths() const
|
||||
{
|
||||
return std::filesystem::path();
|
||||
return {};
|
||||
}
|
||||
|
||||
} /* namespace Files */
|
||||
|
@ -4,6 +4,7 @@
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
/**
|
||||
* \namespace Files
|
||||
*/
|
||||
@ -43,7 +44,7 @@ namespace Files
|
||||
*/
|
||||
std::filesystem::path getCachePath() const;
|
||||
|
||||
std::filesystem::path getInstallPath() const;
|
||||
std::vector<std::filesystem::path> getInstallPaths() const;
|
||||
};
|
||||
|
||||
} /* namespace Files */
|
||||
|
@ -419,9 +419,9 @@ namespace Files
|
||||
return mFixedPath.getCachePath();
|
||||
}
|
||||
|
||||
const std::filesystem::path& ConfigurationManager::getInstallPath() const
|
||||
std::vector<std::filesystem::path> ConfigurationManager::getInstallPaths() const
|
||||
{
|
||||
return mFixedPath.getInstallPath();
|
||||
return mFixedPath.getInstallPaths();
|
||||
}
|
||||
|
||||
const std::filesystem::path& ConfigurationManager::getScreenshotPath() const
|
||||
|
@ -48,7 +48,7 @@ namespace Files
|
||||
|
||||
const std::filesystem::path& getUserConfigPath() const;
|
||||
const std::filesystem::path& getUserDataPath() const;
|
||||
const std::filesystem::path& getInstallPath() const;
|
||||
std::vector<std::filesystem::path> getInstallPaths() const;
|
||||
const std::vector<std::filesystem::path>& getActiveConfigPaths() const { return mActiveConfigPaths; }
|
||||
|
||||
const std::filesystem::path& getCachePath() const;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
|
||||
#ifndef ANDROID
|
||||
@ -66,7 +67,6 @@ namespace Files
|
||||
, mLocalPath(mPath.getLocalPath())
|
||||
, mGlobalDataPath(mPath.getGlobalDataPath())
|
||||
, mCachePath(mPath.getCachePath())
|
||||
, mInstallPath(mPath.getInstallPath())
|
||||
{
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ namespace Files
|
||||
*/
|
||||
const std::filesystem::path& getLocalPath() const { return mLocalPath; }
|
||||
|
||||
const std::filesystem::path& getInstallPath() const { return mInstallPath; }
|
||||
std::vector<std::filesystem::path> getInstallPaths() const { return mPath.getInstallPaths(); }
|
||||
|
||||
const std::filesystem::path& getGlobalDataPath() const { return mGlobalDataPath; }
|
||||
|
||||
@ -104,8 +104,6 @@ namespace Files
|
||||
std::filesystem::path mGlobalDataPath; /**< Global application data path */
|
||||
|
||||
std::filesystem::path mCachePath;
|
||||
|
||||
std::filesystem::path mInstallPath;
|
||||
};
|
||||
|
||||
} /* namespace Files */
|
||||
|
@ -2,13 +2,15 @@
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
|
||||
#include "wine.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::filesystem::path getUserHome()
|
||||
@ -100,75 +102,30 @@ namespace Files
|
||||
return globalDataPath / mName;
|
||||
}
|
||||
|
||||
std::filesystem::path LinuxPath::getInstallPath() const
|
||||
std::vector<std::filesystem::path> LinuxPath::getInstallPaths() const
|
||||
{
|
||||
std::filesystem::path installPath;
|
||||
|
||||
std::vector<std::filesystem::path> paths;
|
||||
std::filesystem::path homePath = getUserHome();
|
||||
|
||||
if (!homePath.empty())
|
||||
{
|
||||
std::filesystem::path wineDefaultRegistry(homePath);
|
||||
wineDefaultRegistry /= ".wine/system.reg";
|
||||
|
||||
if (std::filesystem::is_regular_file(wineDefaultRegistry))
|
||||
std::filesystem::path wine = Wine::getInstallPath(homePath);
|
||||
if (!wine.empty())
|
||||
paths.emplace_back(std::move(wine));
|
||||
std::array steamPaths{
|
||||
// Default (~/.steam/steam can be a symlink or a real directory)
|
||||
homePath / ".steam/steam/steamapps/common/Morrowind",
|
||||
// Snap
|
||||
homePath / "snap/steam/common/.local/share/Steam/steamapps/common/Morrowind",
|
||||
// Flatpak
|
||||
homePath / ".var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/common/Morrowind",
|
||||
};
|
||||
for (std::filesystem::path steam : steamPaths)
|
||||
{
|
||||
std::ifstream file(wineDefaultRegistry);
|
||||
bool isRegEntry = false;
|
||||
std::string line;
|
||||
std::string mwpath;
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line[0] == '[') // we found an entry
|
||||
{
|
||||
if (isRegEntry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
isRegEntry = (line.find("Softworks\\\\Morrowind]") != std::string::npos);
|
||||
}
|
||||
else if (isRegEntry)
|
||||
{
|
||||
if (line[0] == '"') // empty line means new registry key
|
||||
{
|
||||
std::string key = line.substr(1, line.find('"', 1) - 1);
|
||||
if (strcasecmp(key.c_str(), "Installed Path") == 0)
|
||||
{
|
||||
std::string::size_type valuePos = line.find('=') + 2;
|
||||
mwpath = line.substr(valuePos, line.rfind('"') - valuePos);
|
||||
|
||||
std::string::size_type pos = mwpath.find("\\");
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
mwpath.replace(pos, 2, "/");
|
||||
pos = mwpath.find("\\", pos + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mwpath.empty())
|
||||
{
|
||||
// Change drive letter to lowercase, so we could use
|
||||
// ~/.wine/dosdevices symlinks
|
||||
mwpath[0] = Misc::StringUtils::toLower(mwpath[0]);
|
||||
installPath /= homePath;
|
||||
installPath /= ".wine/dosdevices/";
|
||||
installPath /= mwpath;
|
||||
|
||||
if (!std::filesystem::is_directory(installPath))
|
||||
{
|
||||
installPath.clear();
|
||||
}
|
||||
}
|
||||
if (std::filesystem::is_directory(steam))
|
||||
paths.emplace_back(std::move(steam));
|
||||
}
|
||||
}
|
||||
|
||||
return installPath;
|
||||
return paths;
|
||||
}
|
||||
|
||||
} /* namespace Files */
|
||||
|
@ -4,6 +4,7 @@
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
@ -47,9 +48,9 @@ namespace Files
|
||||
std::filesystem::path getCachePath() const;
|
||||
|
||||
/**
|
||||
* \brief Gets the path of the installed Morrowind version if there is one.
|
||||
* \brief Gets the paths of any installed Morrowind versions we can find.
|
||||
*/
|
||||
std::filesystem::path getInstallPath() const;
|
||||
std::vector<std::filesystem::path> getInstallPaths() const;
|
||||
|
||||
std::string mName;
|
||||
};
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
|
||||
#include "wine.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -106,74 +106,17 @@ namespace Files
|
||||
return globalDataPath / mName;
|
||||
}
|
||||
|
||||
std::filesystem::path MacOsPath::getInstallPath() const
|
||||
std::vector<std::filesystem::path> MacOsPath::getInstallPaths() const
|
||||
{
|
||||
std::filesystem::path installPath;
|
||||
|
||||
std::vector<std::filesystem::path> paths;
|
||||
std::filesystem::path homePath = getUserHome();
|
||||
|
||||
if (!homePath.empty())
|
||||
{
|
||||
std::filesystem::path wineDefaultRegistry(homePath);
|
||||
wineDefaultRegistry /= ".wine/system.reg";
|
||||
|
||||
if (std::filesystem::is_regular_file(wineDefaultRegistry))
|
||||
{
|
||||
std::ifstream file(wineDefaultRegistry);
|
||||
bool isRegEntry = false;
|
||||
std::string line;
|
||||
std::string mwpath;
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line[0] == '[') // we found an entry
|
||||
{
|
||||
if (isRegEntry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
isRegEntry = (line.find("Softworks\\\\Morrowind]") != std::string::npos);
|
||||
}
|
||||
else if (isRegEntry)
|
||||
{
|
||||
if (line[0] == '"') // empty line means new registry key
|
||||
{
|
||||
std::string key = line.substr(1, line.find('"', 1) - 1);
|
||||
if (strcasecmp(key.c_str(), "Installed Path") == 0)
|
||||
{
|
||||
std::string::size_type valuePos = line.find('=') + 2;
|
||||
mwpath = line.substr(valuePos, line.rfind('"') - valuePos);
|
||||
|
||||
std::string::size_type pos = mwpath.find("\\");
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
mwpath.replace(pos, 2, "/");
|
||||
pos = mwpath.find("\\", pos + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mwpath.empty())
|
||||
{
|
||||
// Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks
|
||||
mwpath[0] = Misc::StringUtils::toLower(mwpath[0]);
|
||||
installPath /= homePath;
|
||||
installPath /= ".wine/dosdevices/";
|
||||
installPath /= mwpath;
|
||||
|
||||
if (!std::filesystem::is_directory(installPath))
|
||||
{
|
||||
installPath.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::filesystem::path wine = Wine::getInstallPath(homePath);
|
||||
if (!wine.empty())
|
||||
paths.emplace_back(std::move(wine));
|
||||
}
|
||||
|
||||
return installPath;
|
||||
return paths;
|
||||
}
|
||||
|
||||
} /* namespace Files */
|
||||
|
@ -4,6 +4,7 @@
|
||||
#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__)
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
@ -56,7 +57,7 @@ namespace Files
|
||||
*/
|
||||
std::filesystem::path getGlobalDataPath() const;
|
||||
|
||||
std::filesystem::path getInstallPath() const;
|
||||
std::vector<std::filesystem::path> getInstallPaths() const;
|
||||
|
||||
std::string mName;
|
||||
};
|
||||
|
@ -22,6 +22,40 @@
|
||||
*/
|
||||
namespace Files
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct RegistryKey
|
||||
{
|
||||
HKEY mKey = nullptr;
|
||||
|
||||
~RegistryKey()
|
||||
{
|
||||
if (mKey)
|
||||
RegCloseKey(mKey);
|
||||
}
|
||||
};
|
||||
|
||||
std::filesystem::path getRegistryPath(LPCWSTR subKey, LPCWSTR valueName, bool use32)
|
||||
{
|
||||
RegistryKey key;
|
||||
REGSAM flags = KEY_READ;
|
||||
if (use32)
|
||||
flags |= KEY_WOW64_32KEY;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, subKey, 0, flags, &key.mKey) == ERROR_SUCCESS)
|
||||
{
|
||||
// Key existed, let's try to read the install dir
|
||||
std::array<wchar_t, 512> buf{};
|
||||
DWORD len = static_cast<DWORD>(buf.size() * sizeof(wchar_t));
|
||||
|
||||
if (RegQueryValueExW(key.mKey, valueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(buf.data()), &len)
|
||||
== ERROR_SUCCESS)
|
||||
{
|
||||
return std::filesystem::path(buf.data(), buf.data() + len);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
WindowsPath::WindowsPath(const std::string& application_name)
|
||||
: mName(application_name)
|
||||
@ -82,27 +116,22 @@ namespace Files
|
||||
return getUserConfigPath() / "cache";
|
||||
}
|
||||
|
||||
std::filesystem::path WindowsPath::getInstallPath() const
|
||||
std::vector<std::filesystem::path> WindowsPath::getInstallPaths() const
|
||||
{
|
||||
std::filesystem::path installPath{};
|
||||
|
||||
if (HKEY hKey; RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Bethesda Softworks\\Morrowind", 0,
|
||||
KEY_READ | KEY_WOW64_32KEY, &hKey)
|
||||
== ERROR_SUCCESS)
|
||||
std::vector<std::filesystem::path> paths;
|
||||
{
|
||||
// Key existed, let's try to read the install dir
|
||||
std::array<wchar_t, 512> buf{};
|
||||
DWORD len = static_cast<DWORD>(buf.size() * sizeof(wchar_t));
|
||||
|
||||
if (RegQueryValueExW(hKey, L"Installed Path", nullptr, nullptr, reinterpret_cast<LPBYTE>(buf.data()), &len)
|
||||
== ERROR_SUCCESS)
|
||||
{
|
||||
installPath = std::filesystem::path(buf.data());
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
std::filesystem::path disk
|
||||
= getRegistryPath(L"SOFTWARE\\Bethesda Softworks\\Morrowind", L"Installed Path", true);
|
||||
if (!disk.empty() && std::filesystem::is_directory(disk))
|
||||
paths.emplace_back(std::move(disk));
|
||||
}
|
||||
|
||||
return installPath;
|
||||
{
|
||||
std::filesystem::path steam = getRegistryPath(
|
||||
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App 22320", L"InstallLocation", false);
|
||||
if (!steam.empty() && std::filesystem::is_directory(steam))
|
||||
paths.emplace_back(std::move(steam));
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
} /* namespace Files */
|
||||
|
@ -4,6 +4,7 @@
|
||||
#if defined(_WIN32) || defined(__WINDOWS__)
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
@ -63,11 +64,11 @@ namespace Files
|
||||
std::filesystem::path getGlobalDataPath() const;
|
||||
|
||||
/**
|
||||
* \brief Gets the path of the installed Morrowind version if there is one.
|
||||
* \brief Gets the paths of any installed Morrowind versions we can find.
|
||||
*
|
||||
* \return std::filesystem::path
|
||||
* \return std::vector<std::filesystem::path>
|
||||
*/
|
||||
std::filesystem::path getInstallPath() const;
|
||||
std::vector<std::filesystem::path> getInstallPaths() const;
|
||||
|
||||
std::string mName;
|
||||
};
|
||||
|
56
components/files/wine.hpp
Normal file
56
components/files/wine.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef COMPONENTS_FILES_WINE_HPP
|
||||
#define COMPONENTS_FILES_WINE_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
|
||||
namespace Files::Wine
|
||||
{
|
||||
std::filesystem::path getInstallPath(const std::filesystem::path& homePath)
|
||||
{
|
||||
std::filesystem::path wineDefaultRegistry = homePath / ".wine/system.reg";
|
||||
if (!std::filesystem::is_regular_file(wineDefaultRegistry))
|
||||
return {};
|
||||
|
||||
constexpr std::string_view keyStart = "\"Installed Path\"=\"";
|
||||
std::ifstream file(wineDefaultRegistry);
|
||||
bool isRegEntry = false;
|
||||
std::string line;
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.empty())
|
||||
continue;
|
||||
if (line[0] == '[') // we found an entry
|
||||
{
|
||||
if (isRegEntry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
isRegEntry = line.find("Softworks\\\\Morrowind]") != std::string::npos;
|
||||
}
|
||||
else if (isRegEntry && Misc::StringUtils::ciStartsWith(line, keyStart))
|
||||
{
|
||||
std::string mwpath = line.substr(keyStart.size(), line.rfind('"') - keyStart.size());
|
||||
if (mwpath.empty())
|
||||
break;
|
||||
std::transform(
|
||||
mwpath.begin(), mwpath.end(), mwpath.begin(), [](char c) { return c == '\\' ? '/' : c; });
|
||||
// Change drive letter to lowercase, so we could use ~/.wine/dosdevices symlinks
|
||||
mwpath[0] = Misc::StringUtils::toLower(mwpath[0]);
|
||||
std::filesystem::path installPath = homePath / ".wine/dosdevices/" / mwpath;
|
||||
|
||||
if (std::filesystem::is_directory(installPath))
|
||||
return installPath;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* COMPONENTS_FILES_WINE_HPP */
|
Loading…
x
Reference in New Issue
Block a user