/
githubmirror
/
x64dbg
Обзор
Документация
Войти
/
githubmirror
/
x64dbg
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
development
src/bridge/Utf8Ini.h
367 строк
10 KB
Duncan Ogilvie
BRIDGE: remove a bunch of useless return std::move(...)
11 июл 2020, 22:41
11 июл 2020, 22:41
af31d9d
Код
Авторство
О чём код?
#ifndef UTF8INI_H #define UTF8INI_H #include <string> #include <map> #include <vector> class Utf8Ini { public: /** \brief Serialize to the INI file format. */ inline std::string Serialize() const { std::string output; for(const auto & section : mSections) { if(output.length()) appendLine(output, ""); appendLine(output, makeSectionText(section.first)); for(const auto & keyvalue : section.second) if(keyvalue.first.length()) appendLine(output, makeKeyValueText(keyvalue.first, keyvalue.second)); } return output; } /** \brief Deserialize from the INI file format. \param data The INI data. \param [out] errorLine The error line (only has a meaning when this function failed). \return true if it succeeds, false if it fails. */ inline bool Deserialize(const std::string & data, int & errorLine) { //initialize errorLine = 0; Clear(); //read lines std::vector<std::string> lines; std::string curLine; for(auto ch : data) { switch(ch) { case '\r': break; case '\n': lines.push_back(trim(curLine)); curLine.clear(); break; default: curLine += ch; } } if(curLine.length()) lines.push_back(trim(curLine)); //parse lines std::string section = ""; for(const auto & line : lines) { errorLine++; switch(getLineType(line)) { case LineType::Invalid: return false; case LineType::Comment: case LineType::Empty: continue; case LineType::KeyValue: { std::string key; std::string value; if(!section.length() || !parseKeyValueLine(line, key, value) || !SetValue(section, key, value)) return false; } break; case LineType::Section: { if(!parseSectionLine(line, section)) return false; } break; default: return false; } } return true; } /** \brief Sets a value. This will overwrite older values. \param section The section. Must have a length greater than one. \param key The key. Must have a length greater than one. \param value The value. Can be empty (effectively removing the value). \return true if the value was set successfully, false otherwise. */ inline bool SetValue(const std::string & section, const std::string & key, const std::string & value) { auto trimmedSection = trim(section); auto trimmedKey = trim(key); if(!trimmedSection.length() || !trimmedKey.length()) return false; auto found = mSections.find(trimmedSection); if(found != mSections.end()) found->second[std::move(trimmedKey)] = value; else { KeyValueMap keyValueMap; keyValueMap.emplace(std::move(trimmedKey), value); mSections.emplace(std::move(trimmedSection), std::move(keyValueMap)); } return true; } /** \brief Removes all key/value pairs from a section. \param section The section to clear. \return true if it succeeds, false otherwise. */ inline bool ClearSection(const std::string & section) { auto trimmedSection = trim(section); if(!trimmedSection.length()) return false; auto found = mSections.find(trimmedSection); if(found == mSections.end()) return false; mSections.erase(found); return true; } /** \brief Removes all sections. */ inline void Clear() { mSections.clear(); } /** \brief Gets a value. \param section The section. \param key The key. \return The value. Empty string when the value was not found or empty. */ inline std::string GetValue(const std::string & section, const std::string & key) const { auto trimmedSection = trim(section); auto trimmedKey = trim(key); if(!trimmedSection.length() || !trimmedKey.length()) return ""; auto sectionFound = mSections.find(trimmedSection); if(sectionFound == mSections.end()) return ""; const auto & keyValueMap = sectionFound->second; auto keyFound = keyValueMap.find(trimmedKey); if(keyFound == keyValueMap.end()) return ""; return keyFound->second; } /** \brief Gets the section names. \return List of section names. */ inline std::vector<std::string> Sections() const { std::vector<std::string> sections; sections.reserve(mSections.size()); for(const auto & section : mSections) sections.push_back(section.first); return sections; } /** \brief Gets keys in a given section. \param section The section. \return List of keys in the section. Empty if the section is not found or empty. */ inline std::vector<std::string> Keys(const std::string & section) const { std::vector<std::string> keys; auto trimmedSection = trim(section); if(trimmedSection.length()) { auto found = mSections.find(trimmedSection); if(found != mSections.end()) { keys.reserve(found->second.size()); for(const auto & key : found->second) keys.push_back(key.first); } } return keys; } private: typedef std::map<std::string, std::string> KeyValueMap; std::map<std::string, KeyValueMap> mSections; enum class LineType { Invalid, Empty, Section, KeyValue, Comment }; static inline LineType getLineType(const std::string & line) { auto len = line.length(); if(!len) return LineType::Empty; if(line[0] == '[' && line[len - 1] == ']') return LineType::Section; if(line[0] == ';') return LineType::Comment; if(line.find('=') != std::string::npos) return LineType::KeyValue; return LineType::Invalid; } static inline std::string trim(const std::string & str) { auto len = str.length(); if(!len) return ""; size_t pre = 0; while(str[pre] == ' ') pre++; size_t post = 0; while(str[len - post - 1] == ' ' && post < len) post++; auto sublen = len - post - pre; return sublen > 0 ? str.substr(pre, len - post - pre) : ""; } static inline bool parseKeyValueLine(const std::string & line, std::string & key, std::string & value) { auto pos = line.find('='); key = trim(line.substr(0, pos)); value = trim(line.substr(pos + 1)); auto len = value.length(); if(len && value[0] == '\"' && value[len - 1] == '\"') value = unescapeValue(value); return true; } static inline bool parseSectionLine(const std::string & line, std::string & section) { section = trim(line.substr(1, line.length() - 2)); return section.length() > 0; } static inline void appendLine(std::string & output, const std::string & line) { if(output.length()) output += "\r\n"; output += line; } static inline std::string makeSectionText(const std::string & section) { return "[" + section + "]"; } static inline std::string makeKeyValueText(const std::string & key, const std::string & value) { return key + "=" + escapeValue(value); } static inline bool needsEscaping(const std::string & value) { auto len = value.length(); return len && (value[0] == ' ' || value[len - 1] == ' ' || value.find('\n') != std::string::npos || value.find('\"') != std::string::npos); } static inline std::string escapeValue(const std::string & value) { if(!needsEscaping(value)) return value; std::string escaped = "\""; for(auto ch : value) { switch(ch) { case '\"': escaped += "\\\""; break; case '\\': escaped += "\\\\"; break; case '\r': escaped += "\\r"; break; case '\n': escaped += "\\n"; break; case '\t': escaped += "\\t"; break; default: escaped += ch; } } escaped += "\""; return escaped; } static inline std::string unescapeValue(const std::string & str) { std::string result; auto bEscaped = false; for(auto ch : str) { if(!bEscaped) { switch(ch) { case '\"': break; case '\\': bEscaped = true; break; default: result += ch; } } else { switch(ch) { case 'r': result += '\r'; break; case 'n': result += '\n'; break; case 't': result += '\t'; break; default: result += ch; } bEscaped = false; } } if(bEscaped) result += '\\'; return result; } }; #endif //UTF8INI_H