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