forked from dolphin-emu/dolphin
		
	
		
			
	
	
		
			287 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			287 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | // Copyright 2017 Dolphin Emulator Project
 | ||
|  | // Licensed under GPLv2+
 | ||
|  | // Refer to the license.txt file included.
 | ||
|  | 
 | ||
|  | #include <array>
 | ||
|  | #include <cstddef>
 | ||
|  | #include <map>
 | ||
|  | #include <memory>
 | ||
|  | 
 | ||
|  | #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<std::string>& 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<std::string>* 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<std::string>& 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<LayerType, 7> 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!"); | ||
|  | } | ||
|  | } |