aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp')
-rw-r--r--src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp b/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp
new file mode 100644
index 0000000..37991b6
--- /dev/null
+++ b/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp
@@ -0,0 +1,170 @@
+#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);
+ }
+}