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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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