1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 Intel Corporation.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qcborstreamwriter.h"
41 
42 #define CBOR_NO_PARSER_API
43 #include <private/qcborcommon_p.h>
44 
45 #include <private/qnumeric_p.h>
46 #include <qbuffer.h>
47 #include <qdebug.h>
48 #include <qstack.h>
49 
50 QT_BEGIN_NAMESPACE
51 
52 static CborError qt_cbor_encoder_write_callback(void *token, const void *data, size_t len, CborEncoderAppendType);
53 #define CBOR_ENCODER_WRITER_CONTROL     1
54 #define CBOR_ENCODER_WRITE_FUNCTION     qt_cbor_encoder_write_callback
55 #define CBOR_ENCODER_NO_CHECK_USER
56 
57 QT_WARNING_PUSH
58 QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
59 
60 #include <cborencoder.c>
61 
62 QT_WARNING_POP
63 
64 // silence compilers that complain about this being a static function declared
65 // but never defined
cbor_encoder_close_container_checked(CborEncoder *,const CborEncoder *)66 static CborError Q_DECL_UNUSED cbor_encoder_close_container_checked(CborEncoder*, const CborEncoder*)
67 {
68     Q_UNREACHABLE();
69     return CborErrorInternalError;
70 }
71 
cbor_encode_float_as_half_float(CborEncoder *,float)72 static CborError Q_DECL_UNUSED cbor_encode_float_as_half_float(CborEncoder *, float)
73 {
74     Q_UNREACHABLE();
75     return CborErrorInternalError;
76 }
77 
78 Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
79 
80 /*!
81    \class QCborStreamWriter
82    \inmodule QtCore
83    \ingroup cbor
84    \reentrant
85    \since 5.12
86 
87    \brief The QCborStreamWriter class is a simple CBOR encoder operating on a
88    one-way stream.
89 
90    This class can be used to quickly encode a stream of CBOR content directly
91    to either a QByteArray or QIODevice. CBOR is the Concise Binary Object
92    Representation, a very compact form of binary data encoding that is
93    compatible with JSON. It was created by the IETF Constrained RESTful
94    Environments (CoRE) WG, which has used it in many new RFCs. It is meant to
95    be used alongside the \l{https://tools.ietf.org/html/rfc7252}{CoAP
96    protocol}.
97 
98    QCborStreamWriter provides a StAX-like API, similar to that of
99    \l{QXmlStreamWriter}. It is rather low-level and requires a bit of knowledge
100    of CBOR encoding. For a simpler API, see \l{QCborValue} and especially the
101    encoding function QCborValue::toCbor().
102 
103    The typical use of QCborStreamWriter is to create the object on the target
104    QByteArray or QIODevice, then call one of the append() overloads with the
105    desired type to be encoded. To create arrays and maps, QCborStreamWriter
106    provides startArray() and startMap() overloads, which must be terminated by
107    the corresponding endArray() and endMap() functions.
108 
109    The following example encodes the equivalent of this JSON content:
110 
111    \div{class="pre"}
112      {
113        "label": "journald",
114        "autoDetect": false,
115        "condition": "libs.journald",
116        "output": [ "privateFeature" ]
117      }
118    \enddiv
119 
120    \snippet code/src_corelib_serialization_qcborstream.cpp 1
121 
122    \section1 CBOR support
123 
124    QCborStreamWriter supports all CBOR features required to create canonical
125    and strict streams. It implements almost all of the features specified in
126    \l {https://tools.ietf.org/html/rfc7049}{RFC 7049}.
127 
128    The following table lists the CBOR features that QCborStreamWriter supports.
129 
130    \table
131      \header \li Feature                        \li Support
132      \row   \li Unsigned numbers                \li Yes (full range)
133      \row   \li Negative numbers                \li Yes (full range)
134      \row   \li Byte strings                    \li Yes
135      \row   \li Text strings                    \li Yes
136      \row   \li Chunked strings                 \li No
137      \row   \li Tags                            \li Yes (arbitrary)
138      \row   \li Booleans                        \li Yes
139      \row   \li Null                            \li Yes
140      \row   \li Undefined                       \li Yes
141      \row   \li Arbitrary simple values         \li Yes
142      \row   \li Half-precision float (16-bit)   \li Yes
143      \row   \li Single-precision float (32-bit) \li Yes
144      \row   \li Double-precision float (64-bit) \li Yes
145      \row   \li Infinities and NaN floating point \li Yes
146      \row   \li Determinate-length arrays and maps \li Yes
147      \row   \li Indeterminate-length arrays and maps \li Yes
148      \row   \li Map key types other than strings and integers \li Yes (arbitrary)
149    \endtable
150 
151    \section2 Canonical CBOR encoding
152 
153    Canonical CBOR encoding is defined by
154    \l{https://tools.ietf.org/html/rfc7049#section-3.9}{Section 3.9 of RFC
155    7049}. Canonical encoding is not a requirement for Qt's CBOR decoding
156    functionality, but it may be required for some protocols. In particular,
157    protocols that require the ability to reproduce the same stream identically
158    may require this.
159 
160    In order to be considered "canonical", a CBOR stream must meet the
161    following requirements:
162 
163    \list
164      \li Integers must be as small as possible. QCborStreamWriter always
165          does this (no user action is required and it is not possible
166          to write overlong integers).
167      \li Array, map and string lengths must be as short as possible. As
168          above, QCborStreamWriter automatically does this.
169      \li Arrays, maps and strings must use explicit length. QCborStreamWriter
170          always does this for strings; for arrays and maps, be sure to call
171          startArray() and startMap() overloads with explicit length.
172      \li Keys in every map must be sorted in ascending order. QCborStreamWriter
173          offers no help in this item: the developer must ensure that before
174          calling append() for the map pairs.
175      \li Floating point values should be as small as possible. QCborStreamWriter
176          will not convert floating point values; it is up to the developer
177          to perform this check prior to calling append() (see those functions'
178          examples).
179    \endlist
180 
181    \section2 Strict CBOR mode
182 
183    Strict mode is defined by
184    \l{https://tools.ietf.org/html/rfc7049#section-3.10}{Section 3.10 of RFC
185    7049}. As for Canonical encoding above, QCborStreamWriter makes it possible
186    to create strict CBOR streams, but does not require them or validate that
187    the output is so.
188 
189    \list
190      \li Keys in a map must be unique. QCborStreamWriter performs no validation
191          of map keys.
192      \li Tags may be required to be paired only with the correct types,
193          according to their specification. QCborStreamWriter performs no
194          validation of tag usage.
195      \li Text Strings must be properly-encoded UTF-8. QCborStreamWriter always
196          writes proper UTF-8 for strings added with append(), but performs no
197          validation for strings added with appendTextString().
198    \endlist
199 
200    \section2 Invalid CBOR stream
201 
202    It is also possible to misuse QCborStreamWriter and produce invalid CBOR
203    streams that will fail to be decoded by a receiver. The following actions
204    will produce invalid streams:
205 
206    \list
207      \li Append a tag and not append the corresponding tagged value
208          (QCborStreamWriter produces no diagnostic).
209      \li Append too many or too few items to an array or map with explicit
210          length (endMap() and endArray() will return false and
211          QCborStreamWriter will log with qWarning()).
212    \endlist
213 
214    \sa QCborStreamReader, QCborValue, QXmlStreamWriter
215  */
216 
217 class QCborStreamWriterPrivate
218 {
219 public:
220     static Q_CONSTEXPR quint64 IndefiniteLength = (std::numeric_limits<quint64>::max)();
221 
222     QIODevice *device;
223     CborEncoder encoder;
224     QStack<CborEncoder> containerStack;
225     bool deleteDevice = false;
226 
QCborStreamWriterPrivate(QIODevice * device)227     QCborStreamWriterPrivate(QIODevice *device)
228         : device(device)
229     {
230         cbor_encoder_init_writer(&encoder, qt_cbor_encoder_write_callback, this);
231     }
232 
~QCborStreamWriterPrivate()233     ~QCborStreamWriterPrivate()
234     {
235         if (deleteDevice)
236             delete device;
237     }
238 
executeAppend(CborError (* f)(CborEncoder *,Args...),Args...args)239     template <typename... Args> void executeAppend(CborError (*f)(CborEncoder *, Args...), Args... args)
240     {
241         f(&encoder, std::forward<Args>(args)...);
242     }
243 
createContainer(CborError (* f)(CborEncoder *,CborEncoder *,size_t),quint64 len=IndefiniteLength)244     void createContainer(CborError (*f)(CborEncoder *, CborEncoder *, size_t), quint64 len = IndefiniteLength)
245     {
246         Q_STATIC_ASSERT(size_t(IndefiniteLength) == CborIndefiniteLength);
247         if (sizeof(len) != sizeof(size_t) && len != IndefiniteLength) {
248             if (Q_UNLIKELY(len >= CborIndefiniteLength)) {
249                 // TinyCBOR can't do this in 32-bit mode
250                 qWarning("QCborStreamWriter: container of size %llu is too big for a 32-bit build; "
251                          "will use indeterminate length instead", len);
252                 len = CborIndefiniteLength;
253             }
254         }
255 
256         containerStack.push(encoder);
257         f(&containerStack.top(), &encoder, len);
258     }
259 
closeContainer()260     bool closeContainer()
261     {
262         if (containerStack.isEmpty()) {
263             qWarning("QCborStreamWriter: closing map or array that wasn't open");
264             return false;
265         }
266 
267         CborEncoder container = containerStack.pop();
268         CborError err = cbor_encoder_close_container(&container, &encoder);
269         encoder = container;
270 
271         if (Q_UNLIKELY(err)) {
272             if (err == CborErrorTooFewItems)
273                 qWarning("QCborStreamWriter: not enough items added to array or map");
274             else if (err == CborErrorTooManyItems)
275                 qWarning("QCborStreamWriter: too many items added to array or map");
276             return false;
277         }
278 
279         return true;
280     }
281 };
282 
qt_cbor_encoder_write_callback(void * self,const void * data,size_t len,CborEncoderAppendType)283 static CborError qt_cbor_encoder_write_callback(void *self, const void *data, size_t len, CborEncoderAppendType)
284 {
285     auto that = static_cast<QCborStreamWriterPrivate *>(self);
286     if (!that->device)
287         return CborNoError;
288     qint64 written = that->device->write(static_cast<const char *>(data), len);
289     return (written == qsizetype(len) ? CborNoError : CborErrorIO);
290 }
291 
292 /*!
293    Creates a QCborStreamWriter object that will write the stream to \a device.
294    The device must be opened before the first append() call is made. This
295    constructor can be used with any class that derives from QIODevice, such as
296    QFile, QProcess or QTcpSocket.
297 
298    QCborStreamWriter has no buffering, so every append() call will result in
299    one or more calls to the device's \l {QIODevice::}{write()} method.
300 
301    The following example writes an empty map to a file:
302 
303    \snippet code/src_corelib_serialization_qcborstream.cpp 2
304 
305    QCborStreamWriter does not take ownership of \a device.
306 
307    \sa device(), setDevice()
308  */
QCborStreamWriter(QIODevice * device)309 QCborStreamWriter::QCborStreamWriter(QIODevice *device)
310     : d(new QCborStreamWriterPrivate(device))
311 {
312 }
313 
314 /*!
315    Creates a QCborStreamWriter object that will append the stream to \a data.
316    All streaming is done immediately to the byte array, without the need for
317    flushing any buffers.
318 
319    The following example writes a number to a byte array then returns
320    it.
321 
322    \snippet code/src_corelib_serialization_qcborstream.cpp 3
323 
324    QCborStreamWriter does not take ownership of \a data.
325  */
QCborStreamWriter(QByteArray * data)326 QCborStreamWriter::QCborStreamWriter(QByteArray *data)
327     : d(new QCborStreamWriterPrivate(new QBuffer(data)))
328 {
329     d->deleteDevice = true;
330     d->device->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
331 }
332 
333 /*!
334    Destroys this QCborStreamWriter object and frees any resources associated.
335 
336    QCborStreamWriter does not perform error checking to see if all required
337    items were written to the stream prior to the object being destroyed. It is
338    the programmer's responsibility to ensure that it was done.
339  */
~QCborStreamWriter()340 QCborStreamWriter::~QCborStreamWriter()
341 {
342 }
343 
344 /*!
345    Replaces the device or byte array that this QCborStreamWriter object is
346    writing to with \a device.
347 
348    \sa device()
349  */
setDevice(QIODevice * device)350 void QCborStreamWriter::setDevice(QIODevice *device)
351 {
352     if (d->deleteDevice)
353         delete d->device;
354     d->device = device;
355     d->deleteDevice = false;
356 }
357 
358 /*!
359    Returns the QIODevice that this QCborStreamWriter object is writing to. The
360    device must have previously been set with either the constructor or with
361    setDevice().
362 
363    If this object was created by writing to a QByteArray, this function will
364    return an internal instance of QBuffer, which is owned by QCborStreamWriter.
365 
366    \sa setDevice()
367  */
device() const368 QIODevice *QCborStreamWriter::device() const
369 {
370     return d->device;
371 }
372 
373 /*!
374    \overload
375 
376    Appends the 64-bit unsigned value \a u to the CBOR stream, creating a CBOR
377    Unsigned Integer value. In the following example, we write the values 0,
378    2\sup{32} and \c UINT64_MAX:
379 
380    \snippet code/src_corelib_serialization_qcborstream.cpp 4
381 
382    \sa QCborStreamReader::isUnsignedInteger(), QCborStreamReader::toUnsignedInteger()
383  */
append(quint64 u)384 void QCborStreamWriter::append(quint64 u)
385 {
386     d->executeAppend(cbor_encode_uint, uint64_t(u));
387 }
388 
389 /*!
390    \overload
391 
392    Appends the 64-bit signed value \a i to the CBOR stream. This will create
393    either a CBOR Unsigned Integer or CBOR NegativeInteger value based on the
394    sign of the parameter. In the following example, we write the values 0, -1,
395    2\sup{32} and \c INT64_MAX:
396 
397    \snippet code/src_corelib_serialization_qcborstream.cpp 5
398 
399    \sa QCborStreamReader::isInteger(), QCborStreamReader::toInteger()
400  */
append(qint64 i)401 void QCborStreamWriter::append(qint64 i)
402 {
403     d->executeAppend(cbor_encode_int, int64_t(i));
404 }
405 
406 /*!
407    \overload
408 
409    Appends the 64-bit negative value \a n to the CBOR stream.
410    QCborNegativeInteger is a 64-bit enum that holds the absolute value of the
411    negative number we want to write. If n is zero, the value written will be
412    equivalent to 2\sup{64} (that is, -18,446,744,073,709,551,616).
413 
414    In the following example, we write the values -1, -2\sup{32} and INT64_MIN:
415    \snippet code/src_corelib_serialization_qcborstream.cpp 6
416 
417    Note how this function can be used to encode numbers that cannot fit a
418    standard computer's 64-bit signed integer like \l qint64. That is, if \a n
419    is larger than \c{std::numeric_limits<qint64>::max()} or is 0, this will
420    represent a negative number smaller than
421    \c{std::numeric_limits<qint64>::min()}.
422 
423    \sa QCborStreamReader::isNegativeInteger(), QCborStreamReader::toNegativeInteger()
424  */
append(QCborNegativeInteger n)425 void QCborStreamWriter::append(QCborNegativeInteger n)
426 {
427     d->executeAppend(cbor_encode_negative_int, uint64_t(n));
428 }
429 
430 /*!
431    \fn void QCborStreamWriter::append(const QByteArray &ba)
432    \overload
433 
434    Appends the byte array \a ba to the stream, creating a CBOR Byte String
435    value. QCborStreamWriter will attempt to write the entire string in one
436    chunk.
437 
438    The following example will load and append the contents of a file to the
439    stream:
440 
441    \snippet code/src_corelib_serialization_qcborstream.cpp 7
442 
443    As the example shows, unlike JSON, CBOR requires no escaping for binary
444    content.
445 
446    \sa appendByteString(), QCborStreamReader::isByteArray(),
447        QCborStreamReader::readByteArray()
448  */
449 
450 /*!
451    \overload
452 
453    Appends the text string \a str to the stream, creating a CBOR Text String
454    value. QCborStreamWriter will attempt to write the entire string in one
455    chunk.
456 
457    The following example appends a simple string to the stream:
458 
459    \snippet code/src_corelib_serialization_qcborstream.cpp 8
460 
461    \b{Performance note}: CBOR requires that all Text Strings be encoded in
462    UTF-8, so this function will iterate over the characters in the string to
463    determine whether the contents are US-ASCII or not. If the string is found
464    to contain characters outside of US-ASCII, it will allocate memory and
465    convert to UTF-8. If this check is unnecessary, use appendTextString()
466    instead.
467 
468    \sa QCborStreamReader::isString(), QCborStreamReader::readString()
469  */
append(QLatin1String str)470 void QCborStreamWriter::append(QLatin1String str)
471 {
472     // We've got Latin-1 but CBOR wants UTF-8, so check if the string is the
473     // common subset (US-ASCII).
474     if (QtPrivate::isAscii(str)) {
475         // it is plain US-ASCII
476         appendTextString(str.latin1(), str.size());
477     } else {
478         // non-ASCII, so we need a pass-through UTF-16
479         append(QString(str));
480     }
481 }
482 
483 /*!
484    \overload
485 
486    Appends the text string \a str to the stream, creating a CBOR Text String
487    value. QCborStreamWriter will attempt to write the entire string in one
488    chunk.
489 
490    The following example writes an arbitrary QString to the stream:
491 
492    \snippet code/src_corelib_serialization_qcborstream.cpp 9
493 
494    \sa QCborStreamReader::isString(), QCborStreamReader::readString()
495  */
append(QStringView str)496 void QCborStreamWriter::append(QStringView str)
497 {
498     QByteArray utf8 = str.toUtf8();
499     appendTextString(utf8.constData(), utf8.size());
500 }
501 
502 /*!
503    \overload
504 
505    Appends the CBOR tag \a tag to the stream, creating a CBOR Tag value. All
506    tags must be followed by another type which they provide meaning for.
507 
508    In the following example, we append a CBOR Tag 36 (Regular Expression) and a
509    QRegularExpression's pattern to the stream:
510 
511    \snippet code/src_corelib_serialization_qcborstream.cpp 10
512 
513    \sa QCborStreamReader::isTag(), QCborStreamReader::toTag()
514  */
append(QCborTag tag)515 void QCborStreamWriter::append(QCborTag tag)
516 {
517     d->executeAppend(cbor_encode_tag, CborTag(tag));
518 }
519 
520 /*!
521    \fn void QCborStreamWriter::append(QCborKnownTags tag)
522    \overload
523 
524    Appends the CBOR tag \a tag to the stream, creating a CBOR Tag value. All
525    tags must be followed by another type which they provide meaning for.
526 
527    In the following example, we append a CBOR Tag 1 (Unix \c time_t) and an
528    integer representing the current time to the stream, obtained using the \c
529    time() function:
530 
531    \snippet code/src_corelib_serialization_qcborstream.cpp 11
532 
533    \sa QCborStreamReader::isTag(), QCborStreamReader::toTag()
534  */
535 
536 /*!
537    \overload
538 
539    Appends the CBOR simple type \a st to the stream, creating a CBOR Simple
540    Type value. In the following example, we write the simple type for Null as
541    well as for type 32, which Qt has no support for.
542 
543    \snippet code/src_corelib_serialization_qcborstream.cpp 12
544 
545    \note Using Simple Types for which there is no specification can lead to
546    validation errors by the remote receiver. In addition, simple type values 24
547    through 31 (inclusive) are reserved and must not be used.
548 
549    \sa QCborStreamReader::isSimpleType(), QCborStreamReader::toSimpleType()
550  */
append(QCborSimpleType st)551 void QCborStreamWriter::append(QCborSimpleType st)
552 {
553     d->executeAppend(cbor_encode_simple_value, uint8_t(st));
554 }
555 
556 #ifndef QT_BOOTSTRAPPED
557 /*!
558    \overload
559 
560    Appends the floating point number \a f to the stream, creating a CBOR 16-bit
561    Half-Precision Floating Point value. The following code can be used to convert
562    a C++ \tt float to \c qfloat16 if there's no loss of precision and append it, or
563    instead append the \tt float.
564 
565    \snippet code/src_corelib_serialization_qcborstream.cpp 13
566 
567    \sa QCborStreamReader::isFloat16(), QCborStreamReader::toFloat16()
568  */
append(qfloat16 f)569 void QCborStreamWriter::append(qfloat16 f)
570 {
571     d->executeAppend(cbor_encode_half_float, static_cast<const void *>(&f));
572 }
573 #endif // QT_BOOTSTRAPPED
574 
575 /*!
576    \overload
577 
578    Appends the floating point number \a f to the stream, creating a CBOR 32-bit
579    Single-Precision Floating Point value. The following code can be used to convert
580    a C++ \tt double to \tt float if there's no loss of precision and append it, or
581    instead append the \tt double.
582 
583    \snippet code/src_corelib_serialization_qcborstream.cpp 14
584 
585    \sa QCborStreamReader::isFloat(), QCborStreamReader::toFloat()
586  */
append(float f)587 void QCborStreamWriter::append(float f)
588 {
589     d->executeAppend(cbor_encode_float, f);
590 }
591 
592 /*!
593    \overload
594 
595    Appends the floating point number \a d to the stream, creating a CBOR 64-bit
596    Double-Precision Floating Point value. QCborStreamWriter always appends the
597    number as-is, performing no check for whether the number is the canonical
598    form for NaN, an infinite, whether it is denormal or if it could be written
599    with a shorter format.
600 
601    The following code performs all those checks, except for the denormal one,
602    which is expected to be taken into account by the system FPU or floating
603    point emulation directly.
604 
605    \snippet code/src_corelib_serialization_qcborstream.cpp 15
606 
607    Determining if a double can be converted to an integral with no loss of
608    precision is left as an exercise to the reader.
609 
610    \sa QCborStreamReader::isDouble(), QCborStreamReader::toDouble()
611  */
append(double d)612 void QCborStreamWriter::append(double d)
613 {
614     this->d->executeAppend(cbor_encode_double, d);
615 }
616 
617 /*!
618    Appends \a len bytes of data starting from \a data to the stream, creating a
619    CBOR Byte String value. QCborStreamWriter will attempt to write the entire
620    string in one chunk.
621 
622    Unlike the QByteArray overload of append(), this function is not limited by
623    QByteArray's size limits. However, note that neither
624    QCborStreamReader::readByteArray() nor QCborValue support reading CBOR
625    streams with byte arrays larger than 2 GB.
626 
627    \sa append(), appendTextString(),
628        QCborStreamReader::isByteArray(), QCborStreamReader::readByteArray()
629  */
appendByteString(const char * data,qsizetype len)630 void QCborStreamWriter::appendByteString(const char *data, qsizetype len)
631 {
632     d->executeAppend(cbor_encode_byte_string, reinterpret_cast<const uint8_t *>(data), size_t(len));
633 }
634 
635 /*!
636    Appends \a len bytes of text starting from \a utf8 to the stream, creating a
637    CBOR Text String value. QCborStreamWriter will attempt to write the entire
638    string in one chunk.
639 
640    The string pointed to by \a utf8 is expected to be properly encoded UTF-8.
641    QCborStreamWriter performs no validation that this is the case.
642 
643    Unlike the QLatin1String overload of append(), this function is not limited
644    to 2 GB. However, note that neither QCborStreamReader::readString() nor
645    QCborValue support reading CBOR streams with text strings larger than 2 GB.
646 
647    \sa append(QLatin1String), append(QStringView),
648        QCborStreamReader::isString(), QCborStreamReader::readString()
649  */
appendTextString(const char * utf8,qsizetype len)650 void QCborStreamWriter::appendTextString(const char *utf8, qsizetype len)
651 {
652     d->executeAppend(cbor_encode_text_string, utf8, size_t(len));
653 }
654 
655 /*!
656    \fn void QCborStreamWriter::append(const char *str, qsizetype size)
657    \overload
658 
659    Appends \a size bytes of text starting from \a str to the stream, creating a
660    CBOR Text String value. QCborStreamWriter will attempt to write the entire
661    string in one chunk. If \a size is -1, this function will write \c strlen(\a
662    str) bytes.
663 
664    The string pointed to by \a str is expected to be properly encoded UTF-8.
665    QCborStreamWriter performs no validation that this is the case.
666 
667    Unlike the QLatin1String overload of append(), this function is not limited
668    to 2 GB. However, note that neither QCborStreamReader nor QCborValue support
669    reading CBOR streams with text strings larger than 2 GB.
670 
671    \sa append(QLatin1String), append(QStringView),
672        QCborStreamReader::isString(), QCborStreamReader::readString()
673  */
674 
675 /*!
676    \fn void QCborStreamWriter::append(bool b)
677    \overload
678 
679    Appends the boolean value \a b to the stream, creating either a CBOR False
680    value or a CBOR True value. This function is equivalent to (and implemented
681    as):
682 
683    \snippet code/src_corelib_serialization_qcborstream.cpp 16
684 
685    \sa appendNull(), appendUndefined(),
686        QCborStreamReader::isBool(), QCborStreamReader::toBool()
687  */
688 
689 /*!
690    \fn void QCborStreamWriter::append(std::nullptr_t)
691    \overload
692 
693    Appends a CBOR Null value to the stream. This function is equivalent to (and
694    implemented as): The parameter is ignored.
695 
696    \snippet code/src_corelib_serialization_qcborstream.cpp 17
697 
698    \sa appendNull(), append(QCborSimpleType), QCborStreamReader::isNull()
699  */
700 
701 /*!
702    \fn void QCborStreamWriter::appendNull()
703 
704    Appends a CBOR Null value to the stream. This function is equivalent to (and
705    implemented as):
706 
707    \snippet code/src_corelib_serialization_qcborstream.cpp 18
708 
709    \sa append(std::nullptr_t), append(QCborSimpleType), QCborStreamReader::isNull()
710  */
711 
712 /*!
713    \fn void QCborStreamWriter::appendUndefined()
714 
715    Appends a CBOR Undefined value to the stream. This function is equivalent to (and
716    implemented as):
717 
718    \snippet code/src_corelib_serialization_qcborstream.cpp 19
719 
720    \sa append(QCborSimpleType), QCborStreamReader::isUndefined()
721  */
722 
723 /*!
724    Starts a CBOR Array with indeterminate length in the CBOR stream. Each
725    startArray() call must be paired with one endArray() call and the current
726    CBOR element extends until the end of the array.
727 
728    The array created by this function has no explicit length. Instead, its
729    length is implied by the elements contained in it. Note, however, that use
730    of indeterminate-length arrays is not compliant with canonical CBOR encoding.
731 
732    The following example appends elements from the linked list of strings
733    passed as input:
734 
735    \snippet code/src_corelib_serialization_qcborstream.cpp 20
736 
737    \sa startArray(quint64), endArray(), startMap(), QCborStreamReader::isArray(),
738    QCborStreamReader::isLengthKnown()
739  */
startArray()740 void QCborStreamWriter::startArray()
741 {
742     d->createContainer(cbor_encoder_create_array);
743 }
744 
745 /*!
746    \overload
747 
748    Starts a CBOR Array with explicit length of \a count items in the CBOR
749    stream. Each startArray call must be paired with one endArray() call and the
750    current CBOR element extends until the end of the array.
751 
752    The array created by this function has an explicit length and therefore
753    exactly \a count items must be added to the CBOR stream. Adding fewer or
754    more items will result in failure during endArray() and the CBOR stream will
755    be corrupt. However, explicit-length arrays are required by canonical CBOR
756    encoding.
757 
758    The following example appends all strings found in the \l QStringList passed as input:
759 
760    \snippet code/src_corelib_serialization_qcborstream.cpp 21
761 
762    \b{Size limitations}: The parameter to this function is quint64, which would
763    seem to allow up to 2\sup{64}-1 elements in the array. However, both
764    QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{32}-2
765    items on 32-bit systems and 2\sup{64}-2 items on 64-bit ones. Also note that
766    QCborArray is currently limited to 2\sup{27} elements in any platform.
767 
768    \sa startArray(), endArray(), startMap(), QCborStreamReader::isArray(),
769    QCborStreamReader::isLengthKnown()
770  */
startArray(quint64 count)771 void QCborStreamWriter::startArray(quint64 count)
772 {
773     d->createContainer(cbor_encoder_create_array, count);
774 }
775 
776 /*!
777    Terminates the array started by either overload of startArray() and returns
778    true if the correct number of elements was added to the array. This function
779    must be called for every startArray() used.
780 
781    A return of false indicates error in the application and an unrecoverable
782    error in this stream. QCborStreamWriter also writes a warning using
783    qWarning() if that happens.
784 
785    Calling this function when the current container is not an array is also an
786    error, though QCborStreamWriter cannot currently detect this condition.
787 
788    \sa startArray(), startArray(quint64), endMap()
789  */
endArray()790 bool QCborStreamWriter::endArray()
791 {
792     return d->closeContainer();
793 }
794 
795 /*!
796    Starts a CBOR Map with indeterminate length in the CBOR stream. Each
797    startMap() call must be paired with one endMap() call and the current CBOR
798    element extends until the end of the map.
799 
800    The map created by this function has no explicit length. Instead, its length
801    is implied by the elements contained in it. Note, however, that use of
802    indeterminate-length maps is not compliant with canonical CBOR encoding
803    (canonical encoding also requires keys to be unique and in sorted order).
804 
805    The following example appends elements from the linked list of int and
806    string pairs passed as input:
807 
808    \snippet code/src_corelib_serialization_qcborstream.cpp 22
809 
810    \sa startMap(quint64), endMap(), startArray(), QCborStreamReader::isMap(),
811        QCborStreamReader::isLengthKnown()
812  */
startMap()813 void QCborStreamWriter::startMap()
814 {
815     d->createContainer(cbor_encoder_create_map);
816 }
817 
818 /*!
819    \overload
820 
821    Starts a CBOR Map with explicit length of \a count items in the CBOR
822    stream. Each startMap call must be paired with one endMap() call and the
823    current CBOR element extends until the end of the map.
824 
825    The map created by this function has an explicit length and therefore
826    exactly \a count pairs of items must be added to the CBOR stream. Adding
827    fewer or more items will result in failure during endMap() and the CBOR
828    stream will be corrupt. However, explicit-length map are required by
829    canonical CBOR encoding.
830 
831    The following example appends all strings found in the \l QMap passed as input:
832 
833    \snippet code/src_corelib_serialization_qcborstream.cpp 23
834 
835    \b{Size limitations}: The parameter to this function is quint64, which would
836    seem to allow up to 2\sup{64}-1 pairs in the map. However, both
837    QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{31}-1
838    items on 32-bit systems and 2\sup{63}-1 items on 64-bit ones. Also note that
839    QCborMap is currently limited to 2\sup{26} elements in any platform.
840 
841    \sa startMap(), endMap(), startArray(), QCborStreamReader::isMap(),
842        QCborStreamReader::isLengthKnown()
843  */
startMap(quint64 count)844 void QCborStreamWriter::startMap(quint64 count)
845 {
846     d->createContainer(cbor_encoder_create_map, count);
847 }
848 
849 /*!
850    Terminates the map started by either overload of startMap() and returns
851    true if the correct number of elements was added to the array. This function
852    must be called for every startMap() used.
853 
854    A return of false indicates error in the application and an unrecoverable
855    error in this stream. QCborStreamWriter also writes a warning using
856    qWarning() if that happens.
857 
858    Calling this function when the current container is not a map is also an
859    error, though QCborStreamWriter cannot currently detect this condition.
860 
861    \sa startMap(), startMap(quint64), endArray()
862  */
endMap()863 bool QCborStreamWriter::endMap()
864 {
865     return d->closeContainer();
866 }
867 
868 QT_END_NAMESPACE
869