summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization/qcborvalue_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/serialization/qcborvalue_p.h')
-rw-r--r--src/corelib/serialization/qcborvalue_p.h398
1 files changed, 398 insertions, 0 deletions
diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h
new file mode 100644
index 0000000000..3a28707056
--- /dev/null
+++ b/src/corelib/serialization/qcborvalue_p.h
@@ -0,0 +1,398 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 QCBORVALUE_P_H
+#define QCBORVALUE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API.
+// This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qcborvalue.h"
+
+#include <private/qglobal_p.h>
+#include <private/qutfcodec_p.h>
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtCbor {
+struct Undefined {};
+struct Element
+{
+ enum ValueFlag : quint32 {
+ IsContainer = 0x0001,
+ HasByteData = 0x0002,
+ StringIsUtf16 = 0x0004,
+ StringIsAscii = 0x0008
+ };
+ Q_DECLARE_FLAGS(ValueFlags, ValueFlag)
+
+ union {
+ qint64 value;
+ QCborContainerPrivate *container;
+ };
+ QCborValue::Type type;
+ ValueFlags flags = {};
+
+ Element(qint64 v = 0, QCborValue::Type t = QCborValue::Undefined, ValueFlags f = {})
+ : value(v), type(t), flags(f)
+ {}
+
+ Element(QCborContainerPrivate *d, QCborValue::Type t, ValueFlags f = {})
+ : container(d), type(t), flags(f | IsContainer)
+ {}
+
+ double fpvalue() const
+ {
+ double d;
+ memcpy(&d, &value, sizeof(d));
+ return d;
+ }
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(Element::ValueFlags)
+Q_STATIC_ASSERT(sizeof(Element) == 16);
+
+struct ByteData
+{
+ QByteArray::size_type len;
+
+ const char *byte() const { return reinterpret_cast<const char *>(this + 1); }
+ char *byte() { return reinterpret_cast<char *>(this + 1); }
+ const QChar *utf16() const { return reinterpret_cast<const QChar *>(this + 1); }
+ QChar *utf16() { return reinterpret_cast<QChar *>(this + 1); }
+
+ QByteArray toByteArray() const { return QByteArray(byte(), len); }
+ QString toString() const { return QString(utf16(), len / 2); }
+ QString toUtf8String() const { return QString::fromUtf8(byte(), len); }
+
+ QByteArray asByteArrayView() const { return QByteArray::fromRawData(byte(), len); }
+ QLatin1String asLatin1() const { return QLatin1String(byte(), len); }
+ QStringView asStringView() const{ return QStringView(utf16(), len / 2); }
+ QString asQStringRaw() const { return QString::fromRawData(utf16(), len / 2); }
+};
+Q_STATIC_ASSERT(std::is_pod<ByteData>::value);
+} // namespace QtCbor
+
+Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE);
+
+class QCborContainerPrivate : public QSharedData
+{
+ friend class QExplicitlySharedDataPointer<QCborContainerPrivate>;
+ ~QCborContainerPrivate();
+
+public:
+ enum ContainerDisposition { CopyContainer, MoveContainer };
+
+ QByteArray::size_type usedData = 0;
+ QByteArray data;
+ QVector<QtCbor::Element> elements;
+
+ void deref() { if (!ref.deref()) delete this; }
+ void compact(qsizetype reserved);
+ static QCborContainerPrivate *clone(QCborContainerPrivate *d, qsizetype reserved = -1);
+ static QCborContainerPrivate *detach(QCborContainerPrivate *d, qsizetype reserved);
+
+ qptrdiff addByteData(const char *block, qsizetype len)
+ {
+ // This function does not do overflow checking, since the len parameter
+ // is expected to be trusted. There's another version of this function
+ // in decodeStringFromCbor(), which checks.
+
+ qptrdiff offset = data.size();
+
+ // align offset
+ offset += Q_ALIGNOF(QtCbor::ByteData) - 1;
+ offset &= ~(Q_ALIGNOF(QtCbor::ByteData) - 1);
+
+ qptrdiff increment = qptrdiff(sizeof(QtCbor::ByteData)) + len;
+
+ usedData += increment;
+ data.resize(offset + increment);
+
+ char *ptr = data.begin() + offset;
+ auto b = new (ptr) QtCbor::ByteData;
+ b->len = len;
+ if (block)
+ memcpy(b->byte(), block, len);
+
+ return offset;
+ }
+
+ const QtCbor::ByteData *byteData(QtCbor::Element e) const
+ {
+ if ((e.flags & QtCbor::Element::HasByteData) == 0)
+ return nullptr;
+
+ size_t offset = size_t(e.value);
+ Q_ASSERT((offset % Q_ALIGNOF(QtCbor::ByteData)) == 0);
+ Q_ASSERT(offset + sizeof(QtCbor::ByteData) <= size_t(data.size()));
+
+ auto b = reinterpret_cast<const QtCbor::ByteData *>(data.constData() + offset);
+ Q_ASSERT(offset + sizeof(*b) + size_t(b->len) <= size_t(data.size()));
+ return b;
+ }
+ const QtCbor::ByteData *byteData(qsizetype idx) const
+ {
+ return byteData(elements.at(idx));
+ }
+
+ QCborContainerPrivate *containerAt(qsizetype idx, QCborValue::Type type) const
+ {
+ const QtCbor::Element &e = elements.at(idx);
+ if (e.type != type || (e.flags & QtCbor::Element::IsContainer) == 0)
+ return nullptr;
+ return e.container;
+ }
+
+ void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp);
+ void replaceAt_internal(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
+ {
+ if (value.container)
+ return replaceAt_complex(e, value, disp);
+
+ e.value = value.value_helper();
+ e.type = value.type();
+ if (value.isContainer())
+ e.container = nullptr;
+ }
+ void replaceAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
+ {
+ QtCbor::Element &e = elements[idx];
+ if (e.flags & QtCbor::Element::IsContainer) {
+ e.container->deref();
+ e.container = nullptr;
+ e.flags = {};
+ } else if (auto b = byteData(e)) {
+ usedData -= b->len + sizeof(QtCbor::ByteData);
+ }
+ replaceAt_internal(e, value, disp);
+ }
+ void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
+ {
+ replaceAt_internal(*elements.insert(elements.begin() + idx, {}), value, disp);
+ }
+
+ void append(QtCbor::Undefined)
+ {
+ elements.append(QtCbor::Element());
+ }
+ void append(qint64 value)
+ {
+ elements.append(QtCbor::Element(value , QCborValue::Integer));
+ }
+ void append(QCborTag tag)
+ {
+ elements.append(QtCbor::Element(qint64(tag), QCborValue::Tag));
+ }
+ void appendByteData(const char *data, qsizetype len, QCborValue::Type type,
+ QtCbor::Element::ValueFlags extraFlags = {})
+ {
+ elements.append(QtCbor::Element(addByteData(data, len), type,
+ QtCbor::Element::HasByteData | extraFlags));
+ }
+ void append(QLatin1String s)
+ {
+ if (!QtPrivate::isAscii(s))
+ return append(QString(s));
+
+ // US-ASCII is a subset of UTF-8, so we can keep in 8-bit
+ appendByteData(s.latin1(), s.size(), QCborValue::String,
+ QtCbor::Element::StringIsAscii);
+ }
+ void appendAsciiString(const QString &s);
+ void append(const QString &s)
+ {
+ if (QtPrivate::isAscii(s))
+ appendAsciiString(s);
+ else
+ appendByteData(reinterpret_cast<const char *>(s.constData()), s.size() * 2,
+ QCborValue::String, QtCbor::Element::StringIsUtf16);
+ }
+ void append(const QCborValue &v)
+ {
+ insertAt(elements.size(), v);
+ }
+
+ QByteArray byteArrayAt(qsizetype idx) const
+ {
+ const auto &e = elements.at(idx);
+ const auto data = byteData(e);
+ if (!data)
+ return QByteArray();
+ return data->toByteArray();
+ }
+ QString stringAt(qsizetype idx) const
+ {
+ const auto &e = elements.at(idx);
+ const auto data = byteData(e);
+ if (!data)
+ return QString();
+ if (e.flags & QtCbor::Element::StringIsUtf16)
+ return data->toString();
+ if (e.flags & QtCbor::Element::StringIsAscii)
+ return data->asLatin1();
+ return data->toUtf8String();
+ }
+
+ static void resetValue(QCborValue &v)
+ {
+ v.container = nullptr;
+ }
+
+ static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d = nullptr,
+ ContainerDisposition disp = CopyContainer)
+ {
+ QCborValue result(type);
+ result.n = n;
+ result.container = d;
+ if (d && disp == CopyContainer)
+ d->ref.ref();
+ return result;
+ }
+
+ QCborValue valueAt(qsizetype idx) const
+ {
+ const auto &e = elements.at(idx);
+
+ if (e.flags & QtCbor::Element::IsContainer) {
+ if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
+ // invalid tags can be created due to incomplete parsing
+ return makeValue(QCborValue::Invalid, 0, nullptr);
+ }
+ return makeValue(e.type, -1, e.container);
+ } else if (e.flags & QtCbor::Element::HasByteData) {
+ return makeValue(e.type, idx, const_cast<QCborContainerPrivate *>(this));
+ }
+ return makeValue(e.type, e.value);
+ }
+ QCborValue extractAt_complex(QtCbor::Element e);
+ QCborValue extractAt(qsizetype idx)
+ {
+ QtCbor::Element e;
+ qSwap(e, elements[idx]);
+
+ if (e.flags & QtCbor::Element::IsContainer) {
+ if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
+ // invalid tags can be created due to incomplete parsing
+ e.container->deref();
+ return makeValue(QCborValue::Invalid, 0, nullptr);
+ }
+ return makeValue(e.type, -1, e.container, MoveContainer);
+ } else if (e.flags & QtCbor::Element::HasByteData) {
+ return extractAt_complex(e);
+ }
+ return makeValue(e.type, e.value);
+ }
+
+ static QtCbor::Element elementFromValue(const QCborValue &value)
+ {
+ if (value.n >= 0 && value.container)
+ return value.container->elements.at(value.n);
+
+ QtCbor::Element e;
+ e.value = value.n;
+ e.type = value.t;
+ if (value.container) {
+ e.container = value.container;
+ e.flags = QtCbor::Element::IsContainer;
+ }
+ return e;
+ }
+
+ bool stringEqualsElement(qsizetype idx, QLatin1String s) const
+ {
+ const auto &e = elements.at(idx);
+ if (e.type != QCborValue::String)
+ return false;
+
+ const QtCbor::ByteData *b = byteData(idx);
+ if (!b)
+ return s.isEmpty();
+
+ if (e.flags & QtCbor::Element::StringIsUtf16)
+ return QtPrivate::compareStrings(b->asStringView(), s) == 0;
+ return QUtf8::compareUtf8(b->byte(), b->len, s) == 0;
+ }
+ bool stringEqualsElement(qsizetype idx, const QString &s) const
+ {
+ const auto &e = elements.at(idx);
+ if (e.type != QCborValue::String)
+ return false;
+
+ const QtCbor::ByteData *b = byteData(idx);
+ if (!b)
+ return s.isEmpty();
+
+ if (e.flags & QtCbor::Element::StringIsUtf16)
+ return QtPrivate::compareStrings(b->asStringView(), s) == 0;
+ return QUtf8::compareUtf8(b->byte(), b->len, s.data(), s.size()) == 0;
+ }
+
+ static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
+ const QCborContainerPrivate *c2, QtCbor::Element e2);
+ int compareElement(qsizetype idx, const QCborValue &value) const
+ {
+ auto &e1 = elements.at(idx);
+ auto e2 = elementFromValue(value);
+ return compareElement_helper(this, e1, value.container, e2);
+ }
+
+ void removeAt(qsizetype idx)
+ {
+ replaceAt(idx, {});
+ elements.remove(idx);
+ }
+
+ void decodeValueFromCbor(QCborStreamReader &reader);
+ void decodeFromCbor(QCborStreamReader &reader);
+ void decodeStringFromCbor(QCborStreamReader &reader);
+};
+
+QT_END_NAMESPACE
+
+#endif // QCBORVALUE_P_H