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:
parent
13c90a0a75
commit
a6b3a1e459
@ -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
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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" ]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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\" ]";
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user