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