Remove deprecated binary json feature

Deprecated in 5.15 in favor of CBOR.

Fixes: QTBUG-81239
Change-Id: I711d4bd7dd1247f58e77ac9fa53304cbe5028918
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Edward Welbourne 2020-07-20 14:27:19 +02:00 committed by Sona Kurazyan
parent 13c90a0a75
commit a6b3a1e459
56 changed files with 23 additions and 2366 deletions

View File

@ -999,14 +999,6 @@ qt_extend_target(Core CONDITION QT_FEATURE_cborstreamwriter
serialization/qcborstreamwriter.cpp serialization/qcborstreamwriter.h
)
qt_extend_target(Core CONDITION QT_FEATURE_binaryjson
SOURCES
serialization/qbinaryjson.cpp serialization/qbinaryjson_p.h
serialization/qbinaryjsonarray.cpp serialization/qbinaryjsonarray_p.h
serialization/qbinaryjsonobject.cpp serialization/qbinaryjsonobject_p.h
serialization/qbinaryjsonvalue.cpp serialization/qbinaryjsonvalue_p.h
)
qt_extend_target(Core CONDITION QT_FEATURE_qeventtransition
SOURCES
statemachine/qeventtransition.cpp statemachine/qeventtransition.h statemachine/qeventtransition_p.h

View File

@ -1104,14 +1104,6 @@ qt_extend_target(Core CONDITION QT_FEATURE_cborstreamwriter
serialization/qcborstreamwriter.cpp serialization/qcborstreamwriter.h
)
qt_extend_target(Core CONDITION QT_FEATURE_binaryjson
SOURCES
serialization/qbinaryjson.cpp serialization/qbinaryjson_p.h
serialization/qbinaryjsonarray.cpp serialization/qbinaryjsonarray_p.h
serialization/qbinaryjsonobject.cpp serialization/qbinaryjsonobject_p.h
serialization/qbinaryjsonvalue.cpp serialization/qbinaryjsonvalue_p.h
)
qt_extend_target(Core CONDITION QT_FEATURE_qeventtransition
SOURCES
statemachine/qeventtransition.cpp statemachine/qeventtransition.h statemachine/qeventtransition_p.h

View File

@ -958,11 +958,6 @@ qt_feature("cborstreamwriter" PUBLIC
LABEL "CBOR stream writing"
PURPOSE "Provides support for writing the CBOR binary format."
)
qt_feature("binaryjson" PUBLIC
SECTION "Utilities"
LABEL "Binary JSON (deprecated)"
PURPOSE "Provides support for the deprecated binary JSON format."
)
qt_configure_add_summary_section(NAME "Qt Core")
qt_configure_add_summary_entry(ARGS "doubleconversion")
qt_configure_add_summary_entry(ARGS "system-doubleconversion")

View File

@ -1042,12 +1042,6 @@ Note that this is required for plugin loading. Qt GUI needs QPA plugins for basi
"purpose": "Provides support for writing the CBOR binary format.",
"section": "Utilities",
"output": [ "publicFeature" ]
},
"binaryjson": {
"label": "Binary JSON (deprecated)",
"purpose": "Provides support for the deprecated binary JSON format.",
"section": "Utilities",
"output": [ "publicFeature" ]
}
},

View File

@ -78,7 +78,6 @@
#else
# define QT_FEATURE_alloca_malloc_h -1
#endif
#define QT_FEATURE_binaryjson -1
#define QT_FEATURE_cborstreamreader -1
#define QT_FEATURE_cborstreamwriter 1
#define QT_CRYPTOGRAPHICHASH_ONLY_SHA1

View File

