Added support for unicode paths (filesystem::path approach)

This commit is contained in:
Dmitry K 2023-01-18 06:02:55 +00:00 committed by Adam Honse
parent 351515f025
commit b409b5f7cc
14 changed files with 143 additions and 104 deletions

View file

@ -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<std::mutex> 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);
}
}
}
}

View file

@ -7,6 +7,7 @@
#include <queue>
#include <memory>
#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);

View file

@ -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 |

View file

@ -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<std::string> 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;

View file

@ -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<OpenRGBPluginEntry> ActivePlugins;
private:
void ScanAndLoadPluginsFrom(QDir plugins_dir);
void ScanAndLoadPluginsFrom(const filesystem::path & plugins_dir);
AddPluginCallback AddPluginCallbackVal;
void * AddPluginCallbackArg;

View file

@ -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<RGBController*> 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 |

View file

@ -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

View file

@ -14,6 +14,11 @@
#include "LogManager.h"
#include "filesystem.h"
#ifdef _WIN32
#include <codecvt>
#include <locale>
#endif
#include <stdlib.h>
#include <string>
#include <hidapi/hidapi.h>
@ -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();

View file

@ -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<NetworkClient*>& 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<I2CBusListChangeCallback> I2CBusListChangeCallbacks;
std::vector<void *> I2CBusListChangeCallbackArgs;
std::string config_dir;
filesystem::path config_dir;
};

View file

@ -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 |

View file

@ -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;
};

45
cli.cpp
View file

@ -1,8 +1,3 @@
#include <vector>
#include <cstring>
#include <string>
#include <tuple>
#include <iostream>
#include "OpenRGB.h"
#include "AutoStart.h"
#include "filesystem.h"
@ -15,11 +10,18 @@
#include "LogManager.h"
#include "Colors.h"
#include <vector>
#include <cstring>
#include <string>
#include <tuple>
#include <iostream>
/*-------------------------------------------------------------*\
| Quirk for MSVC; which doesn't support this case-insensitive |
| function |
\*-------------------------------------------------------------*/
#ifdef _WIN32
#include <shellapi.h>
#define strcasecmp strcmpi
#endif
@ -804,10 +806,16 @@ int ProcessOptions(int argc, char* argv[], Options* options, std::vector<RGBCont
options->hasDevice = 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::vector<RGBCont
if(arg_index + 1 < argc)
{
argument = argv[arg_index + 1];
#ifdef _WIN32
arg_path = argvw[arg_index + 1];
#else
arg_path = argument;
#endif
}
/*---------------------------------------------------------*\
@ -915,7 +928,7 @@ int ProcessOptions(int argc, char* argv[], Options* options, std::vector<RGBCont
\*---------------------------------------------------------*/
else if(option == "--profile" || option == "-p")
{
options->profile_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::vector<RGBCont
\*---------------------------------------------------------*/
else if(option == "--save-profile" || option == "-sp")
{
OptionSaveProfile(argument);
OptionSaveProfile(arg_path.generic_u8string());
arg_index++;
}
@ -1137,6 +1150,11 @@ unsigned int cli_pre_detection(int argc, char* argv[])
bool server_start = false;
bool print_help = false;
#ifdef _WIN32
int fake_argc;
wchar_t** argvw = CommandLineToArgvW(GetCommandLineW(), &fake_argc);
#endif
while(arg_index < argc)
{
std::string option = argv[arg_index];
@ -1168,15 +1186,20 @@ unsigned int cli_pre_detection(int argc, char* argv[])
{
cfg_args+= 2;
arg_index++;
#ifdef _WIN32
filesystem::path config_path(argvw[arg_index]);
#else
filesystem::path config_path(argument);
#endif
if(filesystem::is_directory(argument))
if(filesystem::is_directory(config_path))
{
ResourceManager::get()->SetConfigurationDirectory(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;
}

View file

@ -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;
}

View file

@ -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);
}