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/qstringconverter_p.h>
48#include <qiodevice.h>
49#include <qdebug.h>
50#include <qstack.h>
51
52QT_BEGIN_NAMESPACE
53
54static bool qt_cbor_decoder_can_read(void *token, size_t len);
55static void qt_cbor_decoder_advance(void *token, size_t len);
56static void *qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len);
57static CborError qt_cbor_decoder_transfer_string(void *token, const void **userptr, size_t offset, size_t len);
58
59#define CBOR_PARSER_READER_CONTROL 1
60#define CBOR_PARSER_CAN_READ_BYTES_FUNCTION qt_cbor_decoder_can_read
61#define CBOR_PARSER_ADVANCE_BYTES_FUNCTION qt_cbor_decoder_advance
62#define CBOR_PARSER_TRANSFER_STRING_FUNCTION qt_cbor_decoder_transfer_string
63#define CBOR_PARSER_READ_BYTES_FUNCTION qt_cbor_decoder_read
64
65QT_WARNING_PUSH
66QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
67
68#include <cborparser.c>
69
70QT_WARNING_POP
71
72static CborError _cbor_value_dup_string(const CborValue *, void **, size_t *, CborValue *)
73{
74 Q_UNREACHABLE();
75 return CborErrorInternalError;
76}
77[[maybe_unused]] static CborError cbor_value_get_half_float_as_float(const CborValue *, float *)
78{
79 Q_UNREACHABLE();
80 return CborErrorInternalError;
81}
82
83// confirm our constants match TinyCBOR's
84static_assert(int(QCborStreamReader::UnsignedInteger) == CborIntegerType);
85static_assert(int(QCborStreamReader::ByteString) == CborByteStringType);
86static_assert(int(QCborStreamReader::TextString) == CborTextStringType);
87static_assert(int(QCborStreamReader::Array) == CborArrayType);
88static_assert(int(QCborStreamReader::Map) == CborMapType);
89static_assert(int(QCborStreamReader::Tag) == CborTagType);
90static_assert(int(QCborStreamReader::SimpleType) == CborSimpleType);
91static_assert(int(QCborStreamReader::HalfFloat) == CborHalfFloatType);
92static_assert(int(QCborStreamReader::Float) == CborFloatType);
93static_assert(int(QCborStreamReader::Double) == CborDoubleType);
94static_assert(int(QCborStreamReader::Invalid) == CborInvalidType);
95
96/*!
97 \class QCborStreamReader
98 \inmodule QtCore
99 \ingroup cbor
100 \reentrant
101 \since 5.12
102
103 \brief The QCborStreamReader class is a simple CBOR stream decoder, operating
104 on either a QByteArray or QIODevice.
105
106 This class can be used to decode a stream of CBOR content directly from
107 either a QByteArray or a QIODevice. CBOR is the Concise Binary Object
108 Representation, a very compact form of binary data encoding that is
109 compatible with JSON. It was created by the IETF Constrained RESTful
110 Environments (CoRE) WG, which has used it in many new RFCs. It is meant to
111 be used alongside the \l{https://tools.ietf.org/html/rfc7252}{CoAP
112 protocol}.
113
114 QCborStreamReader provides a StAX-like API, similar to that of
115 \l{QXmlStreamReader}. Using it requires a bit of knowledge of CBOR encoding.
116 For a simpler API, see \l{QCborValue} and especially the decoding function
117 QCborValue::fromCbor().
118
119 Typically, one creates a QCborStreamReader by passing the source QByteArray
120 or QIODevice as a parameter to the constructor, then pop elements off the
121 stream if there were no errors in decoding. There are three kinds of CBOR
122 types:
123
124 \table
125 \header \li Kind \li Types \li Behavior
126 \row \li Fixed-width \li Integers, Tags, Simple types, Floating point
127 \li Value is pre-parsed by QCborStreamReader, so accessor functions
128 are \c const. Must call next() to advance.
129 \row \li Strings \li Byte arrays, Text strings
130 \li Length (if known) is pre-parsed, but the string itself is not.
131 The accessor functions are not const and may allocate memory.
132 Once called, the accessor functions automatically advance to
133 the next element.
134 \row \li Containers \li Arrays, Maps
135 \li Length (if known) is pre-parsed. To access the elements, you
136 must call enterContainer(), read all elements, then call
137 leaveContainer(). That function advances to the next element.
138 \endtable
139
140 So a processor function typically looks like this:
141
142 \snippet code/src_corelib_serialization_qcborstream.cpp 24
143
144 \section1 CBOR support
145
146 The following table lists the CBOR features that QCborStreamReader supports.
147
148 \table
149 \header \li Feature \li Support
150 \row \li Unsigned numbers \li Yes (full range)
151 \row \li Negative numbers \li Yes (full range)
152 \row \li Byte strings \li Yes
153 \row \li Text strings \li Yes
154 \row \li Chunked strings \li Yes
155 \row \li Tags \li Yes (arbitrary)
156 \row \li Booleans \li Yes
157 \row \li Null \li Yes
158 \row \li Undefined \li Yes
159 \row \li Arbitrary simple values \li Yes
160 \row \li Half-precision float (16-bit) \li Yes
161 \row \li Single-precision float (32-bit) \li Yes
162 \row \li Double-precision float (64-bit) \li Yes
163 \row \li Infinities and NaN floating point \li Yes
164 \row \li Determinate-length arrays and maps \li Yes
165 \row \li Indeterminate-length arrays and maps \li Yes
166 \row \li Map key types other than strings and integers \li Yes (arbitrary)
167 \endtable
168
169 \section1 Dealing with invalid or incomplete CBOR streams
170
171 QCborStreamReader is capable of detecting corrupt input on its own. The
172 library it uses has been extensively tested against invalid input of any
173 kind and is quite able to report errors. If any is detected,
174 QCborStreamReader will set lastError() to a value besides
175 QCborError::NoError, indicating which situation was detected.
176
177 Most errors detected by QCborStreamReader during normal item parsing are not
178 recoverable. The code using QCborStreamReader may opt to handle the data
179 that was properly decoded or it can opt to discard the entire data.
180
181 The only recoverable error is QCborError::EndOfFile, which indicates that
182 more data is required in order to complete the parsing. This situation is
183 useful when data is being read from an asynchronous source, such as a pipe
184 (QProcess) or a socket (QTcpSocket, QUdpSocket, QNetworkReply, etc.). When
185 more data arrives, the surrounding code needs to call either addData(), if
186 parsing from a QByteArray, or reparse(), if it is instead reading directly
187 a the QIDOevice that now has more data available (see setDevice()).
188
189 \sa QCborStreamWriter, QCborValue, QXmlStreamReader
190 */
191
192/*!
193 \enum QCborStreamReader::Type
194
195 This enumeration contains all possible CBOR types as decoded by
196 QCborStreamReader. CBOR has 7 major types, plus a number of simple types
197 carrying no value, and floating point values.
198
199 \value UnsignedInteger (Major type 0) Ranges from 0 to 2\sup{64} - 1
200 (18,446,744,073,709,551,616)
201 \value NegativeInteger (Major type 1) Ranges from -1 to -2\sup{64}
202 (-18,446,744,073,709,551,616)
203 \value ByteArray (Major type 2) Arbitrary binary data.
204 \value ByteString An alias to ByteArray.
205 \value String (Major type 3) Unicode text, possibly containing NULs.
206 \value TextString An alias to String
207 \value Array (Major type 4) Array of heterogeneous items.
208 \value Map (Major type 5) Map/dictionary of heterogeneous items.
209 \value Tag (Major type 6) Numbers giving further semantic value
210 to generic CBOR items. See \l QCborTag for more information.
211 \value SimpleType (Major type 7) Types carrying no further value. Includes
212 booleans (true and false), null, undefined.
213 \value Float16 IEEE 754 half-precision floating point (\c qfloat16).
214 \value HalfFloat An alias to Float16.
215 \value Float IEEE 754 single-precision floating point (\tt float).
216 \value Double IEEE 754 double-precision floating point (\tt double).
217 \value Invalid Not a valid type, either due to parsing error or due to
218 reaching the end of an array or map.
219 */
220
221/*!
222 \enum QCborStreamReader::StringResultCode
223
224 This enum is returned by readString() and readByteArray() and is used to
225 indicate what the status of the parsing is.
226
227 \value EndOfString The parsing for the string is complete, with no error.
228 \value Ok The function returned data; there was no error.
229 \value Error Parsing failed with an error.
230 */
231
232/*!
233 \class QCborStreamReader::StringResult
234 \inmodule QtCore
235
236 This class is returned by readString() and readByteArray(), with either the
237 contents of the string that was read or an indication that the parsing is
238 done or found an error.
239
240 The contents of \l data are valid only if \l status is
241 \l{StringResultCode}{Ok}. Otherwise, it should be null.
242 */
243
244/*!
245 \variable QCborStreamReader::StringResult::data
246
247 Contains the actual data from the string if \l status is \c Ok.
248 */
249
250/*!
251 \variable QCborStreamReader::StringResult::status
252
253 Contains the status of the attempt of reading the string from the stream.
254 */
255
256/*!
257 \fn QCborStreamReader::Type QCborStreamReader::type() const
258
259 Returns the type of the current element. It is one of the valid types or
260 Invalid.
261
262 \sa isValid(), isUnsignedInteger(), isNegativeInteger(), isInteger(),
263 isByteArray(), isString(), isArray(), isMap(), isTag(), isSimpleType(),
264 isBool(), isFalse(), isTrue(), isNull(), isUndefined(), isFloat16(),
265 isFloat(), isDouble()
266 */
267
268/*!
269 \fn bool QCborStreamReader::isValid() const
270
271 Returns true if the current element is valid, false otherwise. The current
272 element may be invalid if there was a decoding error or we've just parsed
273 the last element in an array or map.
274
275 \note This function is not the opposite of isNull(). Null is a normal CBOR
276 type that must be handled by the application.
277
278 \sa type(), isInvalid()
279 */
280
281/*!
282 \fn bool QCborStreamReader::isInvalid() const
283
284 Returns true if the current element is invalid, false otherwise. The current
285 element may be invalid if there was a decoding error or we've just parsed
286 the last element in an array or map.
287
288 \note This function is not to be confused with isNull(). Null is a normal
289 CBOR type that must be handled by the application.
290
291 \sa type(), isValid()
292 */
293
294/*!
295 \fn bool QCborStreamReader::isUnsignedInteger() const
296
297 Returns true if the type of the current element is an unsigned integer (that
298 is if type() returns QCborStreamReader::UnsignedInteger). If this function
299 returns true, you may call toUnsignedInteger() or toInteger() to read that value.
300
301 \sa type(), toUnsignedInteger(), toInteger(), isInteger(), isNegativeInteger()
302 */
303
304/*!
305 \fn bool QCborStreamReader::isNegativeInteger() const
306
307 Returns true if the type of the current element is a negative integer (that
308 is if type() returns QCborStreamReader::NegativeInteger). If this function
309 returns true, you may call toNegativeInteger() or toInteger() to read that value.
310
311 \sa type(), toNegativeInteger(), toInteger(), isInteger(), isUnsignedInteger()
312 */
313
314/*!
315 \fn bool QCborStreamReader::isInteger() const
316
317 Returns true if the type of the current element is either an unsigned
318 integer or a negative one (that is, if type() returns
319 QCborStreamReader::UnsignedInteger or QCborStreamReader::NegativeInteger).
320 If this function returns true, you may call toInteger() to read that
321 value.
322
323 \sa type(), toInteger(), toUnsignedInteger(), toNegativeInteger(),
324 isUnsignedInteger(), isNegativeInteger()
325 */
326
327/*!
328 \fn bool QCborStreamReader::isByteArray() const
329
330 Returns true if the type of the current element is a byte array (that is,
331 if type() returns QCborStreamReader::ByteArray). If this function returns
332 true, you may call readByteArray() to read that data.
333
334 \sa type(), readByteArray(), isString()
335 */
336
337/*!
338 \fn bool QCborStreamReader::isString() const
339
340 Returns true if the type of the current element is a text string (that is,
341 if type() returns QCborStreamReader::String). If this function returns
342 true, you may call readString() to read that data.
343
344 \sa type(), readString(), isByteArray()
345 */
346
347/*!
348 \fn bool QCborStreamReader::isArray() const
349
350 Returns true if the type of the current element is an array (that is,
351 if type() returns QCborStreamReader::Array). If this function returns
352 true, you may call enterContainer() to begin parsing that container.
353
354 When the current element is an array, you may also call isLengthKnown() to
355 find out if the array's size is explicit in the CBOR stream. If it is, that
356 size can be obtained by calling length().
357
358 The following example pre-allocates a QVariantList given the array's size
359 for more efficient decoding:
360
361 \snippet code/src_corelib_serialization_qcborstream.cpp 25
362
363 \note The code above does not validate that the length is a sensible value.
364 If the input stream reports that the length is 1 billion elements, the above
365 function will try to allocate some 16 GB or more of RAM, which can lead to a
366 crash.
367
368 \sa type(), isMap(), isLengthKnown(), length(), enterContainer(), leaveContainer()
369 */
370
371/*!
372 \fn bool QCborStreamReader::isMap() const
373
374 Returns true if the type of the current element is a map (that is, if type()
375 returns QCborStreamReader::Map). If this function returns true, you may call
376 enterContainer() to begin parsing that container.
377
378 When the current element is a map, you may also call isLengthKnown() to
379 find out if the map's size is explicit in the CBOR stream. If it is, that
380 size can be obtained by calling length().
381
382 The following example pre-allocates a QVariantMap given the map's size
383 for more efficient decoding:
384
385 \snippet code/src_corelib_serialization_qcborstream.cpp 26
386
387 The example above uses a function called \c readElementAsString to read the
388 map's keys and obtain a string. That is because CBOR maps may contain any
389 type as keys, not just strings. User code needs to either perform this
390 conversion, reject non-string keys, or instead use a different container
391 besides \l QVariantMap and \l QVariantHash. For example, if the map is
392 expected to contain integer keys, which is recommended as it reduces stream
393 size and parsing, the correct container would be \c{\l{QMap}<int, QVariant>}
394 or \c{\l{QHash}<int, QVariant>}.
395
396 \note The code above does not validate that the length is a sensible value.
397 If the input stream reports that the length is 1 billion elements, the above
398 function will try to allocate some 24 GB or more of RAM, which can lead to a
399 crash.
400
401 \sa type(), isArray(), isLengthKnown(), length(), enterContainer(), leaveContainer()
402 */
403
404/*!
405 \fn bool QCborStreamReader::isTag() const
406
407 Returns true if the type of the current element is a CBOR tag (that is,
408 if type() returns QCborStreamReader::Tag). If this function returns
409 true, you may call toTag() to read that data.
410
411 \sa type(), toTag()
412 */
413
414/*!
415 \fn bool QCborStreamReader::isFloat16() const
416
417 Returns true if the type of the current element is an IEEE 754
418 half-precision floating point (that is, if type() returns
419 QCborStreamReader::Float16). If this function returns true, you may call
420 toFloat16() to read that data.
421
422 \sa type(), toFloat16(), isFloat(), isDouble()
423 */
424
425/*!
426 \fn bool QCborStreamReader::isFloat() const
427
428 Returns true if the type of the current element is an IEEE 754
429 single-precision floating point (that is, if type() returns
430 QCborStreamReader::Float). If this function returns true, you may call
431 toFloat() to read that data.
432
433 \sa type(), toFloat(), isFloat16(), isDouble()
434 */
435
436/*!
437 \fn bool QCborStreamReader::isDouble() const
438
439 Returns true if the type of the current element is an IEEE 754
440 double-precision floating point (that is, if type() returns
441 QCborStreamReader::Double). If this function returns true, you may call
442 toDouble() to read that data.
443
444 \sa type(), toDouble(), isFloat16(), isFloat()
445 */
446
447/*!
448 \fn bool QCborStreamReader::isSimpleType() const
449
450 Returns true if the type of the current element is any CBOR simple type,
451 including a boolean value (true and false) as well as null and undefined. To
452 find out which simple type this is, call toSimpleType(). Alternatively, to
453 test for one specific simple type, call the overload that takes a
454 QCborSimpleType parameter.
455
456 CBOR simple types are types that do not carry extra value. There are 255
457 possibilities, but there are currently only four values that have defined
458 meaning. Code is not expected to cope with unknown simple types and may
459 simply discard the stream as invalid if it finds an unknown one.
460
461 \sa QCborSimpleType, type(), isSimpleType(QCborSimpleType), toSimpleType()
462 */
463
464/*!
465 \fn bool QCborStreamReader::isSimpleType(QCborSimpleType st) const
466
467 Returns true if the type of the current element is the simple type \a st,
468 false otherwise. If this function returns true, then toSimpleType() will
469 return \a st.
470
471 CBOR simple types are types that do not carry extra value. There are 255
472 possibilities, but there are currently only four values that have defined
473 meaning. Code is not expected to cope with unknown simple types and may
474 simply discard the stream as invalid if it finds an unknown one.
475
476 \sa QCborSimpleType, type(), isSimpleType(), toSimpleType()
477 */
478
479/*!
480 \fn bool QCborStreamReader::isFalse() const
481
482 Returns true if the current element is the \c false value, false if it is
483 anything else.
484
485 \sa type(), isTrue(), isBool(), toBool(), isSimpleType(), toSimpleType()
486 */
487
488/*!
489 \fn bool QCborStreamReader::isTrue() const
490
491 Returns true if the current element is the \c true value, false if it is
492 anything else.
493
494 \sa type(), isFalse(), isBool(), toBool(), isSimpleType(), toSimpleType()
495 */
496
497/*!
498 \fn bool QCborStreamReader::isBool() const
499
500 Returns true if the current element is a boolean value (\c true or \c
501 false), false if it is anything else. If this function returns true, you may
502 call toBool() to retrieve the value of the boolean. You may also call
503 toSimpleType() and compare to either QCborSimpleValue::True or
504 QCborSimpleValue::False.
505
506 \sa type(), isFalse(), isTrue(), toBool(), isSimpleType(), toSimpleType()
507 */
508
509/*!
510 \fn bool QCborStreamReader::isNull() const
511
512 Returns true if the current element is the \c null value, false if it is
513 anything else. Null values may be used to indicate the absence of some
514 optional data.
515
516 \note This function is not the opposite of isValid(). A Null value is a
517 valid CBOR value.
518
519 \sa type(), isSimpleType(), toSimpleType()
520 */
521
522/*!
523 \fn bool QCborStreamReader::isUndefined() const
524
525 Returns true if the current element is the \c undefined value, false if it
526 is anything else. Undefined values may be encoded to indicate that some
527 conversion failed or was not possible when creating the stream.
528 QCborStreamReader never performs any replacement and this function will only
529 return true if the stream contains an explicit undefined value.
530
531 \sa type(), isSimpleType(), toSimpleType()
532 */
533
534/*!
535 \fn bool QCborStreamReader::isContainer() const
536
537 Returns true if the current element is a container (that is, an array or a
538 map), false if it is anything else. If the current element is a container,
539 the isLengthKnown() function may be used to find out if the container's size
540 is explicit in the stream and, if so, length() can be used to get that size.
541
542 More importantly, for a container, the enterContainer() function is
543 available to begin iterating through the elements contained therein.
544
545 \sa type(), isArray(), isMap(), isLengthKnown(), length(), enterContainer(),
546 leaveContainer(), containerDepth()
547 */
548
549class QCborStreamReaderPrivate
550{
551public:
552 enum {
553 // 9 bytes is the maximum size for any integer, floating point or
554 // length in CBOR.
555 MaxCborIndividualSize = 9,
556 IdealIoBufferSize = 256
557 };
558
559 QIODevice *device;
560 QByteArray buffer;
561 QStack<CborValue> containerStack;
562
563 CborParser parser;
564 CborValue currentElement;
565 QCborError lastError = {};
566
567 QByteArray::size_type bufferStart;
568 bool corrupt = false;
569
570 QCborStreamReaderPrivate(const QByteArray &data)
571 : device(nullptr), buffer(data)
572 {
573 initDecoder();
574 }
575
576 QCborStreamReaderPrivate(QIODevice *device)
577 {
578 setDevice(device);
579 }
580
581 ~QCborStreamReaderPrivate()
582 {
583 }
584
585 void setDevice(QIODevice *dev)
586 {
587 buffer.clear();
588 device = dev;
589 initDecoder();
590 }
591
592 void initDecoder()
593 {
594 containerStack.clear();
595 bufferStart = 0;
596 if (device) {
597 buffer.clear();
598 buffer.reserve(IdealIoBufferSize); // sets the CapacityReserved flag
599 }
600
601 preread();
602 if (CborError err = cbor_parser_init_reader(nullptr, &parser, &currentElement, this))
603 handleError(err);
604 else
605 lastError = { QCborError::NoError };
606 }
607
608 char *bufferPtr()
609 {
610 Q_ASSERT(buffer.isDetached());
611 return const_cast<char *>(buffer.constData()) + bufferStart;
612 }
613
614 void preread()
615 {
616 if (device && buffer.size() - bufferStart < MaxCborIndividualSize) {
617 // load more, but only if there's more to be read
618 qint64 avail = device->bytesAvailable();
619 Q_ASSERT(avail >= buffer.size());
620 if (avail == buffer.size())
621 return;
622
623 if (bufferStart)
624 device->skip(bufferStart); // skip what we've already parsed
625
626 if (buffer.size() != IdealIoBufferSize)
627 buffer.resize(IdealIoBufferSize);
628
629 bufferStart = 0;
630 qint64 read = device->peek(bufferPtr(), IdealIoBufferSize);
631 if (read < 0)
632 buffer.clear();
633 else if (read != IdealIoBufferSize)
634 buffer.truncate(read);
635 }
636 }
637
638 void handleError(CborError err) noexcept
639 {
640 Q_ASSERT(err);
641
642 // is the error fatal?
643 if (err != CborErrorUnexpectedEOF)
644 corrupt = true;
645
646 lastError = QCborError { QCborError::Code(int(err)) };
647 }
648
649 void updateBufferAfterString(qsizetype offset, qsizetype size)
650 {
651 Q_ASSERT(device);
652
653 bufferStart += offset;
654 qsizetype newStart = bufferStart + size;
655 qsizetype remainingInBuffer = buffer.size() - newStart;
656
657 if (remainingInBuffer <= 0) {
658 // We've read from the QIODevice more than what was in the buffer.
659 buffer.truncate(0);
660 } else {
661 // There's still data buffered, but we need to move it around.
662 char *ptr = buffer.data();
663 memmove(ptr, ptr + newStart, remainingInBuffer);
664 buffer.truncate(remainingInBuffer);
665 }
666
667 bufferStart = 0;
668 }
669
670 bool ensureStringIteration();
671};
672
673void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error)
674{
675 d->handleError(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(userptr, self->buffer.constData() + self->bufferStart + offset, 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 static_assert(sizeof(size_t) >= sizeof(QByteArray::size_type));
713 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>(offset, len, &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(&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(&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(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(d->bufferStart)) - CborSimpleType;
766 } else {
767 // Using internal TinyCBOR API!
768 value64 = _cbor_value_extract_int64_helper(&d->currentElement);
769
770 if (cbor_value_is_negative_integer(&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, 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), 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.constData(), 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(data, len);
900 reparse();
901 } else {
902 qWarning("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(&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(&qAsConst(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(&d->currentElement) &&
1022 !cbor_value_at_end(&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(CborErrorAdvancePastEOF);
1048 } else if (maxRecursion < 0) {
1049 d->handleError(CborErrorNestingTooDeep);
1050 } else if (isContainer()) {
1051 // iterate over each element
1052 enterContainer();
1053 while (lastError() == QCborError::NoError && hasNext())
1054 next(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(CborErrorDataTooLarge);
1062 break;
1063 }
1064 if (isString() && !QUtf8::isValidUtf8(r.data).isValidUtf8) {
1065 d->handleError(CborErrorInvalidUtf8TextString);
1066 break;
1067 }
1068 r = _readByteArray_helper();
1069 }
1070 } else {
1071 // fixed types
1072 CborError err = cbor_value_advance_fixed(&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(&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(d->currentElement);
1152 CborError err = cbor_value_enter_container(&d->containerStack.top(), &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("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(&container, &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 QStringConverter::State cs(QStringConverter::Flag::Stateless);
1353 result.data = QUtf8::convertToUnicode(r.data, &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(CborErrorDataTooLarge);
1392 return result;
1393 }
1394
1395 result.data.resize(len);
1396 auto r = readStringChunk(result.data.data(), 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(&d->currentElement, &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(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 CborError err;
1465 size_t len;
1466 const void *content = nullptr;
1467 QCborStreamReader::StringResult<qsizetype> result;
1468 result.data = 0;
1469 result.status = Error;
1470
1471 d->lastError = {};
1472 if (!d->ensureStringIteration())
1473 return result;
1474
1475#if 1
1476 // Using internal TinyCBOR API!
1477 err = _cbor_value_get_string_chunk(&d->currentElement, &content, &len, &d->currentElement);
1478#else
1479 // the above is effectively the same as:
1480 if (cbor_value_is_byte_string(&currentElement))
1481 err = cbor_value_get_byte_string_chunk(&d->currentElement, reinterpret_cast<const uint8_t **>(&content),
1482 &len, &d->currentElement);
1483 else
1484 err = cbor_value_get_text_string_chunk(&d->currentElement, reinterpret_cast<const char **>(&content),
1485 &len, &d->currentElement);
1486#endif
1487
1488 // Range check: using implementation-defined behavior in converting an
1489 // unsigned value out of range of the destination signed type (same as
1490 // "len > size_t(std::numeric_limits<qsizetype>::max())", but generates
1491 // better code with ICC and MSVC).
1492 if (!err && qsizetype(len) < 0)
1493 err = CborErrorDataTooLarge;
1494
1495 if (err) {
1496 if (err == CborErrorNoMoreStringChunks) {
1497 d->preread();
1498 err = cbor_value_finish_string_iteration(&d->currentElement);
1499 result.status = EndOfString;
1500 }
1501 if (err)
1502 d->handleError(err);
1503 else
1504 preparse();
1505 return result;
1506 }
1507
1508 // Read the chunk into the user's buffer.
1509 qint64 actuallyRead;
1510 qptrdiff offset = qptrdiff(content);
1511 qsizetype toRead = qsizetype(len);
1512 qsizetype left = toRead - maxlen;
1513 if (left < 0)
1514 left = 0; // buffer bigger than string
1515 else
1516 toRead = maxlen; // buffer smaller than string
1517
1518 if (d->device) {
1519 // This first skip can't fail because we've already read this many bytes.
1520 d->device->skip(d->bufferStart + qptrdiff(content));
1521 actuallyRead = d->device->read(ptr, toRead);
1522
1523 if (actuallyRead != toRead) {
1524 actuallyRead = -1;
1525 } else if (left) {
1526 qint64 skipped = d->device->skip(left);
1527 if (skipped != left)
1528 actuallyRead = -1;
1529 }
1530
1531 if (actuallyRead < 0) {
1532 d->handleError(CborErrorIO);
1533 return result;
1534 }
1535
1536 d->updateBufferAfterString(offset, len);
1537 } else {
1538 actuallyRead = toRead;
1539 memcpy(ptr, d->buffer.constData() + d->bufferStart + offset, toRead);
1540 d->bufferStart += QByteArray::size_type(offset + len);
1541 }
1542
1543 d->preread();
1544 result.data = actuallyRead;
1545 result.status = Ok;
1546 return result;
1547}
1548
1549QT_END_NAMESPACE
1550
1551#include "moc_qcborstreamreader.cpp"
1552