@ -1,415 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbinaryjson_p.h"
#include <qjsonobject.h>
#include <qjsonarray.h>
QT_BEGIN_NAMESPACE
namespace QBinaryJsonPrivate {
static Q_CONSTEXPR Base emptyArray = {
{ qle_uint(sizeof(Base)) },
{ 0 },
{ qle_uint(0) }
};
static Q_CONSTEXPR Base emptyObject = {
{ qle_uint(sizeof(Base)) },
{ qToLittleEndian(1U) },
{ qle_uint(0) }
};
void MutableData::compact()
{
static_assert(sizeof(Value) == sizeof(offset));
Base *base = header->root();
int reserve = 0;
if (base->is_object) {
auto *o = static_cast<Object *>(base);
for (uint i = 0; i < o->length; ++i)
reserve += o->entryAt(i)->usedStorage(o);
} else {
auto *a = static_cast<Array *>(base);
for (uint i = 0; i < a->length; ++i)
reserve += a->at(i)->usedStorage(a);
}
uint size = sizeof(Base) + reserve + base->length * sizeof(offset);
uint alloc = sizeof(Header) + size;
auto *h = reinterpret_cast<Header *>(malloc(alloc));
Q_CHECK_PTR(h);
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);
uint offset = sizeof(Base);
if (b->is_object) {
const auto *o = static_cast<const Object *>(base);
auto *no = static_cast<Object *>(b);
for (uint i = 0; i < o->length; ++i) {
no->table()[i] = offset;
const Entry *e = o->entryAt(i);
Entry *ne = no->entryAt(i);
uint s = e->size();
memcpy(ne, e, s);
offset += s;
uint dataSize = e->value.usedStorage(o);
if (dataSize) {
memcpy(reinterpret_cast<char *>(no) + offset, e->value.data(o), dataSize);
ne->value.value = offset;
offset += dataSize;
}
}
} else {
const auto *a = static_cast<const Array *>(base);
auto *na = static_cast<Array *>(b);
for (uint i = 0; i < a->length; ++i) {
const Value *v = a->at(i);
Value *nv = na->at(i);
*nv = *v;
uint dataSize = v->usedStorage(a);
if (dataSize) {
memcpy(reinterpret_cast<char *>(na) + offset, v->data(a), dataSize);
nv->value = offset;
offset += dataSize;
}
}
}
Q_ASSERT(offset == uint(b->tableOffset));
free(header);
header = h;
this->alloc = alloc;
compactionCounter = 0;
}
bool ConstData::isValid() const
{
if (header->tag != QJsonDocument::BinaryFormatTag || header->version != 1U)
return false;
const Base *root = header->root();
const uint maxSize = alloc - sizeof(Header);
return root->is_object
? static_cast<const Object *>(root)->isValid(maxSize)
: static_cast<const Array *>(root)->isValid(maxSize);
}
QJsonDocument ConstData::toJsonDocument() const
{
const Base *root = header->root();
return root->is_object
? QJsonDocument(static_cast<const Object *>(root)->toJsonObject())
: QJsonDocument(static_cast<const Array *>(root)->toJsonArray());
}
uint Base::reserveSpace(uint dataSize, uint posInTable, uint numItems, bool replace)
{
Q_ASSERT(posInTable <= length);
if (size + dataSize >= Value::MaxSize) {
qWarning("QJson: Document too large to store in data structure %d %d %d",
uint(size), dataSize, Value::MaxSize);
return 0;
}
offset off = tableOffset;
// move table to new position
if (replace) {
memmove(reinterpret_cast<char *>(table()) + dataSize, table(), length * sizeof(offset));
} else {
memmove(reinterpret_cast<char *>(table() + posInTable + numItems) + dataSize,
table() + posInTable, (length - posInTable) * sizeof(offset));
memmove(reinterpret_cast<char *>(table()) + dataSize, table(), posInTable * sizeof(offset));
}
tableOffset += dataSize;
for (uint i = 0; i < numItems; ++i)
table()[posInTable + i] = off;
size += dataSize;
if (!replace) {
length += numItems;
size += numItems * sizeof(offset);
}
return off;
}
uint Object::indexOf(QStringView key, bool *exists) const
{
uint min = 0;
uint n = length;
while (n > 0) {
uint half = n >> 1;
uint middle = min + half;
if (*entryAt(middle) >= key) {
n = half;
} else {
min = middle + 1;
n -= half + 1;
}
}
if (min < length && *entryAt(min) == key) {
*exists = true;
return min;
}
*exists = false;
return min;
}
QJsonObject Object::toJsonObject() const
{
QJsonObject object;
for (uint i = 0; i < length; ++i) {
const Entry *e = entryAt(i);
object.insert(e->key(), e->value.toJsonValue(this));
}
return object;
}
bool Object::isValid(uint maxSize) const
{
if (size > maxSize || tableOffset + length * sizeof(offset) > size)
return false;
QString lastKey;
for (uint i = 0; i < length; ++i) {
if (table()[i] + sizeof(Entry) >= tableOffset)
return false;
const Entry *e = entryAt(i);
if (!e->isValid(tableOffset - table()[i]))
return false;
const QString key = e->key();
if (key < lastKey)
return false;
if (!e->value.isValid(this))
return false;
lastKey = key;
}
return true;
}
QJsonArray Array::toJsonArray() const
{
QJsonArray array;
const offset *values = table();
for (uint i = 0; i < length; ++i)
array.append(reinterpret_cast<const Value *>(values + i)->toJsonValue(this));
return array;
}
bool Array::isValid(uint maxSize) const
{
if (size > maxSize || tableOffset + length * sizeof(offset) > size)
return false;
const offset *values = table();
for (uint i = 0; i < length; ++i) {
if (!reinterpret_cast<const Value *>(values + i)->isValid(this))
return false;
}
return true;
}
uint Value::usedStorage(const Base *b) const
{
uint s = 0;
switch (type) {
case QJsonValue::Double:
if (!latinOrIntValue)
s = sizeof(double);
break;
case QJsonValue::String: {
const char *d = data(b);
s = latinOrIntValue
? (sizeof(ushort)
+ qFromLittleEndian(*reinterpret_cast<const ushort *>(d)))
: (sizeof(int)
+ sizeof(ushort) * qFromLittleEndian(*reinterpret_cast<const 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);
}
QJsonValue Value::toJsonValue(const Base *b) const
{
switch (type) {
case QJsonValue::Null:
return QJsonValue(QJsonValue::Null);
case QJsonValue::Bool:
return QJsonValue(toBoolean());
case QJsonValue::Double:
return QJsonValue(toDouble(b));
case QJsonValue::String:
return QJsonValue(toString(b));
case QJsonValue::Array:
return static_cast<const Array *>(base(b))->toJsonArray();
case QJsonValue::Object:
return static_cast<const Object *>(base(b))->toJsonObject();
case QJsonValue::Undefined:
return QJsonValue(QJsonValue::Undefined);
}
Q_UNREACHABLE();
return QJsonValue(QJsonValue::Undefined);
}
inline bool isValidValueOffset(uint offset, uint tableOffset)
{
return offset >= sizeof(Base)
&& offset + sizeof(uint) <= tableOffset;
}
bool Value::isValid(const Base *b) const
{
switch (type) {
case QJsonValue::Null:
case QJsonValue::Bool:
return true;
case QJsonValue::Double:
return latinOrIntValue || isValidValueOffset(value, b->tableOffset);
case QJsonValue::String:
if (!isValidValueOffset(value, b->tableOffset))
return false;
if (latinOrIntValue)
return asLatin1String(b).isValid(b->tableOffset - value);
return asString(b).isValid(b->tableOffset - value);
case QJsonValue::Array:
return isValidValueOffset(value, b->tableOffset)
&& static_cast<const Array *>(base(b))->isValid(b->tableOffset - value);
case QJsonValue::Object:
return isValidValueOffset(value, b->tableOffset)
&& static_cast<const Object *>(base(b))->isValid(b->tableOffset - value);
default:
return false;
}
}
uint Value::requiredStorage(const QBinaryJsonValue &v, bool *compressed)
{
*compressed = false;
switch (v.type()) {
case QJsonValue::Double:
if (QBinaryJsonPrivate::compressedNumber(v.toDouble()) != INT_MAX) {
*compressed = true;
return 0;
}
return sizeof(double);
case QJsonValue::String: {
QString s = v.toString();
*compressed = QBinaryJsonPrivate::useCompressed(s);
return QBinaryJsonPrivate::qStringSize(s, *compressed);
}
case QJsonValue::Array:
case QJsonValue::Object:
return v.base ? uint(v.base->size) : sizeof(QBinaryJsonPrivate::Base);
case QJsonValue::Undefined:
case QJsonValue::Null:
case QJsonValue::Bool:
break;
}
return 0;
}
uint Value::valueToStore(const QBinaryJsonValue &v, uint offset)
{
switch (v.type()) {
case QJsonValue::Undefined:
case QJsonValue::Null:
break;
case QJsonValue::Bool:
return v.toBool();
case QJsonValue::Double: {
int c = QBinaryJsonPrivate::compressedNumber(v.toDouble());
if (c != INT_MAX)
return c;
}
Q_FALLTHROUGH();
case QJsonValue::String:
case QJsonValue::Array:
case QJsonValue::Object:
return offset;
}
return 0;
}
void Value::copyData(const QBinaryJsonValue &v, char *dest, bool compressed)
{
switch (v.type()) {
case QJsonValue::Double:
if (!compressed)
qToLittleEndian(v.toDouble(), dest);
break;
case QJsonValue::String: {
const QString str = v.toString();
QBinaryJsonPrivate::copyString(dest, str, compressed);
break;
}
case QJsonValue::Array:
case QJsonValue::Object: {
const QBinaryJsonPrivate::Base *b = v.base;
if (!b)
b = (v.type() == QJsonValue::Array ? &emptyArray : &emptyObject);
memcpy(dest, b, b->size);
break;
}
default:
break;
}
}
} // namespace QBinaryJsonPrivate
QT_END_NAMESPACE

View File

@ -1,615 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBINARYJSON_P_H
#define QBINARYJSON_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 <private/qbinaryjsonvalue_p.h>
#include <private/qendian_p.h>
#include <qjsondocument.h>
#include <limits>
QT_REQUIRE_CONFIG(binaryjson);
QT_BEGIN_NAMESPACE
// in qstring.cpp
void qt_to_latin1_unchecked(uchar *dst, const char16_t *uc, qsizetype len);
/*
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 QBinaryJsonPrivate {
class Array;
class Object;
class Value;
class Entry;
template<typename T>
using q_littleendian = QLEInteger<T>;
using qle_short = q_littleendian<short>;
using qle_ushort = q_littleendian<unsigned short>;
using qle_int = q_littleendian<int>;
using qle_uint = q_littleendian<unsigned int>;
template<int pos, int width>
using qle_bitfield = QLEIntegerBitfield<uint, pos, width>;
template<int pos, int width>
using qle_signedbitfield = QLEIntegerBitfield<int, pos, width>;
using offset = qle_uint;
// round the size up to the next 4 byte boundary
inline uint alignedSize(uint size) { return (size + 3) & ~3; }
const int MaxLatin1Length = 0x7fff;
static inline bool useCompressed(QStringView s)
{
if (s.length() > MaxLatin1Length)
return false;
return QtPrivate::isLatin1(s);
}
static inline bool useCompressed(QLatin1String s)
{
return s.size() <= MaxLatin1Length;
}
static inline uint qStringSize(const QString &string, bool compress)
{
uint l = 2 + string.size();
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 std::numeric_limits<int>::max();
quint64 non_int = val & (fraction_mask >> exp);
if (non_int)
return std::numeric_limits<int>::max();
bool neg = (val >> 63) != 0;
val &= fraction_mask;
val |= ((quint64)1 << 52);
int res = (int)(val >> (52 - exp));
return neg ? -res : res;
}
class Latin1String;
class String
{
public:
explicit String(const char *data) : d(reinterpret_cast<const Data *>(data)) {}
struct Data {
qle_uint length;
qle_ushort utf16[1];
};
const Data *d;
uint byteSize() const { return sizeof(uint) + sizeof(ushort) * d->length; }
bool isValid(uint maxSize) const
{
// Check byteSize() <= maxSize, avoiding integer overflow
return maxSize >= sizeof(uint)
&& uint(d->length) <= (maxSize - sizeof(uint)) / sizeof(ushort);
}
static void copy(char *dest, QStringView str)
{
Data *data = reinterpret_cast<Data *>(dest);
data->length = str.length();
qToLittleEndian<quint16>(str.utf16(), str.length(), data->utf16);
fillTrailingZeros(data);
}
static void fillTrailingZeros(Data *data)
{
if (data->length & 1)
data->utf16[data->length] = 0;
}
bool operator ==(QStringView str) const
{
int slen = str.length();
int l = d->length;
if (slen != l)
return false;
const auto *s = reinterpret_cast<const ushort *>(str.utf16());
const qle_ushort *a = d->utf16;
const ushort *b = s;
while (l-- && *a == *b)
a++,b++;
return (l == -1);
}
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));
}
QString toString() const
{
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
return QString(reinterpret_cast<const QChar *>(d->utf16), d->length);
#else
const uint l = d->length;
QString str(l, Qt::Uninitialized);
QChar *ch = str.data();
for (uint i = 0; i < l; ++i)
ch[i] = QChar(d->utf16[i]);
return str;
#endif
}
};
class Latin1String
{
public:
explicit Latin1String(const char *data) : d(reinterpret_cast<const Data *>(data)) {}
struct Data {
qle_ushort length;
char latin1[1];
};
const Data *d;
uint byteSize() const { return sizeof(ushort) + sizeof(char) * (d->length); }
bool isValid(uint maxSize) const { return byteSize() <= maxSize; }
static void copy(char *dest, QStringView src)
{
Data *data = reinterpret_cast<Data *>(dest);
data->length = src.length(); // ### narrows from int to ushort
auto *l = reinterpret_cast<uchar *>(data->latin1);
qt_to_latin1_unchecked(l, src.utf16(), data->length);
for (uint len = data->length; quintptr(l + len) & 0x3; ++len)
l[len] = 0;
}
QLatin1String toQLatin1String() const noexcept { return QLatin1String(d->latin1, d->length); }
QString toString() const { return QString::fromLatin1(d->latin1, d->length); }
};
static inline void copyString(char *dest, QStringView str, bool compress)
{
if (compress)
Latin1String::copy(dest, str);
else
String::copy(dest, str);
}
/*
Base is the base class for both Object and Array. Both classes 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
bool isObject() const { return !!is_object; }
bool isArray() const { return !isObject(); }
offset *table()
{
return reinterpret_cast<offset *>(reinterpret_cast<char *>(this) + tableOffset);
}
const offset *table() const
{
return reinterpret_cast<const offset *>(reinterpret_cast<const char *>(this) + tableOffset);
}
uint reserveSpace(uint dataSize, uint posInTable, uint numItems, bool replace);
};
class Object : public Base
{
public:
const Entry *entryAt(uint i) const
{
return reinterpret_cast<const Entry *>(reinterpret_cast<const char *>(this) + table()[i]);
}
Entry *entryAt(uint i)
{
return reinterpret_cast<Entry *>(reinterpret_cast<char *>(this) + table()[i]);
}
uint indexOf(QStringView key, bool *exists) const;
QJsonObject toJsonObject() const;
bool isValid(uint maxSize) const;
};
class Array : public Base
{
public:
const Value *at(uint i) const { return reinterpret_cast<const Value *>(table() + i); }
Value *at(uint i) { return reinterpret_cast<Value *>(table() + i); }
QJsonArray toJsonArray() const;
bool isValid(uint maxSize) const;
};
class Value
{
public:
enum {
MaxSize = (1 << 27) - 1
};
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 const char *data(const Base *b) const
{
return reinterpret_cast<const char *>(b) + value;
}
uint usedStorage(const Base *b) const;
bool toBoolean() const
{
Q_ASSERT(type == QJsonValue::Bool);
return value != 0;
}
double toDouble(const Base *b) const
{
Q_ASSERT(type == QJsonValue::Double);
if (latinOrIntValue)
return int_value;
auto i = qFromLittleEndian<quint64>(reinterpret_cast<const uchar *>(b) + value);
double d;
memcpy(&d, &i, sizeof(double));
return d;
}
QString toString(const Base *b) const
{
return latinOrIntValue
? asLatin1String(b).toString()
: asString(b).toString();
}
String asString(const Base *b) const
{
Q_ASSERT(type == QJsonValue::String && !latinOrIntValue);
return String(data(b));
}
Latin1String asLatin1String(const Base *b) const
{
Q_ASSERT(type == QJsonValue::String && latinOrIntValue);
return Latin1String(data(b));
}
const Base *base(const Base *b) const
{
Q_ASSERT(type == QJsonValue::Array || type == QJsonValue::Object);
return reinterpret_cast<const Base *>(data(b));
}
QJsonValue toJsonValue(const Base *b) const;
bool isValid(const Base *b) const;
static uint requiredStorage(const QBinaryJsonValue &v, bool *compressed);
static uint valueToStore(const QBinaryJsonValue &v, uint offset);
static void copyData(const QBinaryJsonValue &v, char *dest, bool compressed);
};
class Entry {
public:
Value value;
// key
// value data follows key
uint size() const
{
uint s = sizeof(Entry);
if (value.latinKey)
s += shallowLatin1Key().byteSize();
else
s += shallowKey().byteSize();
return alignedSize(s);
}
uint usedStorage(Base *b) const
{
return size() + value.usedStorage(b);
}
String shallowKey() const
{
Q_ASSERT(!value.latinKey);
return String(reinterpret_cast<const char *>(this) + sizeof(Entry));
}
Latin1String shallowLatin1Key() const
{
Q_ASSERT(value.latinKey);
return Latin1String(reinterpret_cast<const char *>(this) + sizeof(Entry));
}
QString key() const
{
return value.latinKey
? shallowLatin1Key().toString()
: shallowKey().toString();
}
bool isValid(uint maxSize) const
{
if (maxSize < sizeof(Entry))
return false;
maxSize -= sizeof(Entry);
return value.latinKey
? shallowLatin1Key().isValid(maxSize)
: shallowKey().isValid(maxSize);
}
bool operator ==(QStringView key) const
{
return value.latinKey
? (shallowLatin1Key().toQLatin1String() == key)
: (shallowKey() == key);
}
bool operator >=(QStringView key) const
{
return value.latinKey
? (shallowLatin1Key().toQLatin1String() >= key)
: (shallowKey().toString() >= key);
}
};
class Header {
public:
qle_uint tag; // 'qbjs'
qle_uint version; // 1
Base *root() { return reinterpret_cast<Base *>(this + 1); }
const Base *root() const { return reinterpret_cast<const Base *>(this + 1); }
};
class ConstData
{
Q_DISABLE_COPY_MOVE(ConstData)
public:
const uint alloc;
union {
const char *rawData;
const Header *header;
};
ConstData(const char *raw, uint a) : alloc(a), rawData(raw) {}
bool isValid() const;
QJsonDocument toJsonDocument() const;
};
class MutableData
{
Q_DISABLE_COPY_MOVE(MutableData)
public:
QAtomicInt ref;
uint alloc;
union {
char *rawData;
Header *header;
};
uint compactionCounter : 31;
MutableData(char *raw, uint a)
: alloc(a), rawData(raw), compactionCounter(0)
{
}
MutableData(uint reserved, QJsonValue::Type valueType)
: rawData(nullptr), compactionCounter(0)
{
Q_ASSERT(valueType == QJsonValue::Array || valueType == QJsonValue::Object);
alloc = sizeof(Header) + sizeof(Base) + reserved + sizeof(offset);
header = reinterpret_cast<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;
}
~MutableData()
{
free(rawData);
}
MutableData *clone(const Base *b, uint reserve = 0)
{
uint size = sizeof(Header) + b->size;
if (b == header->root() && ref.loadRelaxed() == 1 && alloc >= size + reserve)
return this;
if (reserve) {
if (reserve < 128)
reserve = 128;
size = qMax(size + reserve, qMin(size *2, uint(Value::MaxSize)));
if (size > Value::MaxSize) {
qWarning("QJson: Document too large to store in data structure");
return nullptr;
}
}
char *raw = reinterpret_cast<char *>(malloc(size));
Q_CHECK_PTR(raw);
memcpy(raw + sizeof(Header), b, b->size);
auto *h = reinterpret_cast<Header *>(raw);
h->tag = QJsonDocument::BinaryFormatTag;
h->version = 1;
auto *d = new MutableData(raw, size);
d->compactionCounter = (b == header->root()) ? compactionCounter : 0;
return d;
}
char *takeRawData(uint *size)
{
*size = alloc;
char *result = rawData;
rawData = nullptr;
alloc = 0;
return result;
}
void compact();
};
} // namespace QBinaryJsonPrivate
Q_DECLARE_TYPEINFO(QBinaryJsonPrivate::Value, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
#endif // QBINARYJSON_P_H

View File

@ -1,137 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbinaryjsonarray_p.h"
#include "qbinaryjson_p.h"
#include <qjsonarray.h>
QT_BEGIN_NAMESPACE
QBinaryJsonArray::~QBinaryJsonArray()
{
if (d && !d->ref.deref())
delete d;
}
QBinaryJsonArray QBinaryJsonArray::fromJsonArray(const QJsonArray &array)
{
QBinaryJsonArray binary;
for (const QJsonValue &value : array)
binary.append(QBinaryJsonValue::fromJsonValue(value));
if (binary.d) // We want to compact it as it is a root item now
binary.d->compactionCounter++;
binary.compact();
return binary;
}
void QBinaryJsonArray::append(const QBinaryJsonValue &value)
{
const uint i = a ? a->length : 0;
bool compressed;
uint valueSize = QBinaryJsonPrivate::Value::requiredStorage(value, &compressed);
if (!detach(valueSize + sizeof(QBinaryJsonPrivate::Value)))
return;
if (!a->length)
a->tableOffset = sizeof(QBinaryJsonPrivate::Array);
uint valueOffset = a->reserveSpace(valueSize, i, 1, false);
if (!valueOffset)
return;
QBinaryJsonPrivate::Value *v = a->at(i);
v->type = (value.t == QJsonValue::Undefined ? QJsonValue::Null : value.t);
v->latinOrIntValue = compressed;
v->latinKey = false;
v->value = QBinaryJsonPrivate::Value::valueToStore(value, valueOffset);
if (valueSize) {
QBinaryJsonPrivate::Value::copyData(value, reinterpret_cast<char *>(a) + valueOffset,
compressed);
}
}
char *QBinaryJsonArray::takeRawData(uint *size)
{
if (d)
return d->takeRawData(size);
*size = 0;
return nullptr;
}
bool QBinaryJsonArray::detach(uint reserve)
{
if (!d) {
if (reserve >= QBinaryJsonPrivate::Value::MaxSize) {
qWarning("QBinaryJson: Document too large to store in data structure");
return false;
}
d = new QBinaryJsonPrivate::MutableData(reserve, QJsonValue::Array);
a = static_cast<QBinaryJsonPrivate::Array *>(d->header->root());
d->ref.ref();
return true;
}
if (reserve == 0 && d->ref.loadRelaxed() == 1)
return true;
QBinaryJsonPrivate::MutableData *x = d->clone(a, reserve);
if (!x)
return false;
x->ref.ref();
if (!d->ref.deref())
delete d;
d = x;
a = static_cast<QBinaryJsonPrivate::Array *>(d->header->root());
return true;
}
void QBinaryJsonArray::compact()
{
if (!d || !d->compactionCounter)
return;
detach();
d->compact();
a = static_cast<QBinaryJsonPrivate::Array *>(d->header->root());
}
QT_END_NAMESPACE

View File

@ -1,98 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBINARYJSONARRAY_P_H
#define QBINARYJSONARRAY_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 "qbinaryjsonvalue_p.h"
QT_REQUIRE_CONFIG(binaryjson);
QT_BEGIN_NAMESPACE
class QBinaryJsonArray
{
Q_DISABLE_COPY(QBinaryJsonArray)
public:
QBinaryJsonArray() = default;
~QBinaryJsonArray();
QBinaryJsonArray(QBinaryJsonArray &&other) noexcept
: d(other.d),
a(other.a)
{
other.d = nullptr;
other.a = nullptr;
}
QBinaryJsonArray &operator =(QBinaryJsonArray &&other) noexcept
{
qSwap(d, other.d);
qSwap(a, other.a);
return *this;
}
static QBinaryJsonArray fromJsonArray(const QJsonArray &array);
char *takeRawData(uint *size);
private:
friend class QBinaryJsonValue;
void append(const QBinaryJsonValue &value);
void compact();
bool detach(uint reserve = 0);
QBinaryJsonPrivate::MutableData *d = nullptr;
QBinaryJsonPrivate::Array *a = nullptr;
};
QT_END_NAMESPACE
#endif // QBINARYJSONARRAY_P_H

View File

@ -1,149 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbinaryjsonobject_p.h"
#include "qbinaryjson_p.h"
#include <qjsonobject.h>
QT_BEGIN_NAMESPACE
QBinaryJsonObject::~QBinaryJsonObject()
{
if (d && !d->ref.deref())
delete d;
}
QBinaryJsonObject QBinaryJsonObject::fromJsonObject(const QJsonObject &object)
{
QBinaryJsonObject binary;
for (auto it = object.begin(), end = object.end(); it != end; ++it)
binary.insert(it.key(), QBinaryJsonValue::fromJsonValue(it.value()));
if (binary.d) // We want to compact it as it is a root item now
binary.d->compactionCounter++;
binary.compact();
return binary;
}
void QBinaryJsonObject::insert(const QString &key, const QBinaryJsonValue &value)
{
bool latinOrIntValue;
uint valueSize = QBinaryJsonPrivate::Value::requiredStorage(value, &latinOrIntValue);
bool latinKey = QBinaryJsonPrivate::useCompressed(key);
uint valueOffset = sizeof(QBinaryJsonPrivate::Entry)
+ QBinaryJsonPrivate::qStringSize(key, latinKey);
uint requiredSize = valueOffset + valueSize;
if (!detach(requiredSize + sizeof(QBinaryJsonPrivate::offset))) // offset for the new index entry
return;
if (!o->length)
o->tableOffset = sizeof(QBinaryJsonPrivate::Object);
bool keyExists = false;
uint pos = o->indexOf(key, &keyExists);
if (keyExists)
++d->compactionCounter;
uint off = o->reserveSpace(requiredSize, pos, 1, keyExists);
if (!off)
return;
QBinaryJsonPrivate::Entry *e = o->entryAt(pos);
e->value.type = value.t;
e->value.latinKey = latinKey;
e->value.latinOrIntValue = latinOrIntValue;
e->value.value = QBinaryJsonPrivate::Value::valueToStore(
value, reinterpret_cast<char *>(e) - reinterpret_cast<char *>(o) + valueOffset);
QBinaryJsonPrivate::copyString(reinterpret_cast<char *>(e + 1), key, latinKey);
if (valueSize) {
QBinaryJsonPrivate::Value::copyData(value, reinterpret_cast<char *>(e) + valueOffset,
latinOrIntValue);
}
if (d->compactionCounter > 32U && d->compactionCounter >= unsigned(o->length) / 2U)
compact();
}
char *QBinaryJsonObject::takeRawData(uint *size) const
{
if (d)
return d->takeRawData(size);
*size = 0;
return nullptr;
}
bool QBinaryJsonObject::detach(uint reserve)
{
if (!d) {
if (reserve >= QBinaryJsonPrivate::Value::MaxSize) {
qWarning("QBinaryJson: Document too large to store in data structure");
return false;
}
d = new QBinaryJsonPrivate::MutableData(reserve, QJsonValue::Object);
o = static_cast<QBinaryJsonPrivate::Object *>(d->header->root());
d->ref.ref();
return true;
}
if (reserve == 0 && d->ref.loadRelaxed() == 1)
return true;
QBinaryJsonPrivate::MutableData *x = d->clone(o, reserve);
if (!x)
return false;
x->ref.ref();
if (!d->ref.deref())
delete d;
d = x;
o = static_cast<QBinaryJsonPrivate::Object *>(d->header->root());
return true;
}
void QBinaryJsonObject::compact()
{
if (!d || !d->compactionCounter)
return;
detach();
d->compact();
o = static_cast<QBinaryJsonPrivate::Object *>(d->header->root());
}
QT_END_NAMESPACE

View File

@ -1,97 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBINARYJSONOBJECT_H
#define QBINARYJSONOBJECT_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 "qbinaryjsonvalue_p.h"
QT_REQUIRE_CONFIG(binaryjson);
QT_BEGIN_NAMESPACE
class QBinaryJsonObject
{
Q_DISABLE_COPY(QBinaryJsonObject)
public:
QBinaryJsonObject() = default;
~QBinaryJsonObject();
QBinaryJsonObject(QBinaryJsonObject &&other) noexcept
: d(other.d), o(other.o)
{
other.d = nullptr;
other.o = nullptr;
}
QBinaryJsonObject &operator =(QBinaryJsonObject &&other) noexcept
{
qSwap(d, other.d);
qSwap(o, other.o);
return *this;
}
static QBinaryJsonObject fromJsonObject(const QJsonObject &object);
char *takeRawData(uint *size) const;
private:
friend class QBinaryJsonValue;
void insert(const QString &key, const QBinaryJsonValue &value);
bool detach(uint reserve = 0);
void compact();
QBinaryJsonPrivate::MutableData *d = nullptr;
QBinaryJsonPrivate::Object *o = nullptr;
};
QT_END_NAMESPACE
#endif // QBINARYJSONOBJECT_P_H

View File

@ -1,147 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbinaryjsonobject_p.h"
#include "qbinaryjsonvalue_p.h"
#include "qbinaryjsonarray_p.h"
#include "qbinaryjson_p.h"
#include <qjsonarray.h>
#include <qjsonobject.h>
QT_BEGIN_NAMESPACE
QBinaryJsonValue::QBinaryJsonValue(QBinaryJsonPrivate::MutableData *data,
QBinaryJsonPrivate::Base *parent,
const QBinaryJsonPrivate::Value &v)
: t(QJsonValue::Type(uint(v.type)))
{
switch (t) {
case QJsonValue::Undefined:
case QJsonValue::Null:
dbl = 0;
break;
case QJsonValue::Bool:
b = v.toBoolean();
break;
case QJsonValue::Double:
dbl = v.toDouble(parent);
break;
case QJsonValue::String:
stringData = v.toString(parent);
break;
case QJsonValue::Array:
case QJsonValue::Object:
d = data;
base = v.base(parent);
break;
}
if (d)
d->ref.ref();
}
QBinaryJsonValue::QBinaryJsonValue(QString string)
: d(nullptr), t(QJsonValue::String)
{
stringData = std::move(string);
}
QBinaryJsonValue::QBinaryJsonValue(const QBinaryJsonArray &a)
: base(a.a), d(a.d), t(QJsonValue::Array)
{
if (d)
d->ref.ref();
}
QBinaryJsonValue::QBinaryJsonValue(const QBinaryJsonObject &o)
: base(o.o), d(o.d), t(QJsonValue::Object)
{
if (d)
d->ref.ref();
}
QBinaryJsonValue::~QBinaryJsonValue()
{
if (d && !d->ref.deref())
delete d;
}
QBinaryJsonValue QBinaryJsonValue::fromJsonValue(const QJsonValue &json)
{
switch (json.type()) {
case QJsonValue::Bool:
return QBinaryJsonValue(json.toBool());
case QJsonValue::Double:
return QBinaryJsonValue(json.toDouble());
case QJsonValue::String:
return QBinaryJsonValue(json.toString());
case QJsonValue::Array:
return QBinaryJsonArray::fromJsonArray(json.toArray());
case QJsonValue::Object:
return QBinaryJsonObject::fromJsonObject(json.toObject());
case QJsonValue::Null:
return QBinaryJsonValue(QJsonValue::Null);
case QJsonValue::Undefined:
return QBinaryJsonValue(QJsonValue::Undefined);
}
Q_UNREACHABLE();
return QBinaryJsonValue(QJsonValue::Null);
}
QString QBinaryJsonValue::toString() const
{
if (t != QJsonValue::String)
return QString();
return stringData;
}
void QBinaryJsonValue::detach()
{
if (!d)
return;
QBinaryJsonPrivate::MutableData *x = d->clone(base);
x->ref.ref();
if (!d->ref.deref())
delete d;
d = x;
base = static_cast<QBinaryJsonPrivate::Object *>(d->header->root());
}
QT_END_NAMESPACE

View File

@ -1,136 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBINARYJSONVALUE_P_H
#define QBINARYJSONVALUE_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 <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qjsonvalue.h>
QT_REQUIRE_CONFIG(binaryjson);
QT_BEGIN_NAMESPACE
class QBinaryJsonArray;
class QBinaryJsonObject;
namespace QBinaryJsonPrivate {
class ConstData;
class MutableData;
class Base;
class Value;
class Object;
class Array;
}
class Q_CORE_EXPORT QBinaryJsonValue
{
Q_DISABLE_COPY(QBinaryJsonValue)
public:
explicit QBinaryJsonValue(QJsonValue::Type type) : ui(0), t(type) {}
explicit QBinaryJsonValue(bool b) : b(b), t(QJsonValue::Bool) {}
explicit QBinaryJsonValue(double n) : dbl(n), t(QJsonValue::Double) {}
explicit QBinaryJsonValue(QString s);
QBinaryJsonValue(const QBinaryJsonArray &a);
QBinaryJsonValue(const QBinaryJsonObject &o);
~QBinaryJsonValue();
QBinaryJsonValue(QBinaryJsonValue &&other) noexcept
: ui(other.ui),
stringData(std::move(other.stringData)),
d(other.d),
t(other.t)
{
other.ui = 0;
other.d = nullptr;
other.t = QJsonValue::Null;
}
QBinaryJsonValue &operator =(QBinaryJsonValue &&other) noexcept
{
qSwap(stringData, other.stringData);
qSwap(ui, other.ui);
qSwap(d, other.d);
qSwap(t, other.t);
return *this;
}
static QBinaryJsonValue fromJsonValue(const QJsonValue &json);
QJsonValue::Type type() const { return t; }
bool toBool() const { return (t == QJsonValue::Bool) && b; }
double toDouble() const { return (t == QJsonValue::Double) ? dbl : 0; }
QString toString() const;
private:
friend class QBinaryJsonPrivate::Value;
friend class QBinaryJsonArray;
friend class QBinaryJsonObject;
QBinaryJsonValue(QBinaryJsonPrivate::MutableData *d, QBinaryJsonPrivate::Base *parent,
const QBinaryJsonPrivate::Value &v);
void detach();
union {
quint64 ui;
bool b;
double dbl;
const QBinaryJsonPrivate::Base *base;
};
QString stringData;
QBinaryJsonPrivate::MutableData *d = nullptr; // needed for Objects and Arrays
QJsonValue::Type t = QJsonValue::Null;
};
QT_END_NAMESPACE
#endif // QBINARYJSONVALUE_P_H

View File

@ -52,12 +52,6 @@
#include "qjson_p.h"
#include "qdatastream.h"
#if QT_CONFIG(binaryjson)
#include "qbinaryjson_p.h"
#include "qbinaryjsonobject_p.h"
#include "qbinaryjsonarray_p.h"
#endif
#include <private/qmemory_p.h>
QT_BEGIN_NAMESPACE
@ -71,9 +65,9 @@ QT_BEGIN_NAMESPACE
\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.
QJsonDocument is a class that wraps a complete JSON document and can read
this document from, and write it to, a UTF-8 encoded text-based
representation.
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
@ -85,9 +79,6 @@ QT_BEGIN_NAMESPACE
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().
\sa {JSON Support in Qt}, {JSON Save Game Example}
*/
@ -225,180 +216,6 @@ QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
Swaps the document \a other with this. This operation is very fast and never fails.
*/
/*! \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.
*/
#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
/*!
\deprecated
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. The data is
copied into a different data structure, and the original data can be
deleted or modified afterwards.
\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.
\note Deprecated in Qt 5.15. The binary JSON encoding is only retained for backwards
compatibility. It is undocumented and restrictive in the maximum size of JSON
documents that can be encoded. Qt JSON types can be converted to Qt CBOR types,
which can in turn be serialized into the CBOR binary format and vice versa. The
CBOR format is a well-defined and less restrictive binary representation for a
superset of JSON.
\note Before Qt 5.15, the caller had to guarantee that \a data would not be
deleted or modified as long as any QJsonDocument, QJsonObject or QJsonArray
still referenced the data. From Qt 5.15 on, this is not necessary anymore.
\sa rawData(), fromBinaryData(), isNull(), DataValidation, QCborValue
*/
QJsonDocument QJsonDocument::fromRawData(const char *data, int size, DataValidation validation)
{
if (quintptr(data) & 3) {
qWarning("QJsonDocument::fromRawData: data has to have 4 byte alignment");
return QJsonDocument();
}
if (size < 0 || uint(size) < sizeof(QBinaryJsonPrivate::Header) + sizeof(QBinaryJsonPrivate::Base))
return QJsonDocument();
std::unique_ptr<QBinaryJsonPrivate::ConstData> binaryData
= qt_make_unique<QBinaryJsonPrivate::ConstData>(data, size);
return (validation == BypassValidation || binaryData->isValid())
? binaryData->toJsonDocument()
: QJsonDocument();
}
/*!
\deprecated
Returns the raw binary representation of the data
\a size will contain the size of the returned data.
This method is useful to e.g. stream the JSON document
in its binary form to a file.
\note Deprecated in Qt 5.15. The binary JSON encoding is only retained for backwards
compatibility. It is undocumented and restrictive in the maximum size of JSON
documents that can be encoded. Qt JSON types can be converted to Qt CBOR types,
which can in turn be serialized into the CBOR binary format and vice versa. The
CBOR format is a well-defined and less restrictive binary representation for a
superset of JSON.
\sa QCborValue
*/
const char *QJsonDocument::rawData(int *size) const
{
if (!d) {
*size = 0;
return nullptr;
}
if (!d->rawData) {
if (isObject()) {
QBinaryJsonObject o = QBinaryJsonObject::fromJsonObject(object());
d->rawData = o.takeRawData(&(d->rawDataSize));
} else {
QBinaryJsonArray a = QBinaryJsonArray::fromJsonArray(array());
d->rawData = a.takeRawData(&(d->rawDataSize));
}
}
// It would be quite miraculous if not, as we should have hit the 128MB limit then.
Q_ASSERT(d->rawDataSize <= uint(std::numeric_limits<int>::max()));
*size = d->rawDataSize;
return d->rawData;
}
/*!
\deprecated
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.
\note Deprecated in Qt 5.15. The binary JSON encoding is only retained for backwards
compatibility. It is undocumented and restrictive in the maximum size of JSON
documents that can be encoded. Qt JSON types can be converted to Qt CBOR types,
which can in turn be serialized into the CBOR binary format and vice versa. The
CBOR format is a well-defined and less restrictive binary representation for a
superset of JSON.
\sa toBinaryData(), fromRawData(), isNull(), DataValidation, QCborValue
*/
QJsonDocument QJsonDocument::fromBinaryData(const QByteArray &data, DataValidation validation)
{
if (uint(data.size()) < sizeof(QBinaryJsonPrivate::Header) + sizeof(QBinaryJsonPrivate::Base))
return QJsonDocument();
QBinaryJsonPrivate::Header h;
memcpy(&h, data.constData(), sizeof(QBinaryJsonPrivate::Header));
QBinaryJsonPrivate::Base root;
memcpy(&root, data.constData() + sizeof(QBinaryJsonPrivate::Header),
sizeof(QBinaryJsonPrivate::Base));
const uint size = sizeof(QBinaryJsonPrivate::Header) + root.size;
if (h.tag != QJsonDocument::BinaryFormatTag || h.version != 1U || size > uint(data.size()))
return QJsonDocument();
std::unique_ptr<QBinaryJsonPrivate::ConstData> d
= qt_make_unique<QBinaryJsonPrivate::ConstData>(data.constData(), size);
return (validation == BypassValidation || d->isValid())
? d->toJsonDocument()
: QJsonDocument();
}
/*!
\deprecated
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.
\note Deprecated in Qt 5.15. The binary JSON encoding is only retained for backwards
compatibility. It is undocumented and restrictive in the maximum size of JSON
documents that can be encoded. Qt JSON types can be converted to Qt CBOR types,
which can in turn be serialized into the CBOR binary format and vice versa. The
CBOR format is a well-defined and less restrictive binary representation for a
superset of JSON.
\sa fromBinaryData(), QCborValue
*/
QByteArray QJsonDocument::toBinaryData() const
{
int size = 0;
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
const char *raw = rawData(&size);
QT_WARNING_POP
return QByteArray(raw, size);
}
#endif // QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
/*!
Creates a QJsonDocument from the QVariant \a variant.

View File

@ -106,25 +106,6 @@ public:
void swap(QJsonDocument &other) noexcept;
enum DataValidation {
Validate,
BypassValidation
};
#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
QT_DEPRECATED_X("Use CBOR format instead")
static QJsonDocument fromRawData(const char *data, int size, DataValidation validation = Validate);
QT_DEPRECATED_X("Use CBOR format instead")
const char *rawData(int *size) const;
QT_DEPRECATED_X("Use CBOR format instead")
static QJsonDocument fromBinaryData(const QByteArray &data, DataValidation validation = Validate);
QT_DEPRECATED_X("Use CBOR format instead")
QByteArray toBinaryData() const;
#endif // QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
static QJsonDocument fromVariant(const QVariant &variant);
QVariant toVariant() const;

View File

@ -55,20 +55,6 @@ qtConfig(cborstreamwriter): {
serialization/qcborstreamwriter.h
}
qtConfig(binaryjson): {
HEADERS += \
serialization/qbinaryjson_p.h \
serialization/qbinaryjsonarray_p.h \
serialization/qbinaryjsonobject_p.h \
serialization/qbinaryjsonvalue_p.h
SOURCES += \
serialization/qbinaryjson.cpp \
serialization/qbinaryjsonarray.cpp \
serialization/qbinaryjsonobject.cpp \
serialization/qbinaryjsonvalue.cpp \
}
false: SOURCES += \
serialization/qcborarray.cpp \
serialization/qcbormap.cpp

View File

@ -446,17 +446,8 @@ QShader QShader::fromSerialized(const QByteArray &data)
ds >> descBin;
d->desc = QShaderDescription::fromCbor(descBin);
} else {
#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
QByteArray descBin;
ds >> descBin;
d->desc = QShaderDescription::fromBinaryJson(descBin);
QT_WARNING_POP
#else
qWarning("Cannot load QShaderDescription from binary JSON due to disabled binaryjson feature");
qWarning("Can no longer load QShaderDescription from binary JSON.");
d->desc = QShaderDescription();
#endif
}
int count;
ds >> count;

View File

@ -367,26 +367,6 @@ void QShaderDescription::serialize(QDataStream *stream) const
d->writeToStream(stream);
}
#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
/*!
\deprecated
Deserializes the given binary JSON \a data and returns a new
QShaderDescription.
\sa fromCbor()
*/
QShaderDescription QShaderDescription::fromBinaryJson(const QByteArray &data)
{
QShaderDescription desc;
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
QShaderDescriptionPrivate::get(&desc)->loadDoc(QJsonDocument::fromBinaryData(data));
QT_WARNING_POP
return desc;
}
#endif
/*!
Deserializes the given CBOR \a data and returns a new QShaderDescription.
*/

View File

@ -75,10 +75,6 @@ public:
void serialize(QDataStream *stream) const;
QByteArray toJson() const;
#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
QT_DEPRECATED_X("Use CBOR format instead")
static QShaderDescription fromBinaryJson(const QByteArray &data);
#endif
static QShaderDescription fromCbor(const QByteArray &data);
static QShaderDescription deserialize(QDataStream *stream, int version);

View File

@ -103,26 +103,16 @@ private Q_SLOTS:
void toJsonLargeNumericValues();
void fromJson();
void fromJsonErrors();
void fromBinary();
void toAndFromBinary_data();
void toAndFromBinary();
void invalidBinaryData();
void parseNumbers();
void parseStrings();
void parseDuplicateKeys();
void testParser();
void compactArray();
void compactObject();
void validation();
void assignToDocument();
void testDuplicateKeys();
void testCompaction();
void testDebugStream();
void testCompactionError();
void parseUnicodeEscapes();
@ -864,8 +854,6 @@ void tst_QtJson::testArrayNestedEmpty()
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 tst_QtJson::testObjectNestedEmpty()
@ -883,15 +871,6 @@ void tst_QtJson::testObjectNestedEmpty()
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 tst_QtJson::testArrayComfortOperators()
@ -2074,64 +2053,6 @@ void tst_QtJson::fromJsonErrors()
}
}
void tst_QtJson::fromBinary()
{
QFile file(testDataDir + "/test.json");
file.open(QFile::ReadOnly);
QByteArray testJson = file.readAll();
QJsonDocument doc = QJsonDocument::fromJson(testJson);
QJsonDocument outdoc = QJsonDocument::fromBinaryData(doc.toBinaryData());
QVERIFY(!outdoc.isNull());
QCOMPARE(doc, outdoc);
QFile bfile(testDataDir + "/test.bjson");
bfile.open(QFile::ReadOnly);
QByteArray binary = bfile.readAll();
QJsonDocument bdoc = QJsonDocument::fromBinaryData(binary);
QVERIFY(!bdoc.isNull());
QCOMPARE(doc.toVariant(), bdoc.toVariant());
QCOMPARE(doc, bdoc);
}
void tst_QtJson::toAndFromBinary_data()
{
QTest::addColumn<QString>("filename");
QTest::newRow("test.json") << (testDataDir + "/test.json");
QTest::newRow("test2.json") << (testDataDir + "/test2.json");
}
void tst_QtJson::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());
QCOMPARE(doc, outdoc);
}
void tst_QtJson::invalidBinaryData()
{
QDir dir(testDataDir + "/invalidBinaryData");
QFileInfoList files = dir.entryInfoList();
for (int i = 0; i < files.size(); ++i) {
if (!files.at(i).isFile())
continue;
QFile file(files.at(i).filePath());
file.open(QIODevice::ReadOnly);
QByteArray bytes = file.readAll();
bytes.squeeze();
QJsonDocument document = QJsonDocument::fromRawData(bytes.constData(), bytes.size());
QVERIFY(document.isNull());
}
}
void tst_QtJson::parseNumbers()
{
{
@ -2308,131 +2229,6 @@ void tst_QtJson::testParser()
QVERIFY(!doc.isEmpty());
}
void tst_QtJson::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 tst_QtJson::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 tst_QtJson::validation()
{
// this basically tests that we don't crash on corrupt data
QFile file(testDataDir + "/test.json");
QVERIFY(file.open(QFile::ReadOnly));
QByteArray testJson = file.readAll();
QVERIFY(!testJson.isEmpty());
QJsonDocument doc = QJsonDocument::fromJson(testJson);
QVERIFY(!doc.isNull());
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] = char(0xff);
QJsonDocument doc = QJsonDocument::fromBinaryData(corrupted);
if (doc.isNull())
continue;
QByteArray json = doc.toJson();
}
QFile file2(testDataDir + "/test3.json");
file2.open(QFile::ReadOnly);
testJson = file2.readAll();
QVERIFY(!testJson.isEmpty());
doc = QJsonDocument::fromJson(testJson);
QVERIFY(!doc.isNull());
binary = doc.toBinaryData();
for (int i = 0; i < binary.size(); ++i) {
QByteArray corrupted = binary;
corrupted[i] = char(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 tst_QtJson::assignToDocument()
{
{
@ -2482,13 +2278,6 @@ void tst_QtJson::testCompaction()
}
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);
QCOMPARE(doc.object(), obj);
}
void tst_QtJson::testDebugStream()
@ -2578,34 +2367,6 @@ void tst_QtJson::testDebugStream()
}
}
void tst_QtJson::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()));
}
}
void tst_QtJson::parseUnicodeEscapes()
{
const QByteArray json = "[ \"A\\u00e4\\u00C4\" ]";

View File

@ -1,12 +1,12 @@
# Generated from json.pro.
#####################################################################
## tst_bench_qtbinaryjson Binary:
## tst_bench_qtjson Binary:
#####################################################################
qt_add_benchmark(tst_bench_qtbinaryjson
qt_add_benchmark(tst_bench_qtjson
SOURCES
tst_bench_qtbinaryjson.cpp
tst_bench_qtjson.cpp
PUBLIC_LIBRARIES
Qt::Test
)

View File

@ -2,7 +2,7 @@ QT = core testlib
CONFIG += benchmark
CONFIG -= app_bundle
TARGET = tst_bench_qtbinaryjson
SOURCES += tst_bench_qtbinaryjson.cpp
TARGET = tst_bench_qtjson
SOURCES += tst_bench_qtjson.cpp
TESTDATA = numbers.json test.json

View File

@ -30,11 +30,11 @@
#include <qjsondocument.h>
#include <qjsonobject.h>
class BenchmarkQtBinaryJson: public QObject
class BenchmarkQtJson: public QObject
{
Q_OBJECT
public:
BenchmarkQtBinaryJson(QObject *parent = 0);
BenchmarkQtJson(QObject *parent = 0);
private Q_SLOTS:
void initTestCase();
@ -46,39 +46,36 @@ private Q_SLOTS:
void parseJson();
void parseJsonToVariant();
void toByteArray();
void fromByteArray();
void jsonObjectInsert();
void variantMapInsert();
};
BenchmarkQtBinaryJson::BenchmarkQtBinaryJson(QObject *parent) : QObject(parent)
BenchmarkQtJson::BenchmarkQtJson(QObject *parent) : QObject(parent)
{
}
void BenchmarkQtBinaryJson::initTestCase()
void BenchmarkQtJson::initTestCase()
{
}
void BenchmarkQtBinaryJson::cleanupTestCase()
void BenchmarkQtJson::cleanupTestCase()
{
}
void BenchmarkQtBinaryJson::init()
void BenchmarkQtJson::init()
{
}
void BenchmarkQtBinaryJson::cleanup()
void BenchmarkQtJson::cleanup()
{
}
void BenchmarkQtBinaryJson::parseNumbers()
void BenchmarkQtJson::parseNumbers()
{
QString testFile = QFINDTESTDATA("numbers.json");
QVERIFY2(!testFile.isEmpty(), "cannot find test file numbers.json!");
@ -92,7 +89,7 @@ void BenchmarkQtBinaryJson::parseNumbers()
}
}
void BenchmarkQtBinaryJson::parseJson()
void BenchmarkQtJson::parseJson()
{
QString testFile = QFINDTESTDATA("test.json");
QVERIFY2(!testFile.isEmpty(), "cannot find test file test.json!");
@ -106,7 +103,7 @@ void BenchmarkQtBinaryJson::parseJson()
}
}
void BenchmarkQtBinaryJson::parseJsonToVariant()
void BenchmarkQtJson::parseJsonToVariant()
{
QString testFile = QFINDTESTDATA("test.json");
QVERIFY2(!testFile.isEmpty(), "cannot find test file test.json!");
@ -120,37 +117,7 @@ void BenchmarkQtBinaryJson::parseJsonToVariant()
}
}
void BenchmarkQtBinaryJson::toByteArray()
{
// Example: send information over a datastream to another process
// Measure performance of creating and processing data into bytearray
QBENCHMARK {
QVariantMap message;
message.insert("command", 1);
message.insert("key", "some information");
message.insert("env", "some environment variables");
QByteArray msg = QJsonDocument(QJsonObject::fromVariantMap(message)).toBinaryData();
}
}
void BenchmarkQtBinaryJson::fromByteArray()
{
// Example: receive information over a datastream from another process
// Measure performance of converting content back to QVariantMap
// We need to recreate the bytearray but here we only want to measure the latter
QVariantMap message;
message.insert("command", 1);
message.insert("key", "some information");
message.insert("env", "some environment variables");
QByteArray msg = QJsonDocument(QJsonObject::fromVariantMap(message)).toBinaryData();
QBENCHMARK {
QVariantMap message;
message = QJsonDocument::fromBinaryData(msg, QJsonDocument::Validate).object().toVariantMap();
}
}
void BenchmarkQtBinaryJson::jsonObjectInsert()
void BenchmarkQtJson::jsonObjectInsert()
{
QJsonObject object;
QString test(QStringLiteral("testString"));
@ -162,7 +129,7 @@ void BenchmarkQtBinaryJson::jsonObjectInsert()
}
}
void BenchmarkQtBinaryJson::variantMapInsert()
void BenchmarkQtJson::variantMapInsert()
{
QVariantMap object;
QString test(QStringLiteral("testString"));
@ -174,6 +141,6 @@ void BenchmarkQtBinaryJson::variantMapInsert()
}
}
QTEST_MAIN(BenchmarkQtBinaryJson)
#include "tst_bench_qtbinaryjson.moc"
QTEST_MAIN(BenchmarkQtJson)
#include "tst_bench_qtjson.moc"