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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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