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 | |
52 | QT_BEGIN_NAMESPACE |
53 | |
54 | static bool qt_cbor_decoder_can_read(void *token, size_t len); |
55 | static void qt_cbor_decoder_advance(void *token, size_t len); |
56 | static void *qt_cbor_decoder_read(void *token, void *userptr, size_t offset, size_t len); |
57 | static 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 | |
65 | QT_WARNING_PUSH |
66 | QT_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 | |
70 | QT_WARNING_POP |
71 | |
72 | static 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 |
84 | static_assert(int(QCborStreamReader::UnsignedInteger) == CborIntegerType); |
85 | static_assert(int(QCborStreamReader::ByteString) == CborByteStringType); |
86 | static_assert(int(QCborStreamReader::TextString) == CborTextStringType); |
87 | static_assert(int(QCborStreamReader::Array) == CborArrayType); |
88 | static_assert(int(QCborStreamReader::Map) == CborMapType); |
89 | static_assert(int(QCborStreamReader::Tag) == CborTagType); |
90 | static_assert(int(QCborStreamReader::SimpleType) == CborSimpleType); |
91 | static_assert(int(QCborStreamReader::HalfFloat) == CborHalfFloatType); |
92 | static_assert(int(QCborStreamReader::Float) == CborFloatType); |
93 | static_assert(int(QCborStreamReader::Double) == CborDoubleType); |
94 | static_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 | |
549 | class QCborStreamReaderPrivate |
550 | { |
551 | public: |
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, ¤tElement, 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 | |
673 | void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error) |
674 | { |
675 | d->handleError(CborError(error.c)); |
676 | } |
677 | |
678 | static 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 | |
687 | static 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 | |
697 | static 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 | |
708 | static 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 | |
730 | bool QCborStreamReaderPrivate::ensureStringIteration() |
731 | { |
732 | if (currentElement.flags & CborIteratorFlag_IteratingStringChunks) |
733 | return true; |
734 | |
735 | CborError err = cbor_value_begin_string_iteration(¤tElement); |
736 | if (!err) |
737 | return true; |
738 | handleError(err); |
739 | return false; |
740 | } |
741 | |
742 | /*! |
743 | \internal |
744 | */ |
745 | inline 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 | */ |
788 | QCborStreamReader::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 | */ |
799 | QCborStreamReader::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 | */ |
810 | QCborStreamReader::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 | */ |
821 | QCborStreamReader::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 | */ |
834 | QCborStreamReader::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 | */ |
843 | QCborStreamReader::~QCborStreamReader() |
844 | { |
845 | } |
846 | |
847 | /*! |
848 | Sets the source of data to \a device, resetting the decoder to its initial |
849 | state. |
850 | */ |
851 | void 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 | */ |
862 | QIODevice *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 | */ |
872 | void 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 | */ |
895 | void 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 | */ |
914 | void 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 | */ |
933 | void 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 | */ |
951 | void 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 | */ |
966 | QCborError 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 | */ |
979 | qint64 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 | */ |
990 | int 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 | */ |
1003 | QCborStreamReader::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 | */ |
1019 | bool 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 | */ |
1041 | bool 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 | */ |
1099 | bool 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 | */ |
1113 | quint64 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 | */ |
1149 | bool 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 | */ |
1173 | bool 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 | */ |
1339 | QCborStreamReader::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 | */ |
1383 | QCborStreamReader::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 | */ |
1415 | qsizetype 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 | */ |
1461 | QCborStreamReader::StringResult<qsizetype> |
1462 | QCborStreamReader::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(¤tElement)) |
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 | |
1549 | QT_END_NAMESPACE |
1550 | |
1551 | #include "moc_qcborstreamreader.cpp" |
1552 | |