Import json support from playground/qtbinaryjson
authorLars Knoll <lars.knoll@nokia.com>
Wed, 18 Jan 2012 09:12:50 +0000 (10:12 +0100)
committerQt by Nokia <qt-info@nokia.com>
Tue, 24 Jan 2012 14:28:20 +0000 (15:28 +0100)
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>
27 files changed:
doc/src/corelib/json.qdoc [new file with mode: 0644]
src/corelib/corelib.pro
src/corelib/json/json.pri [new file with mode: 0644]
src/corelib/json/qjson.cpp [new file with mode: 0644]
src/corelib/json/qjson_p.h [new file with mode: 0644]
src/corelib/json/qjsonarray.cpp [new file with mode: 0644]
src/corelib/json/qjsonarray.h [new file with mode: 0644]
src/corelib/json/qjsondocument.cpp [new file with mode: 0644]
src/corelib/json/qjsondocument.h [new file with mode: 0644]
src/corelib/json/qjsonobject.cpp [new file with mode: 0644]
src/corelib/json/qjsonobject.h [new file with mode: 0644]
src/corelib/json/qjsonparser.cpp [new file with mode: 0644]
src/corelib/json/qjsonparser_p.h [new file with mode: 0644]
src/corelib/json/qjsonvalue.cpp [new file with mode: 0644]
src/corelib/json/qjsonvalue.h [new file with mode: 0644]
src/corelib/json/qjsonwriter.cpp [new file with mode: 0644]
src/corelib/json/qjsonwriter_p.h [new file with mode: 0644]
tests/auto/corelib/corelib.pro
tests/auto/corelib/json/json.pro [new file with mode: 0644]
tests/auto/corelib/json/test.bjson [new file with mode: 0644]
tests/auto/corelib/json/test.json [new file with mode: 0644]
tests/auto/corelib/json/test2.json [new file with mode: 0644]
tests/auto/corelib/json/tst_qtjson.cpp [new file with mode: 0644]
tests/benchmarks/corelib/corelib.pro
tests/benchmarks/corelib/json/json.pro [new file with mode: 0644]
tests/benchmarks/corelib/json/numbers.json [new file with mode: 0644]
tests/benchmarks/corelib/json/tst_bench_qtbinaryjson.cpp [new file with mode: 0644]

