/* INI Processor - a small library which allows you parsing INI-files Copyright (c) 2015-2018 Vitaly Novichkov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INIPROCESSING_H #define INIPROCESSING_H #include #include #include #include #include #ifdef INI_PROCESSING_ALLOW_QT_TYPES #include #include #include #endif #include "ini_processing_variant.h" /** * @brief INI Processor - an utility which providing fast and flexible INI file parsing API */ class IniProcessing { public: /** * @brief Available error codes */ enum ErrCode { //! Everything is fine ERR_OK = 0, //! File not found or memory pointer is null ERR_NOFILE, //! Invalid section declaration syntax ERR_SECTION_SYNTAX, //! Invalid key declaration syntax ERR_KEY_SYNTAX, //! No available memory ERR_NO_MEMORY }; private: struct params { std::string filePath; bool opened; int lineWithError; ErrCode errorCode; bool modified; typedef std::unordered_map IniKeys; typedef std::unordered_map IniSections; IniSections iniData; IniKeys *currentGroup; std::string currentGroupName; } m_params; template friend void readNumArrHelper(IniProcessing* self, const char *key, TList &dest, const TList &defVal); bool parseHelper(char *data, size_t size); bool parseFile(const char *filename); bool parseMemory(char *mem, size_t size); inline params::IniKeys::iterator readHelper(const char *key, bool &ok) { if(!m_params.opened) return params::IniKeys::iterator(); if(!m_params.currentGroup) return params::IniKeys::iterator(); #ifndef CASE_SENSITIVE_KEYS std::string key1(key); for(char *iter = &key1[0]; *iter != '\0'; ++iter) *iter = (char)tolower(*iter); #endif params::IniKeys::iterator e = m_params.currentGroup->find(key1); if(e != m_params.currentGroup->end()) ok = true; return e; } void writeIniParam(const char *key, const std::string &value); public: IniProcessing(); IniProcessing(const char *iniFileName, int dummy = 0); IniProcessing(const std::string &iniFileName, int dummy = 0); #ifdef INI_PROCESSING_ALLOW_QT_TYPES IniProcessing(const QString &iniFileName, int dummy = 0); #endif IniProcessing(char *memory, size_t size); IniProcessing(const IniProcessing &ip); /** * @brief Open INI-file from disk and parse it * @param iniFileName full path to INI-file to parse * @return true if INI file has been passed, false if any error happen */ bool open(const std::string &iniFileName); /** * @brief Open raw INI-data from memory and parse it * @param memory pointer to memory block * @param size size of memory block to process * @return */ bool openMem(char *memory, size_t size); /** * @brief Clear all internal buffers and close the file */ void close(); /** * @brief Returns last happen error code * @return Error code */ ErrCode lastError(); /** * @brief Line number which contains error * @return line number wit herror */ int lineWithError(); /** * @brief State of INI Processor * @return true if any file is opened */ bool isOpened(); /** * @brief Select a section to process * @param groupName name of section to process * @return true if group exists and opened */ bool beginGroup(const std::string &groupName); /** * @brief Is this INI file contains section of specific name * @param groupName name of section * @return true if section is exists */ bool contains(const std::string &groupName); /** * @brief Currently opened file name * @return path to currently opened file */ std::string fileName(); /** * @brief Currently processing section * @return name of current section */ std::string group(); /** * @brief Get list of available groups * @return Array of strings */ std::vector childGroups(); /** * @brief Is current section contains specific key name * @param keyName name of key * @return true if key is presented in this section */ bool hasKey(const std::string &keyName); /** * @brief Get list of available keys in current groul * @return Array of strings */ std::vector allKeys(); /** * @brief Release current section to choice another for process */ void endGroup(); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, bool &dest, bool defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, unsigned char &dest, unsigned char defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, char &dest, char defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, unsigned short &dest, unsigned short defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, short &dest, short defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, unsigned int &dest, unsigned int defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, int &dest, int defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, unsigned long &dest, unsigned long defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, long &dest, long defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, unsigned long long &dest, unsigned long long defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, long long &dest, long long defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, float &dest, float defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, double &dest, double defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, long double &dest, long double defVal); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::string &dest, const std::string &defVal); #ifdef INI_PROCESSING_ALLOW_QT_TYPES /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QString &dest, const QString &defVal); #endif /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); #ifdef INI_PROCESSING_ALLOW_QT_TYPES /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QList &dest, const QList &defVal = QList()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); /** * @brief Retreive value by specific key and pass it via reference * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key */ void read(const char *key, QVector &dest, const QVector &defVal = QVector()); #endif //! Hash-table for the fast string to enum conversion typedef std::unordered_map StrEnumMap; template /** * @brief Retreive value by string-based enum key * @param [_IN] key name of key with value to retrieved * @param [_OUT] dest Reference to destination variable to store retrieved value * @param [_IN] defVal Default value for case of non-existing key * @param [_IN] enumMap */ void readEnum(const char *key, T &dest, T defVal, IniProcessing::StrEnumMap enumMap) { bool ok = false; params::IniKeys::iterator e = readHelper(key, ok); if(!ok) { dest = defVal; return; } StrEnumMap::iterator em = enumMap.find(e->second); if(em == enumMap.end()) { dest = defVal; return; } dest = static_cast(em->second); } /** * @brief QSettings-compatible way to retreive value * @param key key with value to retreive * @param defVal default value key * @return variant which contains a value */ IniProcessingVariant value(const char *key, const IniProcessingVariant &defVal = IniProcessingVariant()); void setValue(const char *key, unsigned short value); void setValue(const char *key, short value); void setValue(const char *key, unsigned int value); void setValue(const char *key, int value); void setValue(const char *key, unsigned long value); void setValue(const char *key, long value); void setValue(const char *key, unsigned long long value); void setValue(const char *key, long long value); void setValue(const char *key, float value); void setValue(const char *key, double value); void setValue(const char *key, long double value); template static inline std::string to_string_with_precision(const T a_value) { char buf[35]; memset(buf, 0, 35); snprintf(buf, 34, "%.15g", static_cast(a_value)); return buf; } template static inline std::string fromVector(const TList &value) { typedef typename TList::value_type T; std::string out; for(const T &f: value) { if(!out.empty()) out.push_back(','); if(std::is_same::value || std::is_same::value || std::is_same::value) out.append(to_string_with_precision(f)); else out.append(std::to_string(f)); } return out; } template void setValue(const char *key, const std::vector &value) { static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); writeIniParam(key, fromVector(value)); } void setValue(const char *key, const char *value); void setValue(const char *key, const std::string &value); #ifdef INI_PROCESSING_ALLOW_QT_TYPES void setValue(const char *key, const QString &value); template void setValue(const char *key, const QList &value) { static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); writeIniParam(key, fromVector(value)); } template void setValue(const char *key, const QVector &value) { static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); writeIniParam(key, fromVector(value)); } #endif /** * @brief Write INI file by the recently given file path * @return true if INI file was successfully written */ bool writeIniFile(); }; #endif // INIPROCESSING_H