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 \memberswap{document}
183*/
184
185#ifndef QT_NO_VARIANT
186/*!
187 Creates a QJsonDocument from the QVariant \a variant.
188
189 If the \a variant contains any other type than a QVariantMap,
190 QVariantHash, QVariantList or QStringList, the returned document is invalid.
191
192 \sa toVariant()
193 */
194QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
195{
196 QJsonDocument doc;
197
198 switch (variant.metaType().id()) {
199 case QMetaType::QVariantMap:
200 doc.setObject(QJsonObject::fromVariantMap(map: variant.toMap()));
201 break;
202 case QMetaType::QVariantHash:
203 doc.setObject(QJsonObject::fromVariantHash(map: variant.toHash()));
204 break;
205 case QMetaType::QVariantList:
206 doc.setArray(QJsonArray::fromVariantList(list: variant.toList()));
207 break;
208 case QMetaType::QStringList:
209 doc.d = std::make_unique<QJsonDocumentPrivate>();
210 doc.d->value = QCborArray::fromStringList(list: variant.toStringList());
211 break;
212 default:
213 break;
214 }
215 return doc;
216}
217
218/*!
219 Returns a QVariant representing the Json document.
220
221 The returned variant will be a QVariantList if the document is
222 a QJsonArray and a QVariantMap if the document is a QJsonObject.
223
224 \sa fromVariant(), QJsonValue::toVariant()
225 */
226QVariant QJsonDocument::toVariant() const
227{
228 if (!d)
229 return QVariant();
230
231 QCborContainerPrivate *container = QJsonPrivate::Value::container(v: d->value);
232 if (d->value.isArray())
233 return QJsonArray(container).toVariantList();
234 return QJsonObject(container).toVariantMap();
235}
236#endif // !QT_NO_VARIANT
237
238/*!
239 \enum QJsonDocument::JsonFormat
240 \since 5.1
241
242 This value defines the format of the JSON byte array produced
243 when converting to a QJsonDocument using toJson().
244
245 \value Indented Defines human readable output as follows:
246 \snippet code/src_corelib_serialization_qjsondocument.cpp 0
247
248 \value Compact Defines a compact output as follows:
249 \snippet code/src_corelib_serialization_qjsondocument.cpp 1
250 */
251
252/*!
253 \since 5.1
254 Converts the QJsonDocument to a UTF-8 encoded JSON document in the provided \a format.
255
256 \sa fromJson(), JsonFormat
257 */
258#if !defined(QT_JSON_READONLY) || defined(Q_QDOC)
259QByteArray QJsonDocument::toJson(JsonFormat format) const
260{
261 QByteArray json;
262 if (!d)
263 return json;
264
265 const QCborContainerPrivate *container = QJsonPrivate::Value::container(v: d->value);
266 if (d->value.isArray())
267 QJsonPrivate::Writer::arrayToJson(a: container, json, indent: 0, compact: (format == Compact));
268 else
269 QJsonPrivate::Writer::objectToJson(o: container, json, indent: 0, compact: (format == Compact));
270
271 return json;
272}
273#endif
274
275/*!
276 Parses \a json as a UTF-8 encoded JSON document, and creates a QJsonDocument
277 from it.
278
279 Returns a valid (non-null) QJsonDocument if the parsing succeeds. If it fails,
280 the returned document will be null, and the optional \a error variable will contain
281 further details about the error.
282
283 \sa toJson(), QJsonParseError, isNull()
284 */
285QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error)
286{
287 QJsonPrivate::Parser parser(json.constData(), json.size());
288 QJsonDocument result;
289 const QCborValue val = parser.parse(error);
290 if (val.isArray() || val.isMap()) {
291 result.d = std::make_unique<QJsonDocumentPrivate>();
292 result.d->value = val;
293 }
294 return result;
295}
296
297/*!
298 Returns \c true if the document doesn't contain any data.
299 */
300bool QJsonDocument::isEmpty() const
301{
302 if (!d)
303 return true;
304
305 return false;
306}
307
308/*!
309 Returns \c true if the document contains an array.
310
311 \sa array(), isObject()
312 */
313bool QJsonDocument::isArray() const
314{
315 if (!d)
316 return false;
317
318 return d->value.isArray();
319}
320
321/*!
322 Returns \c true if the document contains an object.
323
324 \sa object(), isArray()
325 */
326bool QJsonDocument::isObject() const
327{
328 if (!d)
329 return false;
330
331 return d->value.isMap();
332}
333
334/*!
335 Returns the QJsonObject contained in the document.
336
337 Returns an empty object if the document contains an
338 array.
339
340 \sa isObject(), array(), setObject()
341 */
342QJsonObject QJsonDocument::object() const
343{
344 if (isObject()) {
345 if (auto container = QJsonPrivate::Value::container(v: d->value))
346 return QJsonObject(container);
347 }
348 return QJsonObject();
349}
350
351/*!
352 Returns the QJsonArray contained in the document.
353
354 Returns an empty array if the document contains an
355 object.
356
357 \sa isArray(), object(), setArray()
358 */
359QJsonArray QJsonDocument::array() const
360{
361 if (isArray()) {
362 if (auto container = QJsonPrivate::Value::container(v: d->value))
363 return QJsonArray(container);
364 }
365 return QJsonArray();
366}
367
368/*!
369 Sets \a object as the main object of this document.
370
371 \sa setArray(), object()
372 */
373void QJsonDocument::setObject(const QJsonObject &object)
374{
375 if (!d)
376 d = std::make_unique<QJsonDocumentPrivate>();
377 else
378 d->clearRawData();
379
380 d->value = QCborValue::fromJsonValue(v: object);
381}
382
383/*!
384 Sets \a array as the main object of this document.
385
386 \sa setObject(), array()
387 */
388void QJsonDocument::setArray(const QJsonArray &array)
389{
390 if (!d)
391 d = std::make_unique<QJsonDocumentPrivate>();
392 else
393 d->clearRawData();
394
395 d->value = QCborValue::fromJsonValue(v: array);
396}
397
398/*!
399 Returns a QJsonValue representing the value for the key \a key.
400
401 Equivalent to calling object().value(key).
402
403 The returned QJsonValue is QJsonValue::Undefined if the key does not exist,
404 or if isObject() is false.
405
406 \since 5.10
407
408 \sa QJsonValue, QJsonValue::isUndefined(), QJsonObject
409 */
410const QJsonValue QJsonDocument::operator[](const QString &key) const
411{
412 return (*this)[QStringView(key)];
413}
414
415/*!
416 \overload
417 \since 5.14
418*/
419const QJsonValue QJsonDocument::operator[](QStringView key) const
420{
421 if (!isObject())
422 return QJsonValue(QJsonValue::Undefined);
423
424 return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toMap().value(key));
425}
426
427/*!
428 \overload
429 \since 5.10
430*/
431const QJsonValue QJsonDocument::operator[](QLatin1StringView key) const
432{
433 if (!isObject())
434 return QJsonValue(QJsonValue::Undefined);
435
436 return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toMap().value(key));
437}
438
439/*!
440 Returns a QJsonValue representing the value for index \a i.
441
442 Equivalent to calling array().at(i).
443
444 The returned QJsonValue is QJsonValue::Undefined, if \a i is out of bounds,
445 or if isArray() is false.
446
447 \since 5.10
448
449 \sa QJsonValue, QJsonValue::isUndefined(), QJsonArray
450 */
451const QJsonValue QJsonDocument::operator[](qsizetype i) const
452{
453 if (!isArray())
454 return QJsonValue(QJsonValue::Undefined);
455
456 return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toArray().at(i));
457}
458
459/*!
460 \fn bool QJsonDocument::operator==(const QJsonDocument &lhs, const QJsonDocument &rhs)
461
462 Returns \c true if the \a lhs document is equal to \a rhs document, \c false otherwise.
463*/
464bool comparesEqual(const QJsonDocument &lhs, const QJsonDocument &rhs) noexcept
465{
466 if (lhs.d && rhs.d)
467 return lhs.d->value == rhs.d->value;
468 return !lhs.d == !rhs.d;
469}
470
471/*!
472 \fn bool QJsonDocument::operator!=(const QJsonDocument &lhs, const QJsonDocument &rhs)
473
474 Returns \c true if the \a lhs document is not equal to \a rhs document, \c false otherwise.
475*/
476
477/*!
478 returns \c true if this document is null.
479
480 Null documents are documents created through the default constructor.
481
482 Documents created from UTF-8 encoded text or the binary format are
483 validated during parsing. If validation fails, the returned document
484 will also be null.
485 */
486bool QJsonDocument::isNull() const
487{
488 return (d == nullptr);
489}
490
491#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
492QDebug operator<<(QDebug dbg, const QJsonDocument &o)
493{
494 QDebugStateSaver saver(dbg);
495 if (!o.d) {
496 dbg << "QJsonDocument()";
497 return dbg;
498 }
499 QByteArray json;
500 const QCborContainerPrivate *container = QJsonPrivate::Value::container(v: o.d->value);
501 if (o.d->value.isArray())
502 QJsonPrivate::Writer::arrayToJson(a: container, json, indent: 0, compact: true);
503 else
504 QJsonPrivate::Writer::objectToJson(o: container, json, indent: 0, compact: true);
505 dbg.nospace() << "QJsonDocument("
506 << json.constData() // print as utf-8 string without extra quotation marks
507 << ')';
508 return dbg;
509}
510#endif
511
512#ifndef QT_NO_DATASTREAM
513QDataStream &operator<<(QDataStream &stream, const QJsonDocument &doc)
514{
515 stream << doc.toJson(format: QJsonDocument::Compact);
516 return stream;
517}
518
519QDataStream &operator>>(QDataStream &stream, QJsonDocument &doc)
520{
521 QByteArray buffer;
522 stream >> buffer;
523 QJsonParseError parseError{};
524 doc = QJsonDocument::fromJson(json: buffer, error: &parseError);
525 if (parseError.error && !buffer.isEmpty())
526 stream.setStatus(QDataStream::ReadCorruptData);
527 return stream;
528}
529#endif
530
531QT_END_NAMESPACE
532

Provided by KDAB

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

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