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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtbase/src/corelib/serialization/qjsondocument.cpp