summaryrefslogtreecommitdiffstats
path: root/src/corelib/json/qjsondocument.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/json/qjsondocument.cpp')
-rw-r--r--src/corelib/json/qjsondocument.cpp536
1 files changed, 536 insertions, 0 deletions
diff --git a/src/corelib/json/qjsondocument.cpp b/src/corelib/json/qjsondocument.cpp
new file mode 100644
index 0000000000..e76756da69
--- /dev/null
+++ b/src/corelib/json/qjsondocument.cpp
@@ -0,0 +1,536 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qjsondocument.h>
+#include <qjsonobject.h>
+#include <qjsonvalue.h>
+#include <qjsonarray.h>
+#include <qstringlist.h>
+#include <qdebug.h>
+#include "qjsonwriter_p.h"
+#include "qjsonparser_p.h"
+#include "qjson_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*! \class QJsonDocument
+ \ingroup json
+ \reentrant
+ \since 5.0
+
+ \brief The QJsonDocument class provides a way to read and write JSON documents.
+
+ QJsonDocument is a class that wraps a complete JSON document and can read and
+ write this document both from a UTF-8 encoded text based representation as well
+ as Qt's own binary format.
+
+ A JSON document can be converted from its text-based representation to a QJsonDocument
+ using QJsonDocument::fromJson(). toJson() converts it back to text. The parser is very
+ fast and efficient and converts the JSON to the binary representation used by Qt.
+
+ Validity of the parsed document can be queried with !isNull()
+
+ A document can be queried as to whether it contains an array or an object using isArray()
+ and isObject(). The array or object contained in the document can be retrieved using
+ array() or object() and then read or manipulated.
+
+ A document can also be created from a stored binary representation using fromBinaryData() or
+ fromRawData().
+*/
+
+/*!
+ * Constructs an empty and invalid document.
+ */
+QJsonDocument::QJsonDocument()
+ : d(0)
+{
+}
+
+/*!
+ * Creates a QJsonDocument from \a object.
+ */
+QJsonDocument::QJsonDocument(const QJsonObject &object)
+ : d(0)
+{
+ setObject(object);
+}
+
+/*!
+ * Constructs a QJsonDocument from \a array.
+ */
+QJsonDocument::QJsonDocument(const QJsonArray &array)
+ : d(0)
+{
+ setArray(array);
+}
+
+/*! \internal
+ */
+QJsonDocument::QJsonDocument(QJsonPrivate::Data *data)
+ : d(data)
+{
+ Q_ASSERT(d);
+ d->ref.ref();
+}
+
+/*!
+ Deletes the document.
+
+ Binary data set with fromRawData is not freed.
+ */
+QJsonDocument::~QJsonDocument()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ * Creates a copy of the \a other document.
+ */
+QJsonDocument::QJsonDocument(const QJsonDocument &other)
+{
+ d = other.d;
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ * Assigns the \a other document to this QJsonDocument.
+ * Returns a reference to this object.
+ */
+QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
+{
+ if (d != other.d) {
+ if (d && !d->ref.deref())
+ delete d;
+ d = other.d;
+ if (d)
+ d->ref.ref();
+ }
+
+ return *this;
+}
+
+/*! \enum QJsonDocument::DataValidation
+
+ This value is used to tell QJsonDocument whether to validate the binary data
+ when converting to a QJsonDocument using fromBinaryData() or fromRawData().
+
+ \value Validate Validate the data before using it. This is the default.
+ \value BypassValidation Bypasses data validation. Only use if you received the
+ data from a trusted place and know it's valid, as using of invalid data can crash
+ the application.
+ */
+
+/*!
+ Creates a QJsonDocument that uses the first \a size bytes from
+ \a data. It assumes \a data contains a binary encoded JSON document.
+ The created document does not take ownership of \a data and the caller
+ has to guarantee that \a data will not be deleted or modified as long as
+ any QJsonDocument, QJsonObject or QJsonArray still references the data.
+
+ \a data has to be aligned to a 4 byte boundary.
+
+ \a validation decides whether the data is checked for validity before being used.
+ By default the data is validated. If the \a data is not valid, the method returns
+ a null document.
+
+ Returns a QJsonDocument representing the data.
+
+ \sa rawData fromBinaryData isNull DataValidation
+ */
+QJsonDocument QJsonDocument::fromRawData(const char *data, int size, DataValidation validation)
+{
+ if (!(((quintptr)validation) & ~3)) {
+ qWarning() <<"QJsonDocumnt::fromRawData: data has to have 4 byte alignment";
+ return QJsonDocument();
+ }
+
+ QJsonPrivate::Data *d = new QJsonPrivate::Data((char *)data, size);
+ d->ownsData = false;
+
+ if (validation != BypassValidation && !d->valid()) {
+ delete d;
+ return QJsonDocument();
+ }
+
+ return QJsonDocument(d);
+}
+
+/*!
+ Returns the raw binary representation of the data
+ \a size will contain the size of the \a data.
+
+ This method is useful to e.g. stream the JSON document
+ in it's binary form to a file.
+ */
+const char *QJsonDocument::rawData(int *size) const
+{
+ if (!d) {
+ *size = 0;
+ return 0;
+ }
+ *size = d->alloc;
+ return d->rawData;
+}
+
+/*!
+ Creates a QJsonDocument from \a data.
+
+ \a validation decides whether the data is checked for validity before being used.
+ By default the data is validated. If the \a data is not valid, the method returns
+ a null document.
+
+ \sa toBinaryData fromRawData isNull DataValidation
+ */
+QJsonDocument QJsonDocument::fromBinaryData(const QByteArray &data, DataValidation validation)
+{
+ QJsonPrivate::Header h;
+ memcpy(&h, data.constData(), sizeof(QJsonPrivate::Header));
+ QJsonPrivate::Base root;
+ memcpy(&root, data.constData() + sizeof(QJsonPrivate::Header), sizeof(QJsonPrivate::Base));
+
+ // do basic checks here, so we don't try to allocate more memory than we can.
+ if (data.size() < (int)(sizeof(QJsonPrivate::Header) + sizeof(QJsonPrivate::Base)) ||
+ h.tag != QJsonDocument::BinaryFormatTag || h.version != 1u ||
+ sizeof(QJsonPrivate::Header) + root.size > (uint)data.size())
+ return QJsonDocument();
+
+ char *raw = (char *)malloc(data.size());
+ if (!raw)
+ return QJsonDocument();
+
+ memcpy(raw, data.constData(), data.size());
+ QJsonPrivate::Data *d = new QJsonPrivate::Data(raw, data.size());
+
+ if (validation != BypassValidation && !d->valid()) {
+ delete d;
+ return QJsonDocument();
+ }
+
+ return QJsonDocument(d);
+}
+
+/*!
+ Creates a QJsonDocument from the QVariant \a variant.
+
+ If the \a variant contains any other type than a QVariant::Map,
+ QVariant::List or QVariant::StringList, the returned document
+ document is invalid.
+
+ \sa toVariant
+ */
+QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
+{
+ QJsonDocument doc;
+ if (variant.type() == QVariant::Map) {
+ doc.setObject(QJsonObject::fromVariantMap(variant.toMap()));
+ } else if (variant.type() == QVariant::List) {
+ doc.setArray(QJsonArray::fromVariantList(variant.toList()));
+ } else if (variant.type() == QVariant::StringList) {
+ doc.setArray(QJsonArray::fromStringList(variant.toStringList()));
+ }
+ return doc;
+}
+
+/*!
+ Returns a QVariant representing the Json document.
+
+ The returned variant will be a QVariantList if the document is
+ a QJsonArray and a QVariantMap if the document is a QJsonObject.
+
+ \sa fromVariant, QJsonValue::toVariant()
+ */
+QVariant QJsonDocument::toVariant() const
+{
+ if (!d)
+ return QVariant();
+
+ if (d->header->root()->isArray())
+ return QJsonArray(d, static_cast<QJsonPrivate::Array *>(d->header->root())).toVariantList();
+ else
+ return QJsonObject(d, static_cast<QJsonPrivate::Object *>(d->header->root())).toVariantMap();
+}
+
+/*!
+ Converts the QJsonDocument to a UTF-8 encoded JSON document.
+
+ \sa fromJson
+ */
+QByteArray QJsonDocument::toJson() const
+{
+ if (!d)
+ return QByteArray();
+
+ QByteArray json;
+
+ if (d->header->root()->isArray())
+ QJsonPrivate::Writer::arrayToJson(static_cast<QJsonPrivate::Array *>(d->header->root()), json, 0);
+ else
+ QJsonPrivate::Writer::objectToJson(static_cast<QJsonPrivate::Object *>(d->header->root()), json, 0);
+
+ return json;
+}
+
+/*!
+ Parses a UTF-8 encoded JSON document and creates a QJsonDocument
+ from it. isNull() will return \c false if no error was encountered during
+ parsing.
+
+ \sa toJson
+ */
+QJsonDocument QJsonDocument::fromJson(const QByteArray &json)
+{
+ QJsonPrivate::Parser parser(json.constData(), json.length());
+ return parser.parse();
+}
+
+/*!
+ Returns true if the document doesn't contain any data.
+ */
+bool QJsonDocument::isEmpty() const
+{
+ if (!d)
+ return true;
+
+ return false;
+}
+
+/*!
+ Returns a binary representation of the document.
+
+ The binary representation is also the native format used internally in Qt,
+ and is very efficient and fast to convert to and from.
+
+ The binary format can be stored on disk and interchanged with other applications
+ or computers. fromBinaryData() can be used to convert it back into a
+ JSON document.
+
+ \sa fromBinaryData
+ */
+QByteArray QJsonDocument::toBinaryData() const
+{
+ if (!d || !d->rawData)
+ return QByteArray();
+
+ return QByteArray(d->rawData, d->header->root()->size + sizeof(QJsonPrivate::Header));
+}
+
+/*!
+ Returns true if the document contains an array.
+
+ \sa array() isObject()
+ */
+bool QJsonDocument::isArray() const
+{
+ if (!d)
+ return false;
+
+ QJsonPrivate::Header *h = (QJsonPrivate::Header *)d->rawData;
+ return h->root()->isArray();
+}
+
+/*!
+ Returns true if the document contains an object.
+
+ \sa object() isArray()
+ */
+bool QJsonDocument::isObject() const
+{
+ if (!d)
+ return false;
+
+ QJsonPrivate::Header *h = (QJsonPrivate::Header *)d->rawData;
+ return h->root()->isObject();
+}
+
+/*!
+ Returns the QJsonObject contained in the document.
+
+ Returns an empty object if the document contains an
+ array.
+
+ \sa isObject array setObject
+ */
+QJsonObject QJsonDocument::object() const
+{
+ if (d) {
+ QJsonPrivate::Base *b = d->header->root();
+ if (b->isObject())
+ return QJsonObject(d, static_cast<QJsonPrivate::Object *>(b));
+ }
+ return QJsonObject();
+}
+
+/*!
+ Returns the QJsonArray contained in the document.
+
+ Returns an empty array if the document contains an
+ object.
+
+ \sa isArray object setArray
+ */
+QJsonArray QJsonDocument::array() const
+{
+ if (d) {
+ QJsonPrivate::Base *b = d->header->root();
+ if (b->isArray())
+ return QJsonArray(d, static_cast<QJsonPrivate::Array *>(b));
+ }
+ return QJsonArray();
+}
+
+/*!
+ Sets \a object as the main object of this document.
+
+ \sa setArray object
+ */
+void QJsonDocument::setObject(const QJsonObject &object)
+{
+ if (d && !d->ref.deref())
+ delete d;
+
+ d = object.d;
+
+ if (!d) {
+ d = new QJsonPrivate::Data(0, QJsonValue::Object);
+ } else if (d->compactionCounter || object.o != d->header->root()) {
+ QJsonObject o(object);
+ if (d->compactionCounter)
+ o.compact();
+ else
+ o.detach();
+ d = o.d;
+ d->ref.ref();
+ return;
+ }
+ d->ref.ref();
+}
+
+/*!
+ Sets \a array as the main object of this document.
+
+ \sa setObject array
+ */
+void QJsonDocument::setArray(const QJsonArray &array)
+{
+ if (d && !d->ref.deref())
+ delete d;
+
+ d = array.d;
+
+ if (!d) {
+ d = new QJsonPrivate::Data(0, QJsonValue::Array);
+ } else if (d->compactionCounter || array.a != d->header->root()) {
+ QJsonArray a(array);
+ if (d->compactionCounter)
+ a.compact();
+ else
+ a.detach();
+ d = a.d;
+ d->ref.ref();
+ return;
+ }
+ d->ref.ref();
+}
+
+/*!
+ Returns \c true if the \a other document is equal to this document.
+ */
+bool QJsonDocument::operator==(const QJsonDocument &other) const
+{
+ if (d == other.d)
+ return true;
+
+ if (!d || !other.d)
+ return false;
+
+ if (d->header->root()->isArray() != other.d->header->root()->isArray())
+ return false;
+
+ if (d->header->root()->isObject())
+ return QJsonObject(d, static_cast<QJsonPrivate::Object *>(d->header->root()))
+ == QJsonObject(other.d, static_cast<QJsonPrivate::Object *>(other.d->header->root()));
+ else
+ return QJsonArray(d, static_cast<QJsonPrivate::Array *>(d->header->root()))
+ == QJsonArray(other.d, static_cast<QJsonPrivate::Array *>(other.d->header->root()));
+}
+
+/*!
+ \fn bool QJsonDocument::operator!=(const QJsonDocument &other) const
+
+ returns \c true if \a other is not equal to this document
+ */
+
+/*!
+ returns true if this document is null.
+
+ Null documents are documents created through the default constructor.
+
+ Documents created from UTF-8 encoded text or the binary format are
+ validated during parsing. If validation fails, the returned document
+ will also be null.
+ */
+bool QJsonDocument::isNull() const
+{
+ return (d == 0);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QJsonDocument &o)
+{
+ if (!o.d) {
+ dbg << "QJsonDocument()";
+ return dbg;
+ }
+ QByteArray json;
+ if (o.d->header->root()->isArray())
+ QJsonPrivate::Writer::arrayToJson(static_cast<QJsonPrivate::Array *>(o.d->header->root()), json, 0, true);
+ else
+ QJsonPrivate::Writer::objectToJson(static_cast<QJsonPrivate::Object *>(o.d->header->root()), json, 0, true);
+ dbg.nospace() << "QJsonDocument("
+ << json.constData() // print as utf-8 string without extra quotation marks
+ << ")";
+ return dbg.space();
+}
+#endif
+
+QT_END_NAMESPACE