From 35fb5cecad6d36ac2ebb4c99c9ba406e4d8b565e Mon Sep 17 00:00:00 2001 From: nowrep Date: Mon, 10 Feb 2014 23:33:12 +0100 Subject: [PATCH] [Json] Removed dependency on QJson QtScript is now used instead of QJson. QtScript is available on both Qt 4 & Qt 5 and also as side benefit, is TWICE as fast as QJson! --- .travis.yml | 2 +- src/defines.pri | 8 -- src/lib/bookmarks/bookmarks.cpp | 20 ++-- src/lib/lib.pro | 4 - src/lib/tools/json.cpp | 159 ++++++++++++++++++++++++-------- src/lib/tools/json.h | 22 ++++- 6 files changed, 153 insertions(+), 62 deletions(-) diff --git a/.travis.yml b/.travis.yml index 01f5f996f..5cb6040ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ before_install: install: - sudo apt-get -qq update - sudo apt-get -qq install libssl-dev pkg-config libhunspell-dev - - if [[ "$QT" == "qt4" ]]; then sudo apt-get -qq install libqt4-dev libqt4-webkit libqt4-sql-sqlite libqjson-dev; fi + - if [[ "$QT" == "qt4" ]]; then sudo apt-get -qq install libqt4-dev libqt4-webkit libqt4-sql-sqlite; fi - if [[ "$QT" == "qt5" ]]; then sudo apt-add-repository -y ppa:beineri/opt-qt511; sudo apt-get update -qq; sudo apt-get install -qq qt51base qt51webkit qt51tools qt51script libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev; fi script: diff --git a/src/defines.pri b/src/defines.pri index 3f107eaa7..4755adf24 100644 --- a/src/defines.pri +++ b/src/defines.pri @@ -58,14 +58,6 @@ else { } } -# QJson dependency -!mac:unix:isEqual(QT_MAJOR_VERSION, 4) { - !system(test -d /usr/include/qjson): error(ERROR: QJson cannot be found!) - - # Ugly hack to check for Indent support in QJson - system(grep setIndentMode /usr/include/qjson/serializer.h > /dev/null): DEFINES *= QJSON_HAVE_INDENT -} - DEFINES *= QT_NO_URL_CAST_FROM_STRING DEFINES *= QT_USE_QSTRINGBUILDER diff --git a/src/lib/bookmarks/bookmarks.cpp b/src/lib/bookmarks/bookmarks.cpp index bee61669d..e0b9681d2 100644 --- a/src/lib/bookmarks/bookmarks.cpp +++ b/src/lib/bookmarks/bookmarks.cpp @@ -280,10 +280,10 @@ void Bookmarks::loadBookmarks() QByteArray data = file.readAll(); file.close(); - bool ok; - const QVariant res = Json::parse(data, &ok); + Json json; + const QVariant res = json.parse(QString::fromUtf8(data)); - if (!ok || res.type() != QVariant::Map) { + if (!json.ok() || res.type() != QVariant::Map) { qWarning() << "Bookmarks::init() Error parsing bookmarks! Using default bookmarks!"; qWarning() << "Bookmarks::init() Your bookmarks have been backed up in" << backupFile; @@ -292,9 +292,9 @@ void Bookmarks::loadBookmarks() QFile::copy(bookmarksFile, backupFile); // Load default bookmarks - const QVariant data = Json::parse(QzTools::readAllFileByteContents(":data/bookmarks.json"), &ok); + const QVariant data = json.parse(QzTools::readAllFileContents(":data/bookmarks.json")); - Q_ASSERT(ok); + Q_ASSERT(json.ok()); Q_ASSERT(data.type() == QVariant::Map); loadBookmarksFromMap(data.toMap().value("roots").toMap()); @@ -327,10 +327,10 @@ void Bookmarks::saveBookmarks() map.insert("version", Qz::bookmarksVersion); map.insert("roots", bookmarksMap); - bool ok; - const QByteArray data = Json::serialize(map, &ok); + Json json; + const QString data = json.serialize(map); - if (!ok || data.isEmpty()) { + if (!json.ok() || data.isEmpty()) { qWarning() << "Bookmarks::saveBookmarks() Error serializing bookmarks!"; return; } @@ -341,7 +341,7 @@ void Bookmarks::saveBookmarks() qWarning() << "Bookmarks::saveBookmarks() Error opening bookmarks file for writing!"; } - file.write(data); + file.write(data.toUtf8()); file.close(); } @@ -410,7 +410,7 @@ QVariantList Bookmarks::writeBookmarks(BookmarkItem* parent) switch (child->type()) { case BookmarkItem::Url: - map.insert("url", child->url().toEncoded()); + map.insert("url", child->urlString()); map.insert("name", child->title()); map.insert("description", child->description()); map.insert("keyword", child->keyword()); diff --git a/src/lib/lib.pro b/src/lib/lib.pro index 3d34611ad..f9ebcf249 100644 --- a/src/lib/lib.pro +++ b/src/lib/lib.pro @@ -514,10 +514,6 @@ isEqual(QT_MAJOR_VERSION, 5) { SOURCES += tools/qzregexp.cpp } -!isEqual(QT_MAJOR_VERSION, 5) { - LIBS += -lqjson -} - !mac:unix { target.path = $$library_folder diff --git a/src/lib/tools/json.cpp b/src/lib/tools/json.cpp index 8ffe1f379..3a4c762e5 100644 --- a/src/lib/tools/json.cpp +++ b/src/lib/tools/json.cpp @@ -17,51 +17,138 @@ * ============================================================ */ #include "json.h" -#if QT_VERSION < 0x050000 -#include -#include -#else -#include -#endif - -QVariant Json::parse(const QByteArray &data, bool* ok) +#include +#include + +// Class based on http://stackoverflow.com/a/15805783 + +Json::Json() + : m_engine(0) + , m_ok(true) +{ +} + +Json::~Json() +{ + delete m_engine; +} + +QVariant Json::parse(const QString &data) { -#if QT_VERSION < 0x050000 - QJson::Parser parser; - return parser.parse(data, ok); -#else - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(data, &error); - - if (ok) { - *ok = error.error == QJsonParseError::NoError; + delete m_engine; + m_engine = new QScriptEngine(); + + QString jsonData = QString("(%1)").arg(data); + QScriptValue obj = m_engine->evaluate(jsonData); + m_ok = !obj.isError() && obj.isObject(); + + return decodeInner(obj); +} + +QString Json::serialize(const QVariant &variant) +{ + delete m_engine; + m_engine = new QScriptEngine(); + + m_engine->evaluate("function toString() { return JSON.stringify(this, null, ' ') }"); + + QScriptValue toString = m_engine->globalObject().property("toString"); + QScriptValue obj = encodeInner(variant.toMap()); + QScriptValue result = toString.call(obj); + + m_ok = !obj.isError() && obj.isObject(); + return result.toString(); +} + +bool Json::ok() const +{ + return m_ok; +} + +QMap Json::decodeInner(QScriptValue object) +{ + QMap map; + QScriptValueIterator it(object); + + while (it.hasNext()) { + it.next(); + + if (it.value().isArray()) { + map.insert(it.name(), QVariant(decodeInnerToList(it.value()))); + } + else if (it.value().isNumber()) { + map.insert(it.name(), QVariant(it.value().toNumber())); + } + else if (it.value().isString()) { + map.insert(it.name(), QVariant(it.value().toString())); + } + else if (it.value().isNull()) { + map.insert(it.name(), QVariant()); + } + else if (it.value().isObject()) { + map.insert(it.name(), QVariant(decodeInner(it.value()))); + } } - return doc.toVariant(); -#endif + return map; } -QByteArray Json::serialize(const QVariant &variant, bool* ok) +QList Json::decodeInnerToList(QScriptValue arrayValue) { -#if QT_VERSION < 0x050000 - QJson::Serializer serializer; -#ifdef QJSON_HAVE_INDENT - serializer.setIndentMode(QJson::IndentFull); -#endif - const QByteArray data = serializer.serialize(variant); - - if (ok) { - *ok = !data.isNull(); + QList list; + QScriptValueIterator it(arrayValue); + + while (it.hasNext()) { + it.next(); + + if (it.name() == QLatin1String("length")) { + continue; + } + + if (it.value().isArray()) { + list.append(QVariant(decodeInnerToList(it.value()))); + } + else if (it.value().isNumber()) { + list.append(QVariant(it.value().toNumber())); + } + else if (it.value().isString()) { + list.append(QVariant(it.value().toString())); + } + else if (it.value().isNull()) { + list.append(QVariant()); + } + else if (it.value().isObject()) { + list.append(QVariant(decodeInner(it.value()))); + } } - return data; -#else - QJsonDocument doc = QJsonDocument::fromVariant(variant); + return list; +} + +QScriptValue Json::encodeInner(const QMap &map) +{ + QScriptValue obj = m_engine->newObject(); + QMapIterator i(map); + + while (i.hasNext()) { + i.next(); - if (ok) { - *ok = !doc.isNull(); + if (i.value().type() == QVariant::String) { + obj.setProperty(i.key(), i.value().toString()); + } + else if (i.value().type() == QVariant::Int) { + obj.setProperty(i.key(), i.value().toInt()); + } + else if (i.value().type() == QVariant::Double) { + obj.setProperty(i.key(), i.value().toDouble()); + } + else if (i.value().type() == QVariant::List) { + obj.setProperty(i.key(), qScriptValueFromSequence(m_engine, i.value().toList())); + } + else if (i.value().type() == QVariant::Map) { + obj.setProperty(i.key(), encodeInner(i.value().toMap())); + } } - return doc.toJson(QJsonDocument::Indented); -#endif + return obj; } diff --git a/src/lib/tools/json.h b/src/lib/tools/json.h index 3ec8a6062..e07dde6dd 100644 --- a/src/lib/tools/json.h +++ b/src/lib/tools/json.h @@ -19,15 +19,31 @@ #define JSON_H #include -#include +#include #include "qz_namespace.h" +class QScriptValue; +class QScriptEngine; + class QT_QUPZILLA_EXPORT Json { public: - static QVariant parse(const QByteArray &data, bool* ok); - static QByteArray serialize(const QVariant &variant, bool* ok); + explicit Json(); + ~Json(); + + QVariant parse(const QString &data); + QString serialize(const QVariant &variant); + + bool ok() const; + +private: + QMap decodeInner(QScriptValue object); + QList decodeInnerToList(QScriptValue arrayValue); + QScriptValue encodeInner(const QMap &map); + + QScriptEngine* m_engine; + bool m_ok; }; #endif // JSON_H