From 0770abaa6cfaef6d225b68289b2a7dd681fb32e5 Mon Sep 17 00:00:00 2001 From: Filonenko Michael Date: Sat, 5 Mar 2011 22:37:24 +0200 Subject: [PATCH] Initial commit --- CMakeLists.txt | 52 +++++ json.cpp | 287 +++++++++++++++++++++++++++ json.h | 23 +++ jsonparser.cpp | 469 +++++++++++++++++++++++++++++++++++++++++++++ qtjsonsettings.cpp | 121 ++++++++++++ qtjsonsettings.h | 59 ++++++ qtjsonsettings.pri | 8 + 7 files changed, 1019 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 json.cpp create mode 100644 json.h create mode 100644 jsonparser.cpp create mode 100644 qtjsonsettings.cpp create mode 100644 qtjsonsettings.h create mode 100644 qtjsonsettings.pri diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..49123ee --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 2.6) + +set(CMAKE_DEBUG_POSTFIX _debug) + +# Declare project +project(qtjsonsettings) + +find_package(Qt4 REQUIRED) +set(QT_DONTUSE_QTGUI TRUE) + +include(${QT_USE_FILE}) + +message("Building project ${PROJECT_NAME}") + +message(" +Configuration +------------- +CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE} +CXXFLAGS = $ENV{CXXFLAGS} +CMAKE_CXX_FLAGS = ${CMAKE_CXX_FLAGS} +LDFLAGS = $ENV{LDFLAGS} +CMAKE_EXE_LINKER_FLAGS = ${CMAKE_EXE_LINKER_FLAGS} +CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX} +") + +message("You are linking ${PROJECT_NAME}. I hope it makes your life easier.") + + +# 3rdparty +# SOURCE FILES AND DIRECTORIES + +# simple sources +list(APPEND qtjsonsettings_SOURCES qtjsonsettings.cpp json.cpp jsonparser.cpp) + +# simple headers +list(APPEND qtjsonsettings_HEADERS json.h) +list(APPEND qtjsonsettings_Q_HEADERS qtjsonsettings.h) + +# if you use Q_OBJECT +qt4_wrap_cpp(qtjsonsettings_MOC_SOURCES ${qtjsonsettings_Q_HEADERS}) + +# COMPILATION +add_library(${PROJECT_NAME} STATIC + ${qtjsonsettings_SOURCES} + ${qtjsonsettings_MOC_SOURCES} + ${qtjsonsettings_HEADERS} + ${qtjsonsettings_Q_HEADERS} + ) + +# LINKING +# main library +target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES}) diff --git a/json.cpp b/json.cpp new file mode 100644 index 0000000..7c3ac95 --- /dev/null +++ b/json.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** + ** + ** Copyright (c) 2010 Girish Ramakrishnan + ** + ** Use, modification and distribution is allowed without limitation, + ** warranty, liability or support of any kind. + ** + ****************************************************************************/ + +#include "json.h" +#include "jsonparser.cpp" + +namespace Json { + + QVariant parse(const QByteArray &json, QString *error) + { + JsonLexer lexer(json); + JsonParser parser; + if (!parser.parse(&lexer) && error) + { + *error = parser.errorMessage(); + } + return parser.result(); + } + + static QByteArray escape(const QVariant &variant) + { + QString str = variant.toString(); + QByteArray res; + res.reserve(str.length()); + for (int i = 0; i < str.length(); i++) + { + if (str[i] == '\b') + { + res += "\\b"; + } + else if (str[i] == '\f') + { + res += "\\f"; + } + else if (str[i] == '\n') + { + res += "\\n"; + } + else if (str[i] == '\r') + { + res += "\\r"; + } + else if (str[i] == '\t') + { + res += "\\t"; + } + else if (str[i] == '\"') + { + res += "\\\""; + } + else if (str[i] == '\\') + { + res += "\\\\"; + } + else if (str[i].unicode() > 127) + { + res += "\\u" + QString::number(str[i].unicode(), 16).rightJustified(4, '0'); + } + else + { + res += str[i].toAscii(); + } + } + return res; + } + + QByteArray stringify(const QVariant &variant) + { + QByteArray result; + if (variant.type() == QVariant::List || variant.type() == QVariant::StringList) + { + result += "["; + QVariantList list = variant.toList(); + for (int i = 0; i < list.count(); i++) + { + if (i != 0) + result += ","; + result += stringify(list[i]); + } + result += "]"; + } + else if (variant.type() == QVariant::Map) + { + QVariantMap map = variant.toMap(); + QVariantMap::const_iterator it = map.constBegin(); + result += "{"; + while (it != map.constEnd()) + { + if (it != map.constBegin()) + result += ","; + result += "\"" + escape(it.key()) + "\":"; + result += stringify(it.value()); + ++it; + } + result += "}"; + } + else if (variant.type() == QVariant::String || variant.type() == QVariant::ByteArray) + { + result = "\"" + escape(variant) + "\""; + } + else if (variant.type() == QVariant::Double || (int) variant.type() == (int) QMetaType::Float) + { + result.setNum(variant.toDouble(), 'g', 15); + } + else if (variant.type() == QVariant::Bool) + { + result = variant.toBool() ? "true" : "false"; + } + else if (variant.type() == QVariant::Invalid) + { + result = "null"; + } + else if (variant.type() == QVariant::ULongLong) + { + result = QByteArray::number(variant.toULongLong()); + } + else if (variant.type() == QVariant::LongLong) + { + result = QByteArray::number(variant.toLongLong()); + } + else if (variant.type() == QVariant::Int) + { + result = QByteArray::number(variant.toInt()); + } + else if (variant.type() == QVariant::UInt) + { + result = QByteArray::number(variant.toUInt()); + } + else if (variant.type() == QVariant::Char) + { + QChar c = variant.toChar(); + if (c.unicode() > 127) + result = "\\u" + QByteArray::number(c.unicode(), 16).rightJustified(4, '0'); + else + result.append(c.toAscii()); + } + else if (variant.canConvert ()) + { + result = QByteArray::number(variant.toLongLong()); + } + else if (variant.canConvert ()) + { + result = stringify(variant); + } + + return result; + } + + QByteArray prettyStringify(const QVariant &variant, int indent, int indent0) + { + QByteArray result; + + QString indentstr0 = QString(indent0, ' '); + QString indentstr = QString(indent0 + indent, ' '); + + switch ((int) variant.type()) + { + case QVariant::List: + case QVariant::StringList: + { + result += indentstr0; + result += "[\n"; + + QVariantList list = variant.toList(); + for (int i = 0; i < list.count(); i++) + { + if (i != 0) + result += ",\n"; + + if (list[i].type() != QVariant::Map && list[i].type() != QVariant::List && list[i].type() + != QVariant::StringList) + result += indentstr; + + result += prettyStringify(list[i], indent, indent0 + indent); + } + result += "\n"; + result += indentstr0; + result += "]"; + + break; + } + case QVariant::Map: + { + QVariantMap map = variant.toMap(); + QVariantMap::const_iterator it = map.constBegin(); + + result += indentstr0; + result += "{\n"; + + while (it != map.constEnd()) + { + if (it != map.constBegin()) + result += ",\n"; + + result += indentstr; + result += "\"" + escape(it.key()) + "\":"; + + if (it.value().type() == QVariant::Map || it.value().type() == QVariant::List || it.value().type() + == QVariant::StringList) + { + result += "\n"; + } + result += prettyStringify(it.value(), indent, indent0 + indent); + ++it; + } + result += "\n"; + result += indentstr0; + result += "}"; + break; + } + case QVariant::String: + case QVariant::ByteArray: + { + result = "\"" + escape(variant) + "\""; + break; + } + case QVariant::Double: + case QMetaType::Float: + { + result = QString::number(variant.toDouble(), 'g', 15).toUtf8(); + + break; + } + case QVariant::Bool: + { + result = variant.toBool() ? "true" : "false"; + + break; + } + case QVariant::Invalid: + { + result = "null"; + break; + } + case QVariant::ULongLong: + { + result = QByteArray::number(variant.toULongLong()); + break; + } + case QVariant::LongLong: + { + result = QByteArray::number(variant.toLongLong()); + break; + } + case QVariant::Int: + { + result = QByteArray::number(variant.toInt()); + break; + } + case QVariant::UInt: + { + result = QByteArray::number(variant.toUInt()); + break; + } + case QVariant::Char: + { + QChar c = variant.toChar(); + if (c.unicode() > 127) + result = "\\u" + QByteArray::number(c.unicode(), 16).rightJustified(4, '0'); + else + result.append(c.toAscii()); + break; + } + default: + { + if (variant.canConvert ()) + { + result = QByteArray::number(variant.toLongLong()); + } + else if (variant.canConvert ()) + { + result = stringify(variant); + } + break; + } + } + + return result; + } +} + diff --git a/json.h b/json.h new file mode 100644 index 0000000..af6d109 --- /dev/null +++ b/json.h @@ -0,0 +1,23 @@ +/**************************************************************************** +** +** Copyright (c) 2010 Girish Ramakrishnan +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#ifndef JSON_H +#define JSON_H + +#include +#include + +namespace Json { + QVariant parse(const QByteArray &data, QString *error = 0); + QByteArray stringify(const QVariant &variant); + QByteArray prettyStringify(const QVariant &variant, int indent, int indent0 = 0); +}; + +#endif // JSON_H + diff --git a/jsonparser.cpp b/jsonparser.cpp new file mode 100644 index 0000000..5593c4f --- /dev/null +++ b/jsonparser.cpp @@ -0,0 +1,469 @@ +// This file was generated by qlalr - DO NOT EDIT! +#ifndef JSONPARSER_CPP +#define JSONPARSER_CPP + +class JsonGrammar +{ +public: + enum VariousConstants { + EOF_SYMBOL = 0, + ERROR = 12, + T_COLON = 7, + T_COMMA = 8, + T_FALSE = 9, + T_LCURLYBRACKET = 3, + T_LSQUAREBRACKET = 5, + T_NULL = 11, + T_NUMBER = 2, + T_RCURLYBRACKET = 4, + T_RSQUAREBRACKET = 6, + T_STRING = 1, + T_TRUE = 10, + + ACCEPT_STATE = 12, + RULE_COUNT = 18, + STATE_COUNT = 26, + TERMINAL_COUNT = 13, + NON_TERMINAL_COUNT = 8, + + GOTO_INDEX_OFFSET = 26, + GOTO_INFO_OFFSET = 37, + GOTO_CHECK_OFFSET = 37 + }; + + static const char *const spell []; + static const short lhs []; + static const short rhs []; + +#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO + static const int rule_index []; + static const int rule_info []; +#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO + + static const short goto_default []; + static const short action_default []; + static const short action_index []; + static const short action_info []; + static const short action_check []; + + static inline int nt_action (int state, int nt) + { + const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; + if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) + return goto_default [nt]; + + return action_info [GOTO_INFO_OFFSET + yyn]; + } + + static inline int t_action (int state, int token) + { + const int yyn = action_index [state] + token; + + if (yyn < 0 || action_check [yyn] != token) + return - action_default [state]; + + return action_info [yyn]; + } +}; + + +const char *const JsonGrammar::spell [] = { + "end of file", "string", "number", "{", "}", "[", "]", ":", ",", "false", + "true", "null", "error", +#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO +"Root", "Value", "Object", "Members", "Member", "Array", "Values", + "$accept" +#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO +}; + +const short JsonGrammar::lhs [] = { + 13, 15, 16, 16, 16, 17, 14, 14, 14, 14, + 14, 14, 14, 18, 19, 19, 19, 20}; + +const short JsonGrammar::rhs [] = { + 1, 3, 1, 3, 0, 3, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 3, 0, 2}; + + +#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO +const int JsonGrammar::rule_info [] = { + 13, 14 + , 15, 3, 16, 4 + , 16, 17 + , 16, 16, 8, 17 + , 16 + , 17, 1, 7, 14 + , 14, 9 + , 14, 10 + , 14, 11 + , 14, 15 + , 14, 18 + , 14, 2 + , 14, 1 + , 18, 5, 19, 6 + , 19, 14 + , 19, 19, 8, 14 + , 19 + , 20, 13, 0}; + +const int JsonGrammar::rule_index [] = { + 0, 2, 6, 8, 12, 13, 17, 19, 21, 23, + 25, 27, 29, 31, 35, 37, 41, 42}; +#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO + +const short JsonGrammar::action_default [] = { + 0, 11, 10, 0, 7, 5, 17, 9, 12, 13, + 8, 1, 18, 3, 0, 0, 0, 2, 4, 0, + 6, 15, 0, 0, 14, 16}; + +const short JsonGrammar::goto_default [] = { + 3, 11, 2, 14, 13, 1, 22, 0}; + +const short JsonGrammar::action_index [] = { + 24, -13, -13, 0, -13, 12, 24, -13, -13, -13, + -13, -13, -13, -13, -1, -6, 12, -13, -13, 7, + -13, -13, -4, 24, -13, -13, + + -8, -8, -8, -8, -8, -8, -1, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -2, -8, -8, 0, + -8, -8, -8, 6, -8, -8}; + +const short JsonGrammar::action_info [] = { + 12, 19, 24, 17, 23, 0, 0, 16, 9, 8, + 5, 0, 6, 15, 0, 0, 4, 10, 7, 0, + 0, 0, 0, 0, 0, 9, 8, 5, 0, 6, + 0, 0, 0, 4, 10, 7, 0, + + 21, 20, 18, 0, 0, 0, 0, 25, 0, 0, + 0, 0, 0, 0}; + +const short JsonGrammar::action_check [] = { + 0, 7, 6, 4, 8, -1, -1, 8, 1, 2, + 3, -1, 5, 1, -1, -1, 9, 10, 11, -1, + -1, -1, -1, -1, -1, 1, 2, 3, -1, 5, + -1, -1, -1, 9, 10, 11, -1, + + 1, 1, 4, -1, -1, -1, -1, 1, -1, -1, + -1, -1, -1, -1}; + + +#line 28 "json.g" + +/**************************************************************************** +** +** Copyright (c) 2010 Girish Ramakrishnan +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#ifndef JSONPARSER_P_H +#define JSONPARSER_P_H + +#include +#include +#include + +class JsonLexer +{ +public: + JsonLexer(const QByteArray &data); + ~JsonLexer(); + + int lex(); + QVariant symbol() const { return m_symbol; } + int lineNumber() const { return m_lineNumber; } + int pos() const { return m_pos; } + +private: + int parseNumber(); + int parseString(); + int parseKeyword(); + + QByteArray m_data; + int m_lineNumber; + int m_pos; + QVariant m_symbol; + QHash m_keywords; +}; + +class JsonParser : protected JsonGrammar +{ +public: + JsonParser(); + ~JsonParser(); + + bool parse(JsonLexer *lex); + QVariant result() const { return m_result; } + QString errorMessage() const { return QString("%1 at line %2 pos %3").arg(m_errorMessage).arg(m_errorLineNumber).arg(m_errorPos); } + +private: + void reallocateStack(); + + inline QVariant &sym(int index) + { return m_symStack[m_tos + index - 1]; } + + int m_tos; + QVector m_stateStack; + QVector m_symStack; + QString m_errorMessage; + int m_errorLineNumber; + int m_errorPos; + QVariant m_result; +}; + +#endif // JSONPARSER_P_H + +#line 96 "json.g" + +/**************************************************************************** +** +** Copyright (c) 2010 Girish Ramakrishnan +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#include + +JsonLexer::JsonLexer(const QByteArray &ba) + : m_data(ba), m_lineNumber(1), m_pos(0) +{ + m_keywords.insert("true", JsonGrammar::T_TRUE); + m_keywords.insert("false", JsonGrammar::T_FALSE); + m_keywords.insert("null", JsonGrammar::T_NULL); +} + +JsonLexer::~JsonLexer() +{ +} + +int JsonLexer::parseString() +{ + QString str; + bool esc = false; + ++m_pos; // skip initial " + for (; m_pos < m_data.length(); ++m_pos) { + const char c = m_data[m_pos]; + if (esc) { + if (c == 'b') str += '\b'; + else if (c == 'f') str += '\f'; + else if (c == 'n') str += '\n'; + else if (c == 'r') str += '\r'; + else if (c == 't') str += '\t'; + else if (c == '\\') str += '\\'; + else if (c == '\"') str += '\"'; + else if (c == 'u' && m_pos+4= '0' && c <= '9')) + continue; + if (c == '.' || c == 'e' || c == 'E') { + isDouble = true; + continue; + } + break; + } + QByteArray number = QByteArray::fromRawData(m_data.constData()+start, m_pos-start); + bool ok; + if (!isDouble) { + m_symbol = number.toInt(&ok); + if (!ok) + m_symbol = number.toLongLong(&ok); + } + if (isDouble || !ok) + m_symbol = number.toDouble(); + return JsonGrammar::T_NUMBER; +} + +int JsonLexer::parseKeyword() +{ + int start = m_pos; + for (; m_pos < m_data.length(); ++m_pos) { + const char c = m_data[m_pos]; + if (c >= 'a' && c <= 'z') + continue; + break; + } + QByteArray keyword = QByteArray::fromRawData(m_data.constData()+start, m_pos-start); + if (m_keywords.contains(keyword)) + return m_keywords.value(keyword); + return JsonGrammar::ERROR; +} + +int JsonLexer::lex() +{ + m_symbol.clear(); + while (m_pos < m_data.length()) { + const char c = m_data[m_pos]; + switch (c) { + case '[': ++m_pos; return JsonGrammar::T_LSQUAREBRACKET; + case ']': ++m_pos; return JsonGrammar::T_RSQUAREBRACKET; + case '{': ++m_pos; return JsonGrammar::T_LCURLYBRACKET; + case '}': ++m_pos; return JsonGrammar::T_RCURLYBRACKET; + case ':': ++m_pos; return JsonGrammar::T_COLON; + case ',': ++m_pos; return JsonGrammar::T_COMMA; + case ' ': case '\r': case '\t': case 'b': ++m_pos; break; + case '\n': ++m_pos; ++m_lineNumber; break; + case '"': return parseString(); + default: + if (c == '+' || c == '-' || (c >= '0' && c <= '9')) { + return parseNumber(); + } + if (c >= 'a' && c <= 'z') { + return parseKeyword(); + } + return JsonGrammar::ERROR; + } + } + return JsonGrammar::EOF_SYMBOL; +} + +JsonParser::JsonParser() +{ +} + +JsonParser::~JsonParser() +{ +} + +void JsonParser::reallocateStack() +{ + int size = m_stateStack.size(); + if (size == 0) + size = 128; + else + size <<= 1; + m_symStack.resize(size); + m_stateStack.resize(size); +} + +bool JsonParser::parse(JsonLexer *lexer) +{ + const int INITIAL_STATE = 0; + int yytoken = -1; + reallocateStack(); + m_tos = 0; + m_stateStack[++m_tos] = INITIAL_STATE; + + while (true) { + const int state = m_stateStack[m_tos]; + if (yytoken == -1 && -TERMINAL_COUNT != action_index[state]) { + yytoken = lexer->lex(); + } + int act = t_action(state, yytoken); + if (act == ACCEPT_STATE) + return true; + else if (act > 0) { + if (++m_tos == m_stateStack.size()) + reallocateStack(); + m_stateStack[m_tos] = act; + m_symStack[m_tos] = lexer->symbol(); + yytoken = -1; + } else if (act < 0) { + int r = -act-1; + m_tos -= rhs[r]; + act = m_stateStack.at(m_tos++); + switch (r) { + +#line 276 "json.g" + case 0: { m_result = sym(1); break; } +#line 279 "json.g" + case 1: { sym(1) = sym(2); break; } +#line 284 "json.g" + case 3: { sym(1) = sym(1).toMap().unite(sym(3).toMap()); break; } +#line 287 "json.g" + case 4: { sym(1) = QVariantMap(); break; } +#line 290 "json.g" + case 5: { QVariantMap map; map.insert(sym(1).toString(), sym(3)); sym(1) = map; break; } +#line 293 "json.g" + case 6: { sym(1) = QVariant(false); break; } +#line 296 "json.g" + case 7: { sym(1) = QVariant(true); break; } +#line 305 "json.g" + case 13: { sym(1) = sym(2); break; } +#line 308 "json.g" + case 14: { QVariantList list; list.append(sym(1)); sym(1) = list; break; } +#line 311 "json.g" + case 15: { QVariantList list = sym(1).toList(); list.append(sym(3)); sym(1) = list; break; } +#line 314 "json.g" + case 16: { sym(1) = QVariantList(); break; } +#line 316 "json.g" + + } // switch + m_stateStack[m_tos] = nt_action(act, lhs[r] - TERMINAL_COUNT); + } else { + int ers = state; + int shifts = 0; + int reduces = 0; + int expected_tokens[3]; + for (int tk = 0; tk < TERMINAL_COUNT; ++tk) { + int k = t_action(ers, tk); + + if (! k) + continue; + else if (k < 0) + ++reduces; + else if (spell[tk]) { + if (shifts < 3) + expected_tokens[shifts] = tk; + ++shifts; + } + } + + m_errorLineNumber = lexer->lineNumber(); + m_errorPos = lexer->pos(); + m_errorMessage.clear(); + if (shifts && shifts < 3) { + bool first = true; + + for (int s = 0; s < shifts; ++s) { + if (first) + m_errorMessage += QLatin1String("Expected "); + else + m_errorMessage += QLatin1String(", "); + + first = false; + m_errorMessage += QLatin1String("'"); + m_errorMessage += QLatin1String(spell[expected_tokens[s]]); + m_errorMessage += QLatin1String("'"); + } + } + return false; + } + } + + return false; +} + + +#endif // JSONPARSER_CPP + diff --git a/qtjsonsettings.cpp b/qtjsonsettings.cpp new file mode 100644 index 0000000..71845c4 --- /dev/null +++ b/qtjsonsettings.cpp @@ -0,0 +1,121 @@ +#include "qtjsonsettings.h" + +#include "json.h" + +#include + +#include + +namespace { + + void processReadKey(QString& key, QSettings::SettingsMap &map, const QVariant& element) + { + switch (element.type()) + { + case QVariant::Map: + { + QVariantMap vMap = element.toMap(); + QVariantMap::ConstIterator it = vMap.constBegin(); + QVariantMap::ConstIterator end = vMap.constEnd(); + + for (; it != end; ++it) + { + key.append(it.key()); + key.append("/"); + processReadKey(key, map, it.value()); + } + + break; + } + case QVariant::List: + { + QVariantList list = element.toList(); + map.insert(key + "size", list.count()); + for (int i = 0; i < list.count(); ++i) + { + key.append(QString::number(i + 1)); + key.append("/"); + processReadKey(key, map, list.at(i)); + } + break; + } + default: + map.insert(key.left(key.size() - 1), element); + } + key.truncate(key.lastIndexOf("/", -2) + 1); + } + + QVariant processWriteKey(QVariant& root, const QString& key, const QVariant& value) + { + int slashPos = key.indexOf('/'); + + // If it is key + if (slashPos < 0) + { + QVariantMap map = root.toMap(); + /** TODO VERY UGLY array detecting method + * Key size always placed after all numeric keys (array indexes) + * Convert root map to list and return it. + * Warning. Index starts with 1 + */ + if (key == "size") + { + QVariantList list; + for (int i = 1; i <= value.toInt(); ++i) + { + list.append(map.value(QString::number(i))); + } + return list; + } + else + { + map.insert(key, value); + return map; + } + } + + // get group name + QString groupName = key.left(slashPos); + + // if name is number then it's row of array, convert to list + QVariantMap map = root.toMap(); + QVariant item = map.value(groupName); + map.insert(groupName, processWriteKey(item, key.mid(slashPos + 1), value)); + return map; + } +} +const QSettings::Format QtJsonSettings::json_format = QSettings::registerFormat("json", readJsonFile, writeJsonFile); + +bool QtJsonSettings::readJsonFile(QIODevice &device, QSettings::SettingsMap &map) +{ + QString error; + QVariant parsed = Json::parse(device.readAll(), &error); + if (error.isEmpty()) + { + QString str; + processReadKey(str, map, parsed); + } + else + { + qWarning() << error; + } + + return true; +} + +bool QtJsonSettings::writeJsonFile(QIODevice &device, const QSettings::SettingsMap &map) +{ + QVariant resultMap; + + QSettings::SettingsMap::ConstIterator it = map.constBegin(); + QSettings::SettingsMap::ConstIterator end = map.constEnd(); + + for (; it != end; ++it) + { + resultMap = processWriteKey(resultMap, it.key(), it.value()); + }; + + device.write(Json::prettyStringify(resultMap, 4)); + return true; + +} diff --git a/qtjsonsettings.h b/qtjsonsettings.h new file mode 100644 index 0000000..e5a8261 --- /dev/null +++ b/qtjsonsettings.h @@ -0,0 +1,59 @@ +#ifndef QTJSONSETTINGS_H +#define QTJSONSETTINGS_H + +#include +#include +#include + +class QIODevice; + +#if defined(QTJSONSETTINGS_EXPORTS) +# define QTJSONSETTINGS_EXPORT Q_DECL_EXPORT +#elif defined(QTJSONSETTINGS_IMPORTS) +# define QTJSONSETTINGS_EXPORT Q_DECL_IMPORT /**/ +#else +# define QTJSONSETTINGS_EXPORT /**/ +#endif + +/** + * @brief Class for storing application setting in xml file. This class implements QSettings interface. + * + * @class QtXmlSettings qtxmlsettings.h + */ +class QTJSONSETTINGS_EXPORT QtJsonSettings: public QSettings +{ + Q_OBJECT + public: + QtJsonSettings(const QString &organization, const QString &application, + QObject *parent = 0) : + QSettings(json_format, QSettings::UserScope, organization, application, + parent) + { + } + + QtJsonSettings(Scope scope, const QString &organization, + const QString &application = QString(), QObject *parent = 0) : + QSettings(json_format, scope, organization, application, parent) + { + } + + QtJsonSettings(const QString &fileName, QObject *parent = 0) : + QSettings(fileName, json_format, parent) + { + } + + QtJsonSettings(QObject * parent = 0) : + QSettings(json_format, QSettings::UserScope, + QCoreApplication::organizationName(), + QCoreApplication::applicationName(), parent) + { + } + + static const QSettings::Format json_format; + private: + static bool readJsonFile(QIODevice &device, QSettings::SettingsMap &map); + static bool writeJsonFile(QIODevice &device, + const QSettings::SettingsMap &map); +}; + +#endif // #ifndef QTJSONSETTINGS_H diff --git a/qtjsonsettings.pri b/qtjsonsettings.pri new file mode 100644 index 0000000..58b5900 --- /dev/null +++ b/qtjsonsettings.pri @@ -0,0 +1,8 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD + +HEADERS += $$PWD/qtjsonsettings.h +SOURCES += $$PWD/qtjsonsettings.cpp + +HEADERS += $$PWD/json.h +SOURCES += $$PWD/json.cpp $$PWD/jsonparser.cpp