summaryrefslogtreecommitdiffstats
path: root/src/corelib/json/qjsonparser.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-12-12 18:32:19 -0800
committerThiago Macieira <thiago.macieira@intel.com>2018-01-26 20:59:50 +0000
commita6b697ca13945a174cff9f3e9b1af1cf61c0bea5 (patch)
tree78d5fad97ff8e89f079df29cc5a75b4e7197bfc7 /src/corelib/json/qjsonparser.cpp
parent657894624521b580f59ff5f58b9c0e9be159dc1c (diff)
Create corelib/serialization and move existing file formats into it
This is in preparation to adding CBOR support. We don't need yet another dir for CBOR and placing it in src/corelib/json is just wrong. Change-Id: I9741f017961b410c910dfffd14ffb9d870340fa6 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/json/qjsonparser.cpp')
-rw-r--r--src/corelib/json/qjsonparser.cpp1027
1 files changed, 0 insertions, 1027 deletions
diff --git a/src/corelib/json/qjsonparser.cpp b/src/corelib/json/qjsonparser.cpp
deleted file mode 100644
index 39738b90a8..0000000000
--- a/src/corelib/json/qjsonparser.cpp
+++ /dev/null
@@ -1,1027 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QT_BOOTSTRAPPED
-#include <qcoreapplication.h>
-#endif
-#include <qdebug.h>
-#include "qjsonparser_p.h"
-#include "qjson_p.h"
-#include "private/qutfcodec_p.h"
-
-//#define PARSER_DEBUG
-#ifdef PARSER_DEBUG
-static int indent = 0;
-#define BEGIN qDebug() << QByteArray(4*indent++, ' ').constData() << "pos=" << current
-#define END --indent
-#define DEBUG qDebug() << QByteArray(4*indent, ' ').constData()
-#else
-#define BEGIN if (1) ; else qDebug()
-#define END do {} while (0)
-#define DEBUG if (1) ; else qDebug()
-#endif
-
-static const int nestingLimit = 1024;
-
-QT_BEGIN_NAMESPACE
-
-// error strings for the JSON parser
-#define JSONERR_OK QT_TRANSLATE_NOOP("QJsonParseError", "no error occurred")
-#define JSONERR_UNTERM_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "unterminated object")
-#define JSONERR_MISS_NSEP QT_TRANSLATE_NOOP("QJsonParseError", "missing name separator")
-#define JSONERR_UNTERM_AR QT_TRANSLATE_NOOP("QJsonParseError", "unterminated array")
-#define JSONERR_MISS_VSEP QT_TRANSLATE_NOOP("QJsonParseError", "missing value separator")
-#define JSONERR_ILLEGAL_VAL QT_TRANSLATE_NOOP("QJsonParseError", "illegal value")
-#define JSONERR_END_OF_NUM QT_TRANSLATE_NOOP("QJsonParseError", "invalid termination by number")
-#define JSONERR_ILLEGAL_NUM QT_TRANSLATE_NOOP("QJsonParseError", "illegal number")
-#define JSONERR_STR_ESC_SEQ QT_TRANSLATE_NOOP("QJsonParseError", "invalid escape sequence")
-#define JSONERR_STR_UTF8 QT_TRANSLATE_NOOP("QJsonParseError", "invalid UTF8 string")
-#define JSONERR_UTERM_STR QT_TRANSLATE_NOOP("QJsonParseError", "unterminated string")
-#define JSONERR_MISS_OBJ QT_TRANSLATE_NOOP("QJsonParseError", "object is missing after a comma")
-#define JSONERR_DEEP_NEST QT_TRANSLATE_NOOP("QJsonParseError", "too deeply nested document")
-#define JSONERR_DOC_LARGE QT_TRANSLATE_NOOP("QJsonParseError", "too large document")
-#define JSONERR_GARBAGEEND QT_TRANSLATE_NOOP("QJsonParseError", "garbage at the end of the document")
-
-/*!
- \class QJsonParseError
- \inmodule QtCore
- \ingroup json
- \ingroup shared
- \reentrant
- \since 5.0
-
- \brief The QJsonParseError class is used to report errors during JSON parsing.
-
- \sa {JSON Support in Qt}, {JSON Save Game Example}
-*/
-
-/*!
- \enum QJsonParseError::ParseError
-
- This enum describes the type of error that occurred during the parsing of a JSON document.
-
- \value NoError No error occurred
- \value UnterminatedObject An object is not correctly terminated with a closing curly bracket
- \value MissingNameSeparator A comma separating different items is missing
- \value UnterminatedArray The array is not correctly terminated with a closing square bracket
- \value MissingValueSeparator A colon separating keys from values inside objects is missing
- \value IllegalValue The value is illegal
- \value TerminationByNumber The input stream ended while parsing a number
- \value IllegalNumber The number is not well formed
- \value IllegalEscapeSequence An illegal escape sequence occurred in the input
- \value IllegalUTF8String An illegal UTF8 sequence occurred in the input
- \value UnterminatedString A string wasn't terminated with a quote
- \value MissingObject An object was expected but couldn't be found
- \value DeepNesting The JSON document is too deeply nested for the parser to parse it
- \value DocumentTooLarge The JSON document is too large for the parser to parse it
- \value GarbageAtEnd The parsed document contains additional garbage characters at the end
-
-*/
-
-/*!
- \variable QJsonParseError::error
-
- Contains the type of the parse error. Is equal to QJsonParseError::NoError if the document
- was parsed correctly.
-
- \sa ParseError, errorString()
-*/
-
-
-/*!
- \variable QJsonParseError::offset
-
- Contains the offset in the input string where the parse error occurred.
-
- \sa error, errorString()
-*/
-
-/*!
- Returns the human-readable message appropriate to the reported JSON parsing error.
-
- \sa error
- */
-QString QJsonParseError::errorString() const
-{
- const char *sz = "";
- switch (error) {
- case NoError:
- sz = JSONERR_OK;
- break;
- case UnterminatedObject:
- sz = JSONERR_UNTERM_OBJ;
- break;
- case MissingNameSeparator:
- sz = JSONERR_MISS_NSEP;
- break;
- case UnterminatedArray:
- sz = JSONERR_UNTERM_AR;
- break;
- case MissingValueSeparator:
- sz = JSONERR_MISS_VSEP;
- break;
- case IllegalValue:
- sz = JSONERR_ILLEGAL_VAL;
- break;
- case TerminationByNumber:
- sz = JSONERR_END_OF_NUM;
- break;
- case IllegalNumber:
- sz = JSONERR_ILLEGAL_NUM;
- break;
- case IllegalEscapeSequence:
- sz = JSONERR_STR_ESC_SEQ;
- break;
- case IllegalUTF8String:
- sz = JSONERR_STR_UTF8;
- break;
- case UnterminatedString:
- sz = JSONERR_UTERM_STR;
- break;
- case MissingObject:
- sz = JSONERR_MISS_OBJ;
- break;
- case DeepNesting:
- sz = JSONERR_DEEP_NEST;
- break;
- case DocumentTooLarge:
- sz = JSONERR_DOC_LARGE;
- break;
- case GarbageAtEnd:
- sz = JSONERR_GARBAGEEND;
- break;
- }
-#ifndef QT_BOOTSTRAPPED
- return QCoreApplication::translate("QJsonParseError", sz);
-#else
- return QLatin1String(sz);
-#endif
-}
-
-using namespace QJsonPrivate;
-
-Parser::Parser(const char *json, int length)
- : head(json), json(json), data(0), dataLength(0), current(0), nestingLevel(0), lastError(QJsonParseError::NoError)
-{
- end = json + length;
-}
-
-
-
-/*
-
-begin-array = ws %x5B ws ; [ left square bracket
-
-begin-object = ws %x7B ws ; { left curly bracket
-
-end-array = ws %x5D ws ; ] right square bracket
-
-end-object = ws %x7D ws ; } right curly bracket
-
-name-separator = ws %x3A ws ; : colon
-
-value-separator = ws %x2C ws ; , comma
-
-Insignificant whitespace is allowed before or after any of the six
-structural characters.
-
-ws = *(
- %x20 / ; Space
- %x09 / ; Horizontal tab
- %x0A / ; Line feed or New line
- %x0D ; Carriage return
- )
-
-*/
-
-enum {
- Space = 0x20,
- Tab = 0x09,
- LineFeed = 0x0a,
- Return = 0x0d,
- BeginArray = 0x5b,
- BeginObject = 0x7b,
- EndArray = 0x5d,
- EndObject = 0x7d,
- NameSeparator = 0x3a,
- ValueSeparator = 0x2c,
- Quote = 0x22
-};
-
-void Parser::eatBOM()
-{
- // eat UTF-8 byte order mark
- uchar utf8bom[3] = { 0xef, 0xbb, 0xbf };
- if (end - json > 3 &&
- (uchar)json[0] == utf8bom[0] &&
- (uchar)json[1] == utf8bom[1] &&
- (uchar)json[2] == utf8bom[2])
- json += 3;
-}
-
-bool Parser::eatSpace()
-{
- while (json < end) {
- if (*json > Space)
- break;
- if (*json != Space &&
- *json != Tab &&
- *json != LineFeed &&
- *json != Return)
- break;
- ++json;
- }
- return (json < end);
-}
-
-char Parser::nextToken()
-{
- if (!eatSpace())
- return 0;
- char token = *json++;
- switch (token) {
- case BeginArray:
- case BeginObject:
- case NameSeparator:
- case ValueSeparator:
- case EndArray:
- case EndObject:
- case Quote:
- break;
- default:
- token = 0;
- break;
- }
- return token;
-}
-
-/*
- JSON-text = object / array
-*/
-QJsonDocument Parser::parse(QJsonParseError *error)
-{
-#ifdef PARSER_DEBUG
- indent = 0;
- qDebug(">>>>> parser begin");
-#endif
- // allocate some space
- dataLength = qMax(end - json, (ptrdiff_t) 256);
- data = (char *)malloc(dataLength);
-
- // fill in Header data
- QJsonPrivate::Header *h = (QJsonPrivate::Header *)data;
- h->tag = QJsonDocument::BinaryFormatTag;
- h->version = 1u;
-
- current = sizeof(QJsonPrivate::Header);
-
- eatBOM();
- char token = nextToken();
-
- DEBUG << hex << (uint)token;
- if (token == BeginArray) {
- if (!parseArray())
- goto error;
- } else if (token == BeginObject) {
- if (!parseObject())
- goto error;
- } else {
- lastError = QJsonParseError::IllegalValue;
- goto error;
- }
-
- eatSpace();
- if (json < end) {
- lastError = QJsonParseError::GarbageAtEnd;
- goto error;
- }
-
- END;
- {
- if (error) {
- error->offset = 0;
- error->error = QJsonParseError::NoError;
- }
- QJsonPrivate::Data *d = new QJsonPrivate::Data(data, current);
- return QJsonDocument(d);
- }
-
-error:
-#ifdef PARSER_DEBUG
- qDebug(">>>>> parser error");
-#endif
- if (error) {
- error->offset = json - head;
- error->error = lastError;
- }
- free(data);
- return QJsonDocument();
-}
-
-
-void Parser::ParsedObject::insert(uint offset) {
- const QJsonPrivate::Entry *newEntry = reinterpret_cast<const QJsonPrivate::Entry *>(parser->data + objectPosition + offset);
- int min = 0;
- int n = offsets.size();
- while (n > 0) {
- int half = n >> 1;
- int middle = min + half;
- if (*entryAt(middle) >= *newEntry) {
- n = half;
- } else {
- min = middle + 1;
- n -= half + 1;
- }
- }
- if (min < offsets.size() && *entryAt(min) == *newEntry) {
- offsets[min] = offset;
- } else {
- offsets.insert(min, offset);
- }
-}
-
-/*
- object = begin-object [ member *( value-separator member ) ]
- end-object
-*/
-
-bool Parser::parseObject()
-{
- if (++nestingLevel > nestingLimit) {
- lastError = QJsonParseError::DeepNesting;
- return false;
- }
-
- int objectOffset = reserveSpace(sizeof(QJsonPrivate::Object));
- if (objectOffset < 0)
- return false;
- BEGIN << "parseObject pos=" << objectOffset << current << json;
-
- ParsedObject parsedObject(this, objectOffset);
-
- char token = nextToken();
- while (token == Quote) {
- int off = current - objectOffset;
- if (!parseMember(objectOffset))
- return false;
- parsedObject.insert(off);
- token = nextToken();
- if (token != ValueSeparator)
- break;
- token = nextToken();
- if (token == EndObject) {
- lastError = QJsonParseError::MissingObject;
- return false;
- }
- }
-
- DEBUG << "end token=" << token;
- if (token != EndObject) {
- lastError = QJsonParseError::UnterminatedObject;
- return false;
- }
-
- DEBUG << "numEntries" << parsedObject.offsets.size();
- int table = objectOffset;
- // finalize the object
- if (parsedObject.offsets.size()) {
- int tableSize = parsedObject.offsets.size()*sizeof(uint);
- table = reserveSpace(tableSize);
- if (table < 0)
- return false;
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- memcpy(data + table, parsedObject.offsets.constData(), tableSize);
-#else
- offset *o = (offset *)(data + table);
- for (int i = 0; i < parsedObject.offsets.size(); ++i)
- o[i] = parsedObject.offsets[i];
-
-#endif
- }
-
- QJsonPrivate::Object *o = (QJsonPrivate::Object *)(data + objectOffset);
- o->tableOffset = table - objectOffset;
- o->size = current - objectOffset;
- o->is_object = true;
- o->length = parsedObject.offsets.size();
-
- DEBUG << "current=" << current;
- END;
-
- --nestingLevel;
- return true;
-}
-
-/*
- member = string name-separator value
-*/
-bool Parser::parseMember(int baseOffset)
-{
- int entryOffset = reserveSpace(sizeof(QJsonPrivate::Entry));
- if (entryOffset < 0)
- return false;
- BEGIN << "parseMember pos=" << entryOffset;
-
- bool latin1;
- if (!parseString(&latin1))
- return false;
- char token = nextToken();
- if (token != NameSeparator) {
- lastError = QJsonParseError::MissingNameSeparator;
- return false;
- }
- if (!eatSpace()) {
- lastError = QJsonParseError::UnterminatedObject;
- return false;
- }
- QJsonPrivate::Value val;
- if (!parseValue(&val, baseOffset))
- return false;
-
- // finalize the entry
- QJsonPrivate::Entry *e = (QJsonPrivate::Entry *)(data + entryOffset);
- e->value = val;
- e->value.latinKey = latin1;
-
- END;
- return true;
-}
-
-namespace {
- struct ValueArray {
- static const int prealloc = 128;
- ValueArray() : data(stackValues), alloc(prealloc), size(0) {}
- ~ValueArray() { if (data != stackValues) free(data); }
-
- inline bool grow() {
- alloc *= 2;
- if (data == stackValues) {
- QJsonPrivate::Value *newValues = static_cast<QJsonPrivate::Value *>(malloc(alloc*sizeof(QJsonPrivate::Value)));
- if (!newValues)
- return false;
- memcpy(newValues, data, size*sizeof(QJsonPrivate::Value));
- data = newValues;
- } else {
- void *newValues = realloc(data, alloc * sizeof(QJsonPrivate::Value));
- if (!newValues)
- return false;
- data = static_cast<QJsonPrivate::Value *>(newValues);
- }
- return true;
- }
- bool append(const QJsonPrivate::Value &v) {
- if (alloc == size && !grow())
- return false;
- data[size] = v;
- ++size;
- return true;
- }
-
- QJsonPrivate::Value stackValues[prealloc];
- QJsonPrivate::Value *data;
- int alloc;
- int size;
- };
-}
-
-/*
- array = begin-array [ value *( value-separator value ) ] end-array
-*/
-bool Parser::parseArray()
-{
- BEGIN << "parseArray";
-
- if (++nestingLevel > nestingLimit) {
- lastError = QJsonParseError::DeepNesting;
- return false;
- }
-
- int arrayOffset = reserveSpace(sizeof(QJsonPrivate::Array));
- if (arrayOffset < 0)
- return false;
-
- ValueArray values;
-
- if (!eatSpace()) {
- lastError = QJsonParseError::UnterminatedArray;
- return false;
- }
- if (*json == EndArray) {
- nextToken();
- } else {
- while (1) {
- if (!eatSpace()) {
- lastError = QJsonParseError::UnterminatedArray;
- return false;
- }
- QJsonPrivate::Value val;
- if (!parseValue(&val, arrayOffset))
- return false;
- if (!values.append(val)) {
- lastError = QJsonParseError::DocumentTooLarge;
- return false;
- }
- char token = nextToken();
- if (token == EndArray)
- break;
- else if (token != ValueSeparator) {
- if (!eatSpace())
- lastError = QJsonParseError::UnterminatedArray;
- else
- lastError = QJsonParseError::MissingValueSeparator;
- return false;
- }
- }
- }
-
- DEBUG << "size =" << values.size;
- int table = arrayOffset;
- // finalize the object
- if (values.size) {
- int tableSize = values.size*sizeof(QJsonPrivate::Value);
- table = reserveSpace(tableSize);
- if (table < 0)
- return false;
- memcpy(data + table, values.data, tableSize);
- }
-
- QJsonPrivate::Array *a = (QJsonPrivate::Array *)(data + arrayOffset);
- a->tableOffset = table - arrayOffset;
- a->size = current - arrayOffset;
- a->is_object = false;
- a->length = values.size;
-
- DEBUG << "current=" << current;
- END;
-
- --nestingLevel;
- return true;
-}
-
-/*
-value = false / null / true / object / array / number / string
-
-*/
-
-bool Parser::parseValue(QJsonPrivate::Value *val, int baseOffset)
-{
- BEGIN << "parse Value" << json;
- val->_dummy = 0;
-
- switch (*json++) {
- case 'n':
- if (end - json < 4) {
- lastError = QJsonParseError::IllegalValue;
- return false;
- }
- if (*json++ == 'u' &&
- *json++ == 'l' &&
- *json++ == 'l') {
- val->type = QJsonValue::Null;
- DEBUG << "value: null";
- END;
- return true;
- }
- lastError = QJsonParseError::IllegalValue;
- return false;
- case 't':
- if (end - json < 4) {
- lastError = QJsonParseError::IllegalValue;
- return false;
- }
- if (*json++ == 'r' &&
- *json++ == 'u' &&
- *json++ == 'e') {
- val->type = QJsonValue::Bool;
- val->value = true;
- DEBUG << "value: true";
- END;
- return true;
- }
- lastError = QJsonParseError::IllegalValue;
- return false;
- case 'f':
- if (end - json < 5) {
- lastError = QJsonParseError::IllegalValue;
- return false;
- }
- if (*json++ == 'a' &&
- *json++ == 'l' &&
- *json++ == 's' &&
- *json++ == 'e') {
- val->type = QJsonValue::Bool;
- val->value = false;
- DEBUG << "value: false";
- END;
- return true;
- }
- lastError = QJsonParseError::IllegalValue;
- return false;
- case Quote: {
- val->type = QJsonValue::String;
- if (current - baseOffset >= Value::MaxSize) {
- lastError = QJsonParseError::DocumentTooLarge;
- return false;
- }
- val->value = current - baseOffset;
- bool latin1;
- if (!parseString(&latin1))
- return false;
- val->latinOrIntValue = latin1;
- DEBUG << "value: string";
- END;
- return true;
- }
- case BeginArray:
- val->type = QJsonValue::Array;
- if (current - baseOffset >= Value::MaxSize) {
- lastError = QJsonParseError::DocumentTooLarge;
- return false;
- }
- val->value = current - baseOffset;
- if (!parseArray())
- return false;
- DEBUG << "value: array";
- END;
- return true;
- case BeginObject:
- val->type = QJsonValue::Object;
- if (current - baseOffset >= Value::MaxSize) {
- lastError = QJsonParseError::DocumentTooLarge;
- return false;
- }
- val->value = current - baseOffset;
- if (!parseObject())
- return false;
- DEBUG << "value: object";
- END;
- return true;
- case ValueSeparator:
- // Essentially missing value, but after a colon, not after a comma
- // like the other MissingObject errors.
- lastError = QJsonParseError::IllegalValue;
- return false;
- case EndObject:
- case EndArray:
- lastError = QJsonParseError::MissingObject;
- return false;
- default:
- --json;
- if (!parseNumber(val, baseOffset))
- return false;
- DEBUG << "value: number";
- END;
- }
-
- return true;
-}
-
-
-
-
-
-/*
- number = [ minus ] int [ frac ] [ exp ]
- decimal-point = %x2E ; .
- digit1-9 = %x31-39 ; 1-9
- e = %x65 / %x45 ; e E
- exp = e [ minus / plus ] 1*DIGIT
- frac = decimal-point 1*DIGIT
- int = zero / ( digit1-9 *DIGIT )
- minus = %x2D ; -
- plus = %x2B ; +
- zero = %x30 ; 0
-
-*/
-
-bool Parser::parseNumber(QJsonPrivate::Value *val, int baseOffset)
-{
- BEGIN << "parseNumber" << json;
- val->type = QJsonValue::Double;
-
- const char *start = json;
- bool isInt = true;
-
- // minus
- if (json < end && *json == '-')
- ++json;
-
- // int = zero / ( digit1-9 *DIGIT )
- if (json < end && *json == '0') {
- ++json;
- } else {
- while (json < end && *json >= '0' && *json <= '9')
- ++json;
- }
-
- // frac = decimal-point 1*DIGIT
- if (json < end && *json == '.') {
- isInt = false;
- ++json;
- while (json < end && *json >= '0' && *json <= '9')
- ++json;
- }
-
- // exp = e [ minus / plus ] 1*DIGIT
- if (json < end && (*json == 'e' || *json == 'E')) {
- isInt = false;
- ++json;
- if (json < end && (*json == '-' || *json == '+'))
- ++json;
- while (json < end && *json >= '0' && *json <= '9')
- ++json;
- }
-
- if (json >= end) {
- lastError = QJsonParseError::TerminationByNumber;
- return false;
- }
-
- QByteArray number(start, json - start);
- DEBUG << "numberstring" << number;
-
- if (isInt) {
- bool ok;
- int n = number.toInt(&ok);
- if (ok && n < (1<<25) && n > -(1<<25)) {
- val->int_value = n;
- val->latinOrIntValue = true;
- END;
- return true;
- }
- }
-
- bool ok;
- union {
- quint64 ui;
- double d;
- };
- d = number.toDouble(&ok);
-
- if (!ok) {
- lastError = QJsonParseError::IllegalNumber;
- return false;
- }
-
- int pos = reserveSpace(sizeof(double));
- if (pos < 0)
- return false;
- qToLittleEndian(ui, data + pos);
- if (current - baseOffset >= Value::MaxSize) {
- lastError = QJsonParseError::DocumentTooLarge;
- return false;
- }
- val->value = pos - baseOffset;
- val->latinOrIntValue = false;
-
- END;
- return true;
-}
-
-/*
-
- string = quotation-mark *char quotation-mark
-
- char = unescaped /
- escape (
- %x22 / ; " quotation mark U+0022
- %x5C / ; \ reverse solidus U+005C
- %x2F / ; / solidus U+002F
- %x62 / ; b backspace U+0008
- %x66 / ; f form feed U+000C
- %x6E / ; n line feed U+000A
- %x72 / ; r carriage return U+000D
- %x74 / ; t tab U+0009
- %x75 4HEXDIG ) ; uXXXX U+XXXX
-
- escape = %x5C ; \
-
- quotation-mark = %x22 ; "
-
- unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
- */
-static inline bool addHexDigit(char digit, uint *result)
-{
- *result <<= 4;
- if (digit >= '0' && digit <= '9')
- *result |= (digit - '0');
- else if (digit >= 'a' && digit <= 'f')
- *result |= (digit - 'a') + 10;
- else if (digit >= 'A' && digit <= 'F')
- *result |= (digit - 'A') + 10;
- else
- return false;
- return true;
-}
-
-static inline bool scanEscapeSequence(const char *&json, const char *end, uint *ch)
-{
- ++json;
- if (json >= end)
- return false;
-
- DEBUG << "scan escape" << (char)*json;
- uint escaped = *json++;
- switch (escaped) {
- case '"':
- *ch = '"'; break;
- case '\\':
- *ch = '\\'; break;
- case '/':
- *ch = '/'; break;
- case 'b':
- *ch = 0x8; break;
- case 'f':
- *ch = 0xc; break;
- case 'n':
- *ch = 0xa; break;
- case 'r':
- *ch = 0xd; break;
- case 't':
- *ch = 0x9; break;
- case 'u': {
- *ch = 0;
- if (json > end - 4)
- return false;
- for (int i = 0; i < 4; ++i) {
- if (!addHexDigit(*json, ch))
- return false;
- ++json;
- }
- return true;
- }
- default:
- // this is not as strict as one could be, but allows for more Json files
- // to be parsed correctly.
- *ch = escaped;
- return true;
- }
- return true;
-}
-
-static inline bool scanUtf8Char(const char *&json, const char *end, uint *result)
-{
- const uchar *&src = reinterpret_cast<const uchar *&>(json);
- const uchar *uend = reinterpret_cast<const uchar *>(end);
- uchar b = *src++;
- int res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, result, src, uend);
- if (res < 0) {
- // decoding error, backtrack the character we read above
- --json;
- return false;
- }
-
- return true;
-}
-
-bool Parser::parseString(bool *latin1)
-{
- *latin1 = true;
-
- const char *start = json;
- int outStart = current;
-
- // try to write out a latin1 string
-
- int stringPos = reserveSpace(2);
- if (stringPos < 0)
- return false;
-
- BEGIN << "parse string stringPos=" << stringPos << json;
- while (json < end) {
- uint ch = 0;
- if (*json == '"')
- break;
- else if (*json == '\\') {
- if (!scanEscapeSequence(json, end, &ch)) {
- lastError = QJsonParseError::IllegalEscapeSequence;
- return false;
- }
- } else {
- if (!scanUtf8Char(json, end, &ch)) {
- lastError = QJsonParseError::IllegalUTF8String;
- return false;
- }
- }
- // 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)
- if (ch > 0xff || json - start >= 0x8000) {
- *latin1 = false;
- break;
- }
- int pos = reserveSpace(1);
- if (pos < 0)
- return false;
- DEBUG << " " << ch << (char)ch;
- data[pos] = (uchar)ch;
- }
- ++json;
- DEBUG << "end of string";
- if (json >= end) {
- lastError = QJsonParseError::UnterminatedString;
- return false;
- }
-
- // no unicode string, we are done
- if (*latin1) {
- // write string length
- *(QJsonPrivate::qle_ushort *)(data + stringPos) = ushort(current - outStart - sizeof(ushort));
- int pos = reserveSpace((4 - current) & 3);
- if (pos < 0)
- return false;
- while (pos & 3)
- data[pos++] = 0;
- END;
- return true;
- }
-
- *latin1 = false;
- DEBUG << "not latin";
-
- json = start;
- current = outStart + sizeof(int);
-
- while (json < end) {
- uint ch = 0;
- if (*json == '"')
- break;
- else if (*json == '\\') {
- if (!scanEscapeSequence(json, end, &ch)) {
- lastError = QJsonParseError::IllegalEscapeSequence;
- return false;
- }
- } else {
- if (!scanUtf8Char(json, end, &ch)) {
- lastError = QJsonParseError::IllegalUTF8String;
- return false;
- }
- }
- if (QChar::requiresSurrogates(ch)) {
- int pos = reserveSpace(4);
- if (pos < 0)
- return false;
- *(QJsonPrivate::qle_ushort *)(data + pos) = QChar::highSurrogate(ch);
- *(QJsonPrivate::qle_ushort *)(data + pos + 2) = QChar::lowSurrogate(ch);
- } else {
- int pos = reserveSpace(2);
- if (pos < 0)
- return false;
- *(QJsonPrivate::qle_ushort *)(data + pos) = (ushort)ch;
- }
- }
- ++json;
-
- if (json >= end) {
- lastError = QJsonParseError::UnterminatedString;
- return false;
- }
-
- // write string length
- *(QJsonPrivate::qle_int *)(data + stringPos) = (current - outStart - sizeof(int))/2;
- int pos = reserveSpace((4 - current) & 3);
- if (pos < 0)
- return false;
- while (pos & 3)
- data[pos++] = 0;
- END;
- return true;
-}
-
-QT_END_NAMESPACE