#pragma once #include #include "ListBase.h" #include "StringBase.h" #include "ImmutableStringBase.h" #include "File.h" #include "BinaryReader.h" #include "BinaryWriter.h" namespace System { // Represents the type of setting we are using enum class SettingType : char { Boolean = 'B', Integer = 'I', Integer64 = 'L', String = 'S', ProtectedString = 'P' }; // Used to store a setting. class SettingsObject { public: SettingsObject(); SettingsObject(String Key, SettingType Type, uint8_t* Value); ~SettingsObject(); String Key; SettingType Type; union ValueUn { char* String; bool Boolean; uint32_t Integer; uint64_t Integer64; } Values; SettingsObject& operator=(SettingsObject Rhs) { Key = Rhs.Key; Type = Rhs.Type; if (Type == SettingType::String || Type == SettingType::ProtectedString) { if (this->Values.String) delete[] this->Values.String; auto Len = strlen(Rhs.Values.String); this->Values.String = new char[Len + 1]{}; std::memcpy(this->Values.String, Rhs.Values.String, Len); } else { this->Values.Integer64 = Rhs.Values.Integer64; } return *this; } bool operator==(SettingsObject Rhs) { // yes yes yes i know this is bad but it doesn't cause issues for me so who cares return Key == Rhs.Key && Type == Rhs.Type; } }; // Reads and writes configuration files. class Settings { public: Settings() = default; ~Settings() = default; _declspec(noinline) void SetBool(const imstring& Key, bool Value) { for (auto& Setting : _Settings) { if (Setting.Key == (const char*)Key) { Setting.Values.Boolean = Value; } } _Settings.EmplaceBack(Key, SettingType::Boolean, (uint8_t*)&Value); } _declspec(noinline) void SetInt(const imstring& Key, uint32_t Value) { for (auto& Setting : _Settings) { if (Setting.Key == (const char*)Key) { Setting.Values.Integer = Value; } } _Settings.EmplaceBack(Key, SettingType::Integer, (uint8_t*)&Value); } template _declspec(noinline) void Set(const imstring& Key, V && Value) { for (auto& Setting : _Settings) { if (Setting.Key == (const char*)Key) { if constexpr (T == SettingType::Boolean) Setting.Values.Boolean = Value; else if constexpr (T == SettingType::Integer) Setting.Values.Integer = Value; else if constexpr (T == SettingType::Integer64) Setting.Values.Integer64 = Value; else if constexpr (T == SettingType::ProtectedString || T == SettingType::String) { if (Setting.Values.String != NULL) delete[] Setting.Values.String; if constexpr (std::is_same::value) { Setting.Values.String = new char[Value.Length() + 1]{}; std::memcpy(Setting.Values.String, (const char*)Value, Value.Length()); } else { auto Len = strlen(Value); Setting.Values.String = new char[Len + 1]{}; std::memcpy(Setting.Values.String, Value, Len); } } return; } } if constexpr (T == SettingType::String) _Settings.EmplaceBack(Key, T, (uint8_t*)Value.ToCString()); else _Settings.EmplaceBack(Key, T, (uint8_t*)&Value); } template _declspec(noinline) bool Has(const imstring& Key) { SettingsObject* Value = nullptr; for (auto& Setting : _Settings) { if (Setting.Key == (const char*)Key) { Value = &Setting; break; } } return (Value != nullptr); } // for some reason the template one doesn't even check the type so what is the point in having it as a template? bool Has(const imstring& Key) { SettingsObject* Value = nullptr; for (auto& Setting : _Settings) { if (Setting.Key == (const char*)Key) { Value = &Setting; break; } } return (Value != nullptr); } template _declspec(noinline) void Remove(const imstring& Key) { for (SettingsObject& Setting : _Settings) { if (Setting.Key == (const char*)Key) { Setting = SettingsObject(); break; } } return; }; _declspec(noinline) bool GetBool(const imstring& Key) { SettingsObject* Value = nullptr; for (auto& Setting : _Settings) { if (Setting.Key == (const char*)Key) { Value = &Setting; break; } } if (Value) return Value->Values.Boolean; return false; } template _declspec(noinline) auto Get(const imstring& Key) { SettingsObject* Value = nullptr; for (auto& Setting : _Settings) { if (Setting.Key == (const char*)Key) { Value = &Setting; break; } } if constexpr (T == SettingType::Boolean) { if (Value) return (bool)Value->Values.Boolean; return (bool)false; } else if constexpr (T == SettingType::Integer) { if (Value) return (uint32_t)Value->Values.Integer; return (uint32_t)0; } else if constexpr (T == SettingType::Integer64) { if (Value) return (uint64_t)Value->Values.Integer64; return (uint64_t)0; } else if constexpr (T == SettingType::String || T == SettingType::ProtectedString) { if (Value) return (String)Value->Values.String; return (String)""; } } // Load the config file from the specified path. void Load(const String& Path); // Save the config file to the specified path. void Save(const String& Path); private: // Internal cached settings List _Settings; }; }