#pragma once // ------------------------------------------------------------------------------------------------ #include "Core/Common.hpp" // ------------------------------------------------------------------------------------------------ #include // ------------------------------------------------------------------------------------------------ namespace SqMod { /* ------------------------------------------------------------------------------------------------ * Allows the user to inspect the result of certain operations and act accordingly. */ class IniResult { private: // -------------------------------------------------------------------------------------------- String m_Action; // The action that was performed. SQInteger m_Result; // The internal result code. public: /* -------------------------------------------------------------------------------------------- * Construct with no specific action or result. */ IniResult() : m_Action("unknown action"), m_Result(SI_OK) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Construct with no specific result. */ explicit IniResult(const SQChar * action) : m_Action(!action ? _SC("") : action), m_Result(SI_OK) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Construct with no specific action. */ explicit IniResult(SQInteger result) : m_Action("unknown action"), m_Result(result) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Construct with specific action and result. */ IniResult(const SQChar * action, SQInteger result) : m_Action(!action ? _SC("") : action), m_Result(result) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Copy constructor. */ IniResult(const IniResult & o) = default; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~IniResult() = default; /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ IniResult & operator = (const IniResult & o) = default; /* -------------------------------------------------------------------------------------------- * Perform an equality comparison between two results. */ bool operator == (const IniResult & o) const { return (m_Result == o.m_Result); } /* -------------------------------------------------------------------------------------------- * Perform an inequality comparison between two results. */ bool operator != (const IniResult & o) const { return (m_Result != o.m_Result); } /* -------------------------------------------------------------------------------------------- * Implicit conversion to boolean for use in boolean operations. */ operator bool () const // NOLINT(google-explicit-constructor) { return (m_Result >= 0); } /* -------------------------------------------------------------------------------------------- * Used by the script engine to compare two instances of this type. */ SQMOD_NODISCARD int32_t Cmp(const IniResult & o) const { if (m_Result == o.m_Result) { return 0; } else if (m_Result > o.m_Result) { return 1; } else { return -1; } } /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ SQMOD_NODISCARD const SQChar * ToString() const { return m_Action.c_str(); } /* -------------------------------------------------------------------------------------------- * See whether this instance references a valid INI result. */ SQMOD_NODISCARD bool IsValid() const { return (m_Result >= 0); } /* -------------------------------------------------------------------------------------------- * Retrieve the associated action. */ SQMOD_NODISCARD const SQChar * GetAction() const { return m_Action.c_str(); } /* -------------------------------------------------------------------------------------------- * Retrieve the resulted code. */ SQMOD_NODISCARD SQInteger GetResult() const { return m_Result; } /* -------------------------------------------------------------------------------------------- * Retrieve the resulted code. */ void Check() const; }; /* ------------------------------------------------------------------------------------------------ * Manages a reference counted INI document instance. */ class IniDocumentRef { // -------------------------------------------------------------------------------------------- friend class IniDocument; public: // -------------------------------------------------------------------------------------------- typedef CSimpleIniA Type; // The managed type. // -------------------------------------------------------------------------------------------- typedef Type* Pointer; // Pointer to the managed type. typedef const Type* ConstPtr; // Constant pointer to the managed type. // -------------------------------------------------------------------------------------------- typedef Type& Reference; // Reference to the managed type. typedef const Type& ConstRef; // Constant reference to the managed type. // -------------------------------------------------------------------------------------------- typedef unsigned int Counter; // Reference counter type. /* -------------------------------------------------------------------------------------------- * Validate the document reference and throw an error if invalid. */ void Validate() const; private: // -------------------------------------------------------------------------------------------- Pointer m_Ptr; // The document reader, writer and manager instance. Counter* m_Ref; // Reference count to the managed instance. /* -------------------------------------------------------------------------------------------- * Grab a strong reference to a document instance. */ void Grab() { if (m_Ptr) { ++(*m_Ref); } } /* -------------------------------------------------------------------------------------------- * Drop a strong reference to a document instance. */ void Drop() { if (m_Ptr && --(*m_Ref) == 0) { delete m_Ptr; delete m_Ref; m_Ptr = nullptr; m_Ref = nullptr; } } /* -------------------------------------------------------------------------------------------- * Base constructor. */ IniDocumentRef(bool utf8, bool multikey, bool multiline) : m_Ptr(new Type(utf8, multikey, multiline)), m_Ref(new Counter(1)) { /* ... */ } public: /* -------------------------------------------------------------------------------------------- * Default constructor (null). */ IniDocumentRef() : m_Ptr(nullptr), m_Ref(nullptr) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Copy constructor. */ IniDocumentRef(const IniDocumentRef & o) : m_Ptr(o.m_Ptr), m_Ref(o.m_Ref) { Grab(); } /* -------------------------------------------------------------------------------------------- * Move constructor. */ IniDocumentRef(IniDocumentRef && o) noexcept : m_Ptr(o.m_Ptr), m_Ref(o.m_Ref) { o.m_Ptr = nullptr; o.m_Ref = nullptr; } /* -------------------------------------------------------------------------------------------- * Destructor. */ ~IniDocumentRef() { Drop(); } /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ IniDocumentRef & operator = (const IniDocumentRef & o) noexcept // NOLINT(bugprone-unhandled-self-assignment) { if (m_Ptr != o.m_Ptr) { Drop(); m_Ptr = o.m_Ptr; m_Ref = o.m_Ref; Grab(); } return *this; } /* -------------------------------------------------------------------------------------------- * Move assignment operator. */ IniDocumentRef & operator = (IniDocumentRef && o) noexcept { if (m_Ptr != o.m_Ptr) { m_Ptr = o.m_Ptr; m_Ref = o.m_Ref; o.m_Ptr = nullptr; o.m_Ref = nullptr; } return *this; } /* -------------------------------------------------------------------------------------------- * Perform an equality comparison between two document instances. */ bool operator == (const IniDocumentRef & o) const { return (m_Ptr == o.m_Ptr); } /* -------------------------------------------------------------------------------------------- * Perform an inequality comparison between two document instances. */ bool operator != (const IniDocumentRef & o) const { return (m_Ptr != o.m_Ptr); } /* -------------------------------------------------------------------------------------------- * Implicit conversion to boolean for use in boolean operations. */ operator bool () const // NOLINT(google-explicit-constructor) { return static_cast< bool >(m_Ptr); } /* -------------------------------------------------------------------------------------------- * Implicit conversion to the managed instance pointer. */ operator Pointer () // NOLINT(google-explicit-constructor) { return m_Ptr; } /* -------------------------------------------------------------------------------------------- * Implicit conversion to the managed instance pointer. */ operator ConstPtr () const // NOLINT(google-explicit-constructor) { return m_Ptr; } /* -------------------------------------------------------------------------------------------- * Implicit conversion to the managed instance reference. */ operator Reference () // NOLINT(google-explicit-constructor) { assert(m_Ptr); return *m_Ptr; } /* -------------------------------------------------------------------------------------------- * Implicit conversion to the managed instance reference. */ operator ConstRef () const // NOLINT(google-explicit-constructor) { assert(m_Ptr); return *m_Ptr; } /* -------------------------------------------------------------------------------------------- * Member operator for dereferencing the managed pointer. */ Pointer operator -> () const { assert(m_Ptr); return m_Ptr; } /* -------------------------------------------------------------------------------------------- * Indirection operator for obtaining a reference of the managed pointer. */ Reference operator * () const { assert(m_Ptr); return *m_Ptr; } /* -------------------------------------------------------------------------------------------- * Retrieve the number of active references to the managed instance. */ SQMOD_NODISCARD Counter Count() const { return (m_Ptr && m_Ref) ? (*m_Ref) : 0; } }; /* ------------------------------------------------------------------------------------------------ * Class that can access and iterate a series of entries in the INI document. */ class IniEntries { // -------------------------------------------------------------------------------------------- friend class IniDocument; protected: // -------------------------------------------------------------------------------------------- typedef IniDocumentRef::Type::TNamesDepend Container; // -------------------------------------------------------------------------------------------- typedef Container::iterator Iterator; /* -------------------------------------------------------------------------------------------- * Default constructor. */ IniEntries(const IniDocumentRef & ini, Container & list) // NOLINT(modernize-pass-by-value) : m_Doc(ini), m_List(), m_Elem() { m_List.swap(list); Reset(); } private: // --------------------------------------------------------------------------------------------- IniDocumentRef m_Doc; // The document that contains the elements. Container m_List; // The list of elements to iterate. Iterator m_Elem; // The currently processed element. public: /* -------------------------------------------------------------------------------------------- * Default constructor. (null) */ IniEntries() : m_Doc(), m_List(), m_Elem(m_List.end()) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Copy constructor. */ IniEntries(const IniEntries & o) : m_Doc(o.m_Doc), m_List(o.m_List), m_Elem() { Reset(); } /* -------------------------------------------------------------------------------------------- * Destructor. */ ~IniEntries() = default; /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ IniEntries & operator = (const IniEntries & o) { m_Doc = o.m_Doc; m_List = o.m_List; Reset(); return *this; } /* -------------------------------------------------------------------------------------------- * Used by the script engine to compare two instances of this type. */ SQMOD_NODISCARD int32_t Cmp(const IniEntries & o) const; /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ SQMOD_NODISCARD const SQChar * ToString() const { return GetItem(); } /* -------------------------------------------------------------------------------------------- * Return whether the current element is valid and can be accessed. */ SQMOD_NODISCARD bool IsValid() const { return !(m_List.empty() || m_Elem == m_List.end()); } /* -------------------------------------------------------------------------------------------- * Return whether the entry list is empty. */ SQMOD_NODISCARD bool IsEmpty() const { return m_List.empty(); } /* -------------------------------------------------------------------------------------------- * Return the number of active references to this document instance. */ SQMOD_NODISCARD uint32_t GetRefCount() const { return m_Doc.Count(); } /* -------------------------------------------------------------------------------------------- * Return the total entries in the list. */ SQMOD_NODISCARD int32_t GetSize() const { return static_cast< int32_t >(m_List.size()); } /* -------------------------------------------------------------------------------------------- * Reset the internal iterator to the first element. */ void Reset() { if (m_List.empty()) { m_Elem = m_List.end(); } else { m_Elem = m_List.begin(); } } /* -------------------------------------------------------------------------------------------- * Go to the next element. */ void Next(); /* -------------------------------------------------------------------------------------------- * Go to the previous element. */ void Prev(); /* -------------------------------------------------------------------------------------------- * Advance a certain number of elements. */ void Advance(int32_t n); /* -------------------------------------------------------------------------------------------- * Retreat a certain number of elements. */ void Retreat(int32_t n); /* -------------------------------------------------------------------------------------------- * Sort the entries using the default options. */ void Sort() { if (!m_List.empty()) { m_List.sort(IniDocumentRef::Type::Entry::KeyOrder()); } } /* -------------------------------------------------------------------------------------------- * Sort the entries by name of key only. */ void SortByKeyOrder() { if (!m_List.empty()) { m_List.sort(IniDocumentRef::Type::Entry::KeyOrder()); } } /* -------------------------------------------------------------------------------------------- * Sort the entries by their load order and then name of key. */ void SortByLoadOrder() { if (!m_List.empty()) { m_List.sort(IniDocumentRef::Type::Entry::LoadOrder()); } } /* -------------------------------------------------------------------------------------------- * Retrieve the string value of the current element item. */ SQMOD_NODISCARD const SQChar * GetItem() const; /* -------------------------------------------------------------------------------------------- * Retrieve the string value of the current element comment. */ SQMOD_NODISCARD const SQChar * GetComment() const; /* -------------------------------------------------------------------------------------------- * Retrieve the order of the current element. */ SQMOD_NODISCARD int32_t GetOrder() const; }; /* ------------------------------------------------------------------------------------------------ * Class that can read/write and alter the contents of INI files. */ class IniDocument { protected: // -------------------------------------------------------------------------------------------- typedef IniDocumentRef::Type::TNamesDepend Container; private: // --------------------------------------------------------------------------------------------- IniDocumentRef m_Doc; // The main INI document instance. public: /* -------------------------------------------------------------------------------------------- * Default constructor. */ IniDocument() : m_Doc(false, false, true) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Explicit constructor. */ explicit IniDocument(bool utf8) : m_Doc(utf8, false, true) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Explicit constructor. */ IniDocument(bool utf8, bool multikey) : m_Doc(utf8, multikey, true) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Explicit constructor. */ IniDocument(bool utf8, bool multikey, bool multiline) : m_Doc(utf8, multikey, multiline) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ IniDocument(const IniDocument & o) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~IniDocument() = default; /* -------------------------------------------------------------------------------------------- * Copy assignment operator. (disabled) */ IniDocument & operator = (const IniDocument & o) = delete; /* -------------------------------------------------------------------------------------------- * Used by the script engine to compare two instances of this type. */ SQMOD_NODISCARD int32_t Cmp(const IniDocument & o) const; /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ SQMOD_NODISCARD const SQChar * ToString() const // NOLINT(readability-convert-member-functions-to-static) { return _SC(""); } /* -------------------------------------------------------------------------------------------- * See whether this instance references a valid INI document. */ SQMOD_NODISCARD bool IsValid() const { return m_Doc; } /* -------------------------------------------------------------------------------------------- * Return the number of active references to this document instance. */ SQMOD_NODISCARD uint32_t GetRefCount() const { return m_Doc.Count(); } /* -------------------------------------------------------------------------------------------- * See whether any data has been loaded into this document. */ SQMOD_NODISCARD bool IsEmpty() const { return m_Doc->IsEmpty(); } /* -------------------------------------------------------------------------------------------- * Deallocate all memory stored by this document. */ void Reset() const { m_Doc->Reset(); } /* -------------------------------------------------------------------------------------------- * See whether the INI data is treated as unicode. */ SQMOD_NODISCARD bool GetUnicode() const { return m_Doc->IsUnicode(); } /* -------------------------------------------------------------------------------------------- * Set whether the INI data should be treated as unicode. */ void SetUnicode(bool toggle) { m_Doc->SetUnicode(toggle); } /* -------------------------------------------------------------------------------------------- * See whether multiple identical keys be permitted in the file. */ SQMOD_NODISCARD bool GetMultiKey() const { return m_Doc->IsMultiKey(); } /* -------------------------------------------------------------------------------------------- * Set whether multiple identical keys be permitted in the file. */ void SetMultiKey(bool toggle) { m_Doc->SetMultiKey(toggle); } /* -------------------------------------------------------------------------------------------- * See whether data values are permitted to span multiple lines in the file. */ SQMOD_NODISCARD bool GetMultiLine() const { return m_Doc->IsMultiLine(); } /* -------------------------------------------------------------------------------------------- * Set whether data values are permitted to span multiple lines in the file. */ void SetMultiLine(bool toggle) { m_Doc->SetMultiLine(toggle); } /* -------------------------------------------------------------------------------------------- * See whether spaces are added around the equals sign when writing key/value pairs out. */ SQMOD_NODISCARD bool GetSpaces() const { return m_Doc->UsingSpaces(); } /* -------------------------------------------------------------------------------------------- * Set whether spaces are added around the equals sign when writing key/value pairs out. */ void SetSpaces(bool toggle) { m_Doc->SetSpaces(toggle); } /* -------------------------------------------------------------------------------------------- * Load an INI file from disk into memory. */ IniResult LoadFile(const SQChar * filepath); /* -------------------------------------------------------------------------------------------- * Load INI file data direct from a string. (LoadString collides with the windows api) */ IniResult LoadData(const SQChar * source) { return LoadData(source, -1); } /* -------------------------------------------------------------------------------------------- * Load INI file data direct from a string. (LoadString collides with the windows api) */ IniResult LoadData(const SQChar * source, int32_t size); /* -------------------------------------------------------------------------------------------- * Save an INI file from memory to disk. */ IniResult SaveFile(const SQChar * filepath) { return SaveFile(filepath, true); } /* -------------------------------------------------------------------------------------------- * Save an INI file from memory to disk. */ IniResult SaveFile(const SQChar * filepath, bool signature); /* -------------------------------------------------------------------------------------------- * Save the INI data to a string. */ Object SaveData(bool signature); /* -------------------------------------------------------------------------------------------- * Retrieve all section names. */ SQMOD_NODISCARD IniEntries GetAllSections() const; /* -------------------------------------------------------------------------------------------- * Retrieve all unique key names in a section. */ SQMOD_NODISCARD IniEntries GetAllKeys(const SQChar * section) const; /* -------------------------------------------------------------------------------------------- * Retrieve all values for a specific key. */ SQMOD_NODISCARD IniEntries GetAllValues(const SQChar * section, const SQChar * key) const; /* -------------------------------------------------------------------------------------------- * Query the number of keys in a specific section. */ SQMOD_NODISCARD int32_t GetSectionSize(const SQChar * section) const; /* -------------------------------------------------------------------------------------------- * See whether a certain key has multiple instances. */ SQMOD_NODISCARD bool HasMultipleKeys(const SQChar * section, const SQChar * key) const; /* -------------------------------------------------------------------------------------------- * Retrieve the value for a specific key. */ SQMOD_NODISCARD const char * GetValue(const SQChar * section, const SQChar * key, const SQChar * def) const; /* -------------------------------------------------------------------------------------------- * Retrieve a numeric value for a specific key. */ SQMOD_NODISCARD SQInteger GetInteger(const SQChar * section, const SQChar * key, SQInteger def) const; /* -------------------------------------------------------------------------------------------- * Retrieve a numeric value for a specific key. */ SQMOD_NODISCARD SQFloat GetFloat(const SQChar * section, const SQChar * key, SQFloat def) const; /* -------------------------------------------------------------------------------------------- * Retrieve a boolean value for a specific key. */ SQMOD_NODISCARD bool GetBoolean(const SQChar * section, const SQChar * key, bool def) const; /* -------------------------------------------------------------------------------------------- * Add or update a section or value. */ IniResult SetValue(const SQChar * section, const SQChar * key, const SQChar * value) { return SetValue(section, key, value, false, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a section or value. */ IniResult SetValue(const SQChar * section, const SQChar * key, const SQChar * value, bool force) { return SetValue(section, key, value, force, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a section or value. */ IniResult SetValue(const SQChar * section, const SQChar * key, const SQChar * value, bool force, const SQChar * comment); /* -------------------------------------------------------------------------------------------- * Add or update a numeric value. */ IniResult SetInteger(const SQChar * section, const SQChar * key, SQInteger value) { return SetInteger(section, key, value, false, false, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a numeric value. */ IniResult SetInteger(const SQChar * section, const SQChar * key, SQInteger value, bool hex) { return SetInteger(section, key, value, hex, false, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a numeric value. */ IniResult SetInteger(const SQChar * section, const SQChar * key, SQInteger value, bool hex, bool force) { return SetInteger(section, key, value, hex, force, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a numeric value. */ IniResult SetInteger(const SQChar * section, const SQChar * key, SQInteger value, bool hex, bool force, const SQChar * comment); /* -------------------------------------------------------------------------------------------- * Add or update a double value. */ IniResult SetFloat(const SQChar * section, const SQChar * key, SQFloat value) { return SetFloat(section, key, value, false, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a double value. */ IniResult SetFloat(const SQChar * section, const SQChar * key, SQFloat value, bool force) { return SetFloat(section, key, value, force, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a double value. */ IniResult SetFloat(const SQChar * section, const SQChar * key, SQFloat value, bool force, const SQChar * comment); /* -------------------------------------------------------------------------------------------- * Add or update a double value. */ IniResult SetBoolean(const SQChar * section, const SQChar * key, bool value) { return SetBoolean(section, key, value, false, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a double value. */ IniResult SetBoolean(const SQChar * section, const SQChar * key, bool value, bool force) { return SetBoolean(section, key, value, force, nullptr); } /* -------------------------------------------------------------------------------------------- * Add or update a boolean value. */ IniResult SetBoolean(const SQChar * section, const SQChar * key, bool value, bool force, const SQChar * comment); /* -------------------------------------------------------------------------------------------- * Delete an entire section, or a key from a section. */ bool DeleteValue(const SQChar * section) { return DeleteValue(section, nullptr, nullptr, false); } /* -------------------------------------------------------------------------------------------- * Delete an entire section, or a key from a section. */ bool DeleteValue(const SQChar * section, const SQChar * key) { return DeleteValue(section, key, nullptr, false); } /* -------------------------------------------------------------------------------------------- * Delete an entire section, or a key from a section. */ bool DeleteValue(const SQChar * section, const SQChar * key, const SQChar * value) { return DeleteValue(section, key, value, false); } /* -------------------------------------------------------------------------------------------- * Delete an entire section, or a key from a section. */ bool DeleteValue(const SQChar * section, const SQChar * key, const SQChar * value, bool empty); }; } // Namespace:: SqMod