qjsonparser.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/corelib/json/qjsonparser.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Copyright (C) 2016 Intel Corporation.-
5** Contact: https://www.qt.io/licensing/-
6**-
7** This file is part of the QtCore module of the Qt Toolkit.-
8**-
9** $QT_BEGIN_LICENSE:LGPL$-
10** Commercial License Usage-
11** Licensees holding valid commercial Qt licenses may use this file in-
12** accordance with the commercial license agreement provided with the-
13** Software or, alternatively, in accordance with the terms contained in-
14** a written agreement between you and The Qt Company. For licensing terms-
15** and conditions see https://www.qt.io/terms-conditions. For further-
16** information use the contact form at https://www.qt.io/contact-us.-
17**-
18** GNU Lesser General Public License Usage-
19** Alternatively, this file may be used under the terms of the GNU Lesser-
20** General Public License version 3 as published by the Free Software-
21** Foundation and appearing in the file LICENSE.LGPL3 included in the-
22** packaging of this file. Please review the following information to-
23** ensure the GNU Lesser General Public License version 3 requirements-
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
25**-
26** GNU General Public License Usage-
27** Alternatively, this file may be used under the terms of the GNU-
28** General Public License version 2.0 or (at your option) the GNU General-
29** Public license version 3 or any later version approved by the KDE Free-
30** Qt Foundation. The licenses are as published by the Free Software-
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
32** included in the packaging of this file. Please review the following-
33** information to ensure the GNU General Public License requirements will-
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
35** https://www.gnu.org/licenses/gpl-3.0.html.-
36**-
37** $QT_END_LICENSE$-
38**-
39****************************************************************************/-
40-
41#ifndef QT_BOOTSTRAPPED-
42#include <qcoreapplication.h>-
43#endif-
44#include <qdebug.h>-
45#include "qjsonparser_p.h"-
46#include "qjson_p.h"-
47#include "private/qutfcodec_p.h"-
48-
49//#define PARSER_DEBUG-
50#ifdef PARSER_DEBUG-
51static int indent = 0;-
52#define BEGIN qDebug() << QByteArray(4*indent++, ' ').constData() << "pos=" << current-
53#define END --indent-
54#define DEBUG qDebug() << QByteArray(4*indent, ' ').constData()-
55#else-
56#define BEGIN if (1) ; else qDebug()-
57#define END do {} while (0)-
58#define DEBUG if (1) ; else qDebug()-
59#endif-
60-
61static const int nestingLimit = 1024;-
62-
63QT_BEGIN_NAMESPACE-
64-
65// error strings for the JSON parser-
66#define JSONERR_OK QT_TRANSLATE_NOOP("QJsonParseError", "no error occurred")-
67#define JSONERR_UNTERM_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "unterminated object")-
68#define JSONERR_MISS_NSEP QT_TRANSLATE_NOOP("QJsonParseError", "missing name separator")-
69#define JSONERR_UNTERM_AR QT_TRANSLATE_NOOP("QJsonParseError", "unterminated array")-
70#define JSONERR_MISS_VSEP QT_TRANSLATE_NOOP("QJsonParseError", "missing value separator")-
71#define JSONERR_ILLEGAL_VAL QT_TRANSLATE_NOOP("QJsonParseError", "illegal value")-
72#define JSONERR_END_OF_NUM QT_TRANSLATE_NOOP("QJsonParseError", "invalid termination by number")-
73#define JSONERR_ILLEGAL_NUM QT_TRANSLATE_NOOP("QJsonParseError", "illegal number")-
74#define JSONERR_STR_ESC_SEQ QT_TRANSLATE_NOOP("QJsonParseError", "invalid escape sequence")-
75#define JSONERR_STR_UTF8 QT_TRANSLATE_NOOP("QJsonParseError", "invalid UTF8 string")-
76#define JSONERR_UTERM_STR QT_TRANSLATE_NOOP("QJsonParseError", "unterminated string")-
77#define JSONERR_MISS_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "object is missing after a comma")-
78#define JSONERR_DEEP_NEST QT_TRANSLATE_NOOP("QJsonParseError", "too deeply nested document")-
79#define JSONERR_DOC_LARGE QT_TRANSLATE_NOOP("QJsonParseError", "too large document")-
80#define JSONERR_GARBAGEEND QT_TRANSLATE_NOOP("QJsonParseError", "garbage at the end of the document")-
81-
82/*!-
83 \class QJsonParseError-
84 \inmodule QtCore-
85 \ingroup json-
86 \ingroup shared-
87 \reentrant-
88 \since 5.0-
89-
90 \brief The QJsonParseError class is used to report errors during JSON parsing.-
91-
92 \sa {JSON Support in Qt}, {JSON Save Game Example}-
93*/-
94-
95/*!-
96 \enum QJsonParseError::ParseError-
97-
98 This enum describes the type of error that occurred during the parsing of a JSON document.-
99-
100 \value NoError No error occurred-
101 \value UnterminatedObject An object is not correctly terminated with a closing curly bracket-
102 \value MissingNameSeparator A comma separating different items is missing-
103 \value UnterminatedArray The array is not correctly terminated with a closing square bracket-
104 \value MissingValueSeparator A colon separating keys from values inside objects is missing-
105 \value IllegalValue The value is illegal-
106 \value TerminationByNumber The input stream ended while parsing a number-
107 \value IllegalNumber The number is not well formed-
108 \value IllegalEscapeSequence An illegal escape sequence occurred in the input-
109 \value IllegalUTF8String An illegal UTF8 sequence occurred in the input-
110 \value UnterminatedString A string wasn't terminated with a quote-
111 \value MissingObject An object was expected but couldn't be found-
112 \value DeepNesting The JSON document is too deeply nested for the parser to parse it-
113 \value DocumentTooLarge The JSON document is too large for the parser to parse it-
114 \value GarbageAtEnd The parsed document contains additional garbage characters at the end-
115-
116*/-
117-
118/*!-
119 \variable QJsonParseError::error-
120-
121 Contains the type of the parse error. Is equal to QJsonParseError::NoError if the document-
122 was parsed correctly.-
123-
124 \sa ParseError, errorString()-
125*/-
126-
127-
128/*!-
129 \variable QJsonParseError::offset-
130-
131 Contains the offset in the input string where the parse error occurred.-
132-
133 \sa error, errorString()-
134*/-
135-
136/*!-
137 Returns the human-readable message appropriate to the reported JSON parsing error.-
138-
139 \sa error-
140 */-
141QString QJsonParseError::errorString() const-
142{-
143 const char *sz = "";-
144 switch (error) {-
145 case NoError:-
146 sz = JSONERR_OK;-
147 break;-
148 case UnterminatedObject:-
149 sz = JSONERR_UNTERM_OBJ;-
150 break;-
151 case MissingNameSeparator:-
152 sz = JSONERR_MISS_NSEP;-
153 break;-
154 case UnterminatedArray:-
155 sz = JSONERR_UNTERM_AR;-
156 break;-
157 case MissingValueSeparator:-
158 sz = JSONERR_MISS_VSEP;-
159 break;-
160 case IllegalValue:-
161 sz = JSONERR_ILLEGAL_VAL;-
162 break;-
163 case TerminationByNumber:-
164 sz = JSONERR_END_OF_NUM;-
165 break;-
166 case IllegalNumber:-
167 sz = JSONERR_ILLEGAL_NUM;-
168 break;-
169 case IllegalEscapeSequence:-
170 sz = JSONERR_STR_ESC_SEQ;-
171 break;-
172 case IllegalUTF8String:-
173 sz = JSONERR_STR_UTF8;-
174 break;-
175 case UnterminatedString:-
176 sz = JSONERR_UTERM_STR;-
177 break;-
178 case MissingObject:-
179 sz = JSONERR_MISS_OBJ;-
180 break;-
181 case DeepNesting:-
182 sz = JSONERR_DEEP_NEST;-
183 break;-
184 case DocumentTooLarge:-
185 sz = JSONERR_DOC_LARGE;-
186 break;-
187 case GarbageAtEnd:-
188 sz = JSONERR_GARBAGEEND;-
189 break;-
190 }-
191#ifndef QT_BOOTSTRAPPED-
192 return QCoreApplication::translate("QJsonParseError", sz);-
193#else-
194 return QLatin1String(sz);-
195#endif-
196}-
197-
198using namespace QJsonPrivate;-
199-
200Parser::Parser(const char *json, int length)-
201 : head(json), json(json), data(0), dataLength(0), current(0), nestingLevel(0), lastError(QJsonParseError::NoError)-
202{-
203 end = json + length;-
204}-
205-
206-
207-
208/*-
209-
210begin-array = ws %x5B ws ; [ left square bracket-
211-
212begin-object = ws %x7B ws ; { left curly bracket-
213-
214end-array = ws %x5D ws ; ] right square bracket-
215-
216end-object = ws %x7D ws ; } right curly bracket-
217-
218name-separator = ws %x3A ws ; : colon-
219-
220value-separator = ws %x2C ws ; , comma-
221-
222Insignificant whitespace is allowed before or after any of the six-
223structural characters.-
224-
225ws = *(-
226 %x20 / ; Space-
227 %x09 / ; Horizontal tab-
228 %x0A / ; Line feed or New line-
229 %x0D ; Carriage return-
230 )-
231-
232*/-
233-
234enum {-
235 Space = 0x20,-
236 Tab = 0x09,-
237 LineFeed = 0x0a,-
238 Return = 0x0d,-
239 BeginArray = 0x5b,-
240 BeginObject = 0x7b,-
241 EndArray = 0x5d,-
242 EndObject = 0x7d,-
243 NameSeparator = 0x3a,-
244 ValueSeparator = 0x2c,-
245 Quote = 0x22-
246};-
247-
248void Parser::eatBOM()-
249{-
250 // eat UTF-8 byte order mark-
251 uchar utf8bom[3] = { 0xef, 0xbb, 0xbf };-
252 if (end - json > 3 &&-
253 (uchar)json[0] == utf8bom[0] &&-
254 (uchar)json[1] == utf8bom[1] &&-
255 (uchar)json[2] == utf8bom[2])-
256 json += 3;-
257}-
258-
259bool Parser::eatSpace()-
260{-
261 while (json < end) {-
262 if (*json > Space)-
263 break;-
264 if (*json != Space &&-
265 *json != Tab &&-
266 *json != LineFeed &&-
267 *json != Return)-
268 break;-
269 ++json;-
270 }-
271 return (json < end);-
272}-
273-
274char Parser::nextToken()-
275{-
276 if (!eatSpace())-
277 return 0;-
278 char token = *json++;-
279 switch (token) {-
280 case BeginArray:-
281 case BeginObject:-
282 case NameSeparator:-
283 case ValueSeparator:-
284 case EndArray:-
285 case EndObject:-
286 eatSpace();-
287 case Quote:-
288 break;-
289 default:-
290 token = 0;-
291 break;-
292 }-
293 return token;-
294}-
295-
296/*-
297 JSON-text = object / array-
298*/-
299QJsonDocument Parser::parse(QJsonParseError *error)-
300{-
301#ifdef PARSER_DEBUG-
302 indent = 0;-
303 qDebug() << (">>>>> parser begin";);-
304#endif-
305 // allocate some space-
306 dataLength = qMax(end - json, (ptrdiff_t) 256);-
307 data = (char *)malloc(dataLength);-
308-
309 // fill in Header data-
310 QJsonPrivate::Header *h = (QJsonPrivate::Header *)data;-
311 h->tag = QJsonDocument::BinaryFormatTag;-
312 h->version = 1u;-
313-
314 current = sizeof(QJsonPrivate::Header);-
315-
316 eatBOM();-
317 char token = nextToken();-
318-
319 DEBUG << hex << (uint)token;
executed 10 times by 4 tests: ;
Executed by:
  • tst_QMetaType
  • tst_QNetworkCookieJar
  • tst_QOpenGlConfig
  • tst_qmakelib
dead code: QMessageLogger(__FILE__, 319, __PRETTY_FUNCTION__).debug() << hex << (uint)token;
-
320 if (token == BeginArray) {
token == BeginArrayDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • tst_QNetworkCookieJar
FALSEevaluated 9 times by 3 tests
Evaluated by:
  • tst_QMetaType
  • tst_QOpenGlConfig
  • tst_qmakelib
1-9
321 if (!parseArray())
!parseArray()Description
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_QNetworkCookieJar
0-1
322 goto error;
never executed: goto error;
0
323 } else if (token == BeginObject) {
executed 1 time by 1 test: end of block
Executed by:
  • tst_QNetworkCookieJar
token == BeginObjectDescription
TRUEevaluated 8 times by 3 tests
Evaluated by:
  • tst_QMetaType
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_qmakelib
1-8
324 if (!parseObject())
!parseObject()Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • tst_QMetaType
FALSEevaluated 6 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
2-6
325 goto error;
executed 2 times by 1 test: goto error;
Executed by:
  • tst_QMetaType
2
326 } else {
executed 6 times by 2 tests: end of block
Executed by:
  • tst_QOpenGlConfig
  • tst_qmakelib
6
327 lastError = QJsonParseError::IllegalValue;-
328 goto error;
executed 1 time by 1 test: goto error;
Executed by:
  • tst_qmakelib
1
329 }-
330-
331 eatSpace();-
332 if (json < end) {
json < endDescription
TRUEnever evaluated
FALSEevaluated 7 times by 3 tests
Evaluated by:
  • tst_QNetworkCookieJar
  • tst_QOpenGlConfig
  • tst_qmakelib
0-7
333 lastError = QJsonParseError::GarbageAtEnd;-
334 goto error;
never executed: goto error;
0
335 }-
336-
337 END;-
338 {-
339 if (error) {
errorDescription
TRUEevaluated 5 times by 1 test
Evaluated by:
  • tst_QOpenGlConfig
FALSEevaluated 2 times by 2 tests
Evaluated by:
  • tst_QNetworkCookieJar
  • tst_qmakelib
2-5
340 error->offset = 0;-
341 error->error = QJsonParseError::NoError;-
342 }
executed 5 times by 1 test: end of block
Executed by:
  • tst_QOpenGlConfig
5
343 QJsonPrivate::Data *d = new QJsonPrivate::Data(data, current);-
344 return QJsonDocument(d);
executed 7 times by 3 tests: return QJsonDocument(d);
Executed by:
  • tst_QNetworkCookieJar
  • tst_QOpenGlConfig
  • tst_qmakelib
7
345 }-
346-
347error:-
348#ifdef PARSER_DEBUG-
349 qDebug() << (">>>>> parser error";);-
350#endif-
351 if (error) {
errorDescription
TRUEnever evaluated
FALSEevaluated 3 times by 2 tests
Evaluated by:
  • tst_QMetaType
  • tst_qmakelib
0-3
352 error->offset = json - head;-
353 error->error = lastError;-
354 }
never executed: end of block
0
355 free(data);-
356 return QJsonDocument();
executed 3 times by 2 tests: return QJsonDocument();
Executed by:
  • tst_QMetaType
  • tst_qmakelib
3
357}-
358-
359-
360void Parser::ParsedObject::insert(uint offset) {-
361 const QJsonPrivate::Entry *newEntry = reinterpret_cast<const QJsonPrivate::Entry *>(parser->data + objectPosition + offset);-
362 int min = 0;-
363 int n = offsets.size();-
364 while (n > 0) {-
365 int half = n >> 1;-
366 int middle = min + half;-
367 if (*entryAt(middle) >= *newEntry) {-
368 n = half;-
369 } else {-
370 min = middle + 1;-
371 n -= half + 1;-
372 }-
373 }-
374 if (min < offsets.size() && *entryAt(min) == *newEntry) {-
375 offsets[min] = offset;-
376 } else {-
377 offsets.insert(min, offset);-
378 }-
379}-
380-
381/*-
382 object = begin-object [ member *( value-separator member ) ]-
383 end-object-
384*/-
385-
386bool Parser::parseObject()-
387{-
388 if (++nestingLevel > nestingLimit) {-
389 lastError = QJsonParseError::DeepNesting;-
390 return false;-
391 }-
392-
393 int objectOffset = reserveSpace(sizeof(QJsonPrivate::Object));-
394 if (objectOffset < 0)-
395 return false;-
396 BEGIN << "parseObject pos=" << objectOffset << current << json;
dead code: QMessageLogger(__FILE__, 396, __PRETTY_FUNCTION__).debug() << "parseObject pos=" << objectOffset << current << json;
-
397-
398 ParsedObject parsedObject(this, objectOffset);-
399-
400 char token = nextToken();-
401 while (token == Quote) {-
402 int off = current - objectOffset;-
403 if (!parseMember(objectOffset))-
404 return false;-
405 parsedObject.insert(off);-
406 token = nextToken();-
407 if (token != ValueSeparator)-
408 break;-
409 token = nextToken();-
410 if (token == EndObject) {-
411 lastError = QJsonParseError::MissingObject;-
412 return false;-
413 }-
414 }-
415-
416 DEBUG << "end token=" << token;
dead code: QMessageLogger(__FILE__, 416, __PRETTY_FUNCTION__).debug() << "end token=" << token;
-
417 if (token != EndObject) {-
418 lastError = QJsonParseError::UnterminatedObject;-
419 return false;-
420 }-
421-
422 DEBUG << "numEntries" << parsedObject.offsets.size();
dead code: QMessageLogger(__FILE__, 422, __PRETTY_FUNCTION__).debug() << "numEntries" << parsedObject.offsets.size();
-
423 int table = objectOffset;-
424 // finalize the object-
425 if (parsedObject.offsets.size()) {-
426 int tableSize = parsedObject.offsets.size()*sizeof(uint);-
427 table = reserveSpace(tableSize);-
428 if (table < 0)-
429 return false;-
430-
431#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN-
432 memcpy(data + table, parsedObject.offsets.constData(), tableSize);-
433#else-
434 offset *o = (offset *)(data + table);-
435 for (int i = 0; i < parsedObject.offsets.size(); ++i)-
436 o[i] = parsedObject.offsets[i];-
437-
438#endif-
439 }-
440-
441 QJsonPrivate::Object *o = (QJsonPrivate::Object *)(data + objectOffset);-
442 o->tableOffset = table - objectOffset;-
443 o->size = current - objectOffset;-
444 o->is_object = true;-
445 o->length = parsedObject.offsets.size();-
446-
447 DEBUG << "current=" << current;
dead code: QMessageLogger(__FILE__, 447, __PRETTY_FUNCTION__).debug() << "current=" << current;
-
448 END;-
449-
450 --nestingLevel;-
451 return true;-
452}-
453-
454/*-
455 member = string name-separator value-
456*/-
457bool Parser::parseMember(int baseOffset)-
458{-
459 int entryOffset = reserveSpace(sizeof(QJsonPrivate::Entry));-
460 if (entryOffset < 0)-
461 return false;-
462 BEGIN << "parseMember pos=" << entryOffset;
dead code: QMessageLogger(__FILE__, 462, __PRETTY_FUNCTION__).debug() << "parseMember pos=" << entryOffset;
-
463-
464 bool latin1;-
465 if (!parseString(&latin1))-
466 return false;-
467 char token = nextToken();-
468 if (token != NameSeparator) {-
469 lastError = QJsonParseError::MissingNameSeparator;-
470 return false;-
471 }-
472 QJsonPrivate::Value val;-
473 if (!parseValue(&val, baseOffset))-
474 return false;-
475-
476 // finalize the entry-
477 QJsonPrivate::Entry *e = (QJsonPrivate::Entry *)(data + entryOffset);-
478 e->value = val;-
479 e->value.latinKey = latin1;-
480-
481 END;-
482 return true;-
483}-
484-
485namespace {-
486 struct ValueArray {-
487 static const int prealloc = 128;-
488 ValueArray() : data(stackValues), alloc(prealloc), size(0) {}-
489 ~ValueArray() { if (data != stackValues) free(data); }-
490-
491 inline bool grow() {-
492 alloc *= 2;-
493 if (data == stackValues) {-
494 QJsonPrivate::Value *newValues = static_cast<QJsonPrivate::Value *>(malloc(alloc*sizeof(QJsonPrivate::Value)));-
495 if (!newValues)-
496 return false;-
497 memcpy(newValues, data, size*sizeof(QJsonPrivate::Value));-
498 data = newValues;-
499 } else {-
500 void *newValues = realloc(data, alloc * sizeof(QJsonPrivate::Value));-
501 if (!newValues)-
502 return false;-
503 data = static_cast<QJsonPrivate::Value *>(newValues);-
504 }-
505 return true;-
506 }-
507 bool append(const QJsonPrivate::Value &v) {-
508 if (alloc == size && !grow())-
509 return false;-
510 data[size] = v;-
511 ++size;-
512 return true;-
513 }-
514-
515 QJsonPrivate::Value stackValues[prealloc];-
516 QJsonPrivate::Value *data;-
517 int alloc;-
518 int size;-
519 };-
520}-
521-
522/*-
523 array = begin-array [ value *( value-separator value ) ] end-array-
524*/-
525bool Parser::parseArray()-
526{-
527 BEGIN << "parseArray";
dead code: QMessageLogger(__FILE__, 527, __PRETTY_FUNCTION__).debug() << "parseArray";
-
528-
529 if (++nestingLevel > nestingLimit) {-
530 lastError = QJsonParseError::DeepNesting;-
531 return false;-
532 }-
533-
534 int arrayOffset = reserveSpace(sizeof(QJsonPrivate::Array));-
535 if (arrayOffset < 0)-
536 return false;-
537-
538 ValueArray values;-
539-
540 if (!eatSpace()) {-
541 lastError = QJsonParseError::UnterminatedArray;-
542 return false;-
543 }-
544 if (*json == EndArray) {-
545 nextToken();-
546 } else {-
547 while (1) {-
548 QJsonPrivate::Value val;-
549 if (!parseValue(&val, arrayOffset))-
550 return false;-
551 if (!values.append(val)) {-
552 lastError = QJsonParseError::DocumentTooLarge;-
553 return false;-
554 }-
555 char token = nextToken();-
556 if (token == EndArray)-
557 break;-
558 else if (token != ValueSeparator) {-
559 if (!eatSpace())-
560 lastError = QJsonParseError::UnterminatedArray;-
561 else-
562 lastError = QJsonParseError::MissingValueSeparator;-
563 return false;-
564 }-
565 }-
566 }-
567-
568 DEBUG << "size =" << values.size;
dead code: QMessageLogger(__FILE__, 568, __PRETTY_FUNCTION__).debug() << "size =" << values.size;
-
569 int table = arrayOffset;-
570 // finalize the object-
571 if (values.size) {-
572 int tableSize = values.size*sizeof(QJsonPrivate::Value);-
573 table = reserveSpace(tableSize);-
574 if (table < 0)-
575 return false;-
576 memcpy(data + table, values.data, tableSize);-
577 }-
578-
579 QJsonPrivate::Array *a = (QJsonPrivate::Array *)(data + arrayOffset);-
580 a->tableOffset = table - arrayOffset;-
581 a->size = current - arrayOffset;-
582 a->is_object = false;-
583 a->length = values.size;-
584-
585 DEBUG << "current=" << current;
dead code: QMessageLogger(__FILE__, 585, __PRETTY_FUNCTION__).debug() << "current=" << current;
-
586 END;-
587-
588 --nestingLevel;-
589 return true;-
590}-
591-
592/*-
593value = false / null / true / object / array / number / string-
594-
595*/-
596-
597bool Parser::parseValue(QJsonPrivate::Value *val, int baseOffset)-
598{-
599 BEGIN << "parse Value" << json;
dead code: QMessageLogger(__FILE__, 599, __PRETTY_FUNCTION__).debug() << "parse Value" << json;
-
600 val->_dummy = 0;-
601-
602 switch (*json++) {-
603 case 'n':-
604 if (end - json < 4) {-
605 lastError = QJsonParseError::IllegalValue;-
606 return false;-
607 }-
608 if (*json++ == 'u' &&-
609 *json++ == 'l' &&-
610 *json++ == 'l') {-
611 val->type = QJsonValue::Null;-
612 DEBUG << "value: null";
dead code: QMessageLogger(__FILE__, 612, __PRETTY_FUNCTION__).debug() << "value: null";
-
613 END;-
614 return true;-
615 }-
616 lastError = QJsonParseError::IllegalValue;-
617 return false;-
618 case 't':-
619 if (end - json < 4) {-
620 lastError = QJsonParseError::IllegalValue;-
621 return false;-
622 }-
623 if (*json++ == 'r' &&-
624 *json++ == 'u' &&-
625 *json++ == 'e') {-
626 val->type = QJsonValue::Bool;-
627 val->value = true;-
628 DEBUG << "value: true";
dead code: QMessageLogger(__FILE__, 628, __PRETTY_FUNCTION__).debug() << "value: true";
-
629 END;-
630 return true;-
631 }-
632 lastError = QJsonParseError::IllegalValue;-
633 return false;-
634 case 'f':-
635 if (end - json < 5) {-
636 lastError = QJsonParseError::IllegalValue;-
637 return false;-
638 }-
639 if (*json++ == 'a' &&-
640 *json++ == 'l' &&-
641 *json++ == 's' &&-
642 *json++ == 'e') {-
643 val->type = QJsonValue::Bool;-
644 val->value = false;-
645 DEBUG << "value: false";
dead code: QMessageLogger(__FILE__, 645, __PRETTY_FUNCTION__).debug() << "value: false";
-
646 END;-
647 return true;-
648 }-
649 lastError = QJsonParseError::IllegalValue;-
650 return false;-
651 case Quote: {-
652 val->type = QJsonValue::String;-
653 if (current - baseOffset >= Value::MaxSize) {-
654 lastError = QJsonParseError::DocumentTooLarge;-
655 return false;-
656 }-
657 val->value = current - baseOffset;-
658 bool latin1;-
659 if (!parseString(&latin1))-
660 return false;-
661 val->latinOrIntValue = latin1;-
662 DEBUG << "value: string";
dead code: QMessageLogger(__FILE__, 662, __PRETTY_FUNCTION__).debug() << "value: string";
-
663 END;-
664 return true;-
665 }-
666 case BeginArray:-
667 val->type = QJsonValue::Array;-
668 if (current - baseOffset >= Value::MaxSize) {-
669 lastError = QJsonParseError::DocumentTooLarge;-
670 return false;-
671 }-
672 val->value = current - baseOffset;-
673 if (!parseArray())-
674 return false;-
675 DEBUG << "value: array";
dead code: QMessageLogger(__FILE__, 675, __PRETTY_FUNCTION__).debug() << "value: array";
-
676 END;-
677 return true;-
678 case BeginObject:-
679 val->type = QJsonValue::Object;-
680 if (current - baseOffset >= Value::MaxSize) {-
681 lastError = QJsonParseError::DocumentTooLarge;-
682 return false;-
683 }-
684 val->value = current - baseOffset;-
685 if (!parseObject())-
686 return false;-
687 DEBUG << "value: object";
dead code: QMessageLogger(__FILE__, 687, __PRETTY_FUNCTION__).debug() << "value: object";
-
688 END;-
689 return true;-
690 case EndArray:-
691 lastError = QJsonParseError::MissingObject;-
692 return false;-
693 default:-
694 --json;-
695 if (!parseNumber(val, baseOffset))-
696 return false;-
697 DEBUG << "value: number";
dead code: QMessageLogger(__FILE__, 697, __PRETTY_FUNCTION__).debug() << "value: number";
-
698 END;-
699 }-
700-
701 return true;-
702}-
703-
704-
705-
706-
707-
708/*-
709 number = [ minus ] int [ frac ] [ exp ]-
710 decimal-point = %x2E ; .-
711 digit1-9 = %x31-39 ; 1-9-
712 e = %x65 / %x45 ; e E-
713 exp = e [ minus / plus ] 1*DIGIT-
714 frac = decimal-point 1*DIGIT-
715 int = zero / ( digit1-9 *DIGIT )-
716 minus = %x2D ; --
717 plus = %x2B ; +-
718 zero = %x30 ; 0-
719-
720*/-
721-
722bool Parser::parseNumber(QJsonPrivate::Value *val, int baseOffset)-
723{-
724 BEGIN << "parseNumber" << json;
executed 51 times by 2 tests: ;
Executed by:
  • tst_QOpenGlConfig
  • tst_qmakelib
dead code: QMessageLogger(__FILE__, 724, __PRETTY_FUNCTION__).debug() << "parseNumber" << json;
-
725 val->type = QJsonValue::Double;-
726-
727 const char *start = json;-
728 bool isInt = true;-
729-
730 // minus-
731 if (json < end && *json == '-')
json < endDescription
TRUEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
*json == '-'Description
TRUEnever evaluated
FALSEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
0-51
732 ++json;
never executed: ++json;
0
733-
734 // int = zero / ( digit1-9 *DIGIT )-
735 if (json < end && *json == '0') {
json < endDescription
TRUEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
*json == '0'Description
TRUEnever evaluated
FALSEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
0-51
736 ++json;-
737 } else {
never executed: end of block
0
738 while (json < end && *json >= '0' && *json <= '9')
json < endDescription
TRUEevaluated 114 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
*json >= '0'Description
TRUEevaluated 63 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
*json <= '9'Description
TRUEevaluated 63 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
0-114
739 ++json;
executed 63 times by 2 tests: ++json;
Executed by:
  • tst_QOpenGlConfig
  • tst_qmakelib
63
740 }
executed 51 times by 2 tests: end of block
Executed by:
  • tst_QOpenGlConfig
  • tst_qmakelib
51
741-
742 // frac = decimal-point 1*DIGIT-
743 if (json < end && *json == '.') {
json < endDescription
TRUEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
*json == '.'Description
TRUEnever evaluated
FALSEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
0-51
744 isInt = false;-
745 ++json;-
746 while (json < end && *json >= '0' && *json <= '9')
json < endDescription
TRUEnever evaluated
FALSEnever evaluated
*json >= '0'Description
TRUEnever evaluated
FALSEnever evaluated
*json <= '9'Description
TRUEnever evaluated
FALSEnever evaluated
0
747 ++json;
never executed: ++json;
0
748 }
never executed: end of block
0
749-
750 // exp = e [ minus / plus ] 1*DIGIT-
751 if (json < end && (*json == 'e' || *json == 'E')) {
json < endDescription
TRUEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
*json == 'e'Description
TRUEnever evaluated
FALSEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
*json == 'E'Description
TRUEnever evaluated
FALSEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
0-51
752 isInt = false;-
753 ++json;-
754 if (json < end && (*json == '-' || *json == '+'))
json < endDescription
TRUEnever evaluated
FALSEnever evaluated
*json == '-'Description
TRUEnever evaluated
FALSEnever evaluated
*json == '+'Description
TRUEnever evaluated
FALSEnever evaluated
0
755 ++json;
never executed: ++json;
0
756 while (json < end && *json >= '0' && *json <= '9')
json < endDescription
TRUEnever evaluated
FALSEnever evaluated
*json >= '0'Description
TRUEnever evaluated
FALSEnever evaluated
*json <= '9'Description
TRUEnever evaluated
FALSEnever evaluated
0
757 ++json;
never executed: ++json;
0
758 }
never executed: end of block
0
759-
760 if (json >= end) {
json >= endDescription
TRUEnever evaluated
FALSEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
0-51
761 lastError = QJsonParseError::TerminationByNumber;-
762 return false;
never executed: return false;
0
763 }-
764-
765 QByteArray number(start, json - start);-
766 DEBUG << "numberstring" << number;
executed 51 times by 2 tests: ;
Executed by:
  • tst_QOpenGlConfig
  • tst_qmakelib
dead code: QMessageLogger(__FILE__, 766, __PRETTY_FUNCTION__).debug() << "numberstring" << number;
-
767-
768 if (isInt) {
isIntDescription
TRUEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
0-51
769 bool ok;-
770 int n = number.toInt(&ok);-
771 if (ok && n < (1<<25) && n > -(1<<25)) {
okDescription
TRUEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
n < (1<<25)Description
TRUEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
n > -(1<<25)Description
TRUEevaluated 51 times by 2 tests
Evaluated by:
  • tst_QOpenGlConfig
  • tst_qmakelib
FALSEnever evaluated
0-51
772 val->int_value = n;-
773 val->latinOrIntValue = true;-
774 END;-
775 return true;
executed 51 times by 2 tests: return true;
Executed by:
  • tst_QOpenGlConfig
  • tst_qmakelib
51
776 }-
777 }
never executed: end of block
0
778-
779 bool ok;-
780 union {-
781 quint64 ui;-
782 double d;-
783 };-
784 d = number.toDouble(&ok);-
785-
786 if (!ok) {
!okDescription
TRUEnever evaluated
FALSEnever evaluated
0
787 lastError = QJsonParseError::IllegalNumber;-
788 return false;
never executed: return false;
0
789 }-
790-
791 int pos = reserveSpace(sizeof(double));-
792 if (pos < 0)
pos < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
793 return false;
never executed: return false;
0
794 qToLittleEndian(ui, reinterpret_cast<uchar *>(data + pos)););-
795 if (current - baseOffset >= Value::MaxSize) {
current - base...Value::MaxSizeDescription
TRUEnever evaluated
FALSEnever evaluated
0
796 lastError = QJsonParseError::DocumentTooLarge;-
797 return false;
never executed: return false;
0
798 }-
799 val->value = pos - baseOffset;-
800 val->latinOrIntValue = false;-
801-
802 END;-
803 return true;
never executed: return true;
0
804}-
805-
806/*-
807-
808 string = quotation-mark *char quotation-mark-
809-
810 char = unescaped /-
811 escape (-
812 %x22 / ; " quotation mark U+0022-
813 %x5C / ; \ reverse solidus U+005C-
814 %x2F / ; / solidus U+002F-
815 %x62 / ; b backspace U+0008-
816 %x66 / ; f form feed U+000C-
817 %x6E / ; n line feed U+000A-
818 %x72 / ; r carriage return U+000D-
819 %x74 / ; t tab U+0009-
820 %x75 4HEXDIG ) ; uXXXX U+XXXX-
821-
822 escape = %x5C ; \-
823-
824 quotation-mark = %x22 ; "-
825-
826 unescaped = %x20-21 / %x23-5B / %x5D-10FFFF-
827 */-
828static inline bool addHexDigit(char digit, uint *result)-
829{-
830 *result <<= 4;-
831 if (digit >= '0' && digit <= '9')-
832 *result |= (digit - '0');-
833 else if (digit >= 'a' && digit <= 'f')-
834 *result |= (digit - 'a') + 10;-
835 else if (digit >= 'A' && digit <= 'F')-
836 *result |= (digit - 'A') + 10;-
837 else-
838 return false;-
839 return true;-
840}-
841-
842static inline bool scanEscapeSequence(const char *&json, const char *end, uint *ch)-
843{-
844 ++json;-
845 if (json >= end)-
846 return false;-
847-
848 DEBUG << "scan escape" << (char)*json;
dead code: QMessageLogger(__FILE__, 848, __PRETTY_FUNCTION__).debug() << "scan escape" << (char)*json;
-
849 uint escaped = *json++;-
850 switch (escaped) {-
851 case '"':-
852 *ch = '"'; break;-
853 case '\\':-
854 *ch = '\\'; break;-
855 case '/':-
856 *ch = '/'; break;-
857 case 'b':-
858 *ch = 0x8; break;-
859 case 'f':-
860 *ch = 0xc; break;-
861 case 'n':-
862 *ch = 0xa; break;-
863 case 'r':-
864 *ch = 0xd; break;-
865 case 't':-
866 *ch = 0x9; break;-
867 case 'u': {-
868 *ch = 0;-
869 if (json > end - 4)-
870 return false;-
871 for (int i = 0; i < 4; ++i) {-
872 if (!addHexDigit(*json, ch))-
873 return false;-
874 ++json;-
875 }-
876 return true;-
877 }-
878 default:-
879 // this is not as strict as one could be, but allows for more Json files-
880 // to be parsed correctly.-
881 *ch = escaped;-
882 return true;-
883 }-
884 return true;-
885}-
886-
887static inline bool scanUtf8Char(const char *&json, const char *end, uint *result)-
888{-
889 const uchar *&src = reinterpret_cast<const uchar *&>(json);-
890 const uchar *uend = reinterpret_cast<const uchar *>(end);-
891 uchar b = *src++;-
892 int res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, result, src, uend);-
893 if (res < 0) {-
894 // decoding error, backtrack the character we read above-
895 --json;-
896 return false;-
897 }-
898-
899 return true;-
900}-
901-
902bool Parser::parseString(bool *latin1)-
903{-
904 *latin1 = true;-
905-
906 const char *start = json;-
907 int outStart = current;-
908-
909 // try to write out a latin1 string-
910-
911 int stringPos = reserveSpace(2);-
912 if (stringPos < 0)-
913 return false;-
914-
915 BEGIN << "parse string stringPos=" << stringPos << json;
dead code: QMessageLogger(__FILE__, 915, __PRETTY_FUNCTION__).debug() << "parse string stringPos=" << stringPos << json;
-
916 while (json < end) {-
917 uint ch = 0;-
918 if (*json == '"')-
919 break;-
920 else if (*json == '\\') {-
921 if (!scanEscapeSequence(json, end, &ch)) {-
922 lastError = QJsonParseError::IllegalEscapeSequence;-
923 return false;-
924 }-
925 } else {-
926 if (!scanUtf8Char(json, end, &ch)) {-
927 lastError = QJsonParseError::IllegalUTF8String;-
928 return false;-
929 }-
930 }-
931 // bail out if the string is not pure latin1 or too long to hold as a latin1string (which has only 16 bit for the length)-
932 if (ch > 0xff || json - start >= 0x8000) {-
933 *latin1 = false;-
934 break;-
935 }-
936 int pos = reserveSpace(1);-
937 if (pos < 0)-
938 return false;-
939 DEBUG << " " << ch << (char)ch;
dead code: QMessageLogger(__FILE__, 939, __PRETTY_FUNCTION__).debug() << " " << ch << (char)ch;
-
940 data[pos] = (uchar)ch;-
941 }-
942 ++json;-
943 DEBUG << "end of string";
dead code: QMessageLogger(__FILE__, 943, __PRETTY_FUNCTION__).debug() << "end of string";
-
944 if (json >= end) {-
945 lastError = QJsonParseError::UnterminatedString;-
946 return false;-
947 }-
948-
949 // no unicode string, we are done-
950 if (*latin1) {-
951 // write string length-
952 *(QJsonPrivate::qle_ushort *)(data + stringPos) = ushort(current - outStart - sizeof(ushort));-
953 int pos = reserveSpace((4 - current) & 3);-
954 if (pos < 0)-
955 return false;-
956 while (pos & 3)-
957 data[pos++] = 0;-
958 END;-
959 return true;-
960 }-
961-
962 *latin1 = false;-
963 DEBUG << "not latin";
dead code: QMessageLogger(__FILE__, 963, __PRETTY_FUNCTION__).debug() << "not latin";
-
964-
965 json = start;-
966 current = outStart + sizeof(int);-
967-
968 while (json < end) {-
969 uint ch = 0;-
970 if (*json == '"')-
971 break;-
972 else if (*json == '\\') {-
973 if (!scanEscapeSequence(json, end, &ch)) {-
974 lastError = QJsonParseError::IllegalEscapeSequence;-
975 return false;-
976 }-
977 } else {-
978 if (!scanUtf8Char(json, end, &ch)) {-
979 lastError = QJsonParseError::IllegalUTF8String;-
980 return false;-
981 }-
982 }-
983 if (QChar::requiresSurrogates(ch)) {-
984 int pos = reserveSpace(4);-
985 if (pos < 0)-
986 return false;-
987 *(QJsonPrivate::qle_ushort *)(data + pos) = QChar::highSurrogate(ch);-
988 *(QJsonPrivate::qle_ushort *)(data + pos + 2) = QChar::lowSurrogate(ch);-
989 } else {-
990 int pos = reserveSpace(2);-
991 if (pos < 0)-
992 return false;-
993 *(QJsonPrivate::qle_ushort *)(data + pos) = (ushort)ch;-
994 }-
995 }-
996 ++json;-
997-
998 if (json >= end) {-
999 lastError = QJsonParseError::UnterminatedString;-
1000 return false;-
1001 }-
1002-
1003 // write string length-
1004 *(QJsonPrivate::qle_int *)(data + stringPos) = (current - outStart - sizeof(int))/2;-
1005 int pos = reserveSpace((4 - current) & 3);-
1006 if (pos < 0)-
1007 return false;-
1008 while (pos & 3)-
1009 data[pos++] = 0;-
1010 END;-
1011 return true;-
1012}-
1013-
1014QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9