diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 7ed79d07d1..9b8d3ba3b2 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -1,6 +1,9 @@ set(SRCS Analytics.cpp CDUtils.cpp ColorUtil.cpp + Config/Config.cpp + Config/Layer.cpp + Config/Section.cpp ENetUtil.cpp FileSearch.cpp FileUtil.cpp @@ -15,7 +18,6 @@ set(SRCS Analytics.cpp MsgHandler.cpp NandPaths.cpp Network.cpp - Config.cpp PcapFile.cpp PerformanceCounter.cpp Profiler.cpp diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 047b863443..756c30d473 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -53,6 +53,10 @@ + + + + @@ -123,7 +127,6 @@ - @@ -150,6 +153,9 @@ + + + @@ -173,7 +179,6 @@ - diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index 52625071a4..4ffd6c0575 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -34,6 +34,10 @@ + + + + @@ -53,7 +57,6 @@ - @@ -233,6 +236,9 @@ + + + @@ -246,7 +252,6 @@ - diff --git a/Source/Core/Common/Config.cpp b/Source/Core/Common/Config.cpp deleted file mode 100644 index eb88f79019..0000000000 --- a/Source/Core/Common/Config.cpp +++ /dev/null @@ -1,496 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include -#include -#include - -#include "Common/Assert.h" -#include "Common/Config.h" -#include "Common/StringUtil.h" - -namespace Config -{ -const std::string& Section::NULL_STRING = ""; -static Layers s_layers; -static std::list s_callbacks; - -void CallbackSystems(); - -// Only to be used with the meta-layer -class RecursiveSection final : public Section -{ -public: - RecursiveSection(LayerType layer, System system, const std::string& name) - : Section(layer, system, name) - { - } - - bool Exists(const std::string& key) const override; - - bool Get(const std::string& key, std::string* value, - const std::string& default_value = NULL_STRING) const override; - - void Set(const std::string& key, const std::string& value) override; -}; - -bool RecursiveSection::Exists(const std::string& key) const -{ - auto layers_it = s_layers.find(LayerType::Meta); - do - { - Section* layer_section = layers_it->second->GetSection(m_system, m_name); - if (layer_section && layer_section->Exists(key)) - { - return true; - } - } while (--layers_it != s_layers.end()); - - return false; -} - -bool RecursiveSection::Get(const std::string& key, std::string* value, - const std::string& default_value) const -{ - static const std::array search_order = {{ - // Skip the meta layer - LayerType::CurrentRun, LayerType::CommandLine, LayerType::Movie, LayerType::Netplay, - LayerType::LocalGame, LayerType::GlobalGame, LayerType::Base, - }}; - - for (auto layer_id : search_order) - { - auto layers_it = s_layers.find(layer_id); - if (layers_it == s_layers.end()) - continue; - - Section* layer_section = layers_it->second->GetSection(m_system, m_name); - if (layer_section && layer_section->Exists(key)) - { - return layer_section->Get(key, value, default_value); - } - } - - return Section::Get(key, value, default_value); -} - -void RecursiveSection::Set(const std::string& key, const std::string& value) -{ - // The RecursiveSection can't set since it is used to recursively get values from the layer - // map. - // It is only a part of the meta layer, and the meta layer isn't allowed to set any values. - _assert_msg_(COMMON, false, "Don't try to set values here!"); -} - -class RecursiveLayer final : public Layer -{ -public: - RecursiveLayer() : Layer(LayerType::Meta) {} - Section* GetSection(System system, const std::string& section_name) override; - Section* GetOrCreateSection(System system, const std::string& section_name) override; -}; - -Section* RecursiveLayer::GetSection(System system, const std::string& section_name) -{ - // Always queries backwards recursively, so it doesn't matter if it exists or not on this layer - return GetOrCreateSection(system, section_name); -} - -Section* RecursiveLayer::GetOrCreateSection(System system, const std::string& section_name) -{ - Section* section = Layer::GetSection(system, section_name); - if (!section) - { - m_sections[system].emplace_back(new RecursiveSection(m_layer, system, section_name)); - section = m_sections[system].back(); - } - return section; -} - -bool Section::Exists(const std::string& key) const -{ - return m_values.find(key) != m_values.end(); -} - -bool Section::Delete(const std::string& key) -{ - auto it = m_values.find(key); - if (it == m_values.end()) - return false; - - m_values.erase(it); - - m_deleted_keys.push_back(key); - m_dirty = true; - return true; -} - -void Section::Set(const std::string& key, const std::string& value) -{ - auto it = m_values.find(key); - if (it != m_values.end() && it->second != value) - { - it->second = value; - m_dirty = true; - } - else if (it == m_values.end()) - { - m_values[key] = value; - m_dirty = true; - } -} - -void Section::Set(const std::string& key, u32 newValue) -{ - Section::Set(key, StringFromFormat("0x%08x", newValue)); -} - -void Section::Set(const std::string& key, float newValue) -{ - Section::Set(key, StringFromFormat("%#.9g", newValue)); -} - -void Section::Set(const std::string& key, double newValue) -{ - Section::Set(key, StringFromFormat("%#.17g", newValue)); -} - -void Section::Set(const std::string& key, int newValue) -{ - Section::Set(key, StringFromInt(newValue)); -} - -void Section::Set(const std::string& key, bool newValue) -{ - Section::Set(key, StringFromBool(newValue)); -} - -void Section::Set(const std::string& key, const std::string& newValue, - const std::string& defaultValue) -{ - if (newValue != defaultValue) - Set(key, newValue); - else - Delete(key); -} - -void Section::SetLines(const std::vector& lines) -{ - m_lines = lines; - m_dirty = true; -} - -bool Section::Get(const std::string& key, std::string* value, - const std::string& default_value) const -{ - const auto& it = m_values.find(key); - if (it != m_values.end()) - { - *value = it->second; - return true; - } - else if (&default_value != &NULL_STRING) - { - *value = default_value; - return true; - } - - return false; -} - -bool Section::Get(const std::string& key, int* value, int defaultValue) const -{ - std::string temp; - bool retval = Get(key, &temp); - - if (retval && TryParse(temp, value)) - return true; - - *value = defaultValue; - return false; -} - -bool Section::Get(const std::string& key, u32* value, u32 defaultValue) const -{ - std::string temp; - bool retval = Get(key, &temp); - - if (retval && TryParse(temp, value)) - return true; - - *value = defaultValue; - return false; -} - -bool Section::Get(const std::string& key, bool* value, bool defaultValue) const -{ - std::string temp; - bool retval = Get(key, &temp); - - if (retval && TryParse(temp, value)) - return true; - - *value = defaultValue; - return false; -} - -bool Section::Get(const std::string& key, float* value, float defaultValue) const -{ - std::string temp; - bool retval = Get(key, &temp); - - if (retval && TryParse(temp, value)) - return true; - - *value = defaultValue; - return false; -} - -bool Section::Get(const std::string& key, double* value, double defaultValue) const -{ - std::string temp; - bool retval = Get(key, &temp); - - if (retval && TryParse(temp, value)) - return true; - - *value = defaultValue; - return false; -} - -// Return a list of all lines in a section -bool Section::GetLines(std::vector* lines, const bool remove_comments) const -{ - lines->clear(); - - for (std::string line : m_lines) - { - line = StripSpaces(line); - - if (remove_comments) - { - size_t commentPos = line.find('#'); - if (commentPos == 0) - { - continue; - } - - if (commentPos != std::string::npos) - { - line = StripSpaces(line.substr(0, commentPos)); - } - } - - lines->push_back(line); - } - - return true; -} - -// Onion layers -Layer::Layer(std::unique_ptr loader) - : m_layer(loader->GetLayer()), m_loader(std::move(loader)) -{ - Load(); -} - -Layer::~Layer() -{ - Save(); -} - -bool Layer::Exists(System system, const std::string& section_name, const std::string& key) -{ - Section* section = GetSection(system, section_name); - if (!section) - return false; - return section->Exists(key); -} - -bool Layer::DeleteKey(System system, const std::string& section_name, const std::string& key) -{ - Section* section = GetSection(system, section_name); - if (!section) - return false; - return section->Delete(key); -} - -Section* Layer::GetSection(System system, const std::string& section_name) -{ - for (Section* section : m_sections[system]) - if (!strcasecmp(section->m_name.c_str(), section_name.c_str())) - return section; - return nullptr; -} - -Section* Layer::GetOrCreateSection(System system, const std::string& section_name) -{ - Section* section = GetSection(system, section_name); - if (!section) - { - if (m_layer == LayerType::Meta) - m_sections[system].emplace_back(new RecursiveSection(m_layer, system, section_name)); - else - m_sections[system].emplace_back(new Section(m_layer, system, section_name)); - section = m_sections[system].back(); - } - return section; -} - -void Layer::Load() -{ - if (m_loader) - m_loader->Load(this); - ClearDirty(); - CallbackSystems(); -} - -void Layer::Save() -{ - if (!m_loader || !IsDirty()) - return; - - m_loader->Save(this); - ClearDirty(); - CallbackSystems(); -} - -bool Layer::IsDirty() const -{ - return std::any_of(m_sections.begin(), m_sections.end(), [](const auto& system) { - return std::any_of(system.second.begin(), system.second.end(), - [](const auto& section) { return section->IsDirty(); }); - }); -} - -void Layer::ClearDirty() -{ - std::for_each(m_sections.begin(), m_sections.end(), [](const auto& system) { - std::for_each(system.second.begin(), system.second.end(), - [](const auto& section) { section->ClearDirty(); }); - }); -} - -Section* GetOrCreateSection(System system, const std::string& section_name) -{ - return s_layers[LayerType::Meta]->GetOrCreateSection(system, section_name); -} - -Layers* GetLayers() -{ - return &s_layers; -} - -void AddLayer(std::unique_ptr layer) -{ - s_layers[layer->GetLayer()] = std::move(layer); - CallbackSystems(); -} - -void AddLayer(std::unique_ptr loader) -{ - AddLayer(std::make_unique(std::move(loader))); -} - -void AddLoadLayer(std::unique_ptr layer) -{ - layer->Load(); - AddLayer(std::move(layer)); -} - -void AddLoadLayer(std::unique_ptr loader) -{ - AddLoadLayer(std::make_unique(std::move(loader))); -} - -Layer* GetLayer(LayerType layer) -{ - if (!LayerExists(layer)) - return nullptr; - return s_layers[layer].get(); -} - -void RemoveLayer(LayerType layer) -{ - s_layers.erase(layer); - CallbackSystems(); -} -bool LayerExists(LayerType layer) -{ - return s_layers.find(layer) != s_layers.end(); -} - -void AddConfigChangedCallback(ConfigChangedCallback func) -{ - s_callbacks.emplace_back(func); -} - -void CallbackSystems() -{ - for (const auto& callback : s_callbacks) - callback(); -} - -// Explicit load and save of layers -void Load() -{ - for (auto& layer : s_layers) - layer.second->Load(); -} - -void Save() -{ - for (auto& layer : s_layers) - layer.second->Save(); -} - -void Init() -{ - // This layer always has to exist - s_layers[LayerType::Meta] = std::make_unique(); -} - -void Shutdown() -{ - s_layers.clear(); - s_callbacks.clear(); -} - -static std::map system_to_name = { - {System::Main, "Dolphin"}, {System::GCPad, "GCPad"}, {System::WiiPad, "Wiimote"}, - {System::GCKeyboard, "GCKeyboard"}, {System::GFX, "Graphics"}, {System::Logger, "Logger"}, - {System::Debugger, "Debugger"}, {System::UI, "UI"}, -}; - -const std::string& GetSystemName(System system) -{ - return system_to_name[system]; -} - -System GetSystemFromName(const std::string& system) -{ - for (auto& val : system_to_name) - if (val.second == system) - return val.first; - - _assert_msg_(COMMON, false, "Programming error! Couldn't convert '%s' to system!", - system.c_str()); - return System::Main; -} - -const std::string& GetLayerName(LayerType layer) -{ - static std::map layer_to_name = { - {LayerType::Base, "Base"}, - {LayerType::GlobalGame, "Global GameINI"}, - {LayerType::LocalGame, "Local GameINI"}, - {LayerType::Netplay, "Netplay"}, - {LayerType::Movie, "Movie"}, - {LayerType::CommandLine, "Command Line"}, - {LayerType::CurrentRun, "Current Run"}, - {LayerType::Meta, "Top"}, - }; - return layer_to_name[layer]; -} -} diff --git a/Source/Core/Common/Config.h b/Source/Core/Common/Config.h deleted file mode 100644 index cc880df5e2..0000000000 --- a/Source/Core/Common/Config.h +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include - -// XXX: Purely for case insensitive compare -#include "Common/IniFile.h" - -namespace Config -{ -enum class LayerType -{ - Base, - GlobalGame, - LocalGame, - Movie, - Netplay, - CommandLine, - CurrentRun, - Meta, -}; - -enum class System -{ - Main, - GCPad, - WiiPad, - GCKeyboard, - GFX, - Logger, - Debugger, - UI, -}; - -class Section; -class Layer; -class ConfigLayerLoader; - -using SectionValueMap = std::map; -using LayerMap = std::map>; -using Layers = std::map>; -using ConfigChangedCallback = std::function; - -class Section -{ - friend Layer; - friend ConfigLayerLoader; - -public: - Section(LayerType layer, System system, const std::string& name) - : m_layer(layer), m_system(system), m_name(name) - { - } - - virtual bool Exists(const std::string& key) const; - bool Delete(const std::string& key); - - // Setters - virtual void Set(const std::string& key, const std::string& value); - - void Set(const std::string& key, u32 newValue); - void Set(const std::string& key, float newValue); - void Set(const std::string& key, double newValue); - void Set(const std::string& key, int newValue); - void Set(const std::string& key, bool newValue); - - // Setters with default values - void Set(const std::string& key, const std::string& newValue, const std::string& defaultValue); - template - void Set(const std::string& key, T newValue, const T defaultValue) - { - if (newValue != defaultValue) - Set(key, newValue); - else - Delete(key); - } - - // Getters - virtual bool Get(const std::string& key, std::string* value, - const std::string& default_value = NULL_STRING) const; - - bool Get(const std::string& key, int* value, int defaultValue = 0) const; - bool Get(const std::string& key, u32* value, u32 defaultValue = 0) const; - bool Get(const std::string& key, bool* value, bool defaultValue = false) const; - bool Get(const std::string& key, float* value, float defaultValue = 0.0f) const; - bool Get(const std::string& key, double* value, double defaultValue = 0.0) const; - - template - T Get(const std::string& key, const T& default_value) const - { - T value; - Get(key, value, default_value); - return value; - } - - // Section chunk - void SetLines(const std::vector& lines); - // XXX: Add to recursive layer - virtual bool GetLines(std::vector* lines, const bool remove_comments = true) const; - virtual bool HasLines() const { return m_lines.size() > 0; } - const std::string& GetName() const { return m_name; } - const SectionValueMap& GetValues() const { return m_values; } - const std::vector& GetDeletedKeys() const { return m_deleted_keys; } - bool IsDirty() const { return m_dirty; } - void ClearDirty() { m_dirty = false; } -protected: - bool m_dirty = false; - - LayerType m_layer; - System m_system; - const std::string m_name; - static const std::string& NULL_STRING; - - SectionValueMap m_values; - std::vector m_deleted_keys; - - std::vector m_lines; -}; - -// XXX: Allow easy migration! -class ConfigLayerLoader -{ -public: - ConfigLayerLoader(LayerType layer) : m_layer(layer) {} - ~ConfigLayerLoader() {} - virtual void Load(Layer* config_layer) = 0; - virtual void Save(Layer* config_layer) = 0; - - LayerType GetLayer() const { return m_layer; } -private: - const LayerType m_layer; -}; - -class Layer -{ -public: - explicit Layer(LayerType layer) : m_layer(layer) {} - Layer(std::unique_ptr loader); - virtual ~Layer(); - - // Convenience functions - bool Exists(System system, const std::string& section_name, const std::string& key); - bool DeleteKey(System system, const std::string& section_name, const std::string& key); - template - bool GetIfExists(System system, const std::string& section_name, const std::string& key, T* value) - { - if (Exists(system, section_name, key)) - return GetOrCreateSection(system, section_name)->Get(key, value); - - return false; - } - - virtual Section* GetSection(System system, const std::string& section_name); - virtual Section* GetOrCreateSection(System system, const std::string& section_name); - - // Explicit load and save of layers - void Load(); - void Save(); - - LayerType GetLayer() const { return m_layer; } - const LayerMap& GetLayerMap() { return m_sections; } - // Stay away from this routine as much as possible - ConfigLayerLoader* GetLoader() { return m_loader.get(); } -protected: - bool IsDirty() const; - void ClearDirty(); - - LayerMap m_sections; - const LayerType m_layer; - std::unique_ptr m_loader; -}; - -// Common function used for getting configuration -Section* GetOrCreateSection(System system, const std::string& section_name); - -// Layer management -Layers* GetLayers(); -void AddLayer(std::unique_ptr layer); -void AddLayer(std::unique_ptr loader); -void AddLoadLayer(std::unique_ptr layer); -void AddLoadLayer(std::unique_ptr loader); -Layer* GetLayer(LayerType layer); -void RemoveLayer(LayerType layer); -bool LayerExists(LayerType layer); - -void AddConfigChangedCallback(ConfigChangedCallback func); - -// Explicit load and save of layers -void Load(); -void Save(); - -// Often used functions for getting or setting configuration on the base layer for the main system -template -T Get(const std::string& section_name, const std::string& key, const T& default_value) -{ - auto base_layer = GetLayer(Config::LayerType::Base); - return base_layer->GetOrCreateSection(Config::System::Main, section_name) - ->Get(key, default_value); -} - -template -void Set(const std::string& section_name, const std::string& key, const T& value) -{ - auto base_layer = GetLayer(Config::LayerType::Base); - base_layer->GetOrCreateSection(Config::System::Main, section_name)->Set(key, value); -} - -void Init(); -void Shutdown(); - -const std::string& GetSystemName(System system); -System GetSystemFromName(const std::string& system); -const std::string& GetLayerName(LayerType layer); -} diff --git a/Source/Core/Common/Config/Config.cpp b/Source/Core/Common/Config/Config.cpp new file mode 100644 index 0000000000..bcfb9a2619 --- /dev/null +++ b/Source/Core/Common/Config/Config.cpp @@ -0,0 +1,140 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/Assert.h" +#include "Common/Config/Config.h" + +namespace Config +{ +static Layers s_layers; +static std::list s_callbacks; + +void InvokeConfigChangedCallbacks(); + +Section* GetOrCreateSection(System system, const std::string& section_name) +{ + return s_layers[LayerType::Meta]->GetOrCreateSection(system, section_name); +} + +Layers* GetLayers() +{ + return &s_layers; +} + +void AddLayer(std::unique_ptr layer) +{ + s_layers[layer->GetLayer()] = std::move(layer); + InvokeConfigChangedCallbacks(); +} + +void AddLayer(std::unique_ptr loader) +{ + AddLayer(std::make_unique(std::move(loader))); +} + +void AddLoadLayer(std::unique_ptr layer) +{ + layer->Load(); + AddLayer(std::move(layer)); +} + +void AddLoadLayer(std::unique_ptr loader) +{ + AddLoadLayer(std::make_unique(std::move(loader))); +} + +Layer* GetLayer(LayerType layer) +{ + if (!LayerExists(layer)) + return nullptr; + return s_layers[layer].get(); +} + +void RemoveLayer(LayerType layer) +{ + s_layers.erase(layer); + InvokeConfigChangedCallbacks(); +} +bool LayerExists(LayerType layer) +{ + return s_layers.find(layer) != s_layers.end(); +} + +void AddConfigChangedCallback(ConfigChangedCallback func) +{ + s_callbacks.emplace_back(func); +} + +void InvokeConfigChangedCallbacks() +{ + for (const auto& callback : s_callbacks) + callback(); +} + +// Explicit load and save of layers +void Load() +{ + for (auto& layer : s_layers) + layer.second->Load(); +} + +void Save() +{ + for (auto& layer : s_layers) + layer.second->Save(); +} + +void Init() +{ + // This layer always has to exist + s_layers[LayerType::Meta] = std::make_unique(); +} + +void Shutdown() +{ + s_layers.clear(); + s_callbacks.clear(); +} + +static const std::map system_to_name = { + {System::Main, "Dolphin"}, {System::GCPad, "GCPad"}, {System::WiiPad, "Wiimote"}, + {System::GCKeyboard, "GCKeyboard"}, {System::GFX, "Graphics"}, {System::Logger, "Logger"}, + {System::Debugger, "Debugger"}, {System::UI, "UI"}, +}; + +const std::string& GetSystemName(System system) +{ + return system_to_name.at(system); +} + +System GetSystemFromName(const std::string& name) +{ + const auto system = std::find_if(system_to_name.begin(), system_to_name.end(), + [&name](const auto& entry) { return entry.second == name; }); + if (system != system_to_name.end()) + return system->first; + + _assert_msg_(COMMON, false, "Programming error! Couldn't convert '%s' to system!", name.c_str()); + return System::Main; +} + +const std::string& GetLayerName(LayerType layer) +{ + static const std::map layer_to_name = { + {LayerType::Base, "Base"}, + {LayerType::GlobalGame, "Global GameINI"}, + {LayerType::LocalGame, "Local GameINI"}, + {LayerType::Netplay, "Netplay"}, + {LayerType::Movie, "Movie"}, + {LayerType::CommandLine, "Command Line"}, + {LayerType::CurrentRun, "Current Run"}, + {LayerType::Meta, "Top"}, + }; + return layer_to_name.at(layer); +} +} diff --git a/Source/Core/Common/Config/Config.h b/Source/Core/Common/Config/Config.h new file mode 100644 index 0000000000..a46cd0de2d --- /dev/null +++ b/Source/Core/Common/Config/Config.h @@ -0,0 +1,63 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "Common/Config/Enums.h" +#include "Common/Config/Layer.h" +#include "Common/Config/Section.h" + +namespace Config +{ +using Layers = std::map>; +using ConfigChangedCallback = std::function; + +// Common function used for getting configuration +Section* GetOrCreateSection(System system, const std::string& section_name); + +// Layer management +Layers* GetLayers(); +void AddLayer(std::unique_ptr layer); +void AddLayer(std::unique_ptr loader); +void AddLoadLayer(std::unique_ptr layer); +void AddLoadLayer(std::unique_ptr loader); +Layer* GetLayer(LayerType layer); +void RemoveLayer(LayerType layer); +bool LayerExists(LayerType layer); + +void AddConfigChangedCallback(ConfigChangedCallback func); +void InvokeConfigChangedCallbacks(); + +// Explicit load and save of layers +void Load(); +void Save(); + +// Often used functions for getting or setting configuration on the base layer for the main system +template +T Get(const std::string& section_name, const std::string& key, const T& default_value) +{ + auto base_layer = GetLayer(Config::LayerType::Base); + return base_layer->GetOrCreateSection(Config::System::Main, section_name) + ->Get(key, default_value); +} + +template +void Set(const std::string& section_name, const std::string& key, const T& value) +{ + auto base_layer = GetLayer(Config::LayerType::Base); + base_layer->GetOrCreateSection(Config::System::Main, section_name)->Set(key, value); +} + +void Init(); +void Shutdown(); + +const std::string& GetSystemName(System system); +System GetSystemFromName(const std::string& system); +const std::string& GetLayerName(LayerType layer); +} diff --git a/Source/Core/Common/Config/Enums.h b/Source/Core/Common/Config/Enums.h new file mode 100644 index 0000000000..d5f866ff1e --- /dev/null +++ b/Source/Core/Common/Config/Enums.h @@ -0,0 +1,32 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +namespace Config +{ +enum class LayerType +{ + Base, + GlobalGame, + LocalGame, + Movie, + Netplay, + CommandLine, + CurrentRun, + Meta, +}; + +enum class System +{ + Main, + GCPad, + WiiPad, + GCKeyboard, + GFX, + Logger, + Debugger, + UI, +}; +} diff --git a/Source/Core/Common/Config/Layer.cpp b/Source/Core/Common/Config/Layer.cpp new file mode 100644 index 0000000000..ee5d5e2ad6 --- /dev/null +++ b/Source/Core/Common/Config/Layer.cpp @@ -0,0 +1,148 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/Config/Config.h" +#include "Common/Config/Layer.h" +#include "Common/Config/Section.h" + +namespace Config +{ +ConfigLayerLoader::ConfigLayerLoader(LayerType layer) : m_layer(layer) +{ +} + +ConfigLayerLoader::~ConfigLayerLoader() = default; + +LayerType ConfigLayerLoader::GetLayer() const +{ + return m_layer; +} + +Layer::Layer(LayerType type) : m_layer(type) +{ +} + +Layer::Layer(std::unique_ptr loader) + : m_layer(loader->GetLayer()), m_loader(std::move(loader)) +{ + Load(); +} + +Layer::~Layer() +{ + Save(); +} + +bool Layer::Exists(System system, const std::string& section_name, const std::string& key) +{ + Section* section = GetSection(system, section_name); + if (!section) + return false; + return section->Exists(key); +} + +bool Layer::DeleteKey(System system, const std::string& section_name, const std::string& key) +{ + Section* section = GetSection(system, section_name); + if (!section) + return false; + return section->Delete(key); +} + +Section* Layer::GetSection(System system, const std::string& section_name) +{ + for (auto& section : m_sections[system]) + if (!strcasecmp(section.m_name.c_str(), section_name.c_str())) + return §ion; + return nullptr; +} + +Section* Layer::GetOrCreateSection(System system, const std::string& section_name) +{ + Section* section = GetSection(system, section_name); + if (!section) + { + if (m_layer == LayerType::Meta) + m_sections[system].emplace_back(RecursiveSection(m_layer, system, section_name)); + else + m_sections[system].emplace_back(Section(m_layer, system, section_name)); + section = &m_sections[system].back(); + } + return section; +} + +void Layer::Load() +{ + if (m_loader) + m_loader->Load(this); + ClearDirty(); + InvokeConfigChangedCallbacks(); +} + +void Layer::Save() +{ + if (!m_loader || !IsDirty()) + return; + + m_loader->Save(this); + ClearDirty(); + InvokeConfigChangedCallbacks(); +} + +LayerType Layer::GetLayer() const +{ + return m_layer; +} + +const LayerMap& Layer::GetLayerMap() const +{ + return m_sections; +} + +ConfigLayerLoader* Layer::GetLoader() const +{ + return m_loader.get(); +} + +bool Layer::IsDirty() const +{ + return std::any_of(m_sections.begin(), m_sections.end(), [](const auto& system) { + return std::any_of(system.second.begin(), system.second.end(), + [](const auto& section) { return section.IsDirty(); }); + }); +} + +void Layer::ClearDirty() +{ + std::for_each(m_sections.begin(), m_sections.end(), [](auto& system) { + std::for_each(system.second.begin(), system.second.end(), + [](auto& section) { section.ClearDirty(); }); + }); +} + +RecursiveLayer::RecursiveLayer() : Layer(LayerType::Meta) +{ +} + +Section* RecursiveLayer::GetSection(System system, const std::string& section_name) +{ + // Always queries backwards recursively, so it doesn't matter if it exists or not on this layer + return GetOrCreateSection(system, section_name); +} + +Section* RecursiveLayer::GetOrCreateSection(System system, const std::string& section_name) +{ + Section* section = Layer::GetSection(system, section_name); + if (!section) + { + m_sections[system].emplace_back(RecursiveSection(m_layer, system, section_name)); + section = &m_sections[system].back(); + } + return section; +} +} diff --git a/Source/Core/Common/Config/Layer.h b/Source/Core/Common/Config/Layer.h new file mode 100644 index 0000000000..ade534ce02 --- /dev/null +++ b/Source/Core/Common/Config/Layer.h @@ -0,0 +1,80 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "Common/Config/Enums.h" +#include "Common/Config/Section.h" + +namespace Config +{ +using LayerMap = std::map>; + +class ConfigLayerLoader +{ +public: + explicit ConfigLayerLoader(LayerType layer); + virtual ~ConfigLayerLoader(); + virtual void Load(Layer* config_layer) = 0; + virtual void Save(Layer* config_layer) = 0; + + LayerType GetLayer() const; + +private: + const LayerType m_layer; +}; + +class Layer +{ +public: + explicit Layer(LayerType layer); + explicit Layer(std::unique_ptr loader); + virtual ~Layer(); + + // Convenience functions + bool Exists(System system, const std::string& section_name, const std::string& key); + bool DeleteKey(System system, const std::string& section_name, const std::string& key); + template + bool GetIfExists(System system, const std::string& section_name, const std::string& key, T* value) + { + if (Exists(system, section_name, key)) + return GetOrCreateSection(system, section_name)->Get(key, value); + + return false; + } + + virtual Section* GetSection(System system, const std::string& section_name); + virtual Section* GetOrCreateSection(System system, const std::string& section_name); + + // Explicit load and save of layers + void Load(); + void Save(); + + LayerType GetLayer() const; + const LayerMap& GetLayerMap() const; + // Stay away from this routine as much as possible + ConfigLayerLoader* GetLoader() const; + +protected: + bool IsDirty() const; + void ClearDirty(); + + LayerMap m_sections; + const LayerType m_layer; + std::unique_ptr m_loader; +}; + +class RecursiveLayer final : public Layer +{ +public: + RecursiveLayer(); + Section* GetSection(System system, const std::string& section_name) override; + Section* GetOrCreateSection(System system, const std::string& section_name) override; +}; +} diff --git a/Source/Core/Common/Config/Section.cpp b/Source/Core/Common/Config/Section.cpp new file mode 100644 index 0000000000..5c7f52eb63 --- /dev/null +++ b/Source/Core/Common/Config/Section.cpp @@ -0,0 +1,286 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include +#include + +#include "Common/Assert.h" +#include "Common/Config/Config.h" +#include "Common/Config/Layer.h" +#include "Common/Config/Section.h" +#include "Common/StringUtil.h" + +namespace Config +{ +const std::string& Section::NULL_STRING = ""; + +Section::Section(LayerType layer, System system, const std::string& name) + : m_layer(layer), m_system(system), m_name(name) +{ +} + +bool Section::Exists(const std::string& key) const +{ + return m_values.find(key) != m_values.end(); +} + +bool Section::Delete(const std::string& key) +{ + auto it = m_values.find(key); + if (it == m_values.end()) + return false; + + m_values.erase(it); + + m_deleted_keys.push_back(key); + m_dirty = true; + return true; +} + +void Section::Set(const std::string& key, const std::string& value) +{ + auto it = m_values.find(key); + if (it != m_values.end() && it->second != value) + { + it->second = value; + m_dirty = true; + } + else if (it == m_values.end()) + { + m_values[key] = value; + m_dirty = true; + } +} + +void Section::Set(const std::string& key, u32 newValue) +{ + Section::Set(key, StringFromFormat("0x%08x", newValue)); +} + +void Section::Set(const std::string& key, float newValue) +{ + Section::Set(key, StringFromFormat("%#.9g", newValue)); +} + +void Section::Set(const std::string& key, double newValue) +{ + Section::Set(key, StringFromFormat("%#.17g", newValue)); +} + +void Section::Set(const std::string& key, int newValue) +{ + Section::Set(key, StringFromInt(newValue)); +} + +void Section::Set(const std::string& key, bool newValue) +{ + Section::Set(key, StringFromBool(newValue)); +} + +void Section::Set(const std::string& key, const std::string& newValue, + const std::string& defaultValue) +{ + if (newValue != defaultValue) + Set(key, newValue); + else + Delete(key); +} + +void Section::SetLines(const std::vector& lines) +{ + m_lines = lines; + m_dirty = true; +} + +bool Section::Get(const std::string& key, std::string* value, + const std::string& default_value) const +{ + const auto& it = m_values.find(key); + if (it != m_values.end()) + { + *value = it->second; + return true; + } + else if (&default_value != &NULL_STRING) + { + *value = default_value; + return true; + } + + return false; +} + +bool Section::Get(const std::string& key, int* value, int defaultValue) const +{ + std::string temp; + bool retval = Get(key, &temp); + + if (retval && TryParse(temp, value)) + return true; + + *value = defaultValue; + return false; +} + +bool Section::Get(const std::string& key, u32* value, u32 defaultValue) const +{ + std::string temp; + bool retval = Get(key, &temp); + + if (retval && TryParse(temp, value)) + return true; + + *value = defaultValue; + return false; +} + +bool Section::Get(const std::string& key, bool* value, bool defaultValue) const +{ + std::string temp; + bool retval = Get(key, &temp); + + if (retval && TryParse(temp, value)) + return true; + + *value = defaultValue; + return false; +} + +bool Section::Get(const std::string& key, float* value, float defaultValue) const +{ + std::string temp; + bool retval = Get(key, &temp); + + if (retval && TryParse(temp, value)) + return true; + + *value = defaultValue; + return false; +} + +bool Section::Get(const std::string& key, double* value, double defaultValue) const +{ + std::string temp; + bool retval = Get(key, &temp); + + if (retval && TryParse(temp, value)) + return true; + + *value = defaultValue; + return false; +} + +// Return a list of all lines in a section +bool Section::GetLines(std::vector* lines, const bool remove_comments) const +{ + lines->clear(); + + for (std::string line : m_lines) + { + line = StripSpaces(line); + + if (remove_comments) + { + size_t commentPos = line.find('#'); + if (commentPos == 0) + { + continue; + } + + if (commentPos != std::string::npos) + { + line = StripSpaces(line.substr(0, commentPos)); + } + } + + lines->push_back(line); + } + + return true; +} + +bool Section::HasLines() const +{ + return !m_lines.empty(); +} + +const std::string& Section::GetName() const +{ + return m_name; +} + +const SectionValueMap& Section::GetValues() const +{ + return m_values; +} + +const std::vector& Section::GetDeletedKeys() const +{ + return m_deleted_keys; +} + +bool Section::IsDirty() const +{ + return m_dirty; +} +void Section::ClearDirty() +{ + m_dirty = false; +} + +RecursiveSection::RecursiveSection(LayerType layer, System system, const std::string& name) + : Section(layer, system, name) +{ +} + +bool RecursiveSection::Exists(const std::string& key) const +{ + auto layers_it = Config::GetLayers()->find(LayerType::Meta); + do + { + const Section* layer_section = layers_it->second->GetSection(m_system, m_name); + if (layer_section && layer_section->Exists(key)) + { + return true; + } + } while (--layers_it != Config::GetLayers()->end()); + + return false; +} + +bool RecursiveSection::Get(const std::string& key, std::string* value, + const std::string& default_value) const +{ + static constexpr std::array search_order = {{ + // Skip the meta layer + LayerType::CurrentRun, LayerType::CommandLine, LayerType::Movie, LayerType::Netplay, + LayerType::LocalGame, LayerType::GlobalGame, LayerType::Base, + }}; + + for (auto layer_id : search_order) + { + auto layers_it = Config::GetLayers()->find(layer_id); + if (layers_it == Config::GetLayers()->end()) + continue; + + const Section* layer_section = layers_it->second->GetSection(m_system, m_name); + if (layer_section && layer_section->Exists(key)) + { + return layer_section->Get(key, value, default_value); + } + } + + return Section::Get(key, value, default_value); +} + +void RecursiveSection::Set(const std::string& key, const std::string& value) +{ + // The RecursiveSection can't set since it is used to recursively get values from the layer + // map. + // It is only a part of the meta layer, and the meta layer isn't allowed to set any values. + _assert_msg_(COMMON, false, "Don't try to set values here!"); +} +} diff --git a/Source/Core/Common/Config/Section.h b/Source/Core/Common/Config/Section.h new file mode 100644 index 0000000000..4b4ba263ad --- /dev/null +++ b/Source/Core/Common/Config/Section.h @@ -0,0 +1,110 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +// XXX: Purely for case insensitive compare +#include "Common/CommonTypes.h" +#include "Common/Config/Enums.h" +#include "Common/IniFile.h" + +namespace Config +{ +class Layer; +class ConfigLayerLoader; + +using SectionValueMap = std::map; + +class Section +{ + friend Layer; + friend ConfigLayerLoader; + +public: + Section(LayerType layer, System system, const std::string& name); + + virtual bool Exists(const std::string& key) const; + bool Delete(const std::string& key); + + // Setters + virtual void Set(const std::string& key, const std::string& value); + + void Set(const std::string& key, u32 newValue); + void Set(const std::string& key, float newValue); + void Set(const std::string& key, double newValue); + void Set(const std::string& key, int newValue); + void Set(const std::string& key, bool newValue); + + // Setters with default values + void Set(const std::string& key, const std::string& newValue, const std::string& defaultValue); + template + void Set(const std::string& key, T newValue, const T defaultValue) + { + if (newValue != defaultValue) + Set(key, newValue); + else + Delete(key); + } + + // Getters + virtual bool Get(const std::string& key, std::string* value, + const std::string& default_value = NULL_STRING) const; + + bool Get(const std::string& key, int* value, int defaultValue = 0) const; + bool Get(const std::string& key, u32* value, u32 defaultValue = 0) const; + bool Get(const std::string& key, bool* value, bool defaultValue = false) const; + bool Get(const std::string& key, float* value, float defaultValue = 0.0f) const; + bool Get(const std::string& key, double* value, double defaultValue = 0.0) const; + + template + T Get(const std::string& key, const T& default_value) const + { + T value; + Get(key, value, default_value); + return value; + } + + // Section chunk + void SetLines(const std::vector& lines); + // XXX: Add to recursive layer + virtual bool GetLines(std::vector* lines, const bool remove_comments = true) const; + virtual bool HasLines() const; + const std::string& GetName() const; + const SectionValueMap& GetValues() const; + const std::vector& GetDeletedKeys() const; + bool IsDirty() const; + void ClearDirty(); + +protected: + bool m_dirty = false; + + LayerType m_layer; + System m_system; + const std::string m_name; + static const std::string& NULL_STRING; + + SectionValueMap m_values; + std::vector m_deleted_keys; + + std::vector m_lines; +}; + +// Only to be used with the meta-layer +class RecursiveSection final : public Section +{ +public: + RecursiveSection(LayerType layer, System system, const std::string& name); + + bool Exists(const std::string& key) const override; + + bool Get(const std::string& key, std::string* value, + const std::string& default_value = NULL_STRING) const override; + + void Set(const std::string& key, const std::string& value) override; +}; +}