diff options
author | dec05eba <dec05eba@protonmail.com> | 2024-08-06 05:57:21 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2024-08-06 05:57:21 +0200 |
commit | 9f1fddc47ce10fbc65cdeaa70461063b9921434e (patch) | |
tree | e9a8f19fa2ea5445e62ac2f4f8a488c591805347 /src/Config.cpp | |
parent | b778fd7cc654f28a2bfe0ff74537f120241b289c (diff) |
Copy Config from gpu-screen-recorder-gtk, make it more modern and efficient with string_view and variant, use string_view in gsr info parsing
Diffstat (limited to 'src/Config.cpp')
-rw-r--r-- | src/Config.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100644 index 0000000..51f14f1 --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,153 @@ +#include "../include/Config.hpp" +#include <variant> +#include <limits.h> +#include <inttypes.h> +#include <libgen.h> + +namespace gsr { + #define FORMAT_I32 "%" PRIi32 + #define FORMAT_I64 "%" PRIi64 + #define FORMAT_U32 "%" PRIu32 + + using ConfigValue = std::variant<bool*, std::string*, int32_t*, ConfigHotkey*, std::vector<std::string>*>; + + static std::map<std::string_view, ConfigValue> get_config_options(Config &config) { + return { + {"main.record_area_option", &config.main_config.record_area_option}, + {"main.record_area_width", &config.main_config.record_area_width}, + {"main.record_area_height", &config.main_config.record_area_height}, + {"main.fps", &config.main_config.fps}, + {"main.merge_audio_tracks", &config.main_config.merge_audio_tracks}, + {"main.audio_input", &config.main_config.audio_input}, + {"main.color_range", &config.main_config.color_range}, + {"main.quality", &config.main_config.quality}, + {"main.codec", &config.main_config.video_codec}, + {"main.audio_codec", &config.main_config.audio_codec}, + {"main.framerate_mode", &config.main_config.framerate_mode}, + {"main.advanced_view", &config.main_config.advanced_view}, + {"main.overclock", &config.main_config.overclock}, + {"main.show_recording_started_notifications", &config.main_config.show_recording_started_notifications}, + {"main.show_recording_stopped_notifications", &config.main_config.show_recording_stopped_notifications}, + {"main.show_recording_saved_notifications", &config.main_config.show_recording_saved_notifications}, + {"main.record_cursor", &config.main_config.record_cursor}, + {"main.hide_window_when_recording", &config.main_config.hide_window_when_recording}, + {"main.software_encoding_warning_shown", &config.main_config.software_encoding_warning_shown}, + {"main.restore_portal_session", &config.main_config.restore_portal_session}, + + {"streaming.service", &config.streaming_config.streaming_service}, + {"streaming.youtube.key", &config.streaming_config.youtube.stream_key}, + {"streaming.twitch.key", &config.streaming_config.twitch.stream_key}, + {"streaming.custom.url", &config.streaming_config.custom.url}, + {"streaming.custom.container", &config.streaming_config.custom.container}, + {"streaming.start_stop_recording_hotkey", &config.streaming_config.start_stop_recording_hotkey}, + + {"record.save_directory", &config.record_config.save_directory}, + {"record.container", &config.record_config.container}, + {"record.start_stop_recording_hotkey", &config.record_config.start_stop_recording_hotkey}, + {"record.pause_unpause_recording_hotkey", &config.record_config.pause_unpause_recording_hotkey}, + + {"replay.save_directory", &config.replay_config.save_directory}, + {"replay.container", &config.replay_config.container}, + {"replay.time", &config.replay_config.replay_time}, + {"replay.start_stop_recording_hotkey", &config.replay_config.start_stop_recording_hotkey}, + {"replay.save_recording_hotkey", &config.replay_config.save_recording_hotkey} + }; + } + + Config read_config(bool &config_empty) { + Config config; + + const std::string config_path = get_config_dir() + "/config"; + std::string file_content; + if(!file_get_content(config_path.c_str(), file_content)) { + fprintf(stderr, "Warning: Failed to read config file: %s\n", config_path.c_str()); + config_empty = true; + return config; + } + + auto config_options = get_config_options(config); + + string_split_char(file_content, '\n', [&](std::string_view line) { + const std::optional<KeyValue> key_value = parse_key_value(line); + if(!key_value) { + fprintf(stderr, "Warning: Invalid config option format: %.*s\n", (int)line.size(), line.data()); + return true; + } + + if(key_value->key.empty() || key_value->value.empty()) + return true; + + auto it = config_options.find(key_value->key); + if(it == config_options.end()) + return true; + + if(std::holds_alternative<bool*>(it->second)) { + *std::get<bool*>(it->second) = key_value->value == "true"; + } else if(std::holds_alternative<std::string*>(it->second)) { + std::get<std::string*>(it->second)->assign(key_value->value.data(), key_value->value.size()); + } else if(std::holds_alternative<int32_t*>(it->second)) { + std::string value_str(key_value->value); + int32_t *value = std::get<int32_t*>(it->second); + if(sscanf(value_str.c_str(), FORMAT_I32, value) != 1) { + fprintf(stderr, "Warning: Invalid config option value for %.*s\n", (int)key_value->key.size(), key_value->key.data()); + *value = 0; + } + } else if(std::holds_alternative<ConfigHotkey*>(it->second)) { + std::string value_str(key_value->value); + ConfigHotkey *config_hotkey = std::get<ConfigHotkey*>(it->second); + if(sscanf(value_str.c_str(), FORMAT_I64 " " FORMAT_U32, &config_hotkey->keysym, &config_hotkey->modifiers) != 2) { + fprintf(stderr, "Warning: Invalid config option value for %.*s\n", (int)key_value->key.size(), key_value->key.data()); + config_hotkey->keysym = 0; + config_hotkey->modifiers = 0; + } + } else if(std::holds_alternative<ConfigHotkey*>(it->second)) { + std::string array_value(key_value->value); + std::get<std::vector<std::string>*>(it->second)->push_back(std::move(array_value)); + } + + return true; + }); + + return config; + } + + void save_config(Config &config) { + const std::string config_path = get_config_dir() + "/config"; + + char dir_tmp[PATH_MAX]; + snprintf(dir_tmp, sizeof(dir_tmp), "%s", config_path.c_str()); + char *dir = dirname(dir_tmp); + + if(create_directory_recursive(dir) != 0) { + fprintf(stderr, "Warning: Failed to create config directory: %s\n", dir); + return; + } + + FILE *file = fopen(config_path.c_str(), "wb"); + if(!file) { + fprintf(stderr, "Warning: Failed to create config file: %s\n", config_path.c_str()); + return; + } + + const auto config_options = get_config_options(config); + for(auto it : config_options) { + if(std::holds_alternative<bool*>(it.second)) { + fprintf(file, "%.*s %s\n", (int)it.first.size(), it.first.data(), *std::get<bool*>(it.second) ? "true" : "false"); + } else if(std::holds_alternative<std::string*>(it.second)) { + fprintf(file, "%.*s %s\n", (int)it.first.size(), it.first.data(), std::get<std::string*>(it.second)->c_str()); + } else if(std::holds_alternative<int32_t*>(it.second)) { + fprintf(file, "%.*s " FORMAT_I32 "\n", (int)it.first.size(), it.first.data(), *std::get<int32_t*>(it.second)); + } else if(std::holds_alternative<ConfigHotkey*>(it.second)) { + const ConfigHotkey *config_hotkey = std::get<ConfigHotkey*>(it.second); + fprintf(file, "%.*s " FORMAT_I64 " " FORMAT_U32 "\n", (int)it.first.size(), it.first.data(), config_hotkey->keysym, config_hotkey->modifiers); + } else if(std::holds_alternative<ConfigHotkey*>(it.second)) { + std::vector<std::string> *array = std::get<std::vector<std::string>*>(it.second); + for(const std::string &value : *array) { + fprintf(file, "%.*s %s\n", (int)it.first.size(), it.first.data(), value.c_str()); + } + } + } + + fclose(file); + } +}
\ No newline at end of file |