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