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

source code of qtbase/src/corelib/serialization/qcborstreamwriter.cpp