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