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 : QJsonDocument(QCborMap::fromJsonObject(object))
75{
76}
77
78/*!
79 * \since 6.12
80 * Creates a QJsonDocument from \a object.
81 */
82QJsonDocument::QJsonDocument(QJsonObject &&object)
83 : QJsonDocument(QCborMap::fromJsonObject(std::move(object)))
84{
85
86}
87
88/*!
89 * Constructs a QJsonDocument from \a array.
90 */
91QJsonDocument::QJsonDocument(const QJsonArray &array)
92 : QJsonDocument(QCborArray::fromJsonArray(array))
93{
94}
95
96/*!
97 * \since 6.12
98 * Constructs a QJsonDocument from \a array.
99 */
100QJsonDocument::QJsonDocument(QJsonArray &&array)
101 : QJsonDocument(QCborArray::fromJsonArray(std::move(array)))
102{
103
104}
105
106/*!
107 \internal
108 Only called from this .cpp file.
109 */
110QJsonDocument::QJsonDocument(QCborValue data)
111 : d(new QJsonDocumentPrivate(std::move(data)))
112{
113}
114
115/*!
116 Deletes the document.
117
118 Binary data set with fromRawData is not freed.
119 */
120QJsonDocument::~QJsonDocument()
121{
122 delete d;
123}
124
125/*!
126 * Creates a copy of the \a other document.
127 */
128QJsonDocument::QJsonDocument(const QJsonDocument &other)
129 : d(other.d ? new QJsonDocumentPrivate(other.d->value) : nullptr)
130{
131}
132
133/*!
134 * Assigns the \a other document to this QJsonDocument.
135 * Returns a reference to this object.
136 */
137QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
138{
139 if (d != other.d) {
140 if (other.d) {
141 if (!d)
142 d = new QJsonDocumentPrivate;
143 // this is noexcept:
144 d->value = other.d->value;
145 } else {
146 delete d;
147 d = nullptr;
148 }
149 }
150 return *this;
151}
152
153/*!
154 \fn QJsonDocument::QJsonDocument(QJsonDocument &&other)
155 \since 5.10
156
157 Move-constructs a QJsonDocument from \a other.
158*/
159
160/*!
161 \fn QJsonDocument &QJsonDocument::operator =(QJsonDocument &&other)
162 \since 5.10
163
164 Move-assigns \a other to this document.
165*/
166
167/*!
168 \fn void QJsonDocument::swap(QJsonDocument &other)
169 \since 5.10
170 \memberswap{document}
171*/
172
173#ifndef QT_NO_VARIANT
174/*!
175 Creates a QJsonDocument from the QVariant \a variant.
176
177 If the \a variant contains any other type than a QVariantMap,
178 QVariantHash, QVariantList or QStringList, the returned document is invalid.
179
180 \sa toVariant()
181 */
182QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
183{
184 QJsonDocument doc;
185
186 switch (variant.userType()) {
187 case QMetaType::QVariantMap:
188 doc.setObject(QJsonObject::fromVariantMap(get<QVariantMap>(variant)));
189 break;
190 case QMetaType::QVariantHash:
191 doc.setObject(QJsonObject::fromVariantHash(get<QVariantHash>(variant)));
192 break;
193 case QMetaType::QVariantList:
194 doc.setArray(QJsonArray::fromVariantList(get<QVariantList>(variant)));
195 break;
196 case QMetaType::QStringList:
197 doc = QJsonDocument(QCborArray::fromStringList(get<QStringList>(variant)));
198 break;
199 default:
200 break;
201 }
202 return doc;
203}
204
205/*!
206 Returns a QVariant representing the Json document.
207
208 The returned variant will be a QVariantList if the document is
209 a QJsonArray and a QVariantMap if the document is a QJsonObject.
210
211 \sa fromVariant(), QJsonValue::toVariant()
212 */
213QVariant QJsonDocument::toVariant() const
214{
215 if (!d)
216 return QVariant();
217
218 QCborContainerPrivate *container = QJsonPrivate::Value::container(d->value);
219 if (d->value.isArray())
220 return QJsonArray(container).toVariantList();
221 return QJsonObject(container).toVariantMap();
222}
223#endif // !QT_NO_VARIANT
224
225/*!
226\if !defined(qt7)
227 \enum QJsonDocument::JsonFormat
228 \since 5.1
229
230 This value defines the format of the JSON byte array produced
231 when converting to a QJsonDocument using toJson().
232
233 \value Indented Defines human readable output as follows:
234 \snippet code/src_corelib_serialization_qjsondocument.cpp 0
235
236 \value Compact Defines a compact output as follows:
237 \snippet code/src_corelib_serialization_qjsondocument.cpp 1
238\else
239 \typealias QJsonDocument::JsonFormat
240 \since 5.1
241
242 Same as \l QJsonValue::JsonFormat.
243\endif
244 */
245
246/*!
247 \since 5.1
248 Converts the QJsonDocument to a UTF-8 encoded JSON document in the provided \a format.
249
250 \sa fromJson(), JsonFormat
251 */
252QByteArray QJsonDocument::toJson(JsonFormat format) const
253{
254 QByteArray json;
255 if (!d)
256 return json;
257
258 return QJsonPrivate::Value::fromTrustedCbor(d->value).toJson(
259 format == JsonFormat::Compact ? QJsonValue::JsonFormat::Compact
260 : QJsonValue::JsonFormat::Indented);
261}
262
263/*!
264 Parses \a json as a UTF-8 encoded JSON document, and creates a QJsonDocument
265 from it.
266
267 Returns a valid (non-null) QJsonDocument if the parsing succeeds. If it fails,
268 the returned document will be null, and the optional \a error variable will contain
269 further details about the error.
270
271 \sa toJson(), QJsonParseError, isNull()
272 */
273QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error)
274{
275 QJsonPrivate::Parser parser(json);
276 QJsonDocument result;
277 QCborValue val = parser.parse(error);
278 if (val.isArray() || val.isMap()) {
279 result = QJsonDocument(std::move(val));
280 } else if (!val.isUndefined() && error) {
281 // parsed a valid string/number/bool/null,
282 // but QJsonDocument only stores objects and arrays.
283 error->error = QJsonParseError::IllegalValue;
284 error->offset = 0;
285 }
286 return result;
287}
288
289/*!
290 Returns \c true if the document doesn't contain any data.
291 */
292bool QJsonDocument::isEmpty() const
293{
294 if (!d)
295 return true;
296
297 return false;
298}
299
300/*!
301 Returns \c true if the document contains an array.
302
303 \sa array(), isObject()
304 */
305bool QJsonDocument::isArray() const
306{
307 if (!d)
308 return false;
309
310 return d->value.isArray();
311}
312
313/*!
314 Returns \c true if the document contains an object.
315
316 \sa object(), isArray()
317 */
318bool QJsonDocument::isObject() const
319{
320 if (!d)
321 return false;
322
323 return d->value.isMap();
324}
325
326/*!
327 Returns the QJsonObject contained in the document.
328
329 Returns an empty object if the document contains an
330 array.
331
332 \sa isObject(), array(), setObject()
333 */
334QJsonObject QJsonDocument::object() const
335{
336 if (isObject()) {
337 if (auto container = QJsonPrivate::Value::container(d->value))
338 return QJsonObject(container);
339 }
340 return QJsonObject();
341}
342
343/*!
344 Returns the QJsonArray contained in the document.
345
346 Returns an empty array if the document contains an
347 object.
348
349 \sa isArray(), object(), setArray()
350 */
351QJsonArray QJsonDocument::array() const
352{
353 if (isArray()) {
354 if (auto container = QJsonPrivate::Value::container(d->value))
355 return QJsonArray(container);
356 }
357 return QJsonArray();
358}
359
360/*!
361 Sets \a object as the main object of this document.
362
363 \sa setArray(), object()
364 */
365void QJsonDocument::setObject(const QJsonObject &object)
366{
367 *this = QJsonDocument(QCborValue::fromJsonValue(object));
368}
369
370/*!
371 Sets \a array as the main object of this document.
372
373 \sa setObject(), array()
374 */
375void QJsonDocument::setArray(const QJsonArray &array)
376{
377 *this = QJsonDocument(QCborValue::fromJsonValue(array));
378}
379
380/*!
381 Returns a QJsonValue representing the value for the key \a key.
382
383 Equivalent to calling object().value(key).
384
385 The returned QJsonValue is QJsonValue::Undefined if the key does not exist,
386 or if isObject() is false.
387
388 \since 5.10
389
390 \sa QJsonValue, QJsonValue::isUndefined(), QJsonObject
391 */
392const QJsonValue QJsonDocument::operator[](const QString &key) const
393{
394 return (*this)[QStringView(key)];
395}
396
397/*!
398 \overload
399 \since 5.14
400*/
401const QJsonValue QJsonDocument::operator[](QStringView key) const
402{
403 if (!isObject())
404 return QJsonValue(QJsonValue::Undefined);
405
406 return QJsonPrivate::Value::fromTrustedCbor(d->value.toMap().value(key));
407}
408
409/*!
410 \overload
411 \since 5.10
412*/
413const QJsonValue QJsonDocument::operator[](QLatin1StringView key) const
414{
415 if (!isObject())
416 return QJsonValue(QJsonValue::Undefined);
417
418 return QJsonPrivate::Value::fromTrustedCbor(d->value.toMap().value(key));
419}
420
421/*!
422 Returns a QJsonValue representing the value for index \a i.
423
424 Equivalent to calling array().at(i).
425
426 The returned QJsonValue is QJsonValue::Undefined, if \a i is out of bounds,
427 or if isArray() is false.
428
429 \since 5.10
430
431 \sa QJsonValue, QJsonValue::isUndefined(), QJsonArray
432 */
433const QJsonValue QJsonDocument::operator[](qsizetype i) const
434{
435 if (!isArray())
436 return QJsonValue(QJsonValue::Undefined);
437
438 return QJsonPrivate::Value::fromTrustedCbor(d->value.toArray().at(i));
439}
440
441/*!
442 \fn bool QJsonDocument::operator==(const QJsonDocument &lhs, const QJsonDocument &rhs)
443
444 Returns \c true if the \a lhs document is equal to \a rhs document, \c false otherwise.
445*/
446bool comparesEqual(const QJsonDocument &lhs, const QJsonDocument &rhs) noexcept
447{
448 if (lhs.d && rhs.d)
449 return lhs.d->value == rhs.d->value;
450 return !lhs.d == !rhs.d;
451}
452
453/*!
454 \fn bool QJsonDocument::operator!=(const QJsonDocument &lhs, const QJsonDocument &rhs)
455
456 Returns \c true if the \a lhs document is not equal to \a rhs document, \c false otherwise.
457*/
458
459/*!
460 returns \c true if this document is null.
461
462 Null documents are documents created through the default constructor.
463
464 Documents created from UTF-8 encoded text or the binary format are
465 validated during parsing. If validation fails, the returned document
466 will also be null.
467 */
468bool QJsonDocument::isNull() const
469{
470 return (d == nullptr);
471}
472
473#if !defined(QT_NO_DEBUG_STREAM)
474QDebug operator<<(QDebug dbg, const QJsonDocument &o)
475{
476 QDebugStateSaver saver(dbg);
477 if (!o.d) {
478 dbg << "QJsonDocument()";
479 return dbg;
480 }
481 QByteArray json =
482 QJsonPrivate::Value::fromTrustedCbor(o.d->value).toJson(QJsonValue::JsonFormat::Compact);
483 dbg.nospace() << "QJsonDocument("
484 << json.constData() // print as utf-8 string without extra quotation marks
485 << ')';
486 return dbg;
487}
488#endif
489
490#ifndef QT_NO_DATASTREAM
491QDataStream &operator<<(QDataStream &stream, const QJsonDocument &doc)
492{
493 stream << doc.toJson(QJsonDocument::Compact);
494 return stream;
495}
496
497QDataStream &operator>>(QDataStream &stream, QJsonDocument &doc)
498{
499 QByteArray buffer;
500 stream >> buffer;
501 QJsonParseError parseError{};
502 doc = QJsonDocument::fromJson(buffer, &parseError);
503 if (parseError.error && !buffer.isEmpty())
504 stream.setStatus(QDataStream::ReadCorruptData);
505 return stream;
506}
507#endif
508
509QT_END_NAMESPACE
QJsonDocumentPrivate()=default
QJsonDocumentPrivate(QCborValue data)
Combined button and popup list for selecting options.
QDataStream & operator>>(QDataStream &s, QKeyCombination &combination)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)