Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcborstreamreader.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
6
7#define CBOR_NO_ENCODER_API
8#include <private/qcborcommon_p.h>
9
10#include <private/qnumeric_p.h>
11#include <private/qstringconverter_p.h>
12#include <qiodevice.h>
13#include <qdebug.h>
14#include <qstack.h>
15#include <qvarlengtharray.h>
16
18
19static bool qt_cbor_decoder_can_read(void *token, size_t len);
20static void qt_cbor_decoder_advance(void *token, size_t len);
21static void *qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len);
22static CborError qt_cbor_decoder_transfer_string(void *token, const void **userptr, size_t offset, size_t len);
23
24#define CBOR_PARSER_READER_CONTROL 1
25#define CBOR_PARSER_CAN_READ_BYTES_FUNCTION qt_cbor_decoder_can_read
26#define CBOR_PARSER_ADVANCE_BYTES_FUNCTION qt_cbor_decoder_advance
27#define CBOR_PARSER_TRANSFER_STRING_FUNCTION qt_cbor_decoder_transfer_string
28#define CBOR_PARSER_READ_BYTES_FUNCTION qt_cbor_decoder_read
29
30QT_WARNING_PUSH
31QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
32QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
33
34#include <cborparser.c>
35
36QT_WARNING_POP
37
38static CborError _cbor_value_dup_string(const CborValue *, void **, size_t *, CborValue *)
39{
40 Q_UNREACHABLE_RETURN(CborErrorInternalError);
41}
42[[maybe_unused]] static CborError cbor_value_get_half_float_as_float(const CborValue *, float *)
43{
44 Q_UNREACHABLE_RETURN(CborErrorInternalError);
45}
46
47// confirm our constants match TinyCBOR's
48static_assert(int(QCborStreamReader::UnsignedInteger) == CborIntegerType);
49static_assert(int(QCborStreamReader::ByteString) == CborByteStringType);
50static_assert(int(QCborStreamReader::TextString) == CborTextStringType);
51static_assert(int(QCborStreamReader::Array) == CborArrayType);
52static_assert(int(QCborStreamReader::Map) == CborMapType);
53static_assert(int(QCborStreamReader::Tag) == CborTagType);
54static_assert(int(QCborStreamReader::SimpleType) == CborSimpleType);
55static_assert(int(QCborStreamReader::HalfFloat) == CborHalfFloatType);
56static_assert(int(QCborStreamReader::Float) == CborFloatType);
57static_assert(int(QCborStreamReader::Double) == CborDoubleType);
58static_assert(int(QCborStreamReader::Invalid) == CborInvalidType);
59
60/*!
61 \class QCborStreamReader
62 \inmodule QtCore
63 \ingroup cbor
64 \ingroup qtserialization
65 \reentrant
66 \since 5.12
67
68 \brief The QCborStreamReader class is a simple CBOR stream decoder, operating
69 on either a QByteArray or QIODevice.
70
71 This class can be used to decode a stream of CBOR content directly from
72 either a QByteArray or a QIODevice. CBOR is the Concise Binary Object
73 Representation, a very compact form of binary data encoding that is
74 compatible with JSON. It was created by the IETF Constrained RESTful
75 Environments (CoRE) WG, which has used it in many new RFCs. It is meant to
76 be used alongside the \l{RFC 7252}{CoAP
77 protocol}.
78
79 QCborStreamReader provides a StAX-like API, similar to that of
80 \l{QXmlStreamReader}. Using it requires a bit of knowledge of CBOR encoding.
81 For a simpler API, see \l{QCborValue} and especially the decoding function
82 QCborValue::fromCbor().
83
84 Typically, one creates a QCborStreamReader by passing the source QByteArray
85 or QIODevice as a parameter to the constructor, then pop elements off the
86 stream if there were no errors in decoding. There are three kinds of CBOR
87 types:
88
89 \table
90 \header \li Kind \li Types \li Behavior
91 \row \li Fixed-width \li Integers, Tags, Simple types, Floating point
92 \li Value is pre-parsed by QCborStreamReader, so accessor functions
93 are \c const. Must call next() to advance.
94 \row \li Strings \li Byte arrays, Text strings
95 \li Length (if known) is pre-parsed, but the string itself is not.
96 The accessor functions are not const and may allocate memory.
97 Once called, the accessor functions automatically advance to
98 the next element.
99 \row \li Containers \li Arrays, Maps
100 \li Length (if known) is pre-parsed. To access the elements, you
101 must call enterContainer(), read all elements, then call
102 leaveContainer(). That function advances to the next element.
103 \endtable
104
105 So a processor function typically looks like this:
106
107 \snippet code/src_corelib_serialization_qcborstream.cpp 24
108
109 \section1 CBOR support
110
111 The following table lists the CBOR features that QCborStreamReader supports.
112
113 \table
114 \header \li Feature \li Support
115 \row \li Unsigned numbers \li Yes (full range)
116 \row \li Negative numbers \li Yes (full range)
117 \row \li Byte strings \li Yes
118 \row \li Text strings \li Yes
119 \row \li Chunked strings \li Yes
120 \row \li Tags \li Yes (arbitrary)
121 \row \li Booleans \li Yes
122 \row \li Null \li Yes
123 \row \li Undefined \li Yes
124 \row \li Arbitrary simple values \li Yes
125 \row \li Half-precision float (16-bit) \li Yes
126 \row \li Single-precision float (32-bit) \li Yes
127 \row \li Double-precision float (64-bit) \li Yes
128 \row \li Infinities and NaN floating point \li Yes
129 \row \li Determinate-length arrays and maps \li Yes
130 \row \li Indeterminate-length arrays and maps \li Yes
131 \row \li Map key types other than strings and integers \li Yes (arbitrary)
132 \endtable
133
134 \section1 Dealing with invalid or incomplete CBOR streams
135
136 QCborStreamReader is capable of detecting corrupt input on its own. The
137 library it uses has been extensively tested against invalid input of any
138 kind and is quite able to report errors. If any is detected,
139 QCborStreamReader will set lastError() to a value besides
140 QCborError::NoError, indicating which situation was detected.
141
142 Most errors detected by QCborStreamReader during normal item parsing are not
143 recoverable. The code using QCborStreamReader may opt to handle the data
144 that was properly decoded or it can opt to discard the entire data.
145
146 The only recoverable error is QCborError::EndOfFile, which indicates that
147 more data is required in order to complete the parsing. This situation is
148 useful when data is being read from an asynchronous source, such as a pipe
149 (QProcess) or a socket (QTcpSocket, QUdpSocket, QNetworkReply, etc.). When
150 more data arrives, the surrounding code needs to call either addData(), if
151 parsing from a QByteArray, or reparse(), if it is instead reading directly
152 a the QIDOevice that now has more data available (see setDevice()).
153
154 \sa QCborStreamWriter, QCborValue, QXmlStreamReader,
155 {Parsing and displaying CBOR data}, {Serialization Converter},
156 {Saving and Loading a Game}
157 */
158
159/*!
160 \enum QCborStreamReader::Type
161
162 This enumeration contains all possible CBOR types as decoded by
163 QCborStreamReader. CBOR has 7 major types, plus a number of simple types
164 carrying no value, and floating point values.
165
166 \value UnsignedInteger (Major type 0) Ranges from 0 to 2\sup{64} - 1
167 (18,446,744,073,709,551,616)
168 \value NegativeInteger (Major type 1) Ranges from -1 to -2\sup{64}
169 (-18,446,744,073,709,551,616)
170 \value ByteArray (Major type 2) Arbitrary binary data.
171 \value ByteString An alias to ByteArray.
172 \value String (Major type 3) Unicode text, possibly containing NULs.
173 \value TextString An alias to String
174 \value Array (Major type 4) Array of heterogeneous items.
175 \value Map (Major type 5) Map/dictionary of heterogeneous items.
176 \value Tag (Major type 6) Numbers giving further semantic value
177 to generic CBOR items. See \l QCborTag for more information.
178 \value SimpleType (Major type 7) Types carrying no further value. Includes
179 booleans (true and false), null, undefined.
180 \value Float16 IEEE 754 half-precision floating point (\c qfloat16).
181 \value HalfFloat An alias to Float16.
182 \value Float IEEE 754 single-precision floating point (\tt float).
183 \value Double IEEE 754 double-precision floating point (\tt double).
184 \value Invalid Not a valid type, either due to parsing error or due to
185 reaching the end of an array or map.
186 */
187
188/*!
189 \enum QCborStreamReader::StringResultCode
190
191 This enum is returned by readString() and readByteArray() and is used to
192 indicate what the status of the parsing is.
193
194 \value EndOfString The parsing for the string is complete, with no error.
195 \value Ok The function returned data; there was no error.
196 \value Error Parsing failed with an error.
197 */
198
199/*!
200 \class QCborStreamReader::StringResult
201 \inmodule QtCore
202
203 This class is returned by readString() and readByteArray(), with either the
204 contents of the string that was read or an indication that the parsing is
205 done or found an error.
206
207 The contents of \l data are valid only if \l status is
208 \l{StringResultCode}{Ok}. Otherwise, it should be null.
209 */
210
211/*!
212 \variable QCborStreamReader::StringResult::data
213
214 Contains the actual data from the string if \l status is \c Ok.
215 */
216
217/*!
218 \variable QCborStreamReader::StringResult::status
219
220 Contains the status of the attempt of reading the string from the stream.
221 */
222
223/*!
224 \fn QCborStreamReader::Type QCborStreamReader::type() const
225
226 Returns the type of the current element. It is one of the valid types or
227 Invalid.
228
229 \sa isValid(), isUnsignedInteger(), isNegativeInteger(), isInteger(),
230 isByteArray(), isString(), isArray(), isMap(), isTag(), isSimpleType(),
231 isBool(), isFalse(), isTrue(), isNull(), isUndefined(), isFloat16(),
232 isFloat(), isDouble()
233 */
234
235/*!
236 \fn bool QCborStreamReader::isValid() const
237
238 Returns true if the current element is valid, false otherwise. The current
239 element may be invalid if there was a decoding error or we've just parsed
240 the last element in an array or map.
241
242 \note This function is not the opposite of isNull(). Null is a normal CBOR
243 type that must be handled by the application.
244
245 \sa type(), isInvalid()
246 */
247
248/*!
249 \fn bool QCborStreamReader::isInvalid() const
250
251 Returns true if the current element is invalid, false otherwise. The current
252 element may be invalid if there was a decoding error or we've just parsed
253 the last element in an array or map.
254
255 \note This function is not to be confused with isNull(). Null is a normal
256 CBOR type that must be handled by the application.
257
258 \sa type(), isValid()
259 */
260
261/*!
262 \fn bool QCborStreamReader::isUnsignedInteger() const
263
264 Returns true if the type of the current element is an unsigned integer (that
265 is if type() returns QCborStreamReader::UnsignedInteger). If this function
266 returns true, you may call toUnsignedInteger() or toInteger() to read that value.
267
268 \sa type(), toUnsignedInteger(), toInteger(), isInteger(), isNegativeInteger()
269 */
270
271/*!
272 \fn bool QCborStreamReader::isNegativeInteger() const
273
274 Returns true if the type of the current element is a negative integer (that
275 is if type() returns QCborStreamReader::NegativeInteger). If this function
276 returns true, you may call toNegativeInteger() or toInteger() to read that value.
277
278 \sa type(), toNegativeInteger(), toInteger(), isInteger(), isUnsignedInteger()
279 */
280
281/*!
282 \fn bool QCborStreamReader::isInteger() const
283
284 Returns true if the type of the current element is either an unsigned
285 integer or a negative one (that is, if type() returns
286 QCborStreamReader::UnsignedInteger or QCborStreamReader::NegativeInteger).
287 If this function returns true, you may call toInteger() to read that
288 value.
289
290 \sa type(), toInteger(), toUnsignedInteger(), toNegativeInteger(),
291 isUnsignedInteger(), isNegativeInteger()
292 */
293
294/*!
295 \fn bool QCborStreamReader::isByteArray() const
296
297 Returns true if the type of the current element is a byte array (that is,
298 if type() returns QCborStreamReader::ByteArray). If this function returns
299 true, you may call readByteArray() to read that data.
300
301 \sa type(), readByteArray(), isString()
302 */
303
304/*!
305 \fn bool QCborStreamReader::isString() const
306
307 Returns true if the type of the current element is a text string (that is,
308 if type() returns QCborStreamReader::String). If this function returns
309 true, you may call readString() to read that data.
310
311 \sa type(), readString(), isByteArray()
312 */
313
314/*!
315 \fn bool QCborStreamReader::isArray() const
316
317 Returns true if the type of the current element is an array (that is,
318 if type() returns QCborStreamReader::Array). If this function returns
319 true, you may call enterContainer() to begin parsing that container.
320
321 When the current element is an array, you may also call isLengthKnown() to
322 find out if the array's size is explicit in the CBOR stream. If it is, that
323 size can be obtained by calling length().
324
325 The following example pre-allocates a QVariantList given the array's size
326 for more efficient decoding:
327
328 \snippet code/src_corelib_serialization_qcborstream.cpp 25
329
330 \note The code above does not validate that the length is a sensible value.
331 If the input stream reports that the length is 1 billion elements, the above
332 function will try to allocate some 16 GB or more of RAM, which can lead to a
333 crash.
334
335 \sa type(), isMap(), isLengthKnown(), length(), enterContainer(), leaveContainer()
336 */
337
338/*!
339 \fn bool QCborStreamReader::isMap() const
340
341 Returns true if the type of the current element is a map (that is, if type()
342 returns QCborStreamReader::Map). If this function returns true, you may call
343 enterContainer() to begin parsing that container.
344
345 When the current element is a map, you may also call isLengthKnown() to
346 find out if the map's size is explicit in the CBOR stream. If it is, that
347 size can be obtained by calling length().
348
349 The following example pre-allocates a QVariantMap given the map's size
350 for more efficient decoding:
351
352 \snippet code/src_corelib_serialization_qcborstream.cpp 26
353
354 The example above uses a function called \c readElementAsString to read the
355 map's keys and obtain a string. That is because CBOR maps may contain any
356 type as keys, not just strings. User code needs to either perform this
357 conversion, reject non-string keys, or instead use a different container
358 besides \l QVariantMap and \l QVariantHash. For example, if the map is
359 expected to contain integer keys, which is recommended as it reduces stream
360 size and parsing, the correct container would be \c{\l{QMap}<int, QVariant>}
361 or \c{\l{QHash}<int, QVariant>}.
362
363 \note The code above does not validate that the length is a sensible value.
364 If the input stream reports that the length is 1 billion elements, the above
365 function will try to allocate some 24 GB or more of RAM, which can lead to a
366 crash.
367
368 \sa type(), isArray(), isLengthKnown(), length(), enterContainer(), leaveContainer()
369 */
370
371/*!
372 \fn bool QCborStreamReader::isTag() const
373
374 Returns true if the type of the current element is a CBOR tag (that is,
375 if type() returns QCborStreamReader::Tag). If this function returns
376 true, you may call toTag() to read that data.
377
378 \sa type(), toTag()
379 */
380
381/*!
382 \fn bool QCborStreamReader::isFloat16() const
383
384 Returns true if the type of the current element is an IEEE 754
385 half-precision floating point (that is, if type() returns
386 QCborStreamReader::Float16). If this function returns true, you may call
387 toFloat16() to read that data.
388
389 \sa type(), toFloat16(), isFloat(), isDouble()
390 */
391
392/*!
393 \fn bool QCborStreamReader::isFloat() const
394
395 Returns true if the type of the current element is an IEEE 754
396 single-precision floating point (that is, if type() returns
397 QCborStreamReader::Float). If this function returns true, you may call
398 toFloat() to read that data.
399
400 \sa type(), toFloat(), isFloat16(), isDouble()
401 */
402
403/*!
404 \fn bool QCborStreamReader::isDouble() const
405
406 Returns true if the type of the current element is an IEEE 754
407 double-precision floating point (that is, if type() returns
408 QCborStreamReader::Double). If this function returns true, you may call
409 toDouble() to read that data.
410
411 \sa type(), toDouble(), isFloat16(), isFloat()
412 */
413
414/*!
415 \fn bool QCborStreamReader::isSimpleType() const
416
417 Returns true if the type of the current element is any CBOR simple type,
418 including a boolean value (true and false) as well as null and undefined. To
419 find out which simple type this is, call toSimpleType(). Alternatively, to
420 test for one specific simple type, call the overload that takes a
421 QCborSimpleType parameter.
422
423 CBOR simple types are types that do not carry extra value. There are 255
424 possibilities, but there are currently only four values that have defined
425 meaning. Code is not expected to cope with unknown simple types and may
426 simply discard the stream as invalid if it finds an unknown one.
427
428 \sa QCborSimpleType, type(), isSimpleType(QCborSimpleType), toSimpleType()
429 */
430
431/*!
432 \fn bool QCborStreamReader::isSimpleType(QCborSimpleType st) const
433
434 Returns true if the type of the current element is the simple type \a st,
435 false otherwise. If this function returns true, then toSimpleType() will
436 return \a st.
437
438 CBOR simple types are types that do not carry extra value. There are 255
439 possibilities, but there are currently only four values that have defined
440 meaning. Code is not expected to cope with unknown simple types and may
441 simply discard the stream as invalid if it finds an unknown one.
442
443 \sa QCborSimpleType, type(), isSimpleType(), toSimpleType()
444 */
445
446/*!
447 \fn bool QCborStreamReader::isFalse() const
448
449 Returns true if the current element is the \c false value, false if it is
450 anything else.
451
452 \sa type(), isTrue(), isBool(), toBool(), isSimpleType(), toSimpleType()
453 */
454
455/*!
456 \fn bool QCborStreamReader::isTrue() const
457
458 Returns true if the current element is the \c true value, false if it is
459 anything else.
460
461 \sa type(), isFalse(), isBool(), toBool(), isSimpleType(), toSimpleType()
462 */
463
464/*!
465 \fn bool QCborStreamReader::isBool() const
466
467 Returns true if the current element is a boolean value (\c true or \c
468 false), false if it is anything else. If this function returns true, you may
469 call toBool() to retrieve the value of the boolean. You may also call
470 toSimpleType() and compare to either QCborSimpleValue::True or
471 QCborSimpleValue::False.
472
473 \sa type(), isFalse(), isTrue(), toBool(), isSimpleType(), toSimpleType()
474 */
475
476/*!
477 \fn bool QCborStreamReader::isNull() const
478
479 Returns true if the current element is the \c null value, false if it is
480 anything else. Null values may be used to indicate the absence of some
481 optional data.
482
483 \note This function is not the opposite of isValid(). A Null value is a
484 valid CBOR value.
485
486 \sa type(), isSimpleType(), toSimpleType()
487 */
488
489/*!
490 \fn bool QCborStreamReader::isUndefined() const
491
492 Returns true if the current element is the \c undefined value, false if it
493 is anything else. Undefined values may be encoded to indicate that some
494 conversion failed or was not possible when creating the stream.
495 QCborStreamReader never performs any replacement and this function will only
496 return true if the stream contains an explicit undefined value.
497
498 \sa type(), isSimpleType(), toSimpleType()
499 */
500
501/*!
502 \fn bool QCborStreamReader::isContainer() const
503
504 Returns true if the current element is a container (that is, an array or a
505 map), false if it is anything else. If the current element is a container,
506 the isLengthKnown() function may be used to find out if the container's size
507 is explicit in the stream and, if so, length() can be used to get that size.
508
509 More importantly, for a container, the enterContainer() function is
510 available to begin iterating through the elements contained therein.
511
512 \sa type(), isArray(), isMap(), isLengthKnown(), length(), enterContainer(),
513 leaveContainer(), containerDepth()
514 */
515
517{
518public:
519 enum {
520 // 9 bytes is the maximum size for any integer, floating point or
521 // length in CBOR.
524 };
525
526 QIODevice *device;
529
533
535 bool corrupt = false;
536
538 : device(nullptr), buffer(data)
539 {
541 }
542
543 QCborStreamReaderPrivate(QIODevice *device)
544 {
545 setDevice(device);
546 }
547
551
552 void setDevice(QIODevice *dev)
553 {
554 buffer.clear();
555 device = dev;
557 }
558
560 {
561 containerStack.clear();
562 bufferStart = 0;
563 if (device) {
564 buffer.clear();
565 buffer.reserve(IdealIoBufferSize); // sets the CapacityReserved flag
566 }
567
568 preread();
569 if (CborError err = cbor_parser_init_reader(nullptr, &parser, &currentElement, this))
570 handleError(err);
571 else
572 lastError = { QCborError::NoError };
573 }
574
575 char *bufferPtr()
576 {
577 Q_ASSERT(buffer.isDetached());
578 return const_cast<char *>(buffer.constBegin()) + bufferStart;
579 }
580
581 void preread()
582 {
583 if (device && buffer.size() - bufferStart < MaxCborIndividualSize) {
584 // load more, but only if there's more to be read
585 qint64 avail = device->bytesAvailable();
586 Q_ASSERT(avail >= buffer.size());
587 if (avail == buffer.size())
588 return;
589
590 if (bufferStart)
591 device->skip(bufferStart); // skip what we've already parsed
592
593 if (buffer.size() != IdealIoBufferSize)
594 buffer.resize(IdealIoBufferSize);
595
596 bufferStart = 0;
597 qint64 read = device->peek(bufferPtr(), IdealIoBufferSize);
598 if (read < 0)
599 buffer.clear();
600 else if (read != IdealIoBufferSize)
601 buffer.truncate(read);
602 }
603 }
604
605 void handleError(CborError err) noexcept
606 {
607 Q_ASSERT(err);
608
609 // is the error fatal?
610 if (err != CborErrorUnexpectedEOF)
611 corrupt = true;
612
613 lastError = QCborError { QCborError::Code(int(err)) };
614 }
615
617 union {
618 char *ptr;
621 };
622 enum Type { ByteArray = -1, String = -3, Utf8String = -5 };
624
625 ReadStringChunk(char *ptr, qsizetype maxlen) : ptr(ptr), maxlen_or_type(maxlen) {}
628 bool isString() const { return maxlen_or_type == String; }
629 bool isUtf8String() const { return maxlen_or_type == Utf8String; }
630 bool isByteArray() const { return maxlen_or_type == ByteArray; }
631 bool isPlainPointer() const { return maxlen_or_type >= 0; }
632 };
633
641};
642
644{
645 d->handleError(CborError(error.c));
646}
647
648static inline bool qt_cbor_decoder_can_read(void *token, size_t len)
649{
651 auto self = static_cast<QCborStreamReaderPrivate *>(token);
652
653 qint64 avail = self->buffer.size() - self->bufferStart;
654 return len <= quint64(avail);
655}
656
657static void qt_cbor_decoder_advance(void *token, size_t len)
658{
660 auto self = static_cast<QCborStreamReaderPrivate *>(token);
661 Q_ASSERT(len <= size_t(self->buffer.size() - self->bufferStart));
662
663 self->bufferStart += int(len);
664 self->preread();
665}
666
667static void *qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len)
668{
669 Q_ASSERT(len == 1 || len == 2 || len == 4 || len == 8);
670 Q_ASSERT(offset == 0 || offset == 1);
671 auto self = static_cast<const QCborStreamReaderPrivate *>(token);
672
673 // we must have pre-read the data
674 Q_ASSERT(len + offset <= size_t(self->buffer.size() - self->bufferStart));
675 return memcpy(userptr, self->buffer.constBegin() + self->bufferStart + offset, len);
676}
677
678static CborError qt_cbor_decoder_transfer_string(void *token, const void **userptr, size_t offset, size_t len)
679{
680 auto self = static_cast<QCborStreamReaderPrivate *>(token);
681 Q_ASSERT(offset <= size_t(self->buffer.size()));
682 static_assert(sizeof(size_t) >= sizeof(QByteArray::size_type));
683 static_assert(sizeof(size_t) == sizeof(qsizetype));
684
685 // check that we will have enough data from the QIODevice before we advance
686 // (otherwise, we'd lose the length information)
687 qsizetype total;
688 if (len > size_t(std::numeric_limits<QByteArray::size_type>::max())
689 || qAddOverflow<qsizetype>(offset, len, &total))
690 return CborErrorDataTooLarge;
691
692 // our string transfer is just saving the offset to the userptr
693 *userptr = reinterpret_cast<void *>(offset);
694
695 qint64 avail = (self->device ? self->device->bytesAvailable() : self->buffer.size()) -
696 self->bufferStart;
697 return total > avail ? CborErrorUnexpectedEOF : CborNoError;
698}
699
701{
702 if (currentElement.flags & CborIteratorFlag_IteratingStringChunks)
703 return true;
704
705 CborError err = cbor_value_begin_string_iteration(&currentElement);
706 if (!err)
707 return true;
708 handleError(err);
709 return false;
710}
711
712/*!
713 \internal
714 */
715inline void QCborStreamReader::preparse()
716{
717 if (lastError() == QCborError::NoError) {
718 type_ = cbor_value_get_type(&d->currentElement);
719
720 if (type_ == CborInvalidType) {
721 // We may have reached the end.
722 if (d->device && d->containerStack.isEmpty()) {
723 d->buffer.clear();
724 if (d->bufferStart)
725 d->device->skip(d->bufferStart);
726 d->bufferStart = 0;
727 }
728 } else {
729 d->lastError = {};
730 // Undo the type mapping that TinyCBOR does (we have an explicit type
731 // for negative integer and we don't have separate types for Boolean,
732 // Null and Undefined).
733 if (type_ == CborBooleanType || type_ == CborNullType || type_ == CborUndefinedType) {
734 type_ = CborSimpleType;
735 value64 = quint8(d->buffer.at(d->bufferStart)) - CborSimpleType;
736 } else {
737 // Using internal TinyCBOR API!
738 value64 = _cbor_value_extract_int64_helper(&d->currentElement);
739
740 if (cbor_value_is_negative_integer(&d->currentElement))
741 type_ = quint8(QCborStreamReader::NegativeInteger);
742 }
743 }
744 } else {
745 type_ = Invalid;
746 }
747}
748
749/*!
750 Creates a QCborStreamReader object with no source data. After construction,
751 QCborStreamReader will report an error parsing.
752
753 You can add more data by calling addData() or by setting a different source
754 device using setDevice().
755
756 \sa addData(), isValid()
757 */
758QCborStreamReader::QCborStreamReader()
759 : d(new QCborStreamReaderPrivate({})), type_(Invalid)
760{
761}
762
763/*!
764 \overload
765
766 Creates a QCborStreamReader object with \a len bytes of data starting at \a
767 data. The pointer must remain valid until QCborStreamReader is destroyed.
768 */
769QCborStreamReader::QCborStreamReader(const char *data, qsizetype len)
770 : QCborStreamReader(QByteArray::fromRawData(data, len))
771{
772}
773
774/*!
775 \overload
776
777 Creates a QCborStreamReader object with \a len bytes of data starting at \a
778 data. The pointer must remain valid until QCborStreamReader is destroyed.
779 */
780QCborStreamReader::QCborStreamReader(const quint8 *data, qsizetype len)
781 : QCborStreamReader(QByteArray::fromRawData(reinterpret_cast<const char *>(data), len))
782{
783}
784
785/*!
786 \overload
787
788 Creates a QCborStreamReader object that will parse the CBOR stream found in
789 \a data.
790 */
791QCborStreamReader::QCborStreamReader(const QByteArray &data)
792 : d(new QCborStreamReaderPrivate(data))
793{
794 preparse();
795}
796
797/*!
798 \overload
799
800 Creates a QCborStreamReader object that will parse the CBOR stream found by
801 reading from \a device. QCborStreamReader does not take ownership of \a
802 device, so it must remain valid until this object is destroyed.
803 */
804QCborStreamReader::QCborStreamReader(QIODevice *device)
805 : d(new QCborStreamReaderPrivate(device))
806{
807 preparse();
808}
809
810/*!
811 Destroys this QCborStreamReader object and frees any associated resources.
812 */
813QCborStreamReader::~QCborStreamReader()
814{
815}
816
817/*!
818 Sets the source of data to \a device, resetting the decoder to its initial
819 state.
820 */
821void QCborStreamReader::setDevice(QIODevice *device)
822{
823 d->setDevice(device);
824 preparse();
825}
826
827/*!
828 Returns the QIODevice that was set with either setDevice() or the
829 QCborStreamReader constructor. If this object was reading from a QByteArray,
830 this function returns nullptr instead.
831 */
832QIODevice *QCborStreamReader::device() const
833{
834 return d->device;
835}
836
837/*!
838 Adds \a data to the CBOR stream and reparses the current element. This
839 function is useful if the end of the data was previously reached while
840 processing the stream, but now more data is available.
841 */
842void QCborStreamReader::addData(const QByteArray &data)
843{
844 addData(data.constBegin(), data.size());
845}
846
847/*!
848 \fn void QCborStreamReader::addData(const quint8 *data, qsizetype len)
849 \overload
850
851 Adds \a len bytes of data starting at \a data to the CBOR stream and
852 reparses the current element. This function is useful if the end of the data
853 was previously reached while processing the stream, but now more data is
854 available.
855 */
856
857/*!
858 \overload
859
860 Adds \a len bytes of data starting at \a data to the CBOR stream and
861 reparses the current element. This function is useful if the end of the data
862 was previously reached while processing the stream, but now more data is
863 available.
864 */
865void QCborStreamReader::addData(const char *data, qsizetype len)
866{
867 if (!d->device) {
868 if (len > 0)
869 d->buffer.append(data, len);
870 reparse();
871 } else {
872 qWarning("QCborStreamReader: addData() with device()");
873 }
874}
875
876/*!
877 Reparses the current element. This function must be called when more data
878 becomes available in the source QIODevice after parsing failed due to
879 reaching the end of the input data before the end of the CBOR stream.
880
881 When reading from QByteArray(), the addData() function automatically calls
882 this function. Calling it when the reading had not failed is a no-op.
883 */
884void QCborStreamReader::reparse()
885{
886 d->lastError = {};
887 d->preread();
888 if (CborError err = cbor_value_reparse(&d->currentElement))
889 d->handleError(err);
890 else
891 preparse();
892}
893
894/*!
895 Clears the decoder state and resets the input source data to an empty byte
896 array. After this function is called, QCborStreamReader will be indicating
897 an error parsing.
898
899 Call addData() to add more data to be parsed.
900
901 \sa reset(), setDevice()
902 */
903void QCborStreamReader::clear()
904{
905 setDevice(nullptr);
906}
907
908/*!
909 Resets the source back to the beginning and clears the decoder state. If the
910 source data was a QByteArray, QCborStreamReader will restart from the
911 beginning of the array.
912
913 If the source data is a QIODevice, this function will call
914 QIODevice::reset(), which will seek to byte position 0. If the CBOR stream
915 is not found at the beginning of the device (e.g., beginning of a file),
916 then this function will likely do the wrong thing. Instead, position the
917 QIODevice to the right offset and call setDevice().
918
919 \sa clear(), setDevice()
920 */
921void QCborStreamReader::reset()
922{
923 if (d->device)
924 d->device->reset();
925 d->lastError = {};
926 d->initDecoder();
927 preparse();
928}
929
930/*!
931 Returns the last error in decoding the stream, if any. If no error
932 was encountered, this returns an QCborError::NoError.
933
934 \sa isValid()
935 */
936QCborError QCborStreamReader::lastError() const
937{
938 return d->lastError;
939}
940
941/*!
942 Returns the offset in the input stream of the item currently being decoded.
943 The current offset is the number of decoded bytes so far only if the source
944 data is a QByteArray or it is a QIODevice that was positioned at its
945 beginning when decoding started.
946
947 \sa reset(), clear(), device()
948 */
949qint64 QCborStreamReader::currentOffset() const
950{
951 return (d->device ? d->device->pos() : 0) + d->bufferStart;
952}
953
954/*!
955 Returns the number of containers that this stream has entered with
956 enterContainer() but not yet left.
957
958 \sa enterContainer(), leaveContainer()
959 */
960int QCborStreamReader::containerDepth() const
961{
962 return d->containerStack.size();
963}
964
965/*!
966 Returns either QCborStreamReader::Array or QCborStreamReader::Map,
967 indicating whether the container that contains the current item was an array
968 or map, respectively. If we're currently parsing the root element, this
969 function returns QCborStreamReader::Invalid.
970
971 \sa containerDepth(), enterContainer()
972 */
973QCborStreamReader::Type QCborStreamReader::parentContainerType() const
974{
975 if (d->containerStack.isEmpty())
976 return Invalid;
977 return Type(cbor_value_get_type(&std::as_const(d->containerStack).top()));
978}
979
980/*!
981 Returns true if there are more items to be decoded in the current container
982 or false of we've reached its end. If we're parsing the root element,
983 hasNext() returning false indicates the parsing is complete; otherwise, if
984 the container depth is non-zero, then the outer code needs to call
985 leaveContainer().
986
987 \sa parentContainerType(), containerDepth(), leaveContainer()
988 */
989bool QCborStreamReader::hasNext() const noexcept
990{
991 return cbor_value_is_valid(&d->currentElement) &&
992 !cbor_value_at_end(&d->currentElement);
993}
994
995/*!
996 Advance the CBOR stream decoding one element. You should usually call this
997 function when parsing fixed-width basic elements (that is, integers, simple
998 values, tags and floating point values). But this function can be called
999 when the current item is a string, array or map too and it will skip over
1000 that entire element, including all contained elements.
1001
1002 This function returns true if advancing was successful, false otherwise. It
1003 may fail if the stream is corrupt, incomplete or if the nesting level of
1004 arrays and maps exceeds \a maxRecursion. Calling this function when
1005 hasNext() has returned false is also an error. If this function returns
1006 false, lastError() will return the error code detailing what the failure
1007 was.
1008
1009 \sa lastError(), isValid(), hasNext()
1010 */
1011bool QCborStreamReader::next(int maxRecursion)
1012{
1013 if (lastError() != QCborError::NoError)
1014 return false;
1015
1016 if (!hasNext()) {
1017 d->handleError(CborErrorAdvancePastEOF);
1018 } else if (maxRecursion < 0) {
1019 d->handleError(CborErrorNestingTooDeep);
1020 } else if (isContainer()) {
1021 // iterate over each element
1022 enterContainer();
1023 while (lastError() == QCborError::NoError && hasNext())
1024 next(maxRecursion - 1);
1025 if (lastError() == QCborError::NoError)
1026 leaveContainer();
1027 } else if (isByteArray()) {
1028 char c;
1029 StringResult<qsizetype> r;
1030 do {
1031 r = readStringChunk(&c, 1);
1032 } while (r.status == Ok);
1033 } else if (isString()) {
1034 // we need to use actual readString so we get UTF-8 validation
1035 StringResult<QString> r;
1036 do {
1037 r = readString();
1038 } while (r.status == Ok);
1039 } else {
1040 // fixed types
1041 CborError err = cbor_value_advance_fixed(&d->currentElement);
1042 if (err)
1043 d->handleError(err);
1044 }
1045
1046 preparse();
1047 return d->lastError == QCborError::NoError;
1048}
1049
1050/*!
1051 Returns true if the length of the current array, map, byte array or string
1052 is known (explicit in the CBOR stream), false otherwise. This function
1053 should only be called if the element is one of those.
1054
1055 If the length is known, it may be obtained by calling length().
1056
1057 If the length of a map or an array is not known, it is implied by the number
1058 of elements present in the stream. QCborStreamReader has no API to calculate
1059 the length in that condition.
1060
1061 Strings and byte arrays may also have indeterminate length (that is, they
1062 may be transmitted in multiple chunks). Those cannot currently be created
1063 with QCborStreamWriter, but they could be with other encoders, so
1064 QCborStreamReader supports them.
1065
1066 \sa length(), QCborStreamWriter::startArray(), QCborStreamWriter::startMap()
1067 */
1068bool QCborStreamReader::isLengthKnown() const noexcept
1069{
1070 return cbor_value_is_length_known(&d->currentElement);
1071}
1072
1073/*!
1074 Returns the length of the string or byte array, or the number of items in an
1075 array or the number, of item pairs in a map, if known. This function must
1076 not be called if the length is unknown (that is, if isLengthKnown() returned
1077 false). It is an error to do that and it will cause QCborStreamReader to
1078 stop parsing the input stream.
1079
1080 \sa isLengthKnown(), QCborStreamWriter::startArray(), QCborStreamWriter::startMap()
1081 */
1082quint64 QCborStreamReader::length() const
1083{
1084 CborError err;
1085 switch (type()) {
1086 case String:
1087 case ByteArray:
1088 case Map:
1089 case Array:
1090 if (isLengthKnown())
1091 return value64;
1092 err = CborErrorUnknownLength;
1093 break;
1094
1095 default:
1096 err = CborErrorIllegalType;
1097 break;
1098 }
1099
1100 d->handleError(err);
1101 return quint64(-1);
1102}
1103
1104/*!
1105 \fn bool QCborStreamReader::enterContainer()
1106
1107 Enters the array or map that is the current item and prepares for iterating
1108 the elements contained in the container. Returns true if entering the
1109 container succeeded, false otherwise (usually, a parsing error). Each call
1110 to enterContainer() must be paired with a call to leaveContainer().
1111
1112 This function may only be called if the current item is an array or a map
1113 (that is, if isArray(), isMap() or isContainer() is true). Calling it in any
1114 other condition is an error.
1115
1116 \sa leaveContainer(), isContainer(), isArray(), isMap()
1117 */
1118bool QCborStreamReader::_enterContainer_helper()
1119{
1120 d->containerStack.push(d->currentElement);
1121 CborError err = cbor_value_enter_container(&d->containerStack.top(), &d->currentElement);
1122 if (!err) {
1123 preparse();
1124 return true;
1125 }
1126 d->handleError(err);
1127 return false;
1128}
1129
1130/*!
1131 Leaves the array or map whose items were being processed and positions the
1132 decoder at the next item after the end of the container. Returns true if
1133 leaving the container succeeded, false otherwise (usually, a parsing error).
1134 Each call to enterContainer() must be paired with a call to
1135 leaveContainer().
1136
1137 This function may only be called if hasNext() has returned false and
1138 containerDepth() is not zero. Calling it in any other condition is an error.
1139
1140 \sa enterContainer(), parentContainerType(), containerDepth()
1141 */
1142bool QCborStreamReader::leaveContainer()
1143{
1144 if (d->containerStack.isEmpty()) {
1145 qWarning("QCborStreamReader::leaveContainer: trying to leave top-level element");
1146 return false;
1147 }
1148 if (d->corrupt)
1149 return false;
1150
1151 CborValue container = d->containerStack.pop();
1152 CborError err = cbor_value_leave_container(&container, &d->currentElement);
1153 d->currentElement = container;
1154 if (err) {
1155 d->handleError(err);
1156 return false;
1157 }
1158
1159 preparse();
1160 return true;
1161}
1162
1163/*!
1164 \fn bool QCborStreamReader::toBool() const
1165
1166 Returns the boolean value of the current element.
1167
1168 This function does not perform any type conversions, including from integer.
1169 Therefore, it may only be called if isTrue(), isFalse() or isBool() returned
1170 true; calling it in any other condition is an error.
1171
1172 \sa isBool(), isTrue(), isFalse(), toInteger()
1173 */
1174
1175/*!
1176 \fn QCborTag QCborStreamReader::toTag() const
1177
1178 Returns the tag value of the current element.
1179
1180 This function does not perform any type conversions, including from integer.
1181 Therefore, it may only be called if isTag() is true; calling it in any other
1182 condition is an error.
1183
1184 Tags are 64-bit numbers attached to generic CBOR types that give them
1185 further meaning. For a list of known tags, see the \l QCborKnownTags
1186 enumeration.
1187
1188 \sa isTag(), toInteger(), QCborKnownTags
1189 */
1190
1191/*!
1192 \fn quint64 QCborStreamReader::toUnsignedInteger() const
1193
1194 Returns the unsigned integer value of the current element.
1195
1196 This function does not perform any type conversions, including from boolean
1197 or CBOR tag. Therefore, it may only be called if isUnsignedInteger() is
1198 true; calling it in any other condition is an error.
1199
1200 This function may be used to obtain numbers beyond the range of the return
1201 type of toInteger().
1202
1203 \sa type(), toInteger(), isUnsignedInteger(), isNegativeInteger()
1204 */
1205
1206/*!
1207 \fn QCborNegativeValue QCborStreamReader::toNegativeInteger() const
1208
1209 Returns the negative integer value of the current element.
1210 QCborNegativeValue is a 64-bit unsigned integer containing the absolute
1211 value of the negative number that was stored in the CBOR stream.
1212 Additionally, QCborNegativeValue(0) represents the number -2\sup{64}.
1213
1214 This function does not perform any type conversions, including from boolean
1215 or CBOR tag. Therefore, it may only be called if isNegativeInteger() is
1216 true; calling it in any other condition is an error.
1217
1218 This function may be used to obtain numbers beyond the range of the return
1219 type of toInteger(). However, use of negative numbers smaller than -2\sup{63}
1220 is extremely discouraged.
1221
1222 \sa type(), toInteger(), isNegativeInteger(), isUnsignedInteger()
1223 */
1224
1225/*!
1226 \fn qint64 QCborStreamReader::toInteger() const
1227
1228 Returns the integer value of the current element, be it negative, positive
1229 or zero. If the value is larger than 2\sup{63} - 1 or smaller than
1230 -2\sup{63}, the returned value will overflow and will have an incorrect
1231 sign. If handling those values is required, use toUnsignedInteger() or
1232 toNegativeInteger() instead.
1233
1234 This function does not perform any type conversions, including from boolean
1235 or CBOR tag. Therefore, it may only be called if isInteger() is true;
1236 calling it in any other condition is an error.
1237
1238 \sa isInteger(), toUnsignedInteger(), toNegativeInteger()
1239 */
1240
1241/*!
1242 \fn QCborSimpleType QCborStreamReader::toSimpleType() const
1243
1244 Returns value of the current simple type.
1245
1246 This function does not perform any type conversions, including from integer.
1247 Therefore, it may only be called if isSimpleType() is true; calling it in
1248 any other condition is an error.
1249
1250 \sa isSimpleType(), isTrue(), isFalse(), isBool(), isNull(), isUndefined()
1251 */
1252
1253/*!
1254 \fn qfloat16 QCborStreamReader::toFloat16() const
1255
1256 Returns the 16-bit half-precision floating point value of the current element.
1257
1258 This function does not perform any type conversions, including from other
1259 floating point types or from integer values. Therefore, it may only be
1260 called if isFloat16() is true; calling it in any other condition is an
1261 error.
1262
1263 \sa isFloat16(), toFloat(), toDouble()
1264 */
1265
1266/*!
1267 \fn float QCborStreamReader::toFloat() const
1268
1269 Returns the 32-bit single-precision floating point value of the current
1270 element.
1271
1272 This function does not perform any type conversions, including from other
1273 floating point types or from integer values. Therefore, it may only be
1274 called if isFloat() is true; calling it in any other condition is an error.
1275
1276 \sa isFloat(), toFloat16(), toDouble()
1277 */
1278
1279/*!
1280 \fn double QCborStreamReader::toDouble() const
1281
1282 Returns the 64-bit double-precision floating point value of the current
1283 element.
1284
1285 This function does not perform any type conversions, including from other
1286 floating point types or from integer values. Therefore, it may only be
1287 called if isDouble() is true; calling it in any other condition is an error.
1288
1289 \sa isDouble(), toFloat16(), toFloat()
1290 */
1291
1292/*!
1293 \fn QCborStreamReader::StringResult<QString> QCborStreamReader::readString()
1294
1295 Decodes one string chunk from the CBOR string and returns it. This function
1296 is used for both regular and chunked string contents, so the caller must
1297 always loop around calling this function, even if isLengthKnown()
1298 is true. The typical use of this function is as follows:
1299
1300 \snippet code/src_corelib_serialization_qcborstream.cpp 27
1301
1302 The readAllString() function implements the above loop and some extra checks.
1303
1304//! [string-no-type-conversions]
1305 This function does not perform any type conversions, including from integers
1306 or from byte arrays. Therefore, it may only be called if isString() returned
1307 true; calling it in any other condition is an error.
1308//! [string-no-type-conversions]
1309
1310 \sa readAllString(), readByteArray(), isString(), readStringChunk()
1311 */
1312QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
1313{
1314 QCborStreamReader::StringResult<QString> result;
1315 auto r = d->readStringChunk(&result.data);
1316 result.status = r.status;
1317 if (r.status == Error) {
1318 result.data.clear();
1319 } else {
1320 Q_ASSERT(r.data == result.data.size());
1321 if (r.status == EndOfString && lastError() == QCborError::NoError)
1322 preparse();
1323 }
1324
1325 return result;
1326}
1327
1328/*!
1329 \fn QCborStreamReader::StringResult<QByteArray> QCborStreamReader::readUtf8String()
1330 \since 6.7
1331
1332 Decodes one string chunk from the CBOR string and returns it. This function
1333 is used for both regular and chunked string contents, so the caller must
1334 always loop around calling this function, even if isLengthKnown() is true.
1335 The typical use of this function is as for readString() in the following:
1336
1337 \snippet code/src_corelib_serialization_qcborstream.cpp 27
1338
1339 The readAllUtf8String() function implements the above loop and some extra checks.
1340
1341 \include qcborstreamreader.cpp string-no-type-conversions
1342
1343 \sa readAllString(), readByteArray(), isString(), readStringChunk()
1344 */
1345QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readUtf8String_helper()
1346{
1347 using P = QCborStreamReaderPrivate::ReadStringChunk;
1348 QCborStreamReader::StringResult<QByteArray> result;
1349 auto r = d->readStringChunk(P{ &result.data, P::Utf8String });
1350 result.status = r.status;
1351 if (r.status == Error) {
1352 result.data.clear();
1353 } else {
1354 Q_ASSERT(r.data == result.data.size());
1355 if (r.status == EndOfString && lastError() == QCborError::NoError)
1356 preparse();
1357 }
1358
1359 return result;
1360}
1361
1362/*!
1363 \fn QCborStreamReader::StringResult<QByteArray> QCborStreamReader::readByteArray()
1364
1365 Decodes one byte array chunk from the CBOR string and returns it. This
1366 function is used for both regular and chunked contents, so the caller must
1367 always loop around calling this function, even if isLengthKnown()
1368 is true. The typical use of this function is as follows:
1369
1370 \snippet code/src_corelib_serialization_qcborstream.cpp 28
1371
1372 The readAllByteArray() function implements the above loop and some extra checks.
1373
1374//! [bytearray-no-type-conversions]
1375 This function does not perform any type conversions, including from integers
1376 or from strings. Therefore, it may only be called if isByteArray() is true;
1377 calling it in any other condition is an error.
1378//! [bytearray-no-type-conversions]
1379
1380 \sa readAllByteArray(), readString(), isByteArray(), readStringChunk()
1381 */
1382QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readByteArray_helper()
1383{
1384 QCborStreamReader::StringResult<QByteArray> result;
1385 auto r = d->readStringChunk(&result.data);
1386 result.status = r.status;
1387 if (r.status == Error) {
1388 result.data.clear();
1389 } else {
1390 Q_ASSERT(r.data == result.data.size());
1391 if (r.status == EndOfString && lastError() == QCborError::NoError)
1392 preparse();
1393 }
1394
1395 return result;
1396}
1397
1398/*!
1399 \fn qsizetype QCborStreamReader::currentStringChunkSize() const
1400
1401 Returns the size of the current text or byte string chunk. If the CBOR
1402 stream contains a non-chunked string (that is, if isLengthKnown() returns
1403 \c true), this function returns the size of the entire string, the same as
1404 length().
1405
1406 This function is useful to pre-allocate the buffer whose pointer can be passed
1407 to readStringChunk() later.
1408
1409 \sa readString(), readByteArray(), readStringChunk()
1410 */
1411qsizetype QCborStreamReader::_currentStringChunkSize() const
1412{
1413 if (!d->ensureStringIteration())
1414 return -1;
1415
1416 size_t len;
1417 CborError err = cbor_value_get_string_chunk_size(&d->currentElement, &len);
1418 if (err == CborErrorNoMoreStringChunks)
1419 return 0; // not a real error
1420 else if (err)
1421 d->handleError(err);
1422 else if (qsizetype(len) < 0)
1423 d->handleError(CborErrorDataTooLarge);
1424 else
1425 return qsizetype(len);
1426 return -1;
1427}
1428
1430{
1431 auto r = readStringChunk(params);
1432 while (r.status == QCborStreamReader::Ok) {
1433 // keep appending
1434 r = readStringChunk(params);
1435 }
1436
1437 bool ok = r.status == QCborStreamReader::EndOfString;
1438 Q_ASSERT(ok == !lastError);
1439 return ok;
1440}
1441
1442/*!
1443 \fn QCborStreamReader::readAllString()
1444 \since 6.7
1445
1446 Decodes the current text string and returns it. If the string is chunked,
1447 this function will iterate over all chunks and concatenate them. If an
1448 error happens, this function returns a default-constructed QString(), but
1449 that may not be distinguishable from certain empty text strings. Instead,
1450 check lastError() to determine if an error has happened.
1451
1452 \include qcborstreamreader.cpp string-no-type-conversions
1453
1454//! [note-not-restartable]
1455 \note This function cannot be resumed. That is, this function should not
1456 be used in contexts where the CBOR data may still be received, for example
1457 from a socket or pipe. It should only be used when the full data has
1458 already been received and is available in the input QByteArray or
1459 QIODevice.
1460//! [note-not-restartable]
1461
1462 \sa readString(), readStringChunk(), isString(), readAllByteArray()
1463 */
1464/*!
1465 \fn QCborStreamReader::readAndAppendToString(QString &dst)
1466 \since 6.7
1467
1468 Decodes the current text string and appends to \a dst. If the string is
1469 chunked, this function will iterate over all chunks and concatenate them.
1470 If an error happens during decoding, other chunks that could be decoded
1471 successfully may have been written to \a dst nonetheless. Returns \c true
1472 if the decoding happened without errors, \c false otherwise.
1473
1474 \include qcborstreamreader.cpp string-no-type-conversions
1475
1476 \include qcborstreamreader.cpp note-not-restartable
1477
1478 \sa readString(), readStringChunk(), isString(), readAndAppendToByteArray()
1479 */
1480bool QCborStreamReader::_readAndAppendToString_helper(QString &dst)
1481{
1482 bool ok = d->readFullString(&dst);
1483 if (ok)
1484 preparse();
1485 return ok;
1486}
1487
1488/*!
1489 \fn QCborStreamReader::readAllUtf8String()
1490 \since 6.7
1491
1492 Decodes the current text string and returns it. If the string is chunked,
1493 this function will iterate over all chunks and concatenate them. If an
1494 error happens, this function returns a default-constructed QString(), but
1495 that may not be distinguishable from certain empty text strings. Instead,
1496 check lastError() to determine if an error has happened.
1497
1498 \include qcborstreamreader.cpp string-no-type-conversions
1499
1500 \include qcborstreamreader.cpp note-not-restartable
1501
1502 \sa readString(), readStringChunk(), isString(), readAllByteArray()
1503 */
1504/*!
1505 \fn QCborStreamReader::readAndAppendToUtf8String(QByteArray &dst)
1506 \since 6.7
1507
1508 Decodes the current text string and appends to \a dst. If the string is
1509 chunked, this function will iterate over all chunks and concatenate them.
1510 If an error happens during decoding, other chunks that could be decoded
1511 successfully may have been written to \a dst nonetheless. Returns \c true
1512 if the decoding happened without errors, \c false otherwise.
1513
1514 \include qcborstreamreader.cpp string-no-type-conversions
1515
1516 \include qcborstreamreader.cpp note-not-restartable
1517
1518 \sa readString(), readStringChunk(), isString(), readAndAppendToByteArray()
1519 */
1520bool QCborStreamReader::_readAndAppendToUtf8String_helper(QByteArray &dst)
1521{
1522 using P = QCborStreamReaderPrivate::ReadStringChunk;
1523 bool ok = d->readFullString({ &dst, P::Utf8String });
1524 if (ok)
1525 preparse();
1526 return ok;
1527}
1528
1529/*!
1530 \fn QCborStreamReader::readAllByteArray()
1531 \since 6.7
1532
1533 Decodes the current byte string and returns it. If the string is chunked,
1534 this function will iterate over all chunks and concatenate them. If an
1535 error happens, this function returns a default-constructed QByteArray(),
1536 but that may not be distinguishable from certain empty byte strings.
1537 Instead, check lastError() to determine if an error has happened.
1538
1539 \include qcborstreamreader.cpp bytearray-no-type-conversions
1540
1541 \include qcborstreamreader.cpp note-not-restartable
1542
1543 \sa readByteArray(), readStringChunk(), isByteArray(), readAllString()
1544 */
1545
1546/*!
1547 \fn QCborStreamReader::readAndAppendToByteArray(QByteArray &dst)
1548 \since 6.7
1549
1550 Decodes the current byte string and appends to \a dst. If the string is
1551 chunked, this function will iterate over all chunks and concatenate them.
1552 If an error happens during decoding, other chunks that could be decoded
1553 successfully may have been written to \a dst nonetheless. Returns \c true
1554 if the decoding happened without errors, \c false otherwise.
1555
1556 \include qcborstreamreader.cpp bytearray-no-type-conversions
1557
1558 \include qcborstreamreader.cpp note-not-restartable
1559
1560 \sa readByteArray(), readStringChunk(), isByteArray(), readAndAppendToString()
1561 */
1562bool QCborStreamReader::_readAndAppendToByteArray_helper(QByteArray &dst)
1563{
1564 bool ok = d->readFullString(&dst);
1565 if (ok)
1566 preparse();
1567 return ok;
1568}
1569
1570/*!
1571 Reads the current string chunk into the buffer pointed to by \a ptr, whose
1572 size is \a maxlen. This function returns a \l StringResult object, with the
1573 number of bytes copied into \a ptr saved in the \c \l StringResult::data
1574 member. The \c \l StringResult::status member indicates whether there was
1575 an error reading the string, whether data was copied or whether this was
1576 the last chunk.
1577
1578 This function can be called for both \l String and \l ByteArray types.
1579 For the latter, this function will read the same data that readByteArray()
1580 would have returned. For strings, it returns the UTF-8 equivalent of the \l
1581 QString that would have been returned.
1582
1583 This function is usually used alongside currentStringChunkSize() in a loop.
1584 For example:
1585
1586 \snippet code/src_corelib_serialization_qcborstream.cpp 29
1587
1588 Unlike readByteArray() and readString(), this function is not limited by
1589 implementation limits of QByteArray and QString.
1590
1591 \note This function does not perform verification that the UTF-8 contents
1592 are properly formatted. That means this function does not produce the
1593 QCborError::InvalidUtf8String error, even when readString() does.
1594
1595 \sa currentStringChunkSize(), readString(), readByteArray(),
1596 isString(), isByteArray()
1597 */
1598QCborStreamReader::StringResult<qsizetype>
1599QCborStreamReader::readStringChunk(char *ptr, qsizetype maxlen)
1600{
1601 auto r = d->readStringChunk({ptr, maxlen});
1602 if (r.status == EndOfString && lastError() == QCborError::NoError)
1603 preparse();
1604 return r;
1605}
1606
1607// used by qcborvalue.cpp
1608QCborStreamReader::StringResultCode qt_cbor_append_string_chunk(QCborStreamReader &reader, QByteArray *data)
1609{
1610 return QCborStreamReaderPrivate::appendStringChunk(reader, data);
1611}
1612
1613inline QCborStreamReader::StringResultCode
1614QCborStreamReaderPrivate::appendStringChunk(QCborStreamReader &reader, QByteArray *data)
1615{
1616 auto status = reader.d->readStringChunk(data).status;
1617 if (status == QCborStreamReader::EndOfString && reader.lastError() == QCborError::NoError)
1618 reader.preparse();
1619 return status;
1620}
1621
1622Q_NEVER_INLINE QCborStreamReader::StringResult<qsizetype>
1623QCborStreamReaderPrivate::readStringChunk(ReadStringChunk params)
1624{
1625 CborError err;
1626 size_t len;
1627 const void *content = nullptr;
1628 QCborStreamReader::StringResult<qsizetype> result;
1629 result.data = 0;
1630 result.status = QCborStreamReader::Error;
1631
1632 lastError = {};
1633 if (!ensureStringIteration())
1634 return result;
1635
1636 // Note: in the current implementation, the call into TinyCBOR below only
1637 // succeeds if we *already* have all the data in memory. That's obvious for
1638 // the case of direct memory (no QIODevice), whereas for QIODevices
1639 // qt_cbor_decoder_transfer_string() enforces that
1640 // QIODevice::bytesAvailable() be bigger than the amount we're about to
1641 // read.
1642 //
1643 // This is an important security gate: if the CBOR stream is corrupt or
1644 // malicious, and has an impossibly large string size, we only go past it
1645 // if the transfer to the destination buffer will succeed (modulo QIODevice
1646 // I/O failures).
1647
1648#if 1
1649 // Using internal TinyCBOR API!
1650 err = _cbor_value_get_string_chunk(&currentElement, &content, &len, &currentElement);
1651#else
1652 // the above is effectively the same as:
1653 if (cbor_value_is_byte_string(&currentElement))
1654 err = cbor_value_get_byte_string_chunk(&currentElement, reinterpret_cast<const uint8_t **>(&content),
1655 &len, &currentElement);
1656 else
1657 err = cbor_value_get_text_string_chunk(&currentElement, reinterpret_cast<const char **>(&content),
1658 &len, &currentElement);
1659#endif
1660
1661 // Range check: using implementation-defined behavior in converting an
1662 // unsigned value out of range of the destination signed type (same as
1663 // "len > size_t(std::numeric_limits<qsizetype>::max())", but generates
1664 // better code with ICC and MSVC).
1665 if (!err && qsizetype(len) < 0)
1666 err = CborErrorDataTooLarge;
1667
1668 if (err) {
1669 if (err == CborErrorNoMoreStringChunks) {
1670 preread();
1671 err = cbor_value_finish_string_iteration(&currentElement);
1672 result.status = QCborStreamReader::EndOfString;
1673 }
1674 if (err)
1675 handleError(err);
1676 // caller musts call preparse()
1677 return result;
1678 }
1679
1680 qptrdiff offset = qptrdiff(content);
1681 bufferStart += offset;
1682 if (device) {
1683 // This first skip can't fail because we've already read this many bytes.
1684 device->skip(bufferStart);
1685 }
1686
1687 if (params.isString()) {
1688 // readString()
1689 result.data = readStringChunk_unicode(params, qsizetype(len));
1690 } else if (params.isUtf8String()) {
1691 result.data = readStringChunk_utf8(params, qsizetype(len));
1692 } else {
1693 // readByteArray() or readStringChunk()
1694 result.data = readStringChunk_byte(params, qsizetype(len));
1695 }
1696
1697 if (result.data < 0)
1698 return result; // error
1699
1700 // adjust the buffers after we're done reading the string
1701 bufferStart += len;
1702 if (device) {
1703 qsizetype remainingInBuffer = buffer.size() - bufferStart;
1704
1705 if (remainingInBuffer <= 0) {
1706 // We've read from the QIODevice more than what was in the buffer.
1707 buffer.truncate(0);
1708 } else {
1709 // There's still data buffered, but we need to move it around.
1710 char *ptr = buffer.data();
1711 memmove(ptr, ptr + bufferStart, remainingInBuffer);
1712 buffer.truncate(remainingInBuffer);
1713 }
1714
1715 bufferStart = 0;
1716 }
1717
1718 preread();
1719 result.status = QCborStreamReader::Ok;
1720 return result;
1721}
1722
1723inline qsizetype
1725{
1726 qint64 actuallyRead;
1727 qsizetype toRead = qsizetype(len);
1728 qsizetype left = 0; // bytes from the chunk not copied to the user buffer, to discard
1729 char *ptr = nullptr;
1730
1731 if (params.isPlainPointer()) {
1732 left = toRead - params.maxlen_or_type;
1733 if (left < 0)
1734 left = 0; // buffer bigger than string
1735 else
1736 toRead = params.maxlen_or_type; // buffer smaller than string
1737 ptr = params.ptr;
1738 } else if (!params.isString()) {
1739 // See note above on having ensured there is enough incoming data.
1740 auto oldSize = params.array->size();
1741 auto newSize = oldSize;
1742 if (qAddOverflow<decltype(newSize)>(oldSize, toRead, &newSize)) {
1743 handleError(CborErrorDataTooLarge);
1744 return -1;
1745 }
1746 QT_TRY {
1747 params.array->resize(newSize);
1748 } QT_CATCH (const std::bad_alloc &) {
1749 // the distinction between DataTooLarge and OOM is mostly for
1750 // compatibility with Qt 5; in Qt 6, we could consider everything
1751 // to be OOM.
1752 handleError(newSize > QByteArray::maxSize() ? CborErrorDataTooLarge: CborErrorOutOfMemory);
1753 return -1;
1754 }
1755
1756 ptr = const_cast<char *>(params.array->constBegin()) + oldSize;
1757 }
1758
1759 if (device) {
1760 actuallyRead = device->read(ptr, toRead);
1761
1762 if (actuallyRead != toRead) {
1763 actuallyRead = -1;
1764 } else if (left) {
1765 qint64 skipped = device->skip(left);
1766 if (skipped != left)
1767 actuallyRead = -1;
1768 }
1769
1770 if (actuallyRead < 0) {
1771 handleError(CborErrorIO);
1772 return -1;
1773 }
1774 } else {
1775 actuallyRead = toRead;
1776 memcpy(ptr, buffer.constBegin() + bufferStart, toRead);
1777 }
1778
1779 return actuallyRead;
1780}
1781
1782inline qsizetype
1784{
1785 Q_ASSERT(params.isString());
1786
1787 // See QUtf8::convertToUnicode() a detailed explanation of why this
1788 // conversion uses the same number of words or less.
1789 qsizetype currentSize = params.string->size();
1790 size_t newSize = size_t(utf8len) + size_t(currentSize); // can't overflow
1791 if (utf8len > QString::maxSize() || qsizetype(newSize) < 0) {
1792 handleError(CborErrorDataTooLarge);
1793 return -1;
1794 }
1795 QT_TRY {
1796 params.string->resize(qsizetype(newSize));
1797 } QT_CATCH (const std::bad_alloc &) {
1798 handleError(CborErrorOutOfMemory);
1799 return -1;
1800 }
1801
1802 QChar *begin = const_cast<QChar *>(params.string->constBegin());
1803 QChar *ptr = begin + currentSize;
1804 QStringConverter::State cs(QStringConverter::Flag::Stateless);
1805 if (device == nullptr) {
1806 // Easy case: we can decode straight from the buffer we already have
1807 ptr = QUtf8::convertToUnicode(ptr, { buffer.constBegin() + bufferStart, utf8len }, &cs);
1808 } else {
1809 // read in chunks, to avoid creating large, intermediate buffers
1810 constexpr qsizetype StringChunkSize = 16384;
1811 qsizetype chunkSize = qMin(StringChunkSize, utf8len);
1812 QVarLengthArray<char> chunk(chunkSize);
1813
1814 cs = { QStringConverter::Flag::ConvertInitialBom };
1815 while (utf8len > 0 && cs.invalidChars == 0) {
1816 qsizetype toRead = qMin(chunkSize, utf8len);
1817 qint64 actuallyRead = device->read(chunk.data(), toRead);
1818 if (actuallyRead == toRead)
1819 ptr = QUtf8::convertToUnicode(ptr, { chunk.data(), toRead }, &cs);
1820
1821 if (actuallyRead != toRead) {
1822 handleError(CborErrorIO);
1823 return -1;
1824 }
1825 utf8len -= toRead;
1826 }
1827 }
1828
1829 if (cs.invalidChars != 0 || cs.remainingChars != 0) {
1830 handleError(CborErrorInvalidUtf8TextString);
1831 return -1;
1832 }
1833
1834 qsizetype size = ptr - begin;
1835 params.string->truncate(ptr - begin);
1836 return size - currentSize; // how many bytes we added
1837}
1838
1839inline qsizetype
1841{
1842 qsizetype result = readStringChunk_byte(params, utf8len);
1843 if (result < 0)
1844 return result;
1845
1846 // validate the UTF-8 content we've just read
1847 QByteArrayView chunk = *params.array;
1848 chunk = chunk.last(result);
1849 if (QtPrivate::isValidUtf8(chunk))
1850 return result;
1851
1852 handleError(CborErrorInvalidUtf8TextString);
1853 return -1;
1854}
1855
1856QT_END_NAMESPACE
1857
1858#include "moc_qcborstreamreader.cpp"
void handleError(CborError err) noexcept
QCborStreamReaderPrivate(QIODevice *device)
QByteArray::size_type bufferStart
qsizetype readStringChunk_byte(ReadStringChunk params, qsizetype len)
bool readFullString(ReadStringChunk params)
QStack< CborValue > containerStack
qsizetype readStringChunk_unicode(ReadStringChunk params, qsizetype utf8len)
qsizetype readStringChunk_utf8(ReadStringChunk params, qsizetype utf8len)
void setDevice(QIODevice *dev)
QCborStreamReaderPrivate(const QByteArray &data)
static CborError qt_cbor_decoder_transfer_string(void *token, const void **userptr, size_t offset, size_t len)
QCborStreamReader::StringResultCode qt_cbor_append_string_chunk(QCborStreamReader &reader, QByteArray *data)
static QT_BEGIN_NAMESPACE bool qt_cbor_decoder_can_read(void *token, size_t len)
void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error)
static void qt_cbor_decoder_advance(void *token, size_t len)
static void * qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len)
static CborError cbor_value_get_half_float_as_float(const CborValue *, float *)
ReadStringChunk(QByteArray *array, Type type=ByteArray)