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

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