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