diff options
Diffstat (limited to 'src/corelib/serialization/qcborstreamwriter.cpp')
-rw-r--r-- | src/corelib/serialization/qcborstreamwriter.cpp | 868 |
1 files changed, 868 insertions, 0 deletions
diff --git a/src/corelib/serialization/qcborstreamwriter.cpp b/src/corelib/serialization/qcborstreamwriter.cpp new file mode 100644 index 0000000000..9d78785416 --- /dev/null +++ b/src/corelib/serialization/qcborstreamwriter.cpp @@ -0,0 +1,868 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qcborstreamwriter.h" + +#define CBOR_NO_PARSER_API +#include <private/qcborcommon_p.h> + +#include <private/qnumeric_p.h> +#include <qbuffer.h> +#include <qdebug.h> +#include <qstack.h> + +QT_BEGIN_NAMESPACE + +static CborError qt_cbor_encoder_write_callback(void *token, const void *data, size_t len, CborEncoderAppendType); +#define CBOR_ENCODER_WRITER_CONTROL 1 +#define CBOR_ENCODER_WRITE_FUNCTION qt_cbor_encoder_write_callback +#define CBOR_ENCODER_NO_CHECK_USER + +QT_WARNING_PUSH +QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?) + +#include <cborencoder.c> + +QT_WARNING_POP + +// silence compilers that complain about this being a static function declared +// but never defined +static CborError Q_DECL_UNUSED cbor_encoder_close_container_checked(CborEncoder*, const CborEncoder*) +{ + Q_UNREACHABLE(); + return CborErrorInternalError; +} + +static CborError Q_DECL_UNUSED cbor_encode_float_as_half_float(CborEncoder *, float) +{ + Q_UNREACHABLE(); + return CborErrorInternalError; +} + +Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE); + +/*! + \class QCborStreamWriter + \inmodule QtCore + \ingroup cbor + \reentrant + \since 5.12 + + \brief The QCborStreamWriter class is a simple CBOR encoder operating on a + one-way stream. + + This class can be used to quickly encode a stream of CBOR content directly + to either a QByteArray or QIODevice. CBOR is the Concise Binary Object + Representation, a very compact form of binary data encoding that is + compatible with JSON. It was created by the IETF Constrained RESTful + Environments (CoRE) WG, which has used it in many new RFCs. It is meant to + be used alongside the \l{https://tools.ietf.org/html/rfc7252}{CoAP + protocol}. + + QCborStreamWriter provides a StAX-like API, similar to that of + \l{QXmlStreamWriter}. It is rather low-level and requires a bit of knowledge + of CBOR encoding. For a simpler API, see \l{QCborValue} and especially the + encoding function QCborValue::toCbor(). + + The typical use of QCborStreamWriter is to create the object on the target + QByteArray or QIODevice, then call one of the append() overloads with the + desired type to be encoded. To create arrays and maps, QCborStreamWriter + provides startArray() and startMap() overloads, which must be terminated by + the corresponding endArray() and endMap() functions. + + The following example encodes the equivalent of this JSON content: + + \div{class="pre"} + { + "label": "journald", + "autoDetect": false, + "condition": "libs.journald", + "output": [ "privateFeature" ] + } + \enddiv + + \snippet code/src_corelib_serialization_qcborstream.cpp 1 + + \section1 CBOR support + + QCborStreamWriter supports all CBOR features required to create canonical + and strict streams. It implements almost all of the features specified in + \l {https://tools.ietf.org/html/rfc7049}{RFC 7049}. + + The following table lists the CBOR features that QCborStreamWriter supports. + + \table + \header \li Feature \li Support + \row \li Unsigned numbers \li Yes (full range) + \row \li Negative numbers \li Yes (full range) + \row \li Byte strings \li Yes + \row \li Text strings \li Yes + \row \li Chunked strings \li No + \row \li Tags \li Yes (arbitrary) + \row \li Booleans \li Yes + \row \li Null \li Yes + \row \li Undefined \li Yes + \row \li Arbitrary simple values \li Yes + \row \li Half-precision float (16-bit) \li Yes + \row \li Single-precision float (32-bit) \li Yes + \row \li Double-precision float (64-bit) \li Yes + \row \li Infinities and NaN floating point \li Yes + \row \li Determinate-length arrays and maps \li Yes + \row \li Indeterminate-length arrays and maps \li Yes + \row \li Map key types other than strings and integers \li Yes (arbitrary) + \endtable + + \section2 Canonical CBOR encoding + + Canonical CBOR encoding is defined by + \l{https://tools.ietf.org/html/rfc7049#section-3.9}{Section 3.9 of RFC + 7049}. Canonical encoding is not a requirement for Qt's CBOR decoding + functionality, but it may be required for some protocols. In particular, + protocols that require the ability to reproduce the same stream identically + may require this. + + In order to be considered "canonical", a CBOR stream must meet the + following requirements: + + \list + \li Integers must be as small as possible. QCborStreamWriter always + does this (no user action is required and it is not possible + to write overlong integers). + \li Array, map and string lengths must be as short as possible. As + above, QCborStreamWriter automatically does this. + \li Arrays, maps and strings must use explicit length. QCborStreamWriter + always does this for strings; for arrays and maps, be sure to call + startArray() and startMap() overloads with explicit length. + \li Keys in every map must be sorted in ascending order. QCborStreamWriter + offers no help in this item: the developer must ensure that before + calling append() for the map pairs. + \li Floating point values should be as small as possible. QCborStreamWriter + will not convert floating point values; it is up to the developer + to perform this check prior to calling append() (see those functions' + examples). + \endlist + + \section2 Strict CBOR mode + + Strict mode is defined by + \l{https://tools.ietf.org/html/rfc7049#section-3.10}{Section 3.10 of RFC + 7049}. As for Canonical encoding above, QCborStreamWriter makes it possible + to create strict CBOR streams, but does not require them or validate that + the output is so. + + \list + \li Keys in a map must be unique. QCborStreamWriter performs no validation + of map keys. + \li Tags may be required to be paired only with the correct types, + according to their specification. QCborStreamWriter performs no + validation of tag usage. + \li Text Strings must be properly-encoded UTF-8. QCborStreamWriter always + writes proper UTF-8 for strings added with append(), but performs no + validation for strings added with appendTextString(). + \endlist + + \section2 Invalid CBOR stream + + It is also possible to misuse QCborStreamWriter and produce invalid CBOR + streams that will fail to be decoded by a receiver. The following actions + will produce invalid streams: + + \list + \li Append a tag and not append the corresponding tagged value + (QCborStreamWriter produces no diagnostic). + \li Append too many or too few items to an array or map with explicit + length (endMap() and endArray() will return false and + QCborStreamWriter will log with qWarning()). + \endlist + + \sa QCborStreamReader, QCborValue, QXmlStreamWriter + */ + +class QCborStreamWriterPrivate +{ +public: + static Q_CONSTEXPR quint64 IndefiniteLength = (std::numeric_limits<quint64>::max)(); + + QIODevice *device; + CborEncoder encoder; + QStack<CborEncoder> containerStack; + bool deleteDevice = false; + + QCborStreamWriterPrivate(QIODevice *device) + : device(device) + { + cbor_encoder_init_writer(&encoder, qt_cbor_encoder_write_callback, this); + } + + ~QCborStreamWriterPrivate() + { + if (deleteDevice) + delete device; + } + + template <typename... Args> void executeAppend(CborError (*f)(CborEncoder *, Args...), Args... args) + { + f(&encoder, std::forward<Args>(args)...); + } + + void createContainer(CborError (*f)(CborEncoder *, CborEncoder *, size_t), quint64 len = IndefiniteLength) + { + Q_STATIC_ASSERT(size_t(IndefiniteLength) == CborIndefiniteLength); + if (sizeof(len) != sizeof(size_t) && len != IndefiniteLength) { + if (Q_UNLIKELY(len >= CborIndefiniteLength)) { + // TinyCBOR can't do this in 32-bit mode + qWarning("QCborStreamWriter: container of size %llu is too big for a 32-bit build; " + "will use indeterminate length instead", len); + len = CborIndefiniteLength; + } + } + + containerStack.push(encoder); + f(&containerStack.top(), &encoder, len); + } + + bool closeContainer() + { + if (containerStack.isEmpty()) { + qWarning("QCborStreamWriter: closing map or array that wasn't open"); + return false; + } + + CborEncoder container = containerStack.pop(); + CborError err = cbor_encoder_close_container(&container, &encoder); + encoder = container; + + if (Q_UNLIKELY(err)) { + if (err == CborErrorTooFewItems) + qWarning("QCborStreamWriter: not enough items added to array or map"); + else if (err == CborErrorTooManyItems) + qWarning("QCborStreamWriter: too many items added to array or map"); + return false; + } + + return true; + } +}; + +static CborError qt_cbor_encoder_write_callback(void *self, const void *data, size_t len, CborEncoderAppendType) +{ + auto that = static_cast<QCborStreamWriterPrivate *>(self); + if (!that->device) + return CborNoError; + qint64 written = that->device->write(static_cast<const char *>(data), len); + return (written == qsizetype(len) ? CborNoError : CborErrorIO); +} + +/*! + Creates a QCborStreamWriter object that will write the stream to \a device. + The device must be opened before the first append() call is made. This + constructor can be used with any class that derives from QIODevice, such as + QFile, QProcess or QTcpSocket. + + QCborStreamWriter has no buffering, so every append() call will result in + one or more calls to the device's \l {QIODevice::}{write()} method. + + The following example writes an empty map to a file: + + \snippet code/src_corelib_serialization_qcborstream.cpp 2 + + QCborStreamWriter does not take ownership of \a device. + + \sa device(), setDevice() + */ +QCborStreamWriter::QCborStreamWriter(QIODevice *device) + : d(new QCborStreamWriterPrivate(device)) +{ +} + +/*! + Creates a QCborStreamWriter object that will append the stream to \a data. + All streaming is done immediately to the byte array, without the need for + flushing any buffers. + + The following example writes a number to a byte array then returns + it. + + \snippet code/src_corelib_serialization_qcborstream.cpp 3 + + QCborStreamWriter does not take ownership of \a data. + */ +QCborStreamWriter::QCborStreamWriter(QByteArray *data) + : d(new QCborStreamWriterPrivate(new QBuffer(data))) +{ + d->deleteDevice = true; + d->device->open(QIODevice::WriteOnly | QIODevice::Unbuffered); +} + +/*! + Destroys this QCborStreamWriter object and frees any resources associated. + + QCborStreamWriter does not perform error checking to see if all required + items were written to the stream prior to the object being destroyed. It is + the programmer's responsibility to ensure that it was done. + */ +QCborStreamWriter::~QCborStreamWriter() +{ +} + +/*! + Replaces the device or byte array that this QCborStreamWriter object is + writing to with \a device. + + \sa device() + */ +void QCborStreamWriter::setDevice(QIODevice *device) +{ + if (d->deleteDevice) + delete d->device; + d->device = device; + d->deleteDevice = false; +} + +/*! + Returns the QIODevice that this QCborStreamWriter object is writing to. The + device must have previously been set with either the constructor or with + setDevice(). + + If this object was created by writing to a QByteArray, this function will + return an internal instance of QBuffer, which is owned by QCborStreamWriter. + + \sa setDevice() + */ +QIODevice *QCborStreamWriter::device() const +{ + return d->device; +} + +/*! + \overload + + Appends the 64-bit unsigned value \a u to the CBOR stream, creating a CBOR + Unsigned Integer value. In the following example, we write the values 0, + 2\sup{32} and \c UINT64_MAX: + + \snippet code/src_corelib_serialization_qcborstream.cpp 4 + + \sa QCborStreamReader::isUnsignedInteger(), QCborStreamReader::toUnsignedInteger() + */ +void QCborStreamWriter::append(quint64 u) +{ + d->executeAppend(cbor_encode_uint, uint64_t(u)); +} + +/*! + \overload + + Appends the 64-bit signed value \a i to the CBOR stream. This will create + either a CBOR Unsigned Integer or CBOR NegativeInteger value based on the + sign of the parameter. In the following example, we write the values 0, -1, + 2\sup{32} and \c INT64_MAX: + + \snippet code/src_corelib_serialization_qcborstream.cpp 5 + + \sa QCborStreamReader::isInteger(), QCborStreamReader::toInteger() + */ +void QCborStreamWriter::append(qint64 i) +{ + d->executeAppend(cbor_encode_int, int64_t(i)); +} + +/*! + \overload + + Appends the 64-bit negative value \a n to the CBOR stream. + QCborNegativeInteger is a 64-bit enum that holds the absolute value of the + negative number we want to write. If n is zero, the value written will be + equivalent to 2\sup{64} (that is, -18,446,744,073,709,551,616). + + In the following example, we write the values -1, -2\sup{32} and INT64_MIN: + \snippet code/src_corelib_serialization_qcborstream.cpp 6 + + Note how this function can be used to encode numbers that cannot fit a + standard computer's 64-bit signed integer like \l qint64. That is, if \a n + is larger than \c{std::numeric_limits<qint64>::max()} or is 0, this will + represent a negative number smaller than + \c{std::numeric_limits<qint64>::min()}. + + \sa QCborStreamReader::isNegativeInteger(), QCborStreamReader::toNegativeInteger() + */ +void QCborStreamWriter::append(QCborNegativeInteger n) +{ + d->executeAppend(cbor_encode_negative_int, uint64_t(n)); +} + +/*! + \fn void QCborStreamWriter::append(const QByteArray &ba) + \overload + + Appends the byte array \a ba to the stream, creating a CBOR Byte String + value. QCborStreamWriter will attempt to write the entire string in one + chunk. + + The following example will load and append the contents of a file to the + stream: + + \snippet code/src_corelib_serialization_qcborstream.cpp 7 + + As the example shows, unlike JSON, CBOR requires no escaping for binary + content. + + \sa appendByteString(), QCborStreamReader::isByteArray(), + QCborStreamReader::readByteArray() + */ + +/*! + \overload + + Appends the text string \a str to the stream, creating a CBOR Text String + value. QCborStreamWriter will attempt to write the entire string in one + chunk. + + The following example appends a simple string to the stream: + + \snippet code/src_corelib_serialization_qcborstream.cpp 8 + + \b{Performance note}: CBOR requires that all Text Strings be encoded in + UTF-8, so this function will iterate over the characters in the string to + determine whether the contents are US-ASCII or not. If the string is found + to contain characters outside of US-ASCII, it will allocate memory and + convert to UTF-8. If this check is unnecessary, use appendTextString() + instead. + + \sa QCborStreamReader::isString(), QCborStreamReader::readString() + */ +void QCborStreamWriter::append(QLatin1String str) +{ + // We've got Latin-1 but CBOR wants UTF-8, so check if the string is the + // common subset (US-ASCII). + if (QtPrivate::isAscii(str)) { + // it is plain US-ASCII + appendTextString(str.latin1(), str.size()); + } else { + // non-ASCII, so we need a pass-through UTF-16 + append(QString(str)); + } +} + +/*! + \overload + + Appends the text string \a str to the stream, creating a CBOR Text String + value. QCborStreamWriter will attempt to write the entire string in one + chunk. + + The following example writes an arbitrary QString to the stream: + + \snippet code/src_corelib_serialization_qcborstream.cpp 9 + + \sa QCborStreamReader::isString(), QCborStreamReader::readString() + */ +void QCborStreamWriter::append(QStringView str) +{ + QByteArray utf8 = str.toUtf8(); + appendTextString(utf8.constData(), utf8.size()); +} + +/*! + \overload + + Appends the CBOR tag \a tag to the stream, creating a CBOR Tag value. All + tags must be followed by another type which they provide meaning for. + + In the following example, we append a CBOR Tag 36 (Regular Expression) and a + QRegularExpression's pattern to the stream: + + \snippet code/src_corelib_serialization_qcborstream.cpp 10 + + \sa QCborStreamReader::isTag(), QCborStreamReader::toTag() + */ +void QCborStreamWriter::append(QCborTag tag) +{ + d->executeAppend(cbor_encode_tag, CborTag(tag)); +} + +/*! + \fn void QCborStreamWriter::append(QCborKnownTags tag) + \overload + + Appends the CBOR tag \a tag to the stream, creating a CBOR Tag value. All + tags must be followed by another type which they provide meaning for. + + In the following example, we append a CBOR Tag 1 (Unix \c time_t) and an + integer representing the current time to the stream, obtained using the \c + time() function: + + \snippet code/src_corelib_serialization_qcborstream.cpp 11 + + \sa QCborStreamReader::isTag(), QCborStreamReader::toTag() + */ + +/*! + \overload + + Appends the CBOR simple type \a st to the stream, creating a CBOR Simple + Type value. In the following example, we write the simple type for Null as + well as for type 32, which Qt has no support for. + + \snippet code/src_corelib_serialization_qcborstream.cpp 12 + + \note Using Simple Types for which there is no specification can lead to + validation errors by the remote receiver. In addition, simple type values 24 + through 31 (inclusive) are reserved and must not be used. + + \sa QCborStreamReader::isSimpleType(), QCborStreamReader::toSimpleType() + */ +void QCborStreamWriter::append(QCborSimpleType st) +{ + d->executeAppend(cbor_encode_simple_value, uint8_t(st)); +} + +#ifndef QT_BOOTSTRAPPED +/*! + \overload + + Appends the floating point number \a f to the stream, creating a CBOR 16-bit + Half-Precision Floating Point value. The following code can be used to convert + a C++ \tt float to \c qfloat16 if there's no loss of precision and append it, or + instead append the \tt float. + + \snippet code/src_corelib_serialization_qcborstream.cpp 13 + + \sa QCborStreamReader::isFloat16(), QCborStreamReader::toFloat16() + */ +void QCborStreamWriter::append(qfloat16 f) +{ + d->executeAppend(cbor_encode_half_float, static_cast<const void *>(&f)); +} +#endif // QT_BOOTSTRAPPED + +/*! + \overload + + Appends the floating point number \a f to the stream, creating a CBOR 32-bit + Single-Precision Floating Point value. The following code can be used to convert + a C++ \tt double to \tt float if there's no loss of precision and append it, or + instead append the \tt double. + + \snippet code/src_corelib_serialization_qcborstream.cpp 14 + + \sa QCborStreamReader::isFloat(), QCborStreamReader::toFloat() + */ +void QCborStreamWriter::append(float f) +{ + d->executeAppend(cbor_encode_float, f); +} + +/*! + \overload + + Appends the floating point number \a d to the stream, creating a CBOR 64-bit + Double-Precision Floating Point value. QCborStreamWriter always appends the + number as-is, performing no check for whether the number is the canonical + form for NaN, an infinite, whether it is denormal or if it could be written + with a shorter format. + + The following code performs all those checks, except for the denormal one, + which is expected to be taken into account by the system FPU or floating + point emulation directly. + + \snippet code/src_corelib_serialization_qcborstream.cpp 15 + + Determining if a double can be converted to an integral with no loss of + precision is left as an exercise to the reader. + + \sa QCborStreamReader::isDouble(), QCborStreamReader::toDouble() + */ +void QCborStreamWriter::append(double d) +{ + this->d->executeAppend(cbor_encode_double, d); +} + +/*! + Appends \a len bytes of data starting from \a data to the stream, creating a + CBOR Byte String value. QCborStreamWriter will attempt to write the entire + string in one chunk. + + Unlike the QByteArray overload of append(), this function is not limited by + QByteArray's size limits. However, note that neither + QCborStreamReader::readByteArray() nor QCborValue support reading CBOR + streams with byte arrays larger than 2 GB. + + \sa append(), appendTextString(), + QCborStreamReader::isByteArray(), QCborStreamReader::readByteArray() + */ +void QCborStreamWriter::appendByteString(const char *data, qsizetype len) +{ + d->executeAppend(cbor_encode_byte_string, reinterpret_cast<const uint8_t *>(data), size_t(len)); +} + +/*! + Appends \a len bytes of text starting from \a utf8 to the stream, creating a + CBOR Text String value. QCborStreamWriter will attempt to write the entire + string in one chunk. + + The string pointed to by \a utf8 is expected to be properly encoded UTF-8. + QCborStreamWriter performs no validation that this is the case. + + Unlike the QLatin1String overload of append(), this function is not limited + to 2 GB. However, note that neither QCborStreamReader::readString() nor + QCborValue support reading CBOR streams with text strings larger than 2 GB. + + \sa append(QLatin1String), append(QStringView), + QCborStreamReader::isString(), QCborStreamReader::readString() + */ +void QCborStreamWriter::appendTextString(const char *utf8, qsizetype len) +{ + d->executeAppend(cbor_encode_text_string, utf8, size_t(len)); +} + +/*! + \fn void QCborStreamWriter::append(const char *str, qsizetype size) + \overload + + Appends \a size bytes of text starting from \a str to the stream, creating a + CBOR Text String value. QCborStreamWriter will attempt to write the entire + string in one chunk. If \a size is -1, this function will write \c strlen(\a + str) bytes. + + The string pointed to by \a str is expected to be properly encoded UTF-8. + QCborStreamWriter performs no validation that this is the case. + + Unlike the QLatin1String overload of append(), this function is not limited + to 2 GB. However, note that neither QCborStreamReader nor QCborValue support + reading CBOR streams with text strings larger than 2 GB. + + \sa append(QLatin1String), append(QStringView), + QCborStreamReader::isString(), QCborStreamReader::readString() + */ + +/*! + \fn void QCborStreamWriter::append(bool b) + \overload + + Appends the boolean value \a b to the stream, creating either a CBOR False + value or a CBOR True value. This function is equivalent to (and implemented + as): + + \snippet code/src_corelib_serialization_qcborstream.cpp 16 + + \sa appendNull(), appendUndefined(), + QCborStreamReader::isBool(), QCborStreamReader::toBool() + */ + +/*! + \fn void QCborStreamWriter::append(std::nullptr_t) + \overload + + Appends a CBOR Null value to the stream. This function is equivalent to (and + implemented as): The parameter is ignored. + + \snippet code/src_corelib_serialization_qcborstream.cpp 17 + + \sa appendNull(), append(QCborSimpleType), QCborStreamReader::isNull() + */ + +/*! + \fn void QCborStreamWriter::appendNull() + + Appends a CBOR Null value to the stream. This function is equivalent to (and + implemented as): + + \snippet code/src_corelib_serialization_qcborstream.cpp 18 + + \sa append(std::nullptr_t), append(QCborSimpleType), QCborStreamReader::isNull() + */ + +/*! + \fn void QCborStreamWriter::appendUndefined() + + Appends a CBOR Undefined value to the stream. This function is equivalent to (and + implemented as): + + \snippet code/src_corelib_serialization_qcborstream.cpp 19 + + \sa append(QCborSimpleType), QCborStreamReader::isUndefined() + */ + +/*! + Starts a CBOR Array with indeterminate length in the CBOR stream. Each + startArray() call must be paired with one endArray() call and the current + CBOR element extends until the end of the array. + + The array created by this function has no explicit length. Instead, its + length is implied by the elements contained in it. Note, however, that use + of indeterminate-length arrays is not compliant with canonical CBOR encoding. + + The following example appends elements from the linked list of strings + passed as input: + + \snippet code/src_corelib_serialization_qcborstream.cpp 20 + + \sa startArray(quint64), endArray(), startMap(), QCborStreamReader::isArray(), + QCborStreamReader::isLengthKnown() + */ +void QCborStreamWriter::startArray() +{ + d->createContainer(cbor_encoder_create_array); +} + +/*! + \overload + + Starts a CBOR Array with explicit length of \a count items in the CBOR + stream. Each startArray call must be paired with one endArray() call and the + current CBOR element extends until the end of the array. + + The array created by this function has an explicit length and therefore + exactly \a count items must be added to the CBOR stream. Adding fewer or + more items will result in failure during endArray() and the CBOR stream will + be corrupt. However, explicit-length arrays are required by canonical CBOR + encoding. + + The following example appends all strings found in the \l QStringList passed as input: + + \snippet code/src_corelib_serialization_qcborstream.cpp 21 + + \b{Size limitations}: The parameter to this function is quint64, which would + seem to allow up to 2\sup{64}-1 elements in the array. However, both + QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{32}-2 + items on 32-bit systems and 2\sup{64}-2 items on 64-bit ones. Also note that + QCborArray is currently limited to 2\sup{27} elements in any platform. + + \sa startArray(), endArray(), startMap(), QCborStreamReader::isArray(), + QCborStreamReader::isLengthKnown() + */ +void QCborStreamWriter::startArray(quint64 count) +{ + d->createContainer(cbor_encoder_create_array, count); +} + +/*! + Terminates the array started by either overload of startArray() and returns + true if the correct number of elements was added to the array. This function + must be called for every startArray() used. + + A return of false indicates error in the application and an unrecoverable + error in this stream. QCborStreamWriter also writes a warning using + qWarning() if that happens. + + Calling this function when the current container is not an array is also an + error, though QCborStreamWriter cannot currently detect this condition. + + \sa startArray(), startArray(quint64), endMap() + */ +bool QCborStreamWriter::endArray() +{ + return d->closeContainer(); +} + +/*! + Starts a CBOR Map with indeterminate length in the CBOR stream. Each + startMap() call must be paired with one endMap() call and the current CBOR + element extends until the end of the map. + + The map created by this function has no explicit length. Instead, its length + is implied by the elements contained in it. Note, however, that use of + indeterminate-length maps is not compliant with canonical CBOR encoding + (canonical encoding also requires keys to be unique and in sorted order). + + The following example appends elements from the linked list of int and + string pairs passed as input: + + \snippet code/src_corelib_serialization_qcborstream.cpp 22 + + \sa startMap(quint64), endMap(), startArray(), QCborStreamReader::isMap(), + QCborStreamReader::isLengthKnown() + */ +void QCborStreamWriter::startMap() +{ + d->createContainer(cbor_encoder_create_map); +} + +/*! + \overload + + Starts a CBOR Map with explicit length of \a count items in the CBOR + stream. Each startMap call must be paired with one endMap() call and the + current CBOR element extends until the end of the map. + + The map created by this function has an explicit length and therefore + exactly \a count pairs of items must be added to the CBOR stream. Adding + fewer or more items will result in failure during endMap() and the CBOR + stream will be corrupt. However, explicit-length map are required by + canonical CBOR encoding. + + The following example appends all strings found in the \l QMap passed as input: + + \snippet code/src_corelib_serialization_qcborstream.cpp 23 + + \b{Size limitations}: The parameter to this function is quint64, which would + seem to allow up to 2\sup{64}-1 pairs in the map. However, both + QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{31}-1 + items on 32-bit systems and 2\sup{63}-1 items on 64-bit ones. Also note that + QCborMap is currently limited to 2\sup{26} elements in any platform. + + \sa startMap(), endMap(), startArray(), QCborStreamReader::isMap(), + QCborStreamReader::isLengthKnown() + */ +void QCborStreamWriter::startMap(quint64 count) +{ + d->createContainer(cbor_encoder_create_map, count); +} + +/*! + Terminates the map started by either overload of startMap() and returns + true if the correct number of elements was added to the array. This function + must be called for every startMap() used. + + A return of false indicates error in the application and an unrecoverable + error in this stream. QCborStreamWriter also writes a warning using + qWarning() if that happens. + + Calling this function when the current container is not a map is also an + error, though QCborStreamWriter cannot currently detect this condition. + + \sa startMap(), startMap(quint64), endArray() + */ +bool QCborStreamWriter::endMap() +{ + return d->closeContainer(); +} + +QT_END_NAMESPACE |