Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qjsonparser.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2021 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QT_BOOTSTRAPPED
6#include <qcoreapplication.h>
7#endif
8#include <qdebug.h>
9#include "qjsonparser_p.h"
10#include "qjson_p.h"
11#include "private/qstringconverter_p.h"
12#include "private/qcborvalue_p.h"
13#include "private/qnumeric_p.h"
14#include <private/qtools_p.h>
15
16//#define PARSER_DEBUG
17#ifdef PARSER_DEBUG
18Q_CONSTINIT static int indent = 0;
19#define BEGIN qDebug() << QByteArray(4*indent++, ' ').constData() << "pos=" << current
20#define END --indent
21#define DEBUG qDebug() << QByteArray(4*indent, ' ').constData()
22#else
23#define BEGIN if (1) ; else qDebug()
24#define END do {} while (0)
25#define DEBUG if (1) ; else qDebug()
26#endif
27
28static const int nestingLimit = 1024;
29
31
32using namespace QtMiscUtils;
33
34// error strings for the JSON parser
35#define JSONERR_OK QT_TRANSLATE_NOOP("QJsonParseError", "no error occurred")
36#define JSONERR_UNTERM_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "unterminated object")
37#define JSONERR_MISS_NSEP QT_TRANSLATE_NOOP("QJsonParseError", "missing name separator")
38#define JSONERR_UNTERM_AR QT_TRANSLATE_NOOP("QJsonParseError", "unterminated array")
39#define JSONERR_MISS_VSEP QT_TRANSLATE_NOOP("QJsonParseError", "missing value separator")
40#define JSONERR_ILLEGAL_VAL QT_TRANSLATE_NOOP("QJsonParseError", "illegal value")
41#define JSONERR_END_OF_NUM QT_TRANSLATE_NOOP("QJsonParseError", "invalid termination by number")
42#define JSONERR_ILLEGAL_NUM QT_TRANSLATE_NOOP("QJsonParseError", "illegal number")
43#define JSONERR_STR_ESC_SEQ QT_TRANSLATE_NOOP("QJsonParseError", "invalid escape sequence")
44#define JSONERR_STR_UTF8 QT_TRANSLATE_NOOP("QJsonParseError", "invalid UTF8 string")
45#define JSONERR_UTERM_STR QT_TRANSLATE_NOOP("QJsonParseError", "unterminated string")
46#define JSONERR_MISS_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "object is missing after a comma")
47#define JSONERR_DEEP_NEST QT_TRANSLATE_NOOP("QJsonParseError", "too deeply nested document")
48#define JSONERR_DOC_LARGE QT_TRANSLATE_NOOP("QJsonParseError", "too large document")
49#define JSONERR_GARBAGEEND QT_TRANSLATE_NOOP("QJsonParseError", "garbage at the end of the document")
50
112{
113 const char *sz = "";
114 switch (error) {
115 case NoError:
116 sz = JSONERR_OK;
117 break;
120 break;
123 break;
126 break;
129 break;
130 case IllegalValue:
132 break;
135 break;
136 case IllegalNumber:
138 break;
141 break;
143 sz = JSONERR_STR_UTF8;
144 break;
147 break;
148 case MissingObject:
149 sz = JSONERR_MISS_OBJ;
150 break;
151 case DeepNesting:
153 break;
154 case DocumentTooLarge:
156 break;
157 case GarbageAtEnd:
159 break;
160 }
161#ifndef QT_BOOTSTRAPPED
162 return QCoreApplication::translate("QJsonParseError", sz);
163#else
164 return QLatin1StringView(sz);
165#endif
166}
167
168using namespace QJsonPrivate;
169
171{
172 Q_DISABLE_COPY_MOVE(StashedContainer)
173public:
176 : type(type), stashed(std::move(*container)), current(container)
177 {
178 }
179
181 {
182 stashed->append(QCborContainerPrivate::makeValue(type, -1, current->take(),
184 *current = std::move(stashed);
185 }
186
187private:
191};
192
193Parser::Parser(const char *json, int length)
194 : head(json), json(json)
195 , nestingLevel(0)
196 , lastError(QJsonParseError::NoError)
197{
198 end = json + length;
199}
200
201
202
203/*
204
205begin-array = ws %x5B ws ; [ left square bracket
206
207begin-object = ws %x7B ws ; { left curly bracket
208
209end-array = ws %x5D ws ; ] right square bracket
210
211end-object = ws %x7D ws ; } right curly bracket
212
213name-separator = ws %x3A ws ; : colon
214
215value-separator = ws %x2C ws ; , comma
216
217Insignificant whitespace is allowed before or after any of the six
218structural characters.
219
220ws = *(
221 %x20 / ; Space
222 %x09 / ; Horizontal tab
223 %x0A / ; Line feed or New line
224 %x0D ; Carriage return
225 )
226
227*/
228
229enum {
230 Space = 0x20,
231 Tab = 0x09,
232 LineFeed = 0x0a,
233 Return = 0x0d,
236 EndArray = 0x5d,
237 EndObject = 0x7d,
240 Quote = 0x22
242
243void Parser::eatBOM()
244{
245 // eat UTF-8 byte order mark
246 uchar utf8bom[3] = { 0xef, 0xbb, 0xbf };
247 if (end - json > 3 &&
248 (uchar)json[0] == utf8bom[0] &&
249 (uchar)json[1] == utf8bom[1] &&
250 (uchar)json[2] == utf8bom[2])
251 json += 3;
252}
253
254bool Parser::eatSpace()
255{
256 while (json < end) {
257 if (*json > Space)
258 break;
259 if (*json != Space &&
260 *json != Tab &&
261 *json != LineFeed &&
262 *json != Return)
263 break;
264 ++json;
265 }
266 return (json < end);
267}
268
269char Parser::nextToken()
270{
271 if (!eatSpace())
272 return 0;
273 char token = *json++;
274 switch (token) {
275 case BeginArray:
276 case BeginObject:
277 case NameSeparator:
278 case ValueSeparator:
279 case EndArray:
280 case EndObject:
281 case Quote:
282 break;
283 default:
284 token = 0;
285 break;
286 }
287 return token;
288}
289
290/*
291 JSON-text = object / array
292*/
294{
295#ifdef PARSER_DEBUG
296 indent = 0;
297 qDebug(">>>>> parser begin");
298#endif
299 eatBOM();
300 char token = nextToken();
301
303
304 DEBUG << Qt::hex << (uint)token;
305 if (token == BeginArray) {
306 container = new QCborContainerPrivate;
307 if (!parseArray())
308 goto error;
311 } else if (token == BeginObject) {
312 container = new QCborContainerPrivate;
313 if (!parseObject())
314 goto error;
317 } else {
319 goto error;
320 }
321
322 eatSpace();
323 if (json < end) {
325 goto error;
326 }
327
328 END;
329 {
330 if (error) {
331 error->offset = 0;
333 }
334
335 return data;
336 }
337
338error:
339#ifdef PARSER_DEBUG
340 qDebug(">>>>> parser error");
341#endif
342 container.reset();
343 if (error) {
344 error->offset = json - head;
345 error->error = lastError;
346 }
347 return QCborValue();
348}
349
350// We need to retain the _last_ value for any duplicate keys and we need to deref containers.
351// Therefore the manual implementation of std::unique().
352template<typename Iterator, typename Compare, typename Assign>
353static Iterator customAssigningUniqueLast(Iterator first, Iterator last,
354 Compare compare, Assign assign)
355{
356 first = std::adjacent_find(first, last, compare);
357 if (first == last)
358 return last;
359
360 // After adjacent_find, we know that *first and *(first+1) compare equal,
361 // and that first+1 != last.
362 Iterator result = first++;
364 assign(*result, *first);
365 Q_ASSERT(first != last);
366
367 while (++first != last) {
368 if (!compare(*result, *first))
369 ++result;
370
371 // Due to adjacent_find above, we know that we've at least eliminated one element.
372 // Therefore we have to move each further element across the gap.
374
375 // We have to overwrite each element we want to eliminate, to deref() the container.
376 // Therefore we don't try to optimize the number of assignments here.
377 assign(*result, *first);
378 }
379
380 return ++result;
381}
382
384{
385 using Forward = QJsonPrivate::KeyIterator;
386 using Value = Forward::value_type;
387
388 auto compare = [container](const Value &a, const Value &b)
389 {
390 const auto &aKey = a.key();
391 const auto &bKey = b.key();
392
395
396 const QtCbor::ByteData *aData = container->byteData(aKey);
397 const QtCbor::ByteData *bData = container->byteData(bKey);
398
399 if (!aData)
400 return bData ? -1 : 0;
401 if (!bData)
402 return 1;
403
404 // US-ASCII (StringIsAscii flag) is just a special case of UTF-8
405 // string, so we can safely ignore the flag.
406
407 if (aKey.flags & QtCbor::Element::StringIsUtf16) {
408 if (bKey.flags & QtCbor::Element::StringIsUtf16)
409 return QtPrivate::compareStrings(aData->asStringView(), bData->asStringView());
410
411 return -QCborContainerPrivate::compareUtf8(bData, aData->asStringView());
412 } else {
413 if (bKey.flags & QtCbor::Element::StringIsUtf16)
414 return QCborContainerPrivate::compareUtf8(aData, bData->asStringView());
415
417 }
418 };
419
420 // The elements' containers are owned by the outer container, not by the elements themselves.
421 auto move = [](Forward::reference target, Forward::reference source)
422 {
423 QtCbor::Element &targetValue = target.value();
424
425 // If the target has a container, deref it before overwriting, so that we don't leak.
426 if (targetValue.flags & QtCbor::Element::IsContainer)
427 targetValue.container->deref();
428
429 // Do not move, so that we can clear the value afterwards.
430 target = source;
431
432 // Clear the source value, so that we don't store the same container twice.
433 source.value() = QtCbor::Element();
434 };
435
436 std::stable_sort(
437 Forward(container->elements.begin()), Forward(container->elements.end()),
438 [&compare](const Value &a, const Value &b) { return compare(a, b) < 0; });
439
441 Forward(container->elements.begin()), Forward(container->elements.end()),
442 [&compare](const Value &a, const Value &b) { return compare(a, b) == 0; }, move);
443
444 container->elements.erase(result.elementsIterator(), container->elements.end());
445}
446
447
448/*
449 object = begin-object [ member *( value-separator member ) ]
450 end-object
451*/
452
453bool Parser::parseObject()
454{
455 if (++nestingLevel > nestingLimit) {
457 return false;
458 }
459
460 BEGIN << "parseObject" << json;
461
462 char token = nextToken();
463 while (token == Quote) {
464 if (!container)
465 container = new QCborContainerPrivate;
466 if (!parseMember())
467 return false;
468 token = nextToken();
469 if (token != ValueSeparator)
470 break;
471 token = nextToken();
472 if (token == EndObject) {
474 return false;
475 }
476 }
477
478 DEBUG << "end token=" << token;
479 if (token != EndObject) {
481 return false;
482 }
483
484 END;
485
486 --nestingLevel;
487
488 if (container)
489 sortContainer(container.data());
490 return true;
491}
492
493/*
494 member = string name-separator value
495*/
496bool Parser::parseMember()
497{
498 BEGIN << "parseMember";
499
500 if (!parseString())
501 return false;
502 char token = nextToken();
503 if (token != NameSeparator) {
505 return false;
506 }
507 if (!eatSpace()) {
509 return false;
510 }
511 if (!parseValue())
512 return false;
513
514 END;
515 return true;
516}
517
518/*
519 array = begin-array [ value *( value-separator value ) ] end-array
520*/
521bool Parser::parseArray()
522{
523 BEGIN << "parseArray";
524
525 if (++nestingLevel > nestingLimit) {
527 return false;
528 }
529
530 if (!eatSpace()) {
532 return false;
533 }
534 if (*json == EndArray) {
535 nextToken();
536 } else {
537 while (1) {
538 if (!eatSpace()) {
540 return false;
541 }
542 if (!container)
543 container = new QCborContainerPrivate;
544 if (!parseValue())
545 return false;
546 char token = nextToken();
547 if (token == EndArray)
548 break;
549 else if (token != ValueSeparator) {
550 if (!eatSpace())
552 else
554 return false;
555 }
556 }
557 }
558
559 DEBUG << "size =" << (container ? container->elements.size() : 0);
560 END;
561
562 --nestingLevel;
563
564 return true;
565}
566
567/*
568value = false / null / true / object / array / number / string
569
570*/
571
572bool Parser::parseValue()
573{
574 BEGIN << "parse Value" << json;
575
576 switch (*json++) {
577 case 'n':
578 if (end - json < 4) {
580 return false;
581 }
582 if (*json++ == 'u' &&
583 *json++ == 'l' &&
584 *json++ == 'l') {
586 DEBUG << "value: null";
587 END;
588 return true;
589 }
591 return false;
592 case 't':
593 if (end - json < 4) {
595 return false;
596 }
597 if (*json++ == 'r' &&
598 *json++ == 'u' &&
599 *json++ == 'e') {
600 container->append(QCborValue(true));
601 DEBUG << "value: true";
602 END;
603 return true;
604 }
606 return false;
607 case 'f':
608 if (end - json < 5) {
610 return false;
611 }
612 if (*json++ == 'a' &&
613 *json++ == 'l' &&
614 *json++ == 's' &&
615 *json++ == 'e') {
616 container->append(QCborValue(false));
617 DEBUG << "value: false";
618 END;
619 return true;
620 }
622 return false;
623 case Quote: {
624 if (!parseString())
625 return false;
626 DEBUG << "value: string";
627 END;
628 return true;
629 }
630 case BeginArray: {
631 StashedContainer stashedContainer(&container, QCborValue::Array);
632 if (!parseArray())
633 return false;
634 DEBUG << "value: array";
635 END;
636 return true;
637 }
638 case BeginObject: {
639 StashedContainer stashedContainer(&container, QCborValue::Map);
640 if (!parseObject())
641 return false;
642 DEBUG << "value: object";
643 END;
644 return true;
645 }
646 case ValueSeparator:
647 // Essentially missing value, but after a colon, not after a comma
648 // like the other MissingObject errors.
650 return false;
651 case EndObject:
652 case EndArray:
654 return false;
655 default:
656 --json;
657 if (!parseNumber())
658 return false;
659 DEBUG << "value: number";
660 END;
661 }
662
663 return true;
664}
665
666
667
668
669
670/*
671 number = [ minus ] int [ frac ] [ exp ]
672 decimal-point = %x2E ; .
673 digit1-9 = %x31-39 ; 1-9
674 e = %x65 / %x45 ; e E
675 exp = e [ minus / plus ] 1*DIGIT
676 frac = decimal-point 1*DIGIT
677 int = zero / ( digit1-9 *DIGIT )
678 minus = %x2D ; -
679 plus = %x2B ; +
680 zero = %x30 ; 0
681
682*/
683
684bool Parser::parseNumber()
685{
686 BEGIN << "parseNumber" << json;
687
688 const char *start = json;
689 bool isInt = true;
690
691 // minus
692 if (json < end && *json == '-')
693 ++json;
694
695 // int = zero / ( digit1-9 *DIGIT )
696 if (json < end && *json == '0') {
697 ++json;
698 } else {
699 while (json < end && isAsciiDigit(*json))
700 ++json;
701 }
702
703 // frac = decimal-point 1*DIGIT
704 if (json < end && *json == '.') {
705 ++json;
706 while (json < end && isAsciiDigit(*json)) {
707 isInt = isInt && *json == '0';
708 ++json;
709 }
710 }
711
712 // exp = e [ minus / plus ] 1*DIGIT
713 if (json < end && (*json == 'e' || *json == 'E')) {
714 isInt = false;
715 ++json;
716 if (json < end && (*json == '-' || *json == '+'))
717 ++json;
718 while (json < end && isAsciiDigit(*json))
719 ++json;
720 }
721
722 if (json >= end) {
724 return false;
725 }
726
728 DEBUG << "numberstring" << number;
729
730 if (isInt) {
731 bool ok;
732 qlonglong n = number.toLongLong(&ok);
733 if (ok) {
734 container->append(QCborValue(n));
735 END;
736 return true;
737 }
738 }
739
740 bool ok;
741 double d = number.toDouble(&ok);
742
743 if (!ok) {
745 return false;
746 }
747
748 qint64 n;
749 if (convertDoubleTo(d, &n))
750 container->append(QCborValue(n));
751 else
752 container->append(QCborValue(d));
753
754 END;
755 return true;
756}
757
758/*
759
760 string = quotation-mark *char quotation-mark
761
762 char = unescaped /
763 escape (
764 %x22 / ; " quotation mark U+0022
765 %x5C / ; \ reverse solidus U+005C
766 %x2F / ; / solidus U+002F
767 %x62 / ; b backspace U+0008
768 %x66 / ; f form feed U+000C
769 %x6E / ; n line feed U+000A
770 %x72 / ; r carriage return U+000D
771 %x74 / ; t tab U+0009
772 %x75 4HEXDIG ) ; uXXXX U+XXXX
773
774 escape = %x5C ; \
775
776 quotation-mark = %x22 ; "
777
778 unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
779 */
780static inline bool addHexDigit(char digit, char32_t *result)
781{
782 *result <<= 4;
783 const int h = fromHex(digit);
784 if (h != -1) {
785 *result |= h;
786 return true;
787 }
788
789 return false;
790}
791
792static inline bool scanEscapeSequence(const char *&json, const char *end, char32_t *ch)
793{
794 ++json;
795 if (json >= end)
796 return false;
797
798 DEBUG << "scan escape" << (char)*json;
799 uchar escaped = *json++;
800 switch (escaped) {
801 case '"':
802 *ch = '"'; break;
803 case '\\':
804 *ch = '\\'; break;
805 case '/':
806 *ch = '/'; break;
807 case 'b':
808 *ch = 0x8; break;
809 case 'f':
810 *ch = 0xc; break;
811 case 'n':
812 *ch = 0xa; break;
813 case 'r':
814 *ch = 0xd; break;
815 case 't':
816 *ch = 0x9; break;
817 case 'u': {
818 *ch = 0;
819 if (json > end - 4)
820 return false;
821 for (int i = 0; i < 4; ++i) {
822 if (!addHexDigit(*json, ch))
823 return false;
824 ++json;
825 }
826 return true;
827 }
828 default:
829 // this is not as strict as one could be, but allows for more Json files
830 // to be parsed correctly.
831 *ch = escaped;
832 return true;
833 }
834 return true;
835}
836
837static inline bool scanUtf8Char(const char *&json, const char *end, char32_t *result)
838{
839 const auto *usrc = reinterpret_cast<const uchar *>(json);
840 const auto *uend = reinterpret_cast<const uchar *>(end);
841 const uchar b = *usrc++;
842 qsizetype res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, result, usrc, uend);
843 if (res < 0)
844 return false;
845
846 json = reinterpret_cast<const char *>(usrc);
847 return true;
848}
849
850bool Parser::parseString()
851{
852 const char *start = json;
853
854 // try to parse a utf-8 string without escape sequences, and note whether it's 7bit ASCII.
855
856 BEGIN << "parse string" << json;
857 bool isUtf8 = true;
858 bool isAscii = true;
859 while (json < end) {
860 char32_t ch = 0;
861 if (*json == '"')
862 break;
863 if (*json == '\\') {
864 isAscii = false;
865 // If we find escape sequences, we store UTF-16 as there are some
866 // escape sequences which are hard to represent in UTF-8.
867 // (plain "\\ud800" for example)
868 isUtf8 = false;
869 break;
870 }
871 if (!scanUtf8Char(json, end, &ch)) {
873 return false;
874 }
875 if (ch > 0x7f)
876 isAscii = false;
877 DEBUG << " " << ch << char(ch);
878 }
879 ++json;
880 DEBUG << "end of string";
881 if (json >= end) {
883 return false;
884 }
885
886 // no escape sequences, we are done
887 if (isUtf8) {
888 if (isAscii)
889 container->appendAsciiString(start, json - start - 1);
890 else
891 container->appendUtf8String(start, json - start - 1);
892 END;
893 return true;
894 }
895
896 DEBUG << "has escape sequences";
897
898 json = start;
899
900 QString ucs4;
901 while (json < end) {
902 char32_t ch = 0;
903 if (*json == '"')
904 break;
905 else if (*json == '\\') {
906 if (!scanEscapeSequence(json, end, &ch)) {
908 return false;
909 }
910 } else {
911 if (!scanUtf8Char(json, end, &ch)) {
913 return false;
914 }
915 }
917 }
918 ++json;
919
920 if (json >= end) {
922 return false;
923 }
924
925 container->appendByteData(reinterpret_cast<const char *>(ucs4.constData()), ucs4.size() * 2,
927 END;
928 return true;
929}
930
Parser()
Definition parser.h:17
\inmodule QtCore
Definition qbytearray.h:57
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:394
const QtCbor::ByteData * byteData(QtCbor::Element e) const
void appendUtf8String(const char *str, qsizetype len)
void appendByteData(const char *data, qsizetype len, QCborValue::Type type, QtCbor::Element::ValueFlags extraFlags={})
static int compareUtf8(const QtCbor::ByteData *b, QLatin1StringView s)
QList< QtCbor::Element > elements
void append(QtCbor::Undefined)
static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d=nullptr, ContainerDisposition disp=CopyContainer)
void appendAsciiString(const QString &s)
\inmodule QtCore\reentrant
Definition qcborvalue.h:50
Type
This enum represents the QCborValue type.
Definition qcborvalue.h:73
static constexpr auto fromUcs4(char32_t c) noexcept
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
void reset(T *ptr=nullptr) noexcept
T * data() const noexcept
Returns a pointer to the shared data object.
QCborValue parse(QJsonParseError *error)
qsizetype size() const noexcept
Definition qlist.h:386
iterator erase(const_iterator begin, const_iterator end)
Definition qlist.h:882
iterator end()
Definition qlist.h:609
iterator begin()
Definition qlist.h:608
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1101
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString & append(QChar c)
Definition qstring.cpp:3227
StashedContainer(QExplicitlySharedDataPointer< QCborContainerPrivate > *container, QCborValue::Type type)
Token token
Definition keywords.cpp:444
ObjectIterator< QtCbor::Element, QList< QtCbor::Element >::iterator > KeyIterator
Definition qjson_p.h:153
Combined button and popup list for selecting options.
constexpr bool isAsciiDigit(char32_t c) noexcept
Definition qtools_p.h:67
constexpr int fromHex(char32_t c) noexcept
Definition qtools_p.h:44
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isAscii(QLatin1StringView s) noexcept
Definition qstring.cpp:860
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
DBusConnection const char DBusError * error
#define JSONERR_UNTERM_AR
#define JSONERR_MISS_VSEP
@ Tab
@ EndArray
@ BeginArray
@ LineFeed
@ EndObject
@ BeginObject
@ Return
@ Quote
@ NameSeparator
@ ValueSeparator
#define JSONERR_UNTERM_OBJ
static bool scanEscapeSequence(const char *&json, const char *end, char32_t *ch)
#define END
#define JSONERR_ILLEGAL_NUM
#define JSONERR_DOC_LARGE
#define JSONERR_DEEP_NEST
#define JSONERR_UTERM_STR
#define JSONERR_END_OF_NUM
static bool scanUtf8Char(const char *&json, const char *end, char32_t *result)
#define JSONERR_STR_UTF8
#define JSONERR_STR_ESC_SEQ
#define JSONERR_OK
static const int nestingLimit
#define BEGIN
#define JSONERR_ILLEGAL_VAL
static bool addHexDigit(char digit, char32_t *result)
static void sortContainer(QCborContainerPrivate *container)
#define JSONERR_MISS_NSEP
#define JSONERR_GARBAGEEND
static Iterator customAssigningUniqueLast(Iterator first, Iterator last, Compare compare, Assign assign)
#define JSONERR_MISS_OBJ
#define qDebug
[1]
Definition qlogging.h:160
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum type
GLenum target
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLint first
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLuint res
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
@ Space
static const uchar utf8bom[]
@ NoError
Definition main.cpp:34
static int compare(quint64 a, quint64 b)
unsigned char uchar
Definition qtypes.h:27
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
qint64 qlonglong
Definition qtypes.h:58
\inmodule QtCore\reentrant
ParseError error
QString errorString() const
\variable QJsonParseError::error
QStringView asStringView() const
QUtf8StringView asUtf8StringView() const
ValueFlags flags
QCborContainerPrivate * container