Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjsondocument.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include <qjsondocument.h>
6#include <qjsonobject.h>
7#include <qjsonvalue.h>
8#include <qjsonarray.h>
9#include <qstringlist.h>
10#include <qvariant.h>
11#include <qmap.h>
12#include <qhash.h>
13#include <qdebug.h>
14#include <qcbormap.h>
15#include <qcborarray.h>
16#include "qjsonparser_p.h"
17#include "qjson_p.h"
18#include "qdatastream.h"
19
21
22/*! \class QJsonDocument
23 \inmodule QtCore
24 \ingroup json
25 \ingroup shared
26 \ingroup qtserialization
27 \reentrant
28 \since 5.0
29
30 \brief The QJsonDocument class provides a way to read and write JSON documents.
31
32 \compares equality
33
34 QJsonDocument is a class that wraps a complete JSON document and can read
35 this document from, and write it to, a UTF-8 encoded text-based
36 representation.
37
38 A JSON document can be converted from its text-based representation to a QJsonDocument
39 using QJsonDocument::fromJson(). toJson() converts it back to text. The parser is very
40 fast and efficient and converts the JSON to the binary representation used by Qt.
41
42 Validity of the parsed document can be queried with !isNull()
43
44 A document can be queried as to whether it contains an array or an object using isArray()
45 and isObject(). The array or object contained in the document can be retrieved using
46 array() or object() and then read or manipulated.
47
48 \sa {JSON Support in Qt}, {Saving and Loading a Game}
49*/
50
51
53{
55public:
57 QJsonDocumentPrivate(QCborValue data) : value(std::move(data)) {}
58
59 QCborValue value;
60};
61
62/*!
63 * Constructs an empty and invalid document.
64 */
65QJsonDocument::QJsonDocument()
66 : d(nullptr)
67{
68}
69
70/*!
71 * Creates a QJsonDocument from \a object.
72 */
73QJsonDocument::QJsonDocument(const QJsonObject &object)
74 : d(nullptr)
75{
76 setObject(object);
77}
78
79/*!
80 * Constructs a QJsonDocument from \a array.
81 */
82QJsonDocument::QJsonDocument(const QJsonArray &array)
83 : d(nullptr)
84{
85 setArray(array);
86}
87
88/*!
89 \internal
90 */
91QJsonDocument::QJsonDocument(const QCborValue &data)
92 : d(std::make_unique<QJsonDocumentPrivate>(data))
93{
94 Q_ASSERT(d);
95}
96
97/*!
98 Deletes the document.
99
100 Binary data set with fromRawData is not freed.
101 */
102QJsonDocument::~QJsonDocument() = default;
103
104/*!
105 * Creates a copy of the \a other document.
106 */
107QJsonDocument::QJsonDocument(const QJsonDocument &other)
108{
109 if (other.d) {
110 if (!d)
111 d = std::make_unique<QJsonDocumentPrivate>();
112 d->value = other.d->value;
113 } else {
114 d.reset();
115 }
116}
117
118QJsonDocument::QJsonDocument(QJsonDocument &&other) noexcept
119 : d(std::move(other.d))
120{
121}
122
123void QJsonDocument::swap(QJsonDocument &other) noexcept
124{
125 qSwap(d, other.d);
126}
127
128/*!
129 * Assigns the \a other document to this QJsonDocument.
130 * Returns a reference to this object.
131 */
132QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
133{
134 if (this != &other) {
135 if (other.d) {
136 if (!d)
137 d = std::make_unique<QJsonDocumentPrivate>();
138 d->value = other.d->value;
139 } else {
140 d.reset();
141 }
142 }
143 return *this;
144}
145
146/*!
147 \fn QJsonDocument::QJsonDocument(QJsonDocument &&other)
148 \since 5.10
149
150 Move-constructs a QJsonDocument from \a other.
151*/
152
153/*!
154 \fn QJsonDocument &QJsonDocument::operator =(QJsonDocument &&other)
155 \since 5.10
156
157 Move-assigns \a other to this document.
158*/
159
160/*!
161 \fn void QJsonDocument::swap(QJsonDocument &other)
162 \since 5.10
163 \memberswap{document}
164*/
165
166#ifndef QT_NO_VARIANT
167/*!
168 Creates a QJsonDocument from the QVariant \a variant.
169
170 If the \a variant contains any other type than a QVariantMap,
171 QVariantHash, QVariantList or QStringList, the returned document is invalid.
172
173 \sa toVariant()
174 */
175QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
176{
177 QJsonDocument doc;
178
179 switch (variant.metaType().id()) {
180 case QMetaType::QVariantMap:
181 doc.setObject(QJsonObject::fromVariantMap(variant.toMap()));
182 break;
183 case QMetaType::QVariantHash:
184 doc.setObject(QJsonObject::fromVariantHash(variant.toHash()));
185 break;
186 case QMetaType::QVariantList:
187 doc.setArray(QJsonArray::fromVariantList(variant.toList()));
188 break;
189 case QMetaType::QStringList:
190 doc.d = std::make_unique<QJsonDocumentPrivate>();
191 doc.d->value = QCborArray::fromStringList(variant.toStringList());
192 break;
193 default:
194 break;
195 }
196 return doc;
197}
198
199/*!
200 Returns a QVariant representing the Json document.
201
202 The returned variant will be a QVariantList if the document is
203 a QJsonArray and a QVariantMap if the document is a QJsonObject.
204
205 \sa fromVariant(), QJsonValue::toVariant()
206 */
207QVariant QJsonDocument::toVariant() const
208{
209 if (!d)
210 return QVariant();
211
212 QCborContainerPrivate *container = QJsonPrivate::Value::container(d->value);
213 if (d->value.isArray())
214 return QJsonArray(container).toVariantList();
215 return QJsonObject(container).toVariantMap();
216}
217#endif // !QT_NO_VARIANT
218
219/*!
220\if !defined(qt7)
221 \enum QJsonDocument::JsonFormat
222 \since 5.1
223
224 This value defines the format of the JSON byte array produced
225 when converting to a QJsonDocument using toJson().
226
227 \value Indented Defines human readable output as follows:
228 \snippet code/src_corelib_serialization_qjsondocument.cpp 0
229
230 \value Compact Defines a compact output as follows:
231 \snippet code/src_corelib_serialization_qjsondocument.cpp 1
232\else
233 \typealias QJsonDocument::JsonFormat
234 \since 5.1
235
236 Same as \l QJsonValue::JsonFormat.
237\endif
238 */
239
240/*!
241 \since 5.1
242 Converts the QJsonDocument to a UTF-8 encoded JSON document in the provided \a format.
243
244 \sa fromJson(), JsonFormat
245 */
246QByteArray QJsonDocument::toJson(JsonFormat format) const
247{
248 QByteArray json;
249 if (!d)
250 return json;
251
252 return QJsonPrivate::Value::fromTrustedCbor(d->value).toJson(
253 format == JsonFormat::Compact ? QJsonValue::JsonFormat::Compact
254 : QJsonValue::JsonFormat::Indented);
255}
256
257/*!
258 Parses \a json as a UTF-8 encoded JSON document, and creates a QJsonDocument
259 from it.
260
261 Returns a valid (non-null) QJsonDocument if the parsing succeeds. If it fails,
262 the returned document will be null, and the optional \a error variable will contain
263 further details about the error.
264
265 \sa toJson(), QJsonParseError, isNull()
266 */
267QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error)
268{
269 QJsonPrivate::Parser parser(json);
270 QJsonDocument result;
271 const QCborValue val = parser.parse(error);
272 if (val.isArray() || val.isMap()) {
273 result.d = std::make_unique<QJsonDocumentPrivate>();
274 result.d->value = val;
275 } else if (!val.isUndefined() && error) {
276 // parsed a valid string/number/bool/null,
277 // but QJsonDocument only stores objects and arrays.
278 error->error = QJsonParseError::IllegalValue;
279 error->offset = 0;
280 }
281 return result;
282}
283
284/*!
285 Returns \c true if the document doesn't contain any data.
286 */
287bool QJsonDocument::isEmpty() const
288{
289 if (!d)
290 return true;
291
292 return false;
293}
294
295/*!
296 Returns \c true if the document contains an array.
297
298 \sa array(), isObject()
299 */
300bool QJsonDocument::isArray() const
301{
302 if (!d)
303 return false;
304
305 return d->value.isArray();
306}
307
308/*!
309 Returns \c true if the document contains an object.
310
311 \sa object(), isArray()
312 */
313bool QJsonDocument::isObject() const
314{
315 if (!d)
316 return false;
317
318 return d->value.isMap();
319}
320
321/*!
322 Returns the QJsonObject contained in the document.
323
324 Returns an empty object if the document contains an
325 array.
326
327 \sa isObject(), array(), setObject()
328 */
329QJsonObject QJsonDocument::object() const
330{
331 if (isObject()) {
332 if (auto container = QJsonPrivate::Value::container(d->value))
333 return QJsonObject(container);
334 }
335 return QJsonObject();
336}
337
338/*!
339 Returns the QJsonArray contained in the document.
340
341 Returns an empty array if the document contains an
342 object.
343
344 \sa isArray(), object(), setArray()
345 */
346QJsonArray QJsonDocument::array() const
347{
348 if (isArray()) {
349 if (auto container = QJsonPrivate::Value::container(d->value))
350 return QJsonArray(container);
351 }
352 return QJsonArray();
353}
354
355/*!
356 Sets \a object as the main object of this document.
357
358 \sa setArray(), object()
359 */
360void QJsonDocument::setObject(const QJsonObject &object)
361{
362 if (!d)
363 d = std::make_unique<QJsonDocumentPrivate>();
364
365 d->value = QCborValue::fromJsonValue(object);
366}
367
368/*!
369 Sets \a array as the main object of this document.
370
371 \sa setObject(), array()
372 */
373void QJsonDocument::setArray(const QJsonArray &array)
374{
375 if (!d)
376 d = std::make_unique<QJsonDocumentPrivate>();
377
378 d->value = QCborValue::fromJsonValue(array);
379}
380
381/*!
382 Returns a QJsonValue representing the value for the key \a key.
383
384 Equivalent to calling object().value(key).
385
386 The returned QJsonValue is QJsonValue::Undefined if the key does not exist,
387 or if isObject() is false.
388
389 \since 5.10
390
391 \sa QJsonValue, QJsonValue::isUndefined(), QJsonObject
392 */
393const QJsonValue QJsonDocument::operator[](const QString &key) const
394{
395 return (*this)[QStringView(key)];
396}
397
398/*!
399 \overload
400 \since 5.14
401*/
402const QJsonValue QJsonDocument::operator[](QStringView key) const
403{
404 if (!isObject())
405 return QJsonValue(QJsonValue::Undefined);
406
407 return QJsonPrivate::Value::fromTrustedCbor(d->value.toMap().value(key));
408}
409
410/*!
411 \overload
412 \since 5.10
413*/
414const QJsonValue QJsonDocument::operator[](QLatin1StringView key) const
415{
416 if (!isObject())
417 return QJsonValue(QJsonValue::Undefined);
418
419 return QJsonPrivate::Value::fromTrustedCbor(d->value.toMap().value(key));
420}
421
422/*!
423 Returns a QJsonValue representing the value for index \a i.
424
425 Equivalent to calling array().at(i).
426
427 The returned QJsonValue is QJsonValue::Undefined, if \a i is out of bounds,
428 or if isArray() is false.
429
430 \since 5.10
431
432 \sa QJsonValue, QJsonValue::isUndefined(), QJsonArray
433 */
434const QJsonValue QJsonDocument::operator[](qsizetype i) const
435{
436 if (!isArray())
437 return QJsonValue(QJsonValue::Undefined);
438
439 return QJsonPrivate::Value::fromTrustedCbor(d->value.toArray().at(i));
440}
441
442/*!
443 \fn bool QJsonDocument::operator==(const QJsonDocument &lhs, const QJsonDocument &rhs)
444
445 Returns \c true if the \a lhs document is equal to \a rhs document, \c false otherwise.
446*/
447bool comparesEqual(const QJsonDocument &lhs, const QJsonDocument &rhs) noexcept
448{
449 if (lhs.d && rhs.d)
450 return lhs.d->value == rhs.d->value;
451 return !lhs.d == !rhs.d;
452}
453
454/*!
455 \fn bool QJsonDocument::operator!=(const QJsonDocument &lhs, const QJsonDocument &rhs)
456
457 Returns \c true if the \a lhs document is not equal to \a rhs document, \c false otherwise.
458*/
459
460/*!
461 returns \c true if this document is null.
462
463 Null documents are documents created through the default constructor.
464
465 Documents created from UTF-8 encoded text or the binary format are
466 validated during parsing. If validation fails, the returned document
467 will also be null.
468 */
469bool QJsonDocument::isNull() const
470{
471 return (d == nullptr);
472}
473
474#if !defined(QT_NO_DEBUG_STREAM)
475QDebug operator<<(QDebug dbg, const QJsonDocument &o)
476{
477 QDebugStateSaver saver(dbg);
478 if (!o.d) {
479 dbg << "QJsonDocument()";
480 return dbg;
481 }
482 QByteArray json =
483 QJsonPrivate::Value::fromTrustedCbor(o.d->value).toJson(QJsonValue::JsonFormat::Compact);
484 dbg.nospace() << "QJsonDocument("
485 << json.constData() // print as utf-8 string without extra quotation marks
486 << ')';
487 return dbg;
488}
489#endif
490
491#ifndef QT_NO_DATASTREAM
492QDataStream &operator<<(QDataStream &stream, const QJsonDocument &doc)
493{
494 stream << doc.toJson(QJsonDocument::Compact);
495 return stream;
496}
497
498QDataStream &operator>>(QDataStream &stream, QJsonDocument &doc)
499{
500 QByteArray buffer;
501 stream >> buffer;
502 QJsonParseError parseError{};
503 doc = QJsonDocument::fromJson(buffer, &parseError);
504 if (parseError.error && !buffer.isEmpty())
505 stream.setStatus(QDataStream::ReadCorruptData);
506 return stream;
507}
508#endif
509
510QT_END_NAMESPACE
QJsonDocumentPrivate()=default
QJsonDocumentPrivate(QCborValue data)
QDataStream & operator>>(QDataStream &s, QKeyCombination &combination)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)