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:
Lars Knoll 2012-01-18 10:12:50 +01:00 committed by Qt by Nokia
parent 4b8ceb41ae
commit 37a7b035f8
27 changed files with 8193 additions and 1 deletions

118
doc/src/corelib/json.qdoc Normal file
View 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.
*/

View File

@ -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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -6,6 +6,7 @@ SUBDIRS=\
global \
io \
itemmodels \
json \
kernel \
plugin \
statemachine \

View File

@ -0,0 +1,6 @@
TARGET = tst_qtjson
QT = core testlib
CONFIG -= app_bundle
CONFIG += testcase
SOURCES += tst_qtjson.cpp

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{ "foo": ["ab"] }

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -0,0 +1,6 @@
TARGET = tst_bench_qtbinaryjson
QT = core testlib
CONFIG -= app_bundle
CONFIG += testcase
SOURCES += tst_bench_qtbinaryjson.cpp

View 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
]
]

View 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"