1 // SPDX-License-Identifier: BSD-3-Clause
2 /*==============================================================================
3 Copyright (c) 2016-2018, The Linux Foundation.
4 Copyright (c) 2018-2024, Laurence Lundblade.
5 Copyright (c) 2021, Arm Limited.
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
10 met:
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above
14 copyright notice, this list of conditions and the following
15 disclaimer in the documentation and/or other materials provided
16 with the distribution.
17 * Neither the name of The Linux Foundation nor the names of its
18 contributors, nor the name "Laurence Lundblade" may be used to
19 endorse or promote products derived from this software without
20 specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
23 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
25 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
26 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 =============================================================================*/
34
35
36 #include "qcbor/qcbor_decode.h"
37 #include "qcbor/qcbor_spiffy_decode.h"
38 #include "ieee754.h" /* Does not use math.h */
39
40 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
41
42 #include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
43 * pow(), exp2()
44 */
45 #include <fenv.h> /* feclearexcept(), fetestexcept() */
46
47 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
48
49
50 #if (defined(__GNUC__) && !defined(__clang__))
51 /*
52 * This is how the -Wmaybe-uninitialized compiler warning is
53 * handled. It can’t be ignored because some version of gcc enable it
54 * with -Wall which is a common and useful gcc warning option. It also
55 * can’t be ignored because it is the goal of QCBOR to compile clean
56 * out of the box in all environments.
57 *
58 * The big problem with -Wmaybe-uninitialized is that it generates
59 * false positives. It complains things are uninitialized when they
60 * are not. This is because it is not a thorough static analyzer. This
61 * is why “maybe” is in its name. The problem is it is just not
62 * thorough enough to understand all the code (and someone saw fit to
63 * put it in gcc and worse to enable it with -Wall).
64 *
65 * One solution would be to change the code so -Wmaybe-uninitialized
66 * doesn’t get confused, for example adding an unnecessary extra
67 * initialization to zero. (If variables were truly uninitialized, the
68 * correct path is to understand the code thoroughly and set them to
69 * the correct value at the correct time; in essence this is already
70 * done; -Wmaybe-uninitialized just can’t tell). This path is not
71 * taken because it makes the code bigger and is kind of the tail
72 * wagging the dog.
73 *
74 * The solution here is to just use a pragma to disable it for the
75 * whole file. Disabling it for each line makes the code fairly ugly
76 * requiring #pragma to push, pop and ignore. Another reason is the
77 * warnings issues vary by version of gcc and which optimization
78 * optimizations are selected. Another reason is that compilers other
79 * than gcc don’t have -Wmaybe-uninitialized.
80 *
81 * One may ask how to be sure these warnings are false positives and
82 * not real issues. 1) The code has been read carefully to check. 2)
83 * Testing is pretty thorough. 3) This code has been run through
84 * thorough high-quality static analyzers.
85 *
86 * In particularly, most of the warnings are about
87 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
88 * *always* sets this value and test case confirm
89 * this. -Wmaybe-uninitialized just can't tell.
90 *
91 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
92 */
93 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
94 #endif
95
96
97
98
99 #define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type))
100
101
102
103
104 static bool
QCBORItem_IsMapOrArray(const QCBORItem Item)105 QCBORItem_IsMapOrArray(const QCBORItem Item)
106 {
107 const uint8_t uDataType = Item.uDataType;
108 return uDataType == QCBOR_TYPE_MAP ||
109 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
110 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
111 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
112 uDataType == QCBOR_TYPE_ARRAY;
113 }
114
115 static bool
QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)116 QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
117 {
118 if(!QCBORItem_IsMapOrArray(Item)){
119 return false;
120 }
121
122 if(Item.val.uCount != 0) {
123 return false;
124 }
125 return true;
126 }
127
128 static bool
QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)129 QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
130 {
131 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
132 if(!QCBORItem_IsMapOrArray(Item)){
133 return false;
134 }
135
136 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
137 return false;
138 }
139 return true;
140 #else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
141 (void)Item;
142 return false;
143 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
144 }
145
146 /* Return true if the labels in Item1 and Item2 are the same.
147 Works only for integer and string labels. Returns false
148 for any other type. */
149 static bool
QCBORItem_MatchLabel(const QCBORItem Item1,const QCBORItem Item2)150 QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
151 {
152 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
153 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
154 return true;
155 }
156 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
157 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
158 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
159 return true;
160 }
161 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
162 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
163 return true;
164 }
165 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
166 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
167 return true;
168 }
169 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
170 }
171
172 /* Other label types are never matched */
173 return false;
174 }
175
176
177 /*
178 Returns true if Item1 and Item2 are the same type
179 or if either are of QCBOR_TYPE_ANY.
180 */
181 static bool
QCBORItem_MatchType(const QCBORItem Item1,const QCBORItem Item2)182 QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
183 {
184 if(Item1.uDataType == Item2.uDataType) {
185 return true;
186 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
187 return true;
188 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
189 return true;
190 }
191 return false;
192 }
193
194
195 /*===========================================================================
196 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
197 ===========================================================================*/
198
199 /*
200 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
201 * the data structure all these functions work on.
202 */
203
204
205 static uint8_t
DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting * pNesting)206 DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
207 {
208 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
209 /* Limit in DecodeNesting_Descend against more than
210 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
211 */
212 return (uint8_t)nLevel;
213 }
214
215
216 static uint8_t
DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting * pNesting)217 DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
218 {
219 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
220 /* Limit in DecodeNesting_Descend against more than
221 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
222 */
223 return (uint8_t)nLevel;
224 }
225
226
227 static uint32_t
DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting * pNesting)228 DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
229 {
230 return pNesting->pCurrentBounded->u.ma.uStartOffset;
231 }
232
233
234 static bool
DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting * pNesting)235 DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
236 {
237 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
238 return true;
239 } else {
240 return false;
241 }
242 }
243
244
245 static bool
DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting * pNesting)246 DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
247 {
248 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
249 return true;
250 } else {
251 return false;
252 }
253 }
254
255
256 static bool
DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting * pNesting)257 DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
258 {
259 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
260 /* Not a map or array */
261 return false;
262 }
263
264 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
265 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
266 /* Is indefinite */
267 return false;
268 }
269
270 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
271
272 /* All checks passed; is a definte length map or array */
273 return true;
274 }
275
276 static bool
DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting * pNesting)277 DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
278 {
279 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
280 /* is a byte string */
281 return true;
282 }
283 return false;
284 }
285
286
287 static bool
DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting * pNesting)288 DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
289 {
290 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
291 return true;
292 }
293 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
294 return true;
295 }
296 return false;
297 }
298
299
300 static void
DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting * pNesting,bool bIsEmpty,size_t uStart)301 DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
302 {
303 /* Should be only called on maps and arrays */
304 /*
305 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
306 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
307 * uin32_t so the cast is safe.
308 */
309 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
310
311 if(bIsEmpty) {
312 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
313 }
314 }
315
316
317 static void
DecodeNesting_ClearBoundedMode(QCBORDecodeNesting * pNesting)318 DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
319 {
320 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
321 }
322
323
324 static bool
DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting * pNesting)325 DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
326 {
327 if(pNesting->pCurrentBounded == NULL) {
328 /* No bounded map or array set up */
329 return false;
330 }
331 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
332 /* Not a map or array; end of those is by byte count */
333 return false;
334 }
335 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
336 /* In a traveral at a level deeper than the bounded level */
337 return false;
338 }
339 /* Works for both definite- and indefinitelength maps/arrays */
340 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
341 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
342 /* Count is not zero, still unconsumed item */
343 return false;
344 }
345 /* All checks passed, got to the end of an array or map*/
346 return true;
347 }
348
349
350 static bool
DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting * pNesting)351 DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
352 {
353 /* Must only be called on map / array */
354 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
355 return true;
356 } else {
357 return false;
358 }
359 }
360
361
362 static bool
DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting * pNesting)363 DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
364 {
365 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
366 return true;
367 } else {
368 return false;
369 }
370 }
371
372
373 static bool
DecodeNesting_IsBoundedType(const QCBORDecodeNesting * pNesting,uint8_t uType)374 DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
375 {
376 if(pNesting->pCurrentBounded == NULL) {
377 return false;
378 }
379
380 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
381 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
382 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
383 uItemDataType = QCBOR_TYPE_ARRAY;
384 }
385 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
386
387 if(uItemDataType != uType) {
388 return false;
389 }
390
391 return true;
392 }
393
394
395 static void
DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting * pNesting)396 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
397 {
398 /* Only call on a definite-length array / map */
399 pNesting->pCurrent->u.ma.uCountCursor--;
400 }
401
402
403 static void
DecodeNesting_ReverseDecrement(QCBORDecodeNesting * pNesting)404 DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
405 {
406 /* Only call on a definite-length array / map */
407 pNesting->pCurrent->u.ma.uCountCursor++;
408 }
409
410
411 static void
DecodeNesting_Ascend(QCBORDecodeNesting * pNesting)412 DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
413 {
414 pNesting->pCurrent--;
415 }
416
417
418 static QCBORError
DecodeNesting_Descend(QCBORDecodeNesting * pNesting,uint8_t uType)419 DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
420 {
421 /* Error out if nesting is too deep */
422 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
423 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
424 }
425
426 /* The actual descend */
427 pNesting->pCurrent++;
428
429 pNesting->pCurrent->uLevelType = uType;
430
431 return QCBOR_SUCCESS;
432 }
433
434
435 static QCBORError
DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting * pNesting,bool bIsEmpty,size_t uOffset)436 DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
437 bool bIsEmpty,
438 size_t uOffset)
439 {
440 /*
441 * Should only be called on map/array.
442 *
443 * Have descended into this before this is called. The job here is
444 * just to mark it in bounded mode.
445 *
446 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
447 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
448 *
449 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
450 */
451 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
452 return QCBOR_ERR_INPUT_TOO_LARGE;
453 }
454
455 pNesting->pCurrentBounded = pNesting->pCurrent;
456
457 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
458
459 return QCBOR_SUCCESS;
460 }
461
462
463 static QCBORError
DecodeNesting_DescendMapOrArray(QCBORDecodeNesting * pNesting,uint8_t uQCBORType,uint64_t uCount)464 DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
465 uint8_t uQCBORType,
466 uint64_t uCount)
467 {
468 QCBORError uError = QCBOR_SUCCESS;
469
470 if(uCount == 0) {
471 /* Nothing to do for empty definite-length arrays. They are just are
472 * effectively the same as an item that is not a map or array.
473 */
474 goto Done;
475 /* Empty indefinite-length maps and arrays are handled elsewhere */
476 }
477
478 /* Error out if arrays is too long to handle */
479 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
480 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
481 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
482 goto Done;
483 }
484
485 uError = DecodeNesting_Descend(pNesting, uQCBORType);
486 if(uError != QCBOR_SUCCESS) {
487 goto Done;
488 }
489
490 /* Fill in the new map/array level. Check above makes casts OK. */
491 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
492 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
493
494 DecodeNesting_ClearBoundedMode(pNesting);
495
496 Done:
497 return uError;;
498 }
499
500
501 static void
DecodeNesting_LevelUpCurrent(QCBORDecodeNesting * pNesting)502 DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
503 {
504 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
505 }
506
507
508 static void
DecodeNesting_LevelUpBounded(QCBORDecodeNesting * pNesting)509 DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
510 {
511 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
512 pNesting->pCurrentBounded--;
513 if(DecodeNesting_IsCurrentBounded(pNesting)) {
514 break;
515 }
516 }
517 }
518
519
520 static void
DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting * pNesting)521 DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
522 {
523 pNesting->pCurrent = pNesting->pCurrentBounded;
524 }
525
526
527 static QCBORError
DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting * pNesting,uint32_t uEndOffset,uint32_t uStartOffset)528 DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
529 uint32_t uEndOffset,
530 uint32_t uStartOffset)
531 {
532 QCBORError uError;
533
534 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
535 if(uError != QCBOR_SUCCESS) {
536 goto Done;
537 }
538
539 /* Fill in the new byte string level */
540 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
541 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
542
543 /* Bstr wrapped levels are always bounded */
544 pNesting->pCurrentBounded = pNesting->pCurrent;
545
546 Done:
547 return uError;;
548 }
549
550
551 static void
DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting * pNesting)552 DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
553 {
554 pNesting->pCurrent->u.ma.uCountCursor = 0;
555 }
556
557
558 static void
DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting * pNesting)559 DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
560 {
561 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
562 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
563 }
564 }
565
566
567 static void
DecodeNesting_Init(QCBORDecodeNesting * pNesting)568 DecodeNesting_Init(QCBORDecodeNesting *pNesting)
569 {
570 /* Assumes that *pNesting has been zero'd before this call. */
571 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
572 pNesting->pCurrent = &(pNesting->pLevels[0]);
573 }
574
575
576 static void
DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting * pNesting,QCBORDecodeNesting * pSave)577 DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
578 QCBORDecodeNesting *pSave)
579 {
580 *pSave = *pNesting;
581 }
582
583
584 static void
DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting * pNesting,const QCBORDecodeNesting * pSave)585 DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
586 const QCBORDecodeNesting *pSave)
587 {
588 *pNesting = *pSave;
589 }
590
591
592 static uint32_t
DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting * pMe)593 DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
594 {
595 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
596 }
597
598
599
600
601 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
602 /*===========================================================================
603 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
604
605 The following four functions are pretty wrappers for invocation of
606 the string allocator supplied by the caller.
607
608 ===========================================================================*/
609
610 static void
StringAllocator_Free(const QCBORInternalAllocator * pMe,const void * pMem)611 StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
612 {
613 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
614 * This is the one place where the const needs to be cast away so const can
615 * be use in the rest of the code.
616 */
617 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
618 }
619
620 // StringAllocator_Reallocate called with pMem NULL is
621 // equal to StringAllocator_Allocate()
622 static UsefulBuf
StringAllocator_Reallocate(const QCBORInternalAllocator * pMe,const void * pMem,size_t uSize)623 StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
624 const void *pMem,
625 size_t uSize)
626 {
627 /* See comment in StringAllocator_Free() */
628 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
629 }
630
631 static UsefulBuf
StringAllocator_Allocate(const QCBORInternalAllocator * pMe,size_t uSize)632 StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
633 {
634 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
635 }
636
637 static void
StringAllocator_Destruct(const QCBORInternalAllocator * pMe)638 StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
639 {
640 /* See comment in StringAllocator_Free() */
641 if(pMe->pfAllocator) {
642 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
643 }
644 }
645 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
646
647
648
649
650 /*===========================================================================
651 QCBORDecode -- The main implementation of CBOR decoding
652
653 See qcbor/qcbor_decode.h for definition of the object
654 used here: QCBORDecodeContext
655 ===========================================================================*/
656 /*
657 * Public function, see header file
658 */
659 void
QCBORDecode_Init(QCBORDecodeContext * pMe,UsefulBufC EncodedCBOR,QCBORDecodeMode nDecodeMode)660 QCBORDecode_Init(QCBORDecodeContext *pMe,
661 UsefulBufC EncodedCBOR,
662 QCBORDecodeMode nDecodeMode)
663 {
664 memset(pMe, 0, sizeof(QCBORDecodeContext));
665 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
666 /* Don't bother with error check on decode mode. If a bad value is
667 * passed it will just act as if the default normal mode of 0 was set.
668 */
669 pMe->uDecodeMode = (uint8_t)nDecodeMode;
670 DecodeNesting_Init(&(pMe->nesting));
671
672 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
673 * GetNext_TaggedItem() and MapTagNumber(). */
674 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
675 }
676
677
678 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
679
680 /*
681 * Public function, see header file
682 */
683 void
QCBORDecode_SetUpAllocator(QCBORDecodeContext * pMe,QCBORStringAllocate pfAllocateFunction,void * pAllocateContext,bool bAllStrings)684 QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
685 QCBORStringAllocate pfAllocateFunction,
686 void *pAllocateContext,
687 bool bAllStrings)
688 {
689 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
690 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
691 pMe->bStringAllocateAll = bAllStrings;
692 }
693 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
694
695
696
697
698 /*
699 * Deprecated public function, see header file
700 */
701 void
QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext * pMe,const QCBORTagListIn * pTagList)702 QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
703 const QCBORTagListIn *pTagList)
704 {
705 /* This does nothing now. It is retained for backwards compatibility */
706 (void)pMe;
707 (void)pTagList;
708 }
709
710
711
712
713 /*
714 * Decoding items is done in six layers, one calling the next one
715 * down. If a layer has no work to do for a particular item, it
716 * returns quickly.
717 *
718 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
719 * tagged data items, turning them into the local C representation.
720 * For the most simple it is just associating a QCBOR_TYPE with the
721 * data. For the complex ones that an aggregate of data items, there
722 * is some further decoding and some limited recursion.
723 *
724 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
725 * beginnings and ends of maps and arrays. It tracks descending into
726 * and ascending out of maps/arrays. It processes breaks that
727 * terminate indefinite-length maps and arrays.
728 *
729 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
730 * of two items, the label and the data, that make up a map entry. It
731 * only does work on maps. It combines the label and data items into
732 * one labeled item.
733 *
734 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
735 * numbers. It turns the tag numbers into bit flags associated with
736 * the data item. No actual decoding of the contents of the tag is
737 * performed here.
738 *
739 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
740 * sub-items that make up an indefinite-length string into one string
741 * item. It uses the string allocator to create contiguous space for
742 * the item. It processes all breaks that are part of
743 * indefinite-length strings.
744 *
745 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
746 * data items in CBOR. Each atomic data item has a "major type", an
747 * integer "argument" and optionally some content. For text and byte
748 * strings, the content is the bytes that make up the string. These
749 * are the smallest data items that are considered to be well-formed.
750 * The content may also be other data items in the case of aggregate
751 * types. They are not handled in this layer.
752 *
753 * This uses about 350 bytes of stack. This number comes from
754 * instrumenting (printf address of stack variables) the code on x86
755 * compiled for size optimization.
756 */
757
758
759 /*
760 * Note about use of int and unsigned variables.
761 *
762 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
763 * used carefully here, and in particular why it isn't used in the
764 * public interface. Also see
765 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
766 *
767 * Int is used for values that need less than 16-bits and would be
768 * subject to integer promotion and result in complaining from static
769 * analyzers.
770 */
771
772
773 /**
774 * @brief Decode the CBOR head, the type and argument.
775 *
776 * @param[in] pUInBuf The input buffer to read from.
777 * @param[out] pnMajorType The decoded major type.
778 * @param[out] puArgument The decoded argument.
779 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
780 *
781 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
782 * @retval QCBOR_ERR_HIT_END Unexpected end of input
783 *
784 * This decodes the CBOR "head" that every CBOR data item has. See
785 * longer explaination of the head in documentation for
786 * QCBOREncode_EncodeHead().
787 *
788 * This does the network->host byte order conversion. The conversion
789 * here also results in the conversion for floats in addition to that
790 * for lengths, tags and integer values.
791 *
792 * The int type is preferred to uint8_t for some variables as this
793 * avoids integer promotions, can reduce code size and makes static
794 * analyzers happier.
795 */
796 static QCBORError
QCBOR_Private_DecodeHead(UsefulInputBuf * pUInBuf,int * pnMajorType,uint64_t * puArgument,int * pnAdditionalInfo)797 QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
798 int *pnMajorType,
799 uint64_t *puArgument,
800 int *pnAdditionalInfo)
801 {
802 QCBORError uReturn;
803
804 /* Get the initial byte that every CBOR data item has and break it
805 * down. */
806 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
807 const int nTmpMajorType = nInitialByte >> 5;
808 const int nAdditionalInfo = nInitialByte & 0x1f;
809
810 /* Where the argument accumulates */
811 uint64_t uArgument;
812
813 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
814 /* Need to get 1,2,4 or 8 additional argument bytes. Map
815 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
816 */
817 static const uint8_t aIterate[] = {1,2,4,8};
818
819 /* Loop getting all the bytes in the argument */
820 uArgument = 0;
821 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
822 /* This shift and add gives the endian conversion. */
823 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
824 }
825 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
826 /* The reserved and thus-far unused additional info values */
827 uReturn = QCBOR_ERR_UNSUPPORTED;
828 goto Done;
829 } else {
830 /* Less than 24, additional info is argument or 31, an
831 * indefinite-length. No more bytes to get.
832 */
833 uArgument = (uint64_t)nAdditionalInfo;
834 }
835
836 if(UsefulInputBuf_GetError(pUInBuf)) {
837 uReturn = QCBOR_ERR_HIT_END;
838 goto Done;
839 }
840
841 /* All successful if arrived here. */
842 uReturn = QCBOR_SUCCESS;
843 *pnMajorType = nTmpMajorType;
844 *puArgument = uArgument;
845 *pnAdditionalInfo = nAdditionalInfo;
846
847 Done:
848 return uReturn;
849 }
850
851
852 /**
853 * @brief Decode integer types, major types 0 and 1.
854 *
855 * @param[in] nMajorType The CBOR major type (0 or 1).
856 * @param[in] uArgument The argument from the head.
857 * @param[in] nAdditionalInfo So it can be error-checked.
858 * @param[out] pDecodedItem The filled in decoded item.
859 *
860 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
861 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
862 *
863 * Must only be called when major type is 0 or 1.
864 *
865 * CBOR doesn't explicitly specify two's compliment for integers but
866 * all CPUs use it these days and the test vectors in the RFC are
867 * so. All integers in the CBOR structure are positive and the major
868 * type indicates positive or negative. CBOR can express positive
869 * integers up to 2^x - 1 where x is the number of bits and negative
870 * integers down to 2^x. Note that negative numbers can be one more
871 * away from zero than positive. Stdint, as far as I can tell, uses
872 * two's compliment to represent negative integers.
873 */
874 static QCBORError
QCBOR_Private_DecodeInteger(const int nMajorType,const uint64_t uArgument,const int nAdditionalInfo,QCBORItem * pDecodedItem)875 QCBOR_Private_DecodeInteger(const int nMajorType,
876 const uint64_t uArgument,
877 const int nAdditionalInfo,
878 QCBORItem *pDecodedItem)
879 {
880 QCBORError uReturn = QCBOR_SUCCESS;
881
882 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
883 uReturn = QCBOR_ERR_BAD_INT;
884 goto Done;
885 }
886
887 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
888 if (uArgument <= INT64_MAX) {
889 pDecodedItem->val.int64 = (int64_t)uArgument;
890 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
891
892 } else {
893 pDecodedItem->val.uint64 = uArgument;
894 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
895 }
896
897 } else {
898 if(uArgument <= INT64_MAX) {
899 /* CBOR's representation of negative numbers lines up with
900 * the two-compliment representation. A negative integer has
901 * one more in range than a positive integer. INT64_MIN is
902 * equal to (-INT64_MAX) - 1.
903 */
904 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
905 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
906
907 } else {
908 /* C can't represent a negative integer in this range so it
909 * is an error.
910 */
911 uReturn = QCBOR_ERR_INT_OVERFLOW;
912 }
913 }
914
915 Done:
916 return uReturn;
917 }
918
919
920 /**
921 * @brief Decode text and byte strings
922 *
923 * @param[in] pMe Decoder context.
924 * @param[in] bAllocate Whether to allocate and copy string.
925 * @param[in] nMajorType Whether it is a byte or text string.
926 * @param[in] uStrLen The length of the string.
927 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
928 * @param[out] pDecodedItem The filled-in decoded item.
929 *
930 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
931 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
932 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
933 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
934 *
935 * This reads @c uStrlen bytes from the input and fills in @c
936 * pDecodedItem. If @c bAllocate is true, then memory for the string
937 * is allocated.
938 */
939 static QCBORError
QCBOR_Private_DecodeString(QCBORDecodeContext * pMe,const bool bAllocate,const int nMajorType,const uint64_t uStrLen,const int nAdditionalInfo,QCBORItem * pDecodedItem)940 QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
941 const bool bAllocate,
942 const int nMajorType,
943 const uint64_t uStrLen,
944 const int nAdditionalInfo,
945 QCBORItem *pDecodedItem)
946 {
947 QCBORError uReturn = QCBOR_SUCCESS;
948
949 /* ---- Figure out the major type ---- */
950 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
951 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
952 #endif
953
954 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
955 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
956 #endif
957 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
958
959 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
960 /* --- Just the head of an indefinite-length string --- */
961 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
962
963 } else {
964 /* --- A definite-length string --- */
965 /* --- (which might be a chunk of an indefinte-length string) --- */
966
967 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
968 * CPUs. This check makes the casts to size_t below safe.
969 *
970 * The max is 4 bytes less than the largest sizeof() so this can be
971 * tested by putting a SIZE_MAX length in the CBOR test input (no
972 * one will care the limit on strings is 4 bytes shorter).
973 */
974 if(uStrLen > SIZE_MAX-4) {
975 uReturn = QCBOR_ERR_STRING_TOO_LONG;
976 goto Done;
977 }
978
979 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
980 if(UsefulBuf_IsNULLC(Bytes)) {
981 /* Failed to get the bytes for this string item */
982 uReturn = QCBOR_ERR_HIT_END;
983 goto Done;
984 }
985
986 if(bAllocate) {
987 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
988 /* --- Put string in allocated memory --- */
989
990 /* Note that this is not where allocation to coalesce
991 * indefinite-length strings is done. This is for when the
992 * caller has requested all strings be allocated. Disabling
993 * indefinite length strings also disables this allocate-all
994 * option.
995 */
996
997 if(pMe->StringAllocator.pfAllocator == NULL) {
998 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
999 goto Done;
1000 }
1001 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1002 if(UsefulBuf_IsNULL(NewMem)) {
1003 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1004 goto Done;
1005 }
1006 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1007 pDecodedItem->uDataAlloc = 1;
1008 #else
1009 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1010 #endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1011 } else {
1012 /* --- Normal case with no string allocator --- */
1013 pDecodedItem->val.string = Bytes;
1014 }
1015 }
1016
1017 Done:
1018 return uReturn;
1019 }
1020
1021
1022 /**
1023 * @brief Decode array or map.
1024 *
1025 * @param[in] uMode Decoder mode.
1026 * @param[in] nMajorType Whether it is a byte or text string.
1027 * @param[in] uItemCount The length of the string.
1028 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1029 * @param[out] pDecodedItem The filled-in decoded item.
1030 *
1031 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1032 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1033 *
1034 * Not much to do for arrays and maps. Just the type item count (but a
1035 * little messy because of ifdefs for indefinite-lengths and
1036 * map-as-array decoding).
1037 *
1038 * This also does the bulk of the work for @ref
1039 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1040 * arbitrarily complex map labels. This ifdefs out with
1041 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1042 */
1043 static QCBORError
QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,const int nMajorType,const uint64_t uItemCount,const int nAdditionalInfo,QCBORItem * pDecodedItem)1044 QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1045 const int nMajorType,
1046 const uint64_t uItemCount,
1047 const int nAdditionalInfo,
1048 QCBORItem *pDecodedItem)
1049 {
1050 QCBORError uReturn;
1051
1052 /* ------ Sort out the data type ------ */
1053 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1054 #error QCBOR_TYPE_ARRAY value not lined up with major type
1055 #endif
1056
1057 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1058 #error QCBOR_TYPE_MAP value not lined up with major type
1059 #endif
1060 pDecodedItem->uDataType = (uint8_t)nMajorType;
1061 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1062 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1063 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1064 }
1065 #else
1066 (void)uMode;
1067 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1068
1069 uReturn = QCBOR_SUCCESS;
1070
1071 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1072 /* ------ Indefinite-length array/map ----- */
1073 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1074 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1075 #else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1076 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1077 #endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1078 } else {
1079
1080 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1081 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1082 /* ------ Definite-length map as array ------ */
1083
1084 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1085 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1086 } else {
1087 /* cast OK because of check above */
1088 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1089 }
1090
1091 } else
1092 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1093 {
1094 /* ------ Definite-length array/map ------ */
1095 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1096 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1097 } else {
1098 /* cast OK because of check above */
1099 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1100 }
1101 }
1102 }
1103
1104 return uReturn;
1105 }
1106
1107
1108 /**
1109 * @brief Decode a tag number.
1110 *
1111 * @param[in] uTagNumber The length of the string.
1112 * @param[in] nAdditionalInfo So this can be error-checked.
1113 * @param[out] pDecodedItem The filled-in decoded item.
1114 *
1115 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1116 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1117 *
1118 * Not much to do for tags, but fill in pDecodedItem and check for
1119 * error in nAdditionalInfo.
1120 */
1121 static QCBORError
QCBOR_Private_DecodeTag(const uint64_t uTagNumber,const int nAdditionalInfo,QCBORItem * pDecodedItem)1122 QCBOR_Private_DecodeTag(const uint64_t uTagNumber,
1123 const int nAdditionalInfo,
1124 QCBORItem *pDecodedItem)
1125 {
1126 #ifndef QCBOR_DISABLE_TAGS
1127 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1128 return QCBOR_ERR_BAD_INT;
1129 } else {
1130 pDecodedItem->val.uTagV = uTagNumber;
1131 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1132 return QCBOR_SUCCESS;
1133 }
1134 #else /* QCBOR_DISABLE_TAGS */
1135 (void)nAdditionalInfo;
1136 (void)uTagNumber;
1137 (void)pDecodedItem;
1138 return QCBOR_ERR_TAGS_DISABLED;
1139 #endif /* QCBOR_DISABLE_TAGS */
1140 }
1141
1142
1143 /* Make sure #define value line up as DecodeSimple counts on this. */
1144 #if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1145 #error QCBOR_TYPE_FALSE macro value wrong
1146 #endif
1147
1148 #if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1149 #error QCBOR_TYPE_TRUE macro value wrong
1150 #endif
1151
1152 #if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1153 #error QCBOR_TYPE_NULL macro value wrong
1154 #endif
1155
1156 #if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1157 #error QCBOR_TYPE_UNDEF macro value wrong
1158 #endif
1159
1160 #if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1161 #error QCBOR_TYPE_BREAK macro value wrong
1162 #endif
1163
1164 #if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1165 #error QCBOR_TYPE_DOUBLE macro value wrong
1166 #endif
1167
1168 #if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1169 #error QCBOR_TYPE_FLOAT macro value wrong
1170 #endif
1171
1172
1173 /**
1174 * @brief Decode major type 7 -- true, false, floating-point, break...
1175 *
1176 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1177 * @param[in] uArgument The argument from the head.
1178 * @param[out] pDecodedItem The filled in decoded item.
1179 *
1180 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1181 * of half-precision disabled
1182 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1183 * decode is disabled.
1184 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1185 * type in input.
1186 */
1187 static QCBORError
QCBOR_Private_DecodeType7(const int nAdditionalInfo,const uint64_t uArgument,QCBORItem * pDecodedItem)1188 QCBOR_Private_DecodeType7(const int nAdditionalInfo,
1189 const uint64_t uArgument,
1190 QCBORItem *pDecodedItem)
1191 {
1192 QCBORError uReturn = QCBOR_SUCCESS;
1193
1194 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1195 * checks above make sure uAdditionalInfo values line up with
1196 * uDataType values. DecodeHead() never returns an AdditionalInfo
1197 * > 0x1f so cast is safe.
1198 */
1199 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
1200
1201 switch(nAdditionalInfo) {
1202 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1203 * are caught before this is called.
1204 */
1205
1206 case HALF_PREC_FLOAT: /* 25 */
1207 #ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1208 /* Half-precision is returned as a double. The cast to
1209 * uint16_t is safe because the encoded value was 16 bits. It
1210 * was widened to 64 bits to be passed in here.
1211 */
1212 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
1213 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1214 #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
1215 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
1216 break;
1217 case SINGLE_PREC_FLOAT: /* 26 */
1218 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
1219 /* Single precision is normally returned as a double since
1220 * double is widely supported, there is no loss of precision,
1221 * it makes it easy for the caller in most cases and it can
1222 * be converted back to single with no loss of precision
1223 *
1224 * The cast to uint32_t is safe because the encoded value was
1225 * 32 bits. It was widened to 64 bits to be passed in here.
1226 */
1227 {
1228 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
1229 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
1230 /* In the normal case, use HW to convert float to
1231 * double. */
1232 pDecodedItem->val.dfnum = (double)f;
1233 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1234 #else /* QCBOR_DISABLE_FLOAT_HW_USE */
1235 /* Use of float HW is disabled, return as a float. */
1236 pDecodedItem->val.fnum = f;
1237 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1238
1239 /* IEEE754_FloatToDouble() could be used here to return as
1240 * a double, but it adds object code and most likely
1241 * anyone disabling FLOAT HW use doesn't care about floats
1242 * and wants to save object code.
1243 */
1244 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1245 }
1246 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1247 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1248 break;
1249
1250 case DOUBLE_PREC_FLOAT: /* 27 */
1251 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
1252 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
1253 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1254 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1255 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1256 break;
1257
1258 case CBOR_SIMPLEV_FALSE: /* 20 */
1259 case CBOR_SIMPLEV_TRUE: /* 21 */
1260 case CBOR_SIMPLEV_NULL: /* 22 */
1261 case CBOR_SIMPLEV_UNDEF: /* 23 */
1262 case CBOR_SIMPLE_BREAK: /* 31 */
1263 break; /* nothing to do */
1264
1265 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1266 if(uArgument <= CBOR_SIMPLE_BREAK) {
1267 /* This takes out f8 00 ... f8 1f which should be encoded
1268 * as e0 … f7
1269 */
1270 uReturn = QCBOR_ERR_BAD_TYPE_7;
1271 goto Done;
1272 }
1273 /* FALLTHROUGH */
1274
1275 default: /* 0-19 */
1276 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
1277 /* DecodeHead() will make uArgument equal to
1278 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1279 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1280 * the double/float cases above
1281 */
1282 pDecodedItem->val.uSimple = (uint8_t)uArgument;
1283 break;
1284 }
1285
1286 Done:
1287 return uReturn;
1288 }
1289
1290
1291 /**
1292 * @brief Decode a single primitive data item (decode layer 6).
1293 *
1294 * @param[in] pMe Decoder context.
1295 * @param[in] bAllocateStrings If true, use allocator for strings.
1296 * @param[out] pDecodedItem The filled-in decoded item.
1297 *
1298 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1299 * features
1300 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1301 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1302 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1303 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1304 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
1305 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1306 * of half-precision disabled
1307 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1308 * float decode is disabled.
1309 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1310 * simple type in input.
1311 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1312 * in input, but indefinite
1313 * lengths disabled.
1314 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1315 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1316 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1317 *
1318 * This decodes the most primitive/atomic data item. It does no
1319 * combining of data items.
1320 */
1321 static QCBORError
QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext * pMe,const bool bAllocateStrings,QCBORItem * pDecodedItem)1322 QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1323 const bool bAllocateStrings,
1324 QCBORItem *pDecodedItem)
1325 {
1326 QCBORError uReturn;
1327 int nMajorType = 0;
1328 uint64_t uArgument = 0;
1329 int nAdditionalInfo = 0;
1330
1331 memset(pDecodedItem, 0, sizeof(QCBORItem));
1332
1333 /* Decode the "head" that every CBOR item has into the major type,
1334 * argument and the additional info.
1335 */
1336 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
1337 if(uReturn != QCBOR_SUCCESS) {
1338 return uReturn;
1339 }
1340
1341 /* All the functions below get inlined by the optimizer. This code
1342 * is easier to read with them all being similar functions, even if
1343 * some functions don't do much.
1344 */
1345 switch (nMajorType) {
1346 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1347 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
1348 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
1349 break;
1350
1351 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1352 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
1353 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
1354 break;
1355
1356 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1357 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
1358 return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
1359 break;
1360
1361 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
1362 return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
1363 break;
1364
1365 case CBOR_MAJOR_TYPE_SIMPLE:
1366 /* Major type 7: float, double, true, false, null... */
1367 return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
1368 break;
1369
1370 default:
1371 /* Never happens because DecodeHead() should never return > 7 */
1372 return QCBOR_ERR_UNSUPPORTED;
1373 break;
1374 }
1375 }
1376
1377
1378 /**
1379 * @brief Process indefinite-length strings (decode layer 5).
1380 *
1381 * @param[in] pMe Decoder context
1382 * @param[out] pDecodedItem The decoded item that work is done on.
1383 *
1384 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1385 * features
1386 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1387 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1388 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1389 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1390 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1391 * of half-precision disabled
1392 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1393 * float decode is disabled.
1394 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1395 * simple type in input.
1396 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1397 * in input, but indefinite
1398 * lengths disabled.
1399 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1400 * but no string allocator.
1401 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1402 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1403 * input, but indefinite-length
1404 * strings are disabled.
1405 *
1406 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
1407 *
1408 * If it is, this loops getting the subsequent chunk data items that
1409 * make up the string. The string allocator is used to make a
1410 * contiguous buffer for the chunks. When this completes @c
1411 * pDecodedItem contains the put-together string.
1412 *
1413 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
1414 */
1415 static QCBORError
QCBORDecode_Private_GetNextFullString(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)1416 QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1417 QCBORItem *pDecodedItem)
1418 {
1419 /* Aproximate stack usage
1420 * 64-bit 32-bit
1421 * local vars 32 16
1422 * 2 UsefulBufs 32 16
1423 * QCBORItem 56 52
1424 * TOTAL 120 74
1425 */
1426 QCBORError uReturn;
1427
1428 /* A note about string allocation -- Memory for strings is
1429 * allocated either because 1) indefinte-length string chunks are
1430 * being coalecsed or 2) caller has requested all strings be
1431 * allocated. The first case is handed below here. The second case
1432 * is handled in DecodeString if the bAllocate is true. That
1433 * boolean originates here with pMe->bStringAllocateAll immediately
1434 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1435 * in two different contexts here 1) main-line processing which is
1436 * where definite-length strings need to be allocated if
1437 * bStringAllocateAll is true and 2) processing chunks of
1438 * indefinite-lengths strings in in which case there must be no
1439 * allocation.
1440 */
1441
1442
1443 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
1444 if(uReturn != QCBOR_SUCCESS) {
1445 goto Done;
1446 }
1447
1448
1449 /* This is where out-of-place break is detected for the whole
1450 * decoding stack. Break is an error for everything that calls
1451 * QCBORDecode_Private_GetNextFullString(), so the check is
1452 * centralized here.
1453 */
1454 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1455 uReturn = QCBOR_ERR_BAD_BREAK;
1456 goto Done;
1457 }
1458
1459
1460 /* Skip out if not an indefinite-length string */
1461 const uint8_t uStringType = pDecodedItem->uDataType;
1462 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1463 uStringType != QCBOR_TYPE_TEXT_STRING) {
1464 goto Done;
1465 }
1466 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1467 goto Done;
1468 }
1469
1470 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1471 /* Can't decode indefinite-length strings without a string allocator */
1472 if(!pMe->StringAllocator.pfAllocator) {
1473 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1474 goto Done;
1475 }
1476
1477 /* Loop getting chunks of the indefinite-length string */
1478 UsefulBufC FullString = NULLUsefulBufC;
1479
1480 for(;;) {
1481 /* Get QCBORItem for next chunk */
1482 QCBORItem StringChunkItem;
1483 /* Pass false to DecodeAtomicDataItem() because the individual
1484 * string chunks in an indefinite-length must not be
1485 * allocated. They are always copied into the allocated
1486 * contiguous buffer allocated here.
1487 */
1488 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
1489 if(uReturn) {
1490 break;
1491 }
1492
1493 /* Is item is the marker for end of the indefinite-length string? */
1494 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
1495 /* String is complete */
1496 pDecodedItem->val.string = FullString;
1497 pDecodedItem->uDataAlloc = 1;
1498 break;
1499 }
1500
1501 /* All chunks must be of the same type, the type of the item
1502 * that introduces the indefinite-length string. This also
1503 * catches errors where the chunk is not a string at all and an
1504 * indefinite-length string inside an indefinite-length string.
1505 */
1506 if(StringChunkItem.uDataType != uStringType ||
1507 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1508 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
1509 break;
1510 }
1511
1512 if (StringChunkItem.val.string.len > 0) {
1513 /* The first time throurgh FullString.ptr is NULL and this is
1514 * equivalent to StringAllocator_Allocate(). Subsequently it is
1515 * not NULL and a reallocation happens.
1516 */
1517 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
1518 FullString.ptr,
1519 FullString.len + StringChunkItem.val.string.len);
1520 if(UsefulBuf_IsNULL(NewMem)) {
1521 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1522 break;
1523 }
1524
1525 /* Copy new string chunk to the end of accumulated string */
1526 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
1527 }
1528 }
1529
1530 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1531 /* Getting the item failed, clean up the allocated memory */
1532 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
1533 }
1534 #else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1535 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1536 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1537
1538 Done:
1539 return uReturn;
1540 }
1541
1542
1543 #ifndef QCBOR_DISABLE_TAGS
1544 /**
1545 * @brief This converts a tag number to a shorter mapped value for storage.
1546 *
1547 * @param[in] pMe The decode context.
1548 * @param[in] uUnMappedTag The tag number to map
1549 * @param[out] puMappedTagNumer The stored tag number.
1550 *
1551 * @return error code.
1552 *
1553 * The main point of mapping tag numbers is make QCBORItem
1554 * smaller. With this mapping storage of 4 tags takes up 8
1555 * bytes. Without, it would take up 32 bytes.
1556 *
1557 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1558 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1559 *
1560 * See also UnMapTagNumber() and @ref QCBORItem.
1561 */
1562 static QCBORError
QCBORDecode_Private_MapTagNumber(QCBORDecodeContext * pMe,const uint64_t uUnMappedTag,uint16_t * puMappedTagNumer)1563 QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1564 const uint64_t uUnMappedTag,
1565 uint16_t *puMappedTagNumer)
1566 {
1567 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1568 unsigned uTagMapIndex;
1569 /* Is there room in the tag map, or is it in it already? */
1570 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1571 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1572 break;
1573 }
1574 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1575 break;
1576 }
1577 }
1578 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1579 return QCBOR_ERR_TOO_MANY_TAGS;
1580 }
1581
1582 /* Covers the cases where tag is new and were it is already in the map */
1583 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1584 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1585
1586 } else {
1587 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1588 }
1589
1590 return QCBOR_SUCCESS;
1591 }
1592
1593
1594 /**
1595 * @brief This converts a mapped tag number to the actual tag number.
1596 *
1597 * @param[in] pMe The decode context.
1598 * @param[in] uMappedTagNumber The stored tag number.
1599 *
1600 * @return The actual tag number is returned or
1601 * @ref CBOR_TAG_INVALID64 on error.
1602 *
1603 * This is the reverse of MapTagNumber()
1604 */
1605 static uint64_t
QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext * pMe,const uint16_t uMappedTagNumber)1606 QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1607 const uint16_t uMappedTagNumber)
1608 {
1609 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1610 return uMappedTagNumber;
1611 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
1612 return CBOR_TAG_INVALID64;
1613 } else {
1614 /* This won't be negative because of code below in
1615 * MapTagNumber()
1616 */
1617 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1618 return pMe->auMappedTags[uIndex];
1619 }
1620 }
1621 #endif /* QCBOR_DISABLE_TAGS */
1622
1623
1624 /**
1625 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1626 *
1627 * @param[in] pMe Decoder context
1628 * @param[out] pDecodedItem The decoded item that work is done on.
1629 *
1630 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1631 * features
1632 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1633 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1634 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1635 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1636 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1637 * of half-precision disabled
1638 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1639 * float decode is disabled.
1640 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1641 * simple type in input.
1642 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1643 * in input, but indefinite
1644 * lengths disabled.
1645 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1646 * but no string allocator.
1647 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1648 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1649 * input, but indefinite-length
1650 * strings are disabled.
1651 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1652 *
1653 * This loops getting atomic data items until one is not a tag
1654 * number. Usually this is largely pass-through because most
1655 * item are not tag numbers.
1656 */
1657 static QCBORError
QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)1658 QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1659 QCBORItem *pDecodedItem)
1660 {
1661 #ifndef QCBOR_DISABLE_TAGS
1662 /* Accummulate the tags from multiple items here and then copy them
1663 * into the last item, the non-tag item.
1664 */
1665 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1666
1667 /* Initialize to CBOR_TAG_INVALID16 */
1668 #if CBOR_TAG_INVALID16 != 0xffff
1669 /* Be sure the memset does the right thing. */
1670 #err CBOR_TAG_INVALID16 tag not defined as expected
1671 #endif
1672 memset(auItemsTags, 0xff, sizeof(auItemsTags));
1673
1674 QCBORError uReturn = QCBOR_SUCCESS;
1675
1676 /* Loop fetching data items until the item fetched is not a tag */
1677 for(;;) {
1678 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
1679 if(uErr != QCBOR_SUCCESS) {
1680 uReturn = uErr;
1681 goto Done;
1682 }
1683
1684 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
1685 /* Successful exit from loop; maybe got some tags, maybe not */
1686 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
1687 break;
1688 }
1689
1690 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1691 /* No room in the tag list */
1692 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
1693 /* Continue on to get all tags wrapping this item even though
1694 * it is erroring out in the end. This allows decoding to
1695 * continue. This is a resource limit error, not a problem
1696 * with being well-formed CBOR.
1697 */
1698 continue;
1699 }
1700 /* Slide tags over one in the array to make room at index 0.
1701 * Must use memmove because the move source and destination
1702 * overlap.
1703 */
1704 memmove(&auItemsTags[1],
1705 auItemsTags,
1706 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
1707
1708 /* Map the tag */
1709 uint16_t uMappedTagNumber = 0;
1710 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
1711 /* Continue even on error so as to consume all tags wrapping
1712 * this data item so decoding can go on. If MapTagNumber()
1713 * errors once it will continue to error.
1714 */
1715 auItemsTags[0] = uMappedTagNumber;
1716 }
1717
1718 Done:
1719 return uReturn;
1720
1721 #else /* QCBOR_DISABLE_TAGS */
1722
1723 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
1724
1725 #endif /* QCBOR_DISABLE_TAGS */
1726 }
1727
1728
1729 /**
1730 * @brief Combine a map entry label and value into one item (decode layer 3).
1731 *
1732 * @param[in] pMe Decoder context
1733 * @param[out] pDecodedItem The decoded item that work is done on.
1734 *
1735 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1736 * features
1737 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1738 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1739 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1740 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1741 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1742 * of half-precision disabled
1743 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1744 * float decode is disabled.
1745 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1746 * simple type in input.
1747 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1748 * in input, but indefinite
1749 * lengths disabled.
1750 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1751 * but no string allocator.
1752 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1753 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1754 * input, but indefinite-length
1755 * strings are disabled.
1756 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1757 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1758 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1759 *
1760 * If the current nesting level is a map, then this combines pairs of
1761 * items into one data item with a label and value.
1762 *
1763 * This is passthrough if the current nesting level is not a map.
1764 *
1765 * This also implements maps-as-array mode where a map is treated like
1766 * an array to allow caller to do their own label processing.
1767 */
1768
1769 static QCBORError
QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)1770 QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1771 QCBORItem *pDecodedItem)
1772 {
1773 QCBORItem LabelItem;
1774 QCBORError uErr;
1775
1776 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1777 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1778 goto Done;
1779 }
1780
1781 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1782 /* Not decoding a map. Nothing to do. */
1783 /* When decoding maps-as-arrays, the type will be
1784 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
1785 * here. This is now map processing for maps-as-arrays is not
1786 * done. */
1787 goto Done;
1788 }
1789
1790 /* Decoding a map entry, so the item decoded above was the label */
1791 LabelItem = *pDecodedItem;
1792
1793 /* Get the value of the map item */
1794 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1795 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1796 goto Done;
1797 }
1798
1799 /* Combine the label item and value item into one */
1800 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1801 pDecodedItem->uLabelType = LabelItem.uDataType;
1802
1803 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1804 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
1805 * get rid of it in QCBOR 2.0
1806 */
1807 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1808 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1809 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1810 goto Done;
1811 }
1812 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1813
1814 switch(LabelItem.uDataType) {
1815 case QCBOR_TYPE_INT64:
1816 pDecodedItem->label.int64 = LabelItem.val.int64;
1817 break;
1818
1819 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1820 case QCBOR_TYPE_UINT64:
1821 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1822 break;
1823
1824 case QCBOR_TYPE_TEXT_STRING:
1825 case QCBOR_TYPE_BYTE_STRING:
1826 pDecodedItem->label.string = LabelItem.val.string;
1827 break;
1828 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1829
1830 default:
1831 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1832 goto Done;
1833 }
1834
1835 Done:
1836 return uErr;
1837 }
1838
1839
1840 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1841 /**
1842 * @brief Peek and see if next data item is a break;
1843 *
1844 * param[in] pUIB UsefulInputBuf to read from.
1845 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1846 *
1847 * @return Any decoding error.
1848 *
1849 * See if next item is a CBOR break. If it is, it is consumed,
1850 * if not it is not consumed.
1851 */
1852 static QCBORError
QCBOR_Private_NextIsBreak(QCBORDecodeContext * pMe,bool * pbNextIsBreak)1853 QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
1854 {
1855 *pbNextIsBreak = false;
1856 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
1857 QCBORItem Peek;
1858 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
1859 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
1860 if(uReturn != QCBOR_SUCCESS) {
1861 return uReturn;
1862 }
1863 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1864 /* It is not a break, rewind so it can be processed normally. */
1865 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
1866 } else {
1867 *pbNextIsBreak = true;
1868 }
1869 }
1870
1871 return QCBOR_SUCCESS;
1872 }
1873 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1874
1875
1876 /**
1877 * @brief Ascend up nesting levels if all items in them have been consumed.
1878 *
1879 * @param[in] pMe The decode context.
1880 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
1881 * @param[out] pbBreak Set to true if extra break was consumed.
1882 *
1883 * An item was just consumed, now figure out if it was the
1884 * end of an array/map map that can be closed out. That
1885 * may in turn close out the above array/map...
1886 *
1887 * When ascending indefinite-length arrays and maps, this will correctly
1888 * consume the break for the level above. This is a problem for the
1889 * implementation of QCBORDecode_GetArray() that must not return
1890 * that break. @c pbBreak is set to true to indicate that one
1891 * byte should be removed.
1892 *
1893 * Improvement: this could reduced further if indef is disabled
1894 */
1895 static QCBORError
QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext * pMe,bool bMarkEnd,bool * pbBreak)1896 QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
1897 {
1898 QCBORError uReturn;
1899
1900 /* Loop ascending nesting levels as long as there is ascending to do */
1901 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
1902 if(pbBreak) {
1903 *pbBreak = false;
1904 }
1905
1906 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1907 /* Nesting level is bstr-wrapped CBOR */
1908
1909 /* Ascent for bstr-wrapped CBOR is always by explicit call
1910 * so no further ascending can happen.
1911 */
1912 break;
1913
1914 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1915 /* Level is a definite-length array/map */
1916
1917 /* Decrement the item count the definite-length array/map */
1918 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1919 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
1920 /* Didn't close out array/map, so all work here is done */
1921 break;
1922 }
1923 /* All items in a definite-length array were consumed so it
1924 * is time to ascend one level. This happens below.
1925 */
1926
1927 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1928 } else {
1929 /* Level is an indefinite-length array/map. */
1930
1931 /* Check for a break which is what ends indefinite-length arrays/maps */
1932 bool bIsBreak = false;
1933 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
1934 if(uReturn != QCBOR_SUCCESS) {
1935 goto Done;
1936 }
1937
1938 if(!bIsBreak) {
1939 /* Not a break so array/map does not close out. All work is done */
1940 break;
1941 }
1942
1943 /* It was a break in an indefinitelength map / array so
1944 * it is time to ascend one level.
1945 */
1946 if(pbBreak) {
1947 *pbBreak = true;
1948 }
1949
1950 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1951 }
1952
1953
1954 /* All items in the array/map have been consumed. */
1955
1956 /* But ascent in bounded mode is only by explicit call to
1957 * QCBORDecode_ExitBoundedMode().
1958 */
1959 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
1960 /* Set the count to zero for definite-length arrays to indicate
1961 * cursor is at end of bounded array/map */
1962 if(bMarkEnd) {
1963 /* Used for definite and indefinite to signal end */
1964 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
1965
1966 }
1967 break;
1968 }
1969
1970 /* Finally, actually ascend one level. */
1971 DecodeNesting_Ascend(&(pMe->nesting));
1972 }
1973
1974 uReturn = QCBOR_SUCCESS;
1975
1976 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1977 Done:
1978 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1979
1980 return uReturn;
1981 }
1982
1983
1984 /**
1985 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1986 *
1987 * @param[in] pMe Decoder context
1988 * @param[out] pbBreak Set to true if extra break was consumed.
1989 * @param[out] pDecodedItem The decoded item that work is done on.
1990
1991 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1992 * features
1993 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1994 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1995 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1996 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1997 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1998 * of half-precision disabled
1999 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2000 * float decode is disabled.
2001 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2002 * simple type in input.
2003 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2004 * in input, but indefinite
2005 * lengths disabled.
2006 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2007 * but no string allocator.
2008 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2009 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2010 * input, but indefinite-length
2011 * strings are disabled.
2012 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2013 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2014 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2015 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2016 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2017 * place.
2018 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2019 * can handle.
2020 *
2021 * This handles the traversal descending into and asecnding out of
2022 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2023 * definite- and indefinte-length maps and arrays by looking at the
2024 * item count or finding CBOR breaks. It detects the ends of the
2025 * top-level sequence and of bstr-wrapped CBOR by byte count.
2026 */
2027 static QCBORError
QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext * pMe,bool * pbBreak,QCBORItem * pDecodedItem)2028 QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
2029 bool *pbBreak,
2030 QCBORItem *pDecodedItem)
2031 {
2032 QCBORError uReturn;
2033 /* ==== First: figure out if at the end of a traversal ==== */
2034
2035 /* If out of bytes to consume, it is either the end of the
2036 * top-level sequence of some bstr-wrapped CBOR that was entered.
2037 *
2038 * In the case of bstr-wrapped CBOR, the length of the
2039 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2040 * the bstr-wrapped CBOR is exited, the length is set back to the
2041 * top-level's length or to the next highest bstr-wrapped CBOR.
2042 */
2043 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
2044 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
2045 goto Done;
2046 }
2047
2048 /* Check to see if at the end of a bounded definite-length map or
2049 * array. The check for a break ending indefinite-length array is
2050 * later in QCBORDecode_NestLevelAscender().
2051 */
2052 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
2053 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
2054 goto Done;
2055 }
2056
2057 /* ==== Next: not at the end, so get another item ==== */
2058 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
2059 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2060 /* Error is so bad that traversal is not possible. */
2061 goto Done;
2062 }
2063
2064 /* Record the nesting level for this data item before processing
2065 * any of decrementing and descending.
2066 */
2067 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
2068
2069
2070 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
2071 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
2072 /* If the new item is a map or array, descend.
2073 *
2074 * Empty indefinite-length maps and arrays are descended into,
2075 * but then ascended out of in the next chunk of code.
2076 *
2077 * Maps and arrays do count as items in the map/array that
2078 * encloses them so a decrement needs to be done for them too,
2079 * but that is done only when all the items in them have been
2080 * processed, not when they are opened with the exception of an
2081 * empty map or array.
2082 */
2083 QCBORError uDescendErr;
2084 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
2085 pDecodedItem->uDataType,
2086 pDecodedItem->val.uCount);
2087 if(uDescendErr != QCBOR_SUCCESS) {
2088 /* This error is probably a traversal error and it overrides
2089 * the non-traversal error.
2090 */
2091 uReturn = uDescendErr;
2092 goto Done;
2093 }
2094 }
2095
2096 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2097 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2098 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
2099 /* The following cases are handled here:
2100 * - A non-aggregate item like an integer or string
2101 * - An empty definite-length map or array
2102 * - An indefinite-length map or array that might be empty or might not.
2103 *
2104 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2105 * for an definite-length map/array and break detection for an
2106 * indefinite-0length map/array. If the end of the map/array was
2107 * reached, then it ascends nesting levels, possibly all the way
2108 * to the top level.
2109 */
2110 QCBORError uAscendErr;
2111 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
2112 if(uAscendErr != QCBOR_SUCCESS) {
2113 /* This error is probably a traversal error and it overrides
2114 * the non-traversal error.
2115 */
2116 uReturn = uAscendErr;
2117 goto Done;
2118 }
2119 }
2120
2121 /* ==== Last: tell the caller the nest level of the next item ==== */
2122 /* Tell the caller what level is next. This tells them what
2123 * maps/arrays were closed out and makes it possible for them to
2124 * reconstruct the tree with just the information returned in a
2125 * QCBORItem.
2126 */
2127 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
2128 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
2129 pDecodedItem->uNextNestLevel = 0;
2130 } else {
2131 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
2132 }
2133
2134 Done:
2135 return uReturn;
2136 }
2137
2138
2139 #ifndef QCBOR_DISABLE_TAGS
2140 /**
2141 * @brief Shift 0th tag out of the tag list.
2142 *
2143 * pDecodedItem[in,out] The data item to convert.
2144 *
2145 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2146 * shifted into empty slot at the end of the tag list.
2147 */
2148 static void
QCBOR_Private_ShiftTags(QCBORItem * pDecodedItem)2149 QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
2150 {
2151 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2152 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2153 }
2154 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
2155 }
2156 #endif /* QCBOR_DISABLE_TAGS */
2157
2158
2159 /**
2160 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2161 *
2162 * pDecodedItem[in,out] The data item to convert.
2163 *
2164 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2165 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2166 * floating-point date disabled.
2167 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2168 * all floating-point disabled.
2169 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2170 * error decoding date.
2171 *
2172 * The epoch date tag defined in QCBOR allows for floating-point
2173 * dates. It even allows a protocol to flop between date formats when
2174 * ever it wants. Floating-point dates aren't that useful as they are
2175 * only needed for dates beyond the age of the earth.
2176 *
2177 * This converts all the date formats into one format of an unsigned
2178 * integer plus a floating-point fraction.
2179 */
2180 static QCBORError
QCBOR_Private_DecodeDateEpoch(QCBORItem * pDecodedItem)2181 QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
2182 {
2183 QCBORError uReturn = QCBOR_SUCCESS;
2184
2185 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
2186 pDecodedItem->val.epochDate.fSecondsFraction = 0;
2187 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
2188
2189 switch (pDecodedItem->uDataType) {
2190
2191 case QCBOR_TYPE_INT64:
2192 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2193 break;
2194
2195 case QCBOR_TYPE_UINT64:
2196 /* This only happens for CBOR type 0 > INT64_MAX so it is
2197 * always an overflow.
2198 */
2199 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2200 goto Done;
2201 break;
2202
2203 case QCBOR_TYPE_DOUBLE:
2204 case QCBOR_TYPE_FLOAT:
2205 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
2206 {
2207 /* Convert working value to double if input was a float */
2208 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
2209 pDecodedItem->val.dfnum :
2210 (double)pDecodedItem->val.fnum;
2211
2212 /* The conversion from float to integer requires overflow
2213 * detection since floats can be much larger than integers.
2214 * This implementation errors out on these large float values
2215 * since they are beyond the age of the earth.
2216 *
2217 * These constants for the overflow check are computed by the
2218 * compiler. They are not computed at run time.
2219 *
2220 * The factor of 0x7ff is added/subtracted to avoid a
2221 * rounding error in the wrong direction when the compiler
2222 * computes these constants. There is rounding because a
2223 * 64-bit integer has 63 bits of precision where a double
2224 * only has 53 bits. Without the 0x7ff factor, the compiler
2225 * may round up and produce a double for the bounds check
2226 * that is larger than can be stored in a 64-bit integer. The
2227 * amount of 0x7ff is picked because it has 11 bits set.
2228 *
2229 * Without the 0x7ff there is a ~30 minute range of time
2230 * values 10 billion years in the past and in the future
2231 * where this code could go wrong. Some compilers
2232 * generate a warning or error without the 0x7ff.
2233 */
2234 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2235 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2236
2237 if(isnan(d) || d > dDateMax || d < dDateMin) {
2238 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2239 goto Done;
2240 }
2241
2242 /* The actual conversion */
2243 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
2244 pDecodedItem->val.epochDate.fSecondsFraction =
2245 d - (double)pDecodedItem->val.epochDate.nSeconds;
2246 }
2247 #else /* QCBOR_DISABLE_FLOAT_HW_USE */
2248
2249 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
2250 goto Done;
2251
2252 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
2253 break;
2254
2255 default:
2256 /* It's the arrays and maps that are unrecoverable because
2257 * they are not consumed here. Since this is just an error
2258 * condition, no extra code is added here to make the error
2259 * recoverable for non-arrays and maps like strings. */
2260 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
2261 goto Done;
2262 }
2263
2264 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2265
2266 Done:
2267 return uReturn;
2268 }
2269
2270
2271 /**
2272 * @brief Convert the days epoch date.
2273 *
2274 * pDecodedItem[in,out] The data item to convert.
2275 *
2276 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2277 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2278 * floating-point date disabled.
2279 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2280 * all floating-point disabled.
2281 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2282 * error decoding date.
2283 *
2284 * This is much simpler than the other epoch date format because
2285 * floating-porint is not allowed. This is mostly a simple type check.
2286 */
2287 static QCBORError
QCBOR_Private_DecodeDaysEpoch(QCBORItem * pDecodedItem)2288 QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
2289 {
2290 QCBORError uReturn = QCBOR_SUCCESS;
2291
2292 switch (pDecodedItem->uDataType) {
2293
2294 case QCBOR_TYPE_INT64:
2295 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2296 break;
2297
2298 case QCBOR_TYPE_UINT64:
2299 /* This only happens for CBOR type 0 > INT64_MAX so it is
2300 * always an overflow.
2301 */
2302 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2303 goto Done;
2304 break;
2305
2306 default:
2307 /* It's the arrays and maps that are unrecoverable because
2308 * they are not consumed here. Since this is just an error
2309 * condition, no extra code is added here to make the error
2310 * recoverable for non-arrays and maps like strings. */
2311 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
2312 goto Done;
2313 break;
2314 }
2315
2316 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2317
2318 Done:
2319 return uReturn;
2320 }
2321
2322
2323 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
2324
2325 /* Forward declaration is necessary for
2326 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2327 * tags in the mantissa. If the mantissa is a decimal fraction or big
2328 * float in error, this will result in a recurive call to
2329 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2330 * correctly and the correct error is returned.
2331 */
2332 static QCBORError
2333 QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2334 QCBORItem *pDecodedItem);
2335
2336
2337 /**
2338 * @brief Decode decimal fractions and big floats.
2339 *
2340 * @param[in] pMe The decode context.
2341 * @param[in,out] pDecodedItem On input the array data item that
2342 * holds the mantissa and exponent. On
2343 * output the decoded mantissa and
2344 * exponent.
2345 *
2346 * @returns Decoding errors from getting primitive data items or
2347 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2348 *
2349 * When called pDecodedItem must be the array with two members, the
2350 * exponent and mantissa.
2351 *
2352 * This will fetch and decode the exponent and mantissa and put the
2353 * result back into pDecodedItem.
2354 *
2355 * This does no checking or processing of tag numbers. That is to be
2356 * done by the code that calls this.
2357 *
2358 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2359 * the caller will process it.
2360 */
2361 static QCBORError
QCBORDecode_Private_ExpMantissa(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)2362 QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2363 QCBORItem *pDecodedItem)
2364 {
2365 QCBORError uReturn;
2366
2367 /* --- Make sure it is an array; track nesting level of members --- */
2368 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
2369 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
2370 goto Done;
2371 }
2372
2373 /* A check for pDecodedItem->val.uCount == 2 would work for
2374 * definite-length arrays, but not for indefinite. Instead remember
2375 * the nesting level the two integers must be at, which is one
2376 * deeper than that of the array.
2377 */
2378 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2379
2380 /* --- Get the exponent --- */
2381 QCBORItem exponentItem;
2382 uReturn = QCBORDecode_GetNext(pMe, &exponentItem);
2383 if(uReturn != QCBOR_SUCCESS) {
2384 goto Done;
2385 }
2386 if(exponentItem.uNestingLevel != nNestLevel) {
2387 /* Array is empty or a map/array encountered when expecting an int */
2388 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
2389 goto Done;
2390 }
2391 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
2392 /* Data arriving as an unsigned int < INT64_MAX has been
2393 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2394 * also means that the only data arriving here of type
2395 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2396 * and thus an error that will get handled in the next else.
2397 */
2398 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2399 } else {
2400 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2401 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
2402 goto Done;
2403 }
2404
2405 /* --- Get the mantissa --- */
2406 QCBORItem mantissaItem;
2407 uReturn = QCBORDecode_GetNext(pMe, &mantissaItem);
2408 if(uReturn != QCBOR_SUCCESS) {
2409 goto Done;
2410 }
2411 if(mantissaItem.uNestingLevel != nNestLevel) {
2412 /* Mantissa missing or map/array encountered when expecting number */
2413 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
2414 goto Done;
2415 }
2416 /* Stuff the mantissa data type into the item to send it up to the
2417 * the next level. */
2418 pDecodedItem->uDataType = mantissaItem.uDataType;
2419 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
2420 /* Data arriving as an unsigned int < INT64_MAX has been
2421 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2422 * also means that the only data arriving here of type
2423 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2424 * and thus an error that will get handled in an else below.
2425 */
2426 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
2427 #ifndef QCBOR_DISABLE_TAGS
2428 /* With tags fully disabled a big number mantissa will error out
2429 * in the call to QCBORDecode_GetNextWithTags() because it has
2430 * a tag number.
2431 */
2432 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2433 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
2434 /* Got a good big num mantissa */
2435 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
2436 #endif /* QCBOR_DISABLE_TAGS */
2437 } else {
2438 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2439 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
2440 goto Done;
2441 }
2442
2443 /* --- Check that array only has the two numbers --- */
2444 if(mantissaItem.uNextNestLevel == nNestLevel) {
2445 /* Extra items in the decimal fraction / big float */
2446 /* Improvement: this should probably be an unrecoverable error. */
2447 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
2448 goto Done;
2449 }
2450 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
2451
2452 Done:
2453 return uReturn;
2454 }
2455 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
2456
2457
2458 #ifndef QCBOR_DISABLE_TAGS
2459
2460 #ifndef QCBOR_DISABLE_UNCOMMON_TAGS
2461 /**
2462 * @brief Decode the MIME type tag
2463 *
2464 * @param[in,out] pDecodedItem The item to decode.
2465 *
2466 * Handle the text and binary MIME type tags. Slightly too complicated
2467 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2468 * incorreclty text-only.
2469 */
2470 static QCBORError
QCBOR_Private_DecodeMIME(QCBORItem * pDecodedItem)2471 QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
2472 {
2473 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2474 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
2475 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
2476 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2477 } else {
2478 /* It's the arrays and maps that are unrecoverable because
2479 * they are not consumed here. Since this is just an error
2480 * condition, no extra code is added here to make the error
2481 * recoverable for non-arrays and maps like strings. */
2482 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
2483 }
2484
2485 return QCBOR_SUCCESS;
2486 }
2487 #endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
2488
2489 /**
2490 * Table of CBOR tags whose content is either a text string or a byte
2491 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2492 * of uQCBORtype indicates the content should be a byte string rather
2493 * than a text string
2494 */
2495 struct StringTagMapEntry {
2496 uint16_t uTagNumber;
2497 uint8_t uQCBORtype;
2498 };
2499
2500 #define IS_BYTE_STRING_BIT 0x80
2501 #define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2502
2503 static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
2504 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
2505 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
2506 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2507 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2508 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2509 {CBOR_TAG_URI, QCBOR_TYPE_URI},
2510 #ifndef QCBOR_DISABLE_UNCOMMON_TAGS
2511 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2512 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2513 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2514 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
2515 #endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
2516 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2517 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2518 };
2519
2520
2521 /**
2522 * @brief Process standard CBOR tags whose content is a string
2523 *
2524 * @param[in] uTag The tag.
2525 * @param[in,out] pDecodedItem The data item.
2526 *
2527 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2528 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
2529 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
2530 *
2531 * Process the CBOR tags that whose content is a byte string or a text
2532 * string and for which the string is just passed on to the caller.
2533 *
2534 * This maps the CBOR tag to the QCBOR type and checks the content
2535 * type. Nothing more. It may not be the most important
2536 * functionality, but it part of implementing as much of RFC 8949 as
2537 * possible.
2538 */
2539 static QCBORError
QCBOR_Private_ProcessTaggedString(uint16_t uTag,QCBORItem * pDecodedItem)2540 QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
2541 {
2542 /* This only works on tags that were not mapped; no need for other yet */
2543 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2544 return QCBOR_ERR_UNSUPPORTED;
2545 }
2546
2547 unsigned uIndex;
2548 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2549 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
2550 break;
2551 }
2552 }
2553
2554 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
2555 if(uQCBORType == QCBOR_TYPE_NONE) {
2556 /* repurpose this error to mean not handled here */
2557 return QCBOR_ERR_UNSUPPORTED;
2558 }
2559
2560 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2561 if(uQCBORType & IS_BYTE_STRING_BIT) {
2562 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2563 }
2564
2565 if(pDecodedItem->uDataType != uExpectedType) {
2566 /* It's the arrays and maps that are unrecoverable because
2567 * they are not consumed here. Since this is just an error
2568 * condition, no extra code is added here to make the error
2569 * recoverable for non-arrays and maps like strings. */
2570 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
2571 }
2572
2573 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
2574 return QCBOR_SUCCESS;
2575 }
2576 #endif /* QCBOR_DISABLE_TAGS */
2577
2578
2579 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
2580 /**
2581 * @brief Figures out data type for exponent mantissa tags.
2582 *
2583 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2584 * @ref CBOR_TAG_BIG_FLOAT.
2585 * @param[in] pDecodedItem Item being decoded.
2586 *
2587 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2588 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2589 *
2590 * Does mapping between a CBOR tag number and a QCBOR type. with a
2591 * little bit of logic and arithmatic.
2592 *
2593 * Used in serveral contexts. Does the work where sometimes the data
2594 * item is explicitly tagged and sometimes not.
2595 */
2596 static uint8_t
QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,const QCBORItem * pDecodedItem)2597 QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
2598 const QCBORItem *pDecodedItem)
2599 {
2600 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2601 QCBOR_TYPE_DECIMAL_FRACTION :
2602 QCBOR_TYPE_BIGFLOAT;
2603 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2604 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2605 }
2606 return uBase;
2607 }
2608 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
2609
2610
2611 /**
2612 * @brief Decode tag content for select tags (decoding layer 1).
2613 *
2614 * @param[in] pMe The decode context.
2615 * @param[out] pDecodedItem The decoded item.
2616 *
2617 * @return Decoding error code.
2618 *
2619 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2620 * but the whole tag was not decoded. Here, the whole tags (tag number
2621 * and tag content) that are supported by QCBOR are decoded. This is a
2622 * quick pass through for items that are not tags.
2623 */
2624 static QCBORError
QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)2625 QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2626 QCBORItem *pDecodedItem)
2627 {
2628 QCBORError uReturn;
2629
2630 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
2631 if(uReturn != QCBOR_SUCCESS) {
2632 goto Done;
2633 }
2634
2635 #ifndef QCBOR_DISABLE_TAGS
2636 /* When there are no tag numbers for the item, this exits first
2637 * thing and effectively does nothing.
2638 *
2639 * This loops over all the tag numbers accumulated for this item
2640 * trying to decode and interpret them. This stops at the end of
2641 * the list or at the first tag number that can't be interpreted by
2642 * this code. This is effectively a recursive processing of the
2643 * tags number list that handles nested tags.
2644 */
2645 while(1) {
2646 /* Don't bother to unmap tags via QCBORITem.uTags since this
2647 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2648 */
2649 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
2650
2651 if(uTagToProcess == CBOR_TAG_INVALID16) {
2652 /* Hit the end of the tag list. A successful exit. */
2653 break;
2654
2655 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
2656 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
2657
2658 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
2659 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
2660
2661 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
2662 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2663 uTagToProcess == CBOR_TAG_BIGFLOAT) {
2664 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
2665 /* --- Which is it, decimal fraction or a bigfloat? --- */
2666 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
2667
2668 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
2669 #ifndef QCBOR_DISABLE_UNCOMMON_TAGS
2670 } else if(uTagToProcess == CBOR_TAG_MIME ||
2671 uTagToProcess == CBOR_TAG_BINARY_MIME) {
2672 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
2673 #endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
2674
2675 } else {
2676 /* See if it is a passthrough byte/text string tag; process if so */
2677 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
2678
2679 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
2680 /* It wasn't a passthrough byte/text string tag so it is
2681 * an unknown tag. This is the exit from the loop on the
2682 * first unknown tag. It is a successful exit.
2683 */
2684 uReturn = QCBOR_SUCCESS;
2685 break;
2686 }
2687 }
2688
2689 if(uReturn != QCBOR_SUCCESS) {
2690 /* Error exit from the loop */
2691 break;
2692 }
2693
2694 /* A tag was successfully processed, shift it out of the list of
2695 * tags returned. This is the loop increment.
2696 */
2697 QCBOR_Private_ShiftTags(pDecodedItem);
2698 }
2699 #endif /* QCBOR_DISABLE_TAGS */
2700
2701 Done:
2702 return uReturn;
2703 }
2704
2705
2706 /*
2707 * Public function, see header qcbor/qcbor_decode.h file
2708 */
2709 QCBORError
QCBORDecode_GetNext(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)2710 QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2711 {
2712 QCBORError uErr;
2713 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
2714 if(uErr != QCBOR_SUCCESS) {
2715 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2716 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2717 }
2718 return uErr;
2719 }
2720
2721
2722 /*
2723 * Public function, see header qcbor/qcbor_decode.h file
2724 */
2725 QCBORError
QCBORDecode_PeekNext(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)2726 QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2727 {
2728 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2729 const UsefulInputBuf Save = pMe->InBuf;
2730
2731 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2732
2733 pMe->nesting = SaveNesting;
2734 pMe->InBuf = Save;
2735
2736 return uErr;
2737 }
2738
2739
2740 /*
2741 * Public function, see header qcbor/qcbor_decode.h file
2742 */
2743 void
QCBORDecode_VPeekNext(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)2744 QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2745 {
2746 if(pMe->uLastError != QCBOR_SUCCESS) {
2747 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2748 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2749 return;
2750 }
2751
2752 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2753 }
2754
2755
2756 static void
QCBORDecode_Private_CopyTags(QCBORDecodeContext * pMe,const QCBORItem * pItem)2757 QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
2758 {
2759 #ifndef QCBOR_DISABLE_TAGS
2760 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
2761 #else
2762 (void)pMe;
2763 (void)pItem;
2764 #endif
2765 }
2766
2767 /*
2768 * Public function, see header qcbor/qcbor_decode.h file
2769 */
2770 void
QCBORDecode_VGetNext(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)2771 QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2772 {
2773 if(pMe->uLastError != QCBOR_SUCCESS) {
2774 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2775 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2776 return;
2777 }
2778
2779 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2780 QCBORDecode_Private_CopyTags(pMe, pDecodedItem);
2781 }
2782
2783
2784 /*
2785 * Public function, see header qcbor/qcbor_decode.h file
2786 */
2787 QCBORError
QCBORDecode_GetNextWithTags(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem,QCBORTagListOut * pTags)2788 QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2789 QCBORItem *pDecodedItem,
2790 QCBORTagListOut *pTags)
2791 {
2792 #ifndef QCBOR_DISABLE_TAGS
2793
2794 QCBORError uReturn;
2795
2796 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2797 if(uReturn != QCBOR_SUCCESS) {
2798 return uReturn;
2799 }
2800
2801 if(pTags != NULL) {
2802 pTags->uNumUsed = 0;
2803 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
2804 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2805 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
2806 continue;
2807 }
2808 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2809 return QCBOR_ERR_TOO_MANY_TAGS;
2810 }
2811 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
2812 pTags->uNumUsed++;
2813 }
2814 }
2815
2816 return QCBOR_SUCCESS;
2817
2818 #else /* QCBOR_DISABLE_TAGS */
2819 (void)pMe;
2820 (void)pDecodedItem;
2821 (void)pTags;
2822 return QCBOR_ERR_TAGS_DISABLED;
2823 #endif /* QCBOR_DISABLE_TAGS */
2824 }
2825
2826
2827 /*
2828 * Public function, see header qcbor/qcbor_decode.h file
2829 */
2830 bool
QCBORDecode_IsTagged(QCBORDecodeContext * pMe,const QCBORItem * pItem,uint64_t uTag)2831 QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2832 const QCBORItem *pItem,
2833 uint64_t uTag)
2834 {
2835 #ifndef QCBOR_DISABLE_TAGS
2836 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2837 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
2838 break;
2839 }
2840 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
2841 return true;
2842 }
2843 }
2844 #else /* QCBOR_TAGS_DISABLED */
2845 (void)pMe;
2846 (void)pItem;
2847 (void)uTag;
2848 #endif /* QCBOR_TAGS_DISABLED */
2849
2850 return false;
2851 }
2852
2853
2854 /*
2855 * Public function, see header qcbor/qcbor_decode.h file
2856 */
2857 QCBORError
QCBORDecode_PartialFinish(QCBORDecodeContext * pMe,size_t * puConsumed)2858 QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
2859 {
2860 if(puConsumed != NULL) {
2861 *puConsumed = pMe->InBuf.cursor;
2862 }
2863
2864 QCBORError uReturn = pMe->uLastError;
2865
2866 if(uReturn != QCBOR_SUCCESS) {
2867 goto Done;
2868 }
2869
2870 /* Error out if all the maps/arrays are not closed out */
2871 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
2872 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
2873 goto Done;
2874 }
2875
2876 /* Error out if not all the bytes are consumed */
2877 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
2878 uReturn = QCBOR_ERR_EXTRA_BYTES;
2879 }
2880
2881 Done:
2882 return uReturn;
2883 }
2884
2885
2886 /*
2887 * Public function, see header qcbor/qcbor_decode.h file
2888 */
2889 QCBORError
QCBORDecode_Finish(QCBORDecodeContext * pMe)2890 QCBORDecode_Finish(QCBORDecodeContext *pMe)
2891 {
2892 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
2893 /* Call the destructor for the string allocator if there is one.
2894 * Always called, even if there are errors; always have to clean up.
2895 */
2896 StringAllocator_Destruct(&(pMe->StringAllocator));
2897 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
2898
2899 return QCBORDecode_PartialFinish(pMe, NULL);
2900 }
2901
2902
2903 /*
2904 * Public function, see header qcbor/qcbor_decode.h file
2905 */
2906 uint64_t
QCBORDecode_GetNthTag(QCBORDecodeContext * pMe,const QCBORItem * pItem,uint32_t uIndex)2907 QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2908 const QCBORItem *pItem,
2909 uint32_t uIndex)
2910 {
2911 #ifndef QCBOR_DISABLE_TAGS
2912 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2913 return CBOR_TAG_INVALID64;
2914 }
2915 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2916 return CBOR_TAG_INVALID64;
2917 } else {
2918 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
2919 }
2920 #else /* QCBOR_DISABLE_TAGS */
2921 (void)pMe;
2922 (void)pItem;
2923 (void)uIndex;
2924
2925 return CBOR_TAG_INVALID64;
2926 #endif /* QCBOR_DISABLE_TAGS */
2927 }
2928
2929
2930 /*
2931 * Public function, see header qcbor/qcbor_decode.h file
2932 */
2933 uint64_t
QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext * pMe,uint32_t uIndex)2934 QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2935 uint32_t uIndex)
2936 {
2937 #ifndef QCBOR_DISABLE_TAGS
2938
2939 if(pMe->uLastError != QCBOR_SUCCESS) {
2940 return CBOR_TAG_INVALID64;
2941 }
2942 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2943 return CBOR_TAG_INVALID64;
2944 } else {
2945 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
2946 }
2947 #else /* QCBOR_DISABLE_TAGS */
2948 (void)pMe;
2949 (void)uIndex;
2950
2951 return CBOR_TAG_INVALID64;
2952 #endif /* QCBOR_DISABLE_TAGS */
2953 }
2954
2955
2956
2957
2958 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
2959
2960 /* ===========================================================================
2961 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
2962
2963 This implements a simple sting allocator for indefinite-length
2964 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2965 implements the function type QCBORStringAllocate and allows easy
2966 use of it.
2967
2968 This particular allocator is built-in for convenience. The caller
2969 can implement their own. All of this following code will get
2970 dead-stripped if QCBORDecode_SetMemPool() is not called.
2971
2972 This is a very primitive memory allocator. It does not track
2973 individual allocations, only a high-water mark. A free or
2974 reallocation must be of the last chunk allocated.
2975
2976 The size of the pool and offset to free memory are packed into the
2977 first 8 bytes of the memory pool so we don't have to keep them in
2978 the decode context. Since the address of the pool may not be
2979 aligned, they have to be packed and unpacked as if they were
2980 serialized data of the wire or such.
2981
2982 The sizes packed in are uint32_t to be the same on all CPU types
2983 and simplify the code.
2984 ========================================================================== */
2985
2986
2987 static int
MemPool_Unpack(const void * pMem,uint32_t * puPoolSize,uint32_t * puFreeOffset)2988 MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
2989 {
2990 // Use of UsefulInputBuf is overkill, but it is convenient.
2991 UsefulInputBuf UIB;
2992
2993 // Just assume the size here. It was checked during SetUp so
2994 // the assumption is safe.
2995 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
2996 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2997 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2998 return UsefulInputBuf_GetError(&UIB);
2999 }
3000
3001
3002 static int
MemPool_Pack(UsefulBuf Pool,uint32_t uFreeOffset)3003 MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
3004 {
3005 // Use of UsefulOutBuf is overkill, but convenient. The
3006 // length check performed here is useful.
3007 UsefulOutBuf UOB;
3008
3009 UsefulOutBuf_Init(&UOB, Pool);
3010 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
3011 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3012 return UsefulOutBuf_GetError(&UOB);
3013 }
3014
3015
3016 /*
3017 Internal function for an allocation, reallocation free and destuct.
3018
3019 Having only one function rather than one each per mode saves space in
3020 QCBORDecodeContext.
3021
3022 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3023 */
3024 static UsefulBuf
MemPool_Function(void * pPool,void * pMem,size_t uNewSize)3025 MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
3026 {
3027 UsefulBuf ReturnValue = NULLUsefulBuf;
3028
3029 uint32_t uPoolSize;
3030 uint32_t uFreeOffset;
3031
3032 if(uNewSize > UINT32_MAX) {
3033 // This allocator is only good up to 4GB. This check should
3034 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3035 goto Done;
3036 }
3037 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3038
3039 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3040 goto Done;
3041 }
3042
3043 if(uNewSize) {
3044 if(pMem) {
3045 // REALLOCATION MODE
3046 // Calculate pointer to the end of the memory pool. It is
3047 // assumed that pPool + uPoolSize won't wrap around by
3048 // assuming the caller won't pass a pool buffer in that is
3049 // not in legitimate memory space.
3050 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3051
3052 // Check that the pointer for reallocation is in the range of the
3053 // pool. This also makes sure that pointer math further down
3054 // doesn't wrap under or over.
3055 if(pMem >= pPool && pMem < pPoolEnd) {
3056 // Offset to start of chunk for reallocation. This won't
3057 // wrap under because of check that pMem >= pPool. Cast
3058 // is safe because the pool is always less than UINT32_MAX
3059 // because of check in QCBORDecode_SetMemPool().
3060 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3061
3062 // Check to see if the allocation will fit. uPoolSize -
3063 // uMemOffset will not wrap under because of check that
3064 // pMem is in the range of the uPoolSize by check above.
3065 if(uNewSize <= uPoolSize - uMemOffset) {
3066 ReturnValue.ptr = pMem;
3067 ReturnValue.len = uNewSize;
3068
3069 // Addition won't wrap around over because uNewSize was
3070 // checked to be sure it is less than the pool size.
3071 uFreeOffset = uMemOffset + uNewSize32;
3072 }
3073 }
3074 } else {
3075 // ALLOCATION MODE
3076 // uPoolSize - uFreeOffset will not underflow because this
3077 // pool implementation makes sure uFreeOffset is always
3078 // smaller than uPoolSize through this check here and
3079 // reallocation case.
3080 if(uNewSize <= uPoolSize - uFreeOffset) {
3081 ReturnValue.len = uNewSize;
3082 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
3083 uFreeOffset += (uint32_t)uNewSize;
3084 }
3085 }
3086 } else {
3087 if(pMem) {
3088 // FREE MODE
3089 // Cast is safe because of limit on pool size in
3090 // QCBORDecode_SetMemPool()
3091 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3092 } else {
3093 // DESTRUCT MODE
3094 // Nothing to do for this allocator
3095 }
3096 }
3097
3098 UsefulBuf Pool = {pPool, uPoolSize};
3099 MemPool_Pack(Pool, uFreeOffset);
3100
3101 Done:
3102 return ReturnValue;
3103 }
3104
3105
3106 /*
3107 * Public function, see header qcbor/qcbor_decode.h file
3108 */
3109 QCBORError
QCBORDecode_SetMemPool(QCBORDecodeContext * pMe,UsefulBuf Pool,bool bAllStrings)3110 QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3111 UsefulBuf Pool,
3112 bool bAllStrings)
3113 {
3114 // The pool size and free mem offset are packed into the beginning
3115 // of the pool memory. This compile time check makes sure the
3116 // constant in the header is correct. This check should optimize
3117 // down to nothing.
3118 #ifdef _MSC_VER
3119 #pragma warning(push)
3120 #pragma warning(disable:4127) // conditional expression is constant
3121 #endif
3122 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
3123 return QCBOR_ERR_MEM_POOL_SIZE;
3124 }
3125 #ifdef _MSC_VER
3126 #pragma warning(pop)
3127 #endif
3128
3129 // The pool size and free offset packed in to the beginning of pool
3130 // memory are only 32-bits. This check will optimize out on 32-bit
3131 // machines.
3132 if(Pool.len > UINT32_MAX) {
3133 return QCBOR_ERR_MEM_POOL_SIZE;
3134 }
3135
3136 // This checks that the pool buffer given is big enough.
3137 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
3138 return QCBOR_ERR_MEM_POOL_SIZE;
3139 }
3140
3141 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
3142
3143 return QCBOR_SUCCESS;
3144 }
3145 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
3146
3147
3148
3149
3150 /**
3151 * @brief Consume an entire map or array including its contents.
3152 *
3153 * @param[in] pMe The decoder context.
3154 * @param[in] pItemToConsume The array/map whose contents are to be
3155 * consumed.
3156 * @param[out] puNextNestLevel The next nesting level after the item was
3157 * fully consumed.
3158 *
3159 * This may be called when @c pItemToConsume is not an array or
3160 * map. In that case, this is just a pass through for @c puNextNestLevel
3161 * since there is nothing to do.
3162 */
3163 static QCBORError
QCBORDecode_Private_ConsumeItem(QCBORDecodeContext * pMe,const QCBORItem * pItemToConsume,bool * pbBreak,uint8_t * puNextNestLevel)3164 QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3165 const QCBORItem *pItemToConsume,
3166 bool *pbBreak,
3167 uint8_t *puNextNestLevel)
3168 {
3169 QCBORError uReturn;
3170 QCBORItem Item;
3171
3172 /* If it is a map or array, this will tell if it is empty. */
3173 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3174
3175 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
3176 /* There is only real work to do for non-empty maps and arrays */
3177
3178 /* This works for definite- and indefinite-length maps and
3179 * arrays by using the nesting level
3180 */
3181 do {
3182 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
3183 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3184 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
3185 goto Done;
3186 }
3187 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
3188
3189 *puNextNestLevel = Item.uNextNestLevel;
3190
3191 uReturn = QCBOR_SUCCESS;
3192
3193 } else {
3194 /* pItemToConsume is not a map or array. Just pass the nesting
3195 * level through. */
3196 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3197
3198 uReturn = QCBOR_SUCCESS;
3199 }
3200
3201 Done:
3202 return uReturn;
3203 }
3204
3205
3206 /*
3207 * Public function, see header qcbor/qcbor_decode.h file
3208 */
3209 void
QCBORDecode_VGetNextConsume(QCBORDecodeContext * pMe,QCBORItem * pDecodedItem)3210 QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3211 {
3212 QCBORDecode_VGetNext(pMe, pDecodedItem);
3213
3214 if(pMe->uLastError == QCBOR_SUCCESS) {
3215 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
3216 &pDecodedItem->uNextNestLevel);
3217 }
3218 }
3219
3220
3221 /*
3222 * Public function, see header qcbor/qcbor_decode.h file
3223 */
3224 QCBORError
QCBORDecode_EndCheck(QCBORDecodeContext * pMe)3225 QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
3226 {
3227 size_t uCursorOffset;
3228 QCBORError uErr;
3229
3230 uErr = QCBORDecode_GetError(pMe);
3231 if(uErr != QCBOR_SUCCESS) {
3232 return uErr;
3233 }
3234
3235 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3236
3237 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3238 return QCBOR_ERR_NO_MORE_ITEMS;
3239 }
3240
3241 return QCBOR_SUCCESS;
3242 }
3243
3244
3245 /**
3246 * @brief Rewind cursor to start as if map or array were just entered.
3247 *
3248 * @param[in] pMe The decoding context
3249 *
3250 * This affects the nesting tracking and the UsefulInputBuf.
3251 */
3252 static void
QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext * pMe)3253 QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
3254 {
3255 /* Reset nesting tracking to the deepest bounded level */
3256 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3257
3258 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3259
3260 /* Reposition traversal cursor to the start of the map/array */
3261 UsefulInputBuf_Seek(&(pMe->InBuf),
3262 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3263 }
3264
3265
3266 /*
3267 * Public function, see header qcbor/qcbor_decode.h file
3268 */
3269 void
QCBORDecode_Rewind(QCBORDecodeContext * pMe)3270 QCBORDecode_Rewind(QCBORDecodeContext *pMe)
3271 {
3272 if(pMe->nesting.pCurrentBounded != NULL) {
3273 /* In a bounded map, array or bstr-wrapped CBOR */
3274
3275 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3276 /* In bstr-wrapped CBOR. */
3277
3278 /* Reposition traversal cursor to start of wrapping byte string */
3279 UsefulInputBuf_Seek(&(pMe->InBuf),
3280 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3281 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3282
3283 } else {
3284 /* In a map or array */
3285 QCBORDecode_Private_RewindMapOrArray(pMe);
3286 }
3287
3288 } else {
3289 /* Not in anything bounded */
3290
3291 /* Reposition traversal cursor to the start of input CBOR */
3292 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3293
3294 /* Reset nesting tracking to beginning of input. */
3295 DecodeNesting_Init(&(pMe->nesting));
3296 }
3297
3298 pMe->uLastError = QCBOR_SUCCESS;
3299 }
3300
3301
3302
3303
3304
3305 typedef struct {
3306 void *pCBContext;
3307 QCBORItemCallback pfCallback;
3308 } MapSearchCallBack;
3309
3310 typedef struct {
3311 size_t uStartOffset;
3312 uint16_t uItemCount;
3313 } MapSearchInfo;
3314
3315
3316 /**
3317 * @brief Search a map for a set of items.
3318 *
3319 * @param[in] pMe The decode context to search.
3320 * @param[in,out] pItemArray The items to search for and the items found.
3321 * @param[out] pInfo Several bits of meta-info returned by search.
3322 * @param[in] pCallBack Callback object or @c NULL.
3323 *
3324 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3325 *
3326 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3327 * were found for one of the labels being
3328 * search for. This duplicate detection is
3329 * only performed for items in pItemArray,
3330 * not every item in the map.
3331 *
3332 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3333 * wrong for the matchd label.
3334 *
3335 * @retval Also errors returned by QCBORDecode_GetNext().
3336 *
3337 * On input, \c pItemArray contains a list of labels and data types of
3338 * items to be found.
3339 *
3340 * On output, the fully retrieved items are filled in with values and
3341 * such. The label was matched, so it never changes.
3342 *
3343 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3344 *
3345 * This also finds the ends of maps and arrays when they are exited.
3346 */
3347 static QCBORError
QCBORDecode_Private_MapSearch(QCBORDecodeContext * pMe,QCBORItem * pItemArray,MapSearchInfo * pInfo,MapSearchCallBack * pCallBack)3348 QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3349 QCBORItem *pItemArray,
3350 MapSearchInfo *pInfo,
3351 MapSearchCallBack *pCallBack)
3352 {
3353 QCBORError uReturn;
3354 uint64_t uFoundItemBitMap = 0;
3355
3356 if(pMe->uLastError != QCBOR_SUCCESS) {
3357 uReturn = pMe->uLastError;
3358 goto Done2;
3359 }
3360
3361 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
3362 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3363 /* QCBOR_TYPE_NONE as first item indicates just looking
3364 for the end of an array, so don't give error. */
3365 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3366 goto Done2;
3367 }
3368
3369 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3370 // It is an empty bounded array or map
3371 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3372 // Just trying to find the end of the map or array
3373 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
3374 uReturn = QCBOR_SUCCESS;
3375 } else {
3376 // Nothing is ever found in an empty array or map. All items
3377 // are marked as not found below.
3378 uReturn = QCBOR_SUCCESS;
3379 }
3380 goto Done2;
3381 }
3382
3383 QCBORDecodeNesting SaveNesting;
3384 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
3385 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3386
3387 /* Reposition to search from the start of the map / array */
3388 QCBORDecode_Private_RewindMapOrArray(pMe);
3389
3390 /*
3391 Loop over all the items in the map or array. Each item
3392 could be a map or array, but label matching is only at
3393 the main level. This handles definite- and indefinite-
3394 length maps and arrays. The only reason this is ever
3395 called on arrays is to find their end position.
3396
3397 This will always run over all items in order to do
3398 duplicate detection.
3399
3400 This will exit with failure if it encounters an
3401 unrecoverable error, but continue on for recoverable
3402 errors.
3403
3404 If a recoverable error occurs on a matched item, then
3405 that error code is returned.
3406 */
3407 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
3408 if(pInfo) {
3409 pInfo->uItemCount = 0;
3410 }
3411 uint8_t uNextNestLevel;
3412 do {
3413 /* Remember offset of the item because sometimes it has to be returned */
3414 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3415
3416 /* Get the item */
3417 QCBORItem Item;
3418 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3419 * because a label match is performed on recoverable errors to
3420 * be able to return the the error code for the found item. */
3421 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
3422 if(QCBORDecode_IsUnrecoverableError(uResult)) {
3423 /* The map/array can't be decoded when unrecoverable errors occur */
3424 uReturn = uResult;
3425 goto Done;
3426 }
3427 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
3428 /* Unexpected end of map or array. */
3429 uReturn = uResult;
3430 goto Done;
3431 }
3432
3433 /* See if item has one of the labels that are of interest */
3434 bool bMatched = false;
3435 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
3436 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
3437 /* A label match has been found */
3438 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3439 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
3440 goto Done;
3441 }
3442 if(uResult != QCBOR_SUCCESS) {
3443 /* The label matches, but the data item is in error.
3444 * It is OK to have recoverable errors on items that
3445 * are not matched. */
3446 uReturn = uResult;
3447 goto Done;
3448 }
3449 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
3450 /* The data item is not of the type(s) requested */
3451 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
3452 goto Done;
3453 }
3454
3455 /* Successful match. Return the item. */
3456 pItemArray[nIndex] = Item;
3457 uFoundItemBitMap |= 0x01ULL << nIndex;
3458 if(pInfo) {
3459 pInfo->uStartOffset = uOffset;
3460 }
3461 bMatched = true;
3462 }
3463 }
3464
3465
3466 if(!bMatched && pCallBack != NULL) {
3467 /*
3468 Call the callback on unmatched labels.
3469 (It is tempting to do duplicate detection here, but that would
3470 require dynamic memory allocation because the number of labels
3471 that might be encountered is unbounded.)
3472 */
3473 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
3474 if(uReturn != QCBOR_SUCCESS) {
3475 goto Done;
3476 }
3477 }
3478
3479 /*
3480 Consume the item whether matched or not. This
3481 does the work of traversing maps and array and
3482 everything in them. In this loop only the
3483 items at the current nesting level are examined
3484 to match the labels.
3485 */
3486 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
3487 if(uReturn != QCBOR_SUCCESS) {
3488 goto Done;
3489 }
3490
3491 if(pInfo) {
3492 pInfo->uItemCount++;
3493 }
3494
3495 } while (uNextNestLevel >= uMapNestLevel);
3496
3497 uReturn = QCBOR_SUCCESS;
3498
3499 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3500
3501 // Check here makes sure that this won't accidentally be
3502 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
3503 // QCBOR_MAX_DECODE_INPUT_SIZE.
3504 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3505 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
3506 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3507 goto Done;
3508 }
3509 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3510 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
3511
3512 Done:
3513 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3514 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
3515
3516 Done2:
3517 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
3518 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
3519 if(!(uFoundItemBitMap & (0x01ULL << i))) {
3520 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3521 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
3522 }
3523 }
3524
3525 return uReturn;
3526 }
3527
3528
3529 /*
3530 * Public function, see header qcbor/qcbor_decode.h file
3531 */
3532 void
QCBORDecode_GetItemInMapN(QCBORDecodeContext * pMe,int64_t nLabel,uint8_t uQcborType,QCBORItem * pItem)3533 QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3534 int64_t nLabel,
3535 uint8_t uQcborType,
3536 QCBORItem *pItem)
3537 {
3538 if(pMe->uLastError != QCBOR_SUCCESS) {
3539 return;
3540 }
3541
3542 QCBORItem OneItemSeach[2];
3543 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3544 OneItemSeach[0].label.int64 = nLabel;
3545 OneItemSeach[0].uDataType = uQcborType;
3546 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3547
3548 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3549
3550 if(uReturn != QCBOR_SUCCESS) {
3551 pItem->uDataType = QCBOR_TYPE_NONE;
3552 pItem->uLabelType = QCBOR_TYPE_NONE;
3553 goto Done;
3554 }
3555
3556 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
3557 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3558 }
3559
3560 *pItem = OneItemSeach[0];
3561 QCBORDecode_Private_CopyTags(pMe, pItem);
3562
3563 Done:
3564 pMe->uLastError = (uint8_t)uReturn;
3565 }
3566
3567
3568 /*
3569 * Public function, see header qcbor/qcbor_decode.h file
3570 */
3571 void
QCBORDecode_GetItemInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,uint8_t uQcborType,QCBORItem * pItem)3572 QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3573 const char *szLabel,
3574 uint8_t uQcborType,
3575 QCBORItem *pItem)
3576 {
3577 if(pMe->uLastError != QCBOR_SUCCESS) {
3578 return;
3579 }
3580
3581 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3582 QCBORItem OneItemSeach[2];
3583 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3584 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3585 OneItemSeach[0].uDataType = uQcborType;
3586 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3587
3588 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3589
3590 if(uReturn != QCBOR_SUCCESS) {
3591 pItem->uDataType = QCBOR_TYPE_NONE;
3592 pItem->uLabelType = QCBOR_TYPE_NONE;
3593 goto Done;
3594 }
3595 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
3596 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3597 goto Done;
3598 }
3599
3600 *pItem = OneItemSeach[0];
3601 QCBORDecode_Private_CopyTags(pMe, pItem);
3602
3603 Done:
3604 #else
3605 (void)pMe;
3606 (void)szLabel;
3607 (void)uQcborType;
3608 (void)pItem;
3609 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3610 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3611
3612 pMe->uLastError = (uint8_t)uReturn;
3613 }
3614
3615
3616
3617 /**
3618 * @brief Semi-private. Get pointer, length and item for an array or map.
3619 *
3620 * @param[in] pMe The decode context.
3621 * @param[in] uType CBOR major type, either array/map.
3622 * @param[out] pItem The item for the array/map.
3623 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3624 *
3625 * The next item to be decoded must be a map or array as specified by \c uType.
3626 *
3627 * \c pItem will be filled in with the label and tags of the array or map
3628 * in addition to \c pEncodedCBOR giving the pointer and length of the
3629 * encoded CBOR.
3630 *
3631 * When this is complete, the traversal cursor is at the end of the array or
3632 * map that was retrieved.
3633 */
3634 void
QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext * pMe,const uint8_t uType,QCBORItem * pItem,UsefulBufC * pEncodedCBOR)3635 QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3636 const uint8_t uType,
3637 QCBORItem *pItem,
3638 UsefulBufC *pEncodedCBOR)
3639 {
3640 QCBORError uErr;
3641 uint8_t uNestLevel;
3642 size_t uStartingCursor;
3643 size_t uStartOfReturned;
3644 size_t uEndOfReturned;
3645 size_t uTempSaveCursor;
3646 bool bInMap;
3647 QCBORItem LabelItem;
3648 bool EndedByBreak;
3649
3650 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3651 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3652
3653 /* Could call GetNext here, but don't need to because this
3654 * is only interested in arrays and maps. */
3655 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3656 if(uErr != QCBOR_SUCCESS) {
3657 pMe->uLastError = (uint8_t)uErr;
3658 return;
3659 }
3660
3661 uint8_t uItemDataType = pItem->uDataType;
3662 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3663 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3664 uItemDataType = QCBOR_TYPE_ARRAY;
3665 }
3666 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3667
3668 if(uItemDataType != uType) {
3669 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3670 return;
3671 }
3672
3673 if(bInMap) {
3674 /* If the item is in a map, the start of the array/map
3675 * itself, not the label, must be found. Do this by
3676 * rewinding to the starting position and fetching
3677 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3678 * doesn't do any of the array/map item counting or nesting
3679 * level tracking. Used here it will just fetech the label
3680 * data item.
3681 *
3682 * Have to save the cursor and put it back to the position
3683 * after the full item once the label as been fetched by
3684 * itself.
3685 */
3686 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3687 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3688
3689 /* Item has been fetched once so safe to ignore error */
3690 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3691
3692 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3693 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3694 } else {
3695 uStartOfReturned = uStartingCursor;
3696 }
3697
3698 /* Consume the entire array/map to find the end */
3699 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3700 if(uErr != QCBOR_SUCCESS) {
3701 pMe->uLastError = (uint8_t)uErr;
3702 goto Done;
3703 }
3704
3705 /* Fill in returned values */
3706 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3707 if(EndedByBreak) {
3708 /* When ascending nesting levels, a break for the level above
3709 * was consumed. That break is not a part of what is consumed here. */
3710 uEndOfReturned--;
3711 }
3712 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3713 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3714
3715 Done:
3716 return;
3717 }
3718
3719
3720 /**
3721 * @brief Semi-private. Get pointer, length and item count of an array or map.
3722 *
3723 * @param[in] pMe The decode context.
3724 * @param[in] pTarget The label and type of the array or map to retrieve.
3725 * @param[out] pItem The item for the array/map.
3726 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3727 *
3728 * The next item to be decoded must be a map or array as specified by \c uType.
3729 *
3730 * When this is complete, the traversal cursor is unchanged.
3731 */void
QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext * pMe,QCBORItem * pTarget,QCBORItem * pItem,UsefulBufC * pEncodedCBOR)3732 QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3733 QCBORItem *pTarget,
3734 QCBORItem *pItem,
3735 UsefulBufC *pEncodedCBOR)
3736 {
3737 MapSearchInfo Info;
3738 QCBORDecodeNesting SaveNesting;
3739 size_t uSaveCursor;
3740
3741 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3742 if(pMe->uLastError != QCBOR_SUCCESS) {
3743 return;
3744 }
3745
3746 /* Save the whole position of things so they can be restored.
3747 * so the cursor position is unchanged by this operation, like
3748 * all the other GetXxxxInMap() operations. */
3749 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3750 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3751
3752 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3753 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3754 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3755
3756 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3757 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3758 }
3759
3760
3761
3762
3763 /**
3764 * @brief Is a QCBOR_TYPE in the type list?
3765 *
3766 * @param[in] uDataType Type to check for.
3767 * @param[in] puTypeList List to check.
3768 *
3769 * @retval QCBOR_SUCCESS If in the list.
3770 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3771 */
3772 static QCBORError
QCBOR_Private_CheckTypeList(const int uDataType,const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])3773 QCBOR_Private_CheckTypeList(const int uDataType,
3774 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
3775 {
3776 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
3777 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
3778 return QCBOR_SUCCESS;
3779 }
3780 }
3781 return QCBOR_ERR_UNEXPECTED_TYPE;
3782 }
3783
3784
3785 /**
3786 * Match a tag/type specification against the type of the item.
3787 *
3788 * @param[in] TagSpec Specification for matching tags.
3789 * @param[in] pItem The item to check.
3790 *
3791 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3792 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3793 *
3794 * This checks the item data type of untagged items as well as of
3795 * tagged items against a specification to see if decoding should
3796 * proceed.
3797 *
3798 * This relies on the automatic tag decoding done by QCBOR that turns
3799 * tag numbers into particular QCBOR_TYPEs so there is no actual
3800 * comparsion of tag numbers, just of QCBOR_TYPEs.
3801 *
3802 * This checks the data item type as possibly representing the tag
3803 * number or as the tag content type.
3804 *
3805 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3806 * data type against the allowed tag content types. It will also error out
3807 * if the caller tries to require a tag because there is no way that can
3808 * ever be fulfilled.
3809 */
3810 static QCBORError
QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,const QCBORItem * pItem)3811 QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3812 const QCBORItem *pItem)
3813 {
3814 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
3815 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3816
3817 #ifndef QCBOR_DISABLE_TAGS
3818 /* -Wmaybe-uninitialized falsly warns here */
3819 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3820 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3821 /* There are tags that QCBOR couldn't process on this item and
3822 * the caller has told us there should not be.
3823 */
3824 return QCBOR_ERR_UNEXPECTED_TYPE;
3825 }
3826
3827 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3828 /* Must match the tag number and only the tag */
3829 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
3830 }
3831
3832 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
3833 if(uReturn == QCBOR_SUCCESS) {
3834 return QCBOR_SUCCESS;
3835 }
3836
3837 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3838 /* Must match the content type and only the content type.
3839 * There was no match just above so it is a fail. */
3840 return QCBOR_ERR_UNEXPECTED_TYPE;
3841 }
3842
3843 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3844 * and it hasn't matched the content, so the end
3845 * result is whether it matches the tag. This is
3846 * the tag optional case that the CBOR standard discourages.
3847 */
3848
3849 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
3850
3851 #else /* QCBOR_DISABLE_TAGS */
3852 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3853 return QCBOR_ERR_UNEXPECTED_TYPE;
3854 }
3855
3856 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
3857
3858 #endif /* QCBOR_DISABLE_TAGS */
3859 }
3860
3861
3862 /**
3863 * @brief Get an item by label to match a tag specification.
3864 *
3865 * @param[in] pMe The decode context.
3866 * @param[in] nLabel The label to search map for.
3867 * @param[in] TagSpec The tag number specification to match.
3868 * @param[out] pItem The item found.
3869 *
3870 * This finds the item with the given label in currently open
3871 * map. Then checks that its tag number and types matches the tag
3872 * specification. If not, an error is set in the decode context.
3873 */
3874 static void
QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const QCBOR_Private_TagSpec TagSpec,QCBORItem * pItem)3875 QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3876 const int64_t nLabel,
3877 const QCBOR_Private_TagSpec TagSpec,
3878 QCBORItem *pItem)
3879 {
3880 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3881 if(pMe->uLastError != QCBOR_SUCCESS) {
3882 return;
3883 }
3884
3885 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
3886 }
3887
3888
3889 /**
3890 * @brief Get an item by label to match a tag specification.
3891 *
3892 * @param[in] pMe The decode context.
3893 * @param[in] szLabel The label to search map for.
3894 * @param[in] TagSpec The tag number specification to match.
3895 * @param[out] pItem The item found.
3896 *
3897 * This finds the item with the given label in currently open
3898 * map. Then checks that its tag number and types matches the tag
3899 * specification. If not, an error is set in the decode context.
3900 */
3901 static void
QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const QCBOR_Private_TagSpec TagSpec,QCBORItem * pItem)3902 QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3903 const char *szLabel,
3904 const QCBOR_Private_TagSpec TagSpec,
3905 QCBORItem *pItem)
3906 {
3907 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3908 if(pMe->uLastError != QCBOR_SUCCESS) {
3909 return;
3910 }
3911
3912 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
3913 }
3914
3915
3916 /**
3917 * @brief Semi-private to get an string by label to match a tag specification.
3918 *
3919 * @param[in] pMe The decode context.
3920 * @param[in] nLabel The label to search map for.
3921 * @param[in] TagSpec The tag number specification to match.
3922 * @param[out] pString The string found.
3923 *
3924 * This finds the string with the given label in currently open
3925 * map. Then checks that its tag number and types matches the tag
3926 * specification. If not, an error is set in the decode context.
3927 */
3928 void
QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const QCBOR_Private_TagSpec TagSpec,UsefulBufC * pString)3929 QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3930 const int64_t nLabel,
3931 const QCBOR_Private_TagSpec TagSpec,
3932 UsefulBufC *pString)
3933 {
3934 QCBORItem Item;
3935 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3936 if(pMe->uLastError == QCBOR_SUCCESS) {
3937 *pString = Item.val.string;
3938 }
3939 }
3940
3941
3942 /**
3943 * @brief Semi-private to get an string by label to match a tag specification.
3944 *
3945 * @param[in] pMe The decode context.
3946 * @param[in] szLabel The label to search map for.
3947 * @param[in] TagSpec The tag number specification to match.
3948 * @param[out] pString The string found.
3949 *
3950 * This finds the string with the given label in currently open
3951 * map. Then checks that its tag number and types matches the tag
3952 * specification. If not, an error is set in the decode context.
3953 */void
QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const QCBOR_Private_TagSpec TagSpec,UsefulBufC * pString)3954 QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3955 const char * szLabel,
3956 const QCBOR_Private_TagSpec TagSpec,
3957 UsefulBufC *pString)
3958 {
3959 QCBORItem Item;
3960 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3961 if(pMe->uLastError == QCBOR_SUCCESS) {
3962 *pString = Item.val.string;
3963 }
3964 }
3965
3966
3967 /*
3968 * Public function, see header qcbor/qcbor_decode.h file
3969 */
3970 void
QCBORDecode_GetItemsInMap(QCBORDecodeContext * pMe,QCBORItem * pItemList)3971 QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
3972 {
3973 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
3974 pMe->uLastError = (uint8_t)uErr;
3975 }
3976
3977 /*
3978 * Public function, see header qcbor/qcbor_decode.h file
3979 */
3980 void
QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext * pMe,QCBORItem * pItemList,void * pCallbackCtx,QCBORItemCallback pfCB)3981 QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3982 QCBORItem *pItemList,
3983 void *pCallbackCtx,
3984 QCBORItemCallback pfCB)
3985 {
3986 MapSearchCallBack CallBack;
3987 CallBack.pCBContext = pCallbackCtx;
3988 CallBack.pfCallback = pfCB;
3989
3990 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3991
3992 pMe->uLastError = (uint8_t)uErr;
3993 }
3994
3995
3996 /**
3997 * @brief Search for a map/array by label and enter it
3998 *
3999 * @param[in] pMe The decode context.
4000 * @param[in] pSearch The map/array to search for.
4001 *
4002 * @c pSearch is expected to contain one item of type map or array
4003 * with the label specified. The current bounded map will be searched for
4004 * this and if found will be entered.
4005 *
4006 * If the label is not found, or the item found is not a map or array,
4007 * the error state is set.
4008 */
4009 static void
QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext * pMe,QCBORItem pSearch[])4010 QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
4011 {
4012 // The first item in pSearch is the one that is to be
4013 // entered. It should be the only one filled in. Any other
4014 // will be ignored unless it causes an error.
4015 if(pMe->uLastError != QCBOR_SUCCESS) {
4016 return;
4017 }
4018
4019 MapSearchInfo Info;
4020 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
4021 if(pMe->uLastError != QCBOR_SUCCESS) {
4022 return;
4023 }
4024
4025 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
4026 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4027 return;
4028 }
4029
4030
4031 /* The map or array was found. Now enter it.
4032 *
4033 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4034 * next item for the pre-order traversal cursor to be the map/array
4035 * found by MapSearch(). The next few lines of code force the
4036 * cursor to that.
4037 *
4038 * There is no need to retain the old cursor because
4039 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4040 * beginning of the map/array being entered.
4041 *
4042 * The cursor is forced by: 1) setting the input buffer position to
4043 * the item offset found by MapSearch(), 2) setting the map/array
4044 * counter to the total in the map/array, 3) setting the nesting
4045 * level. Setting the map/array counter to the total is not
4046 * strictly correct, but this is OK because this cursor only needs
4047 * to be used to get one item and MapSearch() has already found it
4048 * confirming it exists.
4049 */
4050 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
4051
4052 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4053
4054 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
4055
4056 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
4057 }
4058
4059
4060 /*
4061 * Public function, see header qcbor/qcbor_decode.h file
4062 */
4063 void
QCBORDecode_EnterMapFromMapN(QCBORDecodeContext * pMe,int64_t nLabel)4064 QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
4065 {
4066 QCBORItem OneItemSeach[2];
4067 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4068 OneItemSeach[0].label.int64 = nLabel;
4069 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4070 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
4071
4072 /* The map to enter was found, now finish off entering it. */
4073 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
4074 }
4075
4076
4077 /*
4078 * Public function, see header qcbor/qcbor_decode.h file
4079 */
4080 void
QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext * pMe,const char * szLabel)4081 QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
4082 {
4083 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
4084 QCBORItem OneItemSeach[2];
4085 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4086 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4087 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4088 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
4089
4090 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
4091 #else
4092 (void)szLabel;
4093 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4094 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4095 }
4096
4097 /*
4098 * Public function, see header qcbor/qcbor_decode.h file
4099 */
4100 void
QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext * pMe,int64_t nLabel)4101 QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
4102 {
4103 QCBORItem OneItemSeach[2];
4104 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4105 OneItemSeach[0].label.int64 = nLabel;
4106 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4107 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
4108
4109 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
4110 }
4111
4112 /*
4113 * Public function, see header qcbor/qcbor_decode.h file
4114 */
4115 void
QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext * pMe,const char * szLabel)4116 QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
4117 {
4118 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
4119 QCBORItem OneItemSeach[2];
4120 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4121 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4122 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4123 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
4124
4125 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
4126 #else
4127 (void)szLabel;
4128 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4129 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4130 }
4131
4132
4133 /**
4134 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4135 *
4136 * @param[in] pMe The decode context
4137 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4138 * @param[out] pItem The data item for the map or array entered.
4139 *
4140 * The next item in the traversal must be a map or array. This
4141 * consumes that item and does the book keeping to enter the map or
4142 * array.
4143 */
4144 void
QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext * pMe,const uint8_t uType,QCBORItem * pItem)4145 QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4146 const uint8_t uType,
4147 QCBORItem *pItem)
4148 {
4149 QCBORError uErr;
4150
4151 /* Must only be called on maps and arrays. */
4152 if(pMe->uLastError != QCBOR_SUCCESS) {
4153 // Already in error state; do nothing.
4154 return;
4155 }
4156
4157 /* Get the data item that is the map or array being entered. */
4158 QCBORItem Item;
4159 uErr = QCBORDecode_GetNext(pMe, &Item);
4160 if(uErr != QCBOR_SUCCESS) {
4161 goto Done;
4162 }
4163
4164 uint8_t uItemDataType = Item.uDataType;
4165
4166 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
4167 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4168 uItemDataType = QCBOR_TYPE_ARRAY;
4169 }
4170 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4171
4172 if(uItemDataType != uType) {
4173 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4174 goto Done;
4175 }
4176
4177 QCBORDecode_Private_CopyTags(pMe, &Item);
4178
4179
4180 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
4181 if(bIsEmpty) {
4182 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4183 // Undo decrement done by QCBORDecode_GetNext() so the the
4184 // the decrement when exiting the map/array works correctly
4185 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4186 }
4187 // Special case to increment nesting level for zero-length maps
4188 // and arrays entered in bounded mode.
4189 DecodeNesting_Descend(&(pMe->nesting), uType);
4190 }
4191
4192 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
4193
4194 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4195 UsefulInputBuf_Tell(&(pMe->InBuf)));
4196
4197 if(pItem != NULL) {
4198 *pItem = Item;
4199 }
4200
4201 Done:
4202 pMe->uLastError = (uint8_t)uErr;
4203 }
4204
4205
4206 /**
4207 * @brief Exit a bounded map, array or bstr (semi-private).
4208 *
4209 * @param[in] pMe Decode context.
4210 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4211 *
4212 * @returns QCBOR_SUCCESS or an error code.
4213 *
4214 * This is the common work for exiting a level that is a bounded map,
4215 * array or bstr wrapped CBOR.
4216 *
4217 * One chunk of work is to set up the pre-order traversal so it is at
4218 * the item just after the bounded map, array or bstr that is being
4219 * exited. This is somewhat complex.
4220 *
4221 * The other work is to level-up the bounded mode to next higest
4222 * bounded mode or the top level if there isn't one.
4223 */
4224 static QCBORError
QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext * pMe,const uint32_t uEndOffset)4225 QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4226 const uint32_t uEndOffset)
4227 {
4228 QCBORError uErr;
4229
4230 /*
4231 * First the pre-order-traversal byte offset is positioned to the
4232 * item just after the bounded mode item that was just consumed.
4233 */
4234 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4235
4236 /*
4237 * Next, set the current nesting level to one above the bounded
4238 * level that was just exited.
4239 *
4240 * DecodeNesting_CheckBoundedType() is always called before this
4241 * and makes sure pCurrentBounded is valid.
4242 */
4243 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4244
4245 /*
4246 * This does the complex work of leveling up the pre-order
4247 * traversal when the end of a map or array or another bounded
4248 * level is reached. It may do nothing, or ascend all the way to
4249 * the top level.
4250 */
4251 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
4252 if(uErr != QCBOR_SUCCESS) {
4253 goto Done;
4254 }
4255
4256 /*
4257 * This makes the next highest bounded level the current bounded
4258 * level. If there is no next highest level, then no bounded mode
4259 * is in effect.
4260 */
4261 DecodeNesting_LevelUpBounded(&(pMe->nesting));
4262
4263 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
4264
4265 Done:
4266 return uErr;
4267 }
4268
4269
4270 /**
4271 * @brief Get started exiting a map or array (semi-private)
4272 *
4273 * @param[in] pMe The decode context
4274 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4275 *
4276 * This does some work for map and array exiting (but not
4277 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4278 * is called to do the rest.
4279 */
4280 void
QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext * pMe,const uint8_t uType)4281 QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4282 const uint8_t uType)
4283 {
4284 if(pMe->uLastError != QCBOR_SUCCESS) {
4285 /* Already in error state; do nothing. */
4286 return;
4287 }
4288
4289 QCBORError uErr;
4290
4291 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
4292 uErr = QCBOR_ERR_EXIT_MISMATCH;
4293 goto Done;
4294 }
4295
4296 /*
4297 Have to set the offset to the end of the map/array
4298 that is being exited. If there is no cached value,
4299 from previous map search, then do a dummy search.
4300 */
4301 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
4302 QCBORItem Dummy;
4303 Dummy.uLabelType = QCBOR_TYPE_NONE;
4304 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
4305 if(uErr != QCBOR_SUCCESS) {
4306 goto Done;
4307 }
4308 }
4309
4310 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
4311
4312 Done:
4313 pMe->uLastError = (uint8_t)uErr;
4314 }
4315
4316
4317 /**
4318 * @brief The main work of entering some byte-string wrapped CBOR.
4319 *
4320 * @param[in] pMe The decode context.
4321 * @param[in] pItem The byte string item.
4322 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4323 * @param[out] pBstr Pointer and length of byte string entered.
4324 *
4325 * This is called once the byte string item has been decoded to do all
4326 * the book keeping work for descending a nesting level into the
4327 * nested CBOR.
4328 *
4329 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4330 */
4331 static QCBORError
QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext * pMe,const QCBORItem * pItem,const uint8_t uTagRequirement,UsefulBufC * pBstr)4332 QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4333 const QCBORItem *pItem,
4334 const uint8_t uTagRequirement,
4335 UsefulBufC *pBstr)
4336 {
4337 if(pBstr) {
4338 *pBstr = NULLUsefulBufC;
4339 }
4340
4341 if(pMe->uLastError != QCBOR_SUCCESS) {
4342 /* Already in error state; do nothing. */
4343 return pMe->uLastError;
4344 }
4345
4346 QCBORError uError;
4347
4348 const QCBOR_Private_TagSpec TagSpec =
4349 {
4350 uTagRequirement,
4351 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4352 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4353 };
4354
4355 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
4356 if(uError != QCBOR_SUCCESS) {
4357 goto Done;
4358 }
4359
4360 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4361 /* Reverse the decrement done by GetNext() for the bstr so the
4362 * increment in QCBORDecode_NestLevelAscender() called by
4363 * ExitBoundedLevel() will work right.
4364 */
4365 DecodeNesting_ReverseDecrement(&(pMe->nesting));
4366 }
4367
4368 if(pBstr) {
4369 *pBstr = pItem->val.string;
4370 }
4371
4372 /* This saves the current length of the UsefulInputBuf and then
4373 * narrows the UsefulInputBuf to start and length of the wrapped
4374 * CBOR that is being entered.
4375 *
4376 * Most of these calls are simple inline accessors so this doesn't
4377 * amount to much code.
4378 */
4379
4380 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4381 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4382 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
4383 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4384 goto Done;
4385 }
4386
4387 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4388 pItem->val.string.ptr);
4389 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4390 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4391 /* This should never happen because pItem->val.string.ptr should
4392 * always be valid since it was just returned.
4393 */
4394 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4395 goto Done;
4396 }
4397
4398 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4399
4400 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
4401 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
4402
4403 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
4404 (uint32_t)uPreviousLength,
4405 (uint32_t)uStartOfBstr);
4406 Done:
4407 return uError;
4408 }
4409
4410
4411 /*
4412 * Public function, see header qcbor/qcbor_decode.h file
4413 */
4414 void
QCBORDecode_EnterBstrWrapped(QCBORDecodeContext * pMe,const uint8_t uTagRequirement,UsefulBufC * pBstr)4415 QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4416 const uint8_t uTagRequirement,
4417 UsefulBufC *pBstr)
4418 {
4419 if(pMe->uLastError != QCBOR_SUCCESS) {
4420 // Already in error state; do nothing.
4421 return;
4422 }
4423
4424 /* Get the data item that is the byte string being entered */
4425 QCBORItem Item;
4426 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4427 if(pMe->uLastError != QCBOR_SUCCESS) {
4428 return;
4429 }
4430
4431 if(Item.uDataAlloc) {
4432 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4433 return;
4434 }
4435
4436 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4437 &Item,
4438 uTagRequirement,
4439 pBstr);
4440 }
4441
4442
4443 /*
4444 * Public function, see header qcbor/qcbor_decode.h file
4445 */
4446 void
QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint8_t uTagRequirement,UsefulBufC * pBstr)4447 QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4448 const int64_t nLabel,
4449 const uint8_t uTagRequirement,
4450 UsefulBufC *pBstr)
4451 {
4452 QCBORItem Item;
4453 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4454
4455 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4456 &Item,
4457 uTagRequirement,
4458 pBstr);
4459 }
4460
4461
4462 /*
4463 * Public function, see header qcbor/qcbor_decode.h file
4464 */
4465 void
QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint8_t uTagRequirement,UsefulBufC * pBstr)4466 QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4467 const char *szLabel,
4468 const uint8_t uTagRequirement,
4469 UsefulBufC *pBstr)
4470 {
4471 QCBORItem Item;
4472 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4473
4474 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4475 &Item,
4476 uTagRequirement,
4477 pBstr);
4478 }
4479
4480
4481 /*
4482 * Public function, see header qcbor/qcbor_decode.h file
4483 */
4484 void
QCBORDecode_ExitBstrWrapped(QCBORDecodeContext * pMe)4485 QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
4486 {
4487 if(pMe->uLastError != QCBOR_SUCCESS) {
4488 // Already in error state; do nothing.
4489 return;
4490 }
4491
4492 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
4493 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
4494 return;
4495 }
4496
4497 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4498
4499 /*
4500 Reset the length of the UsefulInputBuf to what it was before
4501 the bstr wrapped CBOR was entered.
4502 */
4503 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
4504 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
4505
4506
4507 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
4508 pMe->uLastError = (uint8_t)uErr;
4509 }
4510
4511
4512
4513 /**
4514 * @brief Process simple type true and false, a boolean
4515 *
4516 * @param[in] pMe The decode context.
4517 * @param[in] pItem The item with either true or false.
4518 * @param[out] pBool The boolean value output.
4519 *
4520 * Sets the internal error if the item isn't a true or a false. Also
4521 * records any tag numbers as the tag numbers of the last item.
4522 */
4523 static void
QCBORDecode_Private_ProcessBool(QCBORDecodeContext * pMe,const QCBORItem * pItem,bool * pBool)4524 QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4525 const QCBORItem *pItem,
4526 bool *pBool)
4527 {
4528 if(pMe->uLastError != QCBOR_SUCCESS) {
4529 /* Already in error state, do nothing */
4530 return;
4531 }
4532
4533 switch(pItem->uDataType) {
4534 case QCBOR_TYPE_TRUE:
4535 *pBool = true;
4536 break;
4537
4538 case QCBOR_TYPE_FALSE:
4539 *pBool = false;
4540 break;
4541
4542 default:
4543 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4544 break;
4545 }
4546 }
4547
4548
4549 /*
4550 * Public function, see header qcbor/qcbor_decode.h file
4551 */
4552 void
QCBORDecode_GetBool(QCBORDecodeContext * pMe,bool * pValue)4553 QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
4554 {
4555 QCBORItem Item;
4556 QCBORDecode_VGetNext(pMe, &Item);
4557 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
4558 }
4559
4560
4561 /*
4562 * Public function, see header qcbor/qcbor_decode.h file
4563 */
4564 void
QCBORDecode_GetBoolInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,bool * pValue)4565 QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4566 const int64_t nLabel,
4567 bool *pValue)
4568 {
4569 QCBORItem Item;
4570 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4571 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
4572 }
4573
4574
4575 /*
4576 * Public function, see header qcbor/qcbor_decode.h file
4577 */
4578 void
QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,bool * pValue)4579 QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4580 const char *szLabel,
4581 bool *pValue)
4582 {
4583 QCBORItem Item;
4584 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4585 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
4586 }
4587
4588
4589 /**
4590 * @brief Process simple values.
4591 *
4592 * @param[in] pMe The decode context.
4593 * @param[in] pItem The item with the simple value.
4594 * @param[out] puSimple The simple value output.
4595 *
4596 * Sets the internal error if the item isn't a true or a false. Also
4597 * records any tag numbers as the tag numbers of the last item.
4598 */
4599 static void
QCBORDecode_Private_ProcessSimple(QCBORDecodeContext * pMe,const QCBORItem * pItem,uint8_t * puSimple)4600 QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4601 const QCBORItem *pItem,
4602 uint8_t *puSimple)
4603 {
4604 if(pMe->uLastError != QCBOR_SUCCESS) {
4605 return;
4606 }
4607
4608 /* It's kind of lame to remap true...undef back to simple values, but
4609 * this function isn't used much and to not do it would require
4610 * changing GetNext() behavior in an incompatible way.
4611 */
4612 switch(pItem->uDataType) {
4613 case QCBOR_TYPE_UKNOWN_SIMPLE:
4614 *puSimple = pItem->val.uSimple;
4615 break;
4616
4617 case QCBOR_TYPE_TRUE:
4618 *puSimple = CBOR_SIMPLEV_TRUE;
4619 break;
4620
4621 case QCBOR_TYPE_FALSE:
4622 *puSimple = CBOR_SIMPLEV_FALSE;
4623 break;
4624
4625 case QCBOR_TYPE_NULL:
4626 *puSimple = CBOR_SIMPLEV_NULL;
4627 break;
4628
4629 case QCBOR_TYPE_UNDEF:
4630 *puSimple = CBOR_SIMPLEV_UNDEF;
4631 break;
4632
4633 default:
4634 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4635 return;
4636 }
4637 }
4638
4639 /*
4640 * Public function, see header qcbor/qcbor_decode.h file
4641 */
4642 void
QCBORDecode_GetSimple(QCBORDecodeContext * pMe,uint8_t * puSimple)4643 QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
4644 {
4645 QCBORItem Item;
4646 QCBORDecode_VGetNext(pMe, &Item);
4647 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
4648 }
4649
4650 /*
4651 * Public function, see header qcbor/qcbor_decode.h file
4652 */
4653 void
QCBORDecode_GetSimpleInMapN(QCBORDecodeContext * pMe,int64_t nLabel,uint8_t * puSimpleValue)4654 QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
4655 int64_t nLabel,
4656 uint8_t *puSimpleValue)
4657 {
4658 QCBORItem Item;
4659 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4660 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4661 }
4662
4663 /*
4664 * Public function, see header qcbor/qcbor_decode.h file
4665 */
4666 void
QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,uint8_t * puSimpleValue)4667 QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
4668 const char *szLabel,
4669 uint8_t *puSimpleValue)
4670 {
4671 QCBORItem Item;
4672 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4673 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4674 }
4675
4676
4677
4678 /**
4679 * @brief Common processing for an epoch date.
4680 *
4681 * @param[in] pMe The decode context.
4682 * @param[in] pItem The item with the date.
4683 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4684 * @param[out] pnTime The returned date.
4685 *
4686 * Common processing for the date tag. Mostly make sure the tag
4687 * content is correct and copy forward any further other tag numbers.
4688 */
4689 static void
QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext * pMe,QCBORItem * pItem,const uint8_t uTagRequirement,int64_t * pnTime)4690 QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4691 QCBORItem *pItem,
4692 const uint8_t uTagRequirement,
4693 int64_t *pnTime)
4694 {
4695 if(pMe->uLastError != QCBOR_SUCCESS) {
4696 // Already in error state, do nothing
4697 return;
4698 }
4699
4700 QCBORError uErr;
4701
4702 const QCBOR_Private_TagSpec TagSpec =
4703 {
4704 uTagRequirement,
4705 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4706 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
4707 };
4708
4709 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
4710 if(uErr != QCBOR_SUCCESS) {
4711 goto Done;
4712 }
4713
4714 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
4715 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
4716 if(uErr != QCBOR_SUCCESS) {
4717 goto Done;
4718 }
4719 }
4720
4721 *pnTime = pItem->val.epochDate.nSeconds;
4722
4723 Done:
4724 pMe->uLastError = (uint8_t)uErr;
4725 }
4726
4727
4728
4729 /*
4730 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4731 */
4732 void
QCBORDecode_GetEpochDate(QCBORDecodeContext * pMe,uint8_t uTagRequirement,int64_t * pnTime)4733 QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4734 uint8_t uTagRequirement,
4735 int64_t *pnTime)
4736 {
4737 QCBORItem Item;
4738 QCBORDecode_VGetNext(pMe, &Item);
4739 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
4740 }
4741
4742
4743 /*
4744 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4745 */
4746 void
QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext * pMe,int64_t nLabel,uint8_t uTagRequirement,int64_t * pnTime)4747 QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4748 int64_t nLabel,
4749 uint8_t uTagRequirement,
4750 int64_t *pnTime)
4751 {
4752 QCBORItem Item;
4753 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4754 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
4755 }
4756
4757
4758 /*
4759 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4760 */
4761 void
QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,uint8_t uTagRequirement,int64_t * pnTime)4762 QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4763 const char *szLabel,
4764 uint8_t uTagRequirement,
4765 int64_t *pnTime)
4766 {
4767 QCBORItem Item;
4768 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4769 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
4770 }
4771
4772
4773
4774 /**
4775 * @brief Common processing for an epoch date.
4776 *
4777 * @param[in] pMe The decode context.
4778 * @param[in] pItem The item with the date.
4779 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4780 * @param[out] pnDays The returned day count.
4781 *
4782 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4783 * the tag content is correct and copy forward any further other tag
4784 * numbers.
4785 */
4786 static void
QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext * pMe,QCBORItem * pItem,uint8_t uTagRequirement,int64_t * pnDays)4787 QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4788 QCBORItem *pItem,
4789 uint8_t uTagRequirement,
4790 int64_t *pnDays)
4791 {
4792 if(pMe->uLastError != QCBOR_SUCCESS) {
4793 /* Already in error state, do nothing */
4794 return;
4795 }
4796
4797 QCBORError uErr;
4798
4799 const QCBOR_Private_TagSpec TagSpec =
4800 {
4801 uTagRequirement,
4802 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4803 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4804 };
4805
4806 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
4807 if(uErr != QCBOR_SUCCESS) {
4808 goto Done;
4809 }
4810
4811 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
4812 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
4813 if(uErr != QCBOR_SUCCESS) {
4814 goto Done;
4815 }
4816 }
4817
4818 *pnDays = pItem->val.epochDays;
4819
4820 Done:
4821 pMe->uLastError = (uint8_t)uErr;
4822 }
4823
4824
4825 /*
4826 * Public function, see header qcbor/qcbor_decode.h
4827 */
4828 void
QCBORDecode_GetEpochDays(QCBORDecodeContext * pMe,uint8_t uTagRequirement,int64_t * pnDays)4829 QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4830 uint8_t uTagRequirement,
4831 int64_t *pnDays)
4832 {
4833 QCBORItem Item;
4834 QCBORDecode_VGetNext(pMe, &Item);
4835 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
4836 }
4837
4838
4839 /*
4840 * Public function, see header qcbor/qcbor_decode.h
4841 */
4842 void
QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext * pMe,int64_t nLabel,uint8_t uTagRequirement,int64_t * pnDays)4843 QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4844 int64_t nLabel,
4845 uint8_t uTagRequirement,
4846 int64_t *pnDays)
4847 {
4848 QCBORItem Item;
4849 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4850 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
4851 }
4852
4853
4854 /*
4855 * Public function, see header qcbor/qcbor_decode.h
4856 */
4857 void
QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,uint8_t uTagRequirement,int64_t * pnDays)4858 QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4859 const char *szLabel,
4860 uint8_t uTagRequirement,
4861 int64_t *pnDays)
4862 {
4863 QCBORItem Item;
4864 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4865 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
4866 }
4867
4868
4869
4870 /*
4871 * @brief Get a string that matches the type/tag specification.
4872 */
4873 void
QCBORDecode_Private_GetTaggedString(QCBORDecodeContext * pMe,const QCBOR_Private_TagSpec TagSpec,UsefulBufC * pBstr)4874 QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4875 const QCBOR_Private_TagSpec TagSpec,
4876 UsefulBufC *pBstr)
4877 {
4878 QCBORItem Item;
4879
4880 QCBORDecode_VGetNext(pMe, &Item);
4881 if(pMe->uLastError) {
4882 return;
4883 }
4884
4885 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
4886
4887 if(pMe->uLastError == QCBOR_SUCCESS) {
4888 *pBstr = Item.val.string;
4889 } else {
4890 *pBstr = NULLUsefulBufC;
4891 }
4892 }
4893
4894
4895
4896
4897 /**
4898 * @brief Common processing for a big number tag.
4899 *
4900 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4901 * @param[in] pItem The item with the date.
4902 * @param[out] pValue The returned big number
4903 * @param[out] pbIsNegative The returned sign of the big number.
4904 *
4905 * Common processing for the big number tag. Mostly make sure
4906 * the tag content is correct and copy forward any further other tag
4907 * numbers.
4908 */
4909 static QCBORError
QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,const QCBORItem * pItem,UsefulBufC * pValue,bool * pbIsNegative)4910 QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4911 const QCBORItem *pItem,
4912 UsefulBufC *pValue,
4913 bool *pbIsNegative)
4914 {
4915 const QCBOR_Private_TagSpec TagSpec =
4916 {
4917 uTagRequirement,
4918 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4919 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4920 };
4921
4922 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
4923 if(uErr != QCBOR_SUCCESS) {
4924 return uErr;
4925 }
4926
4927 *pValue = pItem->val.string;
4928
4929 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4930 *pbIsNegative = false;
4931 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4932 *pbIsNegative = true;
4933 }
4934
4935 return QCBOR_SUCCESS;
4936 }
4937
4938
4939 /*
4940 * Public function, see header qcbor/qcbor_spiffy_decode.h
4941 */
4942 void
QCBORDecode_GetBignum(QCBORDecodeContext * pMe,const uint8_t uTagRequirement,UsefulBufC * pValue,bool * pbIsNegative)4943 QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4944 const uint8_t uTagRequirement,
4945 UsefulBufC *pValue,
4946 bool *pbIsNegative)
4947 {
4948 QCBORItem Item;
4949 QCBORDecode_VGetNext(pMe, &Item);
4950 if(pMe->uLastError) {
4951 return;
4952 }
4953
4954 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4955 &Item,
4956 pValue,
4957 pbIsNegative);
4958 }
4959
4960
4961 /*
4962 * Public function, see header qcbor/qcbor_spiffy_decode.h
4963 */
4964 void
QCBORDecode_GetBignumInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint8_t uTagRequirement,UsefulBufC * pValue,bool * pbIsNegative)4965 QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4966 const int64_t nLabel,
4967 const uint8_t uTagRequirement,
4968 UsefulBufC *pValue,
4969 bool *pbIsNegative)
4970 {
4971 QCBORItem Item;
4972 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4973 if(pMe->uLastError != QCBOR_SUCCESS) {
4974 return;
4975 }
4976
4977 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4978 &Item,
4979 pValue,
4980 pbIsNegative);
4981 }
4982
4983
4984 /*
4985 * Public function, see header qcbor/qcbor_spiffy_decode.h
4986 */
4987 void
QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint8_t uTagRequirement,UsefulBufC * pValue,bool * pbIsNegative)4988 QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4989 const char *szLabel,
4990 const uint8_t uTagRequirement,
4991 UsefulBufC *pValue,
4992 bool *pbIsNegative)
4993 {
4994 QCBORItem Item;
4995 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4996 if(pMe->uLastError != QCBOR_SUCCESS) {
4997 return;
4998 }
4999
5000 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5001 &Item,
5002 pValue,
5003 pbIsNegative);
5004 }
5005
5006
5007
5008 /**
5009 * @brief Common processing for MIME tag (semi-private).
5010 *
5011 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5012 * @param[in] pItem The item with the date.
5013 * @param[out] pMessage The returned MIME message.
5014 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
5015 *
5016 * Common processing for the MIME tag. Mostly make sure the tag
5017 * content is correct and copy forward any further other tag
5018 * numbers. See QCBORDecode_GetMIMEMessage().
5019 */
5020 QCBORError
QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,const QCBORItem * pItem,UsefulBufC * pMessage,bool * pbIsTag257)5021 QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
5022 const QCBORItem *pItem,
5023 UsefulBufC *pMessage,
5024 bool *pbIsTag257)
5025 {
5026 const QCBOR_Private_TagSpec TagSpecText =
5027 {
5028 uTagRequirement,
5029 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5030 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5031 };
5032 const QCBOR_Private_TagSpec TagSpecBinary =
5033 {
5034 uTagRequirement,
5035 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5036 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5037 };
5038
5039 QCBORError uReturn;
5040
5041 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
5042 *pMessage = pItem->val.string;
5043 if(pbIsTag257 != NULL) {
5044 *pbIsTag257 = false;
5045 }
5046 uReturn = QCBOR_SUCCESS;
5047 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
5048 *pMessage = pItem->val.string;
5049 if(pbIsTag257 != NULL) {
5050 *pbIsTag257 = true;
5051 }
5052 uReturn = QCBOR_SUCCESS;
5053
5054 } else {
5055 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
5056 }
5057
5058 return uReturn;
5059 }
5060
5061 // Improvement: add methods for wrapped CBOR, a simple alternate
5062 // to EnterBstrWrapped
5063
5064
5065
5066
5067 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
5068
5069 /**
5070 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5071 *
5072 * @param[in] uMantissa The mantissa.
5073 * @param[in] nExponent The exponent.
5074 * @param[out] puResult The resulting integer.
5075 *
5076 * Concrete implementations of this are for exponent base 10 and 2 supporting
5077 * decimal fractions and big floats.
5078 */
5079 typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
5080
5081
5082 /**
5083 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5084 *
5085 * @param[in] uMantissa The unsigned integer mantissa.
5086 * @param[in] nExponent The signed integer exponent.
5087 * @param[out] puResult Place to return the unsigned integer result.
5088 *
5089 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5090 * unsigned integer.
5091 *
5092 * There are many inputs for which the result will not fit in the
5093 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5094 * be returned.
5095 */
5096 static QCBORError
QCBOR_Private_Exponentitate10(const uint64_t uMantissa,int64_t nExponent,uint64_t * puResult)5097 QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5098 int64_t nExponent,
5099 uint64_t *puResult)
5100 {
5101 uint64_t uResult = uMantissa;
5102
5103 if(uResult != 0) {
5104 /* This loop will run a maximum of 19 times because
5105 * UINT64_MAX < 10 ^^ 19. More than that will cause
5106 * exit with the overflow error
5107 */
5108 for(; nExponent > 0; nExponent--) {
5109 if(uResult > UINT64_MAX / 10) {
5110 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5111 }
5112 uResult = uResult * 10;
5113 }
5114
5115 for(; nExponent < 0; nExponent++) {
5116 uResult = uResult / 10;
5117 if(uResult == 0) {
5118 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5119 }
5120 }
5121 }
5122 /* else, mantissa is zero so this returns zero */
5123
5124 *puResult = uResult;
5125
5126 return QCBOR_SUCCESS;
5127 }
5128
5129
5130 /**
5131 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5132 *
5133 * @param[in] uMantissa The unsigned integer mantissa.
5134 * @param[in] nExponent The signed integer exponent.
5135 * @param[out] puResult Place to return the unsigned integer result.
5136 *
5137 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5138 * output is a 64-bit unsigned integer.
5139 *
5140 * There are many inputs for which the result will not fit in the
5141 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5142 * be returned.
5143 */
5144 static QCBORError
QCBOR_Private_Exponentitate2(const uint64_t uMantissa,int64_t nExponent,uint64_t * puResult)5145 QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5146 int64_t nExponent,
5147 uint64_t *puResult)
5148 {
5149 uint64_t uResult;
5150
5151 uResult = uMantissa;
5152
5153 /* This loop will run a maximum of 64 times because INT64_MAX <
5154 * 2^31. More than that will cause exit with the overflow error
5155 */
5156 while(nExponent > 0) {
5157 if(uResult > UINT64_MAX >> 1) {
5158 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5159 }
5160 uResult = uResult << 1;
5161 nExponent--;
5162 }
5163
5164 while(nExponent < 0 ) {
5165 if(uResult == 0) {
5166 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5167 }
5168 uResult = uResult >> 1;
5169 nExponent++;
5170 }
5171
5172 *puResult = uResult;
5173
5174 return QCBOR_SUCCESS;
5175 }
5176
5177
5178 /**
5179 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5180 *
5181 * @param[in] nMantissa Signed integer mantissa.
5182 * @param[in] nExponent Signed integer exponent.
5183 * @param[out] pnResult Place to put the signed integer result.
5184 * @param[in] pfExp Exponentiation function.
5185 *
5186 * @returns Error code
5187 *
5188 * \c pfExp performs exponentiation on and unsigned mantissa and
5189 * produces an unsigned result. This converts the mantissa from signed
5190 * and converts the result to signed. The exponentiation function is
5191 * either for base 2 or base 10 (and could be other if needed).
5192 */
5193 static QCBORError
QCBOR_Private_ExponentiateNN(const int64_t nMantissa,const int64_t nExponent,int64_t * pnResult,fExponentiator pfExp)5194 QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5195 const int64_t nExponent,
5196 int64_t *pnResult,
5197 fExponentiator pfExp)
5198 {
5199 uint64_t uResult;
5200 uint64_t uMantissa;
5201
5202 /* Take the absolute value and put it into an unsigned. */
5203 if(nMantissa >= 0) {
5204 /* Positive case is straightforward */
5205 uMantissa = (uint64_t)nMantissa;
5206 } else if(nMantissa != INT64_MIN) {
5207 /* The common negative case. See next. */
5208 uMantissa = (uint64_t)-nMantissa;
5209 } else {
5210 /* int64_t and uint64_t are always two's complement per the
5211 * C standard (and since QCBOR uses these it only works with
5212 * two's complement, which is pretty much universal these
5213 * days). The range of a negative two's complement integer is
5214 * one more that than a positive, so the simple code above might
5215 * not work all the time because you can't simply negate the
5216 * value INT64_MIN because it can't be represented in an
5217 * int64_t. -INT64_MIN can however be represented in a
5218 * uint64_t. Some compilers seem to recognize this case for the
5219 * above code and put the correct value in uMantissa, however
5220 * they are not required to do this by the C standard. This next
5221 * line does however work for all compilers.
5222 *
5223 * This does assume two's complement where -INT64_MIN ==
5224 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5225 * sign and magnitude (but we know we're using two's complement
5226 * because int64_t requires it)).
5227 *
5228 * See these, particularly the detailed commentary:
5229 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5230 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5231 */
5232 uMantissa = (uint64_t)INT64_MAX+1;
5233 }
5234
5235 /* Call the exponentiator passed for either base 2 or base 10.
5236 * Here is where most of the overflow errors are caught. */
5237 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5238 if(uReturn) {
5239 return uReturn;
5240 }
5241
5242 /* Convert back to the sign of the original mantissa */
5243 if(nMantissa >= 0) {
5244 if(uResult > INT64_MAX) {
5245 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5246 }
5247 *pnResult = (int64_t)uResult;
5248 } else {
5249 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5250 * of INT64_MIN. This assumes two's compliment representation
5251 * where INT64_MIN is one increment farther from 0 than
5252 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5253 * this because the compiler makes it an int64_t which can't
5254 * represent -INT64_MIN. Also see above.
5255 */
5256 if(uResult > (uint64_t)INT64_MAX+1) {
5257 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5258 }
5259 *pnResult = -(int64_t)uResult;
5260 }
5261
5262 return QCBOR_SUCCESS;
5263 }
5264
5265
5266 /**
5267 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5268 *
5269 * @param[in] nMantissa Signed integer mantissa.
5270 * @param[in] nExponent Signed integer exponent.
5271 * @param[out] puResult Place to put the signed integer result.
5272 * @param[in] pfExp Exponentiation function.
5273 *
5274 * @returns Error code
5275 *
5276 * \c pfExp performs exponentiation on and unsigned mantissa and
5277 * produces an unsigned result. This errors out if the mantissa
5278 * is negative because the output is unsigned.
5279 */
5280 static QCBORError
QCBOR_Private_ExponentitateNU(const int64_t nMantissa,const int64_t nExponent,uint64_t * puResult,fExponentiator pfExp)5281 QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5282 const int64_t nExponent,
5283 uint64_t *puResult,
5284 fExponentiator pfExp)
5285 {
5286 if(nMantissa < 0) {
5287 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5288 }
5289
5290 /* Cast to unsigned is OK because of check for negative.
5291 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5292 * Exponentiation is straight forward
5293 */
5294 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5295 }
5296
5297
5298 /**
5299 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5300 *
5301 * @param[in] uMantissa Unsigned integer mantissa.
5302 * @param[in] nExponent Unsigned integer exponent.
5303 * @param[out] puResult Place to put the unsigned integer result.
5304 * @param[in] pfExp Exponentiation function.
5305 *
5306 * @returns Error code
5307 *
5308 * \c pfExp performs exponentiation on and unsigned mantissa and
5309 * produces an unsigned result so this is just a wrapper that does
5310 * nothing (and is likely inlined).
5311 */
5312 static QCBORError
QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,const int64_t nExponent,uint64_t * puResult,fExponentiator pfExp)5313 QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5314 const int64_t nExponent,
5315 uint64_t *puResult,
5316 fExponentiator pfExp)
5317 {
5318 return (*pfExp)(uMantissa, nExponent, puResult);
5319 }
5320
5321 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
5322
5323
5324
5325
5326 /**
5327 * @brief Convert a CBOR big number to a uint64_t.
5328 *
5329 * @param[in] BigNum Bytes of the big number to convert.
5330 * @param[in] uMax Maximum value allowed for the result.
5331 * @param[out] pResult Place to put the unsigned integer result.
5332 *
5333 * @returns Error code
5334 *
5335 * Many values will overflow because a big num can represent a much
5336 * larger range than uint64_t.
5337 */
5338 static QCBORError
QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,const uint64_t uMax,uint64_t * pResult)5339 QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5340 const uint64_t uMax,
5341 uint64_t *pResult)
5342 {
5343 uint64_t uResult;
5344
5345 uResult = 0;
5346 const uint8_t *pByte = BigNum.ptr;
5347 size_t uLen = BigNum.len;
5348 while(uLen--) {
5349 if(uResult > (uMax >> 8)) {
5350 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5351 }
5352 uResult = (uResult << 8) + *pByte++;
5353 }
5354
5355 *pResult = uResult;
5356 return QCBOR_SUCCESS;
5357 }
5358
5359
5360 /**
5361 * @brief Convert a CBOR postive big number to a uint64_t.
5362 *
5363 * @param[in] BigNum Bytes of the big number to convert.
5364 * @param[out] pResult Place to put the unsigned integer result.
5365 *
5366 * @returns Error code
5367 *
5368 * Many values will overflow because a big num can represent a much
5369 * larger range than uint64_t.
5370 */
5371 static QCBORError
QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,uint64_t * pResult)5372 QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5373 uint64_t *pResult)
5374 {
5375 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
5376 }
5377
5378
5379 /**
5380 * @brief Convert a CBOR positive big number to an int64_t.
5381 *
5382 * @param[in] BigNum Bytes of the big number to convert.
5383 * @param[out] pResult Place to put the signed integer result.
5384 *
5385 * @returns Error code
5386 *
5387 * Many values will overflow because a big num can represent a much
5388 * larger range than int64_t.
5389 */
5390 static QCBORError
QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,int64_t * pResult)5391 QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5392 int64_t *pResult)
5393 {
5394 uint64_t uResult;
5395 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5396 INT64_MAX,
5397 &uResult);
5398 if(uError) {
5399 return uError;
5400 }
5401 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
5402 *pResult = (int64_t)uResult;
5403 return QCBOR_SUCCESS;
5404 }
5405
5406
5407 /**
5408 * @brief Convert a CBOR negative big number to an int64_t.
5409 *
5410 * @param[in] BigNum Bytes of the big number to convert.
5411 * @param[out] pnResult Place to put the signed integer result.
5412 *
5413 * @returns Error code
5414 *
5415 * Many values will overflow because a big num can represent a much
5416 * larger range than int64_t.
5417 */
5418 static QCBORError
QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,int64_t * pnResult)5419 QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5420 int64_t *pnResult)
5421 {
5422 uint64_t uResult;
5423 /* The negative integer furthest from zero for a C int64_t is
5424 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5425 * negative number in CBOR is computed as -n - 1 where n is the
5426 * encoded integer, where n is what is in the variable BigNum. When
5427 * converting BigNum to a uint64_t, the maximum value is thus
5428 * INT64_MAX, so that when it -n - 1 is applied to it the result
5429 * will never be further from 0 than INT64_MIN.
5430 *
5431 * -n - 1 <= INT64_MIN.
5432 * -n - 1 <= -INT64_MAX - 1
5433 * n <= INT64_MAX.
5434 */
5435 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5436 INT64_MAX,
5437 &uResult);
5438 if(uError != QCBOR_SUCCESS) {
5439 return uError;
5440 }
5441
5442 /* Now apply -n - 1. The cast is safe because
5443 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5444 * is the largest positive integer that an int64_t can
5445 * represent. */
5446 *pnResult = -(int64_t)uResult - 1;
5447
5448 return QCBOR_SUCCESS;
5449 }
5450
5451
5452
5453
5454 /**
5455 * @brief Convert integers and floats to an int64_t.
5456 *
5457 * @param[in] pItem The item to convert.
5458 * @param[in] uConvertTypes Bit mask list of conversion options.
5459 * @param[out] pnValue The resulting converted value.
5460 *
5461 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5462 * in uConvertTypes.
5463 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5464 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5465 * or too small.
5466 */
5467 static QCBORError
QCBOR_Private_ConvertInt64(const QCBORItem * pItem,const uint32_t uConvertTypes,int64_t * pnValue)5468 QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5469 const uint32_t uConvertTypes,
5470 int64_t *pnValue)
5471 {
5472 switch(pItem->uDataType) {
5473 case QCBOR_TYPE_FLOAT:
5474 case QCBOR_TYPE_DOUBLE:
5475 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
5476 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
5477 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5478 http://www.cplusplus.com/reference/cmath/llround/
5479 */
5480 // Not interested in FE_INEXACT
5481 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5482 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5483 *pnValue = llround(pItem->val.dfnum);
5484 } else {
5485 *pnValue = lroundf(pItem->val.fnum);
5486 }
5487 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5488 // llround() shouldn't result in divide by zero, but catch
5489 // it here in case it unexpectedly does. Don't try to
5490 // distinguish between the various exceptions because it seems
5491 // they vary by CPU, compiler and OS.
5492 return QCBOR_ERR_FLOAT_EXCEPTION;
5493 }
5494 } else {
5495 return QCBOR_ERR_UNEXPECTED_TYPE;
5496 }
5497 #else
5498 return QCBOR_ERR_HW_FLOAT_DISABLED;
5499 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
5500 break;
5501
5502 case QCBOR_TYPE_INT64:
5503 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5504 *pnValue = pItem->val.int64;
5505 } else {
5506 return QCBOR_ERR_UNEXPECTED_TYPE;
5507 }
5508 break;
5509
5510 case QCBOR_TYPE_UINT64:
5511 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5512 if(pItem->val.uint64 < INT64_MAX) {
5513 *pnValue = pItem->val.int64;
5514 } else {
5515 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5516 }
5517 } else {
5518 return QCBOR_ERR_UNEXPECTED_TYPE;
5519 }
5520 break;
5521
5522 default:
5523 return QCBOR_ERR_UNEXPECTED_TYPE;
5524 }
5525 return QCBOR_SUCCESS;
5526 }
5527
5528
5529 /**
5530 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5531 *
5532 * @param[in] pMe The decode context.
5533 * @param[in] uConvertTypes Bit mask list of conversion options.
5534 * @param[out] pnValue Result of the conversion.
5535 * @param[in,out] pItem Temporary space to store Item, returned item.
5536 *
5537 * See QCBORDecode_GetInt64Convert().
5538 */
5539 void
QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext * pMe,uint32_t uConvertTypes,int64_t * pnValue,QCBORItem * pItem)5540 QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5541 uint32_t uConvertTypes,
5542 int64_t *pnValue,
5543 QCBORItem *pItem)
5544 {
5545 QCBORDecode_VGetNext(pMe, pItem);
5546 if(pMe->uLastError) {
5547 return;
5548 }
5549
5550 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5551 uConvertTypes,
5552 pnValue);
5553 }
5554
5555 /**
5556 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5557 *
5558 * @param[in] pMe The decode context.
5559 * @param[in] nLabel Label to find in map.
5560 * @param[in] uConvertTypes Bit mask list of conversion options.
5561 * @param[out] pnValue Result of the conversion.
5562 * @param[in,out] pItem Temporary space to store Item, returned item.
5563 *
5564 * See QCBORDecode_GetInt64ConvertInMapN().
5565 */
5566 void
QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext * pMe,int64_t nLabel,uint32_t uConvertTypes,int64_t * pnValue,QCBORItem * pItem)5567 QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5568 int64_t nLabel,
5569 uint32_t uConvertTypes,
5570 int64_t *pnValue,
5571 QCBORItem *pItem)
5572 {
5573 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
5574 if(pMe->uLastError != QCBOR_SUCCESS) {
5575 return;
5576 }
5577
5578 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5579 uConvertTypes,
5580 pnValue);
5581 }
5582
5583 /**
5584 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5585 *
5586 * @param[in] pMe The decode context.
5587 * @param[in] szLabel Label to find in map.
5588 * @param[in] uConvertTypes Bit mask list of conversion options.
5589 * @param[out] pnValue Result of the conversion.
5590 * @param[in,out] pItem Temporary space to store Item, returned item.
5591 *
5592 * See QCBORDecode_GetInt64ConvertInMapSZ().
5593 */
5594 void
QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,uint32_t uConvertTypes,int64_t * pnValue,QCBORItem * pItem)5595 QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5596 const char * szLabel,
5597 uint32_t uConvertTypes,
5598 int64_t *pnValue,
5599 QCBORItem *pItem)
5600 {
5601 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
5602 if(pMe->uLastError != QCBOR_SUCCESS) {
5603 return;
5604 }
5605
5606 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5607 uConvertTypes,
5608 pnValue);
5609 }
5610
5611
5612 /**
5613 * @brief Convert many number types to an int64_t.
5614 *
5615 * @param[in] pItem The item to convert.
5616 * @param[in] uConvertTypes Bit mask list of conversion options.
5617 * @param[out] pnValue The resulting converted value.
5618 *
5619 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5620 * in uConvertTypes.
5621 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5622 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5623 * or too small.
5624 */
5625 static QCBORError
QCBOR_Private_Int64ConvertAll(const QCBORItem * pItem,const uint32_t uConvertTypes,int64_t * pnValue)5626 QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5627 const uint32_t uConvertTypes,
5628 int64_t *pnValue)
5629 {
5630 switch(pItem->uDataType) {
5631
5632 case QCBOR_TYPE_POSBIGNUM:
5633 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
5634 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
5635 } else {
5636 return QCBOR_ERR_UNEXPECTED_TYPE;
5637 }
5638 break;
5639
5640 case QCBOR_TYPE_NEGBIGNUM:
5641 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
5642 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
5643 } else {
5644 return QCBOR_ERR_UNEXPECTED_TYPE;
5645 }
5646 break;
5647
5648 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
5649 case QCBOR_TYPE_DECIMAL_FRACTION:
5650 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
5651 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
5652 pItem->val.expAndMantissa.nExponent,
5653 pnValue,
5654 &QCBOR_Private_Exponentitate10);
5655 } else {
5656 return QCBOR_ERR_UNEXPECTED_TYPE;
5657 }
5658 break;
5659
5660 case QCBOR_TYPE_BIGFLOAT:
5661 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
5662 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
5663 pItem->val.expAndMantissa.nExponent,
5664 pnValue,
5665 QCBOR_Private_Exponentitate2);
5666 } else {
5667 return QCBOR_ERR_UNEXPECTED_TYPE;
5668 }
5669 break;
5670
5671 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
5672 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
5673 int64_t nMantissa;
5674 QCBORError uErr;
5675 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
5676 if(uErr) {
5677 return uErr;
5678 }
5679 return QCBOR_Private_ExponentiateNN(nMantissa,
5680 pItem->val.expAndMantissa.nExponent,
5681 pnValue,
5682 QCBOR_Private_Exponentitate10);
5683 } else {
5684 return QCBOR_ERR_UNEXPECTED_TYPE;
5685 }
5686 break;
5687
5688 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
5689 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
5690 int64_t nMantissa;
5691 QCBORError uErr;
5692 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
5693 if(uErr) {
5694 return uErr;
5695 }
5696 return QCBOR_Private_ExponentiateNN(nMantissa,
5697 pItem->val.expAndMantissa.nExponent,
5698 pnValue,
5699 QCBOR_Private_Exponentitate10);
5700 } else {
5701 return QCBOR_ERR_UNEXPECTED_TYPE;
5702 }
5703 break;
5704
5705 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
5706 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
5707 int64_t nMantissa;
5708 QCBORError uErr;
5709 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
5710 if(uErr) {
5711 return uErr;
5712 }
5713 return QCBOR_Private_ExponentiateNN(nMantissa,
5714 pItem->val.expAndMantissa.nExponent,
5715 pnValue,
5716 QCBOR_Private_Exponentitate2);
5717 } else {
5718 return QCBOR_ERR_UNEXPECTED_TYPE;
5719 }
5720 break;
5721
5722 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
5723 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
5724 int64_t nMantissa;
5725 QCBORError uErr;
5726 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
5727 if(uErr) {
5728 return uErr;
5729 }
5730 return QCBOR_Private_ExponentiateNN(nMantissa,
5731 pItem->val.expAndMantissa.nExponent,
5732 pnValue,
5733 QCBOR_Private_Exponentitate2);
5734 } else {
5735 return QCBOR_ERR_UNEXPECTED_TYPE;
5736 }
5737 break;
5738 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
5739
5740
5741 default:
5742 return QCBOR_ERR_UNEXPECTED_TYPE; }
5743 }
5744
5745
5746 /*
5747 * Public function, see header qcbor/qcbor_decode.h file
5748 */
5749 void
QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext * pMe,const uint32_t uConvertTypes,int64_t * pnValue)5750 QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5751 const uint32_t uConvertTypes,
5752 int64_t *pnValue)
5753 {
5754 QCBORItem Item;
5755
5756 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
5757
5758 if(pMe->uLastError == QCBOR_SUCCESS) {
5759 // The above conversion succeeded
5760 return;
5761 }
5762
5763 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5764 // The above conversion failed in a way that code below can't correct
5765 return;
5766 }
5767
5768 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5769 uConvertTypes,
5770 pnValue);
5771 }
5772
5773
5774 /*
5775 * Public function, see header qcbor/qcbor_decode.h file
5776 */
5777 void
QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint32_t uConvertTypes,int64_t * pnValue)5778 QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5779 const int64_t nLabel,
5780 const uint32_t uConvertTypes,
5781 int64_t *pnValue)
5782 {
5783 QCBORItem Item;
5784
5785 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
5786 nLabel,
5787 uConvertTypes,
5788 pnValue,
5789 &Item);
5790
5791 if(pMe->uLastError == QCBOR_SUCCESS) {
5792 // The above conversion succeeded
5793 return;
5794 }
5795
5796 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5797 // The above conversion failed in a way that code below can't correct
5798 return;
5799 }
5800
5801 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5802 uConvertTypes,
5803 pnValue);
5804 }
5805
5806
5807 /*
5808 * Public function, see header qcbor/qcbor_decode.h file
5809 */
5810 void
QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint32_t uConvertTypes,int64_t * pnValue)5811 QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5812 const char *szLabel,
5813 const uint32_t uConvertTypes,
5814 int64_t *pnValue)
5815 {
5816 QCBORItem Item;
5817 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
5818 szLabel,
5819 uConvertTypes,
5820 pnValue,
5821 &Item);
5822
5823 if(pMe->uLastError == QCBOR_SUCCESS) {
5824 // The above conversion succeeded
5825 return;
5826 }
5827
5828 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5829 // The above conversion failed in a way that code below can't correct
5830 return;
5831 }
5832
5833 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5834 uConvertTypes,
5835 pnValue);
5836 }
5837
5838
5839 /**
5840 * @brief Convert many number types to an uint64_t.
5841 *
5842 * @param[in] pItem The item to convert.
5843 * @param[in] uConvertTypes Bit mask list of conversion options.
5844 * @param[out] puValue The resulting converted value.
5845 *
5846 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5847 * in uConvertTypes.
5848 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5849 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5850 * or too small.
5851 */
5852 static QCBORError
QCBOR_Private_ConvertUInt64(const QCBORItem * pItem,const uint32_t uConvertTypes,uint64_t * puValue)5853 QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5854 const uint32_t uConvertTypes,
5855 uint64_t *puValue)
5856 {
5857 switch(pItem->uDataType) {
5858 case QCBOR_TYPE_DOUBLE:
5859 case QCBOR_TYPE_FLOAT:
5860 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
5861 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
5862 // Can't use llround here because it will not convert values
5863 // greater than INT64_MAX and less than UINT64_MAX that
5864 // need to be converted so it is more complicated.
5865 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5866 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5867 if(isnan(pItem->val.dfnum)) {
5868 return QCBOR_ERR_FLOAT_EXCEPTION;
5869 } else if(pItem->val.dfnum < 0) {
5870 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5871 } else {
5872 double dRounded = round(pItem->val.dfnum);
5873 // See discussion in DecodeDateEpoch() for
5874 // explanation of - 0x7ff
5875 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5876 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5877 }
5878 *puValue = (uint64_t)dRounded;
5879 }
5880 } else {
5881 if(isnan(pItem->val.fnum)) {
5882 return QCBOR_ERR_FLOAT_EXCEPTION;
5883 } else if(pItem->val.fnum < 0) {
5884 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5885 } else {
5886 float fRounded = roundf(pItem->val.fnum);
5887 // See discussion in DecodeDateEpoch() for
5888 // explanation of - 0x7ff
5889 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5890 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5891 }
5892 *puValue = (uint64_t)fRounded;
5893 }
5894 }
5895 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5896 // round() and roundf() shouldn't result in exceptions here, but
5897 // catch them to be robust and thorough. Don't try to
5898 // distinguish between the various exceptions because it seems
5899 // they vary by CPU, compiler and OS.
5900 return QCBOR_ERR_FLOAT_EXCEPTION;
5901 }
5902
5903 } else {
5904 return QCBOR_ERR_UNEXPECTED_TYPE;
5905 }
5906 #else
5907 return QCBOR_ERR_HW_FLOAT_DISABLED;
5908 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
5909 break;
5910
5911 case QCBOR_TYPE_INT64:
5912 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5913 if(pItem->val.int64 >= 0) {
5914 *puValue = (uint64_t)pItem->val.int64;
5915 } else {
5916 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5917 }
5918 } else {
5919 return QCBOR_ERR_UNEXPECTED_TYPE;
5920 }
5921 break;
5922
5923 case QCBOR_TYPE_UINT64:
5924 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5925 *puValue = pItem->val.uint64;
5926 } else {
5927 return QCBOR_ERR_UNEXPECTED_TYPE;
5928 }
5929 break;
5930
5931 default:
5932 return QCBOR_ERR_UNEXPECTED_TYPE;
5933 }
5934
5935 return QCBOR_SUCCESS;
5936 }
5937
5938
5939 /**
5940 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5941 *
5942 * @param[in] pMe The decode context.
5943 * @param[in] uConvertTypes Bit mask list of conversion options.
5944 * @param[out] puValue Result of the conversion.
5945 * @param[in,out] pItem Temporary space to store Item, returned item.
5946 *
5947 * See QCBORDecode_GetUInt64Convert().
5948 */
5949 void
QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext * pMe,const uint32_t uConvertTypes,uint64_t * puValue,QCBORItem * pItem)5950 QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5951 const uint32_t uConvertTypes,
5952 uint64_t *puValue,
5953 QCBORItem *pItem)
5954 {
5955 QCBORDecode_VGetNext(pMe, pItem);
5956 if(pMe->uLastError) {
5957 return;
5958 }
5959
5960 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5961 uConvertTypes,
5962 puValue);
5963 }
5964
5965
5966 /**
5967 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5968 *
5969 * @param[in] pMe The decode context.
5970 * @param[in] nLabel Label to find in map.
5971 * @param[in] uConvertTypes Bit mask list of conversion options.
5972 * @param[out] puValue Result of the conversion.
5973 * @param[in,out] pItem Temporary space to store Item, returned item.
5974 *
5975 * See QCBORDecode_GetUInt64ConvertInMapN().
5976 */
5977 void
QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint32_t uConvertTypes,uint64_t * puValue,QCBORItem * pItem)5978 QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5979 const int64_t nLabel,
5980 const uint32_t uConvertTypes,
5981 uint64_t *puValue,
5982 QCBORItem *pItem)
5983 {
5984 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
5985 if(pMe->uLastError != QCBOR_SUCCESS) {
5986 return;
5987 }
5988
5989 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5990 uConvertTypes,
5991 puValue);
5992 }
5993
5994
5995 /**
5996 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5997 *
5998 * @param[in] pMe The decode context.
5999 * @param[in] szLabel Label to find in map.
6000 * @param[in] uConvertTypes Bit mask list of conversion options.
6001 * @param[out] puValue Result of the conversion.
6002 * @param[in,out] pItem Temporary space to store Item, returned item.
6003 *
6004 * See QCBORDecode_GetUInt64ConvertInMapSZ().
6005 */
6006 void
QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint32_t uConvertTypes,uint64_t * puValue,QCBORItem * pItem)6007 QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
6008 const char *szLabel,
6009 const uint32_t uConvertTypes,
6010 uint64_t *puValue,
6011 QCBORItem *pItem)
6012 {
6013 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
6014 if(pMe->uLastError != QCBOR_SUCCESS) {
6015 return;
6016 }
6017
6018 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6019 uConvertTypes,
6020 puValue);
6021 }
6022
6023
6024 /**
6025 * @brief Convert many number types to an unt64_t.
6026 *
6027 * @param[in] pItem The item to convert.
6028 * @param[in] uConvertTypes Bit mask list of conversion options.
6029 * @param[out] puValue The resulting converted value.
6030 *
6031 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6032 * in uConvertTypes.
6033 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6034 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6035 * or too small.
6036 */
6037 static QCBORError
QCBOR_Private_UInt64ConvertAll(const QCBORItem * pItem,const uint32_t uConvertTypes,uint64_t * puValue)6038 QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
6039 const uint32_t uConvertTypes,
6040 uint64_t *puValue)
6041 {
6042 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
6043
6044 case QCBOR_TYPE_POSBIGNUM:
6045 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
6046 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
6047 } else {
6048 return QCBOR_ERR_UNEXPECTED_TYPE;
6049 }
6050 break;
6051
6052 case QCBOR_TYPE_NEGBIGNUM:
6053 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
6054 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6055 } else {
6056 return QCBOR_ERR_UNEXPECTED_TYPE;
6057 }
6058 break;
6059
6060 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
6061
6062 case QCBOR_TYPE_DECIMAL_FRACTION:
6063 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
6064 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
6065 pItem->val.expAndMantissa.nExponent,
6066 puValue,
6067 QCBOR_Private_Exponentitate10);
6068 } else {
6069 return QCBOR_ERR_UNEXPECTED_TYPE;
6070 }
6071 break;
6072
6073 case QCBOR_TYPE_BIGFLOAT:
6074 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
6075 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
6076 pItem->val.expAndMantissa.nExponent,
6077 puValue,
6078 QCBOR_Private_Exponentitate2);
6079 } else {
6080 return QCBOR_ERR_UNEXPECTED_TYPE;
6081 }
6082 break;
6083
6084 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6085 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
6086 uint64_t uMantissa;
6087 QCBORError uErr;
6088 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
6089 if(uErr != QCBOR_SUCCESS) {
6090 return uErr;
6091 }
6092 return QCBOR_Private_ExponentitateUU(uMantissa,
6093 pItem->val.expAndMantissa.nExponent,
6094 puValue,
6095 QCBOR_Private_Exponentitate10);
6096 } else {
6097 return QCBOR_ERR_UNEXPECTED_TYPE;
6098 }
6099 break;
6100
6101 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6102 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
6103 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6104 } else {
6105 return QCBOR_ERR_UNEXPECTED_TYPE;
6106 }
6107 break;
6108
6109 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6110 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
6111 uint64_t uMantissa;
6112 QCBORError uErr;
6113 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6114 &uMantissa);
6115 if(uErr != QCBOR_SUCCESS) {
6116 return uErr;
6117 }
6118 return QCBOR_Private_ExponentitateUU(uMantissa,
6119 pItem->val.expAndMantissa.nExponent,
6120 puValue,
6121 QCBOR_Private_Exponentitate2);
6122 } else {
6123 return QCBOR_ERR_UNEXPECTED_TYPE;
6124 }
6125 break;
6126
6127 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6128 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
6129 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6130 } else {
6131 return QCBOR_ERR_UNEXPECTED_TYPE;
6132 }
6133 break;
6134 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
6135 default:
6136 return QCBOR_ERR_UNEXPECTED_TYPE;
6137 }
6138 }
6139
6140
6141 /*
6142 * Public function, see header qcbor/qcbor_decode.h file
6143 */
6144 void
QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext * pMe,const uint32_t uConvertTypes,uint64_t * puValue)6145 QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6146 const uint32_t uConvertTypes,
6147 uint64_t *puValue)
6148 {
6149 QCBORItem Item;
6150
6151 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
6152
6153 if(pMe->uLastError == QCBOR_SUCCESS) {
6154 // The above conversion succeeded
6155 return;
6156 }
6157
6158 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6159 // The above conversion failed in a way that code below can't correct
6160 return;
6161 }
6162
6163 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6164 uConvertTypes,
6165 puValue);
6166 }
6167
6168
6169 /*
6170 * Public function, see header qcbor/qcbor_decode.h file
6171 */
6172 void
QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint32_t uConvertTypes,uint64_t * puValue)6173 QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6174 const int64_t nLabel,
6175 const uint32_t uConvertTypes,
6176 uint64_t *puValue)
6177 {
6178 QCBORItem Item;
6179
6180 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
6181 nLabel,
6182 uConvertTypes,
6183 puValue,
6184 &Item);
6185
6186 if(pMe->uLastError == QCBOR_SUCCESS) {
6187 // The above conversion succeeded
6188 return;
6189 }
6190
6191 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6192 // The above conversion failed in a way that code below can't correct
6193 return;
6194 }
6195
6196 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6197 uConvertTypes,
6198 puValue);
6199 }
6200
6201
6202 /*
6203 * Public function, see header qcbor/qcbor_decode.h file
6204 */
6205 void
QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint32_t uConvertTypes,uint64_t * puValue)6206 QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6207 const char *szLabel,
6208 const uint32_t uConvertTypes,
6209 uint64_t *puValue)
6210 {
6211 QCBORItem Item;
6212 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
6213 szLabel,
6214 uConvertTypes,
6215 puValue,
6216 &Item);
6217
6218 if(pMe->uLastError == QCBOR_SUCCESS) {
6219 // The above conversion succeeded
6220 return;
6221 }
6222
6223 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6224 // The above conversion failed in a way that code below can't correct
6225 return;
6226 }
6227
6228 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6229 uConvertTypes,
6230 puValue);
6231 }
6232
6233
6234
6235
6236 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
6237 /**
6238 * @brief Basic conversions to a double.
6239 *
6240 * @param[in] pItem The item to convert
6241 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6242 * @param[out] pdValue The value converted to a double
6243 *
6244 * This does the conversions that don't need much object code,
6245 * the conversions from int, uint and float to double.
6246 *
6247 * See QCBOR_Private_DoubleConvertAll() for the full set
6248 * of conversions.
6249 */
6250 static QCBORError
QCBOR_Private_ConvertDouble(const QCBORItem * pItem,const uint32_t uConvertTypes,double * pdValue)6251 QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6252 const uint32_t uConvertTypes,
6253 double *pdValue)
6254 {
6255 switch(pItem->uDataType) {
6256 case QCBOR_TYPE_FLOAT:
6257 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
6258 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6259 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6260 // Simple cast does the job.
6261 *pdValue = (double)pItem->val.fnum;
6262 } else {
6263 return QCBOR_ERR_UNEXPECTED_TYPE;
6264 }
6265 }
6266 #else /* QCBOR_DISABLE_FLOAT_HW_USE */
6267 return QCBOR_ERR_HW_FLOAT_DISABLED;
6268 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6269 break;
6270
6271 case QCBOR_TYPE_DOUBLE:
6272 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6273 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6274 *pdValue = pItem->val.dfnum;
6275 } else {
6276 return QCBOR_ERR_UNEXPECTED_TYPE;
6277 }
6278 }
6279 break;
6280
6281 case QCBOR_TYPE_INT64:
6282 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
6283 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
6284 // A simple cast seems to do the job with no worry of exceptions.
6285 // There will be precision loss for some values.
6286 *pdValue = (double)pItem->val.int64;
6287
6288 } else {
6289 return QCBOR_ERR_UNEXPECTED_TYPE;
6290 }
6291 #else
6292 return QCBOR_ERR_HW_FLOAT_DISABLED;
6293 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6294 break;
6295
6296 case QCBOR_TYPE_UINT64:
6297 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
6298 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
6299 // A simple cast seems to do the job with no worry of exceptions.
6300 // There will be precision loss for some values.
6301 *pdValue = (double)pItem->val.uint64;
6302 } else {
6303 return QCBOR_ERR_UNEXPECTED_TYPE;
6304 }
6305 break;
6306 #else
6307 return QCBOR_ERR_HW_FLOAT_DISABLED;
6308 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6309
6310 default:
6311 return QCBOR_ERR_UNEXPECTED_TYPE;
6312 }
6313
6314 return QCBOR_SUCCESS;
6315 }
6316
6317
6318 /**
6319 * @brief Almost-public method to decode a number and convert to double (semi-private).
6320 *
6321 * @param[in] pMe The decode context.
6322 * @param[in] uConvertTypes Bit mask list of conversion options
6323 * @param[out] pdValue The output of the conversion.
6324 * @param[in,out] pItem Temporary space to store Item, returned item.
6325 *
6326 * See QCBORDecode_GetDoubleConvert().
6327 */
6328 void
QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext * pMe,const uint32_t uConvertTypes,double * pdValue,QCBORItem * pItem)6329 QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6330 const uint32_t uConvertTypes,
6331 double *pdValue,
6332 QCBORItem *pItem)
6333 {
6334 QCBORDecode_VGetNext(pMe, pItem);
6335 if(pMe->uLastError) {
6336 return;
6337 }
6338
6339 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6340 uConvertTypes,
6341 pdValue);
6342 }
6343
6344
6345 /**
6346 * @brief Almost-public method to decode a number and convert to double (semi-private).
6347 *
6348 * @param[in] pMe The decode context.
6349 * @param[in] nLabel Label to find in map.
6350 * @param[in] uConvertTypes Bit mask list of conversion options
6351 * @param[out] pdValue The output of the conversion.
6352 * @param[in,out] pItem Temporary space to store Item, returned item.
6353 *
6354 * See QCBORDecode_GetDoubleConvertInMapN().
6355 */
6356 void
QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint32_t uConvertTypes,double * pdValue,QCBORItem * pItem)6357 QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6358 const int64_t nLabel,
6359 const uint32_t uConvertTypes,
6360 double *pdValue,
6361 QCBORItem *pItem)
6362 {
6363 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
6364 if(pMe->uLastError != QCBOR_SUCCESS) {
6365 return;
6366 }
6367
6368 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6369 uConvertTypes,
6370 pdValue);
6371 }
6372
6373
6374 /**
6375 * @brief Almost-public method to decode a number and convert to double (semi-private).
6376 *
6377 * @param[in] pMe The decode context.
6378 * @param[in] szLabel Label to find in map.
6379 * @param[in] uConvertTypes Bit mask list of conversion options
6380 * @param[out] pdValue The output of the conversion.
6381 * @param[in,out] pItem Temporary space to store Item, returned item.
6382 *
6383 * See QCBORDecode_GetDoubleConvertInMapSZ().
6384 */
6385 void
QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint32_t uConvertTypes,double * pdValue,QCBORItem * pItem)6386 QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6387 const char *szLabel,
6388 const uint32_t uConvertTypes,
6389 double *pdValue,
6390 QCBORItem *pItem)
6391 {
6392 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
6393 if(pMe->uLastError != QCBOR_SUCCESS) {
6394 return;
6395 }
6396
6397 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6398 uConvertTypes,
6399 pdValue);
6400 }
6401
6402
6403 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
6404 /**
6405 * @brief Convert a big number to double-precision float.
6406 *
6407 * @param[in] BigNum The big number to convert
6408 *
6409 * @returns The double value.
6410 *
6411 * This will always succeed. It will lose precision for larger
6412 * numbers. If the big number is too large to fit (more than
6413 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6414 * returned.
6415 */
6416 static double
QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)6417 QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
6418 {
6419 double dResult;
6420
6421 dResult = 0.0;
6422 const uint8_t *pByte = BigNum.ptr;
6423 size_t uLen = BigNum.len;
6424 /* This will overflow and become the float value INFINITY if the number
6425 * is too large to fit. */
6426 while(uLen--) {
6427 dResult = (dResult * 256.0) + (double)*pByte++;
6428 }
6429
6430 return dResult;
6431 }
6432 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6433
6434
6435
6436
6437 /**
6438 * @brief Convert many number types to a double.
6439 *
6440 * @param[in] pItem The item to convert.
6441 * @param[in] uConvertTypes Bit mask list of conversion options.
6442 * @param[out] pdValue The resulting converted value.
6443 *
6444 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6445 * in uConvertTypes.
6446 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6447 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6448 * or too small.
6449 */
6450 static QCBORError
QCBOR_Private_DoubleConvertAll(const QCBORItem * pItem,const uint32_t uConvertTypes,double * pdValue)6451 QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6452 const uint32_t uConvertTypes,
6453 double *pdValue)
6454 {
6455 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
6456 /*
6457 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6458 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6459 */
6460 switch(pItem->uDataType) {
6461
6462 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
6463 case QCBOR_TYPE_DECIMAL_FRACTION:
6464 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
6465 // Underflow gives 0, overflow gives infinity
6466 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6467 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6468 } else {
6469 return QCBOR_ERR_UNEXPECTED_TYPE;
6470 }
6471 break;
6472
6473 case QCBOR_TYPE_BIGFLOAT:
6474 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
6475 // Underflow gives 0, overflow gives infinity
6476 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6477 exp2((double)pItem->val.expAndMantissa.nExponent);
6478 } else {
6479 return QCBOR_ERR_UNEXPECTED_TYPE;
6480 }
6481 break;
6482 #endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
6483
6484 case QCBOR_TYPE_POSBIGNUM:
6485 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
6486 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
6487 } else {
6488 return QCBOR_ERR_UNEXPECTED_TYPE;
6489 }
6490 break;
6491
6492 case QCBOR_TYPE_NEGBIGNUM:
6493 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
6494 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
6495 } else {
6496 return QCBOR_ERR_UNEXPECTED_TYPE;
6497 }
6498 break;
6499
6500 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
6501 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6502 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
6503 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
6504 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6505 } else {
6506 return QCBOR_ERR_UNEXPECTED_TYPE;
6507 }
6508 break;
6509
6510 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6511 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
6512 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
6513 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6514 } else {
6515 return QCBOR_ERR_UNEXPECTED_TYPE;
6516 }
6517 break;
6518
6519 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6520 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
6521 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
6522 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6523 } else {
6524 return QCBOR_ERR_UNEXPECTED_TYPE;
6525 }
6526 break;
6527
6528 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6529 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
6530 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
6531 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6532 } else {
6533 return QCBOR_ERR_UNEXPECTED_TYPE;
6534 }
6535 break;
6536 #endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
6537
6538 default:
6539 return QCBOR_ERR_UNEXPECTED_TYPE;
6540 }
6541
6542 return QCBOR_SUCCESS;
6543
6544 #else
6545 (void)pItem;
6546 (void)uConvertTypes;
6547 (void)pdValue;
6548 return QCBOR_ERR_HW_FLOAT_DISABLED;
6549 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6550
6551 }
6552
6553
6554 /*
6555 * Public function, see header qcbor/qcbor_decode.h file
6556 */
6557 void
QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext * pMe,const uint32_t uConvertTypes,double * pdValue)6558 QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6559 const uint32_t uConvertTypes,
6560 double *pdValue)
6561 {
6562
6563 QCBORItem Item;
6564
6565 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
6566
6567 if(pMe->uLastError == QCBOR_SUCCESS) {
6568 // The above conversion succeeded
6569 return;
6570 }
6571
6572 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6573 // The above conversion failed in a way that code below can't correct
6574 return;
6575 }
6576
6577 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6578 uConvertTypes,
6579 pdValue);
6580 }
6581
6582
6583 /*
6584 * Public function, see header qcbor/qcbor_decode.h file
6585 */
6586 void
QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint32_t uConvertTypes,double * pdValue)6587 QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6588 const int64_t nLabel,
6589 const uint32_t uConvertTypes,
6590 double *pdValue)
6591 {
6592 QCBORItem Item;
6593
6594 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6595 nLabel,
6596 uConvertTypes,
6597 pdValue,
6598 &Item);
6599
6600 if(pMe->uLastError == QCBOR_SUCCESS) {
6601 // The above conversion succeeded
6602 return;
6603 }
6604
6605 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6606 // The above conversion failed in a way that code below can't correct
6607 return;
6608 }
6609
6610 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6611 uConvertTypes,
6612 pdValue);
6613 }
6614
6615
6616 /*
6617 * Public function, see header qcbor/qcbor_decode.h file
6618 */
6619 void
QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint32_t uConvertTypes,double * pdValue)6620 QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6621 const char *szLabel,
6622 const uint32_t uConvertTypes,
6623 double *pdValue)
6624 {
6625 QCBORItem Item;
6626 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6627 szLabel,
6628 uConvertTypes,
6629 pdValue,
6630 &Item);
6631
6632 if(pMe->uLastError == QCBOR_SUCCESS) {
6633 // The above conversion succeeded
6634 return;
6635 }
6636
6637 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6638 // The above conversion failed in a way that code below can't correct
6639 return;
6640 }
6641
6642 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6643 uConvertTypes,
6644 pdValue);
6645 }
6646 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
6647
6648
6649
6650
6651 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
6652 /**
6653 * @brief Convert an integer to a big number
6654 *
6655 * @param[in] uInt The integer to convert.
6656 * @param[in] Buffer The buffer to output the big number to.
6657 *
6658 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6659 *
6660 * This always succeeds unless the buffer is too small.
6661 */
6662 static UsefulBufC
QCBOR_Private_ConvertIntToBigNum(uint64_t uInt,const UsefulBuf Buffer)6663 QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
6664 {
6665 while((uInt & 0xff00000000000000UL) == 0) {
6666 uInt = uInt << 8;
6667 };
6668
6669 UsefulOutBuf UOB;
6670
6671 UsefulOutBuf_Init(&UOB, Buffer);
6672
6673 while(uInt) {
6674 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6675 uInt = uInt << 8;
6676 }
6677
6678 return UsefulOutBuf_OutUBuf(&UOB);
6679 }
6680
6681
6682 /**
6683 * @brief Check and/or complete exponent and mantissa item.
6684 *
6685 * @param[in] pMe The decoder context.
6686 * @param[in] TagSpec Expected type(s).
6687 * @param[in,out] pItem See below.
6688 *
6689 * This is for decimal fractions and big floats, both of which are an
6690 * exponent and mantissa.
6691 *
6692 * If the item item had a tag number indicating it was a
6693 * decimal fraction or big float, then the input @c pItem will
6694 * have been decoded as exponent and mantissa. If there was
6695 * no tag number, the caller is asking this be decoded as a
6696 * big float or decimal fraction and @c pItem just has the
6697 * first item in an exponent and mantissa.
6698 *
6699 * On output, the item is always a fully decoded decimal fraction or
6700 * big float.
6701 *
6702 * This errors out if the input type does not meet the TagSpec.
6703 */
6704 static QCBORError
QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext * pMe,const QCBOR_Private_TagSpec TagSpec,QCBORItem * pItem)6705 QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6706 const QCBOR_Private_TagSpec TagSpec,
6707 QCBORItem *pItem)
6708 {
6709 QCBORError uErr;
6710
6711 /* pItem could either be a decoded exponent and mantissa or
6712 * the opening array of an undecoded exponent and mantissa. This
6713 * check will succeed on either, but doesn't say which it was.
6714 */
6715 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
6716 if(uErr != QCBOR_SUCCESS) {
6717 goto Done;
6718 }
6719
6720 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
6721 /* The item is an array, which means is is an undecoded exponent
6722 * and mantissa. This call consumes the items in the array and
6723 * results in a decoded exponent and mantissa in pItem. This is
6724 * the case where there was no tag.
6725 */
6726 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
6727 if(uErr != QCBOR_SUCCESS) {
6728 goto Done;
6729 }
6730
6731 /* The above decode didn't determine whether it is a decimal
6732 * fraction or big num. Which of these two depends on what the
6733 * caller wants it decoded as since there is no tag, so fish the
6734 * type out of the TagSpec. */
6735 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
6736
6737 /* No need to check the type again. All that we need to know was
6738 * that it decoded correctly as a exponent and mantissa. The
6739 * QCBOR type is set out by what was requested.
6740 */
6741 }
6742
6743 /* If the item was not an array and the check passed, then
6744 * it is a fully decoded big float or decimal fraction and
6745 * matches what is requested.
6746 */
6747
6748 Done:
6749 return uErr;
6750 }
6751
6752
6753 /* Some notes from the work to disable tags.
6754 *
6755 * The API for big floats and decimal fractions seems good.
6756 * If there's any issue with it it's that the code size to
6757 * implement is a bit large because of the conversion
6758 * to/from int and bignum that is required. There is no API
6759 * that doesn't do the conversion so dead stripping will never
6760 * leave that code out.
6761 *
6762 * The implementation itself seems correct, but not as clean
6763 * and neat as it could be. It could probably be smaller too.
6764 *
6765 * The implementation has three main parts / functions
6766 * - The decoding of the array of two
6767 * - All the tag and type checking for the various API functions
6768 * - Conversion to/from bignum and int
6769 *
6770 * The type checking seems like it wastes the most code for
6771 * what it needs to do.
6772 *
6773 * The inlining for the conversion is probably making the
6774 * overall code base larger.
6775 *
6776 * The tests cases could be organized a lot better and be
6777 * more thorough.
6778 *
6779 * Seems also like there could be more common code in the
6780 * first tier part of the public API. Some functions only
6781 * vary by a TagSpec.
6782 */
6783
6784 /**
6785 * @brief Common processor for exponent and mantissa.
6786 *
6787 * @param[in] pMe The decode context.
6788 * @param[in] TagSpec The expected/allowed tags.
6789 * @param[in] pItem The data item to process.
6790 * @param[out] pnMantissa The returned mantissa as an int64_t.
6791 * @param[out] pnExponent The returned exponent as an int64_t.
6792 *
6793 * This handles exponent and mantissa for base 2 and 10. This
6794 * is limited to a mantissa that is an int64_t. See also
6795 * QCBORDecode_Private_ProcessExpMantissaBig().
6796 */
6797 static void
QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext * pMe,const QCBOR_Private_TagSpec TagSpec,QCBORItem * pItem,int64_t * pnMantissa,int64_t * pnExponent)6798 QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6799 const QCBOR_Private_TagSpec TagSpec,
6800 QCBORItem *pItem,
6801 int64_t *pnMantissa,
6802 int64_t *pnExponent)
6803 {
6804 QCBORError uErr;
6805
6806 if(pMe->uLastError) {
6807 return;
6808 }
6809
6810 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
6811 if(uErr != QCBOR_SUCCESS) {
6812 goto Done;
6813 }
6814
6815 switch (pItem->uDataType) {
6816
6817 case QCBOR_TYPE_DECIMAL_FRACTION:
6818 case QCBOR_TYPE_BIGFLOAT:
6819 *pnExponent = pItem->val.expAndMantissa.nExponent;
6820 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
6821 break;
6822
6823 #ifndef QCBOR_DISABLE_TAGS
6824 /* If tags are disabled, mantissas can never be big nums */
6825 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6826 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6827 *pnExponent = pItem->val.expAndMantissa.nExponent;
6828 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
6829 break;
6830
6831 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6832 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6833 *pnExponent = pItem->val.expAndMantissa.nExponent;
6834 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
6835 break;
6836 #endif /* QCBOR_DISABLE_TAGS */
6837
6838 default:
6839 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6840 }
6841
6842 Done:
6843 pMe->uLastError = (uint8_t)uErr;
6844 }
6845
6846
6847 /**
6848 * @brief Decode exponent and mantissa into a big number.
6849 *
6850 * @param[in] pMe The decode context.
6851 * @param[in] TagSpec The expected/allowed tags.
6852 * @param[in] pItem Item to decode and convert.
6853 * @param[in] BufferForMantissa Buffer to output mantissa into.
6854 * @param[out] pMantissa The output mantissa.
6855 * @param[out] pbIsNegative The sign of the output.
6856 * @param[out] pnExponent The mantissa of the output.
6857 *
6858 * This is the common processing of a decimal fraction or a big float
6859 * into a big number. This will decode and consume all the CBOR items
6860 * that make up the decimal fraction or big float.
6861 */
6862 static void
QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext * pMe,const QCBOR_Private_TagSpec TagSpec,QCBORItem * pItem,const UsefulBuf BufferForMantissa,UsefulBufC * pMantissa,bool * pbIsNegative,int64_t * pnExponent)6863 QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6864 const QCBOR_Private_TagSpec TagSpec,
6865 QCBORItem *pItem,
6866 const UsefulBuf BufferForMantissa,
6867 UsefulBufC *pMantissa,
6868 bool *pbIsNegative,
6869 int64_t *pnExponent)
6870 {
6871 QCBORError uErr;
6872
6873 if(pMe->uLastError != QCBOR_SUCCESS) {
6874 return;
6875 }
6876
6877 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
6878 if(uErr != QCBOR_SUCCESS) {
6879 goto Done;
6880 }
6881
6882 uint64_t uMantissa;
6883
6884 switch (pItem->uDataType) {
6885
6886 case QCBOR_TYPE_DECIMAL_FRACTION:
6887 case QCBOR_TYPE_BIGFLOAT:
6888 /* See comments in ExponentiateNN() on handling INT64_MIN */
6889 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6890 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6891 *pbIsNegative = false;
6892 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
6893 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6894 *pbIsNegative = true;
6895 } else {
6896 uMantissa = (uint64_t)INT64_MAX+1;
6897 *pbIsNegative = true;
6898 }
6899 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6900 BufferForMantissa);
6901 *pnExponent = pItem->val.expAndMantissa.nExponent;
6902 break;
6903
6904 #ifndef QCBOR_DISABLE_TAGS
6905 /* If tags are disabled, mantissas can never be big nums */
6906 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6907 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6908 *pnExponent = pItem->val.expAndMantissa.nExponent;
6909 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6910 *pbIsNegative = false;
6911 break;
6912
6913 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6914 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6915 *pnExponent = pItem->val.expAndMantissa.nExponent;
6916 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6917 *pbIsNegative = true;
6918 break;
6919 #endif /* QCBOR_DISABLE_TAGS */
6920
6921 default:
6922 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6923 }
6924
6925 Done:
6926 pMe->uLastError = (uint8_t)uErr;
6927 }
6928
6929
6930 /*
6931 * Public function, see header qcbor/qcbor_decode.h file
6932 */
6933 void
QCBORDecode_GetDecimalFraction(QCBORDecodeContext * pMe,const uint8_t uTagRequirement,int64_t * pnMantissa,int64_t * pnExponent)6934 QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6935 const uint8_t uTagRequirement,
6936 int64_t *pnMantissa,
6937 int64_t *pnExponent)
6938 {
6939 QCBORItem Item;
6940 QCBORDecode_VGetNext(pMe, &Item);
6941
6942 const QCBOR_Private_TagSpec TagSpec =
6943 {
6944 uTagRequirement,
6945 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6946 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6947 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
6948 };
6949
6950 QCBOR_Private_ProcessExpMantissa(pMe,
6951 TagSpec,
6952 &Item,
6953 pnMantissa,
6954 pnExponent);
6955 }
6956
6957
6958 /*
6959 * Public function, see header qcbor/qcbor_decode.h file
6960 */
6961 void
QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint8_t uTagRequirement,int64_t * pnMantissa,int64_t * pnExponent)6962 QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6963 const int64_t nLabel,
6964 const uint8_t uTagRequirement,
6965 int64_t *pnMantissa,
6966 int64_t *pnExponent)
6967 {
6968 QCBORItem Item;
6969 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6970
6971 const QCBOR_Private_TagSpec TagSpec =
6972 {
6973 uTagRequirement,
6974 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6975 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6976 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
6977 };
6978
6979 QCBOR_Private_ProcessExpMantissa(pMe,
6980 TagSpec,
6981 &Item,
6982 pnMantissa,
6983 pnExponent);
6984 }
6985
6986
6987 /*
6988 * Public function, see header qcbor/qcbor_decode.h file
6989 */
6990 void
QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint8_t uTagRequirement,int64_t * pnMantissa,int64_t * pnExponent)6991 QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6992 const char *szLabel,
6993 const uint8_t uTagRequirement,
6994 int64_t *pnMantissa,
6995 int64_t *pnExponent)
6996 {
6997 QCBORItem Item;
6998 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6999
7000 const QCBOR_Private_TagSpec TagSpec =
7001 {
7002 uTagRequirement,
7003 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7004 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7005 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7006 };
7007
7008 QCBOR_Private_ProcessExpMantissa(pMe,
7009 TagSpec,
7010 &Item,
7011 pnMantissa,
7012 pnExponent);
7013 }
7014
7015
7016 /*
7017 * Public function, see header qcbor/qcbor_decode.h file
7018 */
7019 void
QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext * pMe,const uint8_t uTagRequirement,const UsefulBuf MantissaBuffer,UsefulBufC * pMantissa,bool * pbMantissaIsNegative,int64_t * pnExponent)7020 QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
7021 const uint8_t uTagRequirement,
7022 const UsefulBuf MantissaBuffer,
7023 UsefulBufC *pMantissa,
7024 bool *pbMantissaIsNegative,
7025 int64_t *pnExponent)
7026 {
7027 QCBORItem Item;
7028 QCBORDecode_VGetNext(pMe, &Item);
7029
7030 const QCBOR_Private_TagSpec TagSpec =
7031 {
7032 uTagRequirement,
7033 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7034 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7035 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7036 };
7037
7038 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7039 TagSpec,
7040 &Item,
7041 MantissaBuffer,
7042 pMantissa,
7043 pbMantissaIsNegative,
7044 pnExponent);
7045 }
7046
7047
7048 /*
7049 * Public function, see header qcbor/qcbor_decode.h file
7050 */
7051 void
QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint8_t uTagRequirement,const UsefulBuf BufferForMantissa,UsefulBufC * pMantissa,bool * pbIsNegative,int64_t * pnExponent)7052 QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7053 const int64_t nLabel,
7054 const uint8_t uTagRequirement,
7055 const UsefulBuf BufferForMantissa,
7056 UsefulBufC *pMantissa,
7057 bool *pbIsNegative,
7058 int64_t *pnExponent)
7059 {
7060
7061 QCBORItem Item;
7062 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7063
7064 const QCBOR_Private_TagSpec TagSpec =
7065 {
7066 uTagRequirement,
7067 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7068 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7069 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7070 };
7071
7072 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7073 TagSpec,
7074 &Item,
7075 BufferForMantissa,
7076 pMantissa,
7077 pbIsNegative,
7078 pnExponent);
7079 }
7080
7081
7082 /*
7083 * Public function, see header qcbor/qcbor_decode.h file
7084 */
7085 void
QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint8_t uTagRequirement,const UsefulBuf BufferForMantissa,UsefulBufC * pMantissa,bool * pbIsNegative,int64_t * pnExponent)7086 QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7087 const char *szLabel,
7088 const uint8_t uTagRequirement,
7089 const UsefulBuf BufferForMantissa,
7090 UsefulBufC *pMantissa,
7091 bool *pbIsNegative,
7092 int64_t *pnExponent)
7093 {
7094 QCBORItem Item;
7095 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7096
7097 const QCBOR_Private_TagSpec TagSpec =
7098 {
7099 uTagRequirement,
7100 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7101 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7102 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7103 };
7104
7105 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7106 TagSpec,
7107 &Item,
7108 BufferForMantissa,
7109 pMantissa,
7110 pbIsNegative,
7111 pnExponent);
7112 }
7113
7114
7115 /*
7116 * Public function, see header qcbor/qcbor_decode.h file
7117 */
7118 void
QCBORDecode_GetBigFloat(QCBORDecodeContext * pMe,const uint8_t uTagRequirement,int64_t * pnMantissa,int64_t * pnExponent)7119 QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7120 const uint8_t uTagRequirement,
7121 int64_t *pnMantissa,
7122 int64_t *pnExponent)
7123 {
7124 QCBORItem Item;
7125 QCBORDecode_VGetNext(pMe, &Item);
7126
7127 const QCBOR_Private_TagSpec TagSpec =
7128 {
7129 uTagRequirement,
7130 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7131 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7132 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7133 };
7134
7135 QCBOR_Private_ProcessExpMantissa(pMe,
7136 TagSpec,
7137 &Item,
7138 pnMantissa,
7139 pnExponent);
7140 }
7141
7142
7143 /*
7144 * Public function, see header qcbor/qcbor_decode.h file
7145 */
7146 void
QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint8_t uTagRequirement,int64_t * pnMantissa,int64_t * pnExponent)7147 QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7148 const int64_t nLabel,
7149 const uint8_t uTagRequirement,
7150 int64_t *pnMantissa,
7151 int64_t *pnExponent)
7152 {
7153 QCBORItem Item;
7154 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7155
7156 const QCBOR_Private_TagSpec TagSpec =
7157 {
7158 uTagRequirement,
7159 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7160 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7161 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7162 };
7163
7164 QCBOR_Private_ProcessExpMantissa(pMe,
7165 TagSpec,
7166 &Item,
7167 pnMantissa,
7168 pnExponent);
7169 }
7170
7171
7172 /*
7173 * Public function, see header qcbor/qcbor_decode.h file
7174 */
7175 void
QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint8_t uTagRequirement,int64_t * pnMantissa,int64_t * pnExponent)7176 QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7177 const char *szLabel,
7178 const uint8_t uTagRequirement,
7179 int64_t *pnMantissa,
7180 int64_t *pnExponent)
7181 {
7182 QCBORItem Item;
7183 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7184
7185 const QCBOR_Private_TagSpec TagSpec =
7186 {
7187 uTagRequirement,
7188 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7189 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7190 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7191 };
7192
7193 QCBOR_Private_ProcessExpMantissa(pMe,
7194 TagSpec,
7195 &Item,
7196 pnMantissa,
7197 pnExponent);
7198 }
7199
7200
7201 /*
7202 * Public function, see header qcbor/qcbor_decode.h file
7203 */
7204 void
QCBORDecode_GetBigFloatBig(QCBORDecodeContext * pMe,const uint8_t uTagRequirement,const UsefulBuf MantissaBuffer,UsefulBufC * pMantissa,bool * pbMantissaIsNegative,int64_t * pnExponent)7205 QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7206 const uint8_t uTagRequirement,
7207 const UsefulBuf MantissaBuffer,
7208 UsefulBufC *pMantissa,
7209 bool *pbMantissaIsNegative,
7210 int64_t *pnExponent)
7211 {
7212 QCBORItem Item;
7213 QCBORDecode_VGetNext(pMe, &Item);
7214
7215 const QCBOR_Private_TagSpec TagSpec =
7216 {
7217 uTagRequirement,
7218 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7219 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7220 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7221 };
7222
7223 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7224 TagSpec,
7225 &Item,
7226 MantissaBuffer,
7227 pMantissa,
7228 pbMantissaIsNegative,
7229 pnExponent);
7230 }
7231
7232
7233 /*
7234 * Public function, see header qcbor/qcbor_decode.h file
7235 */
7236 void
QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext * pMe,const int64_t nLabel,const uint8_t uTagRequirement,const UsefulBuf BufferForMantissa,UsefulBufC * pMantissa,bool * pbIsNegative,int64_t * pnExponent)7237 QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7238 const int64_t nLabel,
7239 const uint8_t uTagRequirement,
7240 const UsefulBuf BufferForMantissa,
7241 UsefulBufC *pMantissa,
7242 bool *pbIsNegative,
7243 int64_t *pnExponent)
7244 {
7245 QCBORItem Item;
7246 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7247
7248 const QCBOR_Private_TagSpec TagSpec =
7249 {
7250 uTagRequirement,
7251 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7252 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7253 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7254 };
7255
7256 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7257 TagSpec,
7258 &Item,
7259 BufferForMantissa,
7260 pMantissa,
7261 pbIsNegative,
7262 pnExponent);
7263 }
7264
7265
7266 /*
7267 * Public function, see header qcbor/qcbor_decode.h file
7268 */
7269 void
QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext * pMe,const char * szLabel,const uint8_t uTagRequirement,const UsefulBuf BufferForMantissa,UsefulBufC * pMantissa,bool * pbIsNegative,int64_t * pnExponent)7270 QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7271 const char *szLabel,
7272 const uint8_t uTagRequirement,
7273 const UsefulBuf BufferForMantissa,
7274 UsefulBufC *pMantissa,
7275 bool *pbIsNegative,
7276 int64_t *pnExponent)
7277 {
7278 QCBORItem Item;
7279 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7280
7281 const QCBOR_Private_TagSpec TagSpec =
7282 {
7283 uTagRequirement,
7284 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7285 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7286 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
7287 };
7288
7289 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7290 TagSpec,
7291 &Item,
7292 BufferForMantissa,
7293 pMantissa,
7294 pbIsNegative,
7295 pnExponent);
7296 }
7297
7298 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
7299