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 "qcborstream.h"
41
42#include <private/qnumeric_p.h>
43#include <private/qutfcodec_p.h>
44#include <qbuffer.h>
45#include <qdebug.h>
46#include <qstack.h>
47#include <qdatastream.h>
48
49QT_BEGIN_NAMESPACE
50
51#ifdef QT_NO_DEBUG
52# define NDEBUG 1
53#endif
54#undef assert
55#define assert Q_ASSERT
56
57QT_WARNING_PUSH
58QT_WARNING_DISABLE_GCC("-Wunused-function")
59QT_WARNING_DISABLE_CLANG("-Wunused-function")
60QT_WARNING_DISABLE_CLANG("-Wundefined-internal")
61QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
62
63#define CBOR_ENCODER_NO_CHECK_USER
64
65#define CBOR_NO_VALIDATION_API 1
66#define CBOR_NO_PRETTY_API 1
67#define CBOR_API static inline
68#define CBOR_PRIVATE_API static inline
69#define CBOR_INLINE_API static inline
70
71#include <cbor.h>
72
73static CborError qt_cbor_encoder_write_callback(void *token, const void *data, size_t len, CborEncoderAppendType);
74static bool qt_cbor_decoder_can_read(void *token, size_t len);
75static void qt_cbor_decoder_advance(void *token, size_t len);
76static void *qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len);
77static CborError qt_cbor_decoder_transfer_string(void *token, const void **userptr, size_t offset, size_t len);
78
79#define CBOR_ENCODER_WRITER_CONTROL 1
80#define CBOR_ENCODER_WRITE_FUNCTION qt_cbor_encoder_write_callback
81
82#define CBOR_PARSER_READER_CONTROL 1
83#define CBOR_PARSER_CAN_READ_BYTES_FUNCTION qt_cbor_decoder_can_read
84#define CBOR_PARSER_ADVANCE_BYTES_FUNCTION qt_cbor_decoder_advance
85#define CBOR_PARSER_TRANSFER_STRING_FUNCTION qt_cbor_decoder_transfer_string
86#define CBOR_PARSER_READ_BYTES_FUNCTION qt_cbor_decoder_read
87
88#include "../3rdparty/tinycbor/src/cborencoder.c"
89#include "../3rdparty/tinycbor/src/cborerrorstrings.c"
90#include "../3rdparty/tinycbor/src/cborparser.c"
91
92// silence compilers that complain about this being a static function declared
93// but never defined
94static CborError cbor_encoder_close_container_checked(CborEncoder*, const CborEncoder*)
95{
96 Q_UNREACHABLE();
97 return CborErrorInternalError;
98}
99static CborError _cbor_value_dup_string(const CborValue *, void **, size_t *, CborValue *)
100{
101 Q_UNREACHABLE();
102 return CborErrorInternalError;
103}
104static CborError cbor_value_get_half_float_as_float(const CborValue *, float *)
105{
106 Q_UNREACHABLE();
107 return CborErrorInternalError;
108}
109static CborError cbor_encode_float_as_half_float(CborEncoder *, float)
110{
111 Q_UNREACHABLE();
112 return CborErrorInternalError;
113}
114QT_WARNING_POP
115
116Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
117Q_DECLARE_TYPEINFO(CborValue, Q_PRIMITIVE_TYPE);
118
119// confirm our constants match TinyCBOR's
120Q_STATIC_ASSERT(int(QCborStreamReader::UnsignedInteger) == CborIntegerType);
121Q_STATIC_ASSERT(int(QCborStreamReader::ByteString) == CborByteStringType);
122Q_STATIC_ASSERT(int(QCborStreamReader::TextString) == CborTextStringType);
123Q_STATIC_ASSERT(int(QCborStreamReader::Array) == CborArrayType);
124Q_STATIC_ASSERT(int(QCborStreamReader::Map) == CborMapType);
125Q_STATIC_ASSERT(int(QCborStreamReader::Tag) == CborTagType);
126Q_STATIC_ASSERT(int(QCborStreamReader::SimpleType) == CborSimpleType);
127Q_STATIC_ASSERT(int(QCborStreamReader::HalfFloat) == CborHalfFloatType);
128Q_STATIC_ASSERT(int(QCborStreamReader::Float) == CborFloatType);
129Q_STATIC_ASSERT(int(QCborStreamReader::Double) == CborDoubleType);
130Q_STATIC_ASSERT(int(QCborStreamReader::Invalid) == CborInvalidType);
131
132/*!
133 \headerfile <QtCborCommon>
134
135 \brief The <QtCborCommon> header contains definitions common to both the
136 streaming classes (QCborStreamReader and QCborStreamWriter) and to
137 QCborValue.
138 */
139
140/*!
141 \enum QCborSimpleType
142 \relates <QtCborCommon>
143
144 This enum contains the possible "Simple Types" for CBOR. Simple Types range
145 from 0 to 255 and are types that carry no further value.
146
147 The following values are currently known:
148
149 \value False A "false" boolean.
150 \value True A "true" boolean.
151 \value Null Absence of value (null).
152 \value Undefined Missing or deleted value, usually an error.
153
154 Qt CBOR API supports encoding and decoding any Simple Type, whether one of
155 those above or any other value.
156
157 Applications should only use further values if a corresponding specification
158 has been published, otherwise interpretation and validation by the remote
159 may fail. Values 24 to 31 are reserved and must not be used.
160
161 The current authoritative list is maintained by IANA in the
162 \l{https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xml}{Simple
163 Values registry}.
164
165 \sa QCborStreamWriter::append(QCborSimpleType), QCborStreamReader::isSimpleType(),
166 QCborStreamReader::toSimpleType(), QCborValue::isSimpleType(), QCborValue::toSimpleType()
167 */
168
169Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
170{
171 switch (st) {
172 case QCborSimpleType::False:
173 return "False";
174 case QCborSimpleType::True:
175 return "True";
176 case QCborSimpleType::Null:
177 return "Null";
178 case QCborSimpleType::Undefined:
179 return "Undefined";
180 }
181 return nullptr;
182}
183
184#if !defined(QT_NO_DATASTREAM)
185QDataStream &operator<<(QDataStream &ds, QCborSimpleType st)
186{
187 return ds << quint8(st);
188}
189
190QDataStream &operator>>(QDataStream &ds, QCborSimpleType &st)
191{
192 quint8 v;
193 ds >> v;
194 st = QCborSimpleType(v);
195 return ds;
196}
197#endif
198
199#if !defined(QT_NO_DEBUG_STREAM)
200QDebug operator<<(QDebug dbg, QCborSimpleType st)
201{
202 QDebugStateSaver saver(dbg);
203 const char *id = qt_cbor_simpletype_id(st);
204 if (id)
205 return dbg.nospace() << "QCborSimpleType::" << id;
206
207 return dbg.nospace() << "QCborSimpleType(" << uint(st) << ')';
208}
209#endif
210
211/*!
212 \enum QCborTag
213 \relates <QtCborCommon>
214
215 This enum contains no enumeration and is used only to provide type-safe
216 access to a CBOR tag.
217
218 CBOR tags are 64-bit numbers that are attached to generic CBOR types to
219 provide further semantic meaning. QCborTag may be constructed from an
220 enumeration found in QCborKnownTags or directly by providing the numeric
221 representation.
222
223 For example, the following creates a QCborValue containing a byte array
224 tagged with a tag 2.
225
226 \snippet code/src_corelib_serialization_qcborstream.cpp 0
227
228 \sa QCborKnownTags, QCborStreamWriter::append(QCborTag),
229 QCborStreamReader::isTag(), QCborStreamReader::toTag(),
230 QCborValue::isTag(), QCborValue::tag()
231 */
232
233Q_CORE_EXPORT const char *qt_cbor_tag_id(QCborTag tag)
234{
235 // Casting to QCborKnownTags's underlying type will make the comparison
236 // below fail if the tag value is out of range.
237 auto n = std::underlying_type<QCborKnownTags>::type(tag);
238 if (QCborTag(n) == tag) {
239 switch (QCborKnownTags(n)) {
240 case QCborKnownTags::DateTimeString:
241 return "DateTimeString";
242 case QCborKnownTags::UnixTime_t:
243 return "UnixTime_t";
244 case QCborKnownTags::PositiveBignum:
245 return "PositiveBignum";
246 case QCborKnownTags::NegativeBignum:
247 return "NegativeBignum";
248 case QCborKnownTags::Decimal:
249 return "Decimal";
250 case QCborKnownTags::Bigfloat:
251 return "Bigfloat";
252 case QCborKnownTags::COSE_Encrypt0:
253 return "COSE_Encrypt0";
254 case QCborKnownTags::COSE_Mac0:
255 return "COSE_Mac0";
256 case QCborKnownTags::COSE_Sign1:
257 return "COSE_Sign1";
258 case QCborKnownTags::ExpectedBase64url:
259 return "ExpectedBase64url";
260 case QCborKnownTags::ExpectedBase64:
261 return "ExpectedBase64";
262 case QCborKnownTags::ExpectedBase16:
263 return "ExpectedBase16";
264 case QCborKnownTags::EncodedCbor:
265 return "EncodedCbor";
266 case QCborKnownTags::Url:
267 return "Url";
268 case QCborKnownTags::Base64url:
269 return "Base64url";
270 case QCborKnownTags::Base64:
271 return "Base64";
272 case QCborKnownTags::RegularExpression:
273 return "RegularExpression";
274 case QCborKnownTags::MimeMessage:
275 return "MimeMessage";
276 case QCborKnownTags::Uuid:
277 return "Uuid";
278 case QCborKnownTags::COSE_Encrypt:
279 return "COSE_Encrypt";
280 case QCborKnownTags::COSE_Mac:
281 return "COSE_Mac";
282 case QCborKnownTags::COSE_Sign:
283 return "COSE_Sign";
284 case QCborKnownTags::Signature:
285 return "Signature";
286 }
287 }
288 return nullptr;
289}
290
291#if !defined(QT_NO_DEBUG_STREAM)
292QDebug operator<<(QDebug dbg, QCborTag tag)
293{
294 QDebugStateSaver saver(dbg);
295 const char *id = qt_cbor_tag_id(tag);
296 dbg.nospace() << "QCborTag(";
297 if (id)
298 dbg.nospace() << "QCborKnownTags::" << id;
299 else
300 dbg.nospace() << quint64(tag);
301
302 return dbg << ')';
303}
304#endif
305
306/*!
307 \enum QCborKnownTags
308 \relates <QtCborCommon>
309
310 This enum contains a list of CBOR tags, known at the time of the Qt
311 implementation. This list is not meant to be complete and contains only
312 tags that are either backed by an RFC or specifically used by the Qt
313 implementation.
314
315 The authoritative list is maintained by IANA in the
316 \l{https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml}{CBOR tag
317 registry}.
318
319 \value DateTimeString A date and time string, formatted according to RFC 3339, as refined
320 by RFC 4287. It is the same format as Qt::ISODate and
321 Qt::ISODateWithMs.
322 \value UnixTime_t A numerical representation of seconds elapsed since
323 1970-01-01T00:00Z.
324 \value PositiveBignum A positive number of arbitrary length, encoded as a byte array in
325 network byte order. For example, the number 2\sup{64} is represented by
326 a byte array containing the byte value 0x01 followed by 8 zero bytes.
327 \value NegativeBignum A negative number of arbirary length, encoded as the absolute value
328 of that number, minus one. For example, a byte array containing
329 byte value 0x02 followed by 8 zero bytes represents the number
330 -2\sup{65} - 1.
331 \value Decimal A decimal fraction, encoded as an array of two integers: the first
332 is the exponent of the power of 10, the second the integral
333 mantissa. The value 273.15 would be encoded as array \c{[-2, 27315]}.
334 \value Bigfloat Similar to Decimal, but the exponent is a power of 2 instead.
335 \value COSE_Encrypt0 An \c Encrypt0 map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
336 (CBOR Object Signing and Encryption).
337 \value COSE_Mac0 A \c Mac0 map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
338 (CBOR Object Signing and Encryption).
339 \value COSE_Sign1 A \c Sign1 map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
340 (CBOR Object Signing and Encryption).
341 \value ExpectedBase64url Indicates that the byte array should be encoded using Base64url
342 if the stream is converted to JSON.
343 \value ExpectedBase64 Indicates that the byte array should be encoded using Base64
344 if the stream is converted to JSON.
345 \value ExpectedBase16 Indicates that the byte array should be encoded using Base16 (hex)
346 if the stream is converted to JSON.
347 \value EncodedCbor Indicates that the byte array contains a CBOR stream.
348 \value Url Indicates that the string contains a URL.
349 \value Base64url Indicates that the string contains data encoded using Base64url.
350 \value Base64 Indicates that the string contains data encoded using Base64.
351 \value RegularExpression Indicates that the string contains a Perl-Compatible Regular
352 Expression pattern.
353 \value MimeMessage Indicates that the string contains a MIME message (according to
354 \l{https://tools.ietf.org/html/rfc2045}){RFC 2045}.
355 \value Uuid Indicates that the byte array contains a UUID.
356 \value COSE_Encrypt An \c Encrypt map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
357 (CBOR Object Signing and Encryption).
358 \value COSE_Mac A \c Mac map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
359 (CBOR Object Signing and Encryption).
360 \value COSE_Sign A \c Sign map as specified by \l{https://tools.ietf.org/html/rfc8152}{RFC 8152}
361 (CBOR Object Signing and Encryption).
362 \value Signature No change in interpretation; this tag can be used as the outermost
363 tag in a CBOR stream as the file header.
364
365 The following tags are interpreted by QCborValue during decoding and will
366 produce objects with extended Qt types, and it will use those tags when
367 encoding the same extended types.
368
369 \value DateTimeString \l QDateTime
370 \value UnixTime_t \l QDateTime (only in decoding)
371 \value Url \l QUrl
372 \value Uuid \l QUuid
373
374 Additionally, if a QCborValue containing a QByteArray is tagged using one of
375 \c ExpectedBase64url, \c ExpectedBase64 or \c ExpectedBase16, QCborValue
376 will use the expected encoding when converting to JSON (see
377 QCborValue::toJsonValue).
378
379 \sa QCborTag, QCborStreamWriter::append(QCborTag),
380 QCborStreamReader::isTag(), QCborStreamReader::toTag(),
381 QCborValue::isTag(), QCborValue::tag()
382 */
383
384#if !defined(QT_NO_DEBUG_STREAM)
385QDebug operator<<(QDebug dbg, QCborKnownTags tag)
386{
387 QDebugStateSaver saver(dbg);
388 const char *id = qt_cbor_tag_id(QCborTag(int(tag)));
389 if (id)
390 return dbg.nospace() << "QCborKnownTags::" << id;
391
392 return dbg.nospace() << "QCborKnownTags(" << int(tag) << ')';
393}
394#endif
395
396/*!
397 \class QCborError
398 \inmodule QtCore
399 \relates <QtCborCommon>
400 \reentrant
401 \since 5.12
402
403 \brief The QCborError class holds the error condition found while parsing or
404 validating a CBOR stream.
405
406 \sa QCborStreamReader, QCborValue, QCborParserError
407 */
408
409/*!
410 \enum QCborError::Code
411
412 This enum contains the possible error condition codes.
413
414 \value NoError No error was detected.
415 \value UnknownError An unknown error occurred and no further details are available.
416 \value AdvancePastEnd QCborStreamReader::next() was called but there are no more elements in
417 the current context.
418 \value InputOutputError An I/O error with the QIODevice occurred.
419 \value GarbageAtEnd Data was found in the input stream after the last element.
420 \value EndOfFile The end of the input stream was unexpectedly reached while processing an
421 element.
422 \value UnexpectedBreak The CBOR stream contains a Break where it is not allowed (data is
423 corrupt and the error is not recoverable).
424 \value UnknownType The CBOR stream contains an unknown/unparseable Type (data is corrupt
425 and the and the error is not recoverable).
426 \value IllegalType The CBOR stream contains a known type in a position it is not allowed
427 to exist (data is corrupt and the error is not recoverable).
428 \value IllegalNumber The CBOR stream appears to be encoding a number larger than 64-bit
429 (data is corrupt and the error is not recoverable).
430 \value IllegalSimpleType The CBOR stream contains a Simple Type encoded incorrectly (data is
431 corrupt and the error is not recoverable).
432 \value InvalidUtf8String The CBOR stream contains a text string that does not decode properly
433 as UTF-8 (data is corrupt and the error is not recoverable).
434 \value DataTooLarge CBOR string, map or array is too big and cannot be parsed by Qt
435 (internal limitation, but the error is not recoverable).
436 \value NestingTooDeep Too many levels of arrays or maps encountered while processing the
437 input (internal limitation, but the error is not recoverable).
438 \value UnsupportedType The CBOR stream contains a known type that the implementation does not
439 support (internal limitation, but the error is not recoverable).
440 */
441
442// Convert from CborError to QCborError.
443//
444// Centralized in a function in case we need to make more adjustments in the
445// future.
446static QCborError fromCborError(CborError err)
447{
448 return { QCborError::Code(int(err)) };
449}
450
451// Convert to CborError from QCborError.
452//
453// Centralized in a function in case we need to make more adjustments in the
454// future.
455static CborError toCborError(QCborError c)
456{
457 return CborError(int(c.c));
458}
459
460/*!
461 \variable QCborError::c
462 \internal
463 */
464
465/*!
466 \fn QCborError::operator Code() const
467
468 Returns the error code that this QCborError object stores.
469 */
470
471/*!
472 Returns a text string that matches the error code in this QCborError object.
473
474 Note: the string is not translated. Applications whose interface allow users
475 to parse CBOR streams need to provide their own, translated strings.
476
477 \sa QCborError::Code
478 */
479QString QCborError::toString() const
480{
481 switch (c) {
482 case NoError:
483 Q_STATIC_ASSERT(int(NoError) == int(CborNoError));
484 return QString();
485
486 case UnknownError:
487 Q_STATIC_ASSERT(int(UnknownError) == int(CborUnknownError));
488 return QStringLiteral("Unknown error");
489 case AdvancePastEnd:
490 Q_STATIC_ASSERT(int(AdvancePastEnd) == int(CborErrorAdvancePastEOF));
491 return QStringLiteral("Read past end of buffer (more bytes needed)");
492 case InputOutputError:
493 Q_STATIC_ASSERT(int(InputOutputError) == int(CborErrorIO));
494 return QStringLiteral("Input/Output error");
495 case GarbageAtEnd:
496 Q_STATIC_ASSERT(int(GarbageAtEnd) == int(CborErrorGarbageAtEnd));
497 return QStringLiteral("Data found after the end of the stream");
498 case EndOfFile:
499 Q_STATIC_ASSERT(int(EndOfFile) == int(CborErrorUnexpectedEOF));
500 return QStringLiteral("Unexpected end of input data (more bytes needed)");
501 case UnexpectedBreak:
502 Q_STATIC_ASSERT(int(UnexpectedBreak) == int(CborErrorUnexpectedBreak));
503 return QStringLiteral("Invalid CBOR stream: unexpected 'break' byte");
504 case UnknownType:
505 Q_STATIC_ASSERT(int(UnknownType) == int(CborErrorUnknownType));
506 return QStringLiteral("Invalid CBOR stream: unknown type");
507 case IllegalType:
508 Q_STATIC_ASSERT(int(IllegalType) == int(CborErrorIllegalType));
509 return QStringLiteral("Invalid CBOR stream: illegal type found");
510 case IllegalNumber:
511 Q_STATIC_ASSERT(int(IllegalNumber) == int(CborErrorIllegalNumber));
512 return QStringLiteral("Invalid CBOR stream: illegal number encoding (future extension)");
513 case IllegalSimpleType:
514 Q_STATIC_ASSERT(int(IllegalSimpleType) == int(CborErrorIllegalSimpleType));
515 return QStringLiteral("Invalid CBOR stream: illegal simple type");
516 case InvalidUtf8String:
517 Q_STATIC_ASSERT(int(InvalidUtf8String) == int(CborErrorInvalidUtf8TextString));
518 return QStringLiteral("Invalid CBOR stream: invalid UTF-8 text string");
519 case DataTooLarge:
520 Q_STATIC_ASSERT(int(DataTooLarge) == int(CborErrorDataTooLarge));
521 return QStringLiteral("Internal limitation: data set too large");
522 case NestingTooDeep:
523 Q_STATIC_ASSERT(int(NestingTooDeep) == int(CborErrorNestingTooDeep));
524 return QStringLiteral("Internal limitation: data nesting too deep");
525 case UnsupportedType:
526 Q_STATIC_ASSERT(int(UnsupportedType) == int(CborErrorUnsupportedType));
527 return QStringLiteral("Internal limitation: unsupported type");
528 }
529
530 // get the error string from TinyCBOR
531 CborError err = toCborError(*this);
532 return QString::fromLatin1(cbor_error_string(err));
533}
534
535/*!
536 \class QCborStreamWriter
537 \inmodule QtCore
538 \ingroup cbor
539 \reentrant
540 \since 5.12
541
542 \brief The QCborStreamWriter class is a simple CBOR encoder operating on a
543 one-way stream.
544
545 This class can be used to quickly encode a stream of CBOR content directly
546 to either a QByteArray or QIODevice. CBOR is the Concise Binary Object
547 Representation, a very compact form of binary data encoding that is
548 compatible with JSON. It was created by the IETF Constrained RESTful
549 Environments (CoRE) WG, which has used it in many new RFCs. It is meant to
550 be used alongside the \l{https://tools.ietf.org/html/rfc7252}{CoAP
551 protocol}.
552
553 QCborStreamWriter provides a StAX-like API, similar to that of
554 \l{QXmlStreamWriter}. It is rather low-level and requires a bit of knowledge
555 of CBOR encoding. For a simpler API, see \l{QCborValue} and especially the
556 encoding function QCborValue::toCbor().
557
558 The typical use of QCborStreamWriter is to create the object on the target
559 QByteArray or QIODevice, then call one of the append() overloads with the
560 desired type to be encoded. To create arrays and maps, QCborStreamWriter
561 provides startArray() and startMap() overloads, which must be terminated by
562 the corresponding endArray() and endMap() functions.
563
564 The following example encodes the equivalent of this JSON content:
565
566 \div{class="pre"}
567 {
568 "label": "journald",
569 "autoDetect": false,
570 "condition": "libs.journald",
571 "output": [ "privateFeature" ]
572 }
573 \enddiv
574
575 \snippet code/src_corelib_serialization_qcborstream.cpp 1
576
577 \section1 CBOR support
578
579 QCborStreamWriter supports all CBOR features required to create canonical
580 and strict streams. It implements almost all of the features specified in
581 \l {https://tools.ietf.org/html/rfc7049}{RFC 7049}.
582
583 The following table lists the CBOR features that QCborStreamWriter supports.
584
585 \table
586 \header \li Feature \li Support
587 \row \li Unsigned numbers \li Yes (full range)
588 \row \li Negative numbers \li Yes (full range)
589 \row \li Byte strings \li Yes
590 \row \li Text strings \li Yes
591 \row \li Chunked strings \li No
592 \row \li Tags \li Yes (arbitrary)
593 \row \li Booleans \li Yes
594 \row \li Null \li Yes
595 \row \li Undefined \li Yes
596 \row \li Arbitrary simple values \li Yes
597 \row \li Half-precision float (16-bit) \li Yes
598 \row \li Single-precision float (32-bit) \li Yes
599 \row \li Double-precision float (64-bit) \li Yes
600 \row \li Infinities and NaN floating point \li Yes
601 \row \li Determinate-length arrays and maps \li Yes
602 \row \li Indeterminate-length arrays and maps \li Yes
603 \row \li Map key types other than strings and integers \li Yes (arbitrary)
604 \endtable
605
606 \section2 Canonical CBOR encoding
607
608 Canonical CBOR encoding is defined by
609 \l{https://tools.ietf.org/html/rfc7049#section-3.9}{Section 3.9 of RFC
610 7049}. Canonical encoding is not a requirement for Qt's CBOR decoding
611 functionality, but it may be required for some protocols. In particular,
612 protocols that require the ability to reproduce the same stream identically
613 may require this.
614
615 In order to be considered "canonical", a CBOR stream must meet the
616 following requirements:
617
618 \list
619 \li Integers must be as small as possible. QCborStreamWriter always
620 does this (no user action is required and it is not possible
621 to write overlong integers).
622 \li Array, map and string lengths must be as short as possible. As
623 above, QCborStreamWriter automatically does this.
624 \li Arrays, maps and strings must use explicit length. QCborStreamWriter
625 always does this for strings; for arrays and maps, be sure to call
626 startArray() and startMap() overloads with explicit length.
627 \li Keys in every map must be sorted in ascending order. QCborStreamWriter
628 offers no help in this item: the developer must ensure that before
629 calling append() for the map pairs.
630 \li Floating point values should be as small as possible. QCborStreamWriter
631 will not convert floating point values; it is up to the developer
632 to perform this check prior to calling append() (see those functions'
633 examples).
634 \endlist
635
636 \section2 Strict CBOR mode
637
638 Strict mode is defined by
639 \l{https://tools.ietf.org/html/rfc7049#section-3.10}{Section 3.10 of RFC
640 7049}. As for Canonical encoding above, QCborStreamWriter makes it possible
641 to create strict CBOR streams, but does not require them or validate that
642 the output is so.
643
644 \list
645 \li Keys in a map must be unique. QCborStreamWriter performs no validation
646 of map keys.
647 \li Tags may be required to be paired only with the correct types,
648 according to their specification. QCborStreamWriter performs no
649 validation of tag usage.
650 \li Text Strings must be properly-encoded UTF-8. QCborStreamWriter always
651 writes proper UTF-8 for strings added with append(), but performs no
652 validation for strings added with appendTextString().
653 \endlist
654
655 \section2 Invalid CBOR stream
656
657 It is also possible to misuse QCborStreamWriter and produce invalid CBOR
658 streams that will fail to be decoded by a receiver. The following actions
659 will produce invalid streams:
660
661 \list
662 \li Append a tag and not append the corresponding tagged value
663 (QCborStreamWriter produces no diagnostic).
664 \li Append too many or too few items to an array or map with explicit
665 length (endMap() and endArray() will return false and
666 QCborStreamWriter will log with qWarning()).
667 \endlist
668
669 \sa QCborStreamReader, QCborValue, QXmlStreamWriter
670 */
671
672class QCborStreamWriterPrivate
673{
674public:
675 static Q_CONSTEXPR quint64 IndefiniteLength = (std::numeric_limits<quint64>::max)();
676
677 QIODevice *device;
678 CborEncoder encoder;
679 QStack<CborEncoder> containerStack;
680 bool deleteDevice = false;
681
682 QCborStreamWriterPrivate(QIODevice *device)
683 : device(device)
684 {
685 cbor_encoder_init_writer(&encoder, qt_cbor_encoder_write_callback, this);
686 }
687
688 ~QCborStreamWriterPrivate()
689 {
690 if (deleteDevice)
691 delete device;
692 }
693
694 template <typename... Args> void executeAppend(CborError (*f)(CborEncoder *, Args...), Args... args)
695 {
696 f(&encoder, std::forward<Args>(args)...);
697 }
698
699 void createContainer(CborError (*f)(CborEncoder *, CborEncoder *, size_t), quint64 len = IndefiniteLength)
700 {
701 Q_STATIC_ASSERT(size_t(IndefiniteLength) == CborIndefiniteLength);
702 if (sizeof(len) != sizeof(size_t) && len != IndefiniteLength) {
703 if (Q_UNLIKELY(len >= CborIndefiniteLength)) {
704 // TinyCBOR can't do this in 32-bit mode
705 qWarning("QCborStreamWriter: container of size %llu is too big for a 32-bit build; "
706 "will use indeterminate length instead", len);
707 len = CborIndefiniteLength;
708 }
709 }
710
711 containerStack.push(encoder);
712 f(&containerStack.top(), &encoder, len);
713 }
714
715 bool closeContainer()
716 {
717 if (containerStack.isEmpty()) {
718 qWarning("QCborStreamWriter: closing map or array that wasn't open");
719 return false;
720 }
721
722 CborEncoder container = containerStack.pop();
723 CborError err = cbor_encoder_close_container(&container, &encoder);
724 encoder = container;
725
726 if (Q_UNLIKELY(err)) {
727 if (err == CborErrorTooFewItems)
728 qWarning("QCborStreamWriter: not enough items added to array or map");
729 else if (err == CborErrorTooManyItems)
730 qWarning("QCborStreamWriter: too many items added to array or map");
731 return false;
732 }
733
734 return true;
735 }
736};
737
738static CborError qt_cbor_encoder_write_callback(void *self, const void *data, size_t len, CborEncoderAppendType)
739{
740 auto that = static_cast<QCborStreamWriterPrivate *>(self);
741 if (!that->device)
742 return CborNoError;
743 qint64 written = that->device->write(static_cast<const char *>(data), len);
744 return (written == qsizetype(len) ? CborNoError : CborErrorIO);
745}
746
747/*!
748 Creates a QCborStreamWriter object that will write the stream to \a device.
749 The device must be opened before the first append() call is made. This
750 constructor can be used with any class that derives from QIODevice, such as
751 QFile, QProcess or QTcpSocket.
752
753 QCborStreamWriter has no buffering, so every append() call will result in
754 one or more calls to the device's \l {QIODevice::}{write()} method.
755
756 The following example writes an empty map to a file:
757
758 \snippet code/src_corelib_serialization_qcborstream.cpp 2
759
760 QCborStreamWriter does not take ownership of \a device.
761
762 \sa device(), setDevice()
763 */
764QCborStreamWriter::QCborStreamWriter(QIODevice *device)
765 : d(new QCborStreamWriterPrivate(device))
766{
767}
768
769/*!
770 Creates a QCborStreamWriter object that will append the stream to \a data.
771 All streaming is done immediately to the byte array, without the need for
772 flushing any buffers.
773
774 The following example writes a number to a byte array then returns
775 it.
776
777 \snippet code/src_corelib_serialization_qcborstream.cpp 3
778
779 QCborStreamWriter does not take ownership of \a data.
780 */
781QCborStreamWriter::QCborStreamWriter(QByteArray *data)
782 : d(new QCborStreamWriterPrivate(new QBuffer(data)))
783{
784 d->deleteDevice = true;
785 d->device->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
786}
787
788/*!
789 Destroys this QCborStreamWriter object and frees any resources associated.
790
791 QCborStreamWriter does not perform error checking to see if all required
792 items were written to the stream prior to the object being destroyed. It is
793 the programmer's responsibility to ensure that it was done.
794 */
795QCborStreamWriter::~QCborStreamWriter()
796{
797}
798
799/*!
800 Replaces the device or byte array that this QCborStreamWriter object is
801 writing to with \a device.
802
803 \sa device()
804 */
805void QCborStreamWriter::setDevice(QIODevice *device)
806{
807 if (d->deleteDevice)
808 delete d->device;
809 d->device = device;
810 d->deleteDevice = false;
811}
812
813/*!
814 Returns the QIODevice that this QCborStreamWriter object is writing to. The
815 device must have previously been set with either the constructor or with
816 setDevice().
817
818 If this object was created by writing to a QByteArray, this function will
819 return an internal instance of QBuffer, which is owned by QCborStreamWriter.
820
821 \sa setDevice()
822 */
823QIODevice *QCborStreamWriter::device() const
824{
825 return d->device;
826}
827
828/*!
829 \overload
830
831 Appends the 64-bit unsigned value \a u to the CBOR stream, creating a CBOR
832 Unsigned Integer value. In the following example, we write the values 0,
833 2\sup{32} and \c UINT64_MAX:
834
835 \snippet code/src_corelib_serialization_qcborstream.cpp 4
836
837 \sa QCborStreamReader::isUnsignedInteger(), QCborStreamReader::toUnsignedInteger()
838 */
839void QCborStreamWriter::append(quint64 u)
840{
841 d->executeAppend(cbor_encode_uint, uint64_t(u));
842}
843
844/*!
845 \overload
846
847 Appends the 64-bit signed value \a i to the CBOR stream. This will create
848 either a CBOR Unsigned Integer or CBOR NegativeInteger value based on the
849 sign of the parameter. In the following example, we write the values 0, -1,
850 2\sup{32} and \c INT64_MAX:
851
852 \snippet code/src_corelib_serialization_qcborstream.cpp 5
853
854 \sa QCborStreamReader::isInteger(), QCborStreamReader::toInteger()
855 */
856void QCborStreamWriter::append(qint64 i)
857{
858 d->executeAppend(cbor_encode_int, int64_t(i));
859}
860
861/*!
862 \overload
863
864 Appends the 64-bit negative value \a n to the CBOR stream.
865 QCborNegativeInteger is a 64-bit enum that holds the absolute value of the
866 negative number we want to write. If n is zero, the value written will be
867 equivalent to 2\sup{64} (that is, -18,446,744,073,709,551,616).
868
869 In the following example, we write the values -1, -2\sup{32} and INT64_MIN:
870 \snippet code/src_corelib_serialization_qcborstream.cpp 6
871
872 Note how this function can be used to encode numbers that cannot fit a
873 standard computer's 64-bit signed integer like \l qint64. That is, if \a n
874 is larger than \c{std::numeric_limits<qint64>::max()} or is 0, this will
875 represent a negative number smaller than
876 \c{std::numeric_limits<qint64>::min()}.
877
878 \sa QCborStreamReader::isNegativeInteger(), QCborStreamReader::toNegativeInteger()
879 */
880void QCborStreamWriter::append(QCborNegativeInteger n)
881{
882 d->executeAppend(cbor_encode_negative_int, uint64_t(n));
883}
884
885/*!
886 \fn void QCborStreamWriter::append(const QByteArray &ba)
887 \overload
888
889 Appends the byte array \a ba to the stream, creating a CBOR Byte String
890 value. QCborStreamWriter will attempt to write the entire string in one
891 chunk.
892
893 The following example will load and append the contents of a file to the
894 stream:
895
896 \snippet code/src_corelib_serialization_qcborstream.cpp 7
897
898 As the example shows, unlike JSON, CBOR requires no escaping for binary
899 content.
900
901 \sa appendByteString(), QCborStreamReader::isByteArray(),
902 QCborStreamReader::readByteArray()
903 */
904
905/*!
906 \overload
907
908 Appends the text string \a str to the stream, creating a CBOR Text String
909 value. QCborStreamWriter will attempt to write the entire string in one
910 chunk.
911
912 The following example appends a simple string to the stream:
913
914 \snippet code/src_corelib_serialization_qcborstream.cpp 8
915
916 \b{Performance note}: CBOR requires that all Text Strings be encoded in
917 UTF-8, so this function will iterate over the characters in the string to
918 determine whether the contents are US-ASCII or not. If the string is found
919 to contain characters outside of US-ASCII, it will allocate memory and
920 convert to UTF-8. If this check is unnecessary, use appendTextString()
921 instead.
922
923 \sa QCborStreamReader::isString(), QCborStreamReader::readString()
924 */
925void QCborStreamWriter::append(QLatin1String str)
926{
927 // We've got Latin-1 but CBOR wants UTF-8, so check if the string is the
928 // common subset (US-ASCII).
929 if (QtPrivate::isAscii(str)) {
930 // it is plain US-ASCII
931 appendTextString(str.latin1(), str.size());
932 } else {
933 // non-ASCII, so we need a pass-through UTF-16
934 append(QString(str));
935 }
936}
937
938/*!
939 \overload
940
941 Appends the text string \a str to the stream, creating a CBOR Text String
942 value. QCborStreamWriter will attempt to write the entire string in one
943 chunk.
944
945 The following example writes an arbitrary QString to the stream:
946
947 \snippet code/src_corelib_serialization_qcborstream.cpp 9
948
949 \sa QCborStreamReader::isString(), QCborStreamReader::readString()
950 */
951void QCborStreamWriter::append(QStringView str)
952{
953 QByteArray utf8 = str.toUtf8();
954 appendTextString(utf8.constData(), utf8.size());
955}
956
957/*!
958 \overload
959
960 Appends the CBOR tag \a tag to the stream, creating a CBOR Tag value. All
961 tags must be followed by another type which they provide meaning for.
962
963 In the following example, we append a CBOR Tag 36 (Regular Expression) and a
964 QRegularExpression's pattern to the stream:
965
966 \snippet code/src_corelib_serialization_qcborstream.cpp 10
967
968 \sa QCborStreamReader::isTag(), QCborStreamReader::toTag()
969 */
970void QCborStreamWriter::append(QCborTag tag)
971{
972 d->executeAppend(cbor_encode_tag, CborTag(tag));
973}
974
975/*!
976 \fn void QCborStreamWriter::append(QCborKnownTags tag)
977 \overload
978
979 Appends the CBOR tag \a tag to the stream, creating a CBOR Tag value. All
980 tags must be followed by another type which they provide meaning for.
981
982 In the following example, we append a CBOR Tag 1 (Unix \c time_t) and an
983 integer representing the current time to the stream, obtained using the \c
984 time() function:
985
986 \snippet code/src_corelib_serialization_qcborstream.cpp 11
987
988 \sa QCborStreamReader::isTag(), QCborStreamReader::toTag()
989 */
990
991/*!
992 \overload
993
994 Appends the CBOR simple type \a st to the stream, creating a CBOR Simple
995 Type value. In the following example, we write the simple type for Null as
996 well as for type 32, which Qt has no support for.
997
998 \snippet code/src_corelib_serialization_qcborstream.cpp 12
999
1000 \note Using Simple Types for which there is no specification can lead to
1001 validation errors by the remote receiver. In addition, simple type values 24
1002 through 31 (inclusive) are reserved and must not be used.
1003
1004 \sa QCborStreamReader::isSimpleType(), QCborStreamReader::toSimpleType()
1005 */
1006void QCborStreamWriter::append(QCborSimpleType st)
1007{
1008 d->executeAppend(cbor_encode_simple_value, uint8_t(st));
1009}
1010
1011/*!
1012 \overload
1013
1014 Appends the floating point number \a f to the stream, creating a CBOR 16-bit
1015 Half-Precision Floating Point value. The following code can be used to convert
1016 a C++ \tt float to \c qfloat16 if there's no loss of precision and append it, or
1017 instead append the \tt float.
1018
1019 \snippet code/src_corelib_serialization_qcborstream.cpp 13
1020
1021 \sa QCborStreamReader::isFloat16(), QCborStreamReader::toFloat16()
1022 */
1023void QCborStreamWriter::append(qfloat16 f)
1024{
1025 d->executeAppend(cbor_encode_half_float, static_cast<const void *>(&f));
1026}
1027
1028/*!
1029 \overload
1030
1031 Appends the floating point number \a f to the stream, creating a CBOR 32-bit
1032 Single-Precision Floating Point value. The following code can be used to convert
1033 a C++ \tt double to \tt float if there's no loss of precision and append it, or
1034 instead append the \tt double.
1035
1036 \snippet code/src_corelib_serialization_qcborstream.cpp 14
1037
1038 \sa QCborStreamReader::isFloat(), QCborStreamReader::toFloat()
1039 */
1040void QCborStreamWriter::append(float f)
1041{
1042 d->executeAppend(cbor_encode_float, f);
1043}
1044
1045/*!
1046 \overload
1047
1048 Appends the floating point number \a d to the stream, creating a CBOR 64-bit
1049 Double-Precision Floating Point value. QCborStreamWriter always appends the
1050 number as-is, performing no check for whether the number is the canonical
1051 form for NaN, an infinite, whether it is denormal or if it could be written
1052 with a shorter format.
1053
1054 The following code performs all those checks, except for the denormal one,
1055 which is expected to be taken into account by the system FPU or floating
1056 point emulation directly.
1057
1058 \snippet code/src_corelib_serialization_qcborstream.cpp 15
1059
1060 Determining if a double can be converted to an integral with no loss of
1061 precision is left as an exercise to the reader.
1062
1063 \sa QCborStreamReader::isDouble(), QCborStreamReader::toDouble()
1064 */
1065void QCborStreamWriter::append(double d)
1066{
1067 this->d->executeAppend(cbor_encode_double, d);
1068}
1069
1070/*!
1071 Appends \a len bytes of data starting from \a data to the stream, creating a
1072 CBOR Byte String value. QCborStreamWriter will attempt to write the entire
1073 string in one chunk.
1074
1075 Unlike the QByteArray overload of append(), this function is not limited by
1076 QByteArray's size limits. However, note that neither
1077 QCborStreamReader::readByteArray() nor QCborValue support reading CBOR
1078 streams with byte arrays larger than 2 GB.
1079
1080 \sa append(), appendTextString(),
1081 QCborStreamReader::isByteArray(), QCborStreamReader::readByteArray()
1082 */
1083void QCborStreamWriter::appendByteString(const char *data, qsizetype len)
1084{
1085 d->executeAppend(cbor_encode_byte_string, reinterpret_cast<const uint8_t *>(data), size_t(len));
1086}
1087
1088/*!
1089 Appends \a len bytes of text starting from \a utf8 to the stream, creating a
1090 CBOR Text String value. QCborStreamWriter will attempt to write the entire
1091 string in one chunk.
1092
1093 The string pointed to by \a utf8 is expected to be properly encoded UTF-8.
1094 QCborStreamWriter performs no validation that this is the case.
1095
1096 Unlike the QLatin1String overload of append(), this function is not limited
1097 to 2 GB. However, note that neither QCborStreamReader::readString() nor
1098 QCborValue support reading CBOR streams with text strings larger than 2 GB.
1099
1100 \sa append(QLatin1String), append(QStringView),
1101 QCborStreamReader::isString(), QCborStreamReader::readString()
1102 */
1103void QCborStreamWriter::appendTextString(const char *utf8, qsizetype len)
1104{
1105 d->executeAppend(cbor_encode_text_string, utf8, size_t(len));
1106}
1107
1108/*!
1109 \fn void QCborStreamWriter::append(const char *str, qsizetype size)
1110 \overload
1111
1112 Appends \a size bytes of text starting from \a str to the stream, creating a
1113 CBOR Text String value. QCborStreamWriter will attempt to write the entire
1114 string in one chunk. If \a size is -1, this function will write \c strlen(\a
1115 str) bytes.
1116
1117 The string pointed to by \a str is expected to be properly encoded UTF-8.
1118 QCborStreamWriter performs no validation that this is the case.
1119
1120 Unlike the QLatin1String overload of append(), this function is not limited
1121 to 2 GB. However, note that neither QCborStreamReader nor QCborValue support
1122 reading CBOR streams with text strings larger than 2 GB.
1123
1124 \sa append(QLatin1String), append(QStringView),
1125 QCborStreamReader::isString(), QCborStreamReader::readString()
1126 */
1127
1128/*!
1129 \fn void QCborStreamWriter::append(bool b)
1130 \overload
1131
1132 Appends the boolean value \a b to the stream, creating either a CBOR False
1133 value or a CBOR True value. This function is equivalent to (and implemented
1134 as):
1135
1136 \snippet code/src_corelib_serialization_qcborstream.cpp 16
1137
1138 \sa appendNull(), appendUndefined(),
1139 QCborStreamReader::isBool(), QCborStreamReader::toBool()
1140 */
1141
1142/*!
1143 \fn void QCborStreamWriter::append(std::nullptr_t)
1144 \overload
1145
1146 Appends a CBOR Null value to the stream. This function is equivalent to (and
1147 implemented as): The parameter is ignored.
1148
1149 \snippet code/src_corelib_serialization_qcborstream.cpp 17
1150
1151 \sa appendNull(), append(QCborSimpleType), QCborStreamReader::isNull()
1152 */
1153
1154/*!
1155 \fn void QCborStreamWriter::appendNull()
1156
1157 Appends a CBOR Null value to the stream. This function is equivalent to (and
1158 implemented as):
1159
1160 \snippet code/src_corelib_serialization_qcborstream.cpp 18
1161
1162 \sa append(std::nullptr_t), append(QCborSimpleType), QCborStreamReader::isNull()
1163 */
1164
1165/*!
1166 \fn void QCborStreamWriter::appendUndefined()
1167
1168 Appends a CBOR Undefined value to the stream. This function is equivalent to (and
1169 implemented as):
1170
1171 \snippet code/src_corelib_serialization_qcborstream.cpp 19
1172
1173 \sa append(QCborSimpleType), QCborStreamReader::isUndefined()
1174 */
1175
1176/*!
1177 Starts a CBOR Array with indeterminate length in the CBOR stream. Each
1178 startArray() call must be paired with one endArray() call and the current
1179 CBOR element extends until the end of the array.
1180
1181 The array created by this function has no explicit length. Instead, its
1182 length is implied by the elements contained in it. Note, however, that use
1183 of indeterminate-length arrays is not compliant with canonical CBOR encoding.
1184
1185 The following example appends elements from the linked list of strings
1186 passed as input:
1187
1188 \snippet code/src_corelib_serialization_qcborstream.cpp 20
1189
1190 \sa startArray(quint64), endArray(), startMap(), QCborStreamReader::isArray(),
1191 QCborStreamReader::isLengthKnown()
1192 */
1193void QCborStreamWriter::startArray()
1194{
1195 d->createContainer(cbor_encoder_create_array);
1196}
1197
1198/*!
1199 \overload
1200
1201 Starts a CBOR Array with explicit length of \a count items in the CBOR
1202 stream. Each startArray call must be paired with one endArray() call and the
1203 current CBOR element extends until the end of the array.
1204
1205 The array created by this function has an explicit length and therefore
1206 exactly \a count items must be added to the CBOR stream. Adding fewer or
1207 more items will result in failure during endArray() and the CBOR stream will
1208 be corrupt. However, explicit-length arrays are required by canonical CBOR
1209 encoding.
1210
1211 The following example appends all strings found in the \l QStringList passed as input:
1212
1213 \snippet code/src_corelib_serialization_qcborstream.cpp 21
1214
1215 \b{Size limitations}: The parameter to this function is quint64, which would
1216 seem to allow up to 2\sup{64}-1 elements in the array. However, both
1217 QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{32}-2
1218 items on 32-bit systems and 2\sup{64}-2 items on 64-bit ones. Also note that
1219 QCborArray is currently limited to 2\sup{27} elements in any platform.
1220
1221 \sa startArray(), endArray(), startMap(), QCborStreamReader::isArray(),
1222 QCborStreamReader::isLengthKnown()
1223 */
1224void QCborStreamWriter::startArray(quint64 count)
1225{
1226 d->createContainer(cbor_encoder_create_array, count);
1227}
1228
1229/*!
1230 Terminates the array started by either overload of startArray() and returns
1231 true if the correct number of elements was added to the array. This function
1232 must be called for every startArray() used.
1233
1234 A return of false indicates error in the application and an unrecoverable
1235 error in this stream. QCborStreamWriter also writes a warning using
1236 qWarning() if that happens.
1237
1238 Calling this function when the current container is not an array is also an
1239 error, though QCborStreamWriter cannot currently detect this condition.
1240
1241 \sa startArray(), startArray(quint64), endMap()
1242 */
1243bool QCborStreamWriter::endArray()
1244{
1245 return d->closeContainer();
1246}
1247
1248/*!
1249 Starts a CBOR Map with indeterminate length in the CBOR stream. Each
1250 startMap() call must be paired with one endMap() call and the current CBOR
1251 element extends until the end of the map.
1252
1253 The map created by this function has no explicit length. Instead, its length
1254 is implied by the elements contained in it. Note, however, that use of
1255 indeterminate-length maps is not compliant with canonical CBOR encoding
1256 (canonical encoding also requires keys to be unique and in sorted order).
1257
1258 The following example appends elements from the linked list of int and
1259 string pairs passed as input:
1260
1261 \snippet code/src_corelib_serialization_qcborstream.cpp 22
1262
1263 \sa startMap(quint64), endMap(), startArray(), QCborStreamReader::isMap(),
1264 QCborStreamReader::isLengthKnown()
1265 */
1266void QCborStreamWriter::startMap()
1267{
1268 d->createContainer(cbor_encoder_create_map);
1269}
1270
1271/*!
1272 \overload
1273
1274 Starts a CBOR Map with explicit length of \a count items in the CBOR
1275 stream. Each startMap call must be paired with one endMap() call and the
1276 current CBOR element extends until the end of the map.
1277
1278 The map created by this function has an explicit length and therefore
1279 exactly \a count pairs of items must be added to the CBOR stream. Adding
1280 fewer or more items will result in failure during endMap() and the CBOR
1281 stream will be corrupt. However, explicit-length map are required by
1282 canonical CBOR encoding.
1283
1284 The following example appends all strings found in the \l QMap passed as input:
1285
1286 \snippet code/src_corelib_serialization_qcborstream.cpp 23
1287
1288 \b{Size limitations}: The parameter to this function is quint64, which would
1289 seem to allow up to 2\sup{64}-1 pairs in the map. However, both
1290 QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{31}-1
1291 items on 32-bit systems and 2\sup{63}-1 items on 64-bit ones. Also note that
1292 QCborMap is currently limited to 2\sup{26} elements in any platform.
1293
1294 \sa startMap(), endMap(), startArray(), QCborStreamReader::isMap(),
1295 QCborStreamReader::isLengthKnown()
1296 */
1297void QCborStreamWriter::startMap(quint64 count)
1298{
1299 d->createContainer(cbor_encoder_create_map, count);
1300}
1301
1302/*!
1303 Terminates the map started by either overload of startMap() and returns
1304 true if the correct number of elements was added to the array. This function
1305 must be called for every startMap() used.
1306
1307 A return of false indicates error in the application and an unrecoverable
1308 error in this stream. QCborStreamWriter also writes a warning using
1309 qWarning() if that happens.
1310
1311 Calling this function when the current container is not a map is also an
1312 error, though QCborStreamWriter cannot currently detect this condition.
1313
1314 \sa startMap(), startMap(quint64), endArray()
1315 */
1316bool QCborStreamWriter::endMap()
1317{
1318 return d->closeContainer();
1319}
1320
1321/*!
1322 \class QCborStreamReader
1323 \inmodule QtCore
1324 \ingroup cbor
1325 \reentrant
1326 \since 5.12
1327
1328 \brief The QCborStreamReader class is a simple CBOR stream decoder, operating
1329 on either a QByteArray or QIODevice.
1330
1331 This class can be used to decode a stream of CBOR content directly from
1332 either a QByteArray or a QIODevice. CBOR is the Concise Binary Object
1333 Representation, a very compact form of binary data encoding that is
1334 compatible with JSON. It was created by the IETF Constrained RESTful
1335 Environments (CoRE) WG, which has used it in many new RFCs. It is meant to
1336 be used alongside the \l{https://tools.ietf.org/html/rfc7252}{CoAP
1337 protocol}.
1338
1339 QCborStreamReader provides a StAX-like API, similar to that of
1340 \l{QXmlStreamReader}. Using it requires a bit of knowledge of CBOR encoding.
1341 For a simpler API, see \l{QCborValue} and especially the decoding function
1342 QCborValue::fromCbor().
1343
1344 Typically, one creates a QCborStreamReader by passing the source QByteArray
1345 or QIODevice as a parameter to the constructor, then pop elements off the
1346 stream if there were no errors in decoding. There are three kinds of CBOR
1347 types:
1348
1349 \table
1350 \header \li Kind \li Types \li Behavior
1351 \row \li Fixed-width \li Integers, Tags, Simple types, Floating point
1352 \li Value is pre-parsed by QCborStreamReader, so accessor functions
1353 are \c const. Must call next() to advance.
1354 \row \li Strings \li Byte arrays, Text strings
1355 \li Length (if known) is pre-parsed, but the string itself is not.
1356 The accessor functions are not const and may allocate memory.
1357 Once called, the accessor functions automatically advance to
1358 the next element.
1359 \row \li Containers \li Arrays, Maps
1360 \li Length (if known) is pre-parsed. To access the elements, you
1361 must call enterContainer(), read all elements, then call
1362 leaveContainer(). That function advances to the next element.
1363 \endtable
1364
1365 So a processor function typically looks like this:
1366
1367 \snippet code/src_corelib_serialization_qcborstream.cpp 24
1368
1369 \section1 CBOR support
1370
1371 The following table lists the CBOR features that QCborStreamReader supports.
1372
1373 \table
1374 \header \li Feature \li Support
1375 \row \li Unsigned numbers \li Yes (full range)
1376 \row \li Negative numbers \li Yes (full range)
1377 \row \li Byte strings \li Yes
1378 \row \li Text strings \li Yes
1379 \row \li Chunked strings \li Yes
1380 \row \li Tags \li Yes (arbitrary)
1381 \row \li Booleans \li Yes
1382 \row \li Null \li Yes
1383 \row \li Undefined \li Yes
1384 \row \li Arbitrary simple values \li Yes
1385 \row \li Half-precision float (16-bit) \li Yes
1386 \row \li Single-precision float (32-bit) \li Yes
1387 \row \li Double-precision float (64-bit) \li Yes
1388 \row \li Infinities and NaN floating point \li Yes
1389 \row \li Determinate-length arrays and maps \li Yes
1390 \row \li Indeterminate-length arrays and maps \li Yes
1391 \row \li Map key types other than strings and integers \li Yes (arbitrary)
1392 \endtable
1393
1394 \section1 Dealing with invalid or incomplete CBOR streams
1395
1396 QCborStreamReader is capable of detecting corrupt input on its own. The
1397 library it uses has been extensively tested against invalid input of any
1398 kind and is quite able to report errors. If any is detected,
1399 QCborStreamReader will set lastError() to a value besides
1400 QCborError::NoError, indicating which situation was detected.
1401
1402 Most errors detected by QCborStreamReader during normal item parsing are not
1403 recoverable. The code using QCborStreamReader may opt to handle the data
1404 that was properly decoded or it can opt to discard the entire data.
1405
1406 The only recoverable error is QCborError::EndOfFile, which indicates that
1407 more data is required in order to complete the parsing. This situation is
1408 useful when data is being read from an asynchronous source, such as a pipe
1409 (QProcess) or a socket (QTcpSocket, QUdpSocket, QNetworkReply, etc.). When
1410 more data arrives, the surrounding code needs to call either addData(), if
1411 parsing from a QByteArray, or reparse(), if it is instead reading directly
1412 a the QIDOevice that now has more data available (see setDevice()).
1413
1414 \sa QCborStreamWriter, QCborValue, QXmlStreamReader
1415 */
1416
1417/*!
1418 \enum QCborStreamReader::Type
1419
1420 This enumeration contains all possible CBOR types as decoded by
1421 QCborStreamReader. CBOR has 7 major types, plus a number of simple types
1422 carrying no value, and floating point values.
1423
1424 \value UnsignedInteger (Major type 0) Ranges from 0 to 2\sup{64} - 1
1425 (18,446,744,073,709,551,616)
1426 \value NegativeInteger (Major type 1) Ranges from -1 to -2\sup{64}
1427 (-18,446,744,073,709,551,616)
1428 \value ByteArray (Major type 2) Arbitrary binary data.
1429 \value ByteString An alias to ByteArray.
1430 \value String (Major type 3) Unicode text, possibly containing NULs.
1431 \value TextString An alias to String
1432 \value Array (Major type 4) Array of heterogeneous items.
1433 \value Map (Major type 5) Map/dictionary of heterogeneous items.
1434 \value Tag (Major type 6) Numbers giving further semantic value
1435 to generic CBOR items. See \l QCborTag for more information.
1436 \value SimpleType (Major type 7) Types carrying no further value. Includes
1437 booleans (true and false), null, undefined.
1438 \value Float16 IEEE 754 half-precision floating point (\c qfloat16).
1439 \value HalfFloat An alias to Float16.
1440 \value Float IEEE 754 single-precision floating point (\tt float).
1441 \value Double IEEE 754 double-precision floating point (\tt double).
1442 \value Invalid Not a valid type, either due to parsing error or due to
1443 reaching the end of an array or map.
1444 */
1445
1446/*!
1447 \enum QCborStreamReader::StringResultCode
1448
1449 This enum is returned by readString() and readByteArray() and is used to
1450 indicate what the status of the parsing is.
1451
1452 \value EndOfString The parsing for the string is complete, with no error.
1453 \value Ok The function returned data; there was no error.
1454 \value Error Parsing failed with an error.
1455 */
1456
1457/*!
1458 \class QCborStreamReader::StringResult
1459 \inmodule QtCore
1460
1461 This class is returned by readString() and readByteArray(), with either the
1462 contents of the string that was read or an indication that the parsing is
1463 done or found an error.
1464
1465 The contents of \l data are valid only if \l status is
1466 \l{StringResultCode}{Ok}. Otherwise, it should be null.
1467 */
1468
1469/*!
1470 \variable QCborStreamReader::StringResult::data
1471
1472 Contains the actual data from the string if \l status is \c Ok.
1473 */
1474
1475/*!
1476 \variable QCborStreamReader::StringResult::status
1477
1478 Contains the status of the attempt of reading the string from the stream.
1479 */
1480
1481/*!
1482 \fn QCborStreamReader::Type QCborStreamReader::type() const
1483
1484 Returns the type of the current element. It is one of the valid types or
1485 Invalid.
1486
1487 \sa isValid(), isUnsignedInteger(), isNegativeInteger(), isInteger(),
1488 isByteArray(), isString(), isArray(), isMap(), isTag(), isSimpleType(),
1489 isBool(), isFalse(), isTrue(), isNull(), isUndefined(), isFloat16(),
1490 isFloat(), isDouble()
1491 */
1492
1493/*!
1494 \fn bool QCborStreamReader::isValid() const
1495
1496 Returns true if the current element is valid, false otherwise. The current
1497 element may be invalid if there was a decoding error or we've just parsed
1498 the last element in an array or map.
1499
1500 \note This function is not the opposite of isNull(). Null is a normal CBOR
1501 type that must be handled by the application.
1502
1503 \sa type(), isInvalid()
1504 */
1505
1506/*!
1507 \fn bool QCborStreamReader::isInvalid() const
1508
1509 Returns true if the current element is invalid, false otherwise. The current
1510 element may be invalid if there was a decoding error or we've just parsed
1511 the last element in an array or map.
1512
1513 \note This function is not to be confused with isNull(). Null is a normal
1514 CBOR type that must be handled by the application.
1515
1516 \sa type(), isValid()
1517 */
1518
1519/*!
1520 \fn bool QCborStreamReader::isUnsignedInteger() const
1521
1522 Returns true if the type of the current element is an unsigned integer (that
1523 is if type() returns QCborStreamReader::UnsignedInteger). If this function
1524 returns true, you may call toUnsignedInteger() or toInteger() to read that value.
1525
1526 \sa type(), toUnsignedInteger(), toInteger(), isInteger(), isNegativeInteger()
1527 */
1528
1529/*!
1530 \fn bool QCborStreamReader::isNegativeInteger() const
1531
1532 Returns true if the type of the current element is a negative integer (that
1533 is if type() returns QCborStreamReader::NegativeInteger). If this function
1534 returns true, you may call toNegativeInteger() or toInteger() to read that value.
1535
1536 \sa type(), toNegativeInteger(), toInteger(), isInteger(), isUnsignedInteger()
1537 */
1538
1539/*!
1540 \fn bool QCborStreamReader::isInteger() const
1541
1542 Returns true if the type of the current element is either an unsigned
1543 integer or a negative one (that is, if type() returns
1544 QCborStreamReader::UnsignedInteger or QCborStreamReader::NegativeInteger).
1545 If this function returns true, you may call toInteger() to read that
1546 value.
1547
1548 \sa type(), toInteger(), toUnsignedInteger(), toNegativeInteger(),
1549 isUnsignedInteger(), isNegativeInteger()
1550 */
1551
1552/*!
1553 \fn bool QCborStreamReader::isByteArray() const
1554
1555 Returns true if the type of the current element is a byte array (that is,
1556 if type() returns QCborStreamReader::ByteArray). If this function returns
1557 true, you may call readByteArray() to read that data.
1558
1559 \sa type(), readByteArray(), isString()
1560 */
1561
1562/*!
1563 \fn bool QCborStreamReader::isString() const
1564
1565 Returns true if the type of the current element is a text string (that is,
1566 if type() returns QCborStreamReader::String). If this function returns
1567 true, you may call readString() to read that data.
1568
1569 \sa type(), readString(), isByteArray()
1570 */
1571
1572/*!
1573 \fn bool QCborStreamReader::isArray() const
1574
1575 Returns true if the type of the current element is an array (that is,
1576 if type() returns QCborStreamReader::Array). If this function returns
1577 true, you may call enterContainer() to begin parsing that container.
1578
1579 When the current element is an array, you may also call isLengthKnown() to
1580 find out if the array's size is explicit in the CBOR stream. If it is, that
1581 size can be obtained by calling length().
1582
1583 The following example pre-allocates a QVariantList given the array's size
1584 for more efficient decoding:
1585
1586 \snippet code/src_corelib_serialization_qcborstream.cpp 25
1587
1588 \note The code above does not validate that the length is a sensible value.
1589 If the input stream reports that the length is 1 billion elements, the above
1590 function will try to allocate some 16 GB or more of RAM, which can lead to a
1591 crash.
1592
1593 \sa type(), isMap(), isLengthKnown(), length(), enterContainer(), leaveContainer()
1594 */
1595
1596/*!
1597 \fn bool QCborStreamReader::isMap() const
1598
1599 Returns true if the type of the current element is a map (that is, if type()
1600 returns QCborStreamReader::Map). If this function returns true, you may call
1601 enterContainer() to begin parsing that container.
1602
1603 When the current element is a map, you may also call isLengthKnown() to
1604 find out if the map's size is explicit in the CBOR stream. If it is, that
1605 size can be obtained by calling length().
1606
1607 The following example pre-allocates a QVariantMap given the map's size
1608 for more efficient decoding:
1609
1610 \snippet code/src_corelib_serialization_qcborstream.cpp 26
1611
1612 The example above uses a function called \c readElementAsString to read the
1613 map's keys and obtain a string. That is because CBOR maps may contain any
1614 type as keys, not just strings. User code needs to either perform this
1615 conversion, reject non-string keys, or instead use a different container
1616 besides \l QVariantMap and \l QVariantHash. For example, if the map is
1617 expected to contain integer keys, which is recommended as it reduces stream
1618 size and parsing, the correct container would be \c{\l{QMap}<int, QVariant>}
1619 or \c{\l{QHash}<int, QVariant>}.
1620
1621 \note The code above does not validate that the length is a sensible value.
1622 If the input stream reports that the length is 1 billion elements, the above
1623 function will try to allocate some 24 GB or more of RAM, which can lead to a
1624 crash.
1625
1626 \sa type(), isArray(), isLengthKnown(), length(), enterContainer(), leaveContainer()
1627 */
1628
1629/*!
1630 \fn bool QCborStreamReader::isTag() const
1631
1632 Returns true if the type of the current element is a CBOR tag (that is,
1633 if type() returns QCborStreamReader::Tag). If this function returns
1634 true, you may call toTag() to read that data.
1635
1636 \sa type(), toTag()
1637 */
1638
1639/*!
1640 \fn bool QCborStreamReader::isFloat16() const
1641
1642 Returns true if the type of the current element is an IEEE 754
1643 half-precision floating point (that is, if type() returns
1644 QCborStreamReader::Float16). If this function returns true, you may call
1645 toFloat16() to read that data.
1646
1647 \sa type(), toFloat16(), isFloat(), isDouble()
1648 */
1649
1650/*!
1651 \fn bool QCborStreamReader::isFloat() const
1652
1653 Returns true if the type of the current element is an IEEE 754
1654 single-precision floating point (that is, if type() returns
1655 QCborStreamReader::Float). If this function returns true, you may call
1656 toFloat() to read that data.
1657
1658 \sa type(), toFloat(), isFloat16(), isDouble()
1659 */
1660
1661/*!
1662 \fn bool QCborStreamReader::isDouble() const
1663
1664 Returns true if the type of the current element is an IEEE 754
1665 double-precision floating point (that is, if type() returns
1666 QCborStreamReader::Double). If this function returns true, you may call
1667 toDouble() to read that data.
1668
1669 \sa type(), toDouble(), isFloat16(), isFloat()
1670 */
1671
1672/*!
1673 \fn bool QCborStreamReader::isSimpleType() const
1674
1675 Returns true if the type of the current element is any CBOR simple type,
1676 including a boolean value (true and false) as well as null and undefined. To
1677 find out which simple type this is, call toSimpleType(). Alternatively, to
1678 test for one specific simple type, call the overload that takes a
1679 QCborSimpleType parameter.
1680
1681 CBOR simple types are types that do not carry extra value. There are 255
1682 possibilities, but there are currently only four values that have defined
1683 meaning. Code is not expected to cope with unknown simple types and may
1684 simply discard the stream as invalid if it finds an unknown one.
1685
1686 \sa QCborSimpleType, type(), isSimpleType(QCborSimpleType), toSimpleType()
1687 */
1688
1689/*!
1690 \fn bool QCborStreamReader::isSimpleType(QCborSimpleType st) const
1691
1692 Returns true if the type of the current element is the simple type \a st,
1693 false otherwise. If this function returns true, then toSimpleType() will
1694 return \a st.
1695
1696 CBOR simple types are types that do not carry extra value. There are 255
1697 possibilities, but there are currently only four values that have defined
1698 meaning. Code is not expected to cope with unknown simple types and may
1699 simply discard the stream as invalid if it finds an unknown one.
1700
1701 \sa QCborSimpleType, type(), isSimpleType(), toSimpleType()
1702 */
1703
1704/*!
1705 \fn bool QCborStreamReader::isFalse() const
1706
1707 Returns true if the current element is the \c false value, false if it is
1708 anything else.
1709
1710 \sa type(), isTrue(), isBool(), toBool(), isSimpleType(), toSimpleType()
1711 */
1712
1713/*!
1714 \fn bool QCborStreamReader::isTrue() const
1715
1716 Returns true if the current element is the \c true value, false if it is
1717 anything else.
1718
1719 \sa type(), isFalse(), isBool(), toBool(), isSimpleType(), toSimpleType()
1720 */
1721
1722/*!
1723 \fn bool QCborStreamReader::isBool() const
1724
1725 Returns true if the current element is a boolean value (\c true or \c
1726 false), false if it is anything else. If this function returns true, you may
1727 call toBool() to retrieve the value of the boolean. You may also call
1728 toSimpleType() and compare to either QCborSimpleValue::True or
1729 QCborSimpleValue::False.
1730
1731 \sa type(), isFalse(), isTrue(), toBool(), isSimpleType(), toSimpleType()
1732 */
1733
1734/*!
1735 \fn bool QCborStreamReader::isNull() const
1736
1737 Returns true if the current element is the \c null value, false if it is
1738 anything else. Null values may be used to indicate the absence of some
1739 optional data.
1740
1741 \note This function is not the opposite of isValid(). A Null value is a
1742 valid CBOR value.
1743
1744 \sa type(), isSimpleType(), toSimpleType()
1745 */
1746
1747/*!
1748 \fn bool QCborStreamReader::isUndefined() const
1749
1750 Returns true if the current element is the \c undefined value, false if it
1751 is anything else. Undefined values may be encoded to indicate that some
1752 conversion failed or was not possible when creating the stream.
1753 QCborStreamReader never performs any replacement and this function will only
1754 return true if the stream contains an explicit undefined value.
1755
1756 \sa type(), isSimpleType(), toSimpleType()
1757 */
1758
1759/*!
1760 \fn bool QCborStreamReader::isContainer() const
1761
1762 Returns true if the current element is a container (that is, an array or a
1763 map), false if it is anything else. If the current element is a container,
1764 the isLengthKnown() function may be used to find out if the container's size
1765 is explicit in the stream and, if so, length() can be used to get that size.
1766
1767 More importantly, for a container, the enterContainer() function is
1768 available to begin iterating through the elements contained therein.
1769
1770 \sa type(), isArray(), isMap(), isLengthKnown(), length(), enterContainer(),
1771 leaveContainer(), containerDepth()
1772 */
1773
1774class QCborStreamReaderPrivate
1775{
1776public:
1777 enum {
1778 // 9 bytes is the maximum size for any integer, floating point or
1779 // length in CBOR.
1780 MaxCborIndividualSize = 9,
1781 IdealIoBufferSize = 256
1782 };
1783
1784 QIODevice *device;
1785 QByteArray buffer;
1786 QStack<CborValue> containerStack;
1787
1788 CborParser parser;
1789 CborValue currentElement;
1790 QCborError lastError = {};
1791
1792 QByteArray::size_type bufferStart;
1793 bool corrupt = false;
1794
1795 QCborStreamReaderPrivate(const QByteArray &data)
1796 : device(nullptr), buffer(data)
1797 {
1798 initDecoder();
1799 }
1800
1801 QCborStreamReaderPrivate(QIODevice *device)
1802 {
1803 setDevice(device);
1804 }
1805
1806 ~QCborStreamReaderPrivate()
1807 {
1808 }
1809
1810 void setDevice(QIODevice *dev)
1811 {
1812 buffer.clear();
1813 device = dev;
1814 initDecoder();
1815 }
1816
1817 void initDecoder()
1818 {
1819 containerStack.clear();
1820 bufferStart = 0;
1821 if (device) {
1822 buffer.clear();
1823 buffer.reserve(IdealIoBufferSize); // sets the CapacityReserved flag
1824 }
1825
1826 preread();
1827 if (CborError err = cbor_parser_init_reader(nullptr, &parser, &currentElement, this))
1828 handleError(err);
1829 else
1830 lastError = { QCborError::NoError };
1831 }
1832
1833 char *bufferPtr()
1834 {
1835 Q_ASSERT(buffer.isDetached());
1836 return const_cast<char *>(buffer.constData()) + bufferStart;
1837 }
1838
1839 void preread()
1840 {
1841 if (device && buffer.size() - bufferStart < MaxCborIndividualSize) {
1842 // load more, but only if there's more to be read
1843 qint64 avail = device->bytesAvailable();
1844 Q_ASSERT(avail >= buffer.size());
1845 if (avail == buffer.size())
1846 return;
1847
1848 if (bufferStart)
1849 device->skip(bufferStart); // skip what we've already parsed
1850
1851 if (buffer.size() != IdealIoBufferSize)
1852 buffer.resize(IdealIoBufferSize);
1853
1854 bufferStart = 0;
1855 qint64 read = device->peek(bufferPtr(), IdealIoBufferSize);
1856 if (read < 0)
1857 buffer.clear();
1858 else if (read != IdealIoBufferSize)
1859 buffer.truncate(read);
1860 }
1861 }
1862
1863 void handleError(CborError err) noexcept
1864 {
1865 Q_ASSERT(err);
1866
1867 // is the error fatal?
1868 if (err != CborErrorUnexpectedEOF)
1869 corrupt = true;
1870
1871 lastError = fromCborError(err);
1872 }
1873
1874 void updateBufferAfterString(qsizetype offset, qsizetype size)
1875 {
1876 Q_ASSERT(device);
1877
1878 bufferStart += offset;
1879 qsizetype newStart = bufferStart + size;
1880 qsizetype remainingInBuffer = buffer.size() - newStart;
1881
1882 if (remainingInBuffer <= 0) {
1883 // We've read from the QIODevice more than what was in the buffer.
1884 buffer.truncate(0);
1885 } else {
1886 // There's still data buffered, but we need to move it around.
1887 char *ptr = buffer.data();
1888 memmove(ptr, ptr + newStart, remainingInBuffer);
1889 buffer.truncate(remainingInBuffer);
1890 }
1891
1892 bufferStart = 0;
1893 }
1894
1895 bool ensureStringIteration();
1896};
1897
1898void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error)
1899{
1900 d->handleError(CborError(error.c));
1901}
1902
1903static inline bool qt_cbor_decoder_can_read(void *token, size_t len)
1904{
1905 Q_ASSERT(len <= QCborStreamReaderPrivate::MaxCborIndividualSize);
1906 auto self = static_cast<QCborStreamReaderPrivate *>(token);
1907
1908 qint64 avail = self->buffer.size() - self->bufferStart;
1909 return len <= quint64(avail);
1910}
1911
1912static void qt_cbor_decoder_advance(void *token, size_t len)
1913{
1914 Q_ASSERT(len <= QCborStreamReaderPrivate::MaxCborIndividualSize);
1915 auto self = static_cast<QCborStreamReaderPrivate *>(token);
1916 Q_ASSERT(len <= size_t(self->buffer.size() - self->bufferStart));
1917
1918 self->bufferStart += int(len);
1919 self->preread();
1920}
1921
1922static void *qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len)
1923{
1924 Q_ASSERT(len == 1 || len == 2 || len == 4 || len == 8);
1925 Q_ASSERT(offset == 0 || offset == 1);
1926 auto self = static_cast<const QCborStreamReaderPrivate *>(token);
1927
1928 // we must have pre-read the data
1929 Q_ASSERT(len + offset <= size_t(self->buffer.size() - self->bufferStart));
1930 return memcpy(userptr, self->buffer.constData() + self->bufferStart + offset, len);
1931}
1932
1933static CborError qt_cbor_decoder_transfer_string(void *token, const void **userptr, size_t offset, size_t len)
1934{
1935 auto self = static_cast<QCborStreamReaderPrivate *>(token);
1936 Q_ASSERT(offset <= size_t(self->buffer.size()));
1937 Q_STATIC_ASSERT(sizeof(size_t) >= sizeof(QByteArray::size_type));
1938 Q_STATIC_ASSERT(sizeof(size_t) == sizeof(qsizetype));
1939
1940 // check that we will have enough data from the QIODevice before we advance
1941 // (otherwise, we'd lose the length information)
1942 qsizetype total;
1943 if (len > size_t(std::numeric_limits<QByteArray::size_type>::max())
1944 || add_overflow<qsizetype>(offset, len, &total))
1945 return CborErrorDataTooLarge;
1946
1947 // our string transfer is just saving the offset to the userptr
1948 *userptr = reinterpret_cast<void *>(offset);
1949
1950 qint64 avail = (self->device ? self->device->bytesAvailable() : self->buffer.size()) -
1951 self->bufferStart;
1952 return total > avail ? CborErrorUnexpectedEOF : CborNoError;
1953}
1954
1955bool QCborStreamReaderPrivate::ensureStringIteration()
1956{
1957 if (currentElement.flags & CborIteratorFlag_IteratingStringChunks)
1958 return true;
1959
1960 CborError err = cbor_value_begin_string_iteration(&currentElement);
1961 if (!err)
1962 return true;
1963 handleError(err);
1964 return false;
1965}
1966
1967/*!
1968 \internal
1969 */
1970inline void QCborStreamReader::preparse()
1971{
1972 if (lastError() == QCborError::NoError) {
1973 type_ = cbor_value_get_type(&d->currentElement);
1974
1975 if (type_ == CborInvalidType) {
1976 // We may have reached the end.
1977 if (d->device && d->containerStack.isEmpty()) {
1978 d->buffer.clear();
1979 if (d->bufferStart)
1980 d->device->skip(d->bufferStart);
1981 d->bufferStart = 0;
1982 }
1983 } else {
1984 d->lastError = {};
1985 // Undo the type mapping that TinyCBOR does (we have an explicit type
1986 // for negative integer and we don't have separate types for Boolean,
1987 // Null and Undefined).
1988 if (type_ == CborBooleanType || type_ == CborNullType || type_ == CborUndefinedType) {
1989 type_ = CborSimpleType;
1990 value64 = quint8(d->buffer.at(d->bufferStart)) - CborSimpleType;
1991 } else {
1992 // Using internal TinyCBOR API!
1993 value64 = _cbor_value_extract_int64_helper(&d->currentElement);
1994
1995 if (cbor_value_is_negative_integer(&d->currentElement))
1996 type_ = quint8(QCborStreamReader::NegativeInteger);
1997 }
1998 }
1999 } else {
2000 type_ = Invalid;
2001 }
2002}
2003
2004/*!
2005 Creates a QCborStreamReader object with no source data. After construction,
2006 QCborStreamReader will report an error parsing.
2007
2008 You can add more data by calling addData() or by setting a different source
2009 device using setDevice().
2010
2011 \sa addData(), isValid()
2012 */
2013QCborStreamReader::QCborStreamReader()
2014 : QCborStreamReader(QByteArray())
2015{
2016}
2017
2018/*!
2019 \overload
2020
2021 Creates a QCborStreamReader object with \a len bytes of data starting at \a
2022 data. The pointer must remain valid until QCborStreamReader is destroyed.
2023 */
2024QCborStreamReader::QCborStreamReader(const char *data, qsizetype len)
2025 : QCborStreamReader(QByteArray::fromRawData(data, len))
2026{
2027}
2028
2029/*!
2030 \overload
2031
2032 Creates a QCborStreamReader object with \a len bytes of data starting at \a
2033 data. The pointer must remain valid until QCborStreamReader is destroyed.
2034 */
2035QCborStreamReader::QCborStreamReader(const quint8 *data, qsizetype len)
2036 : QCborStreamReader(QByteArray::fromRawData(reinterpret_cast<const char *>(data), len))
2037{
2038}
2039
2040/*!
2041 \overload
2042
2043 Creates a QCborStreamReader object that will parse the CBOR stream found in
2044 \a data.
2045 */
2046QCborStreamReader::QCborStreamReader(const QByteArray &data)
2047 : d(new QCborStreamReaderPrivate(data))
2048{
2049 preparse();
2050}
2051
2052/*!
2053 \overload
2054
2055 Creates a QCborStreamReader object that will parse the CBOR stream found by
2056 reading from \a device. QCborStreamReader does not take ownership of \a
2057 device, so it must remain valid until this oject is destroyed.
2058 */
2059QCborStreamReader::QCborStreamReader(QIODevice *device)
2060 : d(new QCborStreamReaderPrivate(device))
2061{
2062 preparse();
2063}
2064
2065/*!
2066 Destroys this QCborStreamReader object and frees any associated resources.
2067 */
2068QCborStreamReader::~QCborStreamReader()
2069{
2070}
2071
2072/*!
2073 Sets the source of data to \a device, resetting the decoder to its initial
2074 state.
2075 */
2076void QCborStreamReader::setDevice(QIODevice *device)
2077{
2078 d->setDevice(device);
2079 preparse();
2080}
2081
2082/*!
2083 Returns the QIODevice that was set with either setDevice() or the
2084 QCborStreamReader constructor. If this object was reading from a QByteArray,
2085 this function returns nullptr instead.
2086 */
2087QIODevice *QCborStreamReader::device() const
2088{
2089 return d->device;
2090}
2091
2092/*!
2093 Adds \a data to the CBOR stream and reparses the current element. This
2094 function is useful if the end of the data was previously reached while
2095 processing the stream, but now more data is available.
2096 */
2097void QCborStreamReader::addData(const QByteArray &data)
2098{
2099 addData(data.constData(), data.size());
2100}
2101
2102/*!
2103 \fn void QCborStreamReader::addData(const quint8 *data, qsizetype len)
2104 \overload
2105
2106 Adds \a len bytes of data starting at \a data to the CBOR stream and
2107 reparses the current element. This function is useful if the end of the data
2108 was previously reached while processing the stream, but now more data is
2109 available.
2110 */
2111
2112/*!
2113 \overload
2114
2115 Adds \a len bytes of data starting at \a data to the CBOR stream and
2116 reparses the current element. This function is useful if the end of the data
2117 was previously reached while processing the stream, but now more data is
2118 available.
2119 */
2120void QCborStreamReader::addData(const char *data, qsizetype len)
2121{
2122 if (!d->device) {
2123 if (len > 0)
2124 d->buffer.append(data, len);
2125 reparse();
2126 } else {
2127 qWarning("QCborStreamReader: addData() with device()");
2128 }
2129}
2130
2131/*!
2132 Reparses the current element. This function must be called when more data
2133 becomes available in the source QIODevice after parsing failed due to
2134 reaching the end of the input data before the end of the CBOR stream.
2135
2136 When reading from QByteArray(), the addData() function automatically calls
2137 this function. Calling it when the reading had not failed is a no-op.
2138 */
2139void QCborStreamReader::reparse()
2140{
2141 d->lastError = {};
2142 d->preread();
2143 if (CborError err = cbor_value_reparse(&d->currentElement))
2144 d->handleError(err);
2145 else
2146 preparse();
2147}
2148
2149/*!
2150 Clears the decoder state and resets the input source data to an empty byte
2151 array. After this function is called, QCborStreamReader will be indicating
2152 an error parsing.
2153
2154 Call addData() to add more data to be parsed.
2155
2156 \sa reset(), setDevice()
2157 */
2158void QCborStreamReader::clear()
2159{
2160 setDevice(nullptr);
2161}
2162
2163/*!
2164 Resets the source back to the beginning and clears the decoder state. If the
2165 source data was a QByteArray, QCborStreamReader will restart from the
2166 beginning of the array.
2167
2168 If the source data is a QIODevice, this function will call
2169 QIODevice::reset(), which will seek to byte position 0. If the CBOR stream
2170 is not found at the beginning of the device (e.g., beginning of a file),
2171 then this function will likely do the wrong thing. Instead, position the
2172 QIODevice to the right offset and call setDevice().
2173
2174 \sa clear(), setDevice()
2175 */
2176void QCborStreamReader::reset()
2177{
2178 if (d->device)
2179 d->device->reset();
2180 d->lastError = {};
2181 d->initDecoder();
2182 preparse();
2183}
2184
2185/*!
2186 Returns the last error in decoding the stream, if any. If no error
2187 was encountered, this returns an QCborError::NoError.
2188
2189 \sa isValid()
2190 */
2191QCborError QCborStreamReader::lastError()
2192{
2193 return d->lastError;
2194}
2195
2196/*!
2197 Returns the offset in the input stream of the item currently being decoded.
2198 The current offset is the number of decoded bytes so far only if the source
2199 data is a QByteArray or it is a QIODevice that was positioned at its
2200 beginning when decoding started.
2201
2202 \sa reset(), clear(), device()
2203 */
2204qint64 QCborStreamReader::currentOffset() const
2205{
2206 return (d->device ? d->device->pos() : 0) + d->bufferStart;
2207}
2208
2209/*!
2210 Returns the number of containers that this stream has entered with
2211 enterContainer() but not yet left.
2212
2213 \sa enterContainer(), leaveContainer()
2214 */
2215int QCborStreamReader::containerDepth() const
2216{
2217 return d->containerStack.size();
2218}
2219
2220/*!
2221 Returns either QCborStreamReader::Array or QCborStreamReader::Map,
2222 indicating whether the container that contains the current item was an array
2223 or map, respectively. If we're currently parsing the root element, this
2224 function returns QCborStreamReader::Invalid.
2225
2226 \sa containerDepth(), enterContainer()
2227 */
2228QCborStreamReader::Type QCborStreamReader::parentContainerType() const
2229{
2230 if (d->containerStack.isEmpty())
2231 return Invalid;
2232 return Type(cbor_value_get_type(&qAsConst(d->containerStack).top()));
2233}
2234
2235/*!
2236 Returns true if there are more items to be decoded in the current container
2237 or false of we've reached its end. If we're parsing the root element,
2238 hasNext() returning false indicates the parsing is complete; otherwise, if
2239 the container depth is non-zero, then the outer code needs to call
2240 leaveContainer().
2241
2242 \sa parentContainerType(), containerDepth(), leaveContainer()
2243 */
2244bool QCborStreamReader::hasNext() const noexcept
2245{
2246 return cbor_value_is_valid(&d->currentElement) &&
2247 !cbor_value_at_end(&d->currentElement);
2248}
2249
2250/*!
2251 Advance the CBOR stream decoding one element. You should usually call this
2252 function when parsing fixed-width basic elements (that is, integers, simple
2253 values, tags and floating point values). But this function can be called
2254 when the current item is a string, array or map too and it will skip over
2255 that entire element, including all contained elements.
2256
2257 This function returns true if advancing was successful, false otherwise. It
2258 may fail if the stream is corrupt, incomplete or if the nesting level of
2259 arrays and maps exceeds \a maxRecursion. Calling this function when
2260 hasNext() has returned false is also an error. If this function returns
2261 false, lastError() will return the error code detailing what the failure
2262 was.
2263
2264 \sa lastError(), isValid(), hasNext()
2265 */
2266bool QCborStreamReader::next(int maxRecursion)
2267{
2268 if (lastError() != QCborError::NoError)
2269 return false;
2270
2271 if (!hasNext()) {
2272 d->handleError(CborErrorAdvancePastEOF);
2273 } else if (maxRecursion < 0) {
2274 d->handleError(CborErrorNestingTooDeep);
2275 } else if (isContainer()) {
2276 // iterate over each element
2277 enterContainer();
2278 while (lastError() == QCborError::NoError && hasNext())
2279 next(maxRecursion - 1);
2280 if (lastError() == QCborError::NoError)
2281 leaveContainer();
2282 } else if (isString() || isByteArray()) {
2283 auto r = _readByteArray_helper();
2284 while (r.status == Ok) {
2285 if (isString() && !QUtf8::isValidUtf8(r.data, r.data.size()).isValidUtf8) {
2286 d->handleError(CborErrorInvalidUtf8TextString);
2287 break;
2288 }
2289 r = _readByteArray_helper();
2290 }
2291 } else {
2292 // fixed types
2293 CborError err = cbor_value_advance_fixed(&d->currentElement);
2294 if (err)
2295 d->handleError(err);
2296 }
2297
2298 preparse();
2299 return d->lastError == QCborError::NoError;
2300}
2301
2302/*!
2303 Returns true if the length of the current array, map, byte array or string
2304 is known (explicit in the CBOR stream), false otherwise. This function
2305 should only be called if the element is one of those.
2306
2307 If the length is known, it may be obtained by calling length().
2308
2309 If the length of a map or an array is not known, it is implied by the number
2310 of elements present in the stream. QCborStreamReader has no API to calculate
2311 the length in that condition.
2312
2313 Strings and byte arrays may also have indeterminate length (that is, they
2314 may be transmitted in multiple chunks). Those cannot currently be created
2315 with QCborStreamWriter, but they could be with other encoders, so
2316 QCborStreamReader supports them.
2317
2318 \sa length(), QCborStreamWriter::startArray(), QCborStreamWriter::startMap()
2319 */
2320bool QCborStreamReader::isLengthKnown() const noexcept
2321{
2322 return cbor_value_is_length_known(&d->currentElement);
2323}
2324
2325/*!
2326 Returns the length of the string or byte array, or the number of items in an
2327 array or the number, of item pairs in a map, if known. This function must
2328 not be called if the length is unknown (that is, if isLengthKnown() returned
2329 false). It is an error to do that and it will cause QCborStreamReader to
2330 stop parsing the input stream.
2331
2332 \sa isLengthKnown(), QCborStreamWriter::startArray(), QCborStreamWriter::startMap()
2333 */
2334quint64 QCborStreamReader::length() const
2335{
2336 CborError err;
2337 switch (type()) {
2338 case String:
2339 case ByteArray:
2340 case Map:
2341 case Array:
2342 if (isLengthKnown())
2343 return value64;
2344 err = CborErrorUnknownLength;
2345 break;
2346
2347 default:
2348 err = CborErrorIllegalType;
2349 break;
2350 }
2351
2352 d->handleError(err);
2353 return quint64(-1);
2354}
2355
2356/*!
2357 \fn bool QCborStreamReader::enterContainer()
2358
2359 Enters the array or map that is the current item and prepares for iterating
2360 the elements contained in the container. Returns true if entering the
2361 container succeeded, false otherwise (usually, a parsing error). Each call
2362 to enterContainer() must be paired with a call to leaveContainer().
2363
2364 This function may only be called if the current item is an array or a map
2365 (that is, if isArray(), isMap() or isContainer() is true). Calling it in any
2366 other condition is an error.
2367
2368 \sa leaveContainer(), isContainer(), isArray(), isMap()
2369 */
2370bool QCborStreamReader::_enterContainer_helper()
2371{
2372 d->containerStack.push(d->currentElement);
2373 CborError err = cbor_value_enter_container(&d->containerStack.top(), &d->currentElement);
2374 if (!err) {
2375 preparse();
2376 return true;
2377 }
2378 d->handleError(err);
2379 return false;
2380}
2381
2382/*!
2383 Leaves the array or map whose items were being processed and positions the
2384 decoder at the next item after the end of the container. Returns true if
2385 leaving the container succeeded, false otherwise (usually, a parsing error).
2386 Each call to enterContainer() must be paired with a call to
2387 leaveContainer().
2388
2389 This function may only be called if hasNext() has returned false and
2390 containerDepth() is not zero. Calling it in any other condition is an error.
2391
2392 \sa enterContainer(), parentContainerType(), containerDepth()
2393 */
2394bool QCborStreamReader::leaveContainer()
2395{
2396 if (d->containerStack.isEmpty()) {
2397 qWarning("QCborStreamReader::leaveContainer: trying to leave top-level element");
2398 return false;
2399 }
2400 if (d->corrupt)
2401 return false;
2402
2403 CborValue container = d->containerStack.pop();
2404 CborError err = cbor_value_leave_container(&container, &d->currentElement);
2405 d->currentElement = container;
2406 if (err) {
2407 d->handleError(err);
2408 return false;
2409 }
2410
2411 preparse();
2412 return true;
2413}
2414
2415/*!
2416 \fn bool QCborStreamReader::toBool() const
2417
2418 Returns the boolean value of the current element.
2419
2420 This function does not perform any type conversions, including from integer.
2421 Therefore, it may only be called if isTrue(), isFalse() or isBool() returned
2422 true; calling it in any other condition is an error.
2423
2424 \sa isBool(), isTrue(), isFalse(), toInteger()
2425 */
2426
2427/*!
2428 \fn QCborTag QCborStreamReader::toTag() const
2429
2430 Returns the tag value of the current element.
2431
2432 This function does not perform any type conversions, including from integer.
2433 Therefore, it may only be called if isTag() is true; calling it in any other
2434 condition is an error.
2435
2436 Tags are 64-bit numbers attached to generic CBOR types that give them
2437 further meaning. For a list of known tags, see the \l QCborKnownTags
2438 enumeration.
2439
2440 \sa isTag(), toInteger(), QCborKnownTags
2441 */
2442
2443/*!
2444 \fn quint64 QCborStreamReader::toUnsignedInteger() const
2445
2446 Returns the unsigned integer value of the current element.
2447
2448 This function does not perform any type conversions, including from boolean
2449 or CBOR tag. Therefore, it may only be called if isUnsignedInteger() is
2450 true; calling it in any other condition is an error.
2451
2452 This function may be used to obtain numbers beyond the range of the return
2453 type of toInteger().
2454
2455 \sa type(), toInteger(), isUnsignedInteger(), isNegativeInteger()
2456 */
2457
2458/*!
2459 \fn QCborNegativeValue QCborStreamReader::toNegativeInteger() const
2460
2461 Returns the negative integer value of the current element.
2462 QCborNegativeValue is a 64-bit unsigned integer containing the absolute
2463 value of the negative number that was stored in the CBOR stream.
2464 Additionally, QCborNegativeValue(0) represents the number -2\sup{64}.
2465
2466 This function does not perform any type conversions, including from boolean
2467 or CBOR tag. Therefore, it may only be called if isNegativeInteger() is
2468 true; calling it in any other condition is an error.
2469
2470 This function may be used to obtain numbers beyond the range of the return
2471 type of toInteger(). However, use of negative numbers smaller than -2\sup{63}
2472 is extremely discouraged.
2473
2474 \sa type(), toInteger(), isNegativeInteger(), isUnsignedInteger()
2475 */
2476
2477/*!
2478 \fn qint64 QCborStreamReader::toInteger() const
2479
2480 Returns the integer value of the current element, be it negative, positive
2481 or zero. If the value is larger than 2\sup{63} - 1 or smaller than
2482 -2\sup{63}, the returned value will overflow and will have an incorrect
2483 sign. If handling those values is required, use toUnsignedInteger() or
2484 toNegativeInteger() instead.
2485
2486 This function does not perform any type conversions, including from boolean
2487 or CBOR tag. Therefore, it may only be called if isInteger() is true;
2488 calling it in any other condition is an error.
2489
2490 \sa isInteger(), toUnsignedInteger(), toNegativeInteger()
2491 */
2492
2493/*!
2494 \fn QCborSimpleType QCborStreamReader::toSimpleType() const
2495
2496 Returns value of the current simple type.
2497
2498 This function does not perform any type conversions, including from integer.
2499 Therefore, it may only be called if isSimpleType() is true; calling it in
2500 any other condition is an error.
2501
2502 \sa isSimpleType(), isTrue(), isFalse(), isBool(), isNull(), isUndefined()
2503 */
2504
2505/*!
2506 \fn qfloat16 QCborStreamReader::toFloat16() const
2507
2508 Returns the 16-bit half-precision floating point value of the current element.
2509
2510 This function does not perform any type conversions, including from other
2511 floating point types or from integer values. Therefore, it may only be
2512 called if isFloat16() is true; calling it in any other condition is an
2513 error.
2514
2515 \sa isFloat16(), toFloat(), toDouble()
2516 */
2517
2518/*!
2519 \fn float QCborStreamReader::toFloat() const
2520
2521 Returns the 32-bit single-precision floating point value of the current
2522 element.
2523
2524 This function does not perform any type conversions, including from other
2525 floating point types or from integer values. Therefore, it may only be
2526 called if isFloat() is true; calling it in any other condition is an error.
2527
2528 \sa isFloat(), toFloat16(), toDouble()
2529 */
2530
2531/*!
2532 \fn double QCborStreamReader::toDouble() const
2533
2534 Returns the 64-bit double-precision floating point value of the current
2535 element.
2536
2537 This function does not perform any type conversions, including from other
2538 floating point types or from integer values. Therefore, it may only be
2539 called if isDouble() is true; calling it in any other condition is an error.
2540
2541 \sa isDouble(), toFloat16(), toFloat()
2542 */
2543
2544/*!
2545 \fn QCborStreamReader::StringResult<QString> QCborStreamReader::readString()
2546
2547 Decodes one string chunk from the CBOR string and returns it. This function
2548 is used for both regular and chunked string contents, so the caller must
2549 always loop around calling this function, even if isLengthKnown() has
2550 is true. The typical use of this function is as follows:
2551
2552 \snippet code/src_corelib_serialization_qcborstream.cpp 27
2553
2554 This function does not perform any type conversions, including from integers
2555 or from byte arrays. Therefore, it may only be called if isString() returned
2556 true; calling it in any other condition is an error.
2557
2558 \sa readByteArray(), isString(), readStringChunk()
2559 */
2560QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
2561{
2562 auto r = _readByteArray_helper();
2563 QCborStreamReader::StringResult<QString> result;
2564 result.status = r.status;
2565
2566 if (r.status == Ok) {
2567 QTextCodec::ConverterState cs;
2568 result.data = QUtf8::convertToUnicode(r.data, r.data.size(), &cs);
2569 if (cs.invalidChars == 0 && cs.remainingChars == 0)
2570 return result;
2571
2572 d->handleError(CborErrorInvalidUtf8TextString);
2573 result.data.clear();
2574 result.status = Error;
2575 return result;
2576 }
2577 return result;
2578}
2579
2580/*!
2581 \fn QCborStreamReader::StringResult<QString> QCborStreamReader::readByteArray()
2582
2583 Decodes one byte array chunk from the CBOR string and returns it. This
2584 function is used for both regular and chunked contents, so the caller must
2585 always loop around calling this function, even if isLengthKnown() has
2586 is true. The typical use of this function is as follows:
2587
2588 \snippet code/src_corelib_serialization_qcborstream.cpp 28
2589
2590 This function does not perform any type conversions, including from integers
2591 or from strings. Therefore, it may only be called if isByteArray() is true;
2592 calling it in any other condition is an error.
2593
2594 \sa readString(), isByteArray(), readStringChunk()
2595 */
2596QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readByteArray_helper()
2597{
2598 QCborStreamReader::StringResult<QByteArray> result;
2599 result.status = Error;
2600 qsizetype len = _currentStringChunkSize();
2601 if (len < 0)
2602 return result;
2603
2604 result.data.resize(len);
2605 auto r = readStringChunk(result.data.data(), len);
2606 Q_ASSERT(r.status != Ok || r.data == len);
2607 result.status = r.status;
2608 return result;
2609}
2610
2611/*!
2612 \fn qsizetype QCborStreamReader::currentStringChunkSize() const
2613
2614 Returns the size of the current text or byte string chunk. If the CBOR
2615 stream contains a non-chunked string (that is, if isLengthKnown() returns
2616 \c true), this function returns the size of the entire string, the same as
2617 length().
2618
2619 This function is useful to pre-allocate the buffer whose pointer can be passed
2620 to readStringChunk() later.
2621
2622 \sa readString(), readByteArray(), readStringChunk()
2623 */
2624qsizetype QCborStreamReader::_currentStringChunkSize() const
2625{
2626 if (!d->ensureStringIteration())
2627 return -1;
2628
2629 size_t len;
2630 CborError err = cbor_value_get_string_chunk_size(&d->currentElement, &len);
2631 if (err == CborErrorNoMoreStringChunks)
2632 return 0; // not a real error
2633 else if (err)
2634 d->handleError(err);
2635 else if (qsizetype(len) < 0)
2636 d->handleError(CborErrorDataTooLarge);
2637 else
2638 return qsizetype(len);
2639 return -1;
2640}
2641
2642/*!
2643 Reads the current string chunk into the buffer pointed to by \a ptr, whose
2644 size is \a maxlen. This function returns a \l StringResult object, with the
2645 number of bytes copied into \a ptr saved in the \c \l StringResult::data
2646 member. The \c \l StringResult::status member indicates whether there was
2647 an error reading the string, whether data was copied or whether this was
2648 the last chunk.
2649
2650 This function can be called for both \l String and \l ByteArray types.
2651 For the latter, this function will read the same data that readByteArray()
2652 would have returned. For strings, it returns the UTF-8 equivalent of the \l
2653 QString that would have been returned.
2654
2655 This function is usually used alongside currentStringChunkSize() in a loop.
2656 For example:
2657
2658 \snippet code/src_corelib_serialization_qcborstream.cpp 29
2659
2660 Unlike readByteArray() and readString(), this function is not limited by
2661 implementation limits of QByteArray and QString.
2662
2663 \note This function does not perform verification that the UTF-8 contents
2664 are properly formatted. That means this function does not produce the
2665 QCborError::InvalidUtf8String error, even when readString() does.
2666
2667 \sa currentStringChunkSize(), readString(), readByteArray(),
2668 isString(), isByteArray()
2669 */
2670QCborStreamReader::StringResult<qsizetype>
2671QCborStreamReader::readStringChunk(char *ptr, qsizetype maxlen)
2672{
2673 CborError err;
2674 size_t len;
2675 const void *content = nullptr;
2676 QCborStreamReader::StringResult<qsizetype> result;
2677 result.data = 0;
2678 result.status = Error;
2679
2680 d->lastError = {};
2681 if (!d->ensureStringIteration())
2682 return result;
2683
2684#if 1
2685 // Using internal TinyCBOR API!
2686 err = _cbor_value_get_string_chunk(&d->currentElement, &content, &len, &d->currentElement);
2687#else
2688 // the above is effectively the same as:
2689 if (cbor_value_is_byte_string(&currentElement))
2690 err = cbor_value_get_byte_string_chunk(&d->currentElement, reinterpret_cast<const uint8_t **>(&content),
2691 &len, &d->currentElement);
2692 else
2693 err = cbor_value_get_text_string_chunk(&d->currentElement, reinterpret_cast<const char **>(&content),
2694 &len, &d->currentElement);
2695#endif
2696
2697 // Range check: using implementation-defined behavior in converting an
2698 // unsigned value out of range of the destination signed type (same as
2699 // "len > size_t(std::numeric_limits<qsizetype>::max())", but generates
2700 // better code with ICC and MSVC).
2701 if (!err && qsizetype(len) < 0)
2702 err = CborErrorDataTooLarge;
2703
2704 if (err) {
2705 if (err == CborErrorNoMoreStringChunks) {
2706 d->preread();
2707 err = cbor_value_finish_string_iteration(&d->currentElement);
2708 result.status = EndOfString;
2709 }
2710 if (err)
2711 d->handleError(err);
2712 else
2713 preparse();
2714 return result;
2715 }
2716
2717 // Read the chunk into the user's buffer.
2718 qint64 actuallyRead;
2719 qptrdiff offset = qptrdiff(content);
2720 qsizetype toRead = qsizetype(len);
2721 qsizetype left = toRead - maxlen;
2722 if (left < 0)
2723 left = 0; // buffer bigger than string
2724 else
2725 toRead = maxlen; // buffer smaller than string
2726
2727 if (d->device) {
2728 // This first skip can't fail because we've already read this many bytes.
2729 d->device->skip(d->bufferStart + qptrdiff(content));
2730 actuallyRead = d->device->read(ptr, toRead);
2731
2732 if (actuallyRead != toRead) {
2733 actuallyRead = -1;
2734 } else if (left) {
2735 qint64 skipped = d->device->skip(left);
2736 if (skipped != left)
2737 actuallyRead = -1;
2738 }
2739
2740 if (actuallyRead < 0) {
2741 d->handleError(CborErrorIO);
2742 return result;
2743 }
2744
2745 d->updateBufferAfterString(offset, len);
2746 } else {
2747 actuallyRead = toRead;
2748 memcpy(ptr, d->buffer.constData() + d->bufferStart + offset, toRead);
2749 d->bufferStart += QByteArray::size_type(offset + len);
2750 }
2751
2752 d->preread();
2753 result.data = actuallyRead;
2754 result.status = Ok;
2755 return result;
2756}
2757
2758QT_END_NAMESPACE
2759
2760#include "moc_qcborcommon.cpp"
2761#include "moc_qcborstream.cpp"
2762