diff --git a/doc/src/corelib/json.qdoc b/doc/src/corelib/json.qdoc
new file mode 100644 (file)
index 0000000..57a4986
--- /dev/null
@@ -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.
+*/
index c84aed4..ba741c6 100644 (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)
diff --git a/src/corelib/json/json.pri b/src/corelib/json/json.pri
new file mode 100644 (file)
index 0000000..1a4e2a7
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjson.cpp b/src/corelib/json/qjson.cpp
new file mode 100644 (file)
index 0000000..dedddfc
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h
new file mode 100644 (file)
index 0000000..304aa9c
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp
new file mode 100644 (file)
index 0000000..d5d9e54
--- /dev/null
@@ -0,0 +1,1014 @@
+/****************************************************************************
+**
+** 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 <qjsonvalue.h>
+#include <qstringlist.h>
+#include <qdebug.h>
+
+#include "qjsonwriter_p.h"
+#include "qjson_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \class QJsonArray
+    \ingroup json
+    \reentrant
+    \since 5.0
+
+    \brief The QJsonArray class encapsulates a JSON array.
+
+    A JSON array is a list of values. The list can be manipulated by inserting and
+    removing QJsonValue's from the array.
+
+    A QJsonArray can be converted to and from a QVariantList. You can query the
+    number of entries with size(), insert(), and remove() entries from it
+    and iterate over its content using the standard C++ iterator pattern.
+
+    QJsonArray is an implicitly shared class and shares the data with the document
+    it has been created from as long as it is not being modified.
+
+    You can convert the array to and from text based JSON through QJsonDocument.
+*/
+
+/*!
+    Creates an empty array.
+ */
+QJsonArray::QJsonArray()
+    : d(0), a(0)
+{
+}
+
+/*!
+    \internal
+ */
+QJsonArray::QJsonArray(QJsonPrivate::Data *data, QJsonPrivate::Array *array)
+    : d(data), a(array)
+{
+    d->ref.ref();
+}
+
+/*!
+    Deletes the array.
+ */
+QJsonArray::~QJsonArray()
+{
+    if (d && !d->ref.deref())
+        delete d;
+}
+
+/*!
+    Creates a copy of \a other.
+
+    Since QJsonArray is implicitly shared, the copy is shallow
+    as long as the object doesn't get modified.
+ */
+QJsonArray::QJsonArray(const QJsonArray &other)
+{
+    d = other.d;
+    a = other.a;
+    if (d)
+        d->ref.ref();
+}
+
+/*!
+    Assigns \a other to this array.
+ */
+QJsonArray &QJsonArray::operator =(const QJsonArray &other)
+{
+    if (d != other.d) {
+        if (d && !d->ref.deref())
+            delete d;
+        d = other.d;
+        a = other.a;
+        if (d)
+            d->ref.ref();
+    }
+
+    return *this;
+}
+
+/*!
+    Converts the string list \a list to a QJsonArray.
+
+    The values in \a list will be converted to JSON values.
+
+    \sa toVariantList, QJsonValue::fromString
+ */
+QJsonArray QJsonArray::fromStringList(const QStringList &list)
+{
+    QJsonArray array;
+    for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it)
+        array.append(QJsonValue(*it));
+    return array;
+}
+
+/*!
+    Converts the variant list \a list to a QJsonArray.
+
+    The QVariant values in \a list will be converted to JSON values.
+
+    \sa toVariantList, QJsonValue::fromVariant
+ */
+QJsonArray QJsonArray::fromVariantList(const QVariantList &list)
+{
+    QJsonArray array;
+    for (QVariantList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it)
+        array.append(QJsonValue::fromVariant(*it));
+    return array;
+}
+
+/*!
+    Converts this object to a QVariantList.
+
+    Returns the created map.
+ */
+QVariantList QJsonArray::toVariantList() const
+{
+    QVariantList list;
+
+    if (a) {
+        for (int i = 0; i < (int)a->length; ++i)
+            list.append(QJsonValue(d, a, a->at(i)).toVariant());
+    }
+    return list;
+}
+
+
+/*!
+    Returns the number of values stored in the array.
+ */
+int QJsonArray::size() const
+{
+    if (!d)
+        return 0;
+
+    return (int)a->length;
+}
+
+/*!
+    Returns \c true if the object is empty. This is the same as size() == 0.
+
+    \sa size
+ */
+bool QJsonArray::isEmpty() const
+{
+    if (!d)
+        return true;
+
+    return !a->length;
+}
+
+/*!
+    Returns a QJsonValue representing the value for index \a i.
+
+    The returned QJsonValue is \c Undefined, if \a i is out of bounds.
+
+ */
+QJsonValue QJsonArray::at(int i) const
+{
+    if (!a || i < 0 || i >= (int)a->length)
+        return QJsonValue(QJsonValue::Undefined);
+
+    return QJsonValue(d, a, a->at(i));
+}
+
+/*!
+    Returns the first value stored in the array.
+
+    Same as \c at(0).
+
+    \sa at
+ */
+QJsonValue QJsonArray::first() const
+{
+    return at(0);
+}
+
+/*!
+    Returns the last value stored in the array.
+
+    Same as \c{at(size() - 1)}.
+
+    \sa at
+ */
+QJsonValue QJsonArray::last() const
+{
+    return at(a ? (a->length - 1) : 0);
+}
+
+/*!
+    Inserts \a value at the beginning of the array.
+
+    This is the same as \c{insert(0, \a value)}.
+
+    \sa append(), insert()
+ */
+void QJsonArray::prepend(const QJsonValue &value)
+{
+    insert(0, value);
+}
+
+/*!
+    Inserts \a value at the end of the array.
+
+    \sa prepend(), insert()
+ */
+void QJsonArray::append(const QJsonValue &value)
+{
+    insert(a ? a->length : 0, value);
+}
+
+/*!
+    Removes the value at index position \a i. \a i must be a valid
+    index position in the array (i.e., \c{0 <= \a i < size()}).
+
+    \sa insert(), replace()
+ */
+void QJsonArray::removeAt(int i)
+{
+    if (!a || i < 0 || i >= (int)a->length)
+        return;
+
+    detach();
+    a->removeItems(i, 1);
+    ++d->compactionCounter;
+    if (d->compactionCounter > 32 && d->compactionCounter >= (int)a->length/2)
+        compact();
+}
+
+/*! \fn void QJsonArray::removeFirst()
+
+    Removes the first item in the array. Calling this function is
+    equivalent to calling \c{removeAt(0)}. The array must not be empty. If
+    the array can be empty, call isEmpty() before calling this
+    function.
+
+    \sa removeAt(), takeFirst()
+*/
+
+/*! \fn void QJsonArray::removeLast()
+
+    Removes the last item in the array. Calling this function is
+    equivalent to calling \c{removeAt(size() - 1)}. The array must not be
+    empty. If the array can be empty, call isEmpty() before calling
+    this function.
+
+    \sa removeAt(), takeLast()
+*/
+
+/*!
+    Removes the item at index position \a i and returns it. \a i must
+    be a valid index position in the array (i.e., \c{0 <= \a i < size()}).
+
+    If you don't use the return value, removeAt() is more efficient.
+
+    \sa removeAt()
+ */
+QJsonValue QJsonArray::takeAt(int i)
+{
+    if (!a || i < 0 || i >= (int)a->length)
+        return QJsonValue(QJsonValue::Undefined);
+
+    detach();
+
+    QJsonValue v(d, a, a->at(i));
+    v.detach();
+
+    removeAt(i);
+
+    return v;
+}
+
+/*!
+    Inserts \a value at index position \a i in the array. If \a i
+    is \c 0, the value is prepended to the array. If \a i is size(), the
+    value is appended to the array.
+
+    \sa append(), prepend(), replace(), removeAt()
+ */
+void QJsonArray::insert(int i, const QJsonValue &value)
+{
+    Q_ASSERT (i >= 0 && i <= (int)(a ? a->length : 0));
+
+    bool compressed;
+    int valueSize = QJsonPrivate::Value::requiredStorage(value, &compressed);
+
+    detach(valueSize + sizeof(QJsonPrivate::Value));
+
+    if (!a->length)
+        a->tableOffset = sizeof(QJsonPrivate::Array);
+
+    int valueOffset = a->reserveSpace(valueSize, i, 1, false);
+    QJsonPrivate::Value &v = (*a)[i];
+    v.type = (value.t == QJsonValue::Undefined ? QJsonValue::Null : value.t);
+    v.latinOrIntValue = compressed;
+    v.latinKey = false;
+    v.value = QJsonPrivate::Value::valueToStore(value, valueOffset);
+    if (valueSize)
+        QJsonPrivate::Value::copyData(value, (char *)a + valueOffset, compressed);
+}
+
+/*!
+    Replaces the item at index position \a i with \a value. \a i must
+    be a valid index position in the array (i.e., \c{0 <= \a i < size()}).
+
+    \sa operator[](), removeAt()
+ */
+void QJsonArray::replace(int i, const QJsonValue &value)
+{
+    Q_ASSERT (a && i >= 0 && i < (int)(a->length));
+
+    bool compressed;
+    int valueSize = QJsonPrivate::Value::requiredStorage(value, &compressed);
+
+    detach(valueSize);
+
+    if (!a->length)
+        a->tableOffset = sizeof(QJsonPrivate::Array);
+
+    int valueOffset = a->reserveSpace(valueSize, i, 1, true);
+    QJsonPrivate::Value &v = (*a)[i];
+    v.type = (value.t == QJsonValue::Undefined ? QJsonValue::Null : value.t);
+    v.latinOrIntValue = compressed;
+    v.latinKey = false;
+    v.value = QJsonPrivate::Value::valueToStore(value, valueOffset);
+    if (valueSize)
+        QJsonPrivate::Value::copyData(value, (char *)a + valueOffset, compressed);
+
+    ++d->compactionCounter;
+    if (d->compactionCounter > 32 && d->compactionCounter >= (int)a->length/2)
+        compact();
+}
+
+/*!
+    Returns \c true if the array contains an occurrence of \a value, otherwise \c false.
+
+    \sa count()
+ */
+bool QJsonArray::contains(const QJsonValue &value) const
+{
+    for (int i = 0; i < size(); i++) {
+        if (at(i) == value)
+            return true;
+    }
+    return false;
+}
+
+/*!
+    Returns the value at index position \a i as a modifiable reference.
+    \a i must be a valid index position in the array (i.e., \c{0 <= \a i <
+    size()}).
+
+    The return value is of type QJsonValueRef, a helper class for QJsonArray
+    and QJsonObject. When you get an object of type QJsonValueRef, you can
+    use it as if it were a reference to a QJsonValue. If you assign to it,
+    the assignment will apply to the character in the QJsonArray of QJsonObject
+    from which you got the reference.
+
+    \sa at(), value()
+ */
+QJsonValueRef QJsonArray::operator [](int i)
+{
+    Q_ASSERT(a && i >= 0 && i < (int)a->length);
+    return QJsonValueRef(this, i);
+}
+
+/*!
+    \overload
+
+    Same as at().
+ */
+QJsonValue QJsonArray::operator[](int i) const
+{
+    return at(i);
+}
+
+/*!
+    Returns \c true if this array is equal to \a other.
+ */
+bool QJsonArray::operator==(const QJsonArray &other) const
+{
+    if (a == other.a)
+        return true;
+
+    if (!a)
+        return !other.a->length;
+    if (!other.a)
+        return !a->length;
+    if (a->length != other.a->length)
+        return false;
+
+    for (int i = 0; i < (int)a->length; ++i) {
+        if (QJsonValue(d, a, a->at(i)) != QJsonValue(other.d, other.a, other.a->at(i)))
+            return false;
+    }
+    return true;
+}
+
+/*!
+    Returns \c true if this array is not equal to \a other.
+ */
+bool QJsonArray::operator!=(const QJsonArray &other) const
+{
+    return !(*this == other);
+}
+
+/*! \fn QJsonArray::iterator QJsonArray::begin()
+
+    Returns an \l{STL-style iterator} pointing to the first item in
+    the array.
+
+    \sa constBegin(), end()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::begin() const
+
+    \overload
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::constBegin() const
+
+    Returns a const \l{STL-style iterator} pointing to the first item
+    in the array.
+
+    \sa begin(), constEnd()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::end()
+
+    Returns an \l{STL-style iterator} pointing to the imaginary item
+    after the last item in the array.
+
+    \sa begin(), constEnd()
+*/
+
+/*! \fn const_iterator QJsonArray::end() const
+
+    \overload
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::constEnd() const
+
+    Returns a const \l{STL-style iterator} pointing to the imaginary
+    item after the last item in the array.
+
+    \sa constBegin(), end()
+*/
+
+/*! \fn void QJsonArray::push_back(const T &value)
+
+    This function is provided for STL compatibility. It is equivalent
+    to \l{QJsonArray::append()}{append(\a value)}.
+*/
+
+/*! \fn void QJsonArray::push_front(const T &value)
+
+    This function is provided for STL compatibility. It is equivalent
+    to \l{QJsonArray::prepend()}{prepend(\a value)}.
+*/
+
+/*! \fn void QJsonArray::pop_front()
+
+    This function is provided for STL compatibility. It is equivalent
+    to removeFirst(). The array must not be empty. If the array can be
+    empty, call isEmpty() before calling this function.
+*/
+
+/*! \fn void QJsonArray::pop_back()
+
+    This function is provided for STL compatibility. It is equivalent
+    to removeLast(). The array must not be empty. If the array can be
+    empty, call isEmpty() before calling this function.
+*/
+
+/*! \fn bool QJsonArray::empty() const
+
+    This function is provided for STL compatibility. It is equivalent
+    to isEmpty() and returns \c true if the array is empty.
+*/
+
+/*! \class QJsonArray::iterator
+    \brief The QJsonArray::iterator class provides an STL-style non-const iterator for QJsonArray.
+
+    QJsonArray::iterator allows you to iterate over a QJsonArray
+    and to modify the array item associated with the
+    iterator. If you want to iterate over a const QJsonArray, use
+    QJsonArray::const_iterator instead. It is generally a good practice to
+    use QJsonArray::const_iterator on a non-const QJsonArray as well, unless
+    you need to change the QJsonArray through the iterator. Const
+    iterators are slightly faster and improves code readability.
+
+    The default QJsonArray::iterator constructor creates an uninitialized
+    iterator. You must initialize it using a QJsonArray function like
+    QJsonArray::begin(), QJsonArray::end(), or QJsonArray::insert() before you can
+    start iterating.
+
+    Most QJsonArray functions accept an integer index rather than an
+    iterator. For that reason, iterators are rarely useful in
+    connection with QJsonArray. One place where STL-style iterators do
+    make sense is as arguments to \l{generic algorithms}.
+
+    Multiple iterators can be used on the same array. However, be
+    aware that any non-const function call performed on the QJsonArray
+    will render all existing iterators undefined.
+
+    \sa QJsonArray::const_iterator
+*/
+
+/*! \typedef QJsonArray::iterator::iterator_category
+
+  A synonym for \i {std::random_access_iterator_tag} indicating
+  this iterator is a random access iterator.
+*/
+
+/*! \typedef QJsonArray::iterator::difference_type
+
+    \internal
+*/
+
+/*! \typedef QJsonArray::iterator::value_type
+
+    \internal
+*/
+
+/*! \typedef QJsonArray::iterator::reference
+
+    \internal
+*/
+
+/*! \fn QJsonArray::iterator::iterator()
+
+    Constructs an uninitialized iterator.
+
+    Functions like operator*() and operator++() should not be called
+    on an uninitialized iterator. Use operator=() to assign a value
+    to it before using it.
+
+    \sa QJsonArray::begin() QJsonArray::end()
+*/
+
+/*! \fn QJsonArray::iterator::iterator(const iterator &other)
+
+    Constructs a copy of \a other.
+*/
+
+/*! \fn QJsonValueRef QJsonArray::iterator::operator*() const
+
+    Returns a modifiable reference to the current item.
+
+    You can change the value of an item by using operator*() on the
+    left side of an assignment.
+
+    The return value is of type QJsonValueRef, a helper class for QJsonArray
+    and QJsonObject. When you get an object of type QJsonValueRef, you can
+    use it as if it were a reference to a QJsonValue. If you assign to it,
+    the assignment will apply to the character in the QJsonArray of QJsonObject
+    from which you got the reference.
+*/
+
+/*! \fn QJsonValueRef QJsonArray::iterator::operator[](int j) const
+
+    Returns a modifiable reference to the item at position \c{*this + j}.
+
+    This function is provided to make QJsonArray iterators behave like C++
+    pointers.
+
+    The return value is of type QJsonValueRef, a helper class for QJsonArray
+    and QJsonObject. When you get an object of type QJsonValueRef, you can
+    use it as if it were a reference to a QJsonValue. If you assign to it,
+    the assignment will apply to the character in the QJsonArray of QJsonObject
+    from which you got the reference.
+
+    \sa operator+()
+*/
+
+/*!
+    \fn bool QJsonArray::iterator::operator==(const iterator &other) const
+    \fn bool QJsonArray::iterator::operator==(const const_iterator &other) const
+
+    Returns \c true if \a other points to the same item as this
+    iterator; otherwise returns \c false.
+
+    \sa operator!=()
+*/
+
+/*!
+    \fn bool QJsonArray::iterator::operator!=(const iterator &other) const
+    \fn bool QJsonArray::iterator::operator!=(const const_iterator &other) const
+
+    Returns \c true if \a other points to a different item than this
+    iterator; otherwise returns \c false.
+
+    \sa operator==()
+*/
+
+/*!
+    \fn bool QJsonArray::iterator::operator<(const iterator& other) const
+    \fn bool QJsonArray::iterator::operator<(const const_iterator& other) const
+
+    Returns \c true if the item pointed to by this iterator is less than
+    the item pointed to by the \a other iterator.
+*/
+
+/*!
+    \fn bool QJsonArray::iterator::operator<=(const iterator& other) const
+    \fn bool QJsonArray::iterator::operator<=(const const_iterator& other) const
+
+    Returns \c true if the item pointed to by this iterator is less than
+    or equal to the item pointed to by the \a other iterator.
+*/
+
+/*!
+    \fn bool QJsonArray::iterator::operator>(const iterator& other) const
+    \fn bool QJsonArray::iterator::operator>(const const_iterator& other) const
+
+    Returns \c true if the item pointed to by this iterator is greater
+    than the item pointed to by the \a other iterator.
+*/
+
+/*!
+    \fn bool QJsonArray::iterator::operator>=(const iterator& other) const
+    \fn bool QJsonArray::iterator::operator>=(const const_iterator& other) const
+
+    Returns \c true if the item pointed to by this iterator is greater
+    than or equal to the item pointed to by the \a other iterator.
+*/
+
+/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator++()
+
+    The prefix ++ operator, \c{++it}, advances the iterator to the
+    next item in the array and returns an iterator to the new current
+    item.
+
+    Calling this function on QJsonArray::end() leads to undefined results.
+
+    \sa operator--()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::iterator::operator++(int)
+
+    \overload
+
+    The postfix ++ operator, \c{it++}, advances the iterator to the
+    next item in the array and returns an iterator to the previously
+    current item.
+*/
+
+/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator--()
+
+    The prefix -- operator, \c{--it}, makes the preceding item
+    current and returns an iterator to the new current item.
+
+    Calling this function on QJsonArray::begin() leads to undefined results.
+
+    \sa operator++()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::iterator::operator--(int)
+
+    \overload
+
+    The postfix -- operator, \c{it--}, makes the preceding item
+    current and returns an iterator to the previously current item.
+*/
+
+/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator+=(int j)
+
+    Advances the iterator by \a j items. If \a j is negative, the
+    iterator goes backward.
+
+    \sa operator-=(), operator+()
+*/
+
+/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator-=(int j)
+
+    Makes the iterator go back by \a j items. If \a j is negative,
+    the iterator goes forward.
+
+    \sa operator+=(), operator-()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::iterator::operator+(int j) const
+
+    Returns an iterator to the item at \a j positions forward from
+    this iterator. If \a j is negative, the iterator goes backward.
+
+    \sa operator-(), operator+=()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::iterator::operator-(int j) const
+
+    Returns an iterator to the item at \a j positions backward from
+    this iterator. If \a j is negative, the iterator goes forward.
+
+    \sa operator+(), operator-=()
+*/
+
+/*! \fn int QJsonArray::iterator::operator-(iterator other) const
+
+    Returns the number of items between the item pointed to by \a
+    other and the item pointed to by this iterator.
+*/
+
+/*! \class QJsonArray::const_iterator
+    \brief The QJsonArray::const_iterator class provides an STL-style const iterator for QJsonArray.
+
+    QJsonArray::const_iterator allows you to iterate over a
+    QJsonArray. If you want to modify the QJsonArray as
+    you iterate over it, use QJsonArray::iterator instead. It is generally a
+    good practice to use QJsonArray::const_iterator on a non-const QJsonArray
+    as well, unless you need to change the QJsonArray through the
+    iterator. Const iterators are slightly faster and improves
+    code readability.
+
+    The default QJsonArray::const_iterator constructor creates an
+    uninitialized iterator. You must initialize it using a QJsonArray
+    function like QJsonArray::constBegin(), QJsonArray::constEnd(), or
+    QJsonArray::insert() before you can start iterating.
+
+    Most QJsonArray functions accept an integer index rather than an
+    iterator. For that reason, iterators are rarely useful in
+    connection with QJsonArray. One place where STL-style iterators do
+    make sense is as arguments to \l{generic algorithms}.
+
+    Multiple iterators can be used on the same array. However, be
+    aware that any non-const function call performed on the QJsonArray
+    will render all existing iterators undefined.
+
+    \sa QJsonArray::iterator, QJsonArrayIterator
+*/
+
+/*! \fn QJsonArray::const_iterator::const_iterator()
+
+    Constructs an uninitialized iterator.
+
+    Functions like operator*() and operator++() should not be called
+    on an uninitialized iterator. Use operator=() to assign a value
+    to it before using it.
+
+    \sa QJsonArray::constBegin() QJsonArray::constEnd()
+*/
+
+/*! \typedef QJsonArray::const_iterator::iterator_category
+
+  A synonym for \i {std::random_access_iterator_tag} indicating
+  this iterator is a random access iterator.
+*/
+
+/*! \typedef QJsonArray::const_iterator::difference_type
+
+    \internal
+*/
+
+/*! \typedef QJsonArray::const_iterator::value_type
+
+    \internal
+*/
+
+/*! \typedef QJsonArray::const_iterator::reference
+
+    \internal
+*/
+
+/*! \fn QJsonArray::const_iterator::const_iterator(const const_iterator &other)
+
+    Constructs a copy of \a other.
+*/
+
+/*! \fn QJsonArray::const_iterator::const_iterator(const iterator &other)
+
+    Constructs a copy of \a other.
+*/
+
+/*! \fn QJsonValue QJsonArray::const_iterator::operator*() const
+
+    Returns the current item.
+*/
+
+/*! \fn QJsonValue QJsonArray::const_iterator::operator[](int j) const
+
+    Returns the item at position \c{*this + j}.
+
+    This function is provided to make QJsonArray iterators behave like C++
+    pointers.
+
+    \sa operator+()
+*/
+
+/*! \fn bool QJsonArray::const_iterator::operator==(const const_iterator &other) const
+
+    Returns \c true if \a other points to the same item as this
+    iterator; otherwise returns \c false.
+
+    \sa operator!=()
+*/
+
+/*! \fn bool QJsonArray::const_iterator::operator!=(const const_iterator &other) const
+
+    Returns \c true if \a other points to a different item than this
+    iterator; otherwise returns \c false.
+
+    \sa operator==()
+*/
+
+/*!
+    \fn bool QJsonArray::const_iterator::operator<(const const_iterator& other) const
+
+    Returns \c true if the item pointed to by this iterator is less than
+    the item pointed to by the \a other iterator.
+*/
+
+/*!
+    \fn bool QJsonArray::const_iterator::operator<=(const const_iterator& other) const
+
+    Returns \c true if the item pointed to by this iterator is less than
+    or equal to the item pointed to by the \a other iterator.
+*/
+
+/*!
+    \fn bool QJsonArray::const_iterator::operator>(const const_iterator& other) const
+
+    Returns \c true if the item pointed to by this iterator is greater
+    than the item pointed to by the \a other iterator.
+*/
+
+/*!
+    \fn bool QJsonArray::const_iterator::operator>=(const const_iterator& other) const
+
+    Returns \c true if the item pointed to by this iterator is greater
+    than or equal to the item pointed to by the \a other iterator.
+*/
+
+/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator++()
+
+    The prefix ++ operator, \c{++it}, advances the iterator to the
+    next item in the array and returns an iterator to the new current
+    item.
+
+    Calling this function on QJsonArray::end() leads to undefined results.
+
+    \sa operator--()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::const_iterator::operator++(int)
+
+    \overload
+
+    The postfix ++ operator, \c{it++}, advances the iterator to the
+    next item in the array and returns an iterator to the previously
+    current item.
+*/
+
+/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator--()
+
+    The prefix -- operator, \c{--it}, makes the preceding item
+    current and returns an iterator to the new current item.
+
+    Calling this function on QJsonArray::begin() leads to undefined results.
+
+    \sa operator++()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::const_iterator::operator--(int)
+
+    \overload
+
+    The postfix -- operator, \c{it--}, makes the preceding item
+    current and returns an iterator to the previously current item.
+*/
+
+/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator+=(int j)
+
+    Advances the iterator by \a j items. If \a j is negative, the
+    iterator goes backward.
+
+    \sa operator-=(), operator+()
+*/
+
+/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator-=(int j)
+
+    Makes the iterator go back by \a j items. If \a j is negative,
+    the iterator goes forward.
+
+    \sa operator+=(), operator-()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::const_iterator::operator+(int j) const
+
+    Returns an iterator to the item at \a j positions forward from
+    this iterator. If \a j is negative, the iterator goes backward.
+
+    \sa operator-(), operator+=()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::const_iterator::operator-(int j) const
+
+    Returns an iterator to the item at \a j positions backward from
+    this iterator. If \a j is negative, the iterator goes forward.
+
+    \sa operator+(), operator-=()
+*/
+
+/*! \fn int QJsonArray::const_iterator::operator-(const_iterator other) const
+
+    Returns the number of items between the item pointed to by \a
+    other and the item pointed to by this iterator.
+*/
+
+
+/*!
+    \internal
+ */
+void QJsonArray::detach(uint reserve)
+{
+    if (!d) {
+        d = new QJsonPrivate::Data(reserve, QJsonValue::Array);
+        a = static_cast<QJsonPrivate::Array *>(d->header->root());
+        d->ref.ref();
+        return;
+    }
+    if (reserve == 0 && d->ref.load() == 1)
+        return;
+
+    QJsonPrivate::Data *x = d->clone(a, reserve);
+    x->ref.ref();
+    if (!d->ref.deref())
+        delete d;
+    d = x;
+    a = static_cast<QJsonPrivate::Array *>(d->header->root());
+}
+
+/*!
+    \internal
+ */
+void QJsonArray::compact()
+{
+    if (!d || !d->compactionCounter)
+        return;
+
+    detach();
+    d->compact();
+    a = static_cast<QJsonPrivate::Array *>(d->header->root());
+}
+
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QJsonArray &a)
+{
+    if (!a.a) {
+        dbg << "QJsonArray()";
+        return dbg;
+    }
+    QByteArray json;
+    QJsonPrivate::Writer::arrayToJson(a.a, json, 0, true);
+    dbg.nospace() << "QJsonArray("
+                  << json.constData() // print as utf-8 string without extra quotation marks
+                  << ")";
+    return dbg.space();
+}
+#endif
+
+QT_END_NAMESPACE
+
diff --git a/src/corelib/json/qjsonarray.h b/src/corelib/json/qjsonarray.h
new file mode 100644 (file)
index 0000000..e296458
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsondocument.cpp b/src/corelib/json/qjsondocument.cpp
new file mode 100644 (file)
index 0000000..e76756d
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsondocument.h b/src/corelib/json/qjsondocument.h
new file mode 100644 (file)
index 0000000..0994a80
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp
new file mode 100644 (file)
index 0000000..4252f80
--- /dev/null
@@ -0,0 +1,1014 @@
+/****************************************************************************
+**
+** 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 <qstringlist.h>
+#include <qdebug.h>
+#include "qjson_p.h"
+#include "qjsonwriter_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \class QJsonObject
+    \ingroup json
+    \reentrant
+    \since 5.0
+
+    \brief The QJsonObject class encapsulates a JSON object.
+
+    A JSON object is a list of key value pairs, where the keys are unique strings
+    and the values are represented by a QJsonValue.
+
+    A QJsonObject can be converted to and from a QVariantMap. You can query the
+    number of (key, value) pairs with size(), insert(), and remove() entries from it
+    and iterate over its content using the standard C++ iterator pattern.
+
+    QJsonObject is an implicitly shared class, and shares the data with the document
+    it has been created from as long as it is not being modified.
+
+    You can convert the array to and from text based JSON through QJsonDocument.
+*/
+
+/*!
+    Constructs an empty JSON object
+
+    \sa isEmpty
+ */
+QJsonObject::QJsonObject()
+    : d(0), o(0)
+{
+}
+
+/*!
+    \internal
+ */
+QJsonObject::QJsonObject(QJsonPrivate::Data *data, QJsonPrivate::Object *object)
+    : d(data), o(object)
+{
+    Q_ASSERT(d);
+    Q_ASSERT(o);
+    d->ref.ref();
+}
+
+
+/*!
+    Destroys the object.
+ */
+QJsonObject::~QJsonObject()
+{
+    if (d && !d->ref.deref())
+        delete d;
+}
+
+/*!
+    Creates a copy of \a other.
+
+    Since QJsonObject is implicitly shared, the copy is shallow
+    as long as the object does not get modified.
+ */
+QJsonObject::QJsonObject(const QJsonObject &other)
+{
+    d = other.d;
+    o = other.o;
+    if (d)
+        d->ref.ref();
+}
+
+/*!
+    Assigns \a other to this object.
+ */
+QJsonObject &QJsonObject::operator =(const QJsonObject &other)
+{
+    if (d != other.d) {
+        if (d && !d->ref.deref())
+            delete d;
+        d = other.d;
+        o = other.o;
+        if (d)
+            d->ref.ref();
+    }
+
+    return *this;
+}
+
+/*!
+    Converts the variant map \a map to a QJsonObject.
+
+    The keys in \a map will be used as the keys in the JSON object,
+    and the QVariant values will be converted to JSON values.
+
+    \sa toVariantMap, QJsonValue::fromVariant
+ */
+QJsonObject QJsonObject::fromVariantMap(const QVariantMap &map)
+{
+    // ### this is implemented the trivial way, not the most efficient way
+
+    QJsonObject object;
+    for (QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it)
+        object.insert(it.key(), QJsonValue::fromVariant(it.value()));
+    return object;
+}
+
+/*!
+    Converts this object to a QVariantMap.
+
+    Returns the created map.
+ */
+QVariantMap QJsonObject::toVariantMap() const
+{
+    QVariantMap map;
+    for (uint i = 0; i < o->length; ++i) {
+        QJsonPrivate::Entry *e = o->entryAt(i);
+        map.insert(e->key(), QJsonValue(d, o, e->value).toVariant());
+    }
+    return map;
+}
+
+/*!
+    Returns a list of all keys in this object.
+ */
+QStringList QJsonObject::keys() const
+{
+    if (!d)
+        return QStringList();
+
+    QStringList keys;
+
+    for (uint i = 0; i < o->length; ++i) {
+        QJsonPrivate::Entry *e = o->entryAt(i);
+        keys.append(e->key());
+    }
+
+    return keys;
+}
+
+/*!
+    Returns the the number of (key, value) pairs stored in the object.
+ */
+int QJsonObject::size() const
+{
+    if (!d)
+        return 0;
+
+    return o->length;
+}
+
+/*!
+    Returns \c true if the object is empty. This is the same as size() == 0.
+
+    \sa size
+ */
+bool QJsonObject::isEmpty() const
+{
+    if (!d)
+        return true;
+
+    return !o->length;
+}
+
+/*!
+    Returns a QJsonValue representing the value for the key \a key.
+
+    The returned QJsonValue is \c Undefined, if the key does not exist.
+
+    \sa setValue, QJsonValue, QJsonValue::isUndefined
+ */
+QJsonValue QJsonObject::value(const QString &key) const
+{
+    if (!d)
+        return QJsonValue();
+
+    bool keyExists;
+    int i = o->indexOf(key, &keyExists);
+    if (!keyExists)
+        return QJsonValue(QJsonValue::Undefined);
+    return QJsonValue(d, o, o->entryAt(i)->value);
+}
+
+/*!
+    Returns a QJsonValue representing the value for the key \a key.
+
+    This does the same as value().
+
+    The returned QJsonValue is \c Undefined, if the key does not exist.
+
+    \sa value, setValue, QJsonValue, QJsonValue::isUndefined
+ */
+QJsonValue QJsonObject::operator [](const QString &key) const
+{
+    return value(key);
+}
+
+/*!
+    Returns a reference to the value for \a key.
+
+    The return value is of type QJsonValueRef, a helper class for QJsonArray
+    and QJsonObject. When you get an object of type QJsonValueRef, you can
+    use it as if it were a reference to a QJsonValue. If you assign to it,
+    the assignment will apply to the character in the QJsonArray of QJsonObject
+    from which you got the reference.
+
+    \sa setValue, value
+ */
+QJsonValueRef QJsonObject::operator [](const QString &key)
+{
+    // ### somewhat inefficient, as we lookup the key twice if it doesn't yet exist
+    bool keyExists = false;
+    int index = o ? o->indexOf(key, &keyExists) : -1;
+    if (!keyExists) {
+        iterator i = insert(key, QJsonValue());
+        index = i.i;
+    }
+    return QJsonValueRef(this, index);
+}
+
+/*!
+    Inserts a new item with the key \a key and a value of \a value.
+
+    If there is already an item with the key \a key then that item's value
+    is replaced with \a value.
+
+    Returns an iterator pointing to the inserted item.
+
+    If the value is QJsonValue::Undefined, it will cause the key to get removed
+    from the object. The returned iterator will then point to end()
+
+    \sa remove, take, QJsonObject::iterator, end
+ */
+QJsonObject::iterator QJsonObject::insert(const QString &key, const QJsonValue &value)
+{
+    if (value.t == QJsonValue::Undefined) {
+        remove(key);
+        return end();
+    }
+
+    bool latinOrIntValue;
+    int valueSize = QJsonPrivate::Value::requiredStorage(value, &latinOrIntValue);
+
+    bool latinKey = QJsonPrivate::useCompressed(key);
+    int valueOffset = sizeof(QJsonPrivate::Entry) + QJsonPrivate::qStringSize(key, latinKey);
+    int requiredSize = valueOffset + valueSize;
+
+    detach(requiredSize + sizeof(QJsonPrivate::offset)); // offset for the new index entry
+
+    if (!o->length)
+        o->tableOffset = sizeof(QJsonPrivate::Object);
+
+    bool keyExists = false;
+    int pos = o->indexOf(key, &keyExists);
+    if (keyExists)
+        ++d->compactionCounter;
+
+    o->reserveSpace(requiredSize, pos, 1, keyExists);
+
+    QJsonPrivate::Entry *e = o->entryAt(pos);
+    e->value.type = value.t;
+    e->value.latinKey = latinKey;
+    e->value.latinOrIntValue = latinOrIntValue;
+    e->value.value = QJsonPrivate::Value::valueToStore(value, (char *)e - (char *)o + valueOffset);
+    QJsonPrivate::copyString((char *)(e + 1), key, latinKey);
+    if (valueSize)
+        QJsonPrivate::Value::copyData(value, (char *)e + valueOffset, latinOrIntValue);
+
+    return iterator(this, pos);
+}
+
+/*!
+    Removes \a key from the object.
+
+    \sa insert, take
+ */
+void QJsonObject::remove(const QString &key)
+{
+    if (!d)
+        return;
+
+    bool keyExists;
+    int index = o->indexOf(key, &keyExists);
+    if (!keyExists)
+        return;
+
+    detach();
+    o->removeItems(index, 1);
+    ++d->compactionCounter;
+    if (d->compactionCounter > 32 && d->compactionCounter >= (int)o->length/2)
+        compact();
+}
+
+/*!
+    Removes \a key from the object.
+
+    Returns a QJsonValue containing the value referenced by \a key.
+    If \a key was not contained in the object, the returned QJsonValue
+    is Undefined.
+
+    \sa insert, remove, QJsonValue
+ */
+QJsonValue QJsonObject::take(const QString &key)
+{
+    if (!o)
+        return QJsonValue(QJsonValue::Undefined);
+
+    bool keyExists;
+    int index = o->indexOf(key, &keyExists);
+    if (!keyExists)
+        return QJsonValue(QJsonValue::Undefined);
+
+    QJsonPrivate::Entry *e = o->entryAt(index);
+    o->removeItems(index, 1);
+    ++d->compactionCounter;
+    if (d->compactionCounter > 32 && d->compactionCounter >= (int)o->length/2)
+        compact();
+
+    return QJsonValue(d, o, e->value);
+}
+
+/*!
+    Returns \c true if the object contains key \a key.
+
+    \sa insert, remove, take
+ */
+bool QJsonObject::contains(const QString &key) const
+{
+    if (!o)
+        return false;
+
+    bool keyExists;
+    o->indexOf(key, &keyExists);
+    return keyExists;
+}
+
+/*!
+    Returns \c true if \a other is equal to this object
+ */
+bool QJsonObject::operator==(const QJsonObject &other) const
+{
+    if (o == other.o)
+        return true;
+
+    if (!o)
+        return !other.o->length;
+    if (!other.o)
+        return !o->length;
+    if (o->length != other.o->length)
+        return false;
+
+    for (uint i = 0; i < o->length; ++i) {
+        QJsonPrivate::Entry *e = o->entryAt(i);
+        QJsonValue v(d, o, e->value);
+        if (other.value(e->key()) != v)
+            return false;
+    }
+
+    return true;
+}
+
+/*!
+    Returns \c true if \a other is not equal to this object
+ */
+bool QJsonObject::operator!=(const QJsonObject &other) const
+{
+    return !(*this == other);
+}
+
+/*!
+    Removes the (key, value) pair pointed to by the iterator \a it
+    from the map, and returns an iterator to the next item in the
+    map.
+
+    \sa remove()
+ */
+QJsonObject::iterator QJsonObject::erase(QJsonObject::iterator it)
+{
+    Q_ASSERT(d && d->ref.load() == 1);
+    if (it.o != this || it.i < 0 || it.i >= (int)o->length)
+        return iterator(this, o->length);
+
+    int index = it.i;
+
+    o->removeItems(index, 1);
+    ++d->compactionCounter;
+    if (d->compactionCounter > 32 && d->compactionCounter >= (int)o->length/2)
+        compact();
+
+    // iterator hasn't changed
+    return it;
+}
+
+/*!
+    Returns an iterator pointing to the item with key \a key in the
+    map.
+
+    If the map contains no item with key \a key, the function
+    returns end().
+ */
+QJsonObject::iterator QJsonObject::find(const QString &key)
+{
+    bool keyExists = false;
+    int index = o ? o->indexOf(key, &keyExists) : 0;
+    if (!keyExists)
+        return end();
+    return iterator(this, index);
+}
+
+/*! \fn QJsonObject::const_iterator QJsonObject::find(const Key &key) const
+
+    \overload
+*/
+
+/*!
+    Returns an const iterator pointing to the item with key \a key in the
+    map.
+
+    If the map contains no item with key \a key, the function
+    returns constEnd().
+ */
+QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const
+{
+    bool keyExists = false;
+    int index = o ? o->indexOf(key, &keyExists) : 0;
+    if (!keyExists)
+        return end();
+    return const_iterator(this, index);
+}
+
+/*! \fn int QJsonObject::count() const
+
+    \overload
+
+    Same as size().
+*/
+
+/*! \fn int QJsonObject::length() const
+
+    \overload
+
+    Same as size().
+*/
+
+/*! \fn QJsonObject::iterator QJsonObject::begin()
+
+    Returns an \l{STL-style iterator} pointing to the first item in
+    the object.
+
+    \sa constBegin(), end()
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::begin() const
+
+    \overload
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::constBegin() const
+
+    Returns a const \l{STL-style iterator} pointing to the first item
+    in the object.
+
+    \sa begin(), constEnd()
+*/
+
+/*! \fn QJsonObject::iterator QJsonObject::end()
+
+    Returns an \l{STL-style iterator} pointing to the imaginary item
+    after the last item in the object.
+
+    \sa begin(), constEnd()
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::end() const
+
+    \overload
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::constEnd() const
+
+    Returns a const \l{STL-style iterator} pointing to the imaginary
+    item after the last item in the object.
+
+    \sa constBegin(), end()
+*/
+
+/*!
+    \fn bool QJsonObject::empty() const
+
+    This function is provided for STL compatibility. It is equivalent
+    to isEmpty(), returning \c true if the object is empty; otherwise
+    returning \c false.
+*/
+
+/*! \class QJsonObject::iterator
+    \brief The QJsonObject::iterator class provides an STL-style non-const iterator for QJsonObject.
+
+    QJsonObject::iterator allows you to iterate over a QJsonObject
+    and to modify the value (but not the key) stored under
+    a particular key. If you want to iterate over a const QJsonObject, you
+    should use QJsonObject::const_iterator. It is generally good practice to
+    use QJsonObject::const_iterator on a non-const QJsonObject as well, unless you
+    need to change the QJsonObject through the iterator. Const iterators are
+    slightly faster, and improves code readability.
+
+    The default QJsonObject::iterator constructor creates an uninitialized
+    iterator. You must initialize it using a QJsonObject function like
+    QJsonObject::begin(), QJsonObject::end(), or QJsonObject::find() before you can
+    start iterating.
+
+    Multiple iterators can be used on the same object. Existing iterators will however
+    become dangling once the object gets modified.
+
+    \sa QJsonObject::const_iterator
+*/
+
+/*! \typedef QJsonObject::iterator::difference_type
+
+    \internal
+*/
+
+/*! \typedef QJsonObject::iterator::iterator_category
+
+  A synonym for \i {std::bidirectional_iterator_tag} indicating
+  this iterator is a bidirectional iterator.
+*/
+
+/*! \typedef QJsonObject::iterator::reference
+
+    \internal
+*/
+
+/*! \typedef QJsonObject::iterator::value_type
+
+    \internal
+*/
+
+/*! \fn QJsonObject::iterator::iterator()
+
+    Constructs an uninitialized iterator.
+
+    Functions like key(), value(), and operator++() must not be
+    called on an uninitialized iterator. Use operator=() to assign a
+    value to it before using it.
+
+    \sa QJsonObject::begin() QJsonObject::end()
+*/
+
+/*! \fn QString QJsonObject::iterator::key() const
+
+    Returns the current item's key.
+
+    There is no direct way of changing an item's key through an
+    iterator, although it can be done by calling QJsonObject::erase()
+    followed by QJsonObject::insert().
+
+    \sa value()
+*/
+
+/*! \fn QJsonValueRef QJsonObject::iterator::value() const
+
+    Returns a modifiable reference to the current item's value.
+
+    You can change the value of an item by using value() on
+    the left side of an assignment.
+
+    The return value is of type QJsonValueRef, a helper class for QJsonArray
+    and QJsonObject. When you get an object of type QJsonValueRef, you can
+    use it as if it were a reference to a QJsonValue. If you assign to it,
+    the assignment will apply to the character in the QJsonArray of QJsonObject
+    from which you got the reference.
+
+    \sa key(), operator*()
+*/
+
+/*! \fn QJsonValueRef QJsonObject::iterator::operator*() const
+
+    Returns a modifiable reference to the current item's value.
+
+    Same as value().
+
+    The return value is of type QJsonValueRef, a helper class for QJsonArray
+    and QJsonObject. When you get an object of type QJsonValueRef, you can
+    use it as if it were a reference to a QJsonValue. If you assign to it,
+    the assignment will apply to the character in the QJsonArray of QJsonObject
+    from which you got the reference.
+
+    \sa key()
+*/
+
+/*!
+    \fn bool QJsonObject::iterator::operator==(const iterator &other) const
+    \fn bool QJsonObject::iterator::operator==(const const_iterator &other) const
+
+    Returns \c true if \a other points to the same item as this
+    iterator; otherwise returns \c false.
+
+    \sa operator!=()
+*/
+
+/*!
+    \fn bool QJsonObject::iterator::operator!=(const iterator &other) const
+    \fn bool QJsonObject::iterator::operator!=(const const_iterator &other) const
+
+    Returns \c true if \a other points to a different item than this
+    iterator; otherwise returns \c false.
+
+    \sa operator==()
+*/
+
+/*! \fn QJsonObject::iterator QJsonObject::iterator::operator++()
+
+    The prefix ++ operator, \c{++i}, advances the iterator to the
+    next item in the object and returns an iterator to the new current
+    item.
+
+    Calling this function on QJsonObject::end() leads to undefined results.
+
+    \sa operator--()
+*/
+
+/*! \fn QJsonObject::iterator QJsonObject::iterator::operator++(int)
+
+    \overload
+
+    The postfix ++ operator, \c{i++}, advances the iterator to the
+    next item in the object and returns an iterator to the previously
+    current item.
+*/
+
+/*! \fn QJsonObject::iterator QJsonObject::iterator::operator--()
+
+    The prefix -- operator, \c{--i}, makes the preceding item
+    current and returns an iterator pointing to the new current item.
+
+    Calling this function on QJsonObject::begin() leads to undefined
+    results.
+
+    \sa operator++()
+*/
+
+/*! \fn QJsonObject::iterator QJsonObject::iterator::operator--(int)
+
+    \overload
+
+    The postfix -- operator, \c{i--}, makes the preceding item
+    current and returns an iterator pointing to the previously
+    current item.
+*/
+
+/*! \fn QJsonObject::iterator QJsonObject::iterator::operator+(int j) const
+
+    Returns an iterator to the item at \a j positions forward from
+    this iterator. If \a j is negative, the iterator goes backward.
+
+    \sa operator-()
+
+*/
+
+/*! \fn QJsonObject::iterator QJsonObject::iterator::operator-(int j) const
+
+    Returns an iterator to the item at \a j positions backward from
+    this iterator. If \a j is negative, the iterator goes forward.
+
+    \sa operator+()
+*/
+
+/*! \fn QJsonObject::iterator &QJsonObject::iterator::operator+=(int j)
+
+    Advances the iterator by \a j items. If \a j is negative, the
+    iterator goes backward.
+
+    \sa operator-=(), operator+()
+*/
+
+/*! \fn QJsonObject::iterator &QJsonObject::iterator::operator-=(int j)
+
+    Makes the iterator go back by \a j items. If \a j is negative,
+    the iterator goes forward.
+
+    \sa operator+=(), operator-()
+*/
+
+/*! \class QJsonObject::const_iterator
+    \brief The QJsonObject::const_iterator class provides an STL-style const iterator for QJsonObject.
+
+    QJsonObject::const_iterator allows you to iterate over a QJsonObject.
+    If you want to modify the QJsonObject as you iterate
+    over it, you must use QJsonObject::iterator instead. It is generally
+    good practice to use QJsonObject::const_iterator on a non-const QJsonObject as
+    well, unless you need to change the QJsonObject through the iterator.
+    Const iterators are slightly faster and improves code
+    readability.
+
+    The default QJsonObject::const_iterator constructor creates an
+    uninitialized iterator. You must initialize it using a QJsonObject
+    function like QJsonObject::constBegin(), QJsonObject::constEnd(), or
+    QJsonObject::find() before you can start iterating.
+
+    Multiple iterators can be used on the same object. Existing iterators
+    will however become dangling if the object gets modified.
+
+    \sa QJsonObject::iterator, QJsonObjectIterator
+*/
+
+/*! \typedef QJsonObject::const_iterator::difference_type
+
+    \internal
+*/
+
+/*! \typedef QJsonObject::const_iterator::iterator_category
+
+  A synonym for \i {std::bidirectional_iterator_tag} indicating
+  this iterator is a bidirectional iterator.
+*/
+
+/*! \typedef QJsonObject::const_iterator::reference
+
+    \internal
+*/
+
+/*! \typedef QJsonObject::const_iterator::value_type
+
+    \internal
+*/
+
+/*! \fn QJsonObject::const_iterator::const_iterator()
+
+    Constructs an uninitialized iterator.
+
+    Functions like key(), value(), and operator++() must not be
+    called on an uninitialized iterator. Use operator=() to assign a
+    value to it before using it.
+
+    \sa QJsonObject::constBegin() QJsonObject::constEnd()
+*/
+
+/*! \fn QJsonObject::const_iterator::const_iterator(const iterator &other)
+
+    Constructs a copy of \a other.
+*/
+
+/*! \fn QString QJsonObject::const_iterator::key() const
+
+    Returns the current item's key.
+
+    \sa value()
+*/
+
+/*! \fn QJsonValue QJsonObject::const_iterator::value() const
+
+    Returns the current item's value.
+
+    \sa key(), operator*()
+*/
+
+/*! \fn QJsonValue QJsonObject::const_iterator::operator*() const
+
+    Returns the current item's value.
+
+    Same as value().
+
+    \sa key()
+*/
+
+/*! \fn bool QJsonObject::const_iterator::operator==(const const_iterator &other) const
+
+    Returns \c true if \a other points to the same item as this
+    iterator; otherwise returns \c false.
+
+    \sa operator!=()
+*/
+
+/*! \fn bool QJsonObject::const_iterator::operator!=(const const_iterator &other) const
+
+    Returns \c true if \a other points to a different item than this
+    iterator; otherwise returns \c false.
+
+    \sa operator==()
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator++()
+
+    The prefix ++ operator, \c{++i}, advances the iterator to the
+    next item in the object and returns an iterator to the new current
+    item.
+
+    Calling this function on QJsonObject::end() leads to undefined results.
+
+    \sa operator--()
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator++(int)
+
+    \overload
+
+    The postfix ++ operator, \c{i++}, advances the iterator to the
+    next item in the object and returns an iterator to the previously
+    current item.
+*/
+
+/*! \fn QJsonObject::const_iterator &QJsonObject::const_iterator::operator--()
+
+    The prefix -- operator, \c{--i}, makes the preceding item
+    current and returns an iterator pointing to the new current item.
+
+    Calling this function on QJsonObject::begin() leads to undefined
+    results.
+
+    \sa operator++()
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator--(int)
+
+    \overload
+
+    The postfix -- operator, \c{i--}, makes the preceding item
+    current and returns an iterator pointing to the previously
+    current item.
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator+(int j) const
+
+    Returns an iterator to the item at \a j positions forward from
+    this iterator. If \a j is negative, the iterator goes backward.
+
+    This operation can be slow for large \a j values.
+
+    \sa operator-()
+*/
+
+/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator-(int j) const
+
+    Returns an iterator to the item at \a j positions backward from
+    this iterator. If \a j is negative, the iterator goes forward.
+
+    This operation can be slow for large \a j values.
+
+    \sa operator+()
+*/
+
+/*! \fn QJsonObject::const_iterator &QJsonObject::const_iterator::operator+=(int j)
+
+    Advances the iterator by \a j items. If \a j is negative, the
+    iterator goes backward.
+
+    This operation can be slow for large \a j values.
+
+    \sa operator-=(), operator+()
+*/
+
+/*! \fn QJsonObject::const_iterator &QJsonObject::const_iterator::operator-=(int j)
+
+    Makes the iterator go back by \a j items. If \a j is negative,
+    the iterator goes forward.
+
+    This operation can be slow for large \a j values.
+
+    \sa operator+=(), operator-()
+*/
+
+
+/*!
+    \internal
+ */
+void QJsonObject::detach(uint reserve)
+{
+    if (!d) {
+        d = new QJsonPrivate::Data(reserve, QJsonValue::Object);
+        o = static_cast<QJsonPrivate::Object *>(d->header->root());
+        d->ref.ref();
+        return;
+    }
+    if (reserve == 0 && d->ref.load() == 1)
+        return;
+
+    QJsonPrivate::Data *x = d->clone(o, reserve);
+    x->ref.ref();
+    if (!d->ref.deref())
+        delete d;
+    d = x;
+    o = static_cast<QJsonPrivate::Object *>(d->header->root());
+}
+
+/*!
+    \internal
+ */
+void QJsonObject::compact()
+{
+    if (!d || !d->compactionCounter)
+        return;
+
+    detach();
+    d->compact();
+    o = static_cast<QJsonPrivate::Object *>(d->header->root());
+}
+
+/*!
+    \internal
+ */
+QString QJsonObject::keyAt(int i) const
+{
+    Q_ASSERT(o && i >= 0 && i < (int)o->length);
+
+    QJsonPrivate::Entry *e = o->entryAt(i);
+    return e->key();
+}
+
+/*!
+    \internal
+ */
+QJsonValue QJsonObject::valueAt(int i) const
+{
+    if (!o || i < 0 || i >= (int)o->length)
+        return QJsonValue(QJsonValue::Undefined);
+
+    QJsonPrivate::Entry *e = o->entryAt(i);
+    return QJsonValue(d, o, e->value);
+}
+
+/*!
+    \internal
+ */
+void QJsonObject::setValueAt(int i, const QJsonValue &val)
+{
+    Q_ASSERT(o && i >= 0 && i < (int)o->length);
+
+    QJsonPrivate::Entry *e = o->entryAt(i);
+    insert(e->key(), val);
+}
+
+/*! \typedef QJsonObject::Iterator
+
+    Qt-style synonym for QJsonObject::iterator.
+*/
+
+/*! \typedef QJsonObject::ConstIterator
+
+    Qt-style synonym for QJsonObject::const_iterator.
+*/
+
+
+/*! \class QJsonObject::iterator
+    \ingroup json
+    \reentrant
+    \since 5.0
+
+    \brief The QJsonDocument::iterator class provides a way to iterate over q QJsonObject
+
+
+ */
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QJsonObject &o)
+{
+    if (!o.o) {
+        dbg << "QJsonObject()";
+        return dbg;
+    }
+    QByteArray json;
+    QJsonPrivate::Writer::objectToJson(o.o, json, 0, true);
+    dbg.nospace() << "QJsonObject("
+                  << json.constData() // print as utf-8 string without extra quotation marks
+                  << ")";
+    return dbg.space();
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/json/qjsonobject.h b/src/corelib/json/qjsonobject.h
new file mode 100644 (file)
index 0000000..12e2bca
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsonparser.cpp b/src/corelib/json/qjsonparser.cpp
new file mode 100644 (file)
index 0000000..d071e35
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsonparser_p.h b/src/corelib/json/qjsonparser_p.h
new file mode 100644 (file)
index 0000000..ab8c82f
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/json/qjsonvalue.cpp
new file mode 100644 (file)
index 0000000..bd93cbf
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsonvalue.h b/src/corelib/json/qjsonvalue.h
new file mode 100644 (file)
index 0000000..6efb50b
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsonwriter.cpp b/src/corelib/json/qjsonwriter.cpp
new file mode 100644 (file)
index 0000000..1911b49
--- /dev/null
@@ -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
diff --git a/src/corelib/json/qjsonwriter_p.h b/src/corelib/json/qjsonwriter_p.h
new file mode 100644 (file)
index 0000000..f517b8e
--- /dev/null
@@ -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
index 84eb3f2..be12fda 100644 (file)
@@ -6,6 +6,7 @@ SUBDIRS=\
    global \
    io \
    itemmodels \
+   json \
    kernel \
    plugin \
    statemachine \
diff --git a/tests/auto/corelib/json/json.pro b/tests/auto/corelib/json/json.pro
new file mode 100644 (file)
index 0000000..f7b7a80
--- /dev/null
@@ -0,0 +1,6 @@
+TARGET = tst_qtjson
+QT = core testlib
+CONFIG -= app_bundle
+CONFIG += testcase
+
+SOURCES += tst_qtjson.cpp
diff --git a/tests/auto/corelib/json/test.bjson b/tests/auto/corelib/json/test.bjson
new file mode 100644 (file)
index 0000000..aa412ee
Binary files /dev/null and b/tests/auto/corelib/json/test.bjson differ
diff --git a/tests/auto/corelib/json/test.json b/tests/auto/corelib/json/test.json
new file mode 100644 (file)
index 0000000..7c935ff
--- /dev/null
@@ -0,0 +1,66 @@
+[
+    "JSON Test Pattern pass1",
+    {"object with 1 member":["array with 1 element"]},
+    {},
+    [],
+    -42,
+    true,
+    false,
+    null,
+    {
+        "integer": 1234567890,
+        "real": -9876.543210,
+        "e": 0.123456789e-12,
+        "E": 1.234567890E+34,
+        "":  23456789012E66,
+        "zero": 0,
+        "one": 1,
+        "space": " ",
+        "quote": "\"",
+        "backslash": "\\",
+        "controls": "\b\f\n\r\t",
+        "slash": "/ & \/",
+        "alpha": "abcdefghijklmnopqrstuvwxyz",
+        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+        "digit": "0123456789",
+        "0123456789": "digit",
+        "special": "`1~!@#$%^&*()_+-={\':[,]}|;.</>?",
+        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+        "true": true,
+        "false": false,
+        "null": null,
+        "array":[  ],
+        "object":{  },
+        "address": "50 St. James Street",
+        "url": "http://www.JSON.org/",
+        "comment": "// /* <!-- --",
+        "# -- --> */": " ",
+        " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5        ,          6           ,7        ],"compact":[1,2,3,4,5,6,7],
+        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+        "\/\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?" : "A key can be any string"
+    },
+    0.5 ,98.6
+,
+99.44
+,
+
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,
+2e+00,
+2e-00,
+"rosebud",
+{"foo": "bar"},
+{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}},
+{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}},
+{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}},
+{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}}
+]
+
diff --git a/tests/auto/corelib/json/test2.json b/tests/auto/corelib/json/test2.json
new file mode 100644 (file)
index 0000000..303f879
--- /dev/null
@@ -0,0 +1 @@
+{ "foo": ["ab"] }
diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp
new file mode 100644 (file)
index 0000000..d5575b0
--- /dev/null
@@ -0,0 +1,1535 @@
+/****************************************************************************
+**
+** 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 "qjsonarray.h"
+#include "qjsonobject.h"
+#include "qjsonvalue.h"
+#include "qjsondocument.h"
+
+class TestQtJson: public QObject
+{
+    Q_OBJECT
+public:
+    TestQtJson(QObject *parent = 0);
+
+private Q_SLOTS:
+    void initTestCase();
+    void cleanupTestCase();
+    void init();
+    void cleanup();
+
+    void testValueSimple();
+    void testNumbers();
+
+    void testObjectSimple();
+    void testArraySimple();
+    void testValueObject();
+    void testValueArray();
+    void testObjectNested();
+    void testArrayNested();
+    void testArrayNestedEmpty();
+    void testObjectNestedEmpty();
+
+    void testValueRef();
+    void testObjectIteration();
+    void testArrayIteration();
+
+    void testObjectFind();
+
+    void testDocument();
+
+    void nullValues();
+    void nullArrays();
+    void nullObject();
+
+    void keySorting();
+
+    void undefinedValues();
+
+    void fromVariantMap();
+    void toVariantMap();
+
+    void toJson();
+    void fromJson();
+    void fromBinary();
+    void toAndFromBinary_data();
+    void toAndFromBinary();
+    void parseNumbers();
+    void parseStrings();
+    void parseDuplicateKeys();
+    void testParser();
+
+    void compactArray();
+    void compactObject();
+
+    void validation();
+
+    void assignToDocument();
+
+    void testDuplicateKeys();
+    void testCompaction();
+    void testDebugStream();
+    void testCompactionError();
+};
+
+TestQtJson::TestQtJson(QObject *parent) : QObject(parent)
+{
+}
+
+void TestQtJson::initTestCase()
+{
+}
+
+void TestQtJson::cleanupTestCase()
+{
+}
+
+void TestQtJson::init()
+{
+}
+
+void TestQtJson::cleanup()
+{
+}
+
+void TestQtJson::testValueSimple()
+{
+    QJsonValue value(true);
+    QCOMPARE(value.type(), QJsonValue::Bool);
+    QCOMPARE(value.toDouble(), 0.);
+    QCOMPARE(value.toString(), QString());
+    QCOMPARE(value.toBool(), true);
+    QCOMPARE(value.toObject(), QJsonObject());
+    QCOMPARE(value.toArray(), QJsonArray());
+
+    value = 999.;
+    QCOMPARE(value.type(), QJsonValue::Double);
+    QCOMPARE(value.toDouble(), 999.);
+    QCOMPARE(value.toString(), QString());
+    QCOMPARE(value.toBool(), false);
+    QCOMPARE(value.toObject(), QJsonObject());
+    QCOMPARE(value.toArray(), QJsonArray());
+
+    value = QLatin1String("test");
+    QCOMPARE(value.toDouble(), 0.);
+    QCOMPARE(value.toString(), QLatin1String("test"));
+    QCOMPARE(value.toBool(), false);
+    QCOMPARE(value.toObject(), QJsonObject());
+    QCOMPARE(value.toArray(), QJsonArray());
+
+    value = true;
+    QCOMPARE(value.toDouble(), 0.);
+    QCOMPARE(value.toString(), QString());
+    QCOMPARE(value.toBool(), true);
+    QCOMPARE(value.toObject(), QJsonObject());
+    QCOMPARE(value.toArray(), QJsonArray());
+
+    value = 999.;
+    QCOMPARE(value.toDouble(), 999.);
+    QCOMPARE(value.toString(), QString());
+    QCOMPARE(value.toBool(), false);
+    QCOMPARE(value.toObject(), QJsonObject());
+    QCOMPARE(value.toArray(), QJsonArray());
+
+}
+
+void TestQtJson::testNumbers()
+{
+    {
+        int numbers[] = {
+            0,
+            -1,
+            1,
+            (1<<26),
+            (1<<27),
+            (1<<28),
+            -(1<<26),
+            -(1<<27),
+            -(1<<28),
+            (1<<26) - 1,
+            (1<<27) - 1,
+            (1<<28) - 1,
+            -((1<<26) - 1),
+            -((1<<27) - 1),
+            -((1<<28) - 1)
+        };
+        int n = sizeof(numbers)/sizeof(int);
+
+        QJsonArray array;
+        for (int i = 0; i < n; ++i)
+            array.append((double)numbers[i]);
+        for (int i = 0; i < array.size(); ++i) {
+            QCOMPARE(array.at(i).type(), QJsonValue::Double);
+            QCOMPARE(array.at(i).toDouble(), (double)numbers[i]);
+        }
+    }
+
+    {
+        double numbers[] = {
+            0,
+            -1,
+            1,
+            (1<<26),
+            (1<<27),
+            (1<<28),
+            -(1<<26),
+            -(1<<27),
+            -(1<<28),
+            (1<<26) - 1,
+            (1<<27) - 1,
+            (1<<28) - 1,
+            -((1<<26) - 1),
+            -((1<<27) - 1),
+            -((1<<28) - 1),
+            1.1,
+            0.1,
+            -0.1,
+            -1.1,
+            1e200,
+            -1e200
+        };
+        int n = sizeof(numbers)/sizeof(double);
+
+        QJsonArray array;
+        for (int i = 0; i < n; ++i)
+            array.append(numbers[i]);
+        for (int i = 0; i < array.size(); ++i) {
+            QCOMPARE(array.at(i).type(), QJsonValue::Double);
+            QCOMPARE(array.at(i).toDouble(), numbers[i]);
+        }
+    }
+
+}
+
+void TestQtJson::testObjectSimple()
+{
+    QJsonObject object;
+    object.insert("number", 999.);
+    QCOMPARE(object.value("number").type(), QJsonValue::Double);
+    QCOMPARE(object.value("number").toDouble(), 999.);
+    object.insert("string", QString::fromLatin1("test"));
+    QCOMPARE(object.value("string").type(), QJsonValue::String);
+    QCOMPARE(object.value("string").toString(), QString("test"));
+    object.insert("boolean", true);
+    QCOMPARE(object.value("boolean").toBool(), true);
+
+    QStringList keys = object.keys();
+    QVERIFY2(keys.contains("number"), "key number not found");
+    QVERIFY2(keys.contains("string"), "key string not found");
+    QVERIFY2(keys.contains("boolean"), "key boolean not found");
+
+    // if we put a JsonValue into the JsonObject and retreive
+    // it, it should be identical.
+    QJsonValue value(QLatin1String("foo"));
+    object.insert("value", value);
+    QCOMPARE(object.value("value"), value);
+
+    int size = object.size();
+    object.remove("boolean");
+    QCOMPARE(object.size(), size - 1);
+    QVERIFY2(!object.contains("boolean"), "key boolean should have been removed");
+
+    QJsonValue taken = object.take("value");
+//    QCOMPARE(taken, value);
+    QVERIFY2(!object.contains("value"), "key value should have been removed");
+
+    QString before = object.value("string").toString();
+    object.insert("string", QString::fromLatin1("foo"));
+    QVERIFY2(object.value("string").toString() != before, "value should have been updated");
+}
+
+void TestQtJson::testArraySimple()
+{
+    QJsonArray array;
+    array.append(999.);
+    array.append(QString::fromLatin1("test"));
+    array.append(true);
+
+    QJsonValue val = array.at(0);
+    QCOMPARE(array.at(0).toDouble(), 999.);
+    QCOMPARE(array.at(1).toString(), QString("test"));
+    QCOMPARE(array.at(2).toBool(), true);
+    QCOMPARE(array.size(), 3);
+
+    // if we put a JsonValue into the JsonArray and retreive
+    // it, it should be identical.
+    QJsonValue value(QLatin1String("foo"));
+    array.append(value);
+    QCOMPARE(array.at(3), value);
+
+    int size = array.size();
+    array.removeAt(2);
+    --size;
+    QCOMPARE(array.size(), size);
+
+    QJsonValue taken = array.takeAt(0);
+    --size;
+    QCOMPARE(taken.toDouble(), 999.);
+    QCOMPARE(array.size(), size);
+
+    // check whether null values work
+    array.append(QJsonValue());
+    ++size;
+    QCOMPARE(array.size(), size);
+    QCOMPARE(array.last().type(), QJsonValue::Null);
+    QCOMPARE(array.last(), QJsonValue());
+
+    QCOMPARE(array.first().type(), QJsonValue::String);
+    QCOMPARE(array.first(), QJsonValue(QLatin1String("test")));
+
+    array.prepend(false);
+    QCOMPARE(array.first().type(), QJsonValue::Bool);
+    QCOMPARE(array.first(), QJsonValue(false));
+
+    QCOMPARE(array.at(-1), QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(array.at(array.size()), QJsonValue(QJsonValue::Undefined));
+
+    array.replace(0, -555.);
+    QCOMPARE(array.first().type(), QJsonValue::Double);
+    QCOMPARE(array.first(), QJsonValue(-555.));
+    QCOMPARE(array.at(1).type(), QJsonValue::String);
+    QCOMPARE(array.at(1), QJsonValue(QLatin1String("test")));
+}
+
+void TestQtJson::testValueObject()
+{
+    QJsonObject object;
+    object.insert("number", 999.);
+    object.insert("string", QLatin1String("test"));
+    object.insert("boolean", true);
+
+    QJsonValue value(object);
+
+    // if we don't modify the original JsonObject, toObject()
+    // on the JsonValue should return the same object (non-detached).
+    QCOMPARE(value.toObject(), object);
+
+    // if we modify the original object, it should detach
+    object.insert("test", QJsonValue(QLatin1String("test")));
+    QVERIFY2(value.toObject() != object, "object should have detached");
+}
+
+void TestQtJson::testValueArray()
+{
+    QJsonArray array;
+    array.append(999.);
+    array.append(QLatin1String("test"));
+    array.append(true);
+
+    QJsonValue value(array);
+
+    // if we don't modify the original JsonArray, toArray()
+    // on the JsonValue should return the same object (non-detached).
+    QCOMPARE(value.toArray(), array);
+
+    // if we modify the original array, it should detach
+    array.append(QLatin1String("test"));
+    QVERIFY2(value.toArray() != array, "array should have detached");
+}
+
+void TestQtJson::testObjectNested()
+{
+    QJsonObject inner, outer;
+    inner.insert("number", 999.);
+    outer.insert("nested", inner);
+
+    // if we don't modify the original JsonObject, value()
+    // should return the same object (non-detached).
+    QJsonObject value = outer.value("nested").toObject();
+    QCOMPARE(value, inner);
+    QCOMPARE(value.value("number").toDouble(), 999.);
+
+    // if we modify the original object, it should detach and not
+    // affect the nested object
+    inner.insert("number", 555.);
+    value = outer.value("nested").toObject();
+    QVERIFY2(inner.value("number").toDouble() != value.value("number").toDouble(),
+             "object should have detached");
+
+    // array in object
+    QJsonArray array;
+    array.append(123.);
+    array.append(456.);
+    outer.insert("array", array);
+    QCOMPARE(outer.value("array").toArray(), array);
+    QCOMPARE(outer.value("array").toArray().at(1).toDouble(), 456.);
+
+    // two deep objects
+    QJsonObject twoDeep;
+    twoDeep.insert("boolean", true);
+    inner.insert("nested", twoDeep);
+    outer.insert("nested", inner);
+    QCOMPARE(outer.value("nested").toObject().value("nested").toObject(), twoDeep);
+    QCOMPARE(outer.value("nested").toObject().value("nested").toObject().value("boolean").toBool(),
+             true);
+}
+
+void TestQtJson::testArrayNested()
+{
+    QJsonArray inner, outer;
+    inner.append(999.);
+    outer.append(inner);
+
+    // if we don't modify the original JsonArray, value()
+    // should return the same array (non-detached).
+    QJsonArray value = outer.at(0).toArray();
+    QCOMPARE(value, inner);
+    QCOMPARE(value.at(0).toDouble(), 999.);
+
+    // if we modify the original array, it should detach and not
+    // affect the nested array
+    inner.append(555.);
+    value = outer.at(0).toArray();
+    QVERIFY2(inner.size() != value.size(), "array should have detached");
+
+    // objects in arrays
+    QJsonObject object;
+    object.insert("boolean", true);
+    outer.append(object);
+    QCOMPARE(outer.last().toObject(), object);
+    QCOMPARE(outer.last().toObject().value("boolean").toBool(), true);
+
+    // two deep arrays
+    QJsonArray twoDeep;
+    twoDeep.append(QJsonValue(QString::fromLatin1("nested")));
+    inner.append(twoDeep);
+    outer.append(inner);
+    QCOMPARE(outer.last().toArray().last().toArray(), twoDeep);
+    QCOMPARE(outer.last().toArray().last().toArray().at(0).toString(), QString("nested"));
+}
+
+void TestQtJson::testArrayNestedEmpty()
+{
+    QJsonObject object;
+    QJsonArray inner;
+    object.insert("inner", inner);
+    QJsonValue val = object.value("inner");
+    QJsonArray value = object.value("inner").toArray();
+    QCOMPARE(value.size(), 0);
+    QCOMPARE(value, inner);
+    QCOMPARE(value.size(), 0);
+    object.insert("count", 0.);
+    QCOMPARE(object.value("inner").toArray().size(), 0);
+    QVERIFY(object.value("inner").toArray().isEmpty());
+    QJsonDocument(object).toBinaryData();
+    QCOMPARE(object.value("inner").toArray().size(), 0);
+}
+
+void TestQtJson::testObjectNestedEmpty()
+{
+    QJsonObject object;
+    QJsonObject inner;
+    QJsonObject inner2;
+    object.insert("inner", inner);
+    object.insert("inner2", inner2);
+    QJsonObject value = object.value("inner").toObject();
+    QCOMPARE(value.size(), 0);
+    QCOMPARE(value, inner);
+    QCOMPARE(value.size(), 0);
+    object.insert("count", 0.);
+    QCOMPARE(object.value("inner").toObject().size(), 0);
+    QCOMPARE(object.value("inner").type(), QJsonValue::Object);
+    QJsonDocument(object).toBinaryData();
+    QVERIFY(object.value("inner").toObject().isEmpty());
+    QVERIFY(object.value("inner2").toObject().isEmpty());
+    QJsonDocument doc = QJsonDocument::fromBinaryData(QJsonDocument(object).toBinaryData());
+    QVERIFY(!doc.isNull());
+    QJsonObject reconstituted(doc.object());
+    QCOMPARE(reconstituted.value("inner").toObject().size(), 0);
+    QCOMPARE(reconstituted.value("inner").type(), QJsonValue::Object);
+    QCOMPARE(reconstituted.value("inner2").type(), QJsonValue::Object);
+}
+
+void TestQtJson::testValueRef()
+{
+    QJsonArray array;
+    array.append(1.);
+    array.append(2.);
+    array.append(3.);
+    array[1] = false;
+
+    QCOMPARE(array.size(), 3);
+    QCOMPARE(array.at(0).toDouble(), 1.);
+    QCOMPARE(array.at(2).toDouble(), 3.);
+    QCOMPARE(array.at(1).type(), QJsonValue::Bool);
+    QCOMPARE(array.at(1).toBool(), false);
+
+    QJsonObject object;
+    object[QLatin1String("key")] = true;
+    QCOMPARE(object.size(), 1);
+    object.insert(QLatin1String("null"), QJsonValue());
+    QCOMPARE(object.value(QLatin1String("null")), QJsonValue());
+    object[QLatin1String("null")] = 100.;
+    QCOMPARE(object.value(QLatin1String("null")).type(), QJsonValue::Double);
+    QJsonValue val = object[QLatin1String("null")];
+    QCOMPARE(val.toDouble(), 100.);
+    QCOMPARE(object.size(), 2);
+}
+
+void TestQtJson::testObjectIteration()
+{
+    QJsonObject object;
+    for (int i = 0; i < 10; ++i)
+        object[QString::number(i)] = (double)i;
+
+    QCOMPARE(object.size(), 10);
+
+    for (QJsonObject::iterator it = object.begin(); it != object.end(); ++it) {
+        QJsonValue value = it.value();
+        QCOMPARE((double)it.key().toInt(), value.toDouble());
+    }
+
+    {
+        QJsonObject object2 = object;
+        QVERIFY(object == object2);
+
+        QJsonValue val = *object2.begin();
+        object2.erase(object2.begin());
+        QCOMPARE(object.size(), 10);
+        QCOMPARE(object2.size(), 9);
+
+        for (QJsonObject::const_iterator it = object2.constBegin(); it != object2.constEnd(); ++it) {
+            QJsonValue value = it.value();
+            QVERIFY(it.value() != val);
+            QCOMPARE((double)it.key().toInt(), value.toDouble());
+        }
+    }
+
+    {
+        QJsonObject::Iterator it = object.begin();
+        it += 5;
+        QCOMPARE(QJsonValue(it.value()).toDouble(), 5.);
+        it -= 3;
+        QCOMPARE(QJsonValue(it.value()).toDouble(), 2.);
+        QJsonObject::Iterator it2 = it + 5;
+        QCOMPARE(QJsonValue(it2.value()).toDouble(), 7.);
+        it2 = it - 1;
+        QCOMPARE(QJsonValue(it2.value()).toDouble(), 1.);
+    }
+
+    {
+        QJsonObject::ConstIterator it = object.constBegin();
+        it += 5;
+        QCOMPARE(QJsonValue(it.value()).toDouble(), 5.);
+        it -= 3;
+        QCOMPARE(QJsonValue(it.value()).toDouble(), 2.);
+        QJsonObject::ConstIterator it2 = it + 5;
+        QCOMPARE(QJsonValue(it2.value()).toDouble(), 7.);
+        it2 = it - 1;
+        QCOMPARE(QJsonValue(it2.value()).toDouble(), 1.);
+    }
+
+    QJsonObject::Iterator it = object.begin();
+    while (!object.isEmpty())
+        it = object.erase(it);
+    QCOMPARE(object.size() , 0);
+    QVERIFY(it == object.end());
+}
+
+void TestQtJson::testArrayIteration()
+{
+    QJsonArray array;
+    for (int i = 0; i < 10; ++i)
+        array.append(i);
+
+    QCOMPARE(array.size(), 10);
+
+    int i = 0;
+    for (QJsonArray::iterator it = array.begin(); it != array.end(); ++it, ++i) {
+        QJsonValue value = (*it);
+        QCOMPARE((double)i, value.toDouble());
+    }
+
+    {
+        QJsonArray array2 = array;
+        QVERIFY(array == array2);
+
+        QJsonValue val = *array2.begin();
+        array2.erase(array2.begin());
+        QCOMPARE(array.size(), 10);
+        QCOMPARE(array2.size(), 9);
+
+        i = 1;
+        for (QJsonArray::const_iterator it = array2.constBegin(); it != array2.constEnd(); ++it, ++i) {
+            QJsonValue value = (*it);
+            QCOMPARE((double)i, value.toDouble());
+        }
+    }
+
+    {
+        QJsonArray::Iterator it = array.begin();
+        it += 5;
+        QCOMPARE(QJsonValue((*it)).toDouble(), 5.);
+        it -= 3;
+        QCOMPARE(QJsonValue((*it)).toDouble(), 2.);
+        QJsonArray::Iterator it2 = it + 5;
+        QCOMPARE(QJsonValue(*it2).toDouble(), 7.);
+        it2 = it - 1;
+        QCOMPARE(QJsonValue(*it2).toDouble(), 1.);
+    }
+
+    {
+        QJsonArray::ConstIterator it = array.constBegin();
+        it += 5;
+        QCOMPARE(QJsonValue((*it)).toDouble(), 5.);
+        it -= 3;
+        QCOMPARE(QJsonValue((*it)).toDouble(), 2.);
+        QJsonArray::ConstIterator it2 = it + 5;
+        QCOMPARE(QJsonValue(*it2).toDouble(), 7.);
+        it2 = it - 1;
+        QCOMPARE(QJsonValue(*it2).toDouble(), 1.);
+    }
+
+    QJsonArray::Iterator it = array.begin();
+    while (!array.isEmpty())
+        it = array.erase(it);
+    QCOMPARE(array.size() , 0);
+    QVERIFY(it == array.end());
+}
+
+void TestQtJson::testObjectFind()
+{
+    QJsonObject object;
+    for (int i = 0; i < 10; ++i)
+        object[QString::number(i)] = i;
+
+    QCOMPARE(object.size(), 10);
+
+    QJsonObject::iterator it = object.find(QLatin1String("1"));
+    QCOMPARE((*it).toDouble(), 1.);
+    it = object.find(QLatin1String("11"));
+    QVERIFY((*it).type() == QJsonValue::Undefined);
+    QVERIFY(it == object.end());
+
+    QJsonObject::const_iterator cit = object.constFind(QLatin1String("1"));
+    QCOMPARE((*cit).toDouble(), 1.);
+    cit = object.constFind(QLatin1String("11"));
+    QVERIFY((*it).type() == QJsonValue::Undefined);
+    QVERIFY(it == object.end());
+}
+
+void TestQtJson::testDocument()
+{
+    QJsonDocument doc;
+    QCOMPARE(doc.isEmpty(), true);
+    QCOMPARE(doc.isArray(), false);
+    QCOMPARE(doc.isObject(), false);
+
+    QJsonObject object;
+    doc.setObject(object);
+    QCOMPARE(doc.isEmpty(), false);
+    QCOMPARE(doc.isArray(), false);
+    QCOMPARE(doc.isObject(), true);
+
+    object.insert(QLatin1String("Key"), QLatin1String("Value"));
+    doc.setObject(object);
+    QCOMPARE(doc.isEmpty(), false);
+    QCOMPARE(doc.isArray(), false);
+    QCOMPARE(doc.isObject(), true);
+    QVERIFY(doc.object() == object);
+    QVERIFY(doc.array() == QJsonArray());
+
+    doc = QJsonDocument();
+    QCOMPARE(doc.isEmpty(), true);
+    QCOMPARE(doc.isArray(), false);
+    QCOMPARE(doc.isObject(), false);
+
+    QJsonArray array;
+    doc.setArray(array);
+    QCOMPARE(doc.isEmpty(), false);
+    QCOMPARE(doc.isArray(), true);
+    QCOMPARE(doc.isObject(), false);
+
+    array.append(QLatin1String("Value"));
+    doc.setArray(array);
+    QCOMPARE(doc.isEmpty(), false);
+    QCOMPARE(doc.isArray(), true);
+    QCOMPARE(doc.isObject(), false);
+    QVERIFY(doc.array() == array);
+    QVERIFY(doc.object() == QJsonObject());
+
+    QJsonObject outer;
+    outer.insert(QLatin1String("outerKey"), 22);
+    QJsonObject inner;
+    inner.insert(QLatin1String("innerKey"), 42);
+    outer.insert(QLatin1String("innter"), inner);
+    QJsonArray innerArray;
+    innerArray.append(23);
+    outer.insert(QLatin1String("innterArray"), innerArray);
+
+    QJsonDocument doc2(outer.value(QLatin1String("innter")).toObject());
+    QVERIFY(doc2.object().contains(QLatin1String("innerKey")));
+    QCOMPARE(doc2.object().value(QLatin1String("innerKey")), QJsonValue(42));
+
+    QJsonDocument doc3;
+    doc3.setObject(outer.value(QLatin1String("innter")).toObject());
+    QCOMPARE(doc3.isArray(), false);
+    QCOMPARE(doc3.isObject(), true);
+    QVERIFY(doc3.object().contains(QLatin1String("innerKey")));
+    QCOMPARE(doc3.object().value(QLatin1String("innerKey")), QJsonValue(42));
+
+    QJsonDocument doc4(outer.value(QLatin1String("innterArray")).toArray());
+    QCOMPARE(doc4.isArray(), true);
+    QCOMPARE(doc4.isObject(), false);
+    QCOMPARE(doc4.array().size(), 1);
+    QCOMPARE(doc4.array().at(0), QJsonValue(23));
+
+    QJsonDocument doc5;
+    doc5.setArray(outer.value(QLatin1String("innterArray")).toArray());
+    QCOMPARE(doc5.isArray(), true);
+    QCOMPARE(doc5.isObject(), false);
+    QCOMPARE(doc5.array().size(), 1);
+    QCOMPARE(doc5.array().at(0), QJsonValue(23));
+}
+
+void TestQtJson::nullValues()
+{
+    QJsonArray array;
+    array.append(QJsonValue());
+
+    QCOMPARE(array.size(), 1);
+    QCOMPARE(array.at(0), QJsonValue());
+
+    QJsonObject object;
+    object.insert(QString("key"), QJsonValue());
+    QCOMPARE(object.contains("key"), true);
+    QCOMPARE(object.size(), 1);
+    QCOMPARE(object.value("key"), QJsonValue());
+}
+
+void TestQtJson::nullArrays()
+{
+    QJsonArray nullArray;
+    QJsonArray nonNull;
+    nonNull.append(QLatin1String("bar"));
+
+    QCOMPARE(nullArray, QJsonArray());
+    QVERIFY(nullArray != nonNull);
+    QVERIFY(nonNull != nullArray);
+
+    QCOMPARE(nullArray.size(), 0);
+    QCOMPARE(nullArray.takeAt(0), QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(nullArray.first(), QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(nullArray.last(), QJsonValue(QJsonValue::Undefined));
+    nullArray.removeAt(0);
+    nullArray.removeAt(-1);
+
+    nullArray.append(QString("bar"));
+    nullArray.removeAt(0);
+
+    QCOMPARE(nullArray.size(), 0);
+    QCOMPARE(nullArray.takeAt(0), QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(nullArray.first(), QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(nullArray.last(), QJsonValue(QJsonValue::Undefined));
+    nullArray.removeAt(0);
+    nullArray.removeAt(-1);
+}
+
+void TestQtJson::nullObject()
+{
+    QJsonObject nullObject;
+    QJsonObject nonNull;
+    nonNull.insert(QLatin1String("foo"), QLatin1String("bar"));
+
+    QCOMPARE(nullObject, QJsonObject());
+    QVERIFY(nullObject != nonNull);
+    QVERIFY(nonNull != nullObject);
+
+    QCOMPARE(nullObject.size(), 0);
+    QCOMPARE(nullObject.keys(), QStringList());
+    nullObject.remove("foo");
+    QCOMPARE(nullObject, QJsonObject());
+    QCOMPARE(nullObject.take("foo"), QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(nullObject.contains("foo"), false);
+
+    nullObject.insert("foo", QString("bar"));
+    nullObject.remove("foo");
+
+    QCOMPARE(nullObject.size(), 0);
+    QCOMPARE(nullObject.keys(), QStringList());
+    nullObject.remove("foo");
+    QCOMPARE(nullObject, QJsonObject());
+    QCOMPARE(nullObject.take("foo"), QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(nullObject.contains("foo"), false);
+}
+
+void TestQtJson::keySorting()
+{
+    const char *json = "{ \"B\": true, \"A\": false }";
+    QJsonDocument doc = QJsonDocument::fromJson(json);
+
+    QCOMPARE(doc.isObject(), true);
+
+    QJsonObject o = doc.object();
+    QCOMPARE(o.size(), 2);
+    QJsonObject::const_iterator it = o.constBegin();
+    QCOMPARE(it.key(), QLatin1String("A"));
+    ++it;
+    QCOMPARE(it.key(), QLatin1String("B"));
+}
+
+void TestQtJson::undefinedValues()
+{
+    QJsonObject object;
+    object.insert("Key", QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(object.size(), 0);
+
+    object.insert("Key", QLatin1String("Value"));
+    QCOMPARE(object.size(), 1);
+    QCOMPARE(object.value("Key").type(), QJsonValue::String);
+    QCOMPARE(object.value("foo").type(), QJsonValue::Undefined);
+    object.insert("Key", QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(object.size(), 0);
+    QCOMPARE(object.value("Key").type(), QJsonValue::Undefined);
+
+    QJsonArray array;
+    array.append(QJsonValue(QJsonValue::Undefined));
+    QCOMPARE(array.size(), 1);
+    QCOMPARE(array.at(0).type(), QJsonValue::Null);
+
+    QCOMPARE(array.at(1).type(), QJsonValue::Undefined);
+    QCOMPARE(array.at(-1).type(), QJsonValue::Undefined);
+}
+
+
+void TestQtJson::fromVariantMap()
+{
+    QVariantMap map;
+    map.insert(QLatin1String("key1"), QLatin1String("value1"));
+    map.insert(QLatin1String("key2"), QLatin1String("value2"));
+    QJsonObject object = QJsonObject::fromVariantMap(map);
+    QCOMPARE(object.size(), 2);
+    QCOMPARE(object.value(QLatin1String("key1")), QJsonValue(QLatin1String("value1")));
+    QCOMPARE(object.value(QLatin1String("key2")), QJsonValue(QLatin1String("value2")));
+
+    QVariantList list;
+    list.append(true);
+    list.append(QVariant());
+    list.append(999.);
+    list.append(QLatin1String("foo"));
+    map.insert("list", list);
+    object = QJsonObject::fromVariantMap(map);
+    QCOMPARE(object.size(), 3);
+    QCOMPARE(object.value(QLatin1String("key1")), QJsonValue(QLatin1String("value1")));
+    QCOMPARE(object.value(QLatin1String("key2")), QJsonValue(QLatin1String("value2")));
+    QCOMPARE(object.value(QLatin1String("list")).type(), QJsonValue::Array);
+    QJsonArray array = object.value(QLatin1String("list")).toArray();
+    QCOMPARE(array.size(), 4);
+    QCOMPARE(array.at(0).type(), QJsonValue::Bool);
+    QCOMPARE(array.at(0).toBool(), true);
+    QCOMPARE(array.at(1).type(), QJsonValue::Null);
+    QCOMPARE(array.at(2).type(), QJsonValue::Double);
+    QCOMPARE(array.at(2).toDouble(), 999.);
+    QCOMPARE(array.at(3).type(), QJsonValue::String);
+    QCOMPARE(array.at(3).toString(), QLatin1String("foo"));
+}
+
+void TestQtJson::toVariantMap()
+{
+    QJsonObject object;
+    object.insert("Key", QString("Value"));
+    object.insert("null", QJsonValue());
+    QJsonArray array;
+    array.append(true);
+    array.append(999.);
+    array.append(QLatin1String("string"));
+    array.append(QJsonValue());
+    object.insert("Array", array);
+
+    QVariantMap map = object.toVariantMap();
+
+    QCOMPARE(map.size(), 3);
+    QCOMPARE(map.value("Key"), QVariant(QString("Value")));
+    QCOMPARE(map.value("null"), QVariant());
+    QCOMPARE(map.value("Array").type(), QVariant::List);
+    QVariantList list = map.value("Array").toList();
+    QCOMPARE(list.size(), 4);
+    QCOMPARE(list.at(0), QVariant(true));
+    QCOMPARE(list.at(1), QVariant(999.));
+    QCOMPARE(list.at(2), QVariant(QLatin1String("string")));
+    QCOMPARE(list.at(3), QVariant());
+}
+
+void TestQtJson::toJson()
+{
+    QJsonObject object;
+    object.insert("\\Key\n", QString("Value"));
+    object.insert("null", QJsonValue());
+    QJsonArray array;
+    array.append(true);
+    array.append(999.);
+    array.append(QLatin1String("string"));
+    array.append(QJsonValue());
+    array.append(QLatin1String("\\\a\n\r\b\tabcABC\""));
+    object.insert("Array", array);
+
+    QByteArray json = QJsonDocument(object).toJson();
+
+    QByteArray expected =
+            "{\n"
+            "    \"Array\": [\n"
+            "        true,\n"
+            "        999,\n"
+            "        \"string\",\n"
+            "        null,\n"
+            "        \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n"
+            "    ],\n"
+            "    \"\\\\Key\\n\": \"Value\",\n"
+            "    \"null\": null\n"
+            "}\n";
+    QCOMPARE(json, expected);
+
+    QJsonDocument doc;
+    doc.setObject(object);
+    json = doc.toJson();
+    QCOMPARE(json, expected);
+
+    doc.setArray(array);
+    json = doc.toJson();
+    expected =
+            "[\n"
+            "    true,\n"
+            "    999,\n"
+            "    \"string\",\n"
+            "    null,\n"
+            "    \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n"
+            "]\n";
+    QCOMPARE(json, expected);
+}
+
+void TestQtJson::fromJson()
+{
+    {
+        QByteArray json = "[\n    true\n]\n";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+        QVERIFY(!doc.isEmpty());
+        QCOMPARE(doc.isArray(), true);
+        QCOMPARE(doc.isObject(), false);
+        QJsonArray array = doc.array();
+        QCOMPARE(array.size(), 1);
+        QCOMPARE(array.at(0).type(), QJsonValue::Bool);
+        QCOMPARE(array.at(0).toBool(), true);
+        QCOMPARE(doc.toJson(), json);
+    }
+    {
+        QByteArray json = "[]";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+        QVERIFY(!doc.isEmpty());
+        QCOMPARE(doc.isArray(), true);
+        QCOMPARE(doc.isObject(), false);
+        QJsonArray array = doc.array();
+        QCOMPARE(array.size(), 0);
+    }
+    {
+        QByteArray json = "{}";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+        QVERIFY(!doc.isEmpty());
+        QCOMPARE(doc.isArray(), false);
+        QCOMPARE(doc.isObject(), true);
+        QJsonObject object = doc.object();
+        QCOMPARE(object.size(), 0);
+    }
+    {
+        QByteArray json = "{\n    \"Key\": true\n}\n";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+        QVERIFY(!doc.isEmpty());
+        QCOMPARE(doc.isArray(), false);
+        QCOMPARE(doc.isObject(), true);
+        QJsonObject object = doc.object();
+        QCOMPARE(object.size(), 1);
+        QCOMPARE(object.value("Key"), QJsonValue(true));
+        QCOMPARE(doc.toJson(), json);
+    }
+    {
+        QByteArray json = "[ null, true, false, \"Foo\", 1, [], {} ]";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+        QVERIFY(!doc.isEmpty());
+        QCOMPARE(doc.isArray(), true);
+        QCOMPARE(doc.isObject(), false);
+        QJsonArray array = doc.array();
+        QCOMPARE(array.size(), 7);
+        QCOMPARE(array.at(0).type(), QJsonValue::Null);
+        QCOMPARE(array.at(1).type(), QJsonValue::Bool);
+        QCOMPARE(array.at(1).toBool(), true);
+        QCOMPARE(array.at(2).type(), QJsonValue::Bool);
+        QCOMPARE(array.at(2).toBool(), false);
+        QCOMPARE(array.at(3).type(), QJsonValue::String);
+        QCOMPARE(array.at(3).toString(), QLatin1String("Foo"));
+        QCOMPARE(array.at(4).type(), QJsonValue::Double);
+        QCOMPARE(array.at(4).toDouble(), 1.);
+        QCOMPARE(array.at(5).type(), QJsonValue::Array);
+        QCOMPARE(array.at(5).toArray().size(), 0);
+        QCOMPARE(array.at(6).type(), QJsonValue::Object);
+        QCOMPARE(array.at(6).toObject().size(), 0);
+    }
+    {
+        QByteArray json = "{ \"0\": null, \"1\": true, \"2\": false, \"3\": \"Foo\", \"4\": 1, \"5\": [], \"6\": {} }";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+        QVERIFY(!doc.isEmpty());
+        QCOMPARE(doc.isArray(), false);
+        QCOMPARE(doc.isObject(), true);
+        QJsonObject object = doc.object();
+        QCOMPARE(object.size(), 7);
+        QCOMPARE(object.value("0").type(), QJsonValue::Null);
+        QCOMPARE(object.value("1").type(), QJsonValue::Bool);
+        QCOMPARE(object.value("1").toBool(), true);
+        QCOMPARE(object.value("2").type(), QJsonValue::Bool);
+        QCOMPARE(object.value("2").toBool(), false);
+        QCOMPARE(object.value("3").type(), QJsonValue::String);
+        QCOMPARE(object.value("3").toString(), QLatin1String("Foo"));
+        QCOMPARE(object.value("4").type(), QJsonValue::Double);
+        QCOMPARE(object.value("4").toDouble(), 1.);
+        QCOMPARE(object.value("5").type(), QJsonValue::Array);
+        QCOMPARE(object.value("5").toArray().size(), 0);
+        QCOMPARE(object.value("6").type(), QJsonValue::Object);
+        QCOMPARE(object.value("6").toObject().size(), 0);
+    }
+}
+
+void TestQtJson::fromBinary()
+{
+    QFile file(QLatin1String("test.json"));
+    file.open(QFile::ReadOnly);
+    QByteArray testJson = file.readAll();
+
+    QJsonDocument doc = QJsonDocument::fromJson(testJson);
+    QJsonDocument outdoc = QJsonDocument::fromBinaryData(doc.toBinaryData());
+    QVERIFY(!outdoc.isNull());
+    QVERIFY(doc == outdoc);
+
+    QFile bfile(QLatin1String("test.bjson"));
+    bfile.open(QFile::ReadOnly);
+    QByteArray binary = bfile.readAll();
+
+    QJsonDocument bdoc = QJsonDocument::fromBinaryData(binary);
+    QVERIFY(!bdoc.isNull());
+    QVERIFY(doc.toVariant() == bdoc.toVariant());
+    QVERIFY(doc == bdoc);
+}
+
+void TestQtJson::toAndFromBinary_data()
+{
+    QTest::addColumn<QString>("filename");
+    QTest::newRow("test.json") << QString::fromLatin1("test.json");
+    QTest::newRow("test2.json") << QString::fromLatin1("test2.json");
+}
+
+void TestQtJson::toAndFromBinary()
+{
+    QFETCH(QString, filename);
+    QFile file(filename);
+    QVERIFY(file.open(QFile::ReadOnly));
+    QByteArray data = file.readAll();
+
+    QJsonDocument doc = QJsonDocument::fromJson(data);
+    QVERIFY(!doc.isNull());
+    QJsonDocument outdoc = QJsonDocument::fromBinaryData(doc.toBinaryData());
+    QVERIFY(!outdoc.isNull());
+    QVERIFY(doc == outdoc);
+}
+
+void TestQtJson::parseNumbers()
+{
+    {
+        // test number parsing
+        struct Numbers {
+            const char *str;
+            int n;
+        };
+        Numbers numbers [] = {
+            { "0", 0 },
+            { "1", 1 },
+            { "10", 10 },
+            { "-1", -1 },
+            { "100000", 100000 },
+            { "-999", -999 }
+        };
+        int size = sizeof(numbers)/sizeof(Numbers);
+        for (int i = 0; i < size; ++i) {
+            QByteArray json = "[ ";
+            json += numbers[i].str;
+            json += " ]";
+            QJsonDocument doc = QJsonDocument::fromJson(json);
+            QVERIFY(!doc.isEmpty());
+            QCOMPARE(doc.isArray(), true);
+            QCOMPARE(doc.isObject(), false);
+            QJsonArray array = doc.array();
+            QCOMPARE(array.size(), 1);
+            QJsonValue val = array.at(0);
+            QCOMPARE(val.type(), QJsonValue::Double);
+            QCOMPARE(val.toDouble(), (double)numbers[i].n);
+        }
+    }
+    {
+        // test number parsing
+        struct Numbers {
+            const char *str;
+            double n;
+        };
+        Numbers numbers [] = {
+            { "0", 0 },
+            { "1", 1 },
+            { "10", 10 },
+            { "-1", -1 },
+            { "100000", 100000 },
+            { "-999", -999 },
+            { "1.1", 1.1 },
+            { "1e10", 1e10 },
+            { "-1.1", -1.1 },
+            { "-1e10", -1e10 },
+            { "-1E10", -1e10 },
+            { "1.1e10", 1.1e10 },
+            { "1.1e308", 1.1e308 },
+            { "-1.1e308", -1.1e308 },
+            { "1.1e-308", 1.1e-308 },
+            { "-1.1e-308", -1.1e-308 },
+            { "1.1e+308", 1.1e+308 },
+            { "-1.1e+308", -1.1e+308 },
+            { "1.e+308", 1.e+308 },
+            { "-1.e+308", -1.e+308 }
+        };
+        int size = sizeof(numbers)/sizeof(Numbers);
+        for (int i = 0; i < size; ++i) {
+            QByteArray json = "[ ";
+            json += numbers[i].str;
+            json += " ]";
+            QJsonDocument doc = QJsonDocument::fromJson(json);
+            QVERIFY(!doc.isEmpty());
+            QCOMPARE(doc.isArray(), true);
+            QCOMPARE(doc.isObject(), false);
+            QJsonArray array = doc.array();
+            QCOMPARE(array.size(), 1);
+            QJsonValue val = array.at(0);
+            QCOMPARE(val.type(), QJsonValue::Double);
+            QCOMPARE(val.toDouble(), numbers[i].n);
+        }
+    }
+}
+
+void TestQtJson::parseStrings()
+{
+    const char *strings [] =
+    {
+        "Foo",
+        "abc\\\"abc",
+        "abc\\\\abc",
+        "abc\\babc",
+        "abc\\fabc",
+        "abc\\nabc",
+        "abc\\rabc",
+        "abc\\tabc",
+        "abc\\u0019abc",
+        "abcЂabc",
+    };
+    int size = sizeof(strings)/sizeof(const char *);
+
+    for (int i = 0; i < size; ++i) {
+        QByteArray json = "[\n    \"";
+        json += strings[i];
+        json += "\"\n]\n";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+        QVERIFY(!doc.isEmpty());
+        QCOMPARE(doc.isArray(), true);
+        QCOMPARE(doc.isObject(), false);
+        QJsonArray array = doc.array();
+        QCOMPARE(array.size(), 1);
+        QJsonValue val = array.at(0);
+        QCOMPARE(val.type(), QJsonValue::String);
+
+        QCOMPARE(doc.toJson(), json);
+    }
+
+    struct Pairs {
+        const char *in;
+        const char *out;
+    };
+    Pairs pairs [] = {
+        { "abc\\/abc", "abc/abc" },
+        { "abc\\u0402abc", "abcЂabc" },
+        { "abc\\u0065abc", "abceabc" }
+    };
+    size = sizeof(pairs)/sizeof(Pairs);
+
+    for (int i = 0; i < size; ++i) {
+        QByteArray json = "[\n    \"";
+        json += pairs[i].in;
+        json += "\"\n]\n";
+        QByteArray out = "[\n    \"";
+        out += pairs[i].out;
+        out += "\"\n]\n";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+        QVERIFY(!doc.isEmpty());
+        QCOMPARE(doc.isArray(), true);
+        QCOMPARE(doc.isObject(), false);
+        QJsonArray array = doc.array();
+        QCOMPARE(array.size(), 1);
+        QJsonValue val = array.at(0);
+        QCOMPARE(val.type(), QJsonValue::String);
+
+        QCOMPARE(doc.toJson(), out);
+    }
+
+}
+
+void TestQtJson::parseDuplicateKeys()
+{
+    const char *json = "{ \"B\": true, \"A\": null, \"B\": false }";
+
+    QJsonDocument doc = QJsonDocument::fromJson(json);
+    QCOMPARE(doc.isObject(), true);
+
+    QJsonObject o = doc.object();
+    QCOMPARE(o.size(), 2);
+    QJsonObject::const_iterator it = o.constBegin();
+    QCOMPARE(it.key(), QLatin1String("A"));
+    QCOMPARE(it.value(), QJsonValue());
+    ++it;
+    QCOMPARE(it.key(), QLatin1String("B"));
+    QCOMPARE(it.value(), QJsonValue(false));
+}
+
+void TestQtJson::testParser()
+{
+    QFile file(QLatin1String("test.json"));
+    file.open(QFile::ReadOnly);
+    QByteArray testJson = file.readAll();
+
+    QJsonDocument doc = QJsonDocument::fromJson(testJson);
+    QVERIFY(!doc.isEmpty());
+}
+
+void TestQtJson::compactArray()
+{
+    QJsonArray array;
+    array.append(QLatin1String("First Entry"));
+    array.append(QLatin1String("Second Entry"));
+    array.append(QLatin1String("Third Entry"));
+    QJsonDocument doc(array);
+    int s =  doc.toBinaryData().size();
+    array.removeAt(1);
+    doc.setArray(array);
+    QVERIFY(s > doc.toBinaryData().size());
+    s = doc.toBinaryData().size();
+    QCOMPARE(doc.toJson(),
+             QByteArray("[\n"
+                        "    \"First Entry\",\n"
+                        "    \"Third Entry\"\n"
+                        "]\n"));
+
+    array.removeAt(0);
+    doc.setArray(array);
+    QVERIFY(s > doc.toBinaryData().size());
+    s = doc.toBinaryData().size();
+    QCOMPARE(doc.toJson(),
+             QByteArray("[\n"
+                        "    \"Third Entry\"\n"
+                        "]\n"));
+
+    array.removeAt(0);
+    doc.setArray(array);
+    QVERIFY(s > doc.toBinaryData().size());
+    s = doc.toBinaryData().size();
+    QCOMPARE(doc.toJson(),
+             QByteArray("[\n"
+                        "]\n"));
+
+}
+
+void TestQtJson::compactObject()
+{
+    QJsonObject object;
+    object.insert(QLatin1String("Key1"), QLatin1String("First Entry"));
+    object.insert(QLatin1String("Key2"), QLatin1String("Second Entry"));
+    object.insert(QLatin1String("Key3"), QLatin1String("Third Entry"));
+    QJsonDocument doc(object);
+    int s =  doc.toBinaryData().size();
+    object.remove(QLatin1String("Key2"));
+    doc.setObject(object);
+    QVERIFY(s > doc.toBinaryData().size());
+    s = doc.toBinaryData().size();
+    QCOMPARE(doc.toJson(),
+             QByteArray("{\n"
+                        "    \"Key1\": \"First Entry\",\n"
+                        "    \"Key3\": \"Third Entry\"\n"
+                        "}\n"));
+
+    object.remove(QLatin1String("Key1"));
+    doc.setObject(object);
+    QVERIFY(s > doc.toBinaryData().size());
+    s = doc.toBinaryData().size();
+    QCOMPARE(doc.toJson(),
+             QByteArray("{\n"
+                        "    \"Key3\": \"Third Entry\"\n"
+                        "}\n"));
+
+    object.remove(QLatin1String("Key3"));
+    doc.setObject(object);
+    QVERIFY(s > doc.toBinaryData().size());
+    s = doc.toBinaryData().size();
+    QCOMPARE(doc.toJson(),
+             QByteArray("{\n"
+                        "}\n"));
+
+}
+
+void TestQtJson::validation()
+{
+    // this basically tests that we don't crash on corrupt data
+    QFile file(QLatin1String("test.json"));
+    file.open(QFile::ReadOnly);
+    QByteArray testJson = file.readAll();
+
+    QJsonDocument doc = QJsonDocument::fromJson(testJson);
+
+    QByteArray binary = doc.toBinaryData();
+
+    // only test the first 1000 bytes. Testing the full file takes too long
+    for (int i = 0; i < 1000; ++i) {
+        QByteArray corrupted = binary;
+        corrupted[i] = 0xff;
+        QJsonDocument doc = QJsonDocument::fromBinaryData(corrupted);
+        if (doc.isNull())
+            continue;
+        QByteArray json = doc.toJson();
+    }
+
+
+    QFile file2(QLatin1String("foo.json"));
+    file2.open(QFile::ReadOnly);
+    testJson = file2.readAll();
+
+    doc = QJsonDocument::fromJson(testJson);
+
+    binary = doc.toBinaryData();
+
+    for (int i = 0; i < binary.size(); ++i) {
+        QByteArray corrupted = binary;
+        corrupted[i] = 0xff;
+        QJsonDocument doc = QJsonDocument::fromBinaryData(corrupted);
+        if (doc.isNull())
+            continue;
+        QByteArray json = doc.toJson();
+
+        corrupted = binary;
+        corrupted[i] = 0x00;
+        doc = QJsonDocument::fromBinaryData(corrupted);
+        if (doc.isNull())
+            continue;
+        json = doc.toJson();
+    }
+}
+
+void TestQtJson::assignToDocument()
+{
+    {
+        const char *json = "{ \"inner\": { \"key\": true } }";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+
+        QJsonObject o = doc.object();
+        QJsonValue inner = o.value("inner");
+
+        QJsonDocument innerDoc(inner.toObject());
+
+        QVERIFY(innerDoc != doc);
+        QVERIFY(innerDoc.object() == inner.toObject());
+    }
+    {
+        const char *json = "[ [ true ] ]";
+        QJsonDocument doc = QJsonDocument::fromJson(json);
+
+        QJsonArray a = doc.array();
+        QJsonValue inner = a.at(0);
+
+        QJsonDocument innerDoc(inner.toArray());
+
+        QVERIFY(innerDoc != doc);
+        QVERIFY(innerDoc.array() == inner.toArray());
+    }
+}
+
+
+void TestQtJson::testDuplicateKeys()
+{
+    QJsonObject obj;
+    obj.insert(QLatin1String("foo"), QLatin1String("bar"));
+    obj.insert(QLatin1String("foo"), QLatin1String("zap"));
+    QCOMPARE(obj.size(), 1);
+    QCOMPARE(obj.value(QLatin1String("foo")).toString(), QLatin1String("zap"));
+}
+
+void TestQtJson::testCompaction()
+{
+    // modify object enough times to trigger compactionCounter
+    // and make sure the data is still valid
+    QJsonObject obj;
+    for (int i = 0; i < 33; ++i) {
+        obj.remove(QLatin1String("foo"));
+        obj.insert(QLatin1String("foo"), QLatin1String("bar"));
+    }
+    QCOMPARE(obj.size(), 1);
+    QCOMPARE(obj.value(QLatin1String("foo")).toString(), QLatin1String("bar"));
+
+    QJsonDocument doc = QJsonDocument::fromBinaryData(QJsonDocument(obj).toBinaryData());
+    QVERIFY(!doc.isNull());
+    QVERIFY(!doc.isEmpty());
+    QCOMPARE(doc.isArray(), false);
+    QCOMPARE(doc.isObject(), true);
+    QVERIFY(doc.object() == obj);
+}
+
+void TestQtJson::testDebugStream()
+{
+    {
+        // QJsonObject
+
+        QJsonObject object;
+        QTest::ignoreMessage(QtDebugMsg, "QJsonObject() ");
+        qDebug() << object;
+
+        object.insert(QLatin1String("foo"), QLatin1String("bar"));
+        QTest::ignoreMessage(QtDebugMsg, "QJsonObject({\"foo\": \"bar\"}) ");
+        qDebug() << object;
+    }
+
+    {
+        // QJsonArray
+
+        QJsonArray array;
+        QTest::ignoreMessage(QtDebugMsg, "QJsonArray() ");
+        qDebug() << array;
+
+        array.append(1);
+        array.append(QLatin1String("foo"));
+        QTest::ignoreMessage(QtDebugMsg, "QJsonArray([1,\"foo\"]) ");
+        qDebug() << array;
+    }
+
+    {
+        // QJsonDocument
+
+        QJsonDocument doc;
+        QTest::ignoreMessage(QtDebugMsg, "QJsonDocument() ");
+        qDebug() << doc;
+
+        QJsonObject object;
+        object.insert(QLatin1String("foo"), QLatin1String("bar"));
+        doc.setObject(object);
+        QTest::ignoreMessage(QtDebugMsg, "QJsonDocument({\"foo\": \"bar\"}) ");
+        qDebug() << doc;
+
+        QJsonArray array;
+        array.append(1);
+        array.append(QLatin1String("foo"));
+        QTest::ignoreMessage(QtDebugMsg, "QJsonDocument([1,\"foo\"]) ");
+        doc.setArray(array);
+        qDebug() << doc;
+    }
+
+    {
+        // QJsonValue
+
+        QJsonValue value;
+
+        QTest::ignoreMessage(QtDebugMsg, "QJsonValue(null) ");
+        qDebug() << value;
+
+        value = QJsonValue(true); // bool
+        QTest::ignoreMessage(QtDebugMsg, "QJsonValue(bool, true) ");
+        qDebug() << value;
+
+        value = QJsonValue((double)4.2); // double
+        QTest::ignoreMessage(QtDebugMsg, "QJsonValue(double, 4.2) ");
+        qDebug() << value;
+
+        value = QJsonValue((int)42); // int
+        QTest::ignoreMessage(QtDebugMsg, "QJsonValue(double, 42) ");
+        qDebug() << value;
+
+        value = QJsonValue(QLatin1String("foo")); // string
+        QTest::ignoreMessage(QtDebugMsg, "QJsonValue(string, \"foo\") ");
+        qDebug() << value;
+
+        QJsonArray array;
+        array.append(1);
+        array.append(QLatin1String("foo"));
+        value = QJsonValue(array); // array
+        QTest::ignoreMessage(QtDebugMsg, "QJsonValue(array, QJsonArray([1,\"foo\"]) ) ");
+        qDebug() << value;
+
+        QJsonObject object;
+        object.insert(QLatin1String("foo"), QLatin1String("bar"));
+        value = QJsonValue(object); // object
+        QTest::ignoreMessage(QtDebugMsg, "QJsonValue(object, QJsonObject({\"foo\": \"bar\"}) ) ");
+        qDebug() << value;
+    }
+}
+
+void TestQtJson::testCompactionError()
+{
+    QJsonObject schemaObject;
+    schemaObject.insert("_Type", QLatin1String("_SchemaType"));
+    schemaObject.insert("name", QLatin1String("Address"));
+    schemaObject.insert("schema", QJsonObject());
+    {
+        QJsonObject content(schemaObject);
+        QJsonDocument doc(content);
+        QVERIFY(!doc.isNull());
+        QByteArray hash = QCryptographicHash::hash(doc.toBinaryData(), QCryptographicHash::Md5).toHex();
+        schemaObject.insert("_Version", QString::fromLatin1(hash.constData(), hash.size()));
+    }
+
+    QJsonObject schema;
+    schema.insert("streetNumber", schema.value("number").toObject());
+    schemaObject.insert("schema", schema);
+    {
+        QJsonObject content(schemaObject);
+        content.remove("_Uuid");
+        content.remove("_Version");
+        QJsonDocument doc(content);
+        QVERIFY(!doc.isNull());
+        QByteArray hash = QCryptographicHash::hash(doc.toBinaryData(), QCryptographicHash::Md5).toHex();
+        schemaObject.insert("_Version", QString::fromLatin1(hash.constData(), hash.size()));
+    }
+}
+
+QTEST_MAIN(TestQtJson)
+#include "tst_qtjson.moc"
index a2efe91..da5247c 100644 (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)
\ No newline at end of file
+include(../trusted-benchmarks.pri)
diff --git a/tests/benchmarks/corelib/json/json.pro b/tests/benchmarks/corelib/json/json.pro
new file mode 100644 (file)
index 0000000..14222b3
--- /dev/null
@@ -0,0 +1,6 @@
+TARGET = tst_bench_qtbinaryjson
+QT = core testlib
+CONFIG -= app_bundle
+CONFIG += testcase
+
+SOURCES += tst_bench_qtbinaryjson.cpp
diff --git a/tests/benchmarks/corelib/json/numbers.json b/tests/benchmarks/corelib/json/numbers.json
new file mode 100644 (file)
index 0000000..469156a
--- /dev/null
@@ -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
+     ]
+]
diff --git a/tests/benchmarks/corelib/json/tst_bench_qtbinaryjson.cpp b/tests/benchmarks/corelib/json/tst_bench_qtbinaryjson.cpp
new file mode 100644 (file)
index 0000000..08340ff
--- /dev/null
@@ -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"
+