diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2017-12-12 18:32:19 -0800 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2018-01-26 20:59:50 +0000 |
commit | a6b697ca13945a174cff9f3e9b1af1cf61c0bea5 (patch) | |
tree | 78d5fad97ff8e89f079df29cc5a75b4e7197bfc7 /src/corelib/json/qjsonparser.cpp | |
parent | 657894624521b580f59ff5f58b9c0e9be159dc1c (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.cpp | 1027 |
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 |