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 \sa append(), appendTextString(),
591 QCborStreamReader::isByteArray(), QCborStreamReader::readByteArray()
592 */
593void QCborStreamWriter::appendByteString(const char *data, qsizetype len)
594{
595 d->executeAppend(f: cbor_encode_byte_string, args: reinterpret_cast<const uint8_t *>(data), args: size_t(len));
596}
597
598/*!
599 Appends \a len bytes of text starting from \a utf8 to the stream, creating a
600 CBOR Text String value. QCborStreamWriter will attempt to write the entire
601 string in one chunk.
602
603 The string pointed to by \a utf8 is expected to be properly encoded UTF-8.
604 QCborStreamWriter performs no validation that this is the case.
605
606 \sa append(QLatin1StringView), append(QStringView),
607 QCborStreamReader::isString(), QCborStreamReader::readString()
608 */
609void QCborStreamWriter::appendTextString(const char *utf8, qsizetype len)
610{
611 d->executeAppend(f: cbor_encode_text_string, args: utf8, args: size_t(len));
612}
613
614/*!
615 \fn void QCborStreamWriter::append(const char *str, qsizetype size)
616 \overload
617
618 Appends \a size bytes of text starting from \a str to the stream, creating a
619 CBOR Text String value. QCborStreamWriter will attempt to write the entire
620 string in one chunk. If \a size is -1, this function will write \c strlen(\a
621 str) bytes.
622
623 The string pointed to by \a str is expected to be properly encoded UTF-8.
624 QCborStreamWriter performs no validation that this is the case.
625
626 \sa append(QLatin1StringView), append(QStringView),
627 QCborStreamReader::isString(), QCborStreamReader::readString()
628 */
629
630/*!
631 \fn void QCborStreamWriter::append(bool b)
632 \overload
633
634 Appends the boolean value \a b to the stream, creating either a CBOR False
635 value or a CBOR True value. This function is equivalent to (and implemented
636 as):
637
638 \snippet code/src_corelib_serialization_qcborstream.cpp 16
639
640 \sa appendNull(), appendUndefined(),
641 QCborStreamReader::isBool(), QCborStreamReader::toBool()
642 */
643
644/*!
645 \fn void QCborStreamWriter::append(std::nullptr_t)
646 \overload
647
648 Appends a CBOR Null value to the stream. This function is equivalent to (and
649 implemented as): The parameter is ignored.
650
651 \snippet code/src_corelib_serialization_qcborstream.cpp 17
652
653 \sa appendNull(), append(QCborSimpleType), QCborStreamReader::isNull()
654 */
655
656/*!
657 \fn void QCborStreamWriter::appendNull()
658
659 Appends a CBOR Null value to the stream. This function is equivalent to (and
660 implemented as):
661
662 \snippet code/src_corelib_serialization_qcborstream.cpp 18
663
664 \sa append(std::nullptr_t), append(QCborSimpleType), QCborStreamReader::isNull()
665 */
666
667/*!
668 \fn void QCborStreamWriter::appendUndefined()
669
670 Appends a CBOR Undefined value to the stream. This function is equivalent to (and
671 implemented as):
672
673 \snippet code/src_corelib_serialization_qcborstream.cpp 19
674
675 \sa append(QCborSimpleType), QCborStreamReader::isUndefined()
676 */
677
678/*!
679 Starts a CBOR Array with indeterminate length in the CBOR stream. Each
680 startArray() call must be paired with one endArray() call and the current
681 CBOR element extends until the end of the array.
682
683 The array created by this function has no explicit length. Instead, its
684 length is implied by the elements contained in it. Note, however, that use
685 of indeterminate-length arrays is not compliant with canonical CBOR encoding.
686
687 The following example appends elements from the list of strings
688 passed as input:
689
690 \snippet code/src_corelib_serialization_qcborstream.cpp 20
691
692 \sa startArray(quint64), endArray(), startMap(), QCborStreamReader::isArray(),
693 QCborStreamReader::isLengthKnown()
694 */
695void QCborStreamWriter::startArray()
696{
697 d->createContainer(f: cbor_encoder_create_array);
698}
699
700/*!
701 \overload
702
703 Starts a CBOR Array with explicit length of \a count items in the CBOR
704 stream. Each startArray call must be paired with one endArray() call and the
705 current CBOR element extends until the end of the array.
706
707 The array created by this function has an explicit length and therefore
708 exactly \a count items must be added to the CBOR stream. Adding fewer or
709 more items will result in failure during endArray() and the CBOR stream will
710 be corrupt. However, explicit-length arrays are required by canonical CBOR
711 encoding.
712
713 The following example appends all strings found in the \l QStringList passed as input:
714
715 \snippet code/src_corelib_serialization_qcborstream.cpp 21
716
717 \b{Size limitations}: The parameter to this function is quint64, which would
718 seem to allow up to 2\sup{64}-1 elements in the array. However, both
719 QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{32}-2
720 items on 32-bit systems and 2\sup{64}-2 items on 64-bit ones. Also note that
721 QCborArray is currently limited to 2\sup{27} elements on 32-bit platforms and
722 2\sup{59} elements on 64-bit ones.
723
724 \sa startArray(), endArray(), startMap(), QCborStreamReader::isArray(),
725 QCborStreamReader::isLengthKnown()
726 */
727void QCborStreamWriter::startArray(quint64 count)
728{
729 d->createContainer(f: cbor_encoder_create_array, len: count);
730}
731
732/*!
733 Terminates the array started by either overload of startArray() and returns
734 true if the correct number of elements was added to the array. This function
735 must be called for every startArray() used.
736
737 A return of false indicates error in the application and an unrecoverable
738 error in this stream. QCborStreamWriter also writes a warning using
739 qWarning() if that happens.
740
741 Calling this function when the current container is not an array is also an
742 error, though QCborStreamWriter cannot currently detect this condition.
743
744 \sa startArray(), startArray(quint64), endMap()
745 */
746bool QCborStreamWriter::endArray()
747{
748 return d->closeContainer();
749}
750
751/*!
752 Starts a CBOR Map with indeterminate length in the CBOR stream. Each
753 startMap() call must be paired with one endMap() call and the current CBOR
754 element extends until the end of the map.
755
756 The map created by this function has no explicit length. Instead, its length
757 is implied by the elements contained in it. Note, however, that use of
758 indeterminate-length maps is not compliant with canonical CBOR encoding
759 (canonical encoding also requires keys to be unique and in sorted order).
760
761 The following example appends elements from the list of int and
762 string pairs passed as input:
763
764 \snippet code/src_corelib_serialization_qcborstream.cpp 22
765
766 \sa startMap(quint64), endMap(), startArray(), QCborStreamReader::isMap(),
767 QCborStreamReader::isLengthKnown()
768 */
769void QCborStreamWriter::startMap()
770{
771 d->createContainer(f: cbor_encoder_create_map);
772}
773
774/*!
775 \overload
776
777 Starts a CBOR Map with explicit length of \a count items in the CBOR
778 stream. Each startMap call must be paired with one endMap() call and the
779 current CBOR element extends until the end of the map.
780
781 The map created by this function has an explicit length and therefore
782 exactly \a count pairs of items must be added to the CBOR stream. Adding
783 fewer or more items will result in failure during endMap() and the CBOR
784 stream will be corrupt. However, explicit-length map are required by
785 canonical CBOR encoding.
786
787 The following example appends all strings found in the \l QMap passed as input:
788
789 \snippet code/src_corelib_serialization_qcborstream.cpp 23
790
791 \b{Size limitations}: The parameter to this function is quint64, which would
792 seem to allow up to 2\sup{64}-1 pairs in the map. However, both
793 QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{31}-1
794 items on 32-bit systems and 2\sup{63}-1 items on 64-bit ones. Also note that
795 QCborMap is currently limited to 2\sup{26} elements on 32-bit platforms and
796 2\sup{58} on 64-bit ones.
797
798 \sa startMap(), endMap(), startArray(), QCborStreamReader::isMap(),
799 QCborStreamReader::isLengthKnown()
800 */
801void QCborStreamWriter::startMap(quint64 count)
802{
803 d->createContainer(f: cbor_encoder_create_map, len: count);
804}
805
806/*!
807 Terminates the map started by either overload of startMap() and returns
808 true if the correct number of elements was added to the array. This function
809 must be called for every startMap() used.
810
811 A return of false indicates error in the application and an unrecoverable
812 error in this stream. QCborStreamWriter also writes a warning using
813 qWarning() if that happens.
814
815 Calling this function when the current container is not a map is also an
816 error, though QCborStreamWriter cannot currently detect this condition.
817
818 \sa startMap(), startMap(quint64), endArray()
819 */
820bool QCborStreamWriter::endMap()
821{
822 return d->closeContainer();
823}
824
825QT_END_NAMESPACE
826
827#undef CBOR_ENCODER_WRITER_CONTROL
828#undef CBOR_ENCODER_WRITE_FUNCTION
829#undef CBOR_ENCODER_NO_CHECK_USER
830

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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