summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2011-12-07 11:11:49 +0100
committerSimons Kevin <kevin.simons@nokia.com>2011-12-07 13:16:06 +0100
commit7f2c87f97beddc28cc6357d89f19f63c74d12423 (patch)
tree3d5d4bb2f3e2002a00a3860b1c0ed02dbe4c8a31
parent4cb4e4137bacd15c97f1107a99590ff871381e49 (diff)
Move the code for writing json into it's own class
QJsonWriter is an internal class to convert Json documents to their text based representation. Also fix QJsonDocument::to/fromVariant. Change-Id: I20604b5f0bd75e5e4931cf9a0d391c967ea4d928 Reviewed-by: Simons Kevin <kevin.simons@nokia.com>
-rw-r--r--src/qjson_p.h2
-rw-r--r--src/qjsondocument.cpp51
-rw-r--r--src/qjsondocument.h2
-rw-r--r--src/qjsonobject.cpp218
-rw-r--r--src/qjsonwriter.cpp234
-rw-r--r--src/qjsonwriter_p.h13
-rw-r--r--src/src.pro6
-rw-r--r--tests/auto/tst_qtjson.cpp17
8 files changed, 307 insertions, 236 deletions
diff --git a/src/qjson_p.h b/src/qjson_p.h
index 1fb16ef..491a409 100644
--- a/src/qjson_p.h
+++ b/src/qjson_p.h
@@ -3,6 +3,8 @@
#include <qjsonglobal.h>
#include <qjsonobject.h>
+#include <qjsonvalue.h>
+#include <qjsonarray.h>
#include <qbasicatomic.h>
#include <qstring.h>
diff --git a/src/qjsondocument.cpp b/src/qjsondocument.cpp
index 440e102..26432d4 100644
--- a/src/qjsondocument.cpp
+++ b/src/qjsondocument.cpp
@@ -3,6 +3,7 @@
#include <qjsonvalue.h>
#include <qjsonarray.h>
#include <qjson_p.h>
+#include <qjsonwriter_p.h>
#include <qstringlist.h>
using namespace QtJson;
@@ -65,33 +66,49 @@ JsonDocument JsonDocument::fromData(const QByteArray &data)
return JsonDocument(d);
}
-JsonDocument JsonDocument::fromVariant(const QVariant &map)
+JsonDocument JsonDocument::fromVariant(const QVariant &v)
{
-// // ### this is implemented the trivial way, not the most efficient way
-
-// JsonDocument doc;
-// for (QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it)
-// object.insert(it.key(), JsonValue::fromVariant(it.value()));
-// return object;
+ JsonDocument doc;
+ if (v.type() == QVariant::Map) {
+ doc.setObject(JsonObject::fromVariantMap(v.toMap()));
+ } else if (v.type() == QVariant::List) {
+ doc.setArray(JsonArray::fromVariantList(v.toList()));
+ } else if (v.type() == QVariant::StringList) {
+ doc.setArray(JsonArray::fromStringList(v.toStringList()));
+ }
+ return doc;
}
QVariant JsonDocument::toVariant() const
{
-// QVariantMap map;
-// for (uint i = 0; i < o->length; ++i) {
-// Entry *e = o->entryAt(i);
-// map.insert(e->key(), JsonValue(d, e->value()).toVariant());
-// }
-// return map;
+ ValueType type = d ? (ValueType)d->_header->type : NullValue;
+ switch (type) {
+ case ArrayValue:
+ return JsonArray(d, static_cast<Array *>(&d->_header->root)).toVariantList();
+ break;
+ case ObjectValue:
+ return JsonObject(d, static_cast<Object *>(&d->_header->root)).toVariantMap();
+ break;
+ default:
+ break;
+ }
+ return QVariant();
}
QByteArray JsonDocument::toJson() const
{
QByteArray json;
-// json.reserve(o ? o->size/2 : 0);
-// json += "{\n";
-// objectContentToJson(o, json, 1);
-// json += "}\n";
+ ValueType type = d ? (ValueType)d->_header->type : NullValue;
+ switch (type) {
+ case ArrayValue:
+ QJsonWriter::arrayToJson(static_cast<Array *>(&d->_header->root), json, 0);
+ break;
+ case ObjectValue:
+ QJsonWriter::objectToJson(static_cast<Object *>(&d->_header->root), json, 0);
+ break;
+ default:
+ break;
+ }
return json;
}
diff --git a/src/qjsondocument.h b/src/qjsondocument.h
index 55d2511..2bb3906 100644
--- a/src/qjsondocument.h
+++ b/src/qjsondocument.h
@@ -16,7 +16,7 @@ public:
JsonDocument &operator =(const JsonDocument &other);
static JsonDocument fromData(const QByteArray &data);
- static JsonDocument fromVariant(const QVariant &map);
+ static JsonDocument fromVariant(const QVariant &v);
QVariant toVariant() const;
QByteArray toJson() const;
diff --git a/src/qjsonobject.cpp b/src/qjsonobject.cpp
index b624ebd..9b19845 100644
--- a/src/qjsonobject.cpp
+++ b/src/qjsonobject.cpp
@@ -2,6 +2,7 @@
#include <qjsonvalue.h>
#include <qjsonarray.h>
#include <qjson_p.h>
+#include <qjsonwriter_p.h>
#include <qstringlist.h>
using namespace QtJson;
@@ -81,225 +82,10 @@ QVariantMap JsonObject::toVariantMap() const
return map;
}
-static void objectContentToJson(const Object *o, QByteArray &json, int indent);
-static void arrayContentToJson(const Array *a, QByteArray &json, int indent);
-
-// some code from qutfcodec.cpp, inlined here for performance reasons
-// to allow fast escaping of strings
-static inline bool isUnicodeNonCharacter(uint ucs4)
-{
- // Unicode has a couple of "non-characters" that one can use internally,
- // but are not allowed to be used for text interchange.
- //
- // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
- // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
- // U+FDEF (inclusive)
-
- return (ucs4 & 0xfffe) == 0xfffe
- || (ucs4 - 0xfdd0U) < 16;
-}
-
-static inline uchar hexdig(uint u)
-{
- return (u < 0xa ? '0' + u : 'a' + u - 0xa);
-}
-
-static QByteArray escapedString(const QString &s)
-{
- const uchar replacement = '?';
- QByteArray ba(s.length(), Qt::Uninitialized);
-
- uchar *cursor = (uchar *)ba.data();
- const uchar *ba_end = cursor + ba.length();
-
- const QChar *ch = s.constData();
- const QChar *end = ch + s.length();
-
- int surrogate_high = -1;
-
- while (ch < end) {
- if (cursor >= ba_end - 6) {
- // ensure we have enough space
- int pos = cursor - (uchar *)ba.constData();
- ba.resize(ba.size()*2);
- cursor = (uchar *)ba.data() + pos;
- ba_end = (const uchar *)ba.constData() + ba.length();
- }
-
- uint u = ch->unicode();
- if (surrogate_high >= 0) {
- if (ch->isLowSurrogate()) {
- u = QChar::surrogateToUcs4(surrogate_high, u);
- surrogate_high = -1;
- } else {
- // high surrogate without low
- *cursor = replacement;
- ++ch;
- surrogate_high = -1;
- continue;
- }
- } else if (ch->isLowSurrogate()) {
- // low surrogate without high
- *cursor = replacement;
- ++ch;
- continue;
- } else if (ch->isHighSurrogate()) {
- surrogate_high = u;
- ++ch;
- continue;
- }
-
- if (u < 0x80) {
- if (u < 0x20 || u == 0x22 || u == 0x5c) {
- *cursor++ = '\\';
- switch (u) {
- case 0x22:
- *cursor++ = '"';
- break;
- case 0x5c:
- *cursor++ = '\\';
- break;
- case 0x8:
- *cursor++ = 'b';
- break;
- case 0xc:
- *cursor++ = 'f';
- break;
- case 0xa:
- *cursor++ = 'n';
- break;
- case 0xd:
- *cursor++ = 'r';
- break;
- case 0x9:
- *cursor++ = 't';
- break;
- default:
- *cursor++ = 'u';
- *cursor++ = '0';
- *cursor++ = '0';
- *cursor++ = hexdig(u>>4);
- *cursor++ = hexdig(u & 0xf);
- }
- } else {
- *cursor++ = (uchar)u;
- }
- } else {
- if (u < 0x0800) {
- *cursor++ = 0xc0 | ((uchar) (u >> 6));
- } else {
- // is it one of the Unicode non-characters?
- if (isUnicodeNonCharacter(u)) {
- *cursor++ = replacement;
- ++ch;
- continue;
- }
-
- if (u > 0xffff) {
- *cursor++ = 0xf0 | ((uchar) (u >> 18));
- *cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f);
- } else {
- *cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f);
- }
- *cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f);
- }
- *cursor++ = 0x80 | ((uchar) (u&0x3f));
- }
- ++ch;
- }
-
- ba.resize(cursor - (const uchar *)ba.constData());
- return ba;
-}
-
-static void valueToJson(const Value *v, QByteArray &json, int indent)
-{
- ValueType type = v ? (ValueType)v->type : NullValue;
- switch (type) {
- case BooleanValue:
- json += v->val ? "true" : "false";
- break;
- case NumberValue:
- json += QByteArray::number(v->toNumber());
- break;
- case StringValue:
- json += '"';
- json += escapedString(v->shallowString());
- json += '"';
- break;
- case ArrayValue:
- json += "[\n";
- arrayContentToJson(v->array(), json, indent + 1);
- json += QByteArray(4*indent, ' ');
- json += "]";
- break;
- case ObjectValue:
- json += "{\n";
- objectContentToJson(v->object(), json, indent + 1);
- json += QByteArray(4*indent, ' ');
- json += "}";
- break;
- case NullValue:
- default:
- json += "null";
- }
-}
-
-static void arrayContentToJson(const Array *a, QByteArray &json, int indent)
-{
- if (!a || !a->length)
- return;
-
- QByteArray indentString(4*indent, ' ');
-
- uint i = 0;
- while (1) {
- json += indentString;
- valueToJson(a->at(i), json, indent);
-
- if (++i == a->length) {
- json += '\n';
- break;
- }
-
- json += ",\n";
- }
-}
-
-
-static void objectContentToJson(const Object *o, QByteArray &json, int indent)
-{
- if (!o || !o->length)
- return;
-
- QByteArray indentString(4*indent, ' ');
-
- uint i = 0;
- while (1) {
- Entry *e = o->entryAt(i);
- json += indentString;
- json += '"';
- json += escapedString(e->shallowKey());
- json += "\": ";
- const Value *v = e->value();
- valueToJson(v, json, indent);
-
- if (++i == o->length) {
- json += '\n';
- break;
- }
-
- json += ",\n";
- }
-}
-
QByteArray JsonObject::toJson() const
{
QByteArray json;
- json.reserve(o ? o->size/2 : 0);
- json += "{\n";
- objectContentToJson(o, json, 1);
- json += "}\n";
+ QJsonWriter::objectToJson(o, json, 0);
return json;
}
diff --git a/src/qjsonwriter.cpp b/src/qjsonwriter.cpp
new file mode 100644
index 0000000..133403d
--- /dev/null
+++ b/src/qjsonwriter.cpp
@@ -0,0 +1,234 @@
+#include <qjsonwriter_p.h>
+#include <qjson_p.h>
+
+using namespace QtJson;
+
+static void objectContentToJson(const Object *o, QByteArray &json, int indent);
+static void arrayContentToJson(const Array *a, QByteArray &json, int indent);
+
+// some code from qutfcodec.cpp, inlined here for performance reasons
+// to allow fast escaping of strings
+static inline bool isUnicodeNonCharacter(uint ucs4)
+{
+ // Unicode has a couple of "non-characters" that one can use internally,
+ // but are not allowed to be used for text interchange.
+ //
+ // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
+ // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
+ // U+FDEF (inclusive)
+
+ return (ucs4 & 0xfffe) == 0xfffe
+ || (ucs4 - 0xfdd0U) < 16;
+}
+
+static inline uchar hexdig(uint u)
+{
+ return (u < 0xa ? '0' + u : 'a' + u - 0xa);
+}
+
+static QByteArray escapedString(const QString &s)
+{
+ const uchar replacement = '?';
+ QByteArray ba(s.length(), Qt::Uninitialized);
+
+ uchar *cursor = (uchar *)ba.data();
+ const uchar *ba_end = cursor + ba.length();
+
+ const QChar *ch = s.constData();
+ const QChar *end = ch + s.length();
+
+ int surrogate_high = -1;
+
+ while (ch < end) {
+ if (cursor >= ba_end - 6) {
+ // ensure we have enough space
+ int pos = cursor - (uchar *)ba.constData();
+ ba.resize(ba.size()*2);
+ cursor = (uchar *)ba.data() + pos;
+ ba_end = (const uchar *)ba.constData() + ba.length();
+ }
+
+ uint u = ch->unicode();
+ if (surrogate_high >= 0) {
+ if (ch->isLowSurrogate()) {
+ u = QChar::surrogateToUcs4(surrogate_high, u);
+ surrogate_high = -1;
+ } else {
+ // high surrogate without low
+ *cursor = replacement;
+ ++ch;
+ surrogate_high = -1;
+ continue;
+ }
+ } else if (ch->isLowSurrogate()) {
+ // low surrogate without high
+ *cursor = replacement;
+ ++ch;
+ continue;
+ } else if (ch->isHighSurrogate()) {
+ surrogate_high = u;
+ ++ch;
+ continue;
+ }
+
+ if (u < 0x80) {
+ if (u < 0x20 || u == 0x22 || u == 0x5c) {
+ *cursor++ = '\\';
+ switch (u) {
+ case 0x22:
+ *cursor++ = '"';
+ break;
+ case 0x5c:
+ *cursor++ = '\\';
+ break;
+ case 0x8:
+ *cursor++ = 'b';
+ break;
+ case 0xc:
+ *cursor++ = 'f';
+ break;
+ case 0xa:
+ *cursor++ = 'n';
+ break;
+ case 0xd:
+ *cursor++ = 'r';
+ break;
+ case 0x9:
+ *cursor++ = 't';
+ break;
+ default:
+ *cursor++ = 'u';
+ *cursor++ = '0';
+ *cursor++ = '0';
+ *cursor++ = hexdig(u>>4);
+ *cursor++ = hexdig(u & 0xf);
+ }
+ } else {
+ *cursor++ = (uchar)u;
+ }
+ } else {
+ if (u < 0x0800) {
+ *cursor++ = 0xc0 | ((uchar) (u >> 6));
+ } else {
+ // is it one of the Unicode non-characters?
+ if (isUnicodeNonCharacter(u)) {
+ *cursor++ = replacement;
+ ++ch;
+ continue;
+ }
+
+ if (u > 0xffff) {
+ *cursor++ = 0xf0 | ((uchar) (u >> 18));
+ *cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f);
+ } else {
+ *cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f);
+ }
+ *cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f);
+ }
+ *cursor++ = 0x80 | ((uchar) (u&0x3f));
+ }
+ ++ch;
+ }
+
+ ba.resize(cursor - (const uchar *)ba.constData());
+ return ba;
+}
+
+static void valueToJson(const Value *v, QByteArray &json, int indent)
+{
+ ValueType type = v ? (ValueType)v->type : NullValue;
+ switch (type) {
+ case BooleanValue:
+ json += v->val ? "true" : "false";
+ break;
+ case NumberValue:
+ json += QByteArray::number(v->toNumber());
+ break;
+ case StringValue:
+ json += '"';
+ json += escapedString(v->shallowString());
+ json += '"';
+ break;
+ case ArrayValue:
+ json += "[\n";
+ arrayContentToJson(v->array(), json, indent + 1);
+ json += QByteArray(4*indent, ' ');
+ json += "]";
+ break;
+ case ObjectValue:
+ json += "{\n";
+ objectContentToJson(v->object(), json, indent + 1);
+ json += QByteArray(4*indent, ' ');
+ json += "}";
+ break;
+ case NullValue:
+ default:
+ json += "null";
+ }
+}
+
+static void arrayContentToJson(const Array *a, QByteArray &json, int indent)
+{
+ if (!a || !a->length)
+ return;
+
+ QByteArray indentString(4*indent, ' ');
+
+ uint i = 0;
+ while (1) {
+ json += indentString;
+ valueToJson(a->at(i), json, indent);
+
+ if (++i == a->length) {
+ json += '\n';
+ break;
+ }
+
+ json += ",\n";
+ }
+}
+
+
+static void objectContentToJson(const Object *o, QByteArray &json, int indent)
+{
+ if (!o || !o->length)
+ return;
+
+ QByteArray indentString(4*indent, ' ');
+
+ uint i = 0;
+ while (1) {
+ Entry *e = o->entryAt(i);
+ json += indentString;
+ json += '"';
+ json += escapedString(e->shallowKey());
+ json += "\": ";
+ const Value *v = e->value();
+ valueToJson(v, json, indent);
+
+ if (++i == o->length) {
+ json += '\n';
+ break;
+ }
+
+ json += ",\n";
+ }
+}
+
+void QJsonWriter::objectToJson(const Object *o, QByteArray &json, int indent)
+{
+ json.reserve(json.size() + (o ? o->size : 16));
+ json += "{\n";
+ objectContentToJson(o, json, indent + 1);
+ json += QByteArray(4*indent, ' ');
+ json += "}\n";
+}
+
+void QJsonWriter::arrayToJson(const Array *a, QByteArray &json, int indent)
+{
+ json.reserve(json.size() + (a ? a->size : 16));
+ json += "[\n";
+ arrayContentToJson(a, json, indent + 1);
+ json += QByteArray(4*indent, ' ');
+ json += "]\n";
+}
diff --git a/src/qjsonwriter_p.h b/src/qjsonwriter_p.h
new file mode 100644
index 0000000..8eedb7b
--- /dev/null
+++ b/src/qjsonwriter_p.h
@@ -0,0 +1,13 @@
+#include <qjsonglobal.h>
+
+namespace QtJson
+{
+
+class QJsonWriter
+{
+public:
+ static void objectToJson(const Object *o, QByteArray &json, int indent);
+ static void arrayToJson(const Array *a, QByteArray &json, int indent);
+};
+
+}
diff --git a/src/src.pro b/src/src.pro
index a9a688c..ed34e65 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -11,13 +11,15 @@ HEADERS += \
qjsonobject.h \
qjsonglobal.h \
qjsonvalue.h \
- qjsonarray.h
+ qjsonarray.h \
+ qjsonwriter_p.h
SOURCES += \
qjsondocument.cpp \
qjsonobject.cpp \
qjsonarray.cpp \
- qjsonvalue.cpp
+ qjsonvalue.cpp \
+ qjsonwriter.cpp
diff --git a/tests/auto/tst_qtjson.cpp b/tests/auto/tst_qtjson.cpp
index 9fa1258..3e6cf19 100644
--- a/tests/auto/tst_qtjson.cpp
+++ b/tests/auto/tst_qtjson.cpp
@@ -562,6 +562,23 @@ void TestQtJson::toJson()
" ]\n"
"}\n";
QCOMPARE(json, expected);
+
+ JsonDocument doc;
+ doc.setObject(object);
+ json = doc.toJson();
+ QCOMPARE(json, expected);
+
+ doc.setArray(array);
+ json = doc.toJson();
+ expected =
+ "[\n"
+ " true,\n"
+ " 999,\n"
+ " \"string\",\n"
+ " null,\n"
+ " \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n"
+ "]\n";
+ QCOMPARE(json, expected);
}