Import json support from playground/qtbinaryjson
This imports the JSON support for Qt 5 from playground/qtbinaryjson. It adds a fast, fully compliant json parser, a convenient C++ API, conversion to and from QVariants and a binary format for JSON that is extremely fast to use together with the C++ API. Change-Id: If9e3a21a4241d388d0abaa446b6824f9cc6edb1c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
4b8ceb41ae
commit
37a7b035f8
118
doc/src/corelib/json.qdoc
Normal file
118
doc/src/corelib/json.qdoc
Normal file
@ -0,0 +1,118 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:FDL$
|
||||
** GNU Free Documentation License
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms
|
||||
** and conditions contained in a signed written agreement between you
|
||||
** and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*!
|
||||
\group json
|
||||
\title JSON Classes
|
||||
*/
|
||||
|
||||
/*!
|
||||
\page json.html
|
||||
\title JSON Support in Qt
|
||||
\ingroup qt-basic-concepts
|
||||
\brief An overview over the JSON support in Qt.
|
||||
|
||||
\ingroup frameworks-technologies
|
||||
|
||||
\keyword JSON
|
||||
|
||||
Qt provides support for dealing with JSON data. JSON is a
|
||||
format to encode object data derived from Javascript, but
|
||||
now widely used as a data exchange format on the internet.
|
||||
|
||||
The JSON support in Qt provides an easy to use C++ API to parse,
|
||||
modify and save JSON data. It also contains support for saving this
|
||||
data in a binary format that is directly mmap'able and very fast to
|
||||
access.
|
||||
|
||||
More details about the JSON data format can be found at \link json.org
|
||||
and in \l{http://tools.ietf.org/html/rfc4627}{RFC-4627}.
|
||||
|
||||
\tableofcontents
|
||||
|
||||
\section1 Overview
|
||||
|
||||
JSON is a format to store structured data. It has 6 basic data types:
|
||||
|
||||
\list
|
||||
\o bool
|
||||
\o double
|
||||
\o string
|
||||
\o array
|
||||
\o object
|
||||
\o null
|
||||
\endlist
|
||||
|
||||
Any value can be any of the above type. A boolean value is represented by the
|
||||
strings true or false in JSON. JSON doesn't explicitly specify the valid range
|
||||
for numbers, but the support in Qt is limited to the valid range and precision of
|
||||
doubles. A string can be any valid unicode string. An array is a list of values, and an
|
||||
object is a dictionary of key/value pairs. All keys in an object are strings, and
|
||||
an object cannot contain any duplicated keys.
|
||||
|
||||
The text representation, of JSON encloses arrays in square brackets ([ ... ]) and
|
||||
objects in curly brackets ({ ... }). The different entries in arrays and objects
|
||||
are separated by commas. The separator between keys and values in an object is a
|
||||
colon (:).
|
||||
|
||||
A simple JSON document encoding a person, its age, address and phone numbers could
|
||||
look like:
|
||||
|
||||
\code
|
||||
{
|
||||
"FirstName": "John",
|
||||
"LastName": "Doe",
|
||||
"Age": 43,
|
||||
"Address": {
|
||||
"Street": "Downing Street 10",
|
||||
"City": "London",
|
||||
"Country": "Great Britain"
|
||||
},
|
||||
"Phone numbers": [
|
||||
"+44 1234567",
|
||||
"+44 2345678"
|
||||
]
|
||||
}
|
||||
\endcode
|
||||
|
||||
The above example consists of an object with 5 key/value pairs. Two of the values are strings,
|
||||
one is a number, one is another object and the last one an array.
|
||||
|
||||
A valid JSON document is either an array or an object, so a document always starts
|
||||
with a square or curly bracket.
|
||||
|
||||
The JSON support in Qt consists of a set of 4 classes.
|
||||
|
||||
|
||||
\section1 The JSON Classes
|
||||
|
||||
The JSON support in Qt consists of these classes:
|
||||
|
||||
\annotatedlist json
|
||||
|
||||
All JSON classes are value based, implicitly shared classes.
|
||||
*/
|
@ -24,6 +24,7 @@ include(thread/thread.pri)
|
||||
include(tools/tools.pri)
|
||||
include(io/io.pri)
|
||||
include(itemmodels/itemmodels.pri)
|
||||
include(json/json.pri)
|
||||
include(plugin/plugin.pri)
|
||||
include(kernel/kernel.pri)
|
||||
include(codecs/codecs.pri)
|
||||
|
17
src/corelib/json/json.pri
Normal file
17
src/corelib/json/json.pri
Normal file
@ -0,0 +1,17 @@
|
||||
HEADERS += \
|
||||
json/qjson_p.h \
|
||||
json/qjsondocument.h \
|
||||
json/qjsonobject.h \
|
||||
json/qjsonvalue.h \
|
||||
json/qjsonarray.h \
|
||||
json/qjsonwriter_p.h \
|
||||
json/qjsonparser_p.h
|
||||
|
||||
SOURCES += \
|
||||
json/qjson.cpp \
|
||||
json/qjsondocument.cpp \
|
||||
json/qjsonobject.cpp \
|
||||
json/qjsonarray.cpp \
|
||||
json/qjsonvalue.cpp \
|
||||
json/qjsonwriter.cpp \
|
||||
json/qjsonparser.cpp
|
427
src/corelib/json/qjson.cpp
Normal file
427
src/corelib/json/qjson.cpp
Normal file
@ -0,0 +1,427 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qjson_p.h"
|
||||
#include <qalgorithms.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QJsonPrivate
|
||||
{
|
||||
|
||||
#ifdef Q_LITTLE_ENDIAN
|
||||
#define Q_TO_LITTLE_ENDIAN(x) (x)
|
||||
#else
|
||||
#define Q_TO_LITTLE_ENDIAN(x) ( ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24) )
|
||||
#endif
|
||||
|
||||
static const Base emptyArray = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { 0 }, { 0 } };
|
||||
static const Base emptyObject = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { 0 }, { 0 } };
|
||||
|
||||
|
||||
void Data::compact()
|
||||
{
|
||||
Q_ASSERT(sizeof(Value) == sizeof(offset));
|
||||
|
||||
if (!compactionCounter)
|
||||
return;
|
||||
|
||||
Base *base = header->root();
|
||||
int reserve = 0;
|
||||
if (base->is_object) {
|
||||
Object *o = static_cast<Object *>(base);
|
||||
for (int i = 0; i < (int)o->length; ++i)
|
||||
reserve += o->entryAt(i)->usedStorage(o);
|
||||
} else {
|
||||
Array *a = static_cast<Array *>(base);
|
||||
for (int i = 0; i < (int)a->length; ++i)
|
||||
reserve += (*a)[i].usedStorage(a);
|
||||
}
|
||||
|
||||
int size = sizeof(Base) + reserve + base->length*sizeof(offset);
|
||||
int alloc = sizeof(Header) + size;
|
||||
Header *h = (Header *) malloc(alloc);
|
||||
h->tag = QJsonDocument::BinaryFormatTag;
|
||||
h->version = 1;
|
||||
Base *b = h->root();
|
||||
b->size = size;
|
||||
b->is_object = header->root()->is_object;
|
||||
b->length = base->length;
|
||||
b->tableOffset = reserve + sizeof(Array);
|
||||
|
||||
int offset = sizeof(Base);
|
||||
if (b->is_object) {
|
||||
Object *o = static_cast<Object *>(base);
|
||||
Object *no = static_cast<Object *>(b);
|
||||
|
||||
for (int i = 0; i < (int)o->length; ++i) {
|
||||
no->table()[i] = offset;
|
||||
|
||||
const Entry *e = o->entryAt(i);
|
||||
Entry *ne = no->entryAt(i);
|
||||
int s = e->size();
|
||||
memcpy(ne, e, s);
|
||||
offset += s;
|
||||
int dataSize = e->value.usedStorage(o);
|
||||
if (dataSize) {
|
||||
memcpy((char *)no + offset, e->value.data(o), dataSize);
|
||||
ne->value.value = offset;
|
||||
offset += dataSize;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Array *a = static_cast<Array *>(base);
|
||||
Array *na = static_cast<Array *>(b);
|
||||
|
||||
for (int i = 0; i < (int)a->length; ++i) {
|
||||
const Value &v = (*a)[i];
|
||||
Value &nv = (*na)[i];
|
||||
nv = v;
|
||||
int dataSize = v.usedStorage(a);
|
||||
if (dataSize) {
|
||||
memcpy((char *)na + offset, v.data(a), dataSize);
|
||||
nv.value = offset;
|
||||
offset += dataSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
Q_ASSERT(offset == (int)b->tableOffset);
|
||||
|
||||
free(header);
|
||||
header = h;
|
||||
alloc = alloc;
|
||||
compactionCounter = 0;
|
||||
}
|
||||
|
||||
bool Data::valid() const
|
||||
{
|
||||
if (header->tag != QJsonDocument::BinaryFormatTag || header->version != 1u)
|
||||
return false;
|
||||
|
||||
bool res = false;
|
||||
if (header->root()->is_object)
|
||||
res = static_cast<Object *>(header->root())->isValid();
|
||||
else
|
||||
res = static_cast<Array *>(header->root())->isValid();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int Base::reserveSpace(uint dataSize, int posInTable, uint numItems, bool replace)
|
||||
{
|
||||
Q_ASSERT(posInTable >= 0 && posInTable <= (int)length);
|
||||
|
||||
offset off = tableOffset;
|
||||
// move table to new position
|
||||
if (replace) {
|
||||
memmove((char *)(table()) + dataSize, table(), length*sizeof(offset));
|
||||
} else {
|
||||
memmove((char *)(table() + posInTable + numItems) + dataSize, table() + posInTable, (length - posInTable)*sizeof(offset));
|
||||
memmove((char *)(table()) + dataSize, table(), posInTable*sizeof(offset));
|
||||
}
|
||||
tableOffset += dataSize;
|
||||
for (int i = 0; i < (int)numItems; ++i)
|
||||
table()[posInTable + i] = off;
|
||||
size += dataSize;
|
||||
if (!replace) {
|
||||
length += numItems;
|
||||
size += numItems * sizeof(offset);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
void Base::removeItems(int pos, int numItems)
|
||||
{
|
||||
Q_ASSERT(pos >= 0 && pos <= (int)length);
|
||||
if (pos + numItems < (int)length)
|
||||
memmove(table() + pos, table() + pos + numItems, (length - pos - numItems)*sizeof(offset));
|
||||
length -= numItems;
|
||||
}
|
||||
|
||||
int Object::indexOf(const QString &key, bool *exists)
|
||||
{
|
||||
int min = 0;
|
||||
int n = length;
|
||||
while (n > 0) {
|
||||
int half = n >> 1;
|
||||
int middle = min + half;
|
||||
if (*entryAt(middle) >= key) {
|
||||
n = half;
|
||||
} else {
|
||||
min = middle + 1;
|
||||
n -= half + 1;
|
||||
}
|
||||
}
|
||||
if (min < (int)length && *entryAt(min) == key) {
|
||||
*exists = true;
|
||||
return min;
|
||||
}
|
||||
*exists = false;
|
||||
return min;
|
||||
}
|
||||
|
||||
bool Object::isValid() const
|
||||
{
|
||||
if (tableOffset + length*sizeof(offset) > size)
|
||||
return false;
|
||||
|
||||
for (uint i = 0; i < length; ++i) {
|
||||
offset entryOffset = table()[i];
|
||||
if (entryOffset + sizeof(Entry) >= tableOffset)
|
||||
return false;
|
||||
Entry *e = entryAt(i);
|
||||
int s = e->size();
|
||||
if (table()[i] + s > tableOffset)
|
||||
return false;
|
||||
if (!e->value.isValid(this))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Array::isValid() const
|
||||
{
|
||||
if (tableOffset + length*sizeof(offset) > size)
|
||||
return false;
|
||||
|
||||
for (uint i = 0; i < length; ++i) {
|
||||
if (!at(i).isValid(this))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Entry::operator ==(const QString &key) const
|
||||
{
|
||||
if (value.latinKey)
|
||||
return (shallowLatin1Key() == key);
|
||||
else
|
||||
return (shallowKey() == key);
|
||||
}
|
||||
|
||||
bool Entry::operator >=(const QString &key) const
|
||||
{
|
||||
if (value.latinKey)
|
||||
return (shallowLatin1Key() >= key);
|
||||
else
|
||||
return (shallowKey() >= key);
|
||||
}
|
||||
|
||||
bool Entry::operator ==(const Entry &other) const
|
||||
{
|
||||
if (value.latinKey) {
|
||||
if (other.value.latinKey)
|
||||
return shallowLatin1Key() == other.shallowLatin1Key();
|
||||
return shallowLatin1Key() == other.shallowKey();
|
||||
} else if (other.value.latinKey) {
|
||||
return shallowKey() == other.shallowLatin1Key();
|
||||
}
|
||||
return shallowKey() == other.shallowKey();
|
||||
}
|
||||
|
||||
bool Entry::operator >=(const Entry &other) const
|
||||
{
|
||||
if (value.latinKey) {
|
||||
if (other.value.latinKey)
|
||||
return shallowLatin1Key() >= other.shallowLatin1Key();
|
||||
return shallowLatin1Key() >= other.shallowKey();
|
||||
} else if (other.value.latinKey) {
|
||||
return shallowKey() >= other.shallowLatin1Key();
|
||||
}
|
||||
return shallowKey() >= other.shallowKey();
|
||||
}
|
||||
|
||||
|
||||
int Value::usedStorage(const Base *b) const
|
||||
{
|
||||
int s = 0;
|
||||
switch (type) {
|
||||
case QJsonValue::Double:
|
||||
if (latinOrIntValue)
|
||||
break;
|
||||
s = sizeof(double);
|
||||
break;
|
||||
case QJsonValue::String: {
|
||||
char *d = data(b);
|
||||
if (latinOrIntValue)
|
||||
s = sizeof(ushort) + *(ushort *)d;
|
||||
else
|
||||
s = sizeof(int) + sizeof(ushort)*(*(int *)d);
|
||||
break;
|
||||
}
|
||||
case QJsonValue::Array:
|
||||
case QJsonValue::Object:
|
||||
s = base(b)->size;
|
||||
break;
|
||||
case QJsonValue::Null:
|
||||
case QJsonValue::Bool:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return alignedSize(s);
|
||||
}
|
||||
|
||||
bool Value::isValid(const Base *b) const
|
||||
{
|
||||
int offset = 0;
|
||||
switch (type) {
|
||||
case QJsonValue::Double:
|
||||
if (latinOrIntValue)
|
||||
break;
|
||||
// fall through
|
||||
case QJsonValue::String:
|
||||
case QJsonValue::Array:
|
||||
case QJsonValue::Object:
|
||||
offset = value;
|
||||
break;
|
||||
case QJsonValue::Null:
|
||||
case QJsonValue::Bool:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!offset)
|
||||
return true;
|
||||
if (offset + sizeof(uint) > b->tableOffset)
|
||||
return false;
|
||||
|
||||
int s = usedStorage(b);
|
||||
if (!s)
|
||||
return true;
|
||||
if (s < 0 || offset + s > (int)b->tableOffset)
|
||||
return false;
|
||||
if (type == QJsonValue::Array)
|
||||
return static_cast<Array *>(base(b))->isValid();
|
||||
if (type == QJsonValue::Object)
|
||||
return static_cast<Object *>(base(b))->isValid();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
int Value::requiredStorage(const QJsonValue &v, bool *compressed)
|
||||
{
|
||||
*compressed = false;
|
||||
switch (v.t) {
|
||||
case QJsonValue::Double:
|
||||
if (QJsonPrivate::compressedNumber(v.dbl) != INT_MAX) {
|
||||
*compressed = true;
|
||||
return 0;
|
||||
}
|
||||
return sizeof(double);
|
||||
case QJsonValue::String: {
|
||||
QString s = v.toString();
|
||||
*compressed = QJsonPrivate::useCompressed(s);
|
||||
return QJsonPrivate::qStringSize(s, *compressed);
|
||||
}
|
||||
case QJsonValue::Array:
|
||||
case QJsonValue::Object:
|
||||
return v.base ? v.base->size : sizeof(QJsonPrivate::Base);
|
||||
case QJsonValue::Undefined:
|
||||
case QJsonValue::Null:
|
||||
case QJsonValue::Bool:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
uint Value::valueToStore(const QJsonValue &v, uint offset)
|
||||
{
|
||||
switch (v.t) {
|
||||
case QJsonValue::Undefined:
|
||||
case QJsonValue::Null:
|
||||
break;
|
||||
case QJsonValue::Bool:
|
||||
return v.b;
|
||||
case QJsonValue::Double: {
|
||||
int c = QJsonPrivate::compressedNumber(v.dbl);
|
||||
if (c != INT_MAX)
|
||||
return c;
|
||||
}
|
||||
// fall through
|
||||
case QJsonValue::String:
|
||||
case QJsonValue::Array:
|
||||
case QJsonValue::Object:
|
||||
return offset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void Value::copyData(const QJsonValue &v, char *dest, bool compressed)
|
||||
{
|
||||
switch (v.t) {
|
||||
case QJsonValue::Double:
|
||||
if (!compressed) {
|
||||
qToLittleEndian(v.ui, (uchar *)dest);
|
||||
}
|
||||
break;
|
||||
case QJsonValue::String: {
|
||||
QString str = v.toString();
|
||||
QJsonPrivate::copyString(dest, str, compressed);
|
||||
break;
|
||||
}
|
||||
case QJsonValue::Array:
|
||||
case QJsonValue::Object: {
|
||||
const QJsonPrivate::Base *b = v.base;
|
||||
if (!b)
|
||||
b = (v.t == QJsonValue::Array ? &emptyArray : &emptyObject);
|
||||
memcpy(dest, b, b->size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QJsonPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
760
src/corelib/json/qjson_p.h
Normal file
760
src/corelib/json/qjson_p.h
Normal file
@ -0,0 +1,760 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QJSON_P_H
|
||||
#define QJSON_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <qjsonobject.h>
|
||||
#include <qjsonvalue.h>
|
||||
#include <qjsondocument.h>
|
||||
#include <qjsonarray.h>
|
||||
#include <qatomic.h>
|
||||
#include <qstring.h>
|
||||
#include <qendian.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*
|
||||
This defines a binary data structure for Json data. The data structure is optimised for fast reading
|
||||
and minimum allocations. The whole data structure can be mmap'ed and used directly.
|
||||
|
||||
In most cases the binary structure is not as space efficient as a utf8 encoded text representation, but
|
||||
much faster to access.
|
||||
|
||||
The size requirements are:
|
||||
|
||||
String:
|
||||
Latin1 data: 2 bytes header + string.length()
|
||||
Full Unicode: 4 bytes header + 2*(string.length())
|
||||
|
||||
Values: 4 bytes + size of data (size can be 0 for some data)
|
||||
bool: 0 bytes
|
||||
double: 8 bytes (0 if integer with less than 27bits)
|
||||
string: see above
|
||||
array: size of array
|
||||
object: size of object
|
||||
Array: 12 bytes + 4*length + size of Value data
|
||||
Object: 12 bytes + 8*length + size of Key Strings + size of Value data
|
||||
|
||||
For an example such as
|
||||
|
||||
{ // object: 12 + 5*8 = 52
|
||||
"firstName": "John", // key 12, value 8 = 20
|
||||
"lastName" : "Smith", // key 12, value 8 = 20
|
||||
"age" : 25, // key 8, value 0 = 8
|
||||
"address" : // key 12, object below = 140
|
||||
{ // object: 12 + 4*8
|
||||
"streetAddress": "21 2nd Street", // key 16, value 16
|
||||
"city" : "New York", // key 8, value 12
|
||||
"state" : "NY", // key 8, value 4
|
||||
"postalCode" : "10021" // key 12, value 8
|
||||
}, // object total: 128
|
||||
"phoneNumber": // key: 16, value array below = 172
|
||||
[ // array: 12 + 2*4 + values below: 156
|
||||
{ // object 12 + 2*8
|
||||
"type" : "home", // key 8, value 8
|
||||
"number": "212 555-1234" // key 8, value 16
|
||||
}, // object total: 68
|
||||
{ // object 12 + 2*8
|
||||
"type" : "fax", // key 8, value 8
|
||||
"number": "646 555-4567" // key 8, value 16
|
||||
} // object total: 68
|
||||
] // array total: 156
|
||||
} // great total: 412 bytes
|
||||
|
||||
The uncompressed text file used roughly 500 bytes, so in this case we end up using about
|
||||
the same space as the text representation.
|
||||
|
||||
Other measurements have shown a slightly bigger binary size than a compact text
|
||||
representation where all possible whitespace was stripped out.
|
||||
*/
|
||||
namespace QJsonPrivate {
|
||||
|
||||
class Array;
|
||||
class Object;
|
||||
class Value;
|
||||
class Entry;
|
||||
|
||||
template<typename T>
|
||||
class q_littleendian
|
||||
{
|
||||
public:
|
||||
T val;
|
||||
|
||||
q_littleendian &operator =(T i) { val = qToLittleEndian(i); return *this; }
|
||||
operator T() const { return qFromLittleEndian(val); }
|
||||
|
||||
bool operator ==(T i) { return qFromLittleEndian(val) == i; }
|
||||
bool operator !=(T i) { return qFromLittleEndian(val) != i; }
|
||||
bool operator ==(q_littleendian<T> i) { return val == i.val; }
|
||||
bool operator !=(q_littleendian<T> i) { return val != i.val; }
|
||||
bool operator <(T i) { return qFromLittleEndian(val) < i; }
|
||||
bool operator >(T i) { return qFromLittleEndian(val) > i; }
|
||||
bool operator <=(T i) { return qFromLittleEndian(val) <= i; }
|
||||
bool operator >=(T i) { return qFromLittleEndian(val) >= i; }
|
||||
q_littleendian &operator +=(T i) {
|
||||
val = qToLittleEndian(qFromLittleEndian(val) + i);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
typedef q_littleendian<short> qle_short;
|
||||
typedef q_littleendian<unsigned short> qle_ushort;
|
||||
typedef q_littleendian<int> qle_int;
|
||||
typedef q_littleendian<unsigned int> qle_uint;
|
||||
|
||||
template<int pos, int width>
|
||||
class qle_bitfield
|
||||
{
|
||||
public:
|
||||
uint val;
|
||||
|
||||
enum {
|
||||
mask = ((1u << width) - 1) << pos
|
||||
};
|
||||
|
||||
void operator =(uint t) {
|
||||
uint i = qFromLittleEndian(val);
|
||||
i &= ~mask;
|
||||
i |= t << pos;
|
||||
val = qToLittleEndian(i);
|
||||
}
|
||||
operator uint() const {
|
||||
uint t = qFromLittleEndian(val);
|
||||
t &= mask;
|
||||
t >>= pos;
|
||||
return t;
|
||||
}
|
||||
bool operator !() const {
|
||||
return !operator uint();
|
||||
}
|
||||
|
||||
bool operator ==(uint t) { return uint(*this) == t; }
|
||||
bool operator !=(uint t) { return uint(*this) != t; }
|
||||
bool operator <(uint t) { return uint(*this) < t; }
|
||||
bool operator >(uint t) { return uint(*this) > t; }
|
||||
bool operator <=(uint t) { return uint(*this) <= t; }
|
||||
bool operator >=(uint t) { return uint(*this) >= t; }
|
||||
qle_bitfield &operator +=(uint i) {
|
||||
*this = (uint(*this) + i);
|
||||
return *this;
|
||||
}
|
||||
qle_bitfield &operator -=(uint i) {
|
||||
*this = (uint(*this) - i);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<int pos, int width>
|
||||
class qle_signedbitfield
|
||||
{
|
||||
public:
|
||||
uint val;
|
||||
|
||||
enum {
|
||||
mask = ((1u << width) - 1) << pos
|
||||
};
|
||||
|
||||
void operator =(int t) {
|
||||
uint i = qFromLittleEndian(val);
|
||||
i &= ~mask;
|
||||
i |= t << pos;
|
||||
val = qToLittleEndian(i);
|
||||
}
|
||||
operator int() const {
|
||||
uint i = qFromLittleEndian(val);
|
||||
i <<= 32 - width - pos;
|
||||
int t = (int) i;
|
||||
t >>= pos;
|
||||
return t;
|
||||
}
|
||||
bool operator !() const {
|
||||
return !operator int();
|
||||
}
|
||||
|
||||
bool operator ==(int t) { return int(*this) == t; }
|
||||
bool operator !=(int t) { return int(*this) != t; }
|
||||
bool operator <(int t) { return int(*this) < t; }
|
||||
bool operator >(int t) { return int(*this) > t; }
|
||||
bool operator <=(int t) { return int(*this) <= t; }
|
||||
bool operator >=(int t) { return int(*this) >= t; }
|
||||
qle_signedbitfield &operator +=(int i) {
|
||||
*this = (int(*this) + i);
|
||||
return *this;
|
||||
}
|
||||
qle_signedbitfield &operator -=(int i) {
|
||||
*this = (int(*this) - i);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
typedef qle_uint offset;
|
||||
|
||||
// round the size up to the next 4 byte boundary
|
||||
inline int alignedSize(int size) { return (size + 3) & ~3; }
|
||||
|
||||
static inline bool useCompressed(const QString &s)
|
||||
{
|
||||
if (s.length() >= 0x8000)
|
||||
return false;
|
||||
const ushort *uc = (const ushort *)s.constData();
|
||||
const ushort *e = uc + s.length();
|
||||
while (uc < e) {
|
||||
if (*uc > 0xff)
|
||||
return false;
|
||||
++uc;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline int qStringSize(const QString &string, bool compress)
|
||||
{
|
||||
int l = 2 + string.length();
|
||||
if (!compress)
|
||||
l *= 2;
|
||||
return alignedSize(l);
|
||||
}
|
||||
|
||||
// returns INT_MAX if it can't compress it into 28 bits
|
||||
static inline int compressedNumber(double d)
|
||||
{
|
||||
// this relies on details of how ieee floats are represented
|
||||
const int exponent_off = 52;
|
||||
const quint64 fraction_mask = 0x000fffffffffffffull;
|
||||
const quint64 exponent_mask = 0x7ff0000000000000ull;
|
||||
|
||||
quint64 val;
|
||||
memcpy (&val, &d, sizeof(double));
|
||||
int exp = (int)((val & exponent_mask) >> exponent_off) - 1023;
|
||||
if (exp < 0 || exp > 25)
|
||||
return INT_MAX;
|
||||
|
||||
quint64 non_int = val & (fraction_mask >> exp);
|
||||
if (non_int)
|
||||
return INT_MAX;
|
||||
|
||||
bool neg = (val >> 63);
|
||||
val &= fraction_mask;
|
||||
val |= ((quint64)1 << 52);
|
||||
int res = (int)(val >> (52 - exp));
|
||||
return neg ? -res : res;
|
||||
}
|
||||
|
||||
class Latin1String;
|
||||
|
||||
class String
|
||||
{
|
||||
public:
|
||||
String(const char *data) { d = (Data *)data; }
|
||||
|
||||
struct Data {
|
||||
qle_int length;
|
||||
qle_ushort utf16[1];
|
||||
};
|
||||
|
||||
Data *d;
|
||||
|
||||
inline String &operator=(const QString &str)
|
||||
{
|
||||
d->length = str.length();
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
for (int i = 0; i < str.length(); ++i)
|
||||
d->utf16[i] = uc[i];
|
||||
#else
|
||||
memcpy(d->utf16, str.unicode(), str.length()*sizeof(ushort));
|
||||
#endif
|
||||
if (str.length() & 1)
|
||||
d->utf16[str.length()] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator ==(const QString &str) const {
|
||||
int slen = str.length();
|
||||
int l = d->length;
|
||||
if (slen != l)
|
||||
return false;
|
||||
const ushort *s = (const ushort *)str.constData();
|
||||
const qle_ushort *a = d->utf16;
|
||||
const ushort *b = s;
|
||||
while (l-- && *a == *b)
|
||||
a++,b++;
|
||||
return (l == -1);
|
||||
}
|
||||
inline bool operator !=(const QString &str) const {
|
||||
return !operator ==(str);
|
||||
}
|
||||
inline bool operator >=(const QString &str) const {
|
||||
// ###
|
||||
return toString() >= str;
|
||||
}
|
||||
|
||||
inline bool operator<(const Latin1String &str) const;
|
||||
inline bool operator>=(const Latin1String &str) const { return !operator <(str); }
|
||||
inline bool operator ==(const Latin1String &str) const;
|
||||
|
||||
inline bool operator ==(const String &str) const {
|
||||
if (d->length != str.d->length)
|
||||
return false;
|
||||
return !memcmp(d->utf16, str.d->utf16, d->length*sizeof(ushort));
|
||||
}
|
||||
inline bool operator<(const String &other) const;
|
||||
inline bool operator >=(const String &other) const { return other < *this; }
|
||||
|
||||
inline QString toString() const {
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
return QString((QChar *)d->utf16, d->length);
|
||||
#else
|
||||
int l = d->length;
|
||||
QString str(l, Qt::Uninitialized);
|
||||
QChar *ch = str.data();
|
||||
for (int i = 0; i < l; ++i)
|
||||
ch[i] = d->utf16[i];
|
||||
return str;
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Latin1String
|
||||
{
|
||||
public:
|
||||
Latin1String(const char *data) { d = (Data *)data; }
|
||||
|
||||
struct Data {
|
||||
qle_short length;
|
||||
char latin1[1];
|
||||
};
|
||||
Data *d;
|
||||
|
||||
inline Latin1String &operator=(const QString &str)
|
||||
{
|
||||
d->length = str.length();
|
||||
uchar *l = (uchar *)d->latin1;
|
||||
const ushort *uc = (const ushort *)str.unicode();
|
||||
for (int i = 0; i < str.length(); ++i)
|
||||
*l++ = uc[i];
|
||||
while ((quintptr)l & 0x3)
|
||||
*l++ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator ==(const QString &str) const {
|
||||
return QLatin1String(d->latin1, d->length) == str;
|
||||
}
|
||||
inline bool operator !=(const QString &str) const {
|
||||
return !operator ==(str);
|
||||
}
|
||||
inline bool operator >=(const QString &str) const {
|
||||
return QLatin1String(d->latin1, d->length) >= str;
|
||||
}
|
||||
|
||||
inline bool operator ==(const Latin1String &str) const {
|
||||
return d->length == str.d->length && !strcmp(d->latin1, str.d->latin1);
|
||||
}
|
||||
inline bool operator >=(const Latin1String &str) const {
|
||||
int l = qMin(d->length, str.d->length);
|
||||
int val = strncmp(d->latin1, str.d->latin1, l);
|
||||
if (!val)
|
||||
val = d->length - str.d->length;
|
||||
return val >= 0;
|
||||
}
|
||||
|
||||
inline bool operator ==(const String &str) const {
|
||||
return (str == *this);
|
||||
}
|
||||
inline bool operator >=(const String &str) const {
|
||||
return (str < *this);
|
||||
}
|
||||
|
||||
inline QString toString() const {
|
||||
return QString::fromLatin1(d->latin1, d->length);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool String::operator ==(const Latin1String &str) const
|
||||
{
|
||||
if ((int)d->length != (int)str.d->length)
|
||||
return false;
|
||||
const qle_ushort *uc = d->utf16;
|
||||
const qle_ushort *e = uc + d->length;
|
||||
const uchar *c = (uchar *)str.d->latin1;
|
||||
|
||||
while (uc < e) {
|
||||
if (*uc != *c)
|
||||
return false;
|
||||
++uc;
|
||||
++c;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool String::operator <(const String &other) const
|
||||
{
|
||||
int alen = d->length;
|
||||
int blen = other.d->length;
|
||||
int l = qMin(alen, blen);
|
||||
qle_ushort *a = d->utf16;
|
||||
qle_ushort *b = other.d->utf16;
|
||||
|
||||
while (l-- && *a == *b)
|
||||
a++,b++;
|
||||
if (l==-1)
|
||||
return (alen < blen);
|
||||
return (ushort)*a - (ushort)*b;
|
||||
}
|
||||
|
||||
inline bool String::operator<(const Latin1String &str) const
|
||||
{
|
||||
const uchar *c = (uchar *) str.d->latin1;
|
||||
if (!c || *c == 0)
|
||||
return false;
|
||||
|
||||
const qle_ushort *uc = d->utf16;
|
||||
const qle_ushort *e = uc + qMin((int)d->length, (int)str.d->length);
|
||||
|
||||
while (uc < e) {
|
||||
if (*uc != *c)
|
||||
break;
|
||||
++uc;
|
||||
++c;
|
||||
}
|
||||
return (uc == (d->utf16 + d->length) ? *c : (ushort)*uc < *c);
|
||||
|
||||
}
|
||||
|
||||
static inline void copyString(char *dest, const QString &str, bool compress)
|
||||
{
|
||||
if (compress) {
|
||||
Latin1String string(dest);
|
||||
string = str;
|
||||
} else {
|
||||
String string(dest);
|
||||
string = str;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Base is the base class for both Object and Array. Both classe work more or less the same way.
|
||||
The class starts with a header (defined by the struct below), then followed by data (the data for
|
||||
values in the Array case and Entry's (see below) for objects.
|
||||
|
||||
After the data a table follows (tableOffset points to it) containing Value objects for Arrays, and
|
||||
offsets from the beginning of the object to Entry's in the case of Object.
|
||||
|
||||
Entry's in the Object's table are lexicographically sorted by key in the table(). This allows the usage
|
||||
of a binary search over the keys in an Object.
|
||||
*/
|
||||
class Base
|
||||
{
|
||||
public:
|
||||
qle_uint size;
|
||||
union {
|
||||
uint _dummy;
|
||||
qle_bitfield<0, 1> is_object;
|
||||
qle_bitfield<1, 31> length;
|
||||
};
|
||||
offset tableOffset;
|
||||
// content follows here
|
||||
|
||||
inline bool isObject() const { return is_object; }
|
||||
inline bool isArray() const { return !isObject(); }
|
||||
|
||||
inline offset *table() const { return (offset *) (((char *) this) + tableOffset); }
|
||||
|
||||
int reserveSpace(uint dataSize, int posInTable, uint numItems, bool replace);
|
||||
void removeItems(int pos, int numItems);
|
||||
};
|
||||
|
||||
class Object : public Base
|
||||
{
|
||||
public:
|
||||
Entry *entryAt(int i) const {
|
||||
return reinterpret_cast<Entry *>(((char *)this) + table()[i]);
|
||||
}
|
||||
int indexOf(const QString &key, bool *exists);
|
||||
|
||||
bool isValid() const;
|
||||
};
|
||||
|
||||
|
||||
class Array : public Base
|
||||
{
|
||||
public:
|
||||
inline Value at(int i) const;
|
||||
inline Value &operator [](int i);
|
||||
|
||||
bool isValid() const;
|
||||
};
|
||||
|
||||
|
||||
class Value
|
||||
{
|
||||
public:
|
||||
union {
|
||||
uint _dummy;
|
||||
qle_bitfield<0, 3> type;
|
||||
qle_bitfield<3, 1> latinOrIntValue;
|
||||
qle_bitfield<4, 1> latinKey;
|
||||
qle_bitfield<5, 27> value;
|
||||
qle_signedbitfield<5, 27> int_value;
|
||||
};
|
||||
|
||||
inline char *data(const Base *b) const { return ((char *)b) + value; }
|
||||
int usedStorage(const Base *b) const;
|
||||
|
||||
bool toBoolean() const;
|
||||
double toDouble(const Base *b) const;
|
||||
QString toString(const Base *b) const;
|
||||
String asString(const Base *b) const;
|
||||
Latin1String asLatin1String(const Base *b) const;
|
||||
Base *base(const Base *b) const;
|
||||
|
||||
bool isValid(const Base *b) const;
|
||||
|
||||
static int requiredStorage(const QJsonValue &v, bool *compressed);
|
||||
static uint valueToStore(const QJsonValue &v, uint offset);
|
||||
static void copyData(const QJsonValue &v, char *dest, bool compressed);
|
||||
};
|
||||
|
||||
inline Value Array::at(int i) const
|
||||
{
|
||||
return *(Value *) (table() + i);
|
||||
}
|
||||
|
||||
inline Value &Array::operator [](int i)
|
||||
{
|
||||
return *(Value *) (table() + i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Entry {
|
||||
public:
|
||||
Value value;
|
||||
// key
|
||||
// value data follows key
|
||||
|
||||
int size() const {
|
||||
int s = sizeof(Entry);
|
||||
if (value.latinKey)
|
||||
s += sizeof(ushort) + *(ushort *) ((const char *)this + sizeof(Entry));
|
||||
else
|
||||
s += sizeof(uint) + *(int *) ((const char *)this + sizeof(Entry));
|
||||
return alignedSize(s);
|
||||
}
|
||||
|
||||
int usedStorage(Base *b) const {
|
||||
return size() + value.usedStorage(b);
|
||||
}
|
||||
|
||||
String shallowKey() const
|
||||
{
|
||||
Q_ASSERT(!value.latinKey);
|
||||
return String((const char *)this + sizeof(Entry));
|
||||
}
|
||||
Latin1String shallowLatin1Key() const
|
||||
{
|
||||
Q_ASSERT(value.latinKey);
|
||||
return Latin1String((const char *)this + sizeof(Entry));
|
||||
}
|
||||
QString key() const
|
||||
{
|
||||
if (value.latinKey) {
|
||||
return shallowLatin1Key().toString();
|
||||
}
|
||||
return shallowKey().toString();
|
||||
}
|
||||
|
||||
bool operator ==(const QString &key) const;
|
||||
inline bool operator !=(const QString &key) const { return !operator ==(key); }
|
||||
bool operator >=(const QString &key) const;
|
||||
|
||||
bool operator ==(const Entry &other) const;
|
||||
bool operator >=(const Entry &other) const;
|
||||
};
|
||||
|
||||
inline bool operator <(const QString &key, const Entry &e)
|
||||
{ return e >= key; }
|
||||
|
||||
class Header {
|
||||
public:
|
||||
qle_uint tag; // 'qbjs'
|
||||
qle_uint version; // 1
|
||||
Base *root() { return (Base *)(this + 1); }
|
||||
};
|
||||
|
||||
|
||||
inline bool Value::toBoolean() const
|
||||
{
|
||||
Q_ASSERT(type == QJsonValue::Bool);
|
||||
return value != 0;
|
||||
}
|
||||
|
||||
inline double Value::toDouble(const Base *b) const
|
||||
{
|
||||
Q_ASSERT(type == QJsonValue::Double);
|
||||
if (latinOrIntValue)
|
||||
return int_value;
|
||||
|
||||
quint64 i = qFromLittleEndian<quint64>((const uchar *)b + value);
|
||||
double d;
|
||||
memcpy(&d, &i, sizeof(double));
|
||||
return d;
|
||||
}
|
||||
|
||||
inline String Value::asString(const Base *b) const
|
||||
{
|
||||
Q_ASSERT(type == QJsonValue::String && !latinOrIntValue);
|
||||
return String(data(b));
|
||||
}
|
||||
|
||||
inline Latin1String Value::asLatin1String(const Base *b) const
|
||||
{
|
||||
Q_ASSERT(type == QJsonValue::String && latinOrIntValue);
|
||||
return Latin1String(data(b));
|
||||
}
|
||||
|
||||
inline QString Value::toString(const Base *b) const
|
||||
{
|
||||
if (latinOrIntValue)
|
||||
return asLatin1String(b).toString();
|
||||
else
|
||||
return asString(b).toString();
|
||||
}
|
||||
|
||||
inline Base *Value::base(const Base *b) const
|
||||
{
|
||||
Q_ASSERT(type == QJsonValue::Array || type == QJsonValue::Object);
|
||||
return reinterpret_cast<Base *>(data(b));
|
||||
}
|
||||
|
||||
class Data {
|
||||
public:
|
||||
enum Validation {
|
||||
Unchecked,
|
||||
Validated,
|
||||
Invalid
|
||||
};
|
||||
|
||||
QAtomicInt ref;
|
||||
int alloc;
|
||||
union {
|
||||
char *rawData;
|
||||
Header *header;
|
||||
};
|
||||
uint compactionCounter : 31;
|
||||
uint ownsData : 1;
|
||||
|
||||
inline Data(char *raw, int a)
|
||||
: alloc(a), rawData(raw), compactionCounter(0), ownsData(true)
|
||||
{
|
||||
}
|
||||
inline Data(int reserved, QJsonValue::Type valueType)
|
||||
: rawData(0), compactionCounter(0), ownsData(true)
|
||||
{
|
||||
Q_ASSERT(valueType == QJsonValue::Array || valueType == QJsonValue::Object);
|
||||
|
||||
alloc = sizeof(Header) + sizeof(Base) + reserved + sizeof(offset);
|
||||
header = (Header *)malloc(alloc);
|
||||
Q_CHECK_PTR(header);
|
||||
header->tag = QJsonDocument::BinaryFormatTag;
|
||||
header->version = 1;
|
||||
Base *b = header->root();
|
||||
b->size = sizeof(Base);
|
||||
b->is_object = (valueType == QJsonValue::Object);
|
||||
b->tableOffset = sizeof(Base);
|
||||
b->length = 0;
|
||||
}
|
||||
inline ~Data()
|
||||
{ if (ownsData) free(rawData); }
|
||||
|
||||
uint offsetOf(const void *ptr) const { return (uint)(((char *)ptr - rawData)); }
|
||||
|
||||
QJsonObject toObject(Object *o) const
|
||||
{
|
||||
return QJsonObject(const_cast<Data *>(this), o);
|
||||
}
|
||||
|
||||
QJsonArray toArray(Array *a) const
|
||||
{
|
||||
return QJsonArray(const_cast<Data *>(this), a);
|
||||
}
|
||||
|
||||
Data *clone(Base *b, int reserve = 0)
|
||||
{
|
||||
int size = sizeof(Header) + b->size + reserve;
|
||||
char *raw = (char *)malloc(size);
|
||||
Q_CHECK_PTR(raw);
|
||||
memcpy(raw + sizeof(Header), b, b->size);
|
||||
Header *h = (Header *)raw;
|
||||
h->tag = QJsonDocument::BinaryFormatTag;
|
||||
h->version = 1;
|
||||
Data *d = new Data(raw, size);
|
||||
d->compactionCounter = (b == header->root()) ? compactionCounter : 0;
|
||||
return d;
|
||||
}
|
||||
|
||||
void compact();
|
||||
bool valid() const;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(Data)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QJSON_P_H
|
1014
src/corelib/json/qjsonarray.cpp
Normal file
1014
src/corelib/json/qjsonarray.cpp
Normal file
File diff suppressed because it is too large
Load Diff
223
src/corelib/json/qjsonarray.h
Normal file
223
src/corelib/json/qjsonarray.h
Normal file
@ -0,0 +1,223 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QJSONARRAY_H
|
||||
#define QJSONARRAY_H
|
||||
|
||||
#include <qjsonvalue.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QDebug;
|
||||
class QStringList;
|
||||
template <typename T> class QList;
|
||||
typedef QList<QVariant> QVariantList;
|
||||
|
||||
class Q_CORE_EXPORT QJsonArray
|
||||
{
|
||||
public:
|
||||
QJsonArray();
|
||||
~QJsonArray();
|
||||
|
||||
QJsonArray(const QJsonArray &other);
|
||||
QJsonArray &operator =(const QJsonArray &other);
|
||||
|
||||
static QJsonArray fromStringList(const QStringList &list);
|
||||
static QJsonArray fromVariantList(const QVariantList &list);
|
||||
QVariantList toVariantList() const;
|
||||
|
||||
int size() const;
|
||||
inline int count() const { return size(); }
|
||||
|
||||
bool isEmpty() const;
|
||||
QJsonValue at(int i) const;
|
||||
QJsonValue first() const;
|
||||
QJsonValue last() const;
|
||||
|
||||
void prepend(const QJsonValue &value);
|
||||
void append(const QJsonValue &value);
|
||||
void removeAt(int i);
|
||||
QJsonValue takeAt(int i);
|
||||
inline void removeFirst() { removeAt(0); }
|
||||
inline void removeLast() { removeAt(size() - 1); }
|
||||
|
||||
void insert(int i, const QJsonValue &value);
|
||||
void replace(int i, const QJsonValue &value);
|
||||
|
||||
bool contains(const QJsonValue &element) const;
|
||||
QJsonValueRef operator[](int i);
|
||||
QJsonValue operator[](int i) const;
|
||||
|
||||
bool operator==(const QJsonArray &other) const;
|
||||
bool operator!=(const QJsonArray &other) const;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
QJsonArray *a;
|
||||
int i;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef int difference_type;
|
||||
typedef QJsonValue value_type;
|
||||
//typedef T *pointer;
|
||||
typedef QJsonValueRef reference;
|
||||
|
||||
inline iterator() : a(0), i(0) { }
|
||||
explicit inline iterator(QJsonArray *array, int index) : a(array), i(index) { }
|
||||
|
||||
inline QJsonValueRef operator*() const { return QJsonValueRef(a, i); }
|
||||
//inline T *operator->() const { return &concrete(i)->value; }
|
||||
inline QJsonValueRef operator[](int j) const { return QJsonValueRef(a, i + j); }
|
||||
|
||||
inline bool operator==(const iterator &o) const { return i == o.i; }
|
||||
inline bool operator!=(const iterator &o) const { return i != o.i; }
|
||||
inline bool operator<(const iterator& other) const { return i < other.i; }
|
||||
inline bool operator<=(const iterator& other) const { return i <= other.i; }
|
||||
inline bool operator>(const iterator& other) const { return i > other.i; }
|
||||
inline bool operator>=(const iterator& other) const { return i >= other.i; }
|
||||
inline bool operator==(const const_iterator &o) const { return i == o.i; }
|
||||
inline bool operator!=(const const_iterator &o) const { return i != o.i; }
|
||||
inline bool operator<(const const_iterator& other) const { return i < other.i; }
|
||||
inline bool operator<=(const const_iterator& other) const { return i <= other.i; }
|
||||
inline bool operator>(const const_iterator& other) const { return i > other.i; }
|
||||
inline bool operator>=(const const_iterator& other) const { return i >= other.i; }
|
||||
inline iterator &operator++() { ++i; return *this; }
|
||||
inline iterator operator++(int) { iterator n = *this; ++i; return n; }
|
||||
inline iterator &operator--() { i--; return *this; }
|
||||
inline iterator operator--(int) { iterator n = *this; i--; return n; }
|
||||
inline iterator &operator+=(int j) { i+=j; return *this; }
|
||||
inline iterator &operator-=(int j) { i-=j; return *this; }
|
||||
inline iterator operator+(int j) const { return iterator(a, i+j); }
|
||||
inline iterator operator-(int j) const { return iterator(a, i-j); }
|
||||
inline int operator-(iterator j) const { return i - j.i; }
|
||||
};
|
||||
friend class iterator;
|
||||
|
||||
class const_iterator {
|
||||
public:
|
||||
const QJsonArray *a;
|
||||
int i;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef qptrdiff difference_type;
|
||||
typedef QJsonValue value_type;
|
||||
//typedef const T *pointer;
|
||||
typedef QJsonValue reference;
|
||||
|
||||
inline const_iterator() : a(0), i(0) { }
|
||||
explicit inline const_iterator(const QJsonArray *array, int index) : a(array), i(index) { }
|
||||
inline const_iterator(const const_iterator &o) : a(o.a), i(o.i) {}
|
||||
inline const_iterator(const iterator &o) : a(o.a), i(o.i) {}
|
||||
|
||||
inline QJsonValue operator*() const { return a->at(i); }
|
||||
//inline T *operator->() const { return &concrete(i)->value; }
|
||||
inline QJsonValue operator[](int j) const { return a->at(i+j); }
|
||||
inline bool operator==(const const_iterator &o) const { return i == o.i; }
|
||||
inline bool operator!=(const const_iterator &o) const { return i != o.i; }
|
||||
inline bool operator<(const const_iterator& other) const { return i < other.i; }
|
||||
inline bool operator<=(const const_iterator& other) const { return i <= other.i; }
|
||||
inline bool operator>(const const_iterator& other) const { return i > other.i; }
|
||||
inline bool operator>=(const const_iterator& other) const { return i >= other.i; }
|
||||
inline const_iterator &operator++() { ++i; return *this; }
|
||||
inline const_iterator operator++(int) { const_iterator n = *this; ++i; return n; }
|
||||
inline const_iterator &operator--() { i--; return *this; }
|
||||
inline const_iterator operator--(int) { const_iterator n = *this; i--; return n; }
|
||||
inline const_iterator &operator+=(int j) { i+=j; return *this; }
|
||||
inline const_iterator &operator-=(int j) { i-=j; return *this; }
|
||||
inline const_iterator operator+(int j) const { return const_iterator(a, i+j); }
|
||||
inline const_iterator operator-(int j) const { return const_iterator(a, i-j); }
|
||||
inline int operator-(const_iterator j) const { return i - j.i; }
|
||||
};
|
||||
friend class const_iterator;
|
||||
|
||||
// stl style
|
||||
inline iterator begin() { detach(); return iterator(this, 0); }
|
||||
inline const_iterator begin() const { return const_iterator(this, 0); }
|
||||
inline const_iterator constBegin() const { return const_iterator(this, 0); }
|
||||
inline iterator end() { detach(); return iterator(this, size()); }
|
||||
inline const_iterator end() const { return const_iterator(this, size()); }
|
||||
inline const_iterator constEnd() const { return const_iterator(this, size()); }
|
||||
iterator insert(iterator before, const QJsonValue &value) { insert(before.i, value); return before; }
|
||||
iterator erase(iterator pos) { removeAt(pos.i); return pos; }
|
||||
|
||||
// more Qt
|
||||
typedef iterator Iterator;
|
||||
typedef const_iterator ConstIterator;
|
||||
|
||||
// stl compatibility
|
||||
inline void push_back(const QJsonValue &t) { append(t); }
|
||||
inline void push_front(const QJsonValue &t) { prepend(t); }
|
||||
inline void pop_front() { removeFirst(); }
|
||||
inline void pop_back() { removeLast(); }
|
||||
inline bool empty() const { return isEmpty(); }
|
||||
typedef int size_type;
|
||||
typedef QJsonValue value_type;
|
||||
typedef value_type *pointer;
|
||||
typedef const value_type *const_pointer;
|
||||
typedef QJsonValueRef reference;
|
||||
typedef QJsonValue const_reference;
|
||||
typedef int difference_type;
|
||||
|
||||
private:
|
||||
friend class QJsonPrivate::Data;
|
||||
friend class QJsonValue;
|
||||
friend class QJsonDocument;
|
||||
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &);
|
||||
|
||||
QJsonArray(QJsonPrivate::Data *data, QJsonPrivate::Array *array);
|
||||
void compact();
|
||||
void detach(uint reserve = 0);
|
||||
|
||||
QJsonPrivate::Data *d;
|
||||
QJsonPrivate::Array *a;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &);
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QJSONARRAY_H
|
536
src/corelib/json/qjsondocument.cpp
Normal file
536
src/corelib/json/qjsondocument.cpp
Normal file
@ -0,0 +1,536 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <qjsondocument.h>
|
||||
#include <qjsonobject.h>
|
||||
#include <qjsonvalue.h>
|
||||
#include <qjsonarray.h>
|
||||
#include <qstringlist.h>
|
||||
#include <qdebug.h>
|
||||
#include "qjsonwriter_p.h"
|
||||
#include "qjsonparser_p.h"
|
||||
#include "qjson_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*! \class QJsonDocument
|
||||
\ingroup json
|
||||
\reentrant
|
||||
\since 5.0
|
||||
|
||||
\brief The QJsonDocument class provides a way to read and write JSON documents.
|
||||
|
||||
QJsonDocument is a class that wraps a complete JSON document and can read and
|
||||
write this document both from a UTF-8 encoded text based representation as well
|
||||
as Qt's own binary format.
|
||||
|
||||
A JSON document can be converted from its text-based representation to a QJsonDocument
|
||||
using QJsonDocument::fromJson(). toJson() converts it back to text. The parser is very
|
||||
fast and efficient and converts the JSON to the binary representation used by Qt.
|
||||
|
||||
Validity of the parsed document can be queried with !isNull()
|
||||
|
||||
A document can be queried as to whether it contains an array or an object using isArray()
|
||||
and isObject(). The array or object contained in the document can be retrieved using
|
||||
array() or object() and then read or manipulated.
|
||||
|
||||
A document can also be created from a stored binary representation using fromBinaryData() or
|
||||
fromRawData().
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Constructs an empty and invalid document.
|
||||
*/
|
||||
QJsonDocument::QJsonDocument()
|
||||
: d(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Creates a QJsonDocument from \a object.
|
||||
*/
|
||||
QJsonDocument::QJsonDocument(const QJsonObject &object)
|
||||
: d(0)
|
||||
{
|
||||
setObject(object);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Constructs a QJsonDocument from \a array.
|
||||
*/
|
||||
QJsonDocument::QJsonDocument(const QJsonArray &array)
|
||||
: d(0)
|
||||
{
|
||||
setArray(array);
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
QJsonDocument::QJsonDocument(QJsonPrivate::Data *data)
|
||||
: d(data)
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
Deletes the document.
|
||||
|
||||
Binary data set with fromRawData is not freed.
|
||||
*/
|
||||
QJsonDocument::~QJsonDocument()
|
||||
{
|
||||
if (d && !d->ref.deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Creates a copy of the \a other document.
|
||||
*/
|
||||
QJsonDocument::QJsonDocument(const QJsonDocument &other)
|
||||
{
|
||||
d = other.d;
|
||||
if (d)
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Assigns the \a other document to this QJsonDocument.
|
||||
* Returns a reference to this object.
|
||||
*/
|
||||
QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
|
||||
{
|
||||
if (d != other.d) {
|
||||
if (d && !d->ref.deref())
|
||||
delete d;
|
||||
d = other.d;
|
||||
if (d)
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \enum QJsonDocument::DataValidation
|
||||
|
||||
This value is used to tell QJsonDocument whether to validate the binary data
|
||||
when converting to a QJsonDocument using fromBinaryData() or fromRawData().
|
||||
|
||||
\value Validate Validate the data before using it. This is the default.
|
||||
\value BypassValidation Bypasses data validation. Only use if you received the
|
||||
data from a trusted place and know it's valid, as using of invalid data can crash
|
||||
the application.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Creates a QJsonDocument that uses the first \a size bytes from
|
||||
\a data. It assumes \a data contains a binary encoded JSON document.
|
||||
The created document does not take ownership of \a data and the caller
|
||||
has to guarantee that \a data will not be deleted or modified as long as
|
||||
any QJsonDocument, QJsonObject or QJsonArray still references the data.
|
||||
|
||||
\a data has to be aligned to a 4 byte boundary.
|
||||
|
||||
\a validation decides whether the data is checked for validity before being used.
|
||||
By default the data is validated. If the \a data is not valid, the method returns
|
||||
a null document.
|
||||
|
||||
Returns a QJsonDocument representing the data.
|
||||
|
||||
\sa rawData fromBinaryData isNull DataValidation
|
||||
*/
|
||||
QJsonDocument QJsonDocument::fromRawData(const char *data, int size, DataValidation validation)
|
||||
{
|
||||
if (!(((quintptr)validation) & ~3)) {
|
||||
qWarning() <<"QJsonDocumnt::fromRawData: data has to have 4 byte alignment";
|
||||
return QJsonDocument();
|
||||
}
|
||||
|
||||
QJsonPrivate::Data *d = new QJsonPrivate::Data((char *)data, size);
|
||||
d->ownsData = false;
|
||||
|
||||
if (validation != BypassValidation && !d->valid()) {
|
||||
delete d;
|
||||
return QJsonDocument();
|
||||
}
|
||||
|
||||
return QJsonDocument(d);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the raw binary representation of the data
|
||||
\a size will contain the size of the \a data.
|
||||
|
||||
This method is useful to e.g. stream the JSON document
|
||||
in it's binary form to a file.
|
||||
*/
|
||||
const char *QJsonDocument::rawData(int *size) const
|
||||
{
|
||||
if (!d) {
|
||||
*size = 0;
|
||||
return 0;
|
||||
}
|
||||
*size = d->alloc;
|
||||
return d->rawData;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a QJsonDocument from \a data.
|
||||
|
||||
\a validation decides whether the data is checked for validity before being used.
|
||||
By default the data is validated. If the \a data is not valid, the method returns
|
||||
a null document.
|
||||
|
||||
\sa toBinaryData fromRawData isNull DataValidation
|
||||
*/
|
||||
QJsonDocument QJsonDocument::fromBinaryData(const QByteArray &data, DataValidation validation)
|
||||
{
|
||||
QJsonPrivate::Header h;
|
||||
memcpy(&h, data.constData(), sizeof(QJsonPrivate::Header));
|
||||
QJsonPrivate::Base root;
|
||||
memcpy(&root, data.constData() + sizeof(QJsonPrivate::Header), sizeof(QJsonPrivate::Base));
|
||||
|
||||
// do basic checks here, so we don't try to allocate more memory than we can.
|
||||
if (data.size() < (int)(sizeof(QJsonPrivate::Header) + sizeof(QJsonPrivate::Base)) ||
|
||||
h.tag != QJsonDocument::BinaryFormatTag || h.version != 1u ||
|
||||
sizeof(QJsonPrivate::Header) + root.size > (uint)data.size())
|
||||
return QJsonDocument();
|
||||
|
||||
char *raw = (char *)malloc(data.size());
|
||||
if (!raw)
|
||||
return QJsonDocument();
|
||||
|
||||
memcpy(raw, data.constData(), data.size());
|
||||
QJsonPrivate::Data *d = new QJsonPrivate::Data(raw, data.size());
|
||||
|
||||
if (validation != BypassValidation && !d->valid()) {
|
||||
delete d;
|
||||
return QJsonDocument();
|
||||
}
|
||||
|
||||
return QJsonDocument(d);
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a QJsonDocument from the QVariant \a variant.
|
||||
|
||||
If the \a variant contains any other type than a QVariant::Map,
|
||||
QVariant::List or QVariant::StringList, the returned document
|
||||
document is invalid.
|
||||
|
||||
\sa toVariant
|
||||
*/
|
||||
QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
|
||||
{
|
||||
QJsonDocument doc;
|
||||
if (variant.type() == QVariant::Map) {
|
||||
doc.setObject(QJsonObject::fromVariantMap(variant.toMap()));
|
||||
} else if (variant.type() == QVariant::List) {
|
||||
doc.setArray(QJsonArray::fromVariantList(variant.toList()));
|
||||
} else if (variant.type() == QVariant::StringList) {
|
||||
doc.setArray(QJsonArray::fromStringList(variant.toStringList()));
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a QVariant representing the Json document.
|
||||
|
||||
The returned variant will be a QVariantList if the document is
|
||||
a QJsonArray and a QVariantMap if the document is a QJsonObject.
|
||||
|
||||
\sa fromVariant, QJsonValue::toVariant()
|
||||
*/
|
||||
QVariant QJsonDocument::toVariant() const
|
||||
{
|
||||
if (!d)
|
||||
return QVariant();
|
||||
|
||||
if (d->header->root()->isArray())
|
||||
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(d->header->root())).toVariantList();
|
||||
else
|
||||
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(d->header->root())).toVariantMap();
|
||||
}
|
||||
|
||||
/*!
|
||||
Converts the QJsonDocument to a UTF-8 encoded JSON document.
|
||||
|
||||
\sa fromJson
|
||||
*/
|
||||
QByteArray QJsonDocument::toJson() const
|
||||
{
|
||||
if (!d)
|
||||
return QByteArray();
|
||||
|
||||
QByteArray json;
|
||||
|
||||
if (d->header->root()->isArray())
|
||||
QJsonPrivate::Writer::arrayToJson(static_cast<QJsonPrivate::Array *>(d->header->root()), json, 0);
|
||||
else
|
||||
QJsonPrivate::Writer::objectToJson(static_cast<QJsonPrivate::Object *>(d->header->root()), json, 0);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/*!
|
||||
Parses a UTF-8 encoded JSON document and creates a QJsonDocument
|
||||
from it. isNull() will return \c false if no error was encountered during
|
||||
parsing.
|
||||
|
||||
\sa toJson
|
||||
*/
|
||||
QJsonDocument QJsonDocument::fromJson(const QByteArray &json)
|
||||
{
|
||||
QJsonPrivate::Parser parser(json.constData(), json.length());
|
||||
return parser.parse();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the document doesn't contain any data.
|
||||
*/
|
||||
bool QJsonDocument::isEmpty() const
|
||||
{
|
||||
if (!d)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a binary representation of the document.
|
||||
|
||||
The binary representation is also the native format used internally in Qt,
|
||||
and is very efficient and fast to convert to and from.
|
||||
|
||||
The binary format can be stored on disk and interchanged with other applications
|
||||
or computers. fromBinaryData() can be used to convert it back into a
|
||||
JSON document.
|
||||
|
||||
\sa fromBinaryData
|
||||
*/
|
||||
QByteArray QJsonDocument::toBinaryData() const
|
||||
{
|
||||
if (!d || !d->rawData)
|
||||
return QByteArray();
|
||||
|
||||
return QByteArray(d->rawData, d->header->root()->size + sizeof(QJsonPrivate::Header));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the document contains an array.
|
||||
|
||||
\sa array() isObject()
|
||||
*/
|
||||
bool QJsonDocument::isArray() const
|
||||
{
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
QJsonPrivate::Header *h = (QJsonPrivate::Header *)d->rawData;
|
||||
return h->root()->isArray();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the document contains an object.
|
||||
|
||||
\sa object() isArray()
|
||||
*/
|
||||
bool QJsonDocument::isObject() const
|
||||
{
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
QJsonPrivate::Header *h = (QJsonPrivate::Header *)d->rawData;
|
||||
return h->root()->isObject();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the QJsonObject contained in the document.
|
||||
|
||||
Returns an empty object if the document contains an
|
||||
array.
|
||||
|
||||
\sa isObject array setObject
|
||||
*/
|
||||
QJsonObject QJsonDocument::object() const
|
||||
{
|
||||
if (d) {
|
||||
QJsonPrivate::Base *b = d->header->root();
|
||||
if (b->isObject())
|
||||
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(b));
|
||||
}
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the QJsonArray contained in the document.
|
||||
|
||||
Returns an empty array if the document contains an
|
||||
object.
|
||||
|
||||
\sa isArray object setArray
|
||||
*/
|
||||
QJsonArray QJsonDocument::array() const
|
||||
{
|
||||
if (d) {
|
||||
QJsonPrivate::Base *b = d->header->root();
|
||||
if (b->isArray())
|
||||
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(b));
|
||||
}
|
||||
return QJsonArray();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets \a object as the main object of this document.
|
||||
|
||||
\sa setArray object
|
||||
*/
|
||||
void QJsonDocument::setObject(const QJsonObject &object)
|
||||
{
|
||||
if (d && !d->ref.deref())
|
||||
delete d;
|
||||
|
||||
d = object.d;
|
||||
|
||||
if (!d) {
|
||||
d = new QJsonPrivate::Data(0, QJsonValue::Object);
|
||||
} else if (d->compactionCounter || object.o != d->header->root()) {
|
||||
QJsonObject o(object);
|
||||
if (d->compactionCounter)
|
||||
o.compact();
|
||||
else
|
||||
o.detach();
|
||||
d = o.d;
|
||||
d->ref.ref();
|
||||
return;
|
||||
}
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets \a array as the main object of this document.
|
||||
|
||||
\sa setObject array
|
||||
*/
|
||||
void QJsonDocument::setArray(const QJsonArray &array)
|
||||
{
|
||||
if (d && !d->ref.deref())
|
||||
delete d;
|
||||
|
||||
d = array.d;
|
||||
|
||||
if (!d) {
|
||||
d = new QJsonPrivate::Data(0, QJsonValue::Array);
|
||||
} else if (d->compactionCounter || array.a != d->header->root()) {
|
||||
QJsonArray a(array);
|
||||
if (d->compactionCounter)
|
||||
a.compact();
|
||||
else
|
||||
a.detach();
|
||||
d = a.d;
|
||||
d->ref.ref();
|
||||
return;
|
||||
}
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c true if the \a other document is equal to this document.
|
||||
*/
|
||||
bool QJsonDocument::operator==(const QJsonDocument &other) const
|
||||
{
|
||||
if (d == other.d)
|
||||
return true;
|
||||
|
||||
if (!d || !other.d)
|
||||
return false;
|
||||
|
||||
if (d->header->root()->isArray() != other.d->header->root()->isArray())
|
||||
return false;
|
||||
|
||||
if (d->header->root()->isObject())
|
||||
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(d->header->root()))
|
||||
== QJsonObject(other.d, static_cast<QJsonPrivate::Object *>(other.d->header->root()));
|
||||
else
|
||||
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(d->header->root()))
|
||||
== QJsonArray(other.d, static_cast<QJsonPrivate::Array *>(other.d->header->root()));
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QJsonDocument::operator!=(const QJsonDocument &other) const
|
||||
|
||||
returns \c true if \a other is not equal to this document
|
||||
*/
|
||||
|
||||
/*!
|
||||
returns true if this document is null.
|
||||
|
||||
Null documents are documents created through the default constructor.
|
||||
|
||||
Documents created from UTF-8 encoded text or the binary format are
|
||||
validated during parsing. If validation fails, the returned document
|
||||
will also be null.
|
||||
*/
|
||||
bool QJsonDocument::isNull() const
|
||||
{
|
||||
return (d == 0);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug dbg, const QJsonDocument &o)
|
||||
{
|
||||
if (!o.d) {
|
||||
dbg << "QJsonDocument()";
|
||||
return dbg;
|
||||
}
|
||||
QByteArray json;
|
||||
if (o.d->header->root()->isArray())
|
||||
QJsonPrivate::Writer::arrayToJson(static_cast<QJsonPrivate::Array *>(o.d->header->root()), json, 0, true);
|
||||
else
|
||||
QJsonPrivate::Writer::objectToJson(static_cast<QJsonPrivate::Object *>(o.d->header->root()), json, 0, true);
|
||||
dbg.nospace() << "QJsonDocument("
|
||||
<< json.constData() // print as utf-8 string without extra quotation marks
|
||||
<< ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
125
src/corelib/json/qjsondocument.h
Normal file
125
src/corelib/json/qjsondocument.h
Normal file
@ -0,0 +1,125 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QJSONDOCUMENT_H
|
||||
#define QJSONDOCUMENT_H
|
||||
|
||||
#include <qjsonvalue.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QDebug;
|
||||
|
||||
namespace QJsonPrivate {
|
||||
class Parser;
|
||||
}
|
||||
|
||||
class Q_CORE_EXPORT QJsonDocument
|
||||
{
|
||||
public:
|
||||
#ifdef Q_LITTLE_ENDIAN
|
||||
static const uint BinaryFormatTag = ('q') | ('b' << 8) | ('j' << 16) | ('s' << 24);
|
||||
#else
|
||||
static const uint BinaryFormatTag = ('q' << 24) | ('b' << 16) | ('j' << 8) | ('s');
|
||||
#endif
|
||||
|
||||
QJsonDocument();
|
||||
explicit QJsonDocument(const QJsonObject &object);
|
||||
explicit QJsonDocument(const QJsonArray &array);
|
||||
~QJsonDocument();
|
||||
|
||||
QJsonDocument(const QJsonDocument &other);
|
||||
QJsonDocument &operator =(const QJsonDocument &other);
|
||||
|
||||
enum DataValidation {
|
||||
Validate,
|
||||
BypassValidation
|
||||
};
|
||||
|
||||
static QJsonDocument fromRawData(const char *data, int size, DataValidation validation = Validate);
|
||||
const char *rawData(int *size) const;
|
||||
|
||||
static QJsonDocument fromBinaryData(const QByteArray &data, DataValidation validation = Validate);
|
||||
QByteArray toBinaryData() const;
|
||||
|
||||
static QJsonDocument fromVariant(const QVariant &variant);
|
||||
QVariant toVariant() const;
|
||||
|
||||
static QJsonDocument fromJson(const QByteArray &json);
|
||||
QByteArray toJson() const;
|
||||
|
||||
bool isEmpty() const;
|
||||
bool isArray() const;
|
||||
bool isObject() const;
|
||||
|
||||
QJsonObject object() const;
|
||||
QJsonArray array() const;
|
||||
|
||||
void setObject(const QJsonObject &object);
|
||||
void setArray(const QJsonArray &array);
|
||||
|
||||
bool operator==(const QJsonDocument &other) const;
|
||||
bool operator!=(const QJsonDocument &other) const { return !(*this == other); }
|
||||
|
||||
bool isNull() const;
|
||||
|
||||
private:
|
||||
friend class QJsonValue;
|
||||
friend class QJsonPrivate::Data;
|
||||
friend class QJsonPrivate::Parser;
|
||||
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
|
||||
|
||||
QJsonDocument(QJsonPrivate::Data *data);
|
||||
|
||||
QJsonPrivate::Data *d;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QJSONDOCUMENT_H
|
1014
src/corelib/json/qjsonobject.cpp
Normal file
1014
src/corelib/json/qjsonobject.cpp
Normal file
File diff suppressed because it is too large
Load Diff
218
src/corelib/json/qjsonobject.h
Normal file
218
src/corelib/json/qjsonobject.h
Normal file
@ -0,0 +1,218 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QJSONOBJECT_H
|
||||
#define QJSONOBJECT_H
|
||||
|
||||
#include <qjsonvalue.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QDebug;
|
||||
template <class Key, class T> class QMap;
|
||||
typedef QMap<QString, QVariant> QVariantMap;
|
||||
|
||||
class Q_CORE_EXPORT QJsonObject
|
||||
{
|
||||
public:
|
||||
QJsonObject();
|
||||
~QJsonObject();
|
||||
|
||||
QJsonObject(const QJsonObject &other);
|
||||
QJsonObject &operator =(const QJsonObject &other);
|
||||
|
||||
static QJsonObject fromVariantMap(const QVariantMap &map);
|
||||
QVariantMap toVariantMap() const;
|
||||
|
||||
QStringList keys() const;
|
||||
int size() const;
|
||||
inline int count() const { return size(); }
|
||||
inline int length() const { return size(); }
|
||||
bool isEmpty() const;
|
||||
|
||||
QJsonValue value(const QString &key) const;
|
||||
QJsonValue operator[] (const QString &key) const;
|
||||
QJsonValueRef operator[] (const QString &key);
|
||||
|
||||
void remove(const QString &key);
|
||||
QJsonValue take(const QString &key);
|
||||
bool contains(const QString &key) const;
|
||||
|
||||
bool operator==(const QJsonObject &other) const;
|
||||
bool operator!=(const QJsonObject &other) const;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
class iterator
|
||||
{
|
||||
friend class const_iterator;
|
||||
friend class QJsonObject;
|
||||
QJsonObject *o;
|
||||
int i;
|
||||
|
||||
public:
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
typedef int difference_type;
|
||||
typedef QJsonValue value_type;
|
||||
// typedef T *pointer;
|
||||
typedef QJsonValueRef reference;
|
||||
|
||||
Q_DECL_CONSTEXPR inline iterator() : o(0), i(0) {}
|
||||
Q_DECL_CONSTEXPR inline iterator(QJsonObject *obj, int index) : o(obj), i(index) {}
|
||||
|
||||
inline QString key() const { return o->keyAt(i); }
|
||||
inline QJsonValueRef value() const { return QJsonValueRef(o, i); }
|
||||
inline QJsonValueRef operator*() const { return QJsonValueRef(o, i); }
|
||||
//inline T *operator->() const { return &concrete(i)->value; }
|
||||
inline bool operator==(const iterator &other) const { return i == other.i; }
|
||||
inline bool operator!=(const iterator &other) const { return i != other.i; }
|
||||
|
||||
inline iterator &operator++() { ++i; return *this; }
|
||||
inline iterator operator++(int) { iterator r = *this; ++i; return r; }
|
||||
inline iterator &operator--() { --i; return *this; }
|
||||
inline iterator operator--(int) { iterator r = *this; --i; return r; }
|
||||
inline iterator operator+(int j) const
|
||||
{ iterator r = *this; r.i += j; return r; }
|
||||
inline iterator operator-(int j) const { return operator+(-j); }
|
||||
inline iterator &operator+=(int j) { i += j; return *this; }
|
||||
inline iterator &operator-=(int j) { i -= j; return *this; }
|
||||
|
||||
public:
|
||||
inline bool operator==(const const_iterator &other) const { return i == other.i; }
|
||||
inline bool operator!=(const const_iterator &other) const { return i != other.i; }
|
||||
};
|
||||
friend class iterator;
|
||||
|
||||
class const_iterator
|
||||
{
|
||||
friend class iterator;
|
||||
const QJsonObject *o;
|
||||
int i;
|
||||
|
||||
public:
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
typedef int difference_type;
|
||||
typedef QJsonValue value_type;
|
||||
typedef QJsonValue reference;
|
||||
|
||||
Q_DECL_CONSTEXPR inline const_iterator() : o(0), i(0) {}
|
||||
Q_DECL_CONSTEXPR inline const_iterator(const QJsonObject *obj, int index)
|
||||
: o(obj), i(index) {}
|
||||
inline const_iterator(const iterator &other)
|
||||
: o(other.o), i(other.i) {}
|
||||
|
||||
inline QString key() const { return o->keyAt(i); }
|
||||
inline QJsonValue value() const { return o->valueAt(i); }
|
||||
inline QJsonValue operator*() const { return o->valueAt(i); }
|
||||
//inline const T *operator->() const { return &concrete(i)->value; }
|
||||
inline bool operator==(const const_iterator &other) const { return i == other.i; }
|
||||
inline bool operator!=(const const_iterator &other) const { return i != other.i; }
|
||||
|
||||
inline const_iterator &operator++() { ++i; return *this; }
|
||||
inline const_iterator operator++(int) { const_iterator r = *this; ++i; return r; }
|
||||
inline const_iterator &operator--() { --i; return *this; }
|
||||
inline const_iterator operator--(int) { const_iterator r = *this; --i; return r; }
|
||||
inline const_iterator operator+(int j) const
|
||||
{ const_iterator r = *this; r.i += j; return r; }
|
||||
inline const_iterator operator-(int j) const { return operator+(-j); }
|
||||
inline const_iterator &operator+=(int j) { i += j; return *this; }
|
||||
inline const_iterator &operator-=(int j) { i -= j; return *this; }
|
||||
|
||||
inline bool operator==(const iterator &o) const { return i == o.i; }
|
||||
inline bool operator!=(const iterator &o) const { return i != o.i; }
|
||||
};
|
||||
friend class const_iterator;
|
||||
|
||||
// STL style
|
||||
inline iterator begin() { detach(); return iterator(this, 0); }
|
||||
inline const_iterator begin() const { return const_iterator(this, 0); }
|
||||
inline const_iterator constBegin() const { return const_iterator(this, 0); }
|
||||
inline iterator end() { detach(); return iterator(this, size()); }
|
||||
inline const_iterator end() const { return const_iterator(this, size()); }
|
||||
inline const_iterator constEnd() const { return const_iterator(this, size()); }
|
||||
iterator erase(iterator it);
|
||||
|
||||
// more Qt
|
||||
typedef iterator Iterator;
|
||||
typedef const_iterator ConstIterator;
|
||||
iterator find(const QString &key);
|
||||
const_iterator find(const QString &key) const { return constFind(key); }
|
||||
const_iterator constFind(const QString &key) const;
|
||||
iterator insert(const QString &key, const QJsonValue &value);
|
||||
|
||||
// STL compatibility
|
||||
typedef QJsonValue mapped_type;
|
||||
typedef QString key_type;
|
||||
typedef int size_type;
|
||||
|
||||
inline bool empty() const { return isEmpty(); }
|
||||
|
||||
private:
|
||||
friend class QJsonPrivate::Data;
|
||||
friend class QJsonValue;
|
||||
friend class QJsonDocument;
|
||||
friend class QJsonValueRef;
|
||||
|
||||
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonObject &);
|
||||
|
||||
QJsonObject(QJsonPrivate::Data *data, QJsonPrivate::Object *object);
|
||||
void detach(uint reserve = 0);
|
||||
void compact();
|
||||
|
||||
QString keyAt(int i) const;
|
||||
QJsonValue valueAt(int i) const;
|
||||
void setValueAt(int i, const QJsonValue &val);
|
||||
|
||||
QJsonPrivate::Data *d;
|
||||
QJsonPrivate::Object *o;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonObject &);
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QJSONOBJECT_H
|
752
src/corelib/json/qjsonparser.cpp
Normal file
752
src/corelib/json/qjsonparser.cpp
Normal file
@ -0,0 +1,752 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <qdebug.h>
|
||||
#include "qjsonparser_p.h"
|
||||
#include "qjson_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
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace QJsonPrivate;
|
||||
|
||||
Parser::Parser(const char *json, int length)
|
||||
: json(json), data(0), dataLength(0), current(0)
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
|
||||
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:
|
||||
if (!eatSpace())
|
||||
return 0;
|
||||
case EndArray:
|
||||
case EndObject:
|
||||
eatSpace();
|
||||
case Quote:
|
||||
break;
|
||||
default:
|
||||
token = 0;
|
||||
break;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/*
|
||||
JSON-text = object / array
|
||||
*/
|
||||
QJsonDocument Parser::parse()
|
||||
{
|
||||
#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);
|
||||
|
||||
char token = nextToken();
|
||||
DEBUG << token;
|
||||
if (token == BeginArray) {
|
||||
if (!parseArray())
|
||||
goto error;
|
||||
} else if (token == BeginObject) {
|
||||
if (!parseObject())
|
||||
goto error;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
END;
|
||||
{
|
||||
QJsonPrivate::Data *d = new QJsonPrivate::Data(data, current);
|
||||
return QJsonDocument(d);
|
||||
}
|
||||
|
||||
error:
|
||||
#ifdef PARSER_DEBUG
|
||||
qDebug() << ">>>>> parser error";
|
||||
#endif
|
||||
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()
|
||||
{
|
||||
int objectOffset = reserveSpace(sizeof(QJsonPrivate::Object));
|
||||
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();
|
||||
}
|
||||
|
||||
DEBUG << "end token=" << token;
|
||||
if (token != EndObject)
|
||||
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 Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
memcpy(data + table, parsedObject.offsets.constData(), tableSize);
|
||||
#else
|
||||
offset *o = (offset *)(data + table);
|
||||
for (int i = 0; i < tableSize; ++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;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
member = string name-separator value
|
||||
*/
|
||||
bool Parser::parseMember(int baseOffset)
|
||||
{
|
||||
int entryOffset = reserveSpace(sizeof(QJsonPrivate::Entry));
|
||||
BEGIN << "parseMember pos=" << entryOffset;
|
||||
|
||||
bool latin1;
|
||||
if (!parseString(&latin1))
|
||||
return false;
|
||||
char token = nextToken();
|
||||
if (token != NameSeparator)
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
array = begin-array [ value *( value-separator value ) ] end-array
|
||||
*/
|
||||
bool Parser::parseArray()
|
||||
{
|
||||
BEGIN << "parseArray";
|
||||
int arrayOffset = reserveSpace(sizeof(QJsonPrivate::Array));
|
||||
|
||||
QVarLengthArray<QJsonPrivate::Value> values;
|
||||
|
||||
if (!eatSpace())
|
||||
return false;
|
||||
if (*json == EndArray) {
|
||||
nextToken();
|
||||
} else {
|
||||
while (1) {
|
||||
QJsonPrivate::Value val;
|
||||
if (!parseValue(&val, arrayOffset))
|
||||
return false;
|
||||
values.append(val);
|
||||
char token = nextToken();
|
||||
if (token == EndArray)
|
||||
break;
|
||||
else if (token != ValueSeparator)
|
||||
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);
|
||||
memcpy(data + table, values.constData(), 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;
|
||||
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)
|
||||
return false;
|
||||
if (*json++ == 'u' &&
|
||||
*json++ == 'l' &&
|
||||
*json++ == 'l') {
|
||||
val->type = QJsonValue::Null;
|
||||
DEBUG << "value: null";
|
||||
END;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case 't':
|
||||
if (end - json < 4)
|
||||
return false;
|
||||
if (*json++ == 'r' &&
|
||||
*json++ == 'u' &&
|
||||
*json++ == 'e') {
|
||||
val->type = QJsonValue::Bool;
|
||||
val->value = true;
|
||||
DEBUG << "value: true";
|
||||
END;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case 'f':
|
||||
if (end - json < 5)
|
||||
return false;
|
||||
if (*json++ == 'a' &&
|
||||
*json++ == 'l' &&
|
||||
*json++ == 's' &&
|
||||
*json++ == 'e') {
|
||||
val->type = QJsonValue::Bool;
|
||||
val->value = false;
|
||||
DEBUG << "value: false";
|
||||
END;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case Quote: {
|
||||
val->type = QJsonValue::String;
|
||||
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;
|
||||
val->value = current - baseOffset;
|
||||
if (!parseArray())
|
||||
return false;
|
||||
DEBUG << "value: array";
|
||||
END;
|
||||
return true;
|
||||
case BeginObject:
|
||||
val->type = QJsonValue::Object;
|
||||
val->value = current - baseOffset;
|
||||
if (!parseObject())
|
||||
return false;
|
||||
DEBUG << "value: object";
|
||||
END;
|
||||
return true;
|
||||
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)
|
||||
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)
|
||||
return false;
|
||||
|
||||
int pos = reserveSpace(sizeof(double));
|
||||
*(quint64 *)(data + pos) = qToLittleEndian(ui);
|
||||
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');
|
||||
else if (digit >= 'A' && digit <= 'F')
|
||||
*result |= (digit - 'A');
|
||||
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 isUnicodeNonCharacter(uint ucs4)
|
||||
{
|
||||
// Unicode has a couple of "non-characters" that one can use internally,
|
||||
// but are not allowed to be used for text interchange.
|
||||
//
|
||||
// Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
|
||||
// U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
|
||||
// U+FDEF (inclusive)
|
||||
|
||||
return (ucs4 & 0xfffe) == 0xfffe
|
||||
|| (ucs4 - 0xfdd0U) < 16;
|
||||
}
|
||||
|
||||
static inline bool scanUtf8Char(const char *&json, const char *end, uint *result)
|
||||
{
|
||||
int need;
|
||||
uint min_uc;
|
||||
uint uc;
|
||||
uchar ch = *json++;
|
||||
if (ch < 128) {
|
||||
*result = ch;
|
||||
return true;
|
||||
} else if ((ch & 0xe0) == 0xc0) {
|
||||
uc = ch & 0x1f;
|
||||
need = 1;
|
||||
min_uc = 0x80;
|
||||
} else if ((ch & 0xf0) == 0xe0) {
|
||||
uc = ch & 0x0f;
|
||||
need = 2;
|
||||
min_uc = 0x800;
|
||||
} else if ((ch&0xf8) == 0xf0) {
|
||||
uc = ch & 0x07;
|
||||
need = 3;
|
||||
min_uc = 0x10000;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (json >= end - need)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < need; ++i) {
|
||||
ch = *json++;
|
||||
if ((ch&0xc0) != 0x80)
|
||||
return false;
|
||||
uc = (uc << 6) | (ch & 0x3f);
|
||||
}
|
||||
|
||||
if (isUnicodeNonCharacter(uc) || uc >= 0x110000 ||
|
||||
(uc < min_uc) || (uc >= 0xd800 && uc <= 0xdfff))
|
||||
return false;
|
||||
|
||||
*result = uc;
|
||||
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);
|
||||
BEGIN << "parse string stringPos=" << stringPos << json;
|
||||
while (json < end) {
|
||||
uint ch = 0;
|
||||
if (*json == '"')
|
||||
break;
|
||||
else if (*json == '\\') {
|
||||
if (!scanEscapeSequence(json, end, &ch))
|
||||
return false;
|
||||
} else {
|
||||
if (!scanUtf8Char(json, end, &ch))
|
||||
return false;
|
||||
}
|
||||
if (ch > 0xff) {
|
||||
*latin1 = false;
|
||||
break;
|
||||
}
|
||||
int pos = reserveSpace(1);
|
||||
DEBUG << " " << ch << (char)ch;
|
||||
data[pos] = (uchar)ch;
|
||||
}
|
||||
++json;
|
||||
DEBUG << "end of string";
|
||||
if (json >= end)
|
||||
return false;
|
||||
|
||||
// no unicode string, we are done
|
||||
if (*latin1) {
|
||||
// write string length
|
||||
*(QJsonPrivate::qle_ushort *)(data + stringPos) = current - outStart - sizeof(ushort);
|
||||
int pos = reserveSpace((4 - current) & 3);
|
||||
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))
|
||||
return false;
|
||||
} else {
|
||||
if (!scanUtf8Char(json, end, &ch))
|
||||
return false;
|
||||
}
|
||||
if (ch > 0xffff) {
|
||||
int pos = reserveSpace(4);
|
||||
*(QJsonPrivate::qle_ushort *)(data + pos) = QChar::highSurrogate(ch);
|
||||
*(QJsonPrivate::qle_ushort *)(data + pos + 2) = QChar::lowSurrogate(ch);
|
||||
} else {
|
||||
int pos = reserveSpace(2);
|
||||
*(QJsonPrivate::qle_ushort *)(data + pos) = (ushort)ch;
|
||||
}
|
||||
}
|
||||
++json;
|
||||
|
||||
if (json >= end)
|
||||
return false;
|
||||
|
||||
// write string length
|
||||
*(QJsonPrivate::qle_int *)(data + stringPos) = (current - outStart - sizeof(int))/2;
|
||||
int pos = reserveSpace((4 - current) & 3);
|
||||
while (pos & 3)
|
||||
data[pos++] = 0;
|
||||
END;
|
||||
return true;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
118
src/corelib/json/qjsonparser_p.h
Normal file
118
src/corelib/json/qjsonparser_p.h
Normal file
@ -0,0 +1,118 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QJSONPARSER_P_H
|
||||
#define QJSONPARSER_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <qjsondocument.h>
|
||||
#include <qvarlengtharray.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QJsonPrivate {
|
||||
|
||||
class Parser
|
||||
{
|
||||
public:
|
||||
Parser(const char *json, int length);
|
||||
|
||||
QJsonDocument parse();
|
||||
|
||||
class ParsedObject
|
||||
{
|
||||
public:
|
||||
ParsedObject(Parser *p, int pos) : parser(p), objectPosition(pos) {}
|
||||
void insert(uint offset);
|
||||
|
||||
Parser *parser;
|
||||
int objectPosition;
|
||||
QVarLengthArray<uint> offsets;
|
||||
|
||||
inline QJsonPrivate::Entry *entryAt(int i) const {
|
||||
return reinterpret_cast<QJsonPrivate::Entry *>(parser->data + objectPosition + offsets[i]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
inline bool eatSpace();
|
||||
inline char nextToken();
|
||||
|
||||
bool parseObject();
|
||||
bool parseArray();
|
||||
bool parseMember(int baseOffset);
|
||||
bool parseString(bool *latin1);
|
||||
bool parseValue(QJsonPrivate::Value *val, int baseOffset);
|
||||
bool parseNumber(QJsonPrivate::Value *val, int baseOffset);
|
||||
const char *json;
|
||||
const char *end;
|
||||
|
||||
char *data;
|
||||
int dataLength;
|
||||
int current;
|
||||
|
||||
inline int reserveSpace(int space) {
|
||||
if (current + space >= dataLength) {
|
||||
dataLength = 2*dataLength + space;
|
||||
data = (char *)realloc(data, dataLength);
|
||||
}
|
||||
int pos = current;
|
||||
current += space;
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
569
src/corelib/json/qjsonvalue.cpp
Normal file
569
src/corelib/json/qjsonvalue.cpp
Normal file
@ -0,0 +1,569 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <qjsonobject.h>
|
||||
#include <qjsonvalue.h>
|
||||
#include <qjsonarray.h>
|
||||
#include <qjsonarray.h>
|
||||
#include <qvariant.h>
|
||||
#include <qstringlist.h>
|
||||
#include <qdebug.h>
|
||||
|
||||
#include "qjson_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
\class QJsonValue
|
||||
\ingroup json
|
||||
\reentrant
|
||||
\since 5.0
|
||||
|
||||
\brief The QJsonValue class encapsulates a value in JSON.
|
||||
|
||||
A value in JSON can be one of 6 basic types:
|
||||
|
||||
JSON is a format to store structured data. It has 6 basic data types:
|
||||
|
||||
\list
|
||||
\o bool QJsonValue::Bool
|
||||
\o double QJsonValue::Double
|
||||
\o string QJsonValue::String
|
||||
\o array QJsonValue::Array
|
||||
\o object QJsonValue::Object
|
||||
\o null QJsonValue::Null
|
||||
\endlist
|
||||
|
||||
A value can represent any of the above data types. In addition, QJsonValue has one special
|
||||
flag to represent undefined values. This can be queried with isUndefined().
|
||||
|
||||
The type of the value can be queried with type() or accessors like isBool(), isString(), and so on.
|
||||
Likewise, the value can be converted to the type stored in it using the toBool(), toString() and so on.
|
||||
|
||||
Values are strictly typed internally and contrary to QVariant will not attempt to do any implicit type
|
||||
conversions. This implies that converting to a type that is not stored in the value will return a default
|
||||
constructed return value.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Creates a QJsonValue of type \a type.
|
||||
|
||||
The default is to create a Null value.
|
||||
*/
|
||||
QJsonValue::QJsonValue(Type type)
|
||||
: ui(0), d(0), t(type)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QJsonValue::QJsonValue(QJsonPrivate::Data *data, QJsonPrivate::Base *base, const QJsonPrivate::Value &v)
|
||||
: d(0)
|
||||
{
|
||||
t = (Type)(uint)v.type;
|
||||
switch (t) {
|
||||
case Undefined:
|
||||
case Null:
|
||||
dbl = 0;
|
||||
break;
|
||||
case Bool:
|
||||
b = v.toBoolean();
|
||||
break;
|
||||
case Double:
|
||||
dbl = v.toDouble(base);
|
||||
break;
|
||||
case String: {
|
||||
QString s = v.toString(base);
|
||||
stringData = s.data_ptr();
|
||||
stringData->ref.ref();
|
||||
break;
|
||||
}
|
||||
case Array:
|
||||
case Object:
|
||||
d = data;
|
||||
this->base = v.base(base);
|
||||
break;
|
||||
}
|
||||
if (d)
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a value of type Bool, with value \a b.
|
||||
*/
|
||||
QJsonValue::QJsonValue(bool b)
|
||||
: d(0), t(Bool)
|
||||
{
|
||||
this->b = b;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a value of type Double, with value \a n.
|
||||
*/
|
||||
QJsonValue::QJsonValue(double n)
|
||||
: d(0), t(Double)
|
||||
{
|
||||
this->dbl = n;
|
||||
}
|
||||
|
||||
/*!
|
||||
\overload
|
||||
Creates a value of type Double, with value \a n.
|
||||
*/
|
||||
QJsonValue::QJsonValue(int n)
|
||||
: d(0), t(Double)
|
||||
{
|
||||
this->dbl = n;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a value of type String, with value \a s.
|
||||
*/
|
||||
QJsonValue::QJsonValue(const QString &s)
|
||||
: d(0), t(String)
|
||||
{
|
||||
stringData = *(QStringData **)(&s);
|
||||
stringData->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a value of type String, with value \a s.
|
||||
*/
|
||||
QJsonValue::QJsonValue(const QLatin1String &s)
|
||||
: d(0), t(String)
|
||||
{
|
||||
// ### FIXME: Avoid creating the temp QString below
|
||||
QString str(s);
|
||||
stringData = *(QStringData **)(&str);
|
||||
stringData->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a value of type Array, with value \a a.
|
||||
*/
|
||||
QJsonValue::QJsonValue(const QJsonArray &a)
|
||||
: d(a.d), t(Array)
|
||||
{
|
||||
base = a.a;
|
||||
if (d)
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a value of type Object, with value \a o.
|
||||
*/
|
||||
QJsonValue::QJsonValue(const QJsonObject &o)
|
||||
: d(o.d), t(Object)
|
||||
{
|
||||
base = o.o;
|
||||
if (d)
|
||||
d->ref.ref();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Destroys the value.
|
||||
*/
|
||||
QJsonValue::~QJsonValue()
|
||||
{
|
||||
if (t == String && stringData && !stringData->ref.deref())
|
||||
free(stringData);
|
||||
|
||||
if (d && !d->ref.deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a copy of \a other.
|
||||
*/
|
||||
QJsonValue::QJsonValue(const QJsonValue &other)
|
||||
{
|
||||
t = other.t;
|
||||
d = other.d;
|
||||
ui = other.ui;
|
||||
if (d)
|
||||
d->ref.ref();
|
||||
|
||||
if (t == String && stringData)
|
||||
stringData->ref.ref();
|
||||
}
|
||||
|
||||
/*!
|
||||
Assigns the value stored in \a other to this object.
|
||||
*/
|
||||
QJsonValue &QJsonValue::operator =(const QJsonValue &other)
|
||||
{
|
||||
if (t == String && stringData && !stringData->ref.deref())
|
||||
free(stringData);
|
||||
|
||||
t = other.t;
|
||||
dbl = other.dbl;
|
||||
|
||||
if (d != other.d) {
|
||||
|
||||
if (d && !d->ref.deref())
|
||||
delete d;
|
||||
d = other.d;
|
||||
if (d)
|
||||
d->ref.ref();
|
||||
|
||||
}
|
||||
|
||||
if (t == String && stringData)
|
||||
stringData->ref.ref();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Converts \a variant to a QJsonValue and returns it.
|
||||
|
||||
The conversion will convert QVariant types as follows:
|
||||
|
||||
\list
|
||||
\o QVariant::Bool to Bool
|
||||
\o QVariant::Int
|
||||
\o QVariant::Double
|
||||
\o QVariant::LongLong
|
||||
\o QVariant::ULongLong
|
||||
\o QVariant::UInt to Double
|
||||
\o QVariant::String to String
|
||||
\o QVariant::StringList
|
||||
\o QVariant::VariantList to Array
|
||||
\o QVariant::VariantMap to Object
|
||||
\endlist
|
||||
|
||||
For all other QVariant types a conversion to a QString will be attempted. If the returned string
|
||||
is empty, a Null QJsonValue will be stored, otherwise a String value using the returned QString.
|
||||
|
||||
\sa toVariant()
|
||||
*/
|
||||
QJsonValue QJsonValue::fromVariant(const QVariant &variant)
|
||||
{
|
||||
switch (variant.type()) {
|
||||
case QVariant::Bool:
|
||||
return QJsonValue(variant.toBool());
|
||||
case QVariant::Int:
|
||||
case QVariant::Double:
|
||||
case QVariant::LongLong:
|
||||
case QVariant::ULongLong:
|
||||
case QVariant::UInt:
|
||||
return QJsonValue(variant.toDouble());
|
||||
case QVariant::String:
|
||||
return QJsonValue(variant.toString());
|
||||
case QVariant::StringList:
|
||||
return QJsonValue(QJsonArray::fromStringList(variant.toStringList()));
|
||||
case QVariant::List:
|
||||
return QJsonValue(QJsonArray::fromVariantList(variant.toList()));
|
||||
case QVariant::Map:
|
||||
return QJsonValue(QJsonObject::fromVariantMap(variant.toMap()));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
QString string = variant.toString();
|
||||
if (string.isEmpty())
|
||||
return QJsonValue();
|
||||
return QJsonValue(string);
|
||||
}
|
||||
|
||||
/*!
|
||||
Converts the value to a QVariant.
|
||||
|
||||
The QJsonValue types will be converted as follows:
|
||||
|
||||
\value Null QVariant()
|
||||
\value Bool QVariant::Bool
|
||||
\value Double QVariant::Double
|
||||
\value String QVariant::String
|
||||
\value Array QVariantList
|
||||
\value Object QVariantMap
|
||||
\value Undefined QVariant()
|
||||
|
||||
\sa fromVariant()
|
||||
*/
|
||||
QVariant QJsonValue::toVariant() const
|
||||
{
|
||||
switch (t) {
|
||||
case Bool:
|
||||
return b;
|
||||
case Double:
|
||||
return dbl;
|
||||
case String:
|
||||
return toString();
|
||||
case Array:
|
||||
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(base)).toVariantList();
|
||||
case Object:
|
||||
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(base)).toVariantMap();
|
||||
case Null:
|
||||
case Undefined:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
/*!
|
||||
\enum QJsonValue::Type
|
||||
|
||||
This enum describes the type of the JSON value.
|
||||
|
||||
\value Null A Null value
|
||||
\value Bool A boolean value. Use toBool() to convert to a bool.
|
||||
\value Double A double. Use toDouble() to convert to a double.
|
||||
\value String A string. Use toString() to convert to a QString.
|
||||
\value Array An array. Use toArray() to convert to a QJsonArray.
|
||||
\value Object An object. Use toObject() to convert to a QJsonObject.
|
||||
\value Undefined The value is undefined. This is usually returned as an
|
||||
error condition, when trying to read an out of bounds value
|
||||
in an array or a non existant key in an object.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns the type of the value.
|
||||
|
||||
\sa QJsonValue::Type
|
||||
*/
|
||||
QJsonValue::Type QJsonValue::type() const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
/*!
|
||||
Converts the value to a bool and returns it.
|
||||
|
||||
If type() is not bool, false will be returned.
|
||||
*/
|
||||
bool QJsonValue::toBool() const
|
||||
{
|
||||
if (t != Bool)
|
||||
return false;
|
||||
return b;
|
||||
}
|
||||
|
||||
/*!
|
||||
Converts the value to a double and returns it.
|
||||
|
||||
If type() is not Double, 0. will be returned.
|
||||
*/
|
||||
double QJsonValue::toDouble() const
|
||||
{
|
||||
if (t != Double)
|
||||
return 0;
|
||||
return dbl;
|
||||
}
|
||||
|
||||
/*!
|
||||
Converts the value to a QString and returns it.
|
||||
|
||||
If type() is not String, a QString() will be returned.
|
||||
*/
|
||||
QString QJsonValue::toString() const
|
||||
{
|
||||
if (t != String)
|
||||
return QString();
|
||||
stringData->ref.ref(); // the constructor below doesn't add a ref.
|
||||
return QString(*(const QConstStringData<1> *)stringData);
|
||||
}
|
||||
|
||||
/*!
|
||||
Converts the value to an array and returns it.
|
||||
|
||||
If type() is not Array, a QJsonArray() will be returned.
|
||||
*/
|
||||
QJsonArray QJsonValue::toArray() const
|
||||
{
|
||||
if (!d || t != Array)
|
||||
return QJsonArray();
|
||||
|
||||
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(base));
|
||||
}
|
||||
|
||||
/*!
|
||||
Converts the value to an object and returns it.
|
||||
|
||||
If type() is not Object, a QJsonObject() will be returned.
|
||||
*/
|
||||
QJsonObject QJsonValue::toObject() const
|
||||
{
|
||||
if (!d || t != Object)
|
||||
return QJsonObject();
|
||||
|
||||
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(base));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the value is equal to \a other.
|
||||
*/
|
||||
bool QJsonValue::operator==(const QJsonValue &other) const
|
||||
{
|
||||
if (t != other.t)
|
||||
return false;
|
||||
|
||||
switch (t) {
|
||||
case Undefined:
|
||||
case Null:
|
||||
break;
|
||||
case Bool:
|
||||
return b == other.b;
|
||||
case Double:
|
||||
return dbl == other.dbl;
|
||||
case String:
|
||||
return toString() == other.toString();
|
||||
case Array:
|
||||
return QJsonArray(d, static_cast<QJsonPrivate::Array *>(base))
|
||||
== QJsonArray(other.d, static_cast<QJsonPrivate::Array *>(other.base));
|
||||
case Object:
|
||||
return QJsonObject(d, static_cast<QJsonPrivate::Object *>(base))
|
||||
== QJsonObject(other.d, static_cast<QJsonPrivate::Object *>(other.base));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the value is not equal to \a other.
|
||||
*/
|
||||
bool QJsonValue::operator!=(const QJsonValue &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QJsonValue::detach()
|
||||
{
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
QJsonPrivate::Data *x = d->clone(base);
|
||||
x->ref.ref();
|
||||
if (!d->ref.deref())
|
||||
delete d;
|
||||
d = x;
|
||||
base = static_cast<QJsonPrivate::Object *>(d->header->root());
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\class QJsonValueRef
|
||||
\reentrant
|
||||
\brief The QJsonValueRef class is a helper class for QJsonValue.
|
||||
|
||||
\internal
|
||||
|
||||
\ingroup json
|
||||
|
||||
When you get an object of type QJsonValueRef, if you can assign to it,
|
||||
the assignment will apply to the character in the string from
|
||||
which you got the reference. That is its whole purpose in life.
|
||||
|
||||
You can use it exactly in the same way as a reference to a QJsonValue.
|
||||
|
||||
The QJsonValueRef becomes invalid once modifications are made to the
|
||||
string: if you want to keep the character, copy it into a QJsonValue.
|
||||
|
||||
Most of the QJsonValue member functions also exist in QJsonValueRef.
|
||||
However, they are not explicitly documented here.
|
||||
*/
|
||||
|
||||
|
||||
QJsonValueRef &QJsonValueRef::operator =(const QJsonValue &val)
|
||||
{
|
||||
if (is_object)
|
||||
o->setValueAt(index, val);
|
||||
else
|
||||
a->replace(index, val);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
QJsonArray QJsonValueRef::toArray() const
|
||||
{
|
||||
return toValue().toArray();
|
||||
}
|
||||
|
||||
QJsonObject QJsonValueRef::toObject() const
|
||||
{
|
||||
return toValue().toObject();
|
||||
}
|
||||
|
||||
QJsonValue QJsonValueRef::toValue() const
|
||||
{
|
||||
if (!is_object)
|
||||
return a->at(index);
|
||||
return o->valueAt(index);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug dbg, const QJsonValue &o)
|
||||
{
|
||||
switch (o.t) {
|
||||
case QJsonValue::Undefined:
|
||||
dbg.nospace() << "QJsonValue(undefined)";
|
||||
break;
|
||||
case QJsonValue::Null:
|
||||
dbg.nospace() << "QJsonValue(null)";
|
||||
break;
|
||||
case QJsonValue::Bool:
|
||||
dbg.nospace() << "QJsonValue(bool, " << o.toBool() << ")";
|
||||
break;
|
||||
case QJsonValue::Double:
|
||||
dbg.nospace() << "QJsonValue(double, " << o.toDouble() << ")";
|
||||
break;
|
||||
case QJsonValue::String:
|
||||
dbg.nospace() << "QJsonValue(string, " << o.toString() << ")";
|
||||
break;
|
||||
case QJsonValue::Array:
|
||||
dbg.nospace() << "QJsonValue(array, ";
|
||||
dbg.nospace() << o.toArray();
|
||||
dbg.nospace() << ")";
|
||||
break;
|
||||
case QJsonValue::Object:
|
||||
dbg.nospace() << "QJsonValue(object, ";
|
||||
dbg.nospace() << o.toObject();
|
||||
dbg.nospace() << ")";
|
||||
break;
|
||||
}
|
||||
return dbg.space();
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
186
src/corelib/json/qjsonvalue.h
Normal file
186
src/corelib/json/qjsonvalue.h
Normal file
@ -0,0 +1,186 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QJSONVALUE_H
|
||||
#define QJSONVALUE_H
|
||||
|
||||
#include <qglobal.h>
|
||||
#include <qstring.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QDebug;
|
||||
class QVariant;
|
||||
class QJsonArray;
|
||||
class QJsonObject;
|
||||
|
||||
namespace QJsonPrivate {
|
||||
class Data;
|
||||
class Base;
|
||||
class Object;
|
||||
class Header;
|
||||
class Array;
|
||||
class Value;
|
||||
class Entry;
|
||||
};
|
||||
|
||||
class Q_CORE_EXPORT QJsonValue
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
Null = 0x0,
|
||||
Bool = 0x1,
|
||||
Double = 0x2,
|
||||
String = 0x3,
|
||||
Array = 0x4,
|
||||
Object = 0x5,
|
||||
Undefined = 0x80
|
||||
};
|
||||
|
||||
QJsonValue(Type = Null);
|
||||
QJsonValue(bool b);
|
||||
QJsonValue(double n);
|
||||
QJsonValue(int n);
|
||||
QJsonValue(const QString &s);
|
||||
QJsonValue(const QLatin1String &s);
|
||||
QJsonValue(const QJsonArray &a);
|
||||
QJsonValue(const QJsonObject &o);
|
||||
|
||||
~QJsonValue();
|
||||
|
||||
QJsonValue(const QJsonValue &other);
|
||||
QJsonValue &operator =(const QJsonValue &other);
|
||||
|
||||
static QJsonValue fromVariant(const QVariant &variant);
|
||||
QVariant toVariant() const;
|
||||
|
||||
Type type() const;
|
||||
inline bool isNull() const { return type() == Null; }
|
||||
inline bool isBool() const { return type() == Bool; }
|
||||
inline bool isDouble() const { return type() == Double; }
|
||||
inline bool isString() const { return type() == String; }
|
||||
inline bool isArray() const { return type() == Array; }
|
||||
inline bool isObject() const { return type() == Object; }
|
||||
inline bool isUndefined() const { return type() == Undefined; }
|
||||
|
||||
bool toBool() const;
|
||||
double toDouble() const;
|
||||
QString toString() const;
|
||||
QJsonArray toArray() const;
|
||||
QJsonObject toObject() const;
|
||||
|
||||
bool operator==(const QJsonValue &other) const;
|
||||
bool operator!=(const QJsonValue &other) const;
|
||||
|
||||
private:
|
||||
// avoid implicit conversions from char * to bool
|
||||
inline QJsonValue(const void *) {}
|
||||
friend class QJsonPrivate::Value;
|
||||
friend class QJsonArray;
|
||||
friend class QJsonObject;
|
||||
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
|
||||
|
||||
QJsonValue(QJsonPrivate::Data *d, QJsonPrivate::Base *b, const QJsonPrivate::Value& v);
|
||||
|
||||
void detach();
|
||||
|
||||
union {
|
||||
quint64 ui;
|
||||
bool b;
|
||||
double dbl;
|
||||
QStringData *stringData;
|
||||
QJsonPrivate::Base *base;
|
||||
};
|
||||
QJsonPrivate::Data *d; // needed for Objects and Arrays
|
||||
Type t;
|
||||
};
|
||||
|
||||
class Q_CORE_EXPORT QJsonValueRef
|
||||
{
|
||||
public:
|
||||
QJsonValueRef(QJsonArray *array, int idx)
|
||||
: a(array), is_object(false), index(idx) {}
|
||||
QJsonValueRef(QJsonObject *object, int idx)
|
||||
: o(object), is_object(true), index(idx) {}
|
||||
|
||||
inline operator QJsonValue() const { return toValue(); }
|
||||
QJsonValueRef &operator = (const QJsonValue &val);
|
||||
|
||||
inline QJsonValue::Type type() const { return toValue().type(); }
|
||||
inline bool isNull() const { return type() == QJsonValue::Null; }
|
||||
inline bool isBool() const { return type() == QJsonValue::Bool; }
|
||||
inline bool isDouble() const { return type() == QJsonValue::Double; }
|
||||
inline bool isString() const { return type() == QJsonValue::String; }
|
||||
inline bool isArray() const { return type() == QJsonValue::Array; }
|
||||
inline bool isObject() const { return type() == QJsonValue::Object; }
|
||||
inline bool isUndefined() const { return type() == QJsonValue::Undefined; }
|
||||
|
||||
inline bool toBool() const { return toValue().toBool(); }
|
||||
inline double toDouble() const { return toValue().toDouble(); }
|
||||
inline QString toString() const { return toValue().toString(); }
|
||||
QJsonArray toArray() const;
|
||||
QJsonObject toObject() const;
|
||||
|
||||
inline bool operator==(const QJsonValue &other) const { return toValue() == other; }
|
||||
inline bool operator!=(const QJsonValue &other) const { return toValue() != other; }
|
||||
|
||||
private:
|
||||
QJsonValue toValue() const;
|
||||
|
||||
union {
|
||||
QJsonArray *a;
|
||||
QJsonObject *o;
|
||||
};
|
||||
uint is_object : 1;
|
||||
uint index : 31;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QJSONVALUE_H
|
280
src/corelib/json/qjsonwriter.cpp
Normal file
280
src/corelib/json/qjsonwriter.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qjsonwriter_p.h"
|
||||
#include "qjson_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace QJsonPrivate;
|
||||
|
||||
static void objectContentToJson(const QJsonPrivate::Object *o, QByteArray &json, int indent, bool compact);
|
||||
static void arrayContentToJson(const QJsonPrivate::Array *a, QByteArray &json, int indent, bool compact);
|
||||
|
||||
// some code from qutfcodec.cpp, inlined here for performance reasons
|
||||
// to allow fast escaping of strings
|
||||
static inline bool isUnicodeNonCharacter(uint ucs4)
|
||||
{
|
||||
// Unicode has a couple of "non-characters" that one can use internally,
|
||||
// but are not allowed to be used for text interchange.
|
||||
//
|
||||
// Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
|
||||
// U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
|
||||
// U+FDEF (inclusive)
|
||||
|
||||
return (ucs4 & 0xfffe) == 0xfffe
|
||||
|| (ucs4 - 0xfdd0U) < 16;
|
||||
}
|
||||
|
||||
static inline uchar hexdig(uint u)
|
||||
{
|
||||
return (u < 0xa ? '0' + u : 'a' + u - 0xa);
|
||||
}
|
||||
|
||||
static QByteArray escapedString(const QString &s)
|
||||
{
|
||||
const uchar replacement = '?';
|
||||
QByteArray ba(s.length(), Qt::Uninitialized);
|
||||
|
||||
uchar *cursor = (uchar *)ba.data();
|
||||
const uchar *ba_end = cursor + ba.length();
|
||||
|
||||
const QChar *ch = (const QChar *)s.constData();
|
||||
const QChar *end = ch + s.length();
|
||||
|
||||
int surrogate_high = -1;
|
||||
|
||||
while (ch < end) {
|
||||
if (cursor >= ba_end - 6) {
|
||||
// ensure we have enough space
|
||||
int pos = cursor - (const uchar *)ba.constData();
|
||||
ba.resize(ba.size()*2);
|
||||
cursor = (uchar *)ba.data() + pos;
|
||||
ba_end = (const uchar *)ba.constData() + ba.length();
|
||||
}
|
||||
|
||||
uint u = ch->unicode();
|
||||
if (surrogate_high >= 0) {
|
||||
if (ch->isLowSurrogate()) {
|
||||
u = QChar::surrogateToUcs4(surrogate_high, u);
|
||||
surrogate_high = -1;
|
||||
} else {
|
||||
// high surrogate without low
|
||||
*cursor = replacement;
|
||||
++ch;
|
||||
surrogate_high = -1;
|
||||
continue;
|
||||
}
|
||||
} else if (ch->isLowSurrogate()) {
|
||||
// low surrogate without high
|
||||
*cursor = replacement;
|
||||
++ch;
|
||||
continue;
|
||||
} else if (ch->isHighSurrogate()) {
|
||||
surrogate_high = u;
|
||||
++ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (u < 0x80) {
|
||||
if (u < 0x20 || u == 0x22 || u == 0x5c) {
|
||||
*cursor++ = '\\';
|
||||
switch (u) {
|
||||
case 0x22:
|
||||
*cursor++ = '"';
|
||||
break;
|
||||
case 0x5c:
|
||||
*cursor++ = '\\';
|
||||
break;
|
||||
case 0x8:
|
||||
*cursor++ = 'b';
|
||||
break;
|
||||
case 0xc:
|
||||
*cursor++ = 'f';
|
||||
break;
|
||||
case 0xa:
|
||||
*cursor++ = 'n';
|
||||
break;
|
||||
case 0xd:
|
||||
*cursor++ = 'r';
|
||||
break;
|
||||
case 0x9:
|
||||
*cursor++ = 't';
|
||||
break;
|
||||
default:
|
||||
*cursor++ = 'u';
|
||||
*cursor++ = '0';
|
||||
*cursor++ = '0';
|
||||
*cursor++ = hexdig(u>>4);
|
||||
*cursor++ = hexdig(u & 0xf);
|
||||
}
|
||||
} else {
|
||||
*cursor++ = (uchar)u;
|
||||
}
|
||||
} else {
|
||||
if (u < 0x0800) {
|
||||
*cursor++ = 0xc0 | ((uchar) (u >> 6));
|
||||
} else {
|
||||
// is it one of the Unicode non-characters?
|
||||
if (isUnicodeNonCharacter(u)) {
|
||||
*cursor++ = replacement;
|
||||
++ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (u > 0xffff) {
|
||||
*cursor++ = 0xf0 | ((uchar) (u >> 18));
|
||||
*cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f);
|
||||
} else {
|
||||
*cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f);
|
||||
}
|
||||
*cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f);
|
||||
}
|
||||
*cursor++ = 0x80 | ((uchar) (u&0x3f));
|
||||
}
|
||||
++ch;
|
||||
}
|
||||
|
||||
ba.resize(cursor - (const uchar *)ba.constData());
|
||||
return ba;
|
||||
}
|
||||
|
||||
static void valueToJson(const QJsonPrivate::Base *b, const QJsonPrivate::Value &v, QByteArray &json, int indent, bool compact)
|
||||
{
|
||||
QJsonValue::Type type = (QJsonValue::Type)(uint)v.type;
|
||||
switch (type) {
|
||||
case QJsonValue::Bool:
|
||||
json += v.toBoolean() ? "true" : "false";
|
||||
break;
|
||||
case QJsonValue::Double:
|
||||
json += QByteArray::number(v.toDouble(b));
|
||||
break;
|
||||
case QJsonValue::String:
|
||||
json += '"';
|
||||
json += escapedString(v.toString(b));
|
||||
json += '"';
|
||||
break;
|
||||
case QJsonValue::Array:
|
||||
json += compact ? "[" : "[\n";
|
||||
arrayContentToJson(static_cast<QJsonPrivate::Array *>(v.base(b)), json, indent + (compact ? 0 : 1), compact);
|
||||
json += QByteArray(4*indent, ' ');
|
||||
json += "]";
|
||||
break;
|
||||
case QJsonValue::Object:
|
||||
json += compact ? "{" : "{\n";
|
||||
objectContentToJson(static_cast<QJsonPrivate::Object *>(v.base(b)), json, indent + (compact ? 0 : 1), compact);
|
||||
json += QByteArray(4*indent, ' ');
|
||||
json += "}";
|
||||
break;
|
||||
case QJsonValue::Null:
|
||||
default:
|
||||
json += "null";
|
||||
}
|
||||
}
|
||||
|
||||
static void arrayContentToJson(const QJsonPrivate::Array *a, QByteArray &json, int indent, bool compact)
|
||||
{
|
||||
if (!a || !a->length)
|
||||
return;
|
||||
|
||||
QByteArray indentString(4*indent, ' ');
|
||||
|
||||
uint i = 0;
|
||||
while (1) {
|
||||
json += indentString;
|
||||
valueToJson(a, a->at(i), json, indent, compact);
|
||||
|
||||
if (++i == a->length) {
|
||||
if (!compact)
|
||||
json += '\n';
|
||||
break;
|
||||
}
|
||||
|
||||
json += compact ? "," : ",\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void objectContentToJson(const QJsonPrivate::Object *o, QByteArray &json, int indent, bool compact)
|
||||
{
|
||||
if (!o || !o->length)
|
||||
return;
|
||||
|
||||
QByteArray indentString(4*indent, ' ');
|
||||
|
||||
uint i = 0;
|
||||
while (1) {
|
||||
QJsonPrivate::Entry *e = o->entryAt(i);
|
||||
json += indentString;
|
||||
json += '"';
|
||||
json += escapedString(e->key());
|
||||
json += "\": ";
|
||||
valueToJson(o, e->value, json, indent, compact);
|
||||
|
||||
if (++i == o->length) {
|
||||
if (!compact)
|
||||
json += '\n';
|
||||
break;
|
||||
}
|
||||
|
||||
json += compact ? "," : ",\n";
|
||||
}
|
||||
}
|
||||
|
||||
void Writer::objectToJson(const QJsonPrivate::Object *o, QByteArray &json, int indent, bool compact)
|
||||
{
|
||||
json.reserve(json.size() + (o ? o->size : 16));
|
||||
json += compact ? "{" : "{\n";
|
||||
objectContentToJson(o, json, indent + (compact ? 0 : 1), compact);
|
||||
json += QByteArray(4*indent, ' ');
|
||||
json += compact ? "}" : "}\n";
|
||||
}
|
||||
|
||||
void Writer::arrayToJson(const QJsonPrivate::Array *a, QByteArray &json, int indent, bool compact)
|
||||
{
|
||||
json.reserve(json.size() + (a ? a->size : 16));
|
||||
json += compact ? "[" : "[\n";
|
||||
arrayContentToJson(a, json, indent + (compact ? 0 : 1), compact);
|
||||
json += QByteArray(4*indent, ' ');
|
||||
json += compact ? "]" : "]\n";
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
73
src/corelib/json/qjsonwriter_p.h
Normal file
73
src/corelib/json/qjsonwriter_p.h
Normal file
@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QJSONWRITER_P_H
|
||||
#define QJSONWRITER_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
#include <qjsonvalue.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QJsonPrivate
|
||||
{
|
||||
|
||||
class Writer
|
||||
{
|
||||
public:
|
||||
static void objectToJson(const QJsonPrivate::Object *o, QByteArray &json, int indent, bool compact = false);
|
||||
static void arrayToJson(const QJsonPrivate::Array *a, QByteArray &json, int indent, bool compact = false);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@ SUBDIRS=\
|
||||
global \
|
||||
io \
|
||||
itemmodels \
|
||||
json \
|
||||
kernel \
|
||||
plugin \
|
||||
statemachine \
|
||||
|
6
tests/auto/corelib/json/json.pro
Normal file
6
tests/auto/corelib/json/json.pro
Normal file
@ -0,0 +1,6 @@
|
||||
TARGET = tst_qtjson
|
||||
QT = core testlib
|
||||
CONFIG -= app_bundle
|
||||
CONFIG += testcase
|
||||
|
||||
SOURCES += tst_qtjson.cpp
|
BIN
tests/auto/corelib/json/test.bjson
Normal file
BIN
tests/auto/corelib/json/test.bjson
Normal file
Binary file not shown.
66
tests/auto/corelib/json/test.json
Normal file
66
tests/auto/corelib/json/test.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/auto/corelib/json/test2.json
Normal file
1
tests/auto/corelib/json/test2.json
Normal file
@ -0,0 +1 @@
|
||||
{ "foo": ["ab"] }
|
1535
tests/auto/corelib/json/tst_qtjson.cpp
Normal file
1535
tests/auto/corelib/json/tst_qtjson.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = \
|
||||
io \
|
||||
json \
|
||||
kernel \
|
||||
thread \
|
||||
tools \
|
||||
@ -14,4 +15,4 @@ TRUSTED_BENCHMARKS += \
|
||||
thread/qthreadstorage \
|
||||
io/qdir/tree
|
||||
|
||||
include(../trusted-benchmarks.pri)
|
||||
include(../trusted-benchmarks.pri)
|
||||
|
6
tests/benchmarks/corelib/json/json.pro
Normal file
6
tests/benchmarks/corelib/json/json.pro
Normal file
@ -0,0 +1,6 @@
|
||||
TARGET = tst_bench_qtbinaryjson
|
||||
QT = core testlib
|
||||
CONFIG -= app_bundle
|
||||
CONFIG += testcase
|
||||
|
||||
SOURCES += tst_bench_qtbinaryjson.cpp
|
19
tests/benchmarks/corelib/json/numbers.json
Normal file
19
tests/benchmarks/corelib/json/numbers.json
Normal file
@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1
|
||||
},
|
||||
[
|
||||
-1234567890,
|
||||
-1234567890,
|
||||
-1234567890,
|
||||
1234567890,
|
||||
1234567890,
|
||||
1234567890
|
||||
]
|
||||
]
|
126
tests/benchmarks/corelib/json/tst_bench_qtbinaryjson.cpp
Normal file
126
tests/benchmarks/corelib/json/tst_bench_qtbinaryjson.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtTest>
|
||||
#include <qjsondocument.h>
|
||||
#include <qjsonobject.h>
|
||||
|
||||
class BenchmarkQtBinaryJson: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BenchmarkQtBinaryJson(QObject *parent = 0);
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
void parseNumbers();
|
||||
void parseJson();
|
||||
void parseJsonToVariant();
|
||||
};
|
||||
|
||||
BenchmarkQtBinaryJson::BenchmarkQtBinaryJson(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtBinaryJson::initTestCase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtBinaryJson::cleanupTestCase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtBinaryJson::init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtBinaryJson::cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtBinaryJson::parseNumbers()
|
||||
{
|
||||
QFile file(QLatin1String("numbers.json"));
|
||||
file.open(QFile::ReadOnly);
|
||||
QByteArray testJson = file.readAll();
|
||||
|
||||
QBENCHMARK {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(testJson);
|
||||
QJsonObject object = doc.object();
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkQtBinaryJson::parseJson()
|
||||
{
|
||||
QFile file(QLatin1String("../../../auto/corelib/json/test.json"));
|
||||
file.open(QFile::ReadOnly);
|
||||
QByteArray testJson = file.readAll();
|
||||
|
||||
QBENCHMARK {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(testJson);
|
||||
QJsonObject object = doc.object();
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkQtBinaryJson::parseJsonToVariant()
|
||||
{
|
||||
QFile file(QLatin1String("../../../auto/corelib/json/test.json"));
|
||||
file.open(QFile::ReadOnly);
|
||||
QByteArray testJson = file.readAll();
|
||||
|
||||
QBENCHMARK {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(testJson);
|
||||
QVariant v = doc.toVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(BenchmarkQtBinaryJson)
|
||||
#include "tst_bench_qtbinaryjson.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user