From b409b5f7ccbe3734c26e96b38097de5566a80c44 Mon Sep 17 00:00:00 2001 From: Dmitry K Date: Wed, 18 Jan 2023 06:02:55 +0000 Subject: [PATCH] Added support for unicode paths (filesystem::path approach) --- LogManager.cpp | 9 ++-- LogManager.h | 3 +- OpenRGBPluginInterface.h | 3 +- PluginManager.cpp | 50 +++++++++++--------- PluginManager.h | 10 ++-- ProfileManager.cpp | 25 ++++++---- ProfileManager.h | 12 +++-- ResourceManager.cpp | 43 ++++++++--------- ResourceManager.h | 9 ++-- SettingsManager.cpp | 2 +- SettingsManager.h | 23 ++++----- cli.cpp | 45 +++++++++++++----- qt/OpenRGBPluginsPage/OpenRGBPluginsPage.cpp | 11 ++--- qt/OpenRGBSettingsPage.cpp | 2 +- 14 files changed, 143 insertions(+), 104 deletions(-) diff --git a/LogManager.cpp b/LogManager.cpp index 5af9d09c..43a1596d 100644 --- a/LogManager.cpp +++ b/LogManager.cpp @@ -46,7 +46,7 @@ unsigned int LogManager::getLoglevel() } } -void LogManager::configure(json config, const std::string &defaultDir) +void LogManager::configure(json config, const filesystem::path& defaultDir) { std::lock_guard grd(entry_mutex); @@ -92,11 +92,10 @@ void LogManager::configure(json config, const std::string &defaultDir) /*-------------------------------------------------*\ | If the path is relative, use logs dir | \*-------------------------------------------------*/ - filesystem::path p = logname; + filesystem::path p = filesystem::u8path(logname); if(p.is_relative()) { - p = defaultDir + "logs/"; - p.append(logname); + p = defaultDir / "logs" / logname; } filesystem::create_directories(p.parent_path()); @@ -351,4 +350,4 @@ void LogManager::UnregisterDialogShowCallback(LogDialogShowCallback callback, vo dialog_show_callback_args.erase(dialog_show_callback_args.begin() + idx); } } -} \ No newline at end of file +} diff --git a/LogManager.h b/LogManager.h index 626364bd..cb7b384b 100644 --- a/LogManager.h +++ b/LogManager.h @@ -7,6 +7,7 @@ #include #include #include "json.hpp" +#include "filesystem.h" /*-------------------------------------------------*\ | Common LOG strings | @@ -83,7 +84,7 @@ private: public: static LogManager* get(); - void configure(json config, const std::string& defaultDir); + void configure(json config, const filesystem::path & defaultDir); void flush(); void append(const char* filename, int line, unsigned int level, const char* fmt, ...); void setLoglevel(unsigned int); diff --git a/OpenRGBPluginInterface.h b/OpenRGBPluginInterface.h index 46cbef47..b3228c84 100644 --- a/OpenRGBPluginInterface.h +++ b/OpenRGBPluginInterface.h @@ -22,8 +22,9 @@ | 0: OpenRGB 0.6 Unversioned, early plugin API. | | 1: OpenRGB 0.61 First versioned API, introduced with plugin settings changes | | 2: OpenRGB 0.7 First released versioned API, callback unregister functions in ResourceManager | +| 3: OpenRGB 0.8 A minor change in the API that allows Unicode paths to be used | \*-----------------------------------------------------------------------------------------------------*/ -#define OPENRGB_PLUGIN_API_VERSION 2 +#define OPENRGB_PLUGIN_API_VERSION 3 /*-----------------------------------------------------------------------------------------------------*\ | Plugin Tab Location Values | diff --git a/PluginManager.cpp b/PluginManager.cpp index e71e1a69..7617905f 100644 --- a/PluginManager.cpp +++ b/PluginManager.cpp @@ -3,6 +3,18 @@ #include "PluginManager.h" #include "OpenRGBThemeManager.h" +// These two functions address the lack of a type-aware way to construct a QString +// Allows to avoid double conversions +static QString convertQPath(const std::string & filepath) +{ + return QString::fromStdString(filepath); +} +static QString convertQPath(const std::wstring & filepath) +{ + return QString::fromStdWString(filepath); +} + + PluginManager::PluginManager() { /*---------------------------------------------------------*\ @@ -16,7 +28,7 @@ PluginManager::PluginManager() /*-------------------------------------------------------------------------*\ | Create OpenRGB plugins directory | \*-------------------------------------------------------------------------*/ - std::string plugins_dir = ResourceManager::get()->GetConfigurationDirectory() + plugins_path; + filesystem::path plugins_dir = ResourceManager::get()->GetConfigurationDirectory() / plugins_path; filesystem::create_directories(plugins_dir); } @@ -41,7 +53,8 @@ void PluginManager::ScanAndLoadPlugins() | The plugins directory is a directory named "plugins" in | | the configuration directory | \*---------------------------------------------------------*/ - ScanAndLoadPluginsFrom(QString(ResourceManager::get()->GetConfigurationDirectory().c_str()).append(plugins_path)); + filesystem::path plugins_dir = ResourceManager::get()->GetConfigurationDirectory() / plugins_path; + ScanAndLoadPluginsFrom(plugins_dir); #ifdef OPENRGB_EXTRA_PLUGIN_DIRECTORY /*-----------------------------------------------------------------*\ @@ -52,33 +65,23 @@ void PluginManager::ScanAndLoadPlugins() #endif } -void PluginManager::ScanAndLoadPluginsFrom(QDir plugins_dir) +void PluginManager::ScanAndLoadPluginsFrom(const filesystem::path & plugins_dir) { - LOG_TRACE("[PluginManager] Scanning plugin directory: %s", plugins_dir.absolutePath().toStdString().c_str()); + LOG_TRACE("[PluginManager] Scanning plugin directory: %s", plugins_dir.generic_u8string().c_str()); /*---------------------------------------------------------*\ | Get a list of all files in the plugins directory | \*---------------------------------------------------------*/ - std::vector FileList; - for(int i = 0; i < QDir(plugins_dir).entryList(QDir::Files).size(); i++) + for(const filesystem::directory_entry& entry: filesystem::directory_iterator(plugins_dir)) { - LOG_TRACE("[PluginManager] Found plugin file %s", QDir(plugins_dir).entryList(QDir::Files)[i].toStdString().c_str()); - FileList.push_back(QDir(plugins_dir).entryList(QDir::Files)[i].toStdString()); - } - - /*---------------------------------------------------------*\ - | Attempt to load each file in the plugins directory | - \*---------------------------------------------------------*/ - for(const std::string &plugin_name : FileList) - { - const std::string plugin_path = plugins_dir.absoluteFilePath(QString().fromStdString(plugin_name)).toStdString(); - + filesystem::path plugin_path = entry.path(); + LOG_TRACE("[PluginManager] Found plugin file %s", plugin_path.filename().generic_u8string().c_str()); AddPlugin(plugin_path); } } -void PluginManager::AddPlugin(std::string path) +void PluginManager::AddPlugin(const filesystem::path& path) { OpenRGBPluginInterface* plugin = nullptr; @@ -103,7 +106,8 @@ void PluginManager::AddPlugin(std::string path) /*-----------------------------------------------------------------*\ | Create a QPluginLoader and load the plugin | \*-----------------------------------------------------------------*/ - QPluginLoader* loader = new QPluginLoader(QString().fromStdString(path)); + std::string path_string = path.generic_u8string(); + QPluginLoader* loader = new QPluginLoader(convertQPath(path_string)); QObject* instance = loader->instance(); /*-----------------------------------------------------------------*\ @@ -193,7 +197,7 @@ void PluginManager::AddPlugin(std::string path) entry.plugin = plugin; entry.loader = loader; entry.loaded = false; - entry.path = path; + entry.path = path_string; entry.enabled = enabled; entry.widget = nullptr; @@ -216,7 +220,7 @@ void PluginManager::AddPlugin(std::string path) } } -void PluginManager::RemovePlugin(std::string path) +void PluginManager::RemovePlugin(const filesystem::path& path) { unsigned int plugin_idx; @@ -257,7 +261,7 @@ void PluginManager::RemovePlugin(std::string path) ActivePlugins.erase(ActivePlugins.begin() + plugin_idx); } -void PluginManager::LoadPlugin(std::string path) +void PluginManager::LoadPlugin(const filesystem::path& path) { unsigned int plugin_idx; @@ -317,7 +321,7 @@ void PluginManager::LoadPlugin(std::string path) } } -void PluginManager::UnloadPlugin(std::string path) +void PluginManager::UnloadPlugin(const filesystem::path& path) { unsigned int plugin_idx; diff --git a/PluginManager.h b/PluginManager.h index 9f3d9d0c..6c12990c 100644 --- a/PluginManager.h +++ b/PluginManager.h @@ -36,18 +36,18 @@ public: void ScanAndLoadPlugins(); - void AddPlugin(std::string path); - void RemovePlugin(std::string path); + void AddPlugin(const filesystem::path& path); + void RemovePlugin(const filesystem::path& path); - void LoadPlugin(std::string path); - void UnloadPlugin(std::string path); + void LoadPlugin(const filesystem::path& path); + void UnloadPlugin(const filesystem::path& path); void UnloadPlugins(); std::vector ActivePlugins; private: - void ScanAndLoadPluginsFrom(QDir plugins_dir); + void ScanAndLoadPluginsFrom(const filesystem::path & plugins_dir); AddPluginCallback AddPluginCallbackVal; void * AddPluginCallbackArg; diff --git a/ProfileManager.cpp b/ProfileManager.cpp index 51399063..112205af 100644 --- a/ProfileManager.cpp +++ b/ProfileManager.cpp @@ -11,7 +11,7 @@ #define OPENRGB_PROFILE_HEADER "OPENRGB_PROFILE" #define OPENRGB_PROFILE_VERSION OPENRGB_SDK_PROTOCOL_VERSION -ProfileManager::ProfileManager(std::string config_dir) +ProfileManager::ProfileManager(const filesystem::path& config_dir) { configuration_directory = config_dir; UpdateProfileList(); @@ -54,7 +54,8 @@ bool ProfileManager::SaveProfile(std::string profile_name, bool sizes) /*---------------------------------------------------------*\ | Open an output file in binary mode | \*---------------------------------------------------------*/ - std::ofstream controller_file(configuration_directory + filename, std::ios::out | std::ios::binary | std::ios::trunc); + filesystem::path profile_path = configuration_directory / filesystem::u8path(filename); + std::ofstream controller_file(profile_path, std::ios::out | std::ios::binary | std::ios::trunc); /*---------------------------------------------------------*\ | Write header | @@ -98,7 +99,7 @@ bool ProfileManager::SaveProfile(std::string profile_name, bool sizes) } } -void ProfileManager::SetConfigurationDirectory(std::string directory) +void ProfileManager::SetConfigurationDirectory(const filesystem::path& directory) { configuration_directory = directory; UpdateProfileList(); @@ -124,18 +125,21 @@ std::vector ProfileManager::LoadProfileToList unsigned int controller_size; unsigned int controller_offset = 0; - std::string filename = configuration_directory + profile_name; + filesystem::path filename = configuration_directory / filesystem::u8path(profile_name); /*---------------------------------------------------------*\ | Determine file extension | \*---------------------------------------------------------*/ if(sizes) { - filename += ".ors"; + filename.concat(".ors"); } else { - filename += ((filename.substr(filename.size() - 4)==".orp") ? "" : ".orp"); + if(filename.extension() != ".orp") + { + filename.concat(".orp"); + } } /*---------------------------------------------------------*\ @@ -386,7 +390,10 @@ bool ProfileManager::LoadProfileWithOptions void ProfileManager::DeleteProfile(std::string profile_name) { - remove((configuration_directory + profile_name + ".orp").c_str()); + filesystem::path filename = configuration_directory / profile_name; + filename.concat(".orp"); + + filesystem::remove(filename); UpdateProfileList(); } @@ -409,7 +416,9 @@ void ProfileManager::UpdateProfileList() /*---------------------------------------------------------*\ | Open input file in binary mode | \*---------------------------------------------------------*/ - std::ifstream profile_file(configuration_directory + filename, std::ios::in | std::ios::binary); + filesystem::path file_path = configuration_directory; + file_path.append(filename); + std::ifstream profile_file(file_path, std::ios::in | std::ios::binary); /*---------------------------------------------------------*\ | Read and verify file header | diff --git a/ProfileManager.h b/ProfileManager.h index e72b7f1b..793d1d29 100644 --- a/ProfileManager.h +++ b/ProfileManager.h @@ -1,6 +1,8 @@ +#pragma once + #include "RGBController.h" -#pragma once +#include "filesystem.h" class ProfileManagerInterface { @@ -32,7 +34,7 @@ public: bool sizes = false ) = 0; - virtual void SetConfigurationDirectory(std::string directory) = 0; + virtual void SetConfigurationDirectory(const filesystem::path& directory) = 0; protected: virtual ~ProfileManagerInterface() {}; }; @@ -40,7 +42,7 @@ protected: class ProfileManager: public ProfileManagerInterface { public: - ProfileManager(std::string config_dir); + ProfileManager(const filesystem::path& config_dir); ~ProfileManager(); bool SaveProfile @@ -70,10 +72,10 @@ public: bool sizes = false ); - void SetConfigurationDirectory(std::string directory); + void SetConfigurationDirectory(const filesystem::path& directory); private: - std::string configuration_directory; + filesystem::path configuration_directory; void UpdateProfileList(); bool LoadProfileWithOptions diff --git a/ResourceManager.cpp b/ResourceManager.cpp index 56fee63f..0b768db5 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -14,6 +14,11 @@ #include "LogManager.h" #include "filesystem.h" +#ifdef _WIN32 +#include +#include +#endif + #include #include #include @@ -50,7 +55,8 @@ ResourceManager::ResourceManager() | Load settings from file | \*-------------------------------------------------------------------------*/ settings_manager = new SettingsManager(); - settings_manager->LoadSettings(GetConfigurationDirectory() + "OpenRGB.json"); + + settings_manager->LoadSettings(GetConfigurationDirectory() / "OpenRGB.json"); /*-------------------------------------------------------------------------*\ | Configure the log manager | @@ -448,10 +454,15 @@ void ResourceManager::I2CBusListChanged() void ResourceManager::SetupConfigurationDirectory() { config_dir.clear(); +#ifdef _WIN32 + const wchar_t* appdata = _wgetenv(L"APPDATA"); + if(appdata != NULL) + { + config_dir = appdata; + } +#else const char* xdg_config_home = getenv("XDG_CONFIG_HOME"); const char* home = getenv("HOME"); - const char* appdata = getenv("APPDATA"); - /*-----------------------------------------------------*\ | Check both XDG_CONFIG_HOME and APPDATA environment | | variables. If neither exist, use current directory | @@ -460,22 +471,20 @@ void ResourceManager::SetupConfigurationDirectory() { config_dir = xdg_config_home; } - else if(appdata != NULL) - { - config_dir = appdata; - } else if(home != NULL) { config_dir = home; - config_dir = config_dir + "/.config"; + config_dir /= ".config"; } +#endif + /*-----------------------------------------------------*\ | If a configuration directory was found, append OpenRGB| \*-----------------------------------------------------*/ if(config_dir != "") { - config_dir = config_dir + "/OpenRGB/"; + config_dir.append("OpenRGB"); /*-------------------------------------------------------------------------*\ | Create OpenRGB configuration directory if it doesn't exist | @@ -488,25 +497,15 @@ void ResourceManager::SetupConfigurationDirectory() } } -std::string ResourceManager::GetConfigurationDirectory() +filesystem::path ResourceManager::GetConfigurationDirectory() { return(config_dir); } -void ResourceManager::SetConfigurationDirectory(std::string directory) +void ResourceManager::SetConfigurationDirectory(const filesystem::path &directory) { - /*-----------------------------------------------------*\ - | Ensure the directory string has a trailing slash | - \*-----------------------------------------------------*/ - const char separator = filesystem::path::preferred_separator; - - if(directory[directory.size() - 1] != separator) - { - directory += separator; - } - config_dir = directory; - settings_manager->LoadSettings(directory + "OpenRGB.json"); + settings_manager->LoadSettings(directory / "OpenRGB.json"); profile_manager->SetConfigurationDirectory(directory); rgb_controllers_sizes.clear(); diff --git a/ResourceManager.h b/ResourceManager.h index 65551faa..f9f3d9ff 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -23,6 +23,7 @@ #include "ProfileManager.h" #include "RGBController.h" #include "SettingsManager.h" +#include "filesystem.h" #define HID_INTERFACE_ANY -1 #define HID_USAGE_ANY -1 @@ -91,7 +92,7 @@ public: virtual unsigned int GetDetectionPercent() = 0; - virtual std::string GetConfigurationDirectory() = 0; + virtual filesystem::path GetConfigurationDirectory() = 0; virtual std::vector& GetClients() = 0; virtual NetworkServer* GetServer() = 0; @@ -152,7 +153,7 @@ public: unsigned int GetDetectionPercent(); const char* GetDetectionString(); - std::string GetConfigurationDirectory(); + filesystem::path GetConfigurationDirectory(); void RegisterNetworkClient(NetworkClient* new_client); void UnregisterNetworkClient(NetworkClient* network_client); @@ -163,7 +164,7 @@ public: ProfileManager* GetProfileManager(); SettingsManager* GetSettingsManager(); - void SetConfigurationDirectory(std::string directory); + void SetConfigurationDirectory(const filesystem::path &directory); void ProcessPreDetectionHooks(); void ProcessDynamicDetectors(); @@ -282,5 +283,5 @@ private: std::vector I2CBusListChangeCallbacks; std::vector I2CBusListChangeCallbackArgs; - std::string config_dir; + filesystem::path config_dir; }; diff --git a/SettingsManager.cpp b/SettingsManager.cpp index 467009e1..93a80410 100644 --- a/SettingsManager.cpp +++ b/SettingsManager.cpp @@ -50,7 +50,7 @@ void SettingsManager::SetSettings(std::string settings_key, json new_settings) settings_data[settings_key] = new_settings; } -void SettingsManager::LoadSettings(std::string filename) +void SettingsManager::LoadSettings(const filesystem::path& filename) { /*---------------------------------------------------------*\ | Clear any stored settings before loading | diff --git a/SettingsManager.h b/SettingsManager.h index 350e72c0..3e1e3e84 100644 --- a/SettingsManager.h +++ b/SettingsManager.h @@ -12,17 +12,18 @@ #pragma once #include "json.hpp" +#include "filesystem.h" using json = nlohmann::json; class SettingsManagerInterface { public: - virtual json GetSettings(std::string settings_key) = 0; - virtual void SetSettings(std::string settings_key, json new_settings) = 0; + virtual json GetSettings(std::string settings_key) = 0; + virtual void SetSettings(std::string settings_key, json new_settings) = 0; - virtual void LoadSettings(std::string filename) = 0; - virtual void SaveSettings() = 0; + virtual void LoadSettings(const filesystem::path& filename) = 0; + virtual void SaveSettings() = 0; protected: virtual ~SettingsManagerInterface() {}; @@ -34,14 +35,14 @@ public: SettingsManager(); ~SettingsManager(); - json GetSettings(std::string settings_key) override; - void SetSettings(std::string settings_key, json new_settings) override; + json GetSettings(std::string settings_key) override; + void SetSettings(std::string settings_key, json new_settings) override; - void LoadSettings(std::string filename) override; - void SaveSettings() override; + void LoadSettings(const filesystem::path& filename) override; + void SaveSettings() override; private: - json settings_data; - json settings_prototype; - std::string settings_filename; + json settings_data; + json settings_prototype; + filesystem::path settings_filename; }; diff --git a/cli.cpp b/cli.cpp index e2d019e8..264f21f5 100644 --- a/cli.cpp +++ b/cli.cpp @@ -1,8 +1,3 @@ -#include -#include -#include -#include -#include #include "OpenRGB.h" #include "AutoStart.h" #include "filesystem.h" @@ -15,11 +10,18 @@ #include "LogManager.h" #include "Colors.h" +#include +#include +#include +#include +#include + /*-------------------------------------------------------------*\ | Quirk for MSVC; which doesn't support this case-insensitive | | function | \*-------------------------------------------------------------*/ #ifdef _WIN32 +#include #define strcasecmp strcmpi #endif @@ -804,10 +806,16 @@ int ProcessOptions(int argc, char* argv[], Options* options, std::vectorhasDevice = false; options->profile_loaded = false; +#ifdef _WIN32 + int fake_argc; + wchar_t** argvw = CommandLineToArgvW(GetCommandLineW(), &fake_argc); +#endif + while(arg_index < argc) { std::string option = argv[arg_index]; std::string argument = ""; + filesystem::path arg_path; /*---------------------------------------------------------*\ | Handle options that take an argument | @@ -815,6 +823,11 @@ int ProcessOptions(int argc, char* argv[], Options* options, std::vectorprofile_loaded = OptionProfile(argument, rgb_controllers); + options->profile_loaded = OptionProfile(arg_path.generic_u8string(), rgb_controllers); arg_index++; } @@ -925,7 +938,7 @@ int ProcessOptions(int argc, char* argv[], Options* options, std::vectorSetConfigurationDirectory(argument); - LOG_INFO("Setting config directory to %s",argument.c_str()); + ResourceManager::get()->SetConfigurationDirectory(config_path); + LOG_INFO("Setting config directory to %s",argument.c_str()); // TODO: Use config_path in logs somehow } else { - LOG_ERROR("'%s' is not a valid directory",argument.c_str()); + LOG_ERROR("'%s' is not a valid directory",argument.c_str()); // TODO: Use config_path in logs somehow print_help = true; break; } diff --git a/qt/OpenRGBPluginsPage/OpenRGBPluginsPage.cpp b/qt/OpenRGBPluginsPage/OpenRGBPluginsPage.cpp index be34283e..29e4749e 100644 --- a/qt/OpenRGBPluginsPage/OpenRGBPluginsPage.cpp +++ b/qt/OpenRGBPluginsPage/OpenRGBPluginsPage.cpp @@ -107,9 +107,8 @@ void Ui::OpenRGBPluginsPage::on_InstallPluginButton_clicked() bool Ui::OpenRGBPluginsPage::InstallPlugin(std::string install_file) { - std::string from_path = install_file; - std::string to_path = ResourceManager::get()->GetConfigurationDirectory() + "plugins/"; - std::string to_file = to_path + filesystem::path(from_path).filename().string(); + filesystem::path from_path = filesystem::u8path(install_file); + filesystem::path to_path = ResourceManager::get()->GetConfigurationDirectory() / "plugins" / from_path.filename(); bool match = false; LOG_TRACE("[OpenRGBPluginsPage] Installing plugin %s", install_file.c_str()); @@ -119,7 +118,7 @@ bool Ui::OpenRGBPluginsPage::InstallPlugin(std::string install_file) \*-----------------------------------------------------*/ for(unsigned int plugin_idx = 0; plugin_idx < plugin_manager->ActivePlugins.size(); plugin_idx++) { - if(to_file == plugin_manager->ActivePlugins[plugin_idx].path) + if(to_path == plugin_manager->ActivePlugins[plugin_idx].path) { match = true; break; @@ -147,12 +146,12 @@ bool Ui::OpenRGBPluginsPage::InstallPlugin(std::string install_file) \*-----------------------------------------------------*/ try { - plugin_manager->RemovePlugin(to_file); + plugin_manager->RemovePlugin(to_path); LOG_TRACE("[OpenRGBPluginsPage] Copying from %s to %s", from_path.c_str(), to_path.c_str()); filesystem::copy(from_path, to_path, filesystem::copy_options::overwrite_existing); - plugin_manager->AddPlugin(to_file); + plugin_manager->AddPlugin(to_path); return true; } diff --git a/qt/OpenRGBSettingsPage.cpp b/qt/OpenRGBSettingsPage.cpp index c29e4553..67d19e3c 100644 --- a/qt/OpenRGBSettingsPage.cpp +++ b/qt/OpenRGBSettingsPage.cpp @@ -766,7 +766,7 @@ void OpenRGBSettingsPage::SaveSettings() void Ui::OpenRGBSettingsPage::on_OpenSettingsFolderButton_clicked() { - std::string config_dir = ResourceManager::get()->GetConfigurationDirectory(); + std::string config_dir = ResourceManager::get()->GetConfigurationDirectory().generic_u8string(); QUrl url = QUrl::fromLocalFile(QString::fromStdString(config_dir)); QDesktopServices::openUrl(url); }