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(nullptr)
202 , dataLength(0), current(0), nestingLevel(0)
203 , lastError(QJsonParseError::NoError)
204{
205 end = json + length;
206}
207
208
209
210/*
211
212begin-array = ws %x5B ws ; [ left square bracket
213
214begin-object = ws %x7B ws ; { left curly bracket
215
216end-array = ws %x5D ws ; ] right square bracket
217
218end-object = ws %x7D ws ; } right curly bracket
219
220name-separator = ws %x3A ws ; : colon
221
222value-separator = ws %x2C ws ; , comma
223
224Insignificant whitespace is allowed before or after any of the six
225structural characters.
226
227ws = *(
228 %x20 / ; Space
229 %x09 / ; Horizontal tab
230 %x0A / ; Line feed or New line
231 %x0D ; Carriage return
232 )
233
234*/
235
236enum {
237 Space = 0x20,
238 Tab = 0x09,
239 LineFeed = 0x0a,
240 Return = 0x0d,
241 BeginArray = 0x5b,
242 BeginObject = 0x7b,
243 EndArray = 0x5d,
244 EndObject = 0x7d,
245 NameSeparator = 0x3a,
246 ValueSeparator = 0x2c,
247 Quote = 0x22
248};
249
250void Parser::eatBOM()
251{
252 // eat UTF-8 byte order mark
253 uchar utf8bom[3] = { 0xef, 0xbb, 0xbf };
254 if (end - json > 3 &&
255 (uchar)json[0] == utf8bom[0] &&
256 (uchar)json[1] == utf8bom[1] &&
257 (uchar)json[2] == utf8bom[2])
258 json += 3;
259}
260
261bool Parser::eatSpace()
262{
263 while (json < end) {
264 if (*json > Space)
265 break;
266 if (*json != Space &&
267 *json != Tab &&
268 *json != LineFeed &&
269 *json != Return)
270 break;
271 ++json;
272 }
273 return (json < end);
274}
275
276char Parser::nextToken()
277{
278 if (!eatSpace())
279 return 0;
280 char token = *json++;
281 switch (token) {
282 case BeginArray:
283 case BeginObject:
284 case NameSeparator:
285 case ValueSeparator:
286 case EndArray:
287 case EndObject:
288 case Quote:
289 break;
290 default:
291 token = 0;
292 break;
293 }
294 return token;
295}
296
297/*
298 JSON-text = object / array
299*/
300QJsonDocument Parser::parse(QJsonParseError *error)
301{
302#ifdef PARSER_DEBUG
303 indent = 0;
304 qDebug(">>>>> parser begin");
305#endif
306 // allocate some space
307 dataLength = qMax(end - json, (ptrdiff_t) 256);
308 data = (char *)malloc(dataLength);
309 Q_CHECK_PTR(data);
310
311 // fill in Header data
312 QJsonPrivate::Header *h = (QJsonPrivate::Header *)data;
313 h->tag = QJsonDocument::BinaryFormatTag;
314 h->version = 1u;
315
316 current = sizeof(QJsonPrivate::Header);
317
318 eatBOM();
319 char token = nextToken();
320
321 DEBUG << Qt::hex << (uint)token;
322 if (token == BeginArray) {
323 if (!parseArray())
324 goto error;
325 } else if (token == BeginObject) {
326 if (!parseObject())
327 goto error;
328 } else {
329 lastError = QJsonParseError::IllegalValue;
330 goto error;
331 }
332
333 eatSpace();
334 if (json < end) {
335 lastError = QJsonParseError::GarbageAtEnd;
336 goto error;
337 }
338
339 END;
340 {
341 if (error) {
342 error->offset = 0;
343 error->error = QJsonParseError::NoError;
344 }
345 QJsonPrivate::Data *d = new QJsonPrivate::Data(data, current);
346 return QJsonDocument(d);
347 }
348
349error:
350#ifdef PARSER_DEBUG
351 qDebug(">>>>> parser error");
352#endif
353 if (error) {
354 error->offset = json - head;
355 error->error = lastError;
356 }
357 free(data);
358 return QJsonDocument();
359}
360
361
362void Parser::ParsedObject::insert(uint offset) {
363 const QJsonPrivate::Entry *newEntry = reinterpret_cast<const QJsonPrivate::Entry *>(parser->data + objectPosition + offset);
364 int min = 0;
365 int n = offsets.size();
366 while (n > 0) {
367 int half = n >> 1;
368 int middle = min + half;
369 if (*entryAt(middle) >= *newEntry) {
370 n = half;
371 } else {
372 min = middle + 1;
373 n -= half + 1;
374 }
375 }
376 if (min < offsets.size() && *entryAt(min) == *newEntry) {
377 offsets[min] = offset;
378 } else {
379 offsets.insert(min, offset);
380 }
381}
382
383/*
384 object = begin-object [ member *( value-separator member ) ]
385 end-object
386*/
387
388bool Parser::parseObject()
389{
390 if (++nestingLevel > nestingLimit) {
391 lastError = QJsonParseError::DeepNesting;
392 return false;
393 }
394
395 int objectOffset = reserveSpace(sizeof(QJsonPrivate::Object));
396 if (objectOffset < 0)
397 return false;
398 BEGIN << "parseObject pos=" << objectOffset << current << json;
399
400 ParsedObject parsedObject(this, objectOffset);
401
402 char token = nextToken();
403 while (token == Quote) {
404 int off = current - objectOffset;
405 if (!parseMember(objectOffset))
406 return false;
407 parsedObject.insert(off);
408 token = nextToken();
409 if (token != ValueSeparator)
410 break;
411 token = nextToken();
412 if (token == EndObject) {
413 lastError = QJsonParseError::MissingObject;
414 return false;
415 }
416 }
417
418 DEBUG << "end token=" << token;
419 if (token != EndObject) {
420 lastError = QJsonParseError::UnterminatedObject;
421 return false;
422 }
423
424 DEBUG << "numEntries" << parsedObject.offsets.size();
425 int table = objectOffset;
426 // finalize the object
427 if (parsedObject.offsets.size()) {
428 int tableSize = parsedObject.offsets.size()*sizeof(uint);
429 table = reserveSpace(tableSize);
430 if (table < 0)
431 return false;
432
433#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
434 memcpy(data + table, parsedObject.offsets.constData(), tableSize);
435#else
436 offset *o = (offset *)(data + table);
437 for (int i = 0; i < parsedObject.offsets.size(); ++i)
438 o[i] = parsedObject.offsets[i];
439
440#endif
441 }
442
443 QJsonPrivate::Object *o = (QJsonPrivate::Object *)(data + objectOffset);
444 o->tableOffset = table - objectOffset;
445 o->size = current - objectOffset;
446 o->is_object = true;
447 o->length = parsedObject.offsets.size();
448
449 DEBUG << "current=" << current;
450 END;
451
452 --nestingLevel;
453 return true;
454}
455
456/*
457 member = string name-separator value
458*/
459bool Parser::parseMember(int baseOffset)
460{
461 int entryOffset = reserveSpace(sizeof(QJsonPrivate::Entry));
462 if (entryOffset < 0)
463 return false;
464 BEGIN << "parseMember pos=" << entryOffset;
465
466 bool latin1;
467 if (!parseString(&latin1))
468 return false;
469 char token = nextToken();
470 if (token != NameSeparator) {
471 lastError = QJsonParseError::MissingNameSeparator;
472 return false;
473 }
474 if (!eatSpace()) {
475 lastError = QJsonParseError::UnterminatedObject;
476 return false;
477 }
478 QJsonPrivate::Value val;
479 if (!parseValue(&val, baseOffset))
480 return false;
481
482 // finalize the entry
483 QJsonPrivate::Entry *e = (QJsonPrivate::Entry *)(data + entryOffset);
484 e->value = val;
485 e->value.latinKey = latin1;
486
487 END;
488 return true;
489}
490
491namespace {
492 struct ValueArray {
493 static const int prealloc = 128;
494 ValueArray() : data(stackValues), alloc(prealloc), size(0) {}
495 ~ValueArray() { if (data != stackValues) free(data); }
496
497 inline bool grow() {
498 alloc *= 2;
499 if (data == stackValues) {
500 QJsonPrivate::Value *newValues = static_cast<QJsonPrivate::Value *>(malloc(alloc*sizeof(QJsonPrivate::Value)));
501 if (!newValues)
502 return false;
503 memcpy(newValues, data, size*sizeof(QJsonPrivate::Value));
504 data = newValues;
505 } else {
506 void *newValues = realloc(data, alloc * sizeof(QJsonPrivate::Value));
507 if (!newValues)
508 return false;
509 data = static_cast<QJsonPrivate::Value *>(newValues);
510 }
511 return true;
512 }
513 bool append(const QJsonPrivate::Value &v) {
514 if (alloc == size && !grow())
515 return false;
516 data[size] = v;
517 ++size;
518 return true;
519 }
520
521 QJsonPrivate::Value stackValues[prealloc];
522 QJsonPrivate::Value *data;
523 int alloc;
524 int size;
525 };
526}
527
528/*
529 array = begin-array [ value *( value-separator value ) ] end-array
530*/
531bool Parser::parseArray()
532{
533 BEGIN << "parseArray";
534
535 if (++nestingLevel > nestingLimit) {
536 lastError = QJsonParseError::DeepNesting;
537 return false;
538 }
539
540 int arrayOffset = reserveSpace(sizeof(QJsonPrivate::Array));
541 if (arrayOffset < 0)
542 return false;
543
544 ValueArray values;
545
546 if (!eatSpace()) {
547 lastError = QJsonParseError::UnterminatedArray;
548 return false;
549 }
550 if (*json == EndArray) {
551 nextToken();
552 } else {
553 while (1) {
554 if (!eatSpace()) {
555 lastError = QJsonParseError::UnterminatedArray;
556 return false;
557 }
558 QJsonPrivate::Value val;
559 if (!parseValue(&val, arrayOffset))
560 return false;
561 if (!values.append(val)) {
562 lastError = QJsonParseError::DocumentTooLarge;
563 return false;
564 }
565 char token = nextToken();
566 if (token == EndArray)
567 break;
568 else if (token != ValueSeparator) {
569 if (!eatSpace())
570 lastError = QJsonParseError::UnterminatedArray;
571 else
572 lastError = QJsonParseError::MissingValueSeparator;
573 return false;
574 }
575 }
576 }
577
578 DEBUG << "size =" << values.size;
579 int table = arrayOffset;
580 // finalize the object
581 if (values.size) {
582 int tableSize = values.size*sizeof(QJsonPrivate::Value);
583 table = reserveSpace(tableSize);
584 if (table < 0)
585 return false;
586 memcpy(data + table, values.data, tableSize);
587 }
588
589 QJsonPrivate::Array *a = (QJsonPrivate::Array *)(data + arrayOffset);
590 a->tableOffset = table - arrayOffset;
591 a->size = current - arrayOffset;
592 a->is_object = false;
593 a->length = values.size;
594
595 DEBUG << "current=" << current;
596 END;
597
598 --nestingLevel;
599 return true;
600}
601
602/*
603value = false / null / true / object / array / number / string
604
605*/
606
607bool Parser::parseValue(QJsonPrivate::Value *val, int baseOffset)
608{
609 BEGIN << "parse Value" << json;
610 val->_dummy = 0;
611
612 switch (*json++) {
613 case 'n':
614 if (end - json < 4) {
615 lastError = QJsonParseError::IllegalValue;
616 return false;
617 }
618 if (*json++ == 'u' &&
619 *json++ == 'l' &&
620 *json++ == 'l') {
621 val->type = QJsonValue::Null;
622 DEBUG << "value: null";
623 END;
624 return true;
625 }
626 lastError = QJsonParseError::IllegalValue;
627 return false;
628 case 't':
629 if (end - json < 4) {
630 lastError = QJsonParseError::IllegalValue;
631 return false;
632 }
633 if (*json++ == 'r' &&
634 *json++ == 'u' &&
635 *json++ == 'e') {
636 val->type = QJsonValue::Bool;
637 val->value = true;
638 DEBUG << "value: true";
639 END;
640 return true;
641 }
642 lastError = QJsonParseError::IllegalValue;
643 return false;
644 case 'f':
645 if (end - json < 5) {
646 lastError = QJsonParseError::IllegalValue;
647 return false;
648 }
649 if (*json++ == 'a' &&
650 *json++ == 'l' &&
651 *json++ == 's' &&
652 *json++ == 'e') {
653 val->type = QJsonValue::Bool;
654 val->value = false;
655 DEBUG << "value: false";
656 END;
657 return true;
658 }
659 lastError = QJsonParseError::IllegalValue;
660 return false;
661 case Quote: {
662 val->type = QJsonValue::String;
663 if (current - baseOffset >= Value::MaxSize) {
664 lastError = QJsonParseError::DocumentTooLarge;
665 return false;
666 }
667 val->value = current - baseOffset;
668 bool latin1;
669 if (!parseString(&latin1))
670 return false;
671 val->latinOrIntValue = latin1;
672 DEBUG << "value: string";
673 END;
674 return true;
675 }
676 case BeginArray:
677 val->type = QJsonValue::Array;
678 if (current - baseOffset >= Value::MaxSize) {
679 lastError = QJsonParseError::DocumentTooLarge;
680 return false;
681 }
682 val->value = current - baseOffset;
683 if (!parseArray())
684 return false;
685 DEBUG << "value: array";
686 END;
687 return true;
688 case BeginObject:
689 val->type = QJsonValue::Object;
690 if (current - baseOffset >= Value::MaxSize) {
691 lastError = QJsonParseError::DocumentTooLarge;
692 return false;
693 }
694 val->value = current - baseOffset;
695 if (!parseObject())
696 return false;
697 DEBUG << "value: object";
698 END;
699 return true;
700 case ValueSeparator:
701 // Essentially missing value, but after a colon, not after a comma
702 // like the other MissingObject errors.
703 lastError = QJsonParseError::IllegalValue;
704 return false;
705 case EndObject:
706 case EndArray:
707 lastError = QJsonParseError::MissingObject;
708 return false;
709 default:
710 --json;
711 if (!parseNumber(val, baseOffset))
712 return false;
713 DEBUG << "value: number";
714 END;
715 }
716
717 return true;
718}
719
720
721
722
723
724/*
725 number = [ minus ] int [ frac ] [ exp ]
726 decimal-point = %x2E ; .
727 digit1-9 = %x31-39 ; 1-9
728 e = %x65 / %x45 ; e E
729 exp = e [ minus / plus ] 1*DIGIT
730 frac = decimal-point 1*DIGIT
731 int = zero / ( digit1-9 *DIGIT )
732 minus = %x2D ; -
733 plus = %x2B ; +
734 zero = %x30 ; 0
735
736*/
737
738bool Parser::parseNumber(QJsonPrivate::Value *val, int baseOffset)
739{
740 BEGIN << "parseNumber" << json;
741 val->type = QJsonValue::Double;
742
743 const char *start = json;
744 bool isInt = true;
745
746 // minus
747 if (json < end && *json == '-')
748 ++json;
749
750 // int = zero / ( digit1-9 *DIGIT )
751 if (json < end && *json == '0') {
752 ++json;
753 } else {
754 while (json < end && *json >= '0' && *json <= '9')
755 ++json;
756 }
757
758 // frac = decimal-point 1*DIGIT
759 if (json < end && *json == '.') {
760 isInt = false;
761 ++json;
762 while (json < end && *json >= '0' && *json <= '9')
763 ++json;
764 }
765
766 // exp = e [ minus / plus ] 1*DIGIT
767 if (json < end && (*json == 'e' || *json == 'E')) {
768 isInt = false;
769 ++json;
770 if (json < end && (*json == '-' || *json == '+'))
771 ++json;
772 while (json < end && *json >= '0' && *json <= '9')
773 ++json;
774 }
775
776 if (json >= end) {
777 lastError = QJsonParseError::TerminationByNumber;
778 return false;
779 }
780
781 QByteArray number(start, json - start);
782 DEBUG << "numberstring" << number;
783
784 if (isInt) {
785 bool ok;
786 int n = number.toInt(&ok);
787 if (ok && n < (1<<25) && n > -(1<<25)) {
788 val->int_value = n;
789 val->latinOrIntValue = true;
790 END;
791 return true;
792 }
793 }
794
795 bool ok;
796 union {
797 quint64 ui;
798 double d;
799 };
800 d = number.toDouble(&ok);
801
802 if (!ok) {
803 lastError = QJsonParseError::IllegalNumber;
804 return false;
805 }
806
807 int pos = reserveSpace(sizeof(double));
808 if (pos < 0)
809 return false;
810 qToLittleEndian(ui, data + pos);
811 if (current - baseOffset >= Value::MaxSize) {
812 lastError = QJsonParseError::DocumentTooLarge;
813 return false;
814 }
815 val->value = pos - baseOffset;
816 val->latinOrIntValue = false;
817
818 END;
819 return true;
820}
821
822/*
823
824 string = quotation-mark *char quotation-mark
825
826 char = unescaped /
827 escape (
828 %x22 / ; " quotation mark U+0022
829 %x5C / ; \ reverse solidus U+005C
830 %x2F / ; / solidus U+002F
831 %x62 / ; b backspace U+0008
832 %x66 / ; f form feed U+000C
833 %x6E / ; n line feed U+000A
834 %x72 / ; r carriage return U+000D
835 %x74 / ; t tab U+0009
836 %x75 4HEXDIG ) ; uXXXX U+XXXX
837
838 escape = %x5C ; \
839
840 quotation-mark = %x22 ; "
841
842 unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
843 */
844static inline bool addHexDigit(char digit, uint *result)
845{
846 *result <<= 4;
847 if (digit >= '0' && digit <= '9')
848 *result |= (digit - '0');
849 else if (digit >= 'a' && digit <= 'f')
850 *result |= (digit - 'a') + 10;
851 else if (digit >= 'A' && digit <= 'F')
852 *result |= (digit - 'A') + 10;
853 else
854 return false;
855 return true;
856}
857
858static inline bool scanEscapeSequence(const char *&json, const char *end, uint *ch)
859{
860 ++json;
861 if (json >= end)
862 return false;
863
864 DEBUG << "scan escape" << (char)*json;
865 uint escaped = *json++;
866 switch (escaped) {
867 case '"':
868 *ch = '"'; break;
869 case '\\':
870 *ch = '\\'; break;
871 case '/':
872 *ch = '/'; break;
873 case 'b':
874 *ch = 0x8; break;
875 case 'f':
876 *ch = 0xc; break;
877 case 'n':
878 *ch = 0xa; break;
879 case 'r':
880 *ch = 0xd; break;
881 case 't':
882 *ch = 0x9; break;
883 case 'u': {
884 *ch = 0;
885 if (json > end - 4)
886 return false;
887 for (int i = 0; i < 4; ++i) {
888 if (!addHexDigit(*json, ch))
889 return false;
890 ++json;
891 }
892 return true;
893 }
894 default:
895 // this is not as strict as one could be, but allows for more Json files
896 // to be parsed correctly.
897 *ch = escaped;
898 return true;
899 }
900 return true;
901}
902
903static inline bool scanUtf8Char(const char *&json, const char *end, uint *result)
904{
905 const uchar *&src = reinterpret_cast<const uchar *&>(json);
906 const uchar *uend = reinterpret_cast<const uchar *>(end);
907 uchar b = *src++;
908 int res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, result, src, uend);
909 if (res < 0) {
910 // decoding error, backtrack the character we read above
911 --json;
912 return false;
913 }
914
915 return true;
916}
917
918bool Parser::parseString(bool *latin1)
919{
920 *latin1 = true;
921
922 const char *start = json;
923 int outStart = current;
924
925 // try to write out a latin1 string
926
927 int stringPos = reserveSpace(2);
928 if (stringPos < 0)
929 return false;
930
931 BEGIN << "parse string stringPos=" << stringPos << json;
932 while (json < end) {
933 uint ch = 0;
934 if (*json == '"')
935 break;
936 else if (*json == '\\') {
937 if (!scanEscapeSequence(json, end, &ch)) {
938 lastError = QJsonParseError::IllegalEscapeSequence;
939 return false;
940 }
941 } else {
942 if (!scanUtf8Char(json, end, &ch)) {
943 lastError = QJsonParseError::IllegalUTF8String;
944 return false;
945 }
946 }
947 // 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)
948 if (ch > 0xff || json - start >= 0x8000) {
949 *latin1 = false;
950 break;
951 }
952 int pos = reserveSpace(1);
953 if (pos < 0)
954 return false;
955 DEBUG << " " << ch << (char)ch;
956 data[pos] = (uchar)ch;
957 }
958 ++json;
959 DEBUG << "end of string";
960 if (json >= end) {
961 lastError = QJsonParseError::UnterminatedString;
962 return false;
963 }
964
965 // no unicode string, we are done
966 if (*latin1) {
967 // write string length
968 *(QJsonPrivate::qle_ushort *)(data + stringPos) = ushort(current - outStart - sizeof(ushort));
969 int pos = reserveSpace((4 - current) & 3);
970 if (pos < 0)
971 return false;
972 while (pos & 3)
973 data[pos++] = 0;
974 END;
975 return true;
976 }
977
978 *latin1 = false;
979 DEBUG << "not latin";
980
981 json = start;
982 current = outStart + sizeof(int);
983
984 while (json < end) {
985 uint ch = 0;
986 if (*json == '"')
987 break;
988 else if (*json == '\\') {
989 if (!scanEscapeSequence(json, end, &ch)) {
990 lastError = QJsonParseError::IllegalEscapeSequence;
991 return false;
992 }
993 } else {
994 if (!scanUtf8Char(json, end, &ch)) {
995 lastError = QJsonParseError::IllegalUTF8String;
996 return false;
997 }
998 }
999 if (QChar::requiresSurrogates(ch)) {
1000 int pos = reserveSpace(4);
1001 if (pos < 0)
1002 return false;
1003 *(QJsonPrivate::qle_ushort *)(data + pos) = QChar::highSurrogate(ch);
1004 *(QJsonPrivate::qle_ushort *)(data + pos + 2) = QChar::lowSurrogate(ch);
1005 } else {
1006 int pos = reserveSpace(2);
1007 if (pos < 0)
1008 return false;
1009 *(QJsonPrivate::qle_ushort *)(data + pos) = (ushort)ch;
1010 }
1011 }
1012 ++json;
1013
1014 if (json >= end) {
1015 lastError = QJsonParseError::UnterminatedString;
1016 return false;
1017 }
1018
1019 // write string length
1020 *(QJsonPrivate::qle_int *)(data + stringPos) = (current - outStart - sizeof(int))/2;
1021 int pos = reserveSpace((4 - current) & 3);
1022 if (pos < 0)
1023 return false;
1024 while (pos & 3)
1025 data[pos++] = 0;
1026 END;
1027 return true;
1028}
1029
1030QT_END_NAMESPACE
1031