aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/dataloader/Dataloader_Windows.hpp
diff options
context:
space:
mode:
author Spartan322 <Megacake1234@gmail.com>2023-10-04 10:55:42 +0200
committer Spartan322 <Megacake1234@gmail.com>2023-10-12 16:18:37 +0200
commit5c7af98e3a8a3e7f1462e389c273566d7cdaa5d4 (patch)
treeefeebd80a707a07eda296883772140e9ce32a9ee /src/openvic-simulation/dataloader/Dataloader_Windows.hpp
parent1d113b46161f27551bc3a6a857b8727cfb657b81 (diff)
Add static `Dataloader::search_for_game_path(fs::path)`
Searches for Victoria 2 according to the supplied path If supplied path is empty, presumes Steam install according to platform environment variables If invalid supplied path, falls back to empty path behavior Supports Steam install on Windows, Mac, Linux, and FreeBSD Supports Windows registry Update .clang-format categories to include lexy-vdf Add Utility/ConstexprIntToStr.hpp
Diffstat (limited to 'src/openvic-simulation/dataloader/Dataloader_Windows.hpp')
-rw-r--r--src/openvic-simulation/dataloader/Dataloader_Windows.hpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/openvic-simulation/dataloader/Dataloader_Windows.hpp b/src/openvic-simulation/dataloader/Dataloader_Windows.hpp
new file mode 100644
index 0000000..f4abbb6
--- /dev/null
+++ b/src/openvic-simulation/dataloader/Dataloader_Windows.hpp
@@ -0,0 +1,162 @@
+#pragma once
+
+#include <concepts>
+#pragma comment(lib, "advapi32.lib")
+
+#include <string>
+#include <string_view>
+
+#include <Windows.h>
+
+namespace OpenVic::Windows {
+ inline std::wstring convert(std::string_view as) {
+ // deal with trivial case of empty string
+ if (as.empty()) return std::wstring();
+
+ // determine required length of new string
+ size_t length = ::MultiByteToWideChar(CP_UTF8, 0, as.data(), (int)as.length(), 0, 0);
+
+ // construct new string of required length
+ std::wstring ret(length, L'\0');
+
+ // convert old string to new string
+ ::MultiByteToWideChar(CP_UTF8, 0, as.data(), (int)as.length(), &ret[0], (int)ret.length());
+
+ // return new string ( compiler should optimize this away )
+ return ret;
+ }
+
+ inline std::string convert(std::wstring_view as) {
+ // deal with trivial case of empty string
+ if (as.empty()) return std::string();
+
+ // determine required length of new string
+ size_t length = ::WideCharToMultiByte(CP_UTF8, 0, as.data(), (int)as.length(), 0, 0, NULL, NULL);
+
+ // construct new string of required length
+ std::string ret(length, '\0');
+
+ // convert old string to new string
+ ::WideCharToMultiByte(CP_UTF8, 0, as.data(), (int)as.length(), &ret[0], (int)ret.length(), NULL, NULL);
+
+ // return new string ( compiler should optimize this away )
+ return ret;
+ }
+
+ template<typename T, typename... U>
+ concept any_of = (std::same_as<T, U> || ...);
+
+ template<typename T>
+ concept either_char_type = any_of<T, char, wchar_t>;
+
+ template<typename T>
+ concept has_data = requires(T t) {
+ { t.data() } -> std::convertible_to<const typename T::value_type*>;
+ };
+
+ class RegistryKey {
+ public:
+ RegistryKey(HKEY key_handle)
+ : _key_handle(key_handle) {
+ }
+
+ template<either_char_type CHAR_T, either_char_type CHAR_T2>
+ RegistryKey(HKEY parent_key_handle, std::basic_string_view<CHAR_T> child_key_name, std::basic_string_view<CHAR_T2> value_name) {
+ open_key(parent_key_handle, child_key_name);
+ query_key(value_name);
+ }
+
+ ~RegistryKey() {
+ close_key();
+ }
+
+ bool is_open() const {
+ return _key_handle != nullptr;
+ }
+
+ std::wstring_view value() const {
+ return _value;
+ }
+
+ template<either_char_type CHAR_T>
+ LSTATUS open_key(HKEY parent_key_handle, std::basic_string_view<CHAR_T> key_path) {
+ if (is_open())
+ close_key();
+ if constexpr (std::is_same_v<CHAR_T, char>)
+ return RegOpenKeyExW(parent_key_handle, convert(key_path).data(), REG_NONE, KEY_READ, &_key_handle);
+ else
+ return RegOpenKeyExW(parent_key_handle, key_path.data(), REG_NONE, KEY_READ, &_key_handle);
+ }
+
+ bool is_predefined() const {
+ return (_key_handle == HKEY_CURRENT_USER) ||
+ (_key_handle == HKEY_LOCAL_MACHINE) ||
+ (_key_handle == HKEY_CLASSES_ROOT) ||
+ (_key_handle == HKEY_CURRENT_CONFIG) ||
+ (_key_handle == HKEY_CURRENT_USER_LOCAL_SETTINGS) ||
+ (_key_handle == HKEY_PERFORMANCE_DATA) ||
+ (_key_handle == HKEY_PERFORMANCE_NLSTEXT) ||
+ (_key_handle == HKEY_PERFORMANCE_TEXT) ||
+ (_key_handle == HKEY_USERS);
+ }
+
+ LSTATUS close_key() {
+ if (!is_open() || is_predefined())
+ return ERROR_SUCCESS;
+ auto result = RegCloseKey(_key_handle);
+ _key_handle = nullptr;
+ return result;
+ }
+
+ template<either_char_type CHAR_T>
+ LSTATUS query_key(std::basic_string_view<CHAR_T> value_name) {
+ DWORD data_size;
+ DWORD type;
+
+ const auto& wide_value = [&value_name]() -> has_data auto {
+ if constexpr (std::is_same_v<CHAR_T, char>) {
+ return convert(value_name);
+ } else {
+ return value_name;
+ }
+ }();
+
+ auto result = RegQueryValueExW(_key_handle, wide_value.data(), NULL, &type, NULL, &data_size);
+ if (result != ERROR_SUCCESS || type != REG_SZ) {
+ close_key();
+ return result;
+ }
+ _value = std::wstring(data_size / sizeof(wchar_t), L'\0');
+ result = RegQueryValueExW(_key_handle, wide_value.data(), NULL, NULL, reinterpret_cast<LPBYTE>(_value.data()), &data_size);
+ close_key();
+
+ std::size_t first_null = _value.find_first_of(L'\0');
+ if (first_null != std::string::npos)
+ _value.resize(first_null);
+
+ return result;
+ }
+
+ private:
+ HKEY _key_handle = nullptr;
+ std::wstring _value;
+ };
+
+ template<either_char_type RCHAR_T, either_char_type CHAR_T, either_char_type CHAR_T2>
+ std::basic_string<RCHAR_T> ReadRegValue(HKEY root, std::basic_string_view<CHAR_T> key, std::basic_string_view<CHAR_T2> name) {
+ RegistryKey registry_key(root, key, name);
+ if constexpr (std::is_same_v<RCHAR_T, char>) {
+ return convert(registry_key.value());
+ } else {
+ return registry_key.value();
+ }
+ }
+
+ template<either_char_type RCHAR_T, either_char_type CHAR_T, either_char_type CHAR_T2>
+ std::basic_string<RCHAR_T> ReadRegValue(HKEY root, const CHAR_T* key, const CHAR_T2* name) {
+ auto key_sv = std::basic_string_view(key);
+ auto name_sv = std::basic_string_view(name);
+
+ return ReadRegValue<RCHAR_T>(root, key_sv, name_sv);
+ }
+} \ No newline at end